xsd_parser/generator/
mod.rs

1//! The `generator` module contains the code [`Generator`] and all related types.
2
3pub mod renderer;
4
5mod context;
6mod data;
7mod error;
8mod helper;
9mod misc;
10
11use std::collections::{BTreeMap, HashSet, VecDeque};
12use std::fmt::Display;
13use std::str::FromStr;
14
15use proc_macro2::{Ident as Ident2, TokenStream};
16use quote::{format_ident, ToTokens};
17use renderer::{Renderer, TypesRenderer};
18use smallvec::{smallvec, SmallVec};
19use tracing::instrument;
20
21use crate::code::{format_module_ident, format_type_ident, IdentPath, Module};
22use crate::schema::NamespaceId;
23use crate::types::{Ident, IdentType, Name, Type, TypeVariant, Types};
24
25pub use self::context::Context;
26pub use self::data::{
27    BuildInType, ComplexType, ComplexTypeAttribute, ComplexTypeBase, ComplexTypeContent,
28    ComplexTypeElement, ComplexTypeEnum, ComplexTypeStruct, DerivedType, DynamicType,
29    EnumerationType, EnumerationTypeVariant, ReferenceType, StructMode, TypeData, UnionType,
30    UnionTypeVariant,
31};
32pub use self::error::Error;
33pub use self::misc::{BoxFlags, GeneratorFlags, SerdeSupport, TypedefMode};
34
35use self::helper::Walk;
36use self::misc::{DynTypeTraits, PendingType, TraitInfos, TypeRef};
37
38/// Type that is used to generate rust code from a [`Types`] object.
39#[must_use]
40#[derive(Debug)]
41pub struct Generator<'types> {
42    config: Config<'types>,
43    state: State<'types>,
44    renderers: Vec<Box<dyn Renderer>>,
45}
46
47/// Type that is used to generate rust code from a [`Types`] object.
48///
49/// In contrast to [`Generator`] this type does not allow changes to the
50/// configuration of the generator, because at least one type was already
51/// generated.
52#[must_use]
53#[derive(Debug)]
54pub struct GeneratorFixed<'types> {
55    config: Config<'types>,
56    state: State<'types>,
57    module: Module,
58    renderers: Vec<Box<dyn Renderer>>,
59}
60
61/// Contains the configuration of the generator.
62#[derive(Debug)]
63pub struct Config<'types> {
64    /// Reference to the types the code should be generated for.
65    pub types: &'types Types,
66
67    /// Flags that controls the behavior of the generator.
68    pub flags: GeneratorFlags,
69
70    /// Traits the generator should derive the generated types from.
71    pub derive: Vec<Ident2>,
72
73    /// List of postfixed to add to the name of the generated types.
74    ///
75    /// This corresponds to the variants of [`IdentType`].
76    pub postfixes: [String; 8],
77
78    /// Tells the generator how to deal with boxed elements.
79    pub box_flags: BoxFlags,
80
81    /// Tells the generator how to deal with type definitions.
82    pub typedef_mode: TypedefMode,
83
84    /// Tells the generator if and how to generate code to support [`serde`].
85    pub serde_support: SerdeSupport,
86
87    /// List of traits that should be implemented by dynamic types.
88    pub dyn_type_traits: DynTypeTraits,
89
90    /// Name of the `xsd_parser` crate.
91    pub xsd_parser_crate: Ident2,
92}
93
94#[derive(Debug)]
95struct State<'types> {
96    cache: BTreeMap<Ident, TypeRef>,
97    trait_infos: Option<TraitInfos>,
98    pending: VecDeque<PendingType<'types>>,
99}
100
101/* Generator */
102
103impl<'types> Generator<'types> {
104    /// Create a new code generator from the passed `types`.
105    pub fn new(types: &'types Types) -> Self {
106        let config = Config {
107            types,
108            flags: GeneratorFlags::empty(),
109            derive: vec![format_ident!("Debug")],
110            postfixes: [
111                String::from("Type"),        // Type = 0
112                String::new(),               // Group = 1
113                String::from("ElementType"), // Element = 2
114                String::new(),               // ElementType = 3
115                String::new(),               // Attribute = 4
116                String::new(),               // AttributeGroup = 5
117                String::new(),               // BuildIn = 6
118                String::new(),               // Enumeration = 7
119            ],
120            box_flags: BoxFlags::AUTO,
121            typedef_mode: TypedefMode::Auto,
122            serde_support: SerdeSupport::None,
123            dyn_type_traits: DynTypeTraits::Auto,
124            xsd_parser_crate: format_ident!("xsd_parser"),
125        };
126        let state = State {
127            cache: BTreeMap::new(),
128            trait_infos: None,
129            pending: VecDeque::new(),
130        };
131        let renderers = Vec::new();
132
133        Self {
134            config,
135            state,
136            renderers,
137        }
138    }
139
140    /// Set the name of the `xsd-parser` create that the generator should use for
141    /// generating the code.
142    pub fn xsd_parser_crate<S: Display>(mut self, value: S) -> Self {
143        self.config.xsd_parser_crate = format_ident!("{value}");
144
145        self
146    }
147
148    /// Set the traits the generated types should derive from.
149    ///
150    /// Default is `Debug` and `Clone`.
151    ///
152    /// # Examples
153    ///
154    /// ```ignore
155    /// let generator = Generator::new(types)
156    ///     .derive(["Debug", "Clone", "Eq", "PartialEq", "Ord", "PartialOrd"]);
157    /// ```
158    pub fn derive<I>(mut self, value: I) -> Self
159    where
160        I: IntoIterator,
161        I::Item: Display,
162    {
163        self.config.derive = value.into_iter().map(|x| format_ident!("{x}")).collect();
164
165        self
166    }
167
168    /// Set the traits that should be implemented by dynamic types.
169    ///
170    /// The passed values must be valid type paths.
171    ///
172    /// # Errors
173    ///
174    /// Will raise a [`InvalidIdentifier`](Error::InvalidIdentifier) error
175    /// if the passed strings does not represent a valid identifier.
176    ///
177    /// # Examples
178    ///
179    /// ```ignore
180    /// let generator = Generator::new(types)
181    ///     .dyn_type_traits(["core::fmt::Debug", "core::any::Any"]);
182    /// ```
183    pub fn dyn_type_traits<I>(mut self, value: I) -> Result<Self, Error>
184    where
185        I: IntoIterator,
186        I::Item: AsRef<str>,
187    {
188        let traits = value
189            .into_iter()
190            .map(|x| {
191                let s = x.as_ref();
192                IdentPath::from_str(s).map_err(|()| Error::InvalidIdentifier(s.into()))
193            })
194            .collect::<Result<Vec<_>, _>>()?;
195
196        self.config.dyn_type_traits = DynTypeTraits::Custom(traits);
197
198        Ok(self)
199    }
200
201    /// Set the [`BoxFlags`] flags the generator should use for generating the code.
202    pub fn box_flags(mut self, value: BoxFlags) -> Self {
203        self.config.box_flags = value;
204
205        self
206    }
207
208    /// Set the [`TypedefMode`] value the generator should use for generating the code.
209    pub fn typedef_mode(mut self, value: TypedefMode) -> Self {
210        self.config.typedef_mode = value;
211
212        self
213    }
214
215    /// Set the [`SerdeSupport`] value the generator should use for generating the code.
216    pub fn serde_support(mut self, value: SerdeSupport) -> Self {
217        self.config.serde_support = value;
218
219        self
220    }
221
222    /// Set the [`GeneratorFlags`] flags the generator should use for generating the code.
223    pub fn flags(mut self, value: GeneratorFlags) -> Self {
224        self.config.flags = value;
225
226        self
227    }
228
229    /// Add the passed [`GeneratorFlags`] flags the generator should use for generating the code.
230    pub fn with_flags(mut self, value: GeneratorFlags) -> Self {
231        self.config.flags |= value;
232
233        self
234    }
235
236    /// Set the postfixes the generator should use for the different types.
237    ///
238    /// Default is `"Type"` for the [`IdentType::Type`] type and `""` for the other types.
239    pub fn with_type_postfix<S: Into<String>>(mut self, type_: IdentType, postfix: S) -> Self {
240        self.config.postfixes[type_ as usize] = postfix.into();
241
242        self
243    }
244
245    /// Add a custom implemented type to the generator.
246    ///
247    /// This will add a custom implemented type to the generator. These types are
248    /// usually implemented and provided by the user of the generated code. The
249    /// generator will just reference to the type definition and will not generate
250    /// any code related to this type.
251    ///
252    /// # Errors
253    ///
254    /// Returns an error if the namespace of the passed identifier is unknown.
255    ///
256    /// # Examples
257    ///
258    /// ```ignore
259    /// let generator = Generator::new(types)
260    ///     .with_type(Ident::type_("UserDefinedType"));
261    /// ```
262    pub fn with_type(mut self, ident: Ident) -> Result<Self, Error> {
263        let module_ident = format_module(self.config.types, ident.ns)?;
264        let type_ident = format_ident!("{}", ident.name.to_string());
265
266        let type_ref = TypeRef {
267            ident: ident.clone(),
268            module_ident,
269            type_ident,
270            boxed_elements: HashSet::new(),
271        };
272        self.state.cache.insert(ident, type_ref);
273
274        Ok(self)
275    }
276
277    /// Add a [`Renderer`] to the generator.
278    pub fn with_renderer<X>(mut self, renderer: X) -> Self
279    where
280        X: Renderer + 'static,
281    {
282        self.renderers.push(Box::new(renderer));
283
284        self
285    }
286
287    /// Add the default renderers to the generator.
288    pub fn with_default_renderers(self) -> Self {
289        self.with_renderer(TypesRenderer)
290    }
291
292    /// Remove all [`Renderer`]s from the generator.
293    pub fn clear_renderers(mut self) -> Self {
294        self.renderers.clear();
295
296        self
297    }
298
299    /// Will fix the generator by call [`into_fixed`](Self::into_fixed) and then
300    /// [`generate_type`](GeneratorFixed::generate_type).
301    #[instrument(err, level = "trace", skip(self))]
302    pub fn generate_type(self, ident: Ident) -> Result<GeneratorFixed<'types>, Error> {
303        self.into_fixed().generate_type(ident)
304    }
305
306    /// Will fix the generator by call [`into_fixed`](Self::into_fixed) and then
307    /// [`generate_all_types`](GeneratorFixed::generate_all_types).
308    ///
309    /// # Errors
310    ///
311    /// Will just forward the errors from [`generate_all_types`](GeneratorFixed::generate_all_types).
312    pub fn generate_all_types(self) -> Result<GeneratorFixed<'types>, Error> {
313        self.into_fixed().generate_all_types()
314    }
315
316    /// Will convert the generator into a [`GeneratorFixed`].
317    pub fn into_fixed(self) -> GeneratorFixed<'types> {
318        let Self {
319            mut config,
320            state,
321            mut renderers,
322        } = self;
323        let module = Module::default();
324
325        config.dyn_type_traits = match config.dyn_type_traits {
326            DynTypeTraits::Auto => {
327                let traits = config.derive.iter().map(|x| match x.to_string().as_ref() {
328                    "Debug" => IdentPath::from_str("core::fmt::Debug").unwrap(),
329                    "Hash" => IdentPath::from_str("core::hash::Hash").unwrap(),
330                    _ => IdentPath::from_ident(x.clone()),
331                });
332
333                let serde: SmallVec<[IdentPath; 2]> = if config.serde_support == SerdeSupport::None
334                {
335                    smallvec![]
336                } else {
337                    smallvec![
338                        IdentPath::from_str("serde::Serialize").unwrap(),
339                        IdentPath::from_str("serde::DeserializeOwned").unwrap()
340                    ]
341                };
342
343                let as_any = IdentPath::from_parts(
344                    Some(config.xsd_parser_crate.clone()),
345                    format_ident!("AsAny"),
346                );
347
348                DynTypeTraits::Custom(traits.chain(serde).chain(Some(as_any)).collect())
349            }
350            x => x,
351        };
352
353        for renderer in &mut renderers {
354            renderer.initialize(&mut config);
355        }
356
357        GeneratorFixed {
358            config,
359            state,
360            module,
361            renderers,
362        }
363    }
364}
365
366impl<'types> GeneratorFixed<'types> {
367    /// Generate the code for the given type.
368    ///
369    /// This will generate the code for the passed type identifier and all
370    /// dependencies of this type.
371    ///
372    /// # Examples
373    ///
374    /// ```ignore
375    /// let generator = Generator::new(types)
376    ///     .generate_type(Ident::type_("Root"));
377    /// ```
378    #[instrument(err, level = "trace", skip(self))]
379    pub fn generate_type(mut self, ident: Ident) -> Result<GeneratorFixed<'types>, Error> {
380        self.state.get_or_create_type_ref(&self.config, ident)?;
381        self.generate_pending()?;
382
383        Ok(self)
384    }
385
386    /// Generate the code for all types.
387    ///
388    /// This will generate the code for all types that are specified in
389    /// the [`Types`] object passed to the generator.
390    ///
391    /// # Examples
392    ///
393    /// ```ignore
394    /// let generator = Generator::new(types)
395    ///     .generate_all_types();
396    /// ```
397    #[instrument(err, level = "trace", skip(self))]
398    pub fn generate_all_types(mut self) -> Result<Self, Error> {
399        for ident in self.config.types.keys() {
400            self.state
401                .get_or_create_type_ref(&self.config, ident.clone())?;
402        }
403        self.generate_pending()?;
404
405        Ok(self)
406    }
407
408    /// Generate the code for all named types.
409    ///
410    /// This will generate the code for all types with an explicit name and all
411    /// dependencies of these types that are specified in the [`Types`] object
412    /// passed to the generator.
413    ///
414    /// # Examples
415    ///
416    /// ```ignore
417    /// let generator = Generator::new(types)
418    ///     .generate_named_types();
419    /// ```
420    #[instrument(err, level = "trace", skip(self))]
421    pub fn generate_named_types(mut self) -> Result<Self, Error> {
422        for ident in self.config.types.keys() {
423            if ident.name.is_named() {
424                self.state
425                    .get_or_create_type_ref(&self.config, ident.clone())?;
426            }
427        }
428        self.generate_pending()?;
429
430        Ok(self)
431    }
432
433    /// Finish the code generation.
434    ///
435    /// This will return the generated code as [`TokenStream`].
436    #[instrument(level = "trace", skip(self))]
437    pub fn finish(self) -> TokenStream {
438        let Self {
439            config,
440            mut module,
441            state: _,
442            mut renderers,
443        } = self;
444
445        for renderer in &mut renderers {
446            renderer.finish(&config, &mut module);
447        }
448
449        module.to_token_stream()
450    }
451
452    #[instrument(err, level = "trace", skip(self))]
453    fn generate_pending(&mut self) -> Result<(), Error> {
454        while let Some(args) = self.state.pending.pop_front() {
455            self.generate_type_intern(args)?;
456        }
457
458        Ok(())
459    }
460
461    #[instrument(err, level = "trace", skip(self))]
462    fn generate_type_intern(&mut self, data: PendingType<'types>) -> Result<(), Error> {
463        let PendingType { ty, ident } = data;
464        let Self {
465            config,
466            state,
467            module,
468            renderers,
469        } = self;
470        let ty = TypeData::new(ty, &ident, config, state)?;
471        let mut ctx = Context::new(&ident, config, module);
472
473        tracing::debug!("Render type: {ident}");
474
475        for renderer in renderers {
476            renderer.render_type(&mut ctx, &ty);
477        }
478
479        Ok(())
480    }
481}
482
483impl Config<'_> {
484    fn check_flags(&self, flags: GeneratorFlags) -> bool {
485        self.flags.intersects(flags)
486    }
487}
488
489impl<'types> State<'types> {
490    #[instrument(level = "trace", skip(self, config))]
491    fn get_or_create_type_ref(
492        &mut self,
493        config: &Config<'types>,
494        ident: Ident,
495    ) -> Result<&TypeRef, Error> {
496        if !self.cache.contains_key(&ident) {
497            let ty = config
498                .types
499                .get(&ident)
500                .ok_or_else(|| Error::UnknownType(ident.clone()))?;
501            let name = make_type_name(&config.postfixes, ty, &ident);
502            let (module_ident, type_ident) = if let TypeVariant::BuildIn(x) = &ty.variant {
503                (None, format_ident!("{x}"))
504            } else {
505                let use_modules = config.flags.intersects(GeneratorFlags::USE_MODULES);
506                let module_ident =
507                    format_module(config.types, use_modules.then_some(ident.ns).flatten())?;
508                let type_ident = format_type_ident(&name, ty.display_name.as_deref());
509
510                (module_ident, type_ident)
511            };
512
513            tracing::debug!("Queue new type generation: {ident}");
514
515            let boxed_elements = get_boxed_elements(&ident, ty, config.types, &self.cache);
516            self.pending.push_back(PendingType {
517                ty,
518                ident: ident.clone(),
519            });
520
521            let type_ref = TypeRef {
522                ident: ident.clone(),
523                type_ident,
524                module_ident,
525                boxed_elements,
526            };
527
528            assert!(self.cache.insert(ident.clone(), type_ref).is_none());
529        }
530
531        Ok(self.cache.get_mut(&ident).unwrap())
532    }
533}
534
535/* Helper */
536
537fn get_boxed_elements<'a>(
538    ident: &Ident,
539    mut ty: &'a Type,
540    types: &'a Types,
541    cache: &BTreeMap<Ident, TypeRef>,
542) -> HashSet<Ident> {
543    if let TypeVariant::ComplexType(ci) = &ty.variant {
544        if let Some(type_) = ci.content.as_ref().and_then(|ident| types.get(ident)) {
545            ty = type_;
546        }
547    }
548
549    match &ty.variant {
550        TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si) => si
551            .elements
552            .iter()
553            .filter_map(|f| {
554                if Walk::new(types, cache).is_loop(ident, &f.type_) {
555                    Some(f.ident.clone())
556                } else {
557                    None
558                }
559            })
560            .collect(),
561        _ => HashSet::new(),
562    }
563}
564
565fn make_type_name(postfixes: &[String], ty: &Type, ident: &Ident) -> Name {
566    if let TypeVariant::Reference(ti) = &ty.variant {
567        if ident.name.is_generated() && ti.type_.name.is_named() {
568            if ti.min_occurs > 1 {
569                return Name::new_generated(format!("{}List", ti.type_.name.to_type_name()));
570            } else if ti.min_occurs == 0 {
571                return Name::new_generated(format!("{}Opt", ti.type_.name.to_type_name()));
572            }
573        }
574    }
575
576    let postfix = postfixes
577        .get(ident.type_ as usize)
578        .map_or("", |s| s.as_str());
579
580    let s = ident.name.to_type_name();
581
582    if s.ends_with(postfix) {
583        ident.name.clone()
584    } else {
585        Name::new_generated(format!("{s}{postfix}"))
586    }
587}
588
589fn format_module(types: &Types, ns: Option<NamespaceId>) -> Result<Option<Ident2>, Error> {
590    let Some(ns) = ns else {
591        return Ok(None);
592    };
593
594    let module = types.modules.get(&ns).ok_or(Error::UnknownNamespace(ns))?;
595    let Some(name) = &module.name else {
596        return Ok(None);
597    };
598
599    Ok(Some(format_module_ident(name)))
600}