Skip to main content

reflectapi_schema/
lib.rs

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