xsd_parser/generator/
mod.rs

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