Skip to main content

reflectapi_schema/
lib.rs

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