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