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    /// Remove fields marked as `hidden` from all struct and enum variant fields
204    /// in both input and output typespaces. Intended to be called at codegen
205    /// entry points so that no backend can accidentally leak hidden fields.
206    pub fn strip_hidden_fields(&mut self) {
207        fn strip(ts: &mut Typespace) {
208            for ty in ts.types.iter_mut() {
209                match ty {
210                    Type::Struct(s) => s.fields.retain(|f| !f.hidden),
211                    Type::Enum(e) => {
212                        for v in e.variants.iter_mut() {
213                            v.fields.retain(|f| !f.hidden);
214                        }
215                    }
216                    Type::Primitive(_) => {}
217                }
218            }
219        }
220        strip(&mut self.input_types);
221        strip(&mut self.output_types);
222    }
223
224    pub fn fold_transparent_types(&mut self) {
225        // Replace the transparent struct `strukt` with it's single field.
226        #[derive(Debug)]
227        struct SubstVisitor {
228            strukt: Struct,
229            to: TypeReference,
230        }
231
232        impl SubstVisitor {
233            fn new(strukt: Struct) -> Self {
234                assert!(strukt.transparent && strukt.fields.len() == 1);
235                Self {
236                    to: strukt.fields[0].type_ref.clone(),
237                    strukt,
238                }
239            }
240        }
241
242        impl Visitor for SubstVisitor {
243            type Output = ();
244
245            fn visit_type_ref(
246                &mut self,
247                type_ref: &mut TypeReference,
248            ) -> ControlFlow<Self::Output, Self::Output> {
249                if type_ref.name == self.strukt.name {
250                    let subst = subst::mk_subst(&self.strukt.parameters, &type_ref.arguments);
251                    *type_ref = self.to.clone().subst(&subst);
252                }
253
254                type_ref.visit_mut(self)?;
255
256                ControlFlow::Continue(())
257            }
258        }
259
260        let transparent_types = self
261            .input_types()
262            .types()
263            .filter_map(|t| {
264                t.as_struct()
265                    .filter(|i| i.transparent && i.fields.len() == 1)
266                    .cloned()
267            })
268            .collect::<Vec<_>>();
269
270        for strukt in transparent_types {
271            self.input_types.remove_type(strukt.name());
272            let _ = SubstVisitor::new(strukt).visit_schema_inputs(self);
273        }
274
275        let transparent_types = self
276            .output_types()
277            .types()
278            .filter_map(|t| {
279                t.as_struct()
280                    .filter(|i| i.transparent && i.fields.len() == 1)
281                    .cloned()
282            })
283            .collect::<Vec<_>>();
284
285        for strukt in transparent_types {
286            self.output_types.remove_type(strukt.name());
287            let _ = SubstVisitor::new(strukt).visit_schema_outputs(self);
288        }
289    }
290}
291
292#[derive(Clone, serde::Serialize, serde::Deserialize, Default)]
293pub struct Typespace {
294    #[serde(skip_serializing_if = "Vec::is_empty", default)]
295    types: Vec<Type>,
296
297    #[serde(skip_serializing, default)]
298    types_map: std::cell::RefCell<HashMap<String, usize>>,
299}
300
301impl fmt::Debug for Typespace {
302    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303        f.debug_map()
304            .entries(self.types.iter().map(|t| (t.name().to_string(), t)))
305            .finish()
306    }
307}
308
309impl Typespace {
310    pub fn new() -> Self {
311        Typespace {
312            types: Vec::new(),
313            types_map: std::cell::RefCell::new(HashMap::new()),
314        }
315    }
316
317    pub fn is_empty(&self) -> bool {
318        self.types.is_empty()
319    }
320
321    pub fn types(&self) -> std::slice::Iter<'_, Type> {
322        self.types.iter()
323    }
324
325    pub fn get_type(&self, name: &str) -> Option<&Type> {
326        self.ensure_types_map();
327        let index = {
328            let b = self.types_map.borrow();
329            b.get(name).copied().unwrap_or(usize::MAX)
330        };
331        if index == usize::MAX {
332            return None;
333        }
334        self.types.get(index)
335    }
336
337    pub fn get_type_mut(&mut self, name: &str) -> Option<&mut Type> {
338        self.ensure_types_map();
339        let index = {
340            let b = self.types_map.borrow();
341            b.get(name).copied().unwrap_or(usize::MAX)
342        };
343        if index == usize::MAX {
344            return None;
345        }
346        self.types.get_mut(index)
347    }
348
349    pub fn reserve_type(&mut self, name: &str) -> bool {
350        self.ensure_types_map();
351        if self.types_map.borrow().contains_key(name) {
352            return false;
353        }
354        self.types_map.borrow_mut().insert(name.into(), usize::MAX);
355        true
356    }
357
358    pub fn insert_type(&mut self, ty: Type) {
359        self.ensure_types_map();
360        if let Some(index) = self.types_map.borrow().get(ty.name()) {
361            if index != &usize::MAX {
362                return;
363            }
364        }
365        self.types_map
366            .borrow_mut()
367            .insert(ty.name().into(), self.types.len());
368        self.types.push(ty);
369    }
370
371    pub fn remove_type(&mut self, ty: &str) -> Option<Type> {
372        self.ensure_types_map();
373        let index = self
374            .types_map
375            .borrow()
376            .get(ty)
377            .copied()
378            .unwrap_or(usize::MAX);
379        if index == usize::MAX {
380            return None;
381        }
382
383        let removed = self.types.remove(index);
384        // `Vec::remove` shifts every later element down by one, so all
385        // map entries that pointed past `index` are now stale. Drop
386        // the whole map; the next `ensure_types_map` rebuilds it.
387        // (Removing the single key for `ty` and leaving the rest
388        // alone — the previous behaviour — was the bug.)
389        self.invalidate_types_map();
390        Some(removed)
391    }
392
393    pub fn sort_types(&mut self) {
394        self.types.sort_by(|a, b| a.name().cmp(b.name()));
395        self.build_types_map();
396    }
397
398    pub fn has_type(&self, name: &str) -> bool {
399        self.ensure_types_map();
400        self.types_map.borrow().contains_key(name)
401    }
402
403    pub fn extend(&mut self, other: Self) {
404        self.ensure_types_map();
405        for ty in other.types {
406            if self.has_type(ty.name()) {
407                continue;
408            }
409            self.insert_type(ty);
410        }
411    }
412
413    fn invalidate_types_map(&self) {
414        self.types_map.borrow_mut().clear()
415    }
416
417    fn ensure_types_map(&self) {
418        if self.types_map.borrow().is_empty() && !self.types.is_empty() {
419            self.build_types_map();
420        }
421    }
422
423    fn build_types_map(&self) {
424        let mut types_map = HashMap::new();
425        for (i, ty) in self.types.iter().enumerate() {
426            types_map.insert(ty.name().into(), i);
427        }
428        *(self.types_map.borrow_mut()) = types_map;
429    }
430}
431
432#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
433pub struct Function {
434    /// Includes entity and action, for example: users.login
435    pub name: String,
436    /// URL mounting path, for example: /api/v1
437    pub path: String,
438    /// Description of the call
439    #[serde(skip_serializing_if = "String::is_empty", default)]
440    pub description: String,
441    /// Deprecation note. If none, function is not deprecated.
442    /// If present as empty string, function is deprecated without a note.
443    #[serde(skip_serializing_if = "Option::is_none", default)]
444    pub deprecation_note: Option<String>,
445
446    #[serde(skip_serializing_if = "Option::is_none", default)]
447    pub input_type: Option<TypeReference>,
448    #[serde(skip_serializing_if = "Option::is_none", default)]
449    pub input_headers: Option<TypeReference>,
450
451    #[serde(skip_serializing_if = "Option::is_none", default)]
452    pub error_type: Option<TypeReference>,
453
454    #[serde(flatten)]
455    pub output_type: OutputType,
456
457    /// Supported content types for request and response bodies.
458    ///
459    /// Note: serialization for header values is not affected by this field.
460    /// For displayable types of fields, it is encoded in plain strings.
461    /// For non-displayable types, it is encoded as json.
462    ///
463    /// Default: only json if empty
464    ///
465    #[serde(skip_serializing_if = "Vec::is_empty", default)]
466    pub serialization: Vec<SerializationMode>,
467
468    /// If a function is readonly, it means it does not modify the state of an application
469    #[serde(skip_serializing_if = "is_false", default)]
470    pub readonly: bool,
471
472    #[serde(skip_serializing_if = "BTreeSet::is_empty", default)]
473    pub tags: BTreeSet<String>,
474}
475
476impl Function {
477    pub fn new(name: String) -> Self {
478        Function {
479            name,
480            deprecation_note: Default::default(),
481            path: Default::default(),
482            description: Default::default(),
483            input_type: None,
484            input_headers: None,
485            error_type: None,
486            output_type: OutputType::Complete { output_type: None },
487            serialization: Default::default(),
488            readonly: Default::default(),
489            tags: Default::default(),
490        }
491    }
492
493    pub fn name(&self) -> &str {
494        self.name.as_str()
495    }
496
497    pub fn path(&self) -> &str {
498        self.path.as_str()
499    }
500
501    pub fn description(&self) -> &str {
502        self.description.as_str()
503    }
504
505    pub fn deprecated(&self) -> bool {
506        self.deprecation_note.is_some()
507    }
508
509    pub fn input_type(&self) -> Option<&TypeReference> {
510        self.input_type.as_ref()
511    }
512
513    pub fn input_headers(&self) -> Option<&TypeReference> {
514        self.input_headers.as_ref()
515    }
516
517    pub fn output_type(&self) -> &OutputType {
518        &self.output_type
519    }
520
521    pub fn serialization(&self) -> std::slice::Iter<'_, SerializationMode> {
522        self.serialization.iter()
523    }
524
525    pub fn readonly(&self) -> bool {
526        self.readonly
527    }
528}
529
530#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
531#[serde(tag = "output_kind", rename_all = "snake_case")]
532pub enum OutputType {
533    Complete {
534        #[serde(skip_serializing_if = "Option::is_none", default)]
535        output_type: Option<TypeReference>,
536    },
537    Stream {
538        item_type: TypeReference,
539    },
540}
541
542impl OutputType {
543    pub fn type_refs(&self) -> Vec<&TypeReference> {
544        match self {
545            OutputType::Complete {
546                output_type: Some(output_type),
547            } => vec![output_type],
548            OutputType::Complete { output_type: None } => vec![],
549            OutputType::Stream { item_type } => vec![item_type],
550        }
551    }
552}
553
554#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
555#[serde(rename_all = "snake_case")]
556pub enum SerializationMode {
557    #[default]
558    Json,
559    Msgpack,
560}
561
562#[derive(
563    Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord,
564)]
565pub struct TypeReference {
566    pub name: String,
567    /**
568     * References to actual types to use instead of the type parameters
569     * declared on the referred generic type
570     */
571    #[serde(skip_serializing_if = "Vec::is_empty", default)]
572    pub arguments: Vec<TypeReference>,
573}
574
575impl TypeReference {
576    pub fn new(name: impl Into<String>, arguments: Vec<TypeReference>) -> Self {
577        TypeReference {
578            name: name.into(),
579            arguments,
580        }
581    }
582
583    pub fn name(&self) -> &str {
584        self.name.as_str()
585    }
586
587    pub fn arguments(&self) -> std::slice::Iter<'_, TypeReference> {
588        self.arguments.iter()
589    }
590
591    pub fn fallback_recursively(&mut self, schema: &Typespace) {
592        loop {
593            let Some(type_def) = schema.get_type(self.name()) else {
594                return;
595            };
596            let Some(fallback_type_ref) = type_def.fallback_internal(self) else {
597                return;
598            };
599            *self = fallback_type_ref;
600        }
601    }
602
603    pub fn fallback_once(&self, schema: &Typespace) -> Option<TypeReference> {
604        let type_def = schema.get_type(self.name())?;
605        type_def.fallback_internal(self)
606    }
607}
608
609impl From<&str> for TypeReference {
610    fn from(name: &str) -> Self {
611        TypeReference::new(name, Vec::new())
612    }
613}
614
615impl From<String> for TypeReference {
616    fn from(name: String) -> Self {
617        TypeReference::new(name, Vec::new())
618    }
619}
620
621#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
622pub struct TypeParameter {
623    pub name: String,
624    #[serde(skip_serializing_if = "String::is_empty", default)]
625    pub description: String,
626}
627
628impl TypeParameter {
629    pub fn new(name: String, description: String) -> Self {
630        TypeParameter { name, description }
631    }
632
633    pub fn name(&self) -> &str {
634        self.name.as_str()
635    }
636
637    pub fn description(&self) -> &str {
638        self.description.as_str()
639    }
640}
641
642impl From<&str> for TypeParameter {
643    fn from(name: &str) -> Self {
644        TypeParameter {
645            name: name.into(),
646            description: String::new(),
647        }
648    }
649}
650
651impl From<String> for TypeParameter {
652    fn from(name: String) -> Self {
653        TypeParameter {
654            name,
655            description: String::new(),
656        }
657    }
658}
659
660impl PartialEq for TypeParameter {
661    fn eq(&self, other: &Self) -> bool {
662        self.name == other.name
663    }
664}
665
666impl Eq for TypeParameter {}
667
668impl std::hash::Hash for TypeParameter {
669    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
670        self.name.hash(state);
671    }
672}
673
674#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
675#[serde(rename_all = "snake_case", tag = "kind")]
676pub enum Type {
677    Primitive(Primitive),
678    Struct(Struct),
679    Enum(Enum),
680}
681
682impl Type {
683    pub fn name(&self) -> &str {
684        match self {
685            Type::Primitive(p) => &p.name,
686            Type::Struct(s) => &s.name,
687            Type::Enum(e) => &e.name,
688        }
689    }
690
691    pub fn serde_name(&self) -> &str {
692        match self {
693            Type::Primitive(_) => self.name(),
694            Type::Struct(s) => s.serde_name(),
695            Type::Enum(e) => e.serde_name(),
696        }
697    }
698
699    pub fn description(&self) -> &str {
700        match self {
701            Type::Primitive(p) => &p.description,
702            Type::Struct(s) => &s.description,
703            Type::Enum(e) => &e.description,
704        }
705    }
706
707    pub fn parameters(&self) -> std::slice::Iter<'_, TypeParameter> {
708        match self {
709            Type::Primitive(p) => p.parameters(),
710            Type::Struct(s) => s.parameters(),
711            Type::Enum(e) => e.parameters(),
712        }
713    }
714
715    pub fn as_struct(&self) -> Option<&Struct> {
716        match self {
717            Type::Struct(s) => Some(s),
718            _ => None,
719        }
720    }
721
722    pub fn is_struct(&self) -> bool {
723        matches!(self, Type::Struct(_))
724    }
725
726    pub fn as_enum(&self) -> Option<&Enum> {
727        match self {
728            Type::Enum(e) => Some(e),
729            _ => None,
730        }
731    }
732
733    pub fn is_enum(&self) -> bool {
734        matches!(self, Type::Enum(_))
735    }
736
737    pub fn as_primitive(&self) -> Option<&Primitive> {
738        match self {
739            Type::Primitive(p) => Some(p),
740            _ => None,
741        }
742    }
743
744    pub fn is_primitive(&self) -> bool {
745        matches!(self, Type::Primitive(_))
746    }
747
748    fn fallback_internal(&self, origin: &TypeReference) -> Option<TypeReference> {
749        match self {
750            Type::Primitive(p) => p.fallback_internal(origin),
751            Type::Struct(_) => None,
752            Type::Enum(_) => None,
753        }
754    }
755
756    pub fn __internal_rename_current(&mut self, new_name: String) {
757        match self {
758            Type::Primitive(p) => p.name = new_name,
759            Type::Struct(s) => s.name = new_name,
760            Type::Enum(e) => e.name = new_name,
761        }
762    }
763
764    pub fn __internal_rebind_generic_parameters(
765        &mut self,
766        unresolved_to_resolved_map: &std::collections::HashMap<TypeReference, TypeReference>,
767        schema: &Typespace,
768    ) {
769        internal::replace_type_references_for_type(self, unresolved_to_resolved_map, schema)
770    }
771}
772
773#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash)]
774pub struct Primitive {
775    pub name: String,
776    #[serde(skip_serializing_if = "String::is_empty", default)]
777    pub description: String,
778
779    /// Generic type parameters, if any
780    #[serde(skip_serializing_if = "Vec::is_empty", default)]
781    pub parameters: Vec<TypeParameter>,
782
783    /// Fallback type to use when the type is not supported by the target language
784    #[serde(skip_serializing_if = "Option::is_none", default)]
785    pub fallback: Option<TypeReference>,
786
787    #[serde(
788        skip_serializing_if = "LanguageSpecificTypeCodegenConfig::is_serialization_default",
789        default
790    )]
791    pub codegen_config: LanguageSpecificTypeCodegenConfig,
792}
793
794impl Primitive {
795    pub fn new(
796        name: String,
797        description: String,
798        parameters: Vec<TypeParameter>,
799        fallback: Option<TypeReference>,
800    ) -> Self {
801        Primitive {
802            name,
803            description,
804            parameters,
805            fallback,
806            codegen_config: Default::default(),
807        }
808    }
809
810    pub fn name(&self) -> &str {
811        self.name.as_str()
812    }
813
814    pub fn description(&self) -> &str {
815        self.description.as_str()
816    }
817
818    pub fn parameters(&self) -> std::slice::Iter<'_, TypeParameter> {
819        self.parameters.iter()
820    }
821
822    pub fn fallback(&self) -> Option<&TypeReference> {
823        self.fallback.as_ref()
824    }
825
826    fn fallback_internal(&self, origin: &TypeReference) -> Option<TypeReference> {
827        // example:
828        // Self is DashMap<K, V>
829        // fallback is HashSet<V> (stupid example, but it demos generic param discard)
830        // origin is DashMap<String, u8>
831        // It should transform origin to HashSet<u8>
832        let fallback = self.fallback.as_ref()?;
833
834        if let Some((type_def_param_index, _)) = self
835            .parameters()
836            .enumerate()
837            .find(|(_, type_def_param)| type_def_param.name() == fallback.name())
838        {
839            // this is the case when fallback is to one of the generic parameters
840            // for example, Arc<T> to T
841            let Some(origin_type_ref_param) = origin.arguments.get(type_def_param_index) else {
842                // It means the origin type reference does no provide correct number of generic parameters
843                // required by the type definition
844                // It is invalid schema
845                return None;
846            };
847            return Some(TypeReference {
848                name: origin_type_ref_param.name.clone(),
849                arguments: origin_type_ref_param.arguments.clone(),
850            });
851        }
852
853        let mut new_arguments_for_origin = Vec::new();
854        for fallback_type_ref_param in fallback.arguments() {
855            let Some((type_def_param_index, _)) =
856                self.parameters().enumerate().find(|(_, type_def_param)| {
857                    type_def_param.name() == fallback_type_ref_param.name()
858                })
859            else {
860                // It means fallback type does not have
861                // as much generic parameters as this type definition
862                // in our example, it would be index 0
863                continue;
864            };
865
866            // in our example type_def_param_index would be index 1 for V
867            let Some(origin_type_ref_param) = origin.arguments.get(type_def_param_index) else {
868                // It means the origin type reference does no provide correct number of generic parameters
869                // required by the type definition
870                // It is invalid schema
871                return None;
872            };
873            new_arguments_for_origin.push(origin_type_ref_param.clone());
874        }
875
876        Some(TypeReference {
877            name: fallback.name.clone(),
878            arguments: new_arguments_for_origin,
879        })
880    }
881}
882
883impl From<Primitive> for Type {
884    fn from(val: Primitive) -> Self {
885        Type::Primitive(val)
886    }
887}
888
889#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
890pub struct Struct {
891    /// Name of a struct, should be a valid Rust struct name identifier
892    pub name: String,
893
894    /// If a serialized name is not a valid Rust struct name identifier
895    /// then this defines the name of a struct to be used in serialization
896    #[serde(skip_serializing_if = "String::is_empty", default)]
897    pub serde_name: String,
898
899    /// Markdown docs for the struct
900    #[serde(skip_serializing_if = "String::is_empty", default)]
901    pub description: String,
902
903    /// Generic type parameters, if any
904    #[serde(skip_serializing_if = "Vec::is_empty", default)]
905    pub parameters: Vec<TypeParameter>,
906
907    pub fields: Fields,
908
909    /// If serde transparent attribute is set on a struct
910    #[serde(skip_serializing_if = "is_false", default)]
911    pub transparent: bool,
912
913    #[serde(
914        skip_serializing_if = "LanguageSpecificTypeCodegenConfig::is_serialization_default",
915        default
916    )]
917    pub codegen_config: LanguageSpecificTypeCodegenConfig,
918}
919
920impl Struct {
921    pub fn new(name: impl Into<String>) -> Self {
922        let name = name.into();
923        Struct {
924            name,
925            serde_name: Default::default(),
926            description: Default::default(),
927            parameters: Default::default(),
928            fields: Default::default(),
929            transparent: Default::default(),
930            codegen_config: Default::default(),
931        }
932    }
933
934    /// Returns the name of a struct, should be a valid Rust struct name identifier
935    pub fn name(&self) -> &str {
936        self.name.as_str()
937    }
938
939    /// Returns the name of a struct to be used in serialization
940    pub fn serde_name(&self) -> &str {
941        if self.serde_name.is_empty() {
942            self.name.as_str()
943        } else {
944            self.serde_name.as_str()
945        }
946    }
947
948    pub fn description(&self) -> &str {
949        self.description.as_str()
950    }
951
952    pub fn parameters(&self) -> std::slice::Iter<'_, TypeParameter> {
953        self.parameters.iter()
954    }
955
956    pub fn fields(&self) -> std::slice::Iter<'_, Field> {
957        self.fields.iter()
958    }
959
960    pub fn transparent(&self) -> bool {
961        self.transparent
962    }
963
964    /// Returns true if a struct has 1 field and it is either named "0"
965    /// or is transparent in the serialized form
966    pub fn is_alias(&self) -> bool {
967        self.fields.len() == 1 && (self.fields[0].name() == "0" || self.transparent)
968    }
969
970    /// Returns true is a struct is a Rust unit struct.
971    /// Please note, that a unit struct is also an alias
972    // NOTE(andy): does this function make sense? A unit struct is a struct with no fields.
973    pub fn is_unit(&self) -> bool {
974        let Some(first_field) = self.fields.iter().next() else {
975            return false;
976        };
977
978        self.fields.len() == 1
979            && first_field.name() == "0"
980            && first_field.type_ref.name == "std::tuple::Tuple0"
981            && !first_field.required
982    }
983
984    /// Returns true if a struct is a Rust tuple struct.
985    pub fn is_tuple(&self) -> bool {
986        !self.fields.is_empty()
987            && self
988                .fields
989                .iter()
990                .all(|f| f.name().parse::<usize>().is_ok())
991    }
992}
993
994impl From<Struct> for Type {
995    fn from(val: Struct) -> Self {
996        Type::Struct(val)
997    }
998}
999
1000#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Default)]
1001#[serde(rename_all = "snake_case")]
1002pub enum Fields {
1003    /// Named struct or variant:
1004    /// struct S { a: u8, b: u8 }
1005    /// enum S { T { a: u8, b: u8 } }
1006    Named(Vec<Field>),
1007    /// Tuple struct or variant:
1008    /// struct S(u8, u8);
1009    /// enum S { T(u8, u8) }
1010    Unnamed(Vec<Field>),
1011    /// Unit struct or variant:
1012    ///
1013    /// struct S;
1014    /// enum S { U }
1015    #[default]
1016    None,
1017}
1018
1019impl Fields {
1020    pub fn is_empty(&self) -> bool {
1021        match self {
1022            Fields::Named(fields) | Fields::Unnamed(fields) => fields.is_empty(),
1023            Fields::None => true,
1024        }
1025    }
1026
1027    pub fn len(&self) -> usize {
1028        match self {
1029            Fields::Named(fields) | Fields::Unnamed(fields) => fields.len(),
1030            Fields::None => 0,
1031        }
1032    }
1033
1034    pub fn iter(&self) -> std::slice::Iter<'_, Field> {
1035        match self {
1036            Fields::Named(fields) | Fields::Unnamed(fields) => fields.iter(),
1037            Fields::None => [].iter(),
1038        }
1039    }
1040
1041    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Field> {
1042        match self {
1043            Fields::Named(fields) | Fields::Unnamed(fields) => fields.iter_mut(),
1044            Fields::None => [].iter_mut(),
1045        }
1046    }
1047
1048    /// Keep only fields for which `predicate` returns `true`.
1049    pub fn retain<F>(&mut self, mut predicate: F)
1050    where
1051        F: FnMut(&Field) -> bool,
1052    {
1053        match self {
1054            Fields::Named(fields) | Fields::Unnamed(fields) => fields.retain(|f| predicate(f)),
1055            Fields::None => {}
1056        }
1057    }
1058}
1059
1060impl Index<usize> for Fields {
1061    type Output = Field;
1062
1063    fn index(&self, index: usize) -> &Self::Output {
1064        match self {
1065            Fields::Named(fields) | Fields::Unnamed(fields) => &fields[index],
1066            Fields::None => panic!("index out of bounds"),
1067        }
1068    }
1069}
1070
1071impl IntoIterator for Fields {
1072    type Item = Field;
1073    type IntoIter = std::vec::IntoIter<Field>;
1074
1075    fn into_iter(self) -> Self::IntoIter {
1076        match self {
1077            Fields::Named(fields) => fields.into_iter(),
1078            Fields::Unnamed(fields) => fields.into_iter(),
1079            Fields::None => vec![].into_iter(),
1080        }
1081    }
1082}
1083
1084#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq)]
1085pub struct Field {
1086    /// Field name, should be a valid Rust field name identifier
1087    pub name: String,
1088    /// If a serialized name is not a valid Rust field name identifier
1089    /// then this defines the name of a field to be used in serialization
1090    #[serde(skip_serializing_if = "String::is_empty", default)]
1091    pub serde_name: String,
1092    /// Rust docs for the field
1093    #[serde(skip_serializing_if = "String::is_empty", default)]
1094    pub description: String,
1095
1096    /// Deprecation note. If none, field is not deprecated.
1097    /// If present as empty string, field is deprecated without a note.
1098    #[serde(skip_serializing_if = "Option::is_none", default)]
1099    pub deprecation_note: Option<String>,
1100
1101    /// Type of a field
1102    #[serde(rename = "type")]
1103    pub type_ref: TypeReference,
1104    /// required and not nullable:
1105    /// - field always present and not null / none
1106    ///
1107    /// required and nullable:
1108    /// - Rust: `Option<T>`, do not skip serializing if None
1109    /// - TypeScript: T | null, do not skip serializing if null
1110    ///
1111    /// not required and not nullable:
1112    /// - Rust: `Option<T>`, skip serializing if None
1113    /// - TypeScript: T | undefined, skip serializing if undefined
1114    ///
1115    /// not required and nullable:
1116    ///   serializers and deserializers are required to differentiate between
1117    ///   missing fields and null / none fields
1118    /// - Rust: `reflectapi::Option<T>` is enum with Undefined, None and Some variants
1119    /// - TypeScript: T | null | undefined
1120    ///
1121    /// Default is false
1122    #[serde(skip_serializing_if = "is_false", default)]
1123    pub required: bool,
1124    /// If serde flatten attribute is set on a field
1125    /// Default is false
1126    #[serde(skip_serializing_if = "is_false", default)]
1127    pub flattened: bool,
1128
1129    /// If true, the field is excluded from generated clients and documentation
1130    /// but is still functional at runtime (e.g. for header extraction).
1131    /// Default is false
1132    #[serde(skip_serializing_if = "is_false", default)]
1133    pub hidden: bool,
1134
1135    #[serde(skip, default)]
1136    pub transform_callback: String,
1137    #[serde(skip, default)]
1138    pub transform_callback_fn: Option<fn(&mut TypeReference, &Typespace) -> ()>,
1139}
1140
1141impl PartialEq for Field {
1142    fn eq(
1143        &self,
1144        Self {
1145            name,
1146            serde_name,
1147            description,
1148            deprecation_note,
1149            type_ref,
1150            required,
1151            flattened,
1152            hidden,
1153            transform_callback,
1154            transform_callback_fn: _,
1155        }: &Self,
1156    ) -> bool {
1157        self.name == *name
1158            && self.serde_name == *serde_name
1159            && self.description == *description
1160            && self.deprecation_note == *deprecation_note
1161            && self.type_ref == *type_ref
1162            && self.required == *required
1163            && self.flattened == *flattened
1164            && self.hidden == *hidden
1165            && self.transform_callback == *transform_callback
1166    }
1167}
1168
1169impl std::hash::Hash for Field {
1170    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1171        self.name.hash(state);
1172        self.serde_name.hash(state);
1173        self.description.hash(state);
1174        self.deprecation_note.hash(state);
1175        self.type_ref.hash(state);
1176        self.required.hash(state);
1177        self.flattened.hash(state);
1178        self.hidden.hash(state);
1179        self.transform_callback.hash(state);
1180    }
1181}
1182
1183impl Field {
1184    pub fn new(name: String, type_ref: TypeReference) -> Self {
1185        Field {
1186            name,
1187            type_ref,
1188            serde_name: Default::default(),
1189            description: Default::default(),
1190            deprecation_note: Default::default(),
1191            required: Default::default(),
1192            flattened: Default::default(),
1193            hidden: Default::default(),
1194            transform_callback: Default::default(),
1195            transform_callback_fn: Default::default(),
1196        }
1197    }
1198
1199    pub fn with_required(mut self, required: bool) -> Self {
1200        self.required = required;
1201        self
1202    }
1203
1204    pub fn name(&self) -> &str {
1205        self.name.as_str()
1206    }
1207
1208    pub fn is_named(&self) -> bool {
1209        !self.is_unnamed()
1210    }
1211
1212    pub fn is_unnamed(&self) -> bool {
1213        self.name.parse::<u64>().is_ok()
1214    }
1215
1216    pub fn serde_name(&self) -> &str {
1217        if self.serde_name.is_empty() {
1218            self.name.as_str()
1219        } else {
1220            self.serde_name.as_str()
1221        }
1222    }
1223
1224    pub fn description(&self) -> &str {
1225        self.description.as_str()
1226    }
1227
1228    pub fn deprecated(&self) -> bool {
1229        self.deprecation_note.is_some()
1230    }
1231
1232    pub fn hidden(&self) -> bool {
1233        self.hidden
1234    }
1235
1236    pub fn type_ref(&self) -> &TypeReference {
1237        &self.type_ref
1238    }
1239
1240    pub fn required(&self) -> bool {
1241        self.required
1242    }
1243
1244    pub fn flattened(&self) -> bool {
1245        self.flattened
1246    }
1247
1248    pub fn transform_callback(&self) -> &str {
1249        self.transform_callback.as_str()
1250    }
1251
1252    pub fn transform_callback_fn(&self) -> Option<fn(&mut TypeReference, &Typespace)> {
1253        self.transform_callback_fn
1254    }
1255}
1256
1257fn is_false(b: &bool) -> bool {
1258    !*b
1259}
1260
1261#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
1262pub struct Enum {
1263    pub name: String,
1264    #[serde(skip_serializing_if = "String::is_empty", default)]
1265    pub serde_name: String,
1266    #[serde(skip_serializing_if = "String::is_empty", default)]
1267    pub description: String,
1268
1269    /// Generic type parameters, if any
1270    #[serde(skip_serializing_if = "Vec::is_empty", default)]
1271    pub parameters: Vec<TypeParameter>,
1272
1273    #[serde(skip_serializing_if = "Representation::is_default", default)]
1274    pub representation: Representation,
1275
1276    #[serde(skip_serializing_if = "Vec::is_empty", default)]
1277    pub variants: Vec<Variant>,
1278
1279    #[serde(
1280        skip_serializing_if = "LanguageSpecificTypeCodegenConfig::is_serialization_default",
1281        default
1282    )]
1283    pub codegen_config: LanguageSpecificTypeCodegenConfig,
1284}
1285
1286impl Enum {
1287    pub fn new(name: String) -> Self {
1288        Enum {
1289            name,
1290            serde_name: Default::default(),
1291            description: Default::default(),
1292            parameters: Default::default(),
1293            representation: Default::default(),
1294            variants: Default::default(),
1295            codegen_config: Default::default(),
1296        }
1297    }
1298
1299    pub fn name(&self) -> &str {
1300        self.name.as_str()
1301    }
1302
1303    pub fn serde_name(&self) -> &str {
1304        if self.serde_name.is_empty() {
1305            self.name.as_str()
1306        } else {
1307            self.serde_name.as_str()
1308        }
1309    }
1310
1311    pub fn description(&self) -> &str {
1312        self.description.as_str()
1313    }
1314
1315    pub fn parameters(&self) -> std::slice::Iter<'_, TypeParameter> {
1316        self.parameters.iter()
1317    }
1318
1319    pub fn representation(&self) -> &Representation {
1320        &self.representation
1321    }
1322
1323    pub fn variants(&self) -> std::slice::Iter<'_, Variant> {
1324        self.variants.iter()
1325    }
1326}
1327
1328impl From<Enum> for Type {
1329    fn from(val: Enum) -> Self {
1330        Type::Enum(val)
1331    }
1332}
1333
1334#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
1335pub struct Variant {
1336    pub name: String,
1337    #[serde(skip_serializing_if = "String::is_empty", default)]
1338    pub serde_name: String,
1339    #[serde(skip_serializing_if = "String::is_empty", default)]
1340    pub description: String,
1341
1342    pub fields: Fields,
1343    #[serde(skip_serializing_if = "Option::is_none", default)]
1344    pub discriminant: Option<isize>,
1345
1346    /// If serde `untagged` attribute is set on a variant
1347    #[serde(skip_serializing_if = "is_false", default)]
1348    pub untagged: bool,
1349}
1350
1351impl Variant {
1352    pub fn new(name: String) -> Self {
1353        Variant {
1354            name,
1355            serde_name: String::new(),
1356            description: String::new(),
1357            fields: Fields::None,
1358            discriminant: None,
1359            untagged: false,
1360        }
1361    }
1362
1363    pub fn name(&self) -> &str {
1364        self.name.as_str()
1365    }
1366
1367    pub fn serde_name(&self) -> &str {
1368        if self.serde_name.is_empty() {
1369            self.name.as_str()
1370        } else {
1371            self.serde_name.as_str()
1372        }
1373    }
1374
1375    pub fn description(&self) -> &str {
1376        self.description.as_str()
1377    }
1378
1379    pub fn fields(&self) -> std::slice::Iter<'_, Field> {
1380        self.fields.iter()
1381    }
1382
1383    pub fn discriminant(&self) -> Option<isize> {
1384        self.discriminant
1385    }
1386
1387    pub fn untagged(&self) -> bool {
1388        self.untagged
1389    }
1390}
1391
1392#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash, Default)]
1393#[serde(rename_all = "snake_case")]
1394pub enum Representation {
1395    /// The default.
1396    ///
1397    /// ```json
1398    /// {"variant1": {"key1": "value1", "key2": "value2"}}
1399    /// ```
1400    #[default]
1401    External,
1402
1403    /// `#[serde(tag = "type")]`
1404    ///
1405    /// ```json
1406    /// {"type": "variant1", "key1": "value1", "key2": "value2"}
1407    /// ```
1408    Internal { tag: String },
1409
1410    /// `#[serde(tag = "t", content = "c")]`
1411    ///
1412    /// ```json
1413    /// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}}
1414    /// ```
1415    Adjacent { tag: String, content: String },
1416
1417    /// `#[serde(untagged)]`
1418    ///
1419    /// ```json
1420    /// {"key1": "value1", "key2": "value2"}
1421    /// ```
1422    None,
1423}
1424
1425impl Representation {
1426    pub fn new() -> Self {
1427        Default::default()
1428    }
1429
1430    pub fn is_default(&self) -> bool {
1431        matches!(self, Representation::External)
1432    }
1433
1434    pub fn is_external(&self) -> bool {
1435        matches!(self, Representation::External)
1436    }
1437
1438    pub fn is_internal(&self) -> bool {
1439        matches!(self, Representation::Internal { .. })
1440    }
1441
1442    pub fn is_adjacent(&self) -> bool {
1443        matches!(self, Representation::Adjacent { .. })
1444    }
1445
1446    pub fn is_none(&self) -> bool {
1447        matches!(self, Representation::None)
1448    }
1449}
1450
1451#[cfg(test)]
1452mod tests {
1453    use super::*;
1454
1455    fn primitive(name: &str) -> Type {
1456        Type::Primitive(Primitive {
1457            name: name.to_string(),
1458            description: String::new(),
1459            parameters: vec![],
1460            fallback: None,
1461            codegen_config: LanguageSpecificTypeCodegenConfig::default(),
1462        })
1463    }
1464
1465    /// Regression: `remove_type` used to drop only the removed key
1466    /// from `types_map` while `Vec::remove` shifted every later
1467    /// element's index down by one. The next call would either
1468    /// panic on an out-of-bounds slot or silently return the wrong
1469    /// type. The fix is to invalidate the whole map after removal
1470    /// so the next access rebuilds it.
1471    #[test]
1472    fn remove_type_keeps_map_consistent_across_multiple_removals() {
1473        let mut ts = Typespace::default();
1474        ts.insert_type(primitive("a"));
1475        ts.insert_type(primitive("b"));
1476        ts.insert_type(primitive("c"));
1477        ts.insert_type(primitive("d"));
1478
1479        // Remove two — the second one used to land on a stale index.
1480        let _ = ts.remove_type("b");
1481        let _ = ts.remove_type("c");
1482
1483        assert!(ts.has_type("a"), "untouched type 'a' should still resolve");
1484        assert!(ts.has_type("d"), "untouched type 'd' should still resolve");
1485        assert!(!ts.has_type("b"));
1486        assert!(!ts.has_type("c"));
1487
1488        // Each surviving lookup should return the right Type, not
1489        // some other slot that the stale index pointed at.
1490        assert_eq!(ts.get_type("a").map(|t| t.name()), Some("a"));
1491        assert_eq!(ts.get_type("d").map(|t| t.name()), Some("d"));
1492    }
1493
1494    #[test]
1495    fn remove_type_returns_the_value_we_asked_for() {
1496        let mut ts = Typespace::default();
1497        ts.insert_type(primitive("first"));
1498        ts.insert_type(primitive("second"));
1499        ts.insert_type(primitive("third"));
1500
1501        let removed = ts.remove_type("second").expect("should find 'second'");
1502        assert_eq!(removed.name(), "second");
1503
1504        // The other two must still be there at the right names.
1505        assert_eq!(ts.get_type("first").map(|t| t.name()), Some("first"));
1506        assert_eq!(ts.get_type("third").map(|t| t.name()), Some("third"));
1507    }
1508}