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
1028impl Index<usize> for Fields {
1029    type Output = Field;
1030
1031    fn index(&self, index: usize) -> &Self::Output {
1032        match self {
1033            Fields::Named(fields) | Fields::Unnamed(fields) => &fields[index],
1034            Fields::None => panic!("index out of bounds"),
1035        }
1036    }
1037}
1038
1039impl IntoIterator for Fields {
1040    type Item = Field;
1041    type IntoIter = std::vec::IntoIter<Field>;
1042
1043    fn into_iter(self) -> Self::IntoIter {
1044        match self {
1045            Fields::Named(fields) => fields.into_iter(),
1046            Fields::Unnamed(fields) => fields.into_iter(),
1047            Fields::None => vec![].into_iter(),
1048        }
1049    }
1050}
1051
1052#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq)]
1053pub struct Field {
1054    /// Field name, should be a valid Rust field name identifier
1055    pub name: String,
1056    /// If a serialized name is not a valid Rust field name identifier
1057    /// then this defines the name of a field to be used in serialization
1058    #[serde(skip_serializing_if = "String::is_empty", default)]
1059    pub serde_name: String,
1060    /// Rust docs for the field
1061    #[serde(skip_serializing_if = "String::is_empty", default)]
1062    pub description: String,
1063
1064    /// Deprecation note. If none, field is not deprecated.
1065    /// If present as empty string, field is deprecated without a note.
1066    #[serde(skip_serializing_if = "Option::is_none", default)]
1067    pub deprecation_note: Option<String>,
1068
1069    /// Type of a field
1070    #[serde(rename = "type")]
1071    pub type_ref: TypeReference,
1072    /// required and not nullable:
1073    /// - field always present and not null / none
1074    ///
1075    /// required and nullable:
1076    /// - Rust: `Option<T>`, do not skip serializing if None
1077    /// - TypeScript: T | null, do not skip serializing if null
1078    ///
1079    /// not required and not nullable:
1080    /// - Rust: `Option<T>`, skip serializing if None
1081    /// - TypeScript: T | undefined, skip serializing if undefined
1082    ///
1083    /// not required and nullable:
1084    ///   serializers and deserializers are required to differentiate between
1085    ///   missing fields and null / none fields
1086    /// - Rust: `reflectapi::Option<T>` is enum with Undefined, None and Some variants
1087    /// - TypeScript: T | null | undefined
1088    ///
1089    /// Default is false
1090    #[serde(skip_serializing_if = "is_false", default)]
1091    pub required: bool,
1092    /// If serde flatten attribute is set on a field
1093    /// Default is false
1094    #[serde(skip_serializing_if = "is_false", default)]
1095    pub flattened: bool,
1096
1097    #[serde(skip, default)]
1098    pub transform_callback: String,
1099    #[serde(skip, default)]
1100    pub transform_callback_fn: Option<fn(&mut TypeReference, &Typespace) -> ()>,
1101}
1102
1103impl PartialEq for Field {
1104    fn eq(
1105        &self,
1106        Self {
1107            name,
1108            serde_name,
1109            description,
1110            deprecation_note,
1111            type_ref,
1112            required,
1113            flattened,
1114            transform_callback,
1115            transform_callback_fn: _,
1116        }: &Self,
1117    ) -> bool {
1118        self.name == *name
1119            && self.serde_name == *serde_name
1120            && self.description == *description
1121            && self.deprecation_note == *deprecation_note
1122            && self.type_ref == *type_ref
1123            && self.required == *required
1124            && self.flattened == *flattened
1125            && self.transform_callback == *transform_callback
1126    }
1127}
1128
1129impl std::hash::Hash for Field {
1130    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1131        self.name.hash(state);
1132        self.serde_name.hash(state);
1133        self.description.hash(state);
1134        self.deprecation_note.hash(state);
1135        self.type_ref.hash(state);
1136        self.required.hash(state);
1137        self.flattened.hash(state);
1138        self.transform_callback.hash(state);
1139    }
1140}
1141
1142impl Field {
1143    pub fn new(name: String, type_ref: TypeReference) -> Self {
1144        Field {
1145            name,
1146            type_ref,
1147            serde_name: Default::default(),
1148            description: Default::default(),
1149            deprecation_note: Default::default(),
1150            required: Default::default(),
1151            flattened: Default::default(),
1152            transform_callback: Default::default(),
1153            transform_callback_fn: Default::default(),
1154        }
1155    }
1156
1157    pub fn with_required(mut self, required: bool) -> Self {
1158        self.required = required;
1159        self
1160    }
1161
1162    pub fn name(&self) -> &str {
1163        self.name.as_str()
1164    }
1165
1166    pub fn is_named(&self) -> bool {
1167        !self.is_unnamed()
1168    }
1169
1170    pub fn is_unnamed(&self) -> bool {
1171        self.name.parse::<u64>().is_ok()
1172    }
1173
1174    pub fn serde_name(&self) -> &str {
1175        if self.serde_name.is_empty() {
1176            self.name.as_str()
1177        } else {
1178            self.serde_name.as_str()
1179        }
1180    }
1181
1182    pub fn description(&self) -> &str {
1183        self.description.as_str()
1184    }
1185
1186    pub fn deprecated(&self) -> bool {
1187        self.deprecation_note.is_some()
1188    }
1189
1190    pub fn type_ref(&self) -> &TypeReference {
1191        &self.type_ref
1192    }
1193
1194    pub fn required(&self) -> bool {
1195        self.required
1196    }
1197
1198    pub fn flattened(&self) -> bool {
1199        self.flattened
1200    }
1201
1202    pub fn transform_callback(&self) -> &str {
1203        self.transform_callback.as_str()
1204    }
1205
1206    pub fn transform_callback_fn(&self) -> Option<fn(&mut TypeReference, &Typespace)> {
1207        self.transform_callback_fn
1208    }
1209}
1210
1211fn is_false(b: &bool) -> bool {
1212    !*b
1213}
1214
1215#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
1216pub struct Enum {
1217    pub name: String,
1218    #[serde(skip_serializing_if = "String::is_empty", default)]
1219    pub serde_name: String,
1220    #[serde(skip_serializing_if = "String::is_empty", default)]
1221    pub description: String,
1222
1223    /// Generic type parameters, if any
1224    #[serde(skip_serializing_if = "Vec::is_empty", default)]
1225    pub parameters: Vec<TypeParameter>,
1226
1227    #[serde(skip_serializing_if = "Representation::is_default", default)]
1228    pub representation: Representation,
1229
1230    #[serde(skip_serializing_if = "Vec::is_empty", default)]
1231    pub variants: Vec<Variant>,
1232
1233    #[serde(
1234        skip_serializing_if = "LanguageSpecificTypeCodegenConfig::is_serialization_default",
1235        default
1236    )]
1237    pub codegen_config: LanguageSpecificTypeCodegenConfig,
1238}
1239
1240impl Enum {
1241    pub fn new(name: String) -> Self {
1242        Enum {
1243            name,
1244            serde_name: Default::default(),
1245            description: Default::default(),
1246            parameters: Default::default(),
1247            representation: Default::default(),
1248            variants: Default::default(),
1249            codegen_config: Default::default(),
1250        }
1251    }
1252
1253    pub fn name(&self) -> &str {
1254        self.name.as_str()
1255    }
1256
1257    pub fn serde_name(&self) -> &str {
1258        if self.serde_name.is_empty() {
1259            self.name.as_str()
1260        } else {
1261            self.serde_name.as_str()
1262        }
1263    }
1264
1265    pub fn description(&self) -> &str {
1266        self.description.as_str()
1267    }
1268
1269    pub fn parameters(&self) -> std::slice::Iter<'_, TypeParameter> {
1270        self.parameters.iter()
1271    }
1272
1273    pub fn representation(&self) -> &Representation {
1274        &self.representation
1275    }
1276
1277    pub fn variants(&self) -> std::slice::Iter<'_, Variant> {
1278        self.variants.iter()
1279    }
1280}
1281
1282impl From<Enum> for Type {
1283    fn from(val: Enum) -> Self {
1284        Type::Enum(val)
1285    }
1286}
1287
1288#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
1289pub struct Variant {
1290    pub name: String,
1291    #[serde(skip_serializing_if = "String::is_empty", default)]
1292    pub serde_name: String,
1293    #[serde(skip_serializing_if = "String::is_empty", default)]
1294    pub description: String,
1295
1296    pub fields: Fields,
1297    #[serde(skip_serializing_if = "Option::is_none", default)]
1298    pub discriminant: Option<isize>,
1299
1300    /// If serde `untagged` attribute is set on a variant
1301    #[serde(skip_serializing_if = "is_false", default)]
1302    pub untagged: bool,
1303}
1304
1305impl Variant {
1306    pub fn new(name: String) -> Self {
1307        Variant {
1308            name,
1309            serde_name: String::new(),
1310            description: String::new(),
1311            fields: Fields::None,
1312            discriminant: None,
1313            untagged: false,
1314        }
1315    }
1316
1317    pub fn name(&self) -> &str {
1318        self.name.as_str()
1319    }
1320
1321    pub fn serde_name(&self) -> &str {
1322        if self.serde_name.is_empty() {
1323            self.name.as_str()
1324        } else {
1325            self.serde_name.as_str()
1326        }
1327    }
1328
1329    pub fn description(&self) -> &str {
1330        self.description.as_str()
1331    }
1332
1333    pub fn fields(&self) -> std::slice::Iter<'_, Field> {
1334        self.fields.iter()
1335    }
1336
1337    pub fn discriminant(&self) -> Option<isize> {
1338        self.discriminant
1339    }
1340
1341    pub fn untagged(&self) -> bool {
1342        self.untagged
1343    }
1344}
1345
1346#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash, Default)]
1347#[serde(rename_all = "snake_case")]
1348pub enum Representation {
1349    /// The default.
1350    ///
1351    /// ```json
1352    /// {"variant1": {"key1": "value1", "key2": "value2"}}
1353    /// ```
1354    #[default]
1355    External,
1356
1357    /// `#[serde(tag = "type")]`
1358    ///
1359    /// ```json
1360    /// {"type": "variant1", "key1": "value1", "key2": "value2"}
1361    /// ```
1362    Internal { tag: String },
1363
1364    /// `#[serde(tag = "t", content = "c")]`
1365    ///
1366    /// ```json
1367    /// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}}
1368    /// ```
1369    Adjacent { tag: String, content: String },
1370
1371    /// `#[serde(untagged)]`
1372    ///
1373    /// ```json
1374    /// {"key1": "value1", "key2": "value2"}
1375    /// ```
1376    None,
1377}
1378
1379impl Representation {
1380    pub fn new() -> Self {
1381        Default::default()
1382    }
1383
1384    pub fn is_default(&self) -> bool {
1385        matches!(self, Representation::External)
1386    }
1387
1388    pub fn is_external(&self) -> bool {
1389        matches!(self, Representation::External)
1390    }
1391
1392    pub fn is_internal(&self) -> bool {
1393        matches!(self, Representation::Internal { .. })
1394    }
1395
1396    pub fn is_adjacent(&self) -> bool {
1397        matches!(self, Representation::Adjacent { .. })
1398    }
1399
1400    pub fn is_none(&self) -> bool {
1401        matches!(self, Representation::None)
1402    }
1403}
1404
1405#[cfg(test)]
1406mod tests {
1407    use super::*;
1408
1409    fn primitive(name: &str) -> Type {
1410        Type::Primitive(Primitive {
1411            name: name.to_string(),
1412            description: String::new(),
1413            parameters: vec![],
1414            fallback: None,
1415            codegen_config: LanguageSpecificTypeCodegenConfig::default(),
1416        })
1417    }
1418
1419    /// Regression: `remove_type` used to drop only the removed key
1420    /// from `types_map` while `Vec::remove` shifted every later
1421    /// element's index down by one. The next call would either
1422    /// panic on an out-of-bounds slot or silently return the wrong
1423    /// type. The fix is to invalidate the whole map after removal
1424    /// so the next access rebuilds it.
1425    #[test]
1426    fn remove_type_keeps_map_consistent_across_multiple_removals() {
1427        let mut ts = Typespace::default();
1428        ts.insert_type(primitive("a"));
1429        ts.insert_type(primitive("b"));
1430        ts.insert_type(primitive("c"));
1431        ts.insert_type(primitive("d"));
1432
1433        // Remove two — the second one used to land on a stale index.
1434        let _ = ts.remove_type("b");
1435        let _ = ts.remove_type("c");
1436
1437        assert!(ts.has_type("a"), "untouched type 'a' should still resolve");
1438        assert!(ts.has_type("d"), "untouched type 'd' should still resolve");
1439        assert!(!ts.has_type("b"));
1440        assert!(!ts.has_type("c"));
1441
1442        // Each surviving lookup should return the right Type, not
1443        // some other slot that the stale index pointed at.
1444        assert_eq!(ts.get_type("a").map(|t| t.name()), Some("a"));
1445        assert_eq!(ts.get_type("d").map(|t| t.name()), Some("d"));
1446    }
1447
1448    #[test]
1449    fn remove_type_returns_the_value_we_asked_for() {
1450        let mut ts = Typespace::default();
1451        ts.insert_type(primitive("first"));
1452        ts.insert_type(primitive("second"));
1453        ts.insert_type(primitive("third"));
1454
1455        let removed = ts.remove_type("second").expect("should find 'second'");
1456        assert_eq!(removed.name(), "second");
1457
1458        // The other two must still be there at the right names.
1459        assert_eq!(ts.get_type("first").map(|t| t.name()), Some("first"));
1460        assert_eq!(ts.get_type("third").map(|t| t.name()), Some("third"));
1461    }
1462}