serde_intermediate/
schema.rs

1use pest::{iterators::Pairs, Parser};
2use pest_derive::Parser;
3use serde::{Deserialize, Serialize};
4use std::{collections::HashMap, hash::Hash};
5
6#[derive(Parser)]
7#[grammar = "schema.grammar.pest"]
8struct SchemaIdParser;
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub enum SchemaIdTree {
12    Tuple(Vec<Self>),
13    Path { path: Vec<String>, args: Vec<Self> },
14}
15
16impl SchemaIdTree {
17    pub fn new<T>() -> Self {
18        let id = SchemaId::new::<T>();
19        id.tree()
20            .unwrap_or_else(|| panic!("Cannot produce schema id tree from: {}", id.id()))
21    }
22
23    pub fn as_tuple(&self) -> Option<&[Self]> {
24        match self {
25            Self::Tuple(list) => Some(list),
26            _ => None,
27        }
28    }
29
30    pub fn as_path(&self) -> Option<&[String]> {
31        match self {
32            Self::Path { path, .. } => Some(path),
33            _ => None,
34        }
35    }
36
37    pub fn as_path_name(&self) -> Option<&str> {
38        self.as_path()
39            .and_then(|list| list.last())
40            .map(|segment| segment.as_str())
41    }
42
43    pub fn as_path_args(&self) -> Option<&[Self]> {
44        match self {
45            Self::Path { args, .. } => Some(args),
46            _ => None,
47        }
48    }
49}
50
51impl std::fmt::Display for SchemaIdTree {
52    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53        match self {
54            Self::Tuple(list) => {
55                write!(f, "(")?;
56                for (i, item) in list.iter().enumerate() {
57                    if i > 0 {
58                        write!(f, ", ")?;
59                    }
60                    item.fmt(f)?;
61                }
62                write!(f, ")")?;
63            }
64            Self::Path { path, args } => {
65                for (i, segment) in path.iter().enumerate() {
66                    if i > 0 {
67                        write!(f, "::")?;
68                    }
69                    segment.fmt(f)?;
70                }
71                if !args.is_empty() {
72                    write!(f, "<")?;
73                    for (i, arg) in args.iter().enumerate() {
74                        if i > 0 {
75                            write!(f, ", ")?;
76                        }
77                        arg.fmt(f)?;
78                    }
79                    write!(f, ">")?;
80                }
81            }
82        }
83        Ok(())
84    }
85}
86
87impl TryFrom<SchemaId> for SchemaIdTree {
88    type Error = ();
89
90    fn try_from(id: SchemaId) -> Result<Self, Self::Error> {
91        id.tree().ok_or(())
92    }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
96pub struct SchemaId(String);
97
98impl SchemaId {
99    pub fn new<T>() -> Self {
100        Self(std::any::type_name::<T>().to_string())
101    }
102
103    pub fn id(&self) -> &str {
104        &self.0
105    }
106
107    pub fn tree(&self) -> Option<SchemaIdTree> {
108        let pairs = SchemaIdParser::parse(Rule::main, &self.0)
109            .ok()?
110            .next()?
111            .into_inner();
112        Some(Self::parse_tree(pairs))
113    }
114
115    fn parse_tree(mut pairs: Pairs<Rule>) -> SchemaIdTree {
116        let pair = pairs.next().unwrap();
117        match pair.as_rule() {
118            Rule::tuple_element => SchemaIdTree::Tuple(Self::parse_list(pair.into_inner())),
119            Rule::path_element => {
120                let mut pairs = pair.into_inner();
121                let path = Self::parse_path(pairs.next().unwrap().into_inner());
122                let args = pairs
123                    .next()
124                    .map(|pair| Self::parse_list(pair.into_inner()))
125                    .unwrap_or_default();
126                SchemaIdTree::Path { path, args }
127            }
128            _ => unreachable!(),
129        }
130    }
131
132    fn parse_path(pairs: Pairs<Rule>) -> Vec<String> {
133        pairs.map(|pair| pair.as_str().to_owned()).collect()
134    }
135
136    fn parse_list(pairs: Pairs<Rule>) -> Vec<SchemaIdTree> {
137        pairs
138            .map(|pair| Self::parse_tree(pair.into_inner()))
139            .collect()
140    }
141}
142
143impl std::fmt::Display for SchemaId {
144    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145        write!(f, "{}", self.0)
146    }
147}
148
149impl From<SchemaIdTree> for SchemaId {
150    fn from(tree: SchemaIdTree) -> Self {
151        Self(tree.to_string())
152    }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
156pub enum SchemaIdContainer {
157    Id(SchemaId),
158    Tree(SchemaIdTree),
159}
160
161impl SchemaIdContainer {
162    pub fn new<T>(prefer_tree: bool) -> Self {
163        let id = SchemaId::new::<T>();
164        if prefer_tree {
165            id.tree()
166                .map(|tree| tree.into())
167                .unwrap_or_else(|| id.into())
168        } else {
169            id.into()
170        }
171    }
172
173    pub fn new_id(id: impl Into<SchemaId>) -> Self {
174        Self::Id(id.into())
175    }
176
177    pub fn new_tree(tree: impl Into<SchemaIdTree>) -> Self {
178        Self::Tree(tree.into())
179    }
180
181    pub fn as_id(&self) -> Option<&SchemaId> {
182        match self {
183            Self::Id(id) => Some(id),
184            _ => None,
185        }
186    }
187
188    pub fn as_tree(&self) -> Option<&SchemaIdTree> {
189        match self {
190            Self::Tree(tree) => Some(tree),
191            _ => None,
192        }
193    }
194
195    pub fn into_id(self) -> SchemaId {
196        match self {
197            Self::Id(id) => id,
198            Self::Tree(tree) => tree.into(),
199        }
200    }
201
202    pub fn try_into_tree(self) -> Option<SchemaIdTree> {
203        match self {
204            Self::Id(id) => id.tree(),
205            Self::Tree(tree) => Some(tree),
206        }
207    }
208}
209
210impl std::fmt::Display for SchemaIdContainer {
211    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212        match self {
213            Self::Id(id) => id.fmt(f),
214            Self::Tree(tree) => tree.fmt(f),
215        }
216    }
217}
218
219impl From<SchemaId> for SchemaIdContainer {
220    fn from(id: SchemaId) -> Self {
221        Self::Id(id)
222    }
223}
224
225impl From<SchemaIdTree> for SchemaIdContainer {
226    fn from(tree: SchemaIdTree) -> Self {
227        Self::Tree(tree)
228    }
229}
230
231#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
232pub struct SchemaTypeInstance {
233    pub id: SchemaIdContainer,
234    #[serde(default)]
235    pub description: String,
236}
237
238impl SchemaTypeInstance {
239    pub fn new(id: impl Into<SchemaIdContainer>) -> Self {
240        Self {
241            id: id.into(),
242            description: Default::default(),
243        }
244    }
245
246    pub fn description(mut self, content: impl ToString) -> Self {
247        self.description = content.to_string();
248        self
249    }
250}
251
252impl<ID> From<ID> for SchemaTypeInstance
253where
254    ID: Into<SchemaIdContainer>,
255{
256    fn from(id: ID) -> Self {
257        Self::new(id)
258    }
259}
260
261#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
262pub struct SchemaTypeTuple(pub Vec<SchemaTypeInstance>);
263
264impl SchemaTypeTuple {
265    pub fn item(mut self, type_instance: impl Into<SchemaTypeInstance>) -> Self {
266        self.0.push(type_instance.into());
267        self
268    }
269}
270
271impl<TI> FromIterator<TI> for SchemaTypeTuple
272where
273    TI: Into<SchemaTypeInstance>,
274{
275    fn from_iter<I>(iter: I) -> Self
276    where
277        I: IntoIterator<Item = TI>,
278    {
279        Self(
280            iter.into_iter()
281                .map(|type_instance| type_instance.into())
282                .collect(),
283        )
284    }
285}
286
287#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
288pub struct SchemaTypeStruct(pub HashMap<String, SchemaTypeInstance>);
289
290impl SchemaTypeStruct {
291    pub fn field(
292        mut self,
293        name: impl ToString,
294        type_instance: impl Into<SchemaTypeInstance>,
295    ) -> Self {
296        self.0.insert(name.to_string(), type_instance.into());
297        self
298    }
299}
300
301impl<N, TI> FromIterator<(N, TI)> for SchemaTypeStruct
302where
303    N: ToString,
304    TI: Into<SchemaTypeInstance>,
305{
306    fn from_iter<I>(iter: I) -> Self
307    where
308        I: IntoIterator<Item = (N, TI)>,
309    {
310        Self(
311            iter.into_iter()
312                .map(|(name, type_instance)| (name.to_string(), type_instance.into()))
313                .collect(),
314        )
315    }
316}
317
318#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
319pub struct SchemaTypeArrayOrSlice {
320    pub type_instance: SchemaTypeInstance,
321    pub count: usize,
322}
323
324impl SchemaTypeArrayOrSlice {
325    pub fn new(type_instance: impl Into<SchemaTypeInstance>, count: usize) -> Self {
326        Self {
327            type_instance: type_instance.into(),
328            count,
329        }
330    }
331}
332
333impl<TI> From<(TI, usize)> for SchemaTypeArrayOrSlice
334where
335    TI: Into<SchemaTypeInstance>,
336{
337    fn from((type_instance, count): (TI, usize)) -> Self {
338        Self::new(type_instance, count)
339    }
340}
341
342#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
343pub enum SchemaTypeEnumVariant {
344    #[default]
345    Empty,
346    Tuple(SchemaTypeTuple),
347    Struct(SchemaTypeStruct),
348}
349
350impl SchemaTypeEnumVariant {
351    pub fn new_tuple(content: impl Into<SchemaTypeTuple>) -> Self {
352        Self::Tuple(content.into())
353    }
354
355    pub fn new_struct(content: impl Into<SchemaTypeStruct>) -> Self {
356        Self::Struct(content.into())
357    }
358}
359
360#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
361pub struct SchemaTypeEnum(pub HashMap<String, SchemaTypeEnumVariant>);
362
363impl SchemaTypeEnum {
364    pub fn variant(
365        mut self,
366        name: impl ToString,
367        content: impl Into<SchemaTypeEnumVariant>,
368    ) -> Self {
369        self.0.insert(name.to_string(), content.into());
370        self
371    }
372}
373
374impl<N, V> FromIterator<(N, V)> for SchemaTypeEnum
375where
376    N: ToString,
377    V: Into<SchemaTypeEnumVariant>,
378{
379    fn from_iter<I>(iter: I) -> Self
380    where
381        I: IntoIterator<Item = (N, V)>,
382    {
383        Self(
384            iter.into_iter()
385                .map(|(name, variant)| (name.to_string(), variant.into()))
386                .collect(),
387        )
388    }
389}
390
391#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
392pub enum SchemaType {
393    Tuple(SchemaTypeTuple),
394    Array(SchemaTypeArrayOrSlice),
395    Slice(SchemaTypeArrayOrSlice),
396    TupleStruct(SchemaTypeTuple),
397    Struct(SchemaTypeStruct),
398    Enum(SchemaTypeEnum),
399}
400
401impl SchemaType {
402    pub fn new_tuple(content: impl Into<SchemaTypeTuple>) -> Self {
403        Self::Tuple(content.into())
404    }
405
406    pub fn new_array(content: impl Into<SchemaTypeArrayOrSlice>) -> Self {
407        Self::Array(content.into())
408    }
409
410    pub fn new_slice(content: impl Into<SchemaTypeArrayOrSlice>) -> Self {
411        Self::Slice(content.into())
412    }
413
414    pub fn new_tuple_struct(content: impl Into<SchemaTypeTuple>) -> Self {
415        Self::TupleStruct(content.into())
416    }
417
418    pub fn new_struct(content: impl Into<SchemaTypeStruct>) -> Self {
419        Self::Struct(content.into())
420    }
421
422    pub fn new_enum(content: impl Into<SchemaTypeEnum>) -> Self {
423        Self::Enum(content.into())
424    }
425}
426
427#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
428pub struct Schema {
429    pub data_type: SchemaType,
430    #[serde(default)]
431    pub description: String,
432}
433
434impl Schema {
435    pub fn new(data_type: impl Into<SchemaType>) -> Self {
436        Self {
437            description: Default::default(),
438            data_type: data_type.into(),
439        }
440    }
441
442    pub fn description(mut self, content: impl ToString) -> Self {
443        self.description = content.to_string();
444        self
445    }
446}
447
448impl<T> From<T> for Schema
449where
450    T: Into<SchemaType>,
451{
452    fn from(data_type: T) -> Self {
453        Self::new(data_type)
454    }
455}
456
457#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
458pub struct SchemaPackage {
459    #[serde(default)]
460    pub prefer_tree_id: bool,
461    pub schemas: HashMap<SchemaIdContainer, Schema>,
462}
463
464impl SchemaPackage {
465    pub fn with_capacity(capacity: usize) -> Self {
466        Self {
467            prefer_tree_id: false,
468            schemas: HashMap::with_capacity(capacity),
469        }
470    }
471
472    pub fn prefer_tree_id(mut self, value: bool) -> Self {
473        self.prefer_tree_id = value;
474        self
475    }
476
477    pub fn with(
478        &mut self,
479        id: impl Into<SchemaIdContainer>,
480        schema: impl Into<Schema>,
481    ) -> &mut Self {
482        self.schemas.insert(id.into(), schema.into());
483        self
484    }
485}
486
487pub trait SchemaIntermediate: Sized {
488    fn schema(package: &mut SchemaPackage) -> SchemaIdContainer;
489}