Skip to main content

reflectapi_schema/
lib.rs

1mod codegen;
2mod internal;
3mod rename;
4mod subst;
5mod visit;
6
7pub use self::codegen::*;
8pub use self::subst::{mk_subst, Instantiate, Substitute};
9pub use self::visit::{VisitMut, Visitor};
10
11#[cfg(feature = "glob")]
12pub use self::rename::Glob;
13
14#[cfg(feature = "glob")]
15pub use glob::PatternError;
16
17pub use self::rename::*;
18use core::fmt;
19use std::collections::BTreeSet;
20use std::{
21    collections::HashMap,
22    ops::{ControlFlow, Index},
23};
24
25#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
26pub struct Schema {
27    pub name: String,
28
29    #[serde(skip_serializing_if = "String::is_empty", default)]
30    pub description: String,
31
32    #[serde(skip_serializing_if = "Vec::is_empty", default)]
33    pub functions: Vec<Function>,
34
35    #[serde(skip_serializing_if = "Typespace::is_empty", default)]
36    pub input_types: Typespace,
37
38    #[serde(skip_serializing_if = "Typespace::is_empty", default)]
39    pub output_types: Typespace,
40}
41
42impl Default for Schema {
43    fn default() -> Self {
44        Self::new()
45    }
46}
47
48impl Schema {
49    pub fn new() -> Self {
50        Schema {
51            name: String::new(),
52            description: String::new(),
53            functions: Vec::new(),
54            input_types: Typespace::new(),
55            output_types: Typespace::new(),
56        }
57    }
58
59    pub fn name(&self) -> &str {
60        self.name.as_str()
61    }
62
63    pub fn description(&self) -> &str {
64        self.description.as_str()
65    }
66
67    pub fn functions(&self) -> std::slice::Iter<'_, Function> {
68        self.functions.iter()
69    }
70
71    pub fn input_types(&self) -> &Typespace {
72        &self.input_types
73    }
74
75    pub fn is_input_type(&self, name: &str) -> bool {
76        self.input_types.has_type(name)
77    }
78
79    pub fn output_types(&self) -> &Typespace {
80        &self.output_types
81    }
82
83    pub fn is_output_type(&self, name: &str) -> bool {
84        self.output_types.has_type(name)
85    }
86
87    pub fn extend(&mut self, other: Self) {
88        let Self {
89            functions,
90            input_types,
91            output_types,
92            name: _,
93            description: _,
94        } = other;
95        self.functions.extend(functions);
96        self.input_types.extend(input_types);
97        self.output_types.extend(output_types);
98    }
99
100    pub fn prepend_path(&mut self, path: &str) {
101        if path.is_empty() {
102            return;
103        }
104        for function in self.functions.iter_mut() {
105            function.path = format!("{}{}", path, function.path);
106        }
107    }
108
109    pub fn consolidate_types(&mut self) -> Vec<String> {
110        // this is probably very inefficient approach to deduplicate types
111        // but is simple enough and will work for foreseeable future
112        loop {
113            let mut all_types = std::collections::HashSet::new();
114            let mut colliding_types = std::collections::HashSet::new();
115            let mut colliging_non_equal_types = std::collections::HashSet::new();
116
117            for input_type in self.input_types.types() {
118                all_types.insert(input_type.name().to_string());
119                if let Some(output_type) = self.output_types.get_type(input_type.name()) {
120                    colliding_types.insert(input_type.name().to_string());
121                    if input_type != output_type {
122                        colliging_non_equal_types.insert(input_type.name().to_string());
123                    }
124                }
125            }
126            for output_type in self.output_types.types() {
127                all_types.insert(output_type.name().to_string());
128                if let Some(input_type) = self.input_types.get_type(output_type.name()) {
129                    colliding_types.insert(output_type.name().to_string());
130                    if input_type != output_type {
131                        colliging_non_equal_types.insert(output_type.name().to_string());
132                    }
133                }
134            }
135
136            if colliging_non_equal_types.is_empty() {
137                let mut r: Vec<_> = all_types.into_iter().collect();
138                r.sort();
139                return r;
140            }
141
142            for type_name in colliging_non_equal_types.iter() {
143                // we assume for now that there is not collision with input / output submodule
144
145                let mut type_name_parts = type_name.split("::").collect::<Vec<_>>();
146                type_name_parts.insert(type_name_parts.len() - 1, "input");
147                self.rename_input_types(type_name.as_str(), &type_name_parts.join("::"));
148
149                let mut type_name_parts = type_name.split("::").collect::<Vec<_>>();
150                type_name_parts.insert(type_name_parts.len() - 1, "output");
151                self.rename_output_types(type_name.as_str(), &type_name_parts.join("::"));
152            }
153        }
154    }
155
156    pub fn get_type(&self, name: &str) -> Option<&Type> {
157        if let Some(t) = self.input_types.get_type(name) {
158            return Some(t);
159        }
160        if let Some(t) = self.output_types.get_type(name) {
161            return Some(t);
162        }
163        None
164    }
165
166    pub fn get_type_mut(&mut self, name: &str) -> Option<&mut Type> {
167        if let Some(t) = self.input_types.get_type_mut(name) {
168            return Some(t);
169        }
170        if let Some(t) = self.output_types.get_type_mut(name) {
171            return Some(t);
172        }
173        None
174    }
175
176    #[cfg(feature = "glob")]
177    pub fn glob_rename_types(
178        &mut self,
179        glob: &str,
180        replacer: &str,
181    ) -> Result<(), glob::PatternError> {
182        let pattern = glob.parse::<Glob>()?;
183        self.rename_types(&pattern, replacer);
184        Ok(())
185    }
186
187    pub fn rename_types(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
188        self.rename_input_types(pattern, replacer) + self.rename_output_types(pattern, replacer)
189    }
190
191    fn rename_input_types(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
192        match Renamer::new(pattern, replacer).visit_schema_inputs(self) {
193            ControlFlow::Continue(c) | ControlFlow::Break(c) => c,
194        }
195    }
196
197    fn rename_output_types(&mut self, pattern: impl Pattern, replacer: &str) -> usize {
198        match Renamer::new(pattern, replacer).visit_schema_outputs(self) {
199            ControlFlow::Continue(c) | ControlFlow::Break(c) => c,
200        }
201    }
202
203    pub fn fold_transparent_types(&mut self) {
204        // Replace the transparent struct `strukt` with it's single field.
205        #[derive(Debug)]
206        struct SubstVisitor {
207            strukt: Struct,
208            to: TypeReference,
209        }
210
211        impl SubstVisitor {
212            fn new(strukt: Struct) -> Self {
213                assert!(strukt.transparent && strukt.fields.len() == 1);
214                Self {
215                    to: strukt.fields[0].type_ref.clone(),
216                    strukt,
217                }
218            }
219        }
220
221        impl Visitor for SubstVisitor {
222            type Output = ();
223
224            fn visit_type_ref(
225                &mut self,
226                type_ref: &mut TypeReference,
227            ) -> ControlFlow<Self::Output, Self::Output> {
228                if type_ref.name == self.strukt.name {
229                    let subst = subst::mk_subst(&self.strukt.parameters, &type_ref.arguments);
230                    *type_ref = self.to.clone().subst(&subst);
231                }
232
233                type_ref.visit_mut(self)?;
234
235                ControlFlow::Continue(())
236            }
237        }
238
239        let transparent_types = self
240            .input_types()
241            .types()
242            .filter_map(|t| {
243                t.as_struct()
244                    .filter(|i| i.transparent && i.fields.len() == 1)
245                    .cloned()
246            })
247            .collect::<Vec<_>>();
248
249        for strukt in transparent_types {
250            self.input_types.remove_type(strukt.name());
251            let _ = SubstVisitor::new(strukt).visit_schema_inputs(self);
252        }
253
254        let transparent_types = self
255            .output_types()
256            .types()
257            .filter_map(|t| {
258                t.as_struct()
259                    .filter(|i| i.transparent && i.fields.len() == 1)
260                    .cloned()
261            })
262            .collect::<Vec<_>>();
263
264        for strukt in transparent_types {
265            self.output_types.remove_type(strukt.name());
266            let _ = SubstVisitor::new(strukt).visit_schema_outputs(self);
267        }
268    }
269}
270
271#[derive(Clone, serde::Serialize, serde::Deserialize, Default)]
272pub struct Typespace {
273    #[serde(skip_serializing_if = "Vec::is_empty", default)]
274    types: Vec<Type>,
275
276    #[serde(skip_serializing, default)]
277    types_map: std::cell::RefCell<HashMap<String, usize>>,
278}
279
280impl fmt::Debug for Typespace {
281    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282        f.debug_map()
283            .entries(self.types.iter().map(|t| (t.name().to_string(), t)))
284            .finish()
285    }
286}
287
288impl Typespace {
289    pub fn new() -> Self {
290        Typespace {
291            types: Vec::new(),
292            types_map: std::cell::RefCell::new(HashMap::new()),
293        }
294    }
295
296    pub fn is_empty(&self) -> bool {
297        self.types.is_empty()
298    }
299
300    pub fn types(&self) -> std::slice::Iter<'_, Type> {
301        self.types.iter()
302    }
303
304    pub fn get_type(&self, name: &str) -> Option<&Type> {
305        self.ensure_types_map();
306        let index = {
307            let b = self.types_map.borrow();
308            b.get(name).copied().unwrap_or(usize::MAX)
309        };
310        if index == usize::MAX {
311            return None;
312        }
313        self.types.get(index)
314    }
315
316    pub fn get_type_mut(&mut self, name: &str) -> Option<&mut Type> {
317        self.ensure_types_map();
318        let index = {
319            let b = self.types_map.borrow();
320            b.get(name).copied().unwrap_or(usize::MAX)
321        };
322        if index == usize::MAX {
323            return None;
324        }
325        self.types.get_mut(index)
326    }
327
328    pub fn reserve_type(&mut self, name: &str) -> bool {
329        self.ensure_types_map();
330        if self.types_map.borrow().contains_key(name) {
331            return false;
332        }
333        self.types_map.borrow_mut().insert(name.into(), usize::MAX);
334        true
335    }
336
337    pub fn insert_type(&mut self, ty: Type) {
338        self.ensure_types_map();
339        if let Some(index) = self.types_map.borrow().get(ty.name()) {
340            if index != &usize::MAX {
341                return;
342            }
343        }
344        self.types_map
345            .borrow_mut()
346            .insert(ty.name().into(), self.types.len());
347        self.types.push(ty);
348    }
349
350    pub fn remove_type(&mut self, ty: &str) -> Option<Type> {
351        self.ensure_types_map();
352        let index = self
353            .types_map
354            .borrow()
355            .get(ty)
356            .copied()
357            .unwrap_or(usize::MAX);
358        if index == usize::MAX {
359            return None;
360        }
361
362        self.types_map.borrow_mut().remove(ty);
363        Some(self.types.remove(index))
364    }
365
366    pub fn sort_types(&mut self) {
367        self.types.sort_by(|a, b| a.name().cmp(b.name()));
368        self.build_types_map();
369    }
370
371    pub fn has_type(&self, name: &str) -> bool {
372        self.ensure_types_map();
373        self.types_map.borrow().contains_key(name)
374    }
375
376    pub fn extend(&mut self, other: Self) {
377        self.ensure_types_map();
378        for ty in other.types {
379            if self.has_type(ty.name()) {
380                continue;
381            }
382            self.insert_type(ty);
383        }
384    }
385
386    fn invalidate_types_map(&self) {
387        self.types_map.borrow_mut().clear()
388    }
389
390    fn ensure_types_map(&self) {
391        if self.types_map.borrow().is_empty() && !self.types.is_empty() {
392            self.build_types_map();
393        }
394    }
395
396    fn build_types_map(&self) {
397        let mut types_map = HashMap::new();
398        for (i, ty) in self.types.iter().enumerate() {
399            types_map.insert(ty.name().into(), i);
400        }
401        *(self.types_map.borrow_mut()) = types_map;
402    }
403}
404
405#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
406pub struct Function {
407    /// Includes entity and action, for example: users.login
408    pub name: String,
409    /// URL mounting path, for example: /api/v1
410    pub path: String,
411    /// Description of the call
412    #[serde(skip_serializing_if = "String::is_empty", default)]
413    pub description: String,
414    /// Deprecation note. If none, function is not deprecated.
415    /// If present as empty string, function is deprecated without a note.
416    #[serde(skip_serializing_if = "Option::is_none", default)]
417    pub deprecation_note: Option<String>,
418
419    #[serde(skip_serializing_if = "Option::is_none", default)]
420    pub input_type: Option<TypeReference>,
421    #[serde(skip_serializing_if = "Option::is_none", default)]
422    pub input_headers: Option<TypeReference>,
423
424    #[serde(skip_serializing_if = "Option::is_none", default)]
425    pub output_type: Option<TypeReference>,
426
427    #[serde(skip_serializing_if = "Option::is_none", default)]
428    pub error_type: Option<TypeReference>,
429
430    ///
431    /// Supported content types for request and response bodies.
432    ///
433    /// Note: serialization for header values is not affected by this field.
434    /// For displayable types of fields, it is encoded in plain strings.
435    /// For non-displayable types, it is encoded as json.
436    ///
437    /// Default: only json if empty
438    ///
439    #[serde(skip_serializing_if = "Vec::is_empty", default)]
440    pub serialization: Vec<SerializationMode>,
441
442    /// If a function is readonly, it means it does not modify the state of an application
443    #[serde(skip_serializing_if = "is_false", default)]
444    pub readonly: bool,
445
446    #[serde(skip_serializing_if = "BTreeSet::is_empty", default)]
447    pub tags: BTreeSet<String>,
448}
449
450impl Function {
451    pub fn new(name: String) -> Self {
452        Function {
453            name,
454            deprecation_note: Default::default(),
455            path: Default::default(),
456            description: Default::default(),
457            input_type: None,
458            input_headers: None,
459            output_type: None,
460            error_type: None,
461            serialization: Default::default(),
462            readonly: Default::default(),
463            tags: Default::default(),
464        }
465    }
466
467    pub fn name(&self) -> &str {
468        self.name.as_str()
469    }
470
471    pub fn path(&self) -> &str {
472        self.path.as_str()
473    }
474
475    pub fn description(&self) -> &str {
476        self.description.as_str()
477    }
478
479    pub fn deprecated(&self) -> bool {
480        self.deprecation_note.is_some()
481    }
482
483    pub fn input_type(&self) -> Option<&TypeReference> {
484        self.input_type.as_ref()
485    }
486
487    pub fn input_headers(&self) -> Option<&TypeReference> {
488        self.input_headers.as_ref()
489    }
490
491    pub fn output_type(&self) -> Option<&TypeReference> {
492        self.output_type.as_ref()
493    }
494
495    pub fn error_type(&self) -> Option<&TypeReference> {
496        self.error_type.as_ref()
497    }
498
499    pub fn serialization(&self) -> std::slice::Iter<'_, SerializationMode> {
500        self.serialization.iter()
501    }
502
503    pub fn readonly(&self) -> bool {
504        self.readonly
505    }
506}
507
508#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
509#[serde(rename_all = "snake_case")]
510pub enum SerializationMode {
511    #[default]
512    Json,
513    Msgpack,
514}
515
516#[derive(
517    Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord,
518)]
519pub struct TypeReference {
520    pub name: String,
521    /**
522     * References to actual types to use instead of the type parameters
523     * declared on the referred generic type
524     */
525    #[serde(skip_serializing_if = "Vec::is_empty", default)]
526    pub arguments: Vec<TypeReference>,
527}
528
529impl TypeReference {
530    pub fn new(name: impl Into<String>, arguments: Vec<TypeReference>) -> Self {
531        TypeReference {
532            name: name.into(),
533            arguments,
534        }
535    }
536
537    pub fn name(&self) -> &str {
538        self.name.as_str()
539    }
540
541    pub fn arguments(&self) -> std::slice::Iter<'_, TypeReference> {
542        self.arguments.iter()
543    }
544
545    pub fn fallback_recursively(&mut self, schema: &Typespace) {
546        loop {
547            let Some(type_def) = schema.get_type(self.name()) else {
548                return;
549            };
550            let Some(fallback_type_ref) = type_def.fallback_internal(self) else {
551                return;
552            };
553            *self = fallback_type_ref;
554        }
555    }
556
557    pub fn fallback_once(&self, schema: &Typespace) -> Option<TypeReference> {
558        let type_def = schema.get_type(self.name())?;
559        type_def.fallback_internal(self)
560    }
561}
562
563impl From<&str> for TypeReference {
564    fn from(name: &str) -> Self {
565        TypeReference::new(name, Vec::new())
566    }
567}
568
569impl From<String> for TypeReference {
570    fn from(name: String) -> Self {
571        TypeReference::new(name, Vec::new())
572    }
573}
574
575#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
576pub struct TypeParameter {
577    pub name: String,
578    #[serde(skip_serializing_if = "String::is_empty", default)]
579    pub description: String,
580}
581
582impl TypeParameter {
583    pub fn new(name: String, description: String) -> Self {
584        TypeParameter { name, description }
585    }
586
587    pub fn name(&self) -> &str {
588        self.name.as_str()
589    }
590
591    pub fn description(&self) -> &str {
592        self.description.as_str()
593    }
594}
595
596impl From<&str> for TypeParameter {
597    fn from(name: &str) -> Self {
598        TypeParameter {
599            name: name.into(),
600            description: String::new(),
601        }
602    }
603}
604
605impl From<String> for TypeParameter {
606    fn from(name: String) -> Self {
607        TypeParameter {
608            name,
609            description: String::new(),
610        }
611    }
612}
613
614impl PartialEq for TypeParameter {
615    fn eq(&self, other: &Self) -> bool {
616        self.name == other.name
617    }
618}
619
620impl Eq for TypeParameter {}
621
622impl std::hash::Hash for TypeParameter {
623    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
624        self.name.hash(state);
625    }
626}
627
628#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
629#[serde(rename_all = "snake_case", tag = "kind")]
630pub enum Type {
631    Primitive(Primitive),
632    Struct(Struct),
633    Enum(Enum),
634}
635
636impl Type {
637    pub fn name(&self) -> &str {
638        match self {
639            Type::Primitive(p) => &p.name,
640            Type::Struct(s) => &s.name,
641            Type::Enum(e) => &e.name,
642        }
643    }
644
645    pub fn serde_name(&self) -> &str {
646        match self {
647            Type::Primitive(_) => self.name(),
648            Type::Struct(s) => s.serde_name(),
649            Type::Enum(e) => e.serde_name(),
650        }
651    }
652
653    pub fn description(&self) -> &str {
654        match self {
655            Type::Primitive(p) => &p.description,
656            Type::Struct(s) => &s.description,
657            Type::Enum(e) => &e.description,
658        }
659    }
660
661    pub fn parameters(&self) -> std::slice::Iter<'_, TypeParameter> {
662        match self {
663            Type::Primitive(p) => p.parameters(),
664            Type::Struct(s) => s.parameters(),
665            Type::Enum(e) => e.parameters(),
666        }
667    }
668
669    pub fn as_struct(&self) -> Option<&Struct> {
670        match self {
671            Type::Struct(s) => Some(s),
672            _ => None,
673        }
674    }
675
676    pub fn is_struct(&self) -> bool {
677        matches!(self, Type::Struct(_))
678    }
679
680    pub fn as_enum(&self) -> Option<&Enum> {
681        match self {
682            Type::Enum(e) => Some(e),
683            _ => None,
684        }
685    }
686
687    pub fn is_enum(&self) -> bool {
688        matches!(self, Type::Enum(_))
689    }
690
691    pub fn as_primitive(&self) -> Option<&Primitive> {
692        match self {
693            Type::Primitive(p) => Some(p),
694            _ => None,
695        }
696    }
697
698    pub fn is_primitive(&self) -> bool {
699        matches!(self, Type::Primitive(_))
700    }
701
702    fn fallback_internal(&self, origin: &TypeReference) -> Option<TypeReference> {
703        match self {
704            Type::Primitive(p) => p.fallback_internal(origin),
705            Type::Struct(_) => None,
706            Type::Enum(_) => None,
707        }
708    }
709
710    pub fn __internal_rename_current(&mut self, new_name: String) {
711        match self {
712            Type::Primitive(p) => p.name = new_name,
713            Type::Struct(s) => s.name = new_name,
714            Type::Enum(e) => e.name = new_name,
715        }
716    }
717
718    pub fn __internal_rebind_generic_parameters(
719        &mut self,
720        unresolved_to_resolved_map: &std::collections::HashMap<TypeReference, TypeReference>,
721        schema: &Typespace,
722    ) {
723        internal::replace_type_references_for_type(self, unresolved_to_resolved_map, schema)
724    }
725}
726
727#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
728pub struct Primitive {
729    pub name: String,
730    #[serde(skip_serializing_if = "String::is_empty", default)]
731    pub description: String,
732
733    /// Generic type parameters, if any
734    #[serde(skip_serializing_if = "Vec::is_empty", default)]
735    pub parameters: Vec<TypeParameter>,
736
737    /// Fallback type to use when the type is not supported by the target language
738    #[serde(skip_serializing_if = "Option::is_none", default)]
739    pub fallback: Option<TypeReference>,
740}
741
742impl Primitive {
743    pub fn new(
744        name: String,
745        description: String,
746        parameters: Vec<TypeParameter>,
747        fallback: Option<TypeReference>,
748    ) -> Self {
749        Primitive {
750            name,
751            description,
752            parameters,
753            fallback,
754        }
755    }
756
757    pub fn name(&self) -> &str {
758        self.name.as_str()
759    }
760
761    pub fn description(&self) -> &str {
762        self.description.as_str()
763    }
764
765    pub fn parameters(&self) -> std::slice::Iter<'_, TypeParameter> {
766        self.parameters.iter()
767    }
768
769    pub fn fallback(&self) -> Option<&TypeReference> {
770        self.fallback.as_ref()
771    }
772
773    fn fallback_internal(&self, origin: &TypeReference) -> Option<TypeReference> {
774        // example:
775        // Self is DashMap<K, V>
776        // fallback is HashSet<V> (stupid example, but it demos generic param discard)
777        // origin is DashMap<String, u8>
778        // It should transform origin to HashSet<u8>
779        let fallback = self.fallback.as_ref()?;
780
781        if let Some((type_def_param_index, _)) = self
782            .parameters()
783            .enumerate()
784            .find(|(_, type_def_param)| type_def_param.name() == fallback.name())
785        {
786            // this is the case when fallback is to one of the generic parameters
787            // for example, Arc<T> to T
788            let Some(origin_type_ref_param) = origin.arguments.get(type_def_param_index) else {
789                // It means the origin type reference does no provide correct number of generic parameters
790                // required by the type definition
791                // It is invalid schema
792                return None;
793            };
794            return Some(TypeReference {
795                name: origin_type_ref_param.name.clone(),
796                arguments: origin_type_ref_param.arguments.clone(),
797            });
798        }
799
800        let mut new_arguments_for_origin = Vec::new();
801        for fallback_type_ref_param in fallback.arguments() {
802            let Some((type_def_param_index, _)) =
803                self.parameters().enumerate().find(|(_, type_def_param)| {
804                    type_def_param.name() == fallback_type_ref_param.name()
805                })
806            else {
807                // It means fallback type does not have
808                // as much generic parameters as this type definition
809                // in our example, it would be index 0
810                continue;
811            };
812
813            // in our example type_def_param_index would be index 1 for V
814            let Some(origin_type_ref_param) = origin.arguments.get(type_def_param_index) else {
815                // It means the origin type reference does no provide correct number of generic parameters
816                // required by the type definition
817                // It is invalid schema
818                return None;
819            };
820            new_arguments_for_origin.push(origin_type_ref_param.clone());
821        }
822
823        Some(TypeReference {
824            name: fallback.name.clone(),
825            arguments: new_arguments_for_origin,
826        })
827    }
828}
829
830impl From<Primitive> for Type {
831    fn from(val: Primitive) -> Self {
832        Type::Primitive(val)
833    }
834}
835
836#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
837pub struct Struct {
838    /// Name of a struct, should be a valid Rust struct name identifier
839    pub name: String,
840
841    /// If a serialized name is not a valid Rust struct name identifier
842    /// then this defines the name of a struct to be used in serialization
843    #[serde(skip_serializing_if = "String::is_empty", default)]
844    pub serde_name: String,
845
846    /// Markdown docs for the struct
847    #[serde(skip_serializing_if = "String::is_empty", default)]
848    pub description: String,
849
850    /// Generic type parameters, if any
851    #[serde(skip_serializing_if = "Vec::is_empty", default)]
852    pub parameters: Vec<TypeParameter>,
853
854    pub fields: Fields,
855
856    /// If serde transparent attribute is set on a struct
857    #[serde(skip_serializing_if = "is_false", default)]
858    pub transparent: bool,
859
860    #[serde(skip_serializing_if = "is_default", default)]
861    pub codegen_config: LanguageSpecificTypeCodegenConfig,
862}
863
864impl Struct {
865    pub fn new(name: impl Into<String>) -> Self {
866        Struct {
867            name: name.into(),
868            serde_name: Default::default(),
869            description: Default::default(),
870            parameters: Default::default(),
871            fields: Default::default(),
872            transparent: Default::default(),
873            codegen_config: Default::default(),
874        }
875    }
876
877    /// Returns the name of a struct, should be a valid Rust struct name identifier
878    pub fn name(&self) -> &str {
879        self.name.as_str()
880    }
881
882    /// Returns the name of a struct to be used in serialization
883    pub fn serde_name(&self) -> &str {
884        if self.serde_name.is_empty() {
885            self.name.as_str()
886        } else {
887            self.serde_name.as_str()
888        }
889    }
890
891    pub fn description(&self) -> &str {
892        self.description.as_str()
893    }
894
895    pub fn parameters(&self) -> std::slice::Iter<'_, TypeParameter> {
896        self.parameters.iter()
897    }
898
899    pub fn fields(&self) -> std::slice::Iter<'_, Field> {
900        self.fields.iter()
901    }
902
903    pub fn transparent(&self) -> bool {
904        self.transparent
905    }
906
907    /// Returns true if a struct has 1 field and it is either named "0"
908    /// or is transparent in the serialized form
909    pub fn is_alias(&self) -> bool {
910        self.fields.len() == 1 && (self.fields[0].name() == "0" || self.transparent)
911    }
912
913    /// Returns true is a struct is a Rust unit struct.
914    /// Please note, that a unit struct is also an alias
915    // NOTE(andy): does this function make sense? A unit struct is a struct with no fields.
916    pub fn is_unit(&self) -> bool {
917        let Some(first_field) = self.fields.iter().next() else {
918            return false;
919        };
920
921        self.fields.len() == 1
922            && first_field.name() == "0"
923            && first_field.type_ref.name == "std::tuple::Tuple0"
924            && !first_field.required
925    }
926
927    /// Returns true if a struct is a Rust tuple struct.
928    pub fn is_tuple(&self) -> bool {
929        !self.fields.is_empty()
930            && self
931                .fields
932                .iter()
933                .all(|f| f.name().parse::<usize>().is_ok())
934    }
935}
936
937impl From<Struct> for Type {
938    fn from(val: Struct) -> Self {
939        Type::Struct(val)
940    }
941}
942
943#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash, Default)]
944#[serde(rename_all = "snake_case")]
945pub enum Fields {
946    /// Named struct or variant:
947    /// struct S { a: u8, b: u8 }
948    /// enum S { T { a: u8, b: u8 } }
949    Named(Vec<Field>),
950    /// Tuple struct or variant:
951    /// struct S(u8, u8);
952    /// enum S { T(u8, u8) }
953    Unnamed(Vec<Field>),
954    /// Unit struct or variant:
955    ///
956    /// struct S;
957    /// enum S { U }
958    #[default]
959    None,
960}
961
962impl Fields {
963    pub fn is_empty(&self) -> bool {
964        match self {
965            Fields::Named(fields) | Fields::Unnamed(fields) => fields.is_empty(),
966            Fields::None => true,
967        }
968    }
969
970    pub fn len(&self) -> usize {
971        match self {
972            Fields::Named(fields) | Fields::Unnamed(fields) => fields.len(),
973            Fields::None => 0,
974        }
975    }
976
977    pub fn iter(&self) -> std::slice::Iter<'_, Field> {
978        match self {
979            Fields::Named(fields) | Fields::Unnamed(fields) => fields.iter(),
980            Fields::None => [].iter(),
981        }
982    }
983
984    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Field> {
985        match self {
986            Fields::Named(fields) | Fields::Unnamed(fields) => fields.iter_mut(),
987            Fields::None => [].iter_mut(),
988        }
989    }
990}
991
992impl Index<usize> for Fields {
993    type Output = Field;
994
995    fn index(&self, index: usize) -> &Self::Output {
996        match self {
997            Fields::Named(fields) | Fields::Unnamed(fields) => &fields[index],
998            Fields::None => panic!("index out of bounds"),
999        }
1000    }
1001}
1002
1003impl IntoIterator for Fields {
1004    type Item = Field;
1005    type IntoIter = std::vec::IntoIter<Field>;
1006
1007    fn into_iter(self) -> Self::IntoIter {
1008        match self {
1009            Fields::Named(fields) => fields.into_iter(),
1010            Fields::Unnamed(fields) => fields.into_iter(),
1011            Fields::None => vec![].into_iter(),
1012        }
1013    }
1014}
1015
1016#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, Hash)]
1017pub struct Field {
1018    /// Field name, should be a valid Rust field name identifier
1019    pub name: String,
1020    /// If a serialized name is not a valid Rust field name identifier
1021    /// then this defines the name of a field to be used in serialization
1022    #[serde(skip_serializing_if = "String::is_empty", default)]
1023    pub serde_name: String,
1024    /// Rust docs for the field
1025    #[serde(skip_serializing_if = "String::is_empty", default)]
1026    pub description: String,
1027
1028    /// Deprecation note. If none, field is not deprecated.
1029    /// If present as empty string, field is deprecated without a note.
1030    #[serde(skip_serializing_if = "Option::is_none", default)]
1031    pub deprecation_note: Option<String>,
1032
1033    /// Type of a field
1034    #[serde(rename = "type")]
1035    pub type_ref: TypeReference,
1036    /// required and not nullable:
1037    /// - field always present and not null / none
1038    ///
1039    /// required and nullable:
1040    /// - Rust: `Option<T>`, do not skip serializing if None
1041    /// - TypeScript: T | null, do not skip serializing if null
1042    ///
1043    /// not required and not nullable:
1044    /// - Rust: `Option<T>`, skip serializing if None
1045    /// - TypeScript: T | undefined, skip serializing if undefined
1046    ///
1047    /// not required and nullable:
1048    ///   serializers and deserializers are required to differentiate between
1049    ///   missing fields and null / none fields
1050    /// - Rust: `reflectapi::Option<T>` is enum with Undefined, None and Some variants
1051    /// - TypeScript: T | null | undefined
1052    ///
1053    /// Default is false
1054    #[serde(skip_serializing_if = "is_false", default)]
1055    pub required: bool,
1056    /// If serde flatten attribute is set on a field
1057    /// Default is false
1058    #[serde(skip_serializing_if = "is_false", default)]
1059    pub flattened: bool,
1060
1061    #[serde(skip, default)]
1062    pub transform_callback: String,
1063    #[serde(skip, default)]
1064    pub transform_callback_fn: Option<fn(&mut TypeReference, &Typespace) -> ()>,
1065}
1066
1067impl PartialEq for Field {
1068    fn eq(
1069        &self,
1070        Self {
1071            name,
1072            serde_name,
1073            description,
1074            deprecation_note,
1075            type_ref,
1076            required,
1077            flattened,
1078            transform_callback,
1079            transform_callback_fn: _,
1080        }: &Self,
1081    ) -> bool {
1082        self.name == *name
1083            && self.serde_name == *serde_name
1084            && self.description == *description
1085            && self.deprecation_note == *deprecation_note
1086            && self.type_ref == *type_ref
1087            && self.required == *required
1088            && self.flattened == *flattened
1089            && self.transform_callback == *transform_callback
1090    }
1091}
1092
1093impl Field {
1094    pub fn new(name: String, type_ref: TypeReference) -> Self {
1095        Field {
1096            name,
1097            type_ref,
1098            serde_name: Default::default(),
1099            description: Default::default(),
1100            deprecation_note: Default::default(),
1101            required: Default::default(),
1102            flattened: Default::default(),
1103            transform_callback: Default::default(),
1104            transform_callback_fn: Default::default(),
1105        }
1106    }
1107
1108    pub fn with_required(mut self, required: bool) -> Self {
1109        self.required = required;
1110        self
1111    }
1112
1113    pub fn name(&self) -> &str {
1114        self.name.as_str()
1115    }
1116
1117    pub fn is_named(&self) -> bool {
1118        !self.is_unnamed()
1119    }
1120
1121    pub fn is_unnamed(&self) -> bool {
1122        self.name.parse::<u64>().is_ok()
1123    }
1124
1125    pub fn serde_name(&self) -> &str {
1126        if self.serde_name.is_empty() {
1127            self.name.as_str()
1128        } else {
1129            self.serde_name.as_str()
1130        }
1131    }
1132
1133    pub fn description(&self) -> &str {
1134        self.description.as_str()
1135    }
1136
1137    pub fn deprecated(&self) -> bool {
1138        self.deprecation_note.is_some()
1139    }
1140
1141    pub fn type_ref(&self) -> &TypeReference {
1142        &self.type_ref
1143    }
1144
1145    pub fn required(&self) -> bool {
1146        self.required
1147    }
1148
1149    pub fn flattened(&self) -> bool {
1150        self.flattened
1151    }
1152
1153    pub fn transform_callback(&self) -> &str {
1154        self.transform_callback.as_str()
1155    }
1156
1157    pub fn transform_callback_fn(&self) -> Option<fn(&mut TypeReference, &Typespace)> {
1158        self.transform_callback_fn
1159    }
1160}
1161
1162fn is_false(b: &bool) -> bool {
1163    !*b
1164}
1165
1166fn is_default<T: Default + PartialEq>(t: &T) -> bool {
1167    *t == Default::default()
1168}
1169
1170#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
1171pub struct Enum {
1172    pub name: String,
1173    #[serde(skip_serializing_if = "String::is_empty", default)]
1174    pub serde_name: String,
1175    #[serde(skip_serializing_if = "String::is_empty", default)]
1176    pub description: String,
1177
1178    /// Generic type parameters, if any
1179    #[serde(skip_serializing_if = "Vec::is_empty", default)]
1180    pub parameters: Vec<TypeParameter>,
1181
1182    #[serde(skip_serializing_if = "Representation::is_default", default)]
1183    pub representation: Representation,
1184
1185    #[serde(skip_serializing_if = "Vec::is_empty", default)]
1186    pub variants: Vec<Variant>,
1187
1188    #[serde(skip_serializing_if = "is_default", default)]
1189    pub codegen_config: LanguageSpecificTypeCodegenConfig,
1190}
1191
1192impl Enum {
1193    pub fn new(name: String) -> Self {
1194        Enum {
1195            name,
1196            serde_name: Default::default(),
1197            description: Default::default(),
1198            parameters: Default::default(),
1199            representation: Default::default(),
1200            variants: Default::default(),
1201            codegen_config: Default::default(),
1202        }
1203    }
1204
1205    pub fn name(&self) -> &str {
1206        self.name.as_str()
1207    }
1208
1209    pub fn serde_name(&self) -> &str {
1210        if self.serde_name.is_empty() {
1211            self.name.as_str()
1212        } else {
1213            self.serde_name.as_str()
1214        }
1215    }
1216
1217    pub fn description(&self) -> &str {
1218        self.description.as_str()
1219    }
1220
1221    pub fn parameters(&self) -> std::slice::Iter<'_, TypeParameter> {
1222        self.parameters.iter()
1223    }
1224
1225    pub fn representation(&self) -> &Representation {
1226        &self.representation
1227    }
1228
1229    pub fn variants(&self) -> std::slice::Iter<'_, Variant> {
1230        self.variants.iter()
1231    }
1232}
1233
1234impl From<Enum> for Type {
1235    fn from(val: Enum) -> Self {
1236        Type::Enum(val)
1237    }
1238}
1239
1240#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
1241pub struct Variant {
1242    pub name: String,
1243    #[serde(skip_serializing_if = "String::is_empty", default)]
1244    pub serde_name: String,
1245    #[serde(skip_serializing_if = "String::is_empty", default)]
1246    pub description: String,
1247
1248    pub fields: Fields,
1249    #[serde(skip_serializing_if = "Option::is_none", default)]
1250    pub discriminant: Option<isize>,
1251
1252    /// If serde `untagged` attribute is set on a variant
1253    #[serde(skip_serializing_if = "is_false", default)]
1254    pub untagged: bool,
1255}
1256
1257impl Variant {
1258    pub fn new(name: String) -> Self {
1259        Variant {
1260            name,
1261            serde_name: String::new(),
1262            description: String::new(),
1263            fields: Fields::None,
1264            discriminant: None,
1265            untagged: false,
1266        }
1267    }
1268
1269    pub fn name(&self) -> &str {
1270        self.name.as_str()
1271    }
1272
1273    pub fn serde_name(&self) -> &str {
1274        if self.serde_name.is_empty() {
1275            self.name.as_str()
1276        } else {
1277            self.serde_name.as_str()
1278        }
1279    }
1280
1281    pub fn description(&self) -> &str {
1282        self.description.as_str()
1283    }
1284
1285    pub fn fields(&self) -> std::slice::Iter<'_, Field> {
1286        self.fields.iter()
1287    }
1288
1289    pub fn discriminant(&self) -> Option<isize> {
1290        self.discriminant
1291    }
1292
1293    pub fn untagged(&self) -> bool {
1294        self.untagged
1295    }
1296}
1297
1298#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash, Default)]
1299#[serde(rename_all = "snake_case")]
1300pub enum Representation {
1301    /// The default.
1302    ///
1303    /// ```json
1304    /// {"variant1": {"key1": "value1", "key2": "value2"}}
1305    /// ```
1306    #[default]
1307    External,
1308
1309    /// `#[serde(tag = "type")]`
1310    ///
1311    /// ```json
1312    /// {"type": "variant1", "key1": "value1", "key2": "value2"}
1313    /// ```
1314    Internal { tag: String },
1315
1316    /// `#[serde(tag = "t", content = "c")]`
1317    ///
1318    /// ```json
1319    /// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}}
1320    /// ```
1321    Adjacent { tag: String, content: String },
1322
1323    /// `#[serde(untagged)]`
1324    ///
1325    /// ```json
1326    /// {"key1": "value1", "key2": "value2"}
1327    /// ```
1328    None,
1329}
1330
1331impl Representation {
1332    pub fn new() -> Self {
1333        Default::default()
1334    }
1335
1336    pub fn is_default(&self) -> bool {
1337        matches!(self, Representation::External)
1338    }
1339
1340    pub fn is_external(&self) -> bool {
1341        matches!(self, Representation::External)
1342    }
1343
1344    pub fn is_internal(&self) -> bool {
1345        matches!(self, Representation::Internal { .. })
1346    }
1347
1348    pub fn is_adjacent(&self) -> bool {
1349        matches!(self, Representation::Adjacent { .. })
1350    }
1351
1352    pub fn is_none(&self) -> bool {
1353        matches!(self, Representation::None)
1354    }
1355}