xsd_parser/config/
renderer.rs

1use std::any::{Any, TypeId};
2use std::fmt::Debug;
3
4use bitflags::bitflags;
5
6use xsd_parser_types::misc::Namespace;
7
8use crate::models::code::IdentPath;
9use crate::pipeline::renderer::{
10    NamespaceSerialization, RenderStep as RenderStepTrait, RenderStepType,
11};
12
13/// Configuration for the actual code rendering.
14#[derive(Debug)]
15pub struct RendererConfig {
16    /// List of renderers to use for code rendering.
17    pub steps: Vec<Box<dyn RenderStepConfig>>,
18
19    /// Additional flags to control the renderer.
20    pub flags: RendererFlags,
21
22    /// Sets the traits the generated types should derive from.
23    ///
24    /// See [`derive`](crate::Renderer::derive) for more details.
25    pub derive: Option<Vec<String>>,
26
27    /// Name of the `alloc` crate that is used for the generated code.
28    pub alloc: String,
29
30    /// Set the traits that should be implemented by dynamic types.
31    ///
32    /// See [`dyn_type_traits`](crate::Renderer::dyn_type_traits) for more details.
33    pub dyn_type_traits: Option<Vec<String>>,
34
35    /// Name of the `xsd-parser-types` crate that is used for the generated code.
36    pub xsd_parser_types: String,
37}
38
39impl Default for RendererConfig {
40    fn default() -> Self {
41        Self {
42            steps: vec![Box::new(RenderStep::Types)],
43            flags: RendererFlags::empty(),
44            derive: None,
45            alloc: "std".into(),
46            dyn_type_traits: None,
47            xsd_parser_types: "xsd_parser_types".into(),
48        }
49    }
50}
51
52impl Clone for RendererConfig {
53    fn clone(&self) -> Self {
54        Self {
55            steps: self.steps.iter().map(|x| x.boxed_clone()).collect(),
56            flags: self.flags,
57            derive: self.derive.clone(),
58            alloc: self.alloc.clone(),
59            dyn_type_traits: self.dyn_type_traits.clone(),
60            xsd_parser_types: self.xsd_parser_types.clone(),
61        }
62    }
63}
64
65bitflags! {
66    /// Different flags that control what code the [`Renderer`](super::Renderer)
67    /// is generating.
68    #[derive(Debug, Clone, Copy)]
69    pub struct RendererFlags: u32 {
70        /// None of the features are enabled.
71        ///
72        /// # Examples
73        ///
74        /// Consider the following XML schema:
75        /// ```xml
76        #[doc = include_str!("../../tests/renderer/renderer_flags/schema.xsd")]
77        /// ```
78        ///
79        /// Setting none of the flags will result in the following code:
80        /// ```rust
81        #[doc = include_str!("../../tests/renderer/renderer_flags/expected/empty.rs")]
82        /// ```
83        const NONE = 0;
84
85        /// The renderer adds documentation to the rendered code if a
86        /// `xs:documentation` element was placed in the schema.
87        ///
88        /// # Examples
89        ///
90        /// Consider the following XML schema:
91        /// ```xml
92        #[doc = include_str!("../../tests/renderer/renderer_flags/schema_with_docs.xsd")]
93        /// ```
94        ///
95        /// Enable the `RENDER_DOCS` feature only will result in the following code:
96        /// ```rust
97        #[doc = include_str!("../../tests/renderer/renderer_flags/expected/render_docs.rs")]
98        /// ```
99        const RENDER_DOCS = Self::RENDER_TYPE_DOCS.bits()
100            | Self::RENDER_ELEMENT_DOCS.bits()
101            | Self::RENDER_ATTRIBUTE_DOCS.bits()
102            | Self::RENDER_VARIANT_DOCS.bits();
103
104        /// The renderer adds documentation to the rendered types if a
105        /// `xs:documentation` element was placed in the schema.
106        ///
107        /// See [`RENDER_DOCS`](Self::RENDER_DOCS) for details.
108        const RENDER_TYPE_DOCS = 1 << 0;
109
110        /// The renderer adds documentation to the rendered elements if a
111        /// `xs:documentation` element was placed in the schema.
112        ///
113        /// See [`RENDER_DOCS`](Self::RENDER_DOCS) for details.
114        const RENDER_ELEMENT_DOCS = 1 << 1;
115
116        /// The renderer adds documentation to the rendered attributes if a
117        /// `xs:documentation` element was placed in the schema.
118        ///
119        /// See [`RENDER_DOCS`](Self::RENDER_DOCS) for details.
120        const RENDER_ATTRIBUTE_DOCS = 1 << 2;
121
122        /// The renderer adds documentation to the rendered enum variants for
123        /// `xs:enumeration` types if a `xs:documentation` element was placed
124        /// in the schema.
125        ///
126        /// See [`RENDER_DOCS`](Self::RENDER_DOCS) for details.
127        const RENDER_VARIANT_DOCS = 1 << 3;
128    }
129}
130
131/// Configuration for the [`RenderSteps`](crate::pipeline::renderer::RenderStep)s
132/// the [`Renderer`](crate::Renderer) should use for rendering the code.
133///
134/// Caution: Some render steps are incompatible to each other (e.g. only
135/// one `TypesXXX` step should be used, because they render the general type
136/// structure). While other render steps depend on each other (e.g. `QuickXmlXXX`
137/// depends on `Types` and `NamespaceConstants`).
138#[derive(Debug, Clone)]
139pub enum RenderStep {
140    /// Step to render the pure types.
141    Types,
142
143    /// Step to render the types with `serde-xml-rs` support.
144    TypesSerdeXmlRs {
145        /// Version of `serde-xml-rs` to render the code for.
146        version: SerdeXmlRsVersion,
147    },
148
149    /// Step to render the types with `quick_xml` serde support.
150    TypesSerdeQuickXml,
151
152    /// Renderer to render associated methods that return the default values
153    /// of the different fields of a struct.
154    Defaults,
155
156    /// Renderer to add constants for the namespaces to the generated code.
157    NamespaceConstants,
158
159    /// Renderer to add constants for the namespace prefixes to the generated code.
160    PrefixConstants,
161
162    /// Renderer that adds the [`WithNamespace`](xsd_parser_types::WithNamespace) trait to
163    /// the generated types.
164    WithNamespaceTrait,
165
166    /// Renderer that renders code for the `quick_xml` serializer of the
167    /// different types.
168    QuickXmlSerialize {
169        /// Whether to add namespaces to the root element during serialization or not.
170        namespaces: NamespaceSerialization,
171
172        /// Default namespace to use for the serialization.
173        default_namespace: Option<Namespace>,
174    },
175
176    /// Renderer that renders code for the `quick_xml` deserializer of the
177    /// different types.
178    QuickXmlDeserialize {
179        /// Whether to box the deserializer or not.
180        ///
181        /// For more details have a look at [`QuickXmlDeserializeRenderer::boxed_deserializer`](crate::pipeline::renderer::QuickXmlDeserializeRenderStep::boxed_deserializer).
182        boxed_deserializer: bool,
183    },
184}
185
186/// Helper trait to deal with custom render steps.
187pub trait RenderStepConfig: Debug + Any {
188    /// Returns a boxed clone of the current object.
189    fn boxed_clone(&self) -> Box<dyn RenderStepConfig>;
190
191    /// Creates the actual render step and returned it as a box.
192    fn into_render_step(self: Box<Self>) -> Box<dyn RenderStepTrait>;
193
194    /// Returns the type of this render step.
195    fn render_step_type(&self) -> RenderStepType {
196        RenderStepType::Undefined
197    }
198
199    /// Returns `true` if `self` is mutual exclusive to `other`, `false` otherwise.
200    fn is_mutual_exclusive_to(&self, other: &dyn RenderStepConfig) -> bool {
201        self.type_id() == other.type_id()
202            || self
203                .render_step_type()
204                .is_mutual_exclusive_to(other.render_step_type())
205    }
206}
207
208impl<X> RenderStepConfig for X
209where
210    X: RenderStepTrait + Clone + Any + 'static,
211{
212    fn render_step_type(&self) -> RenderStepType {
213        X::render_step_type(self)
214    }
215
216    fn boxed_clone(&self) -> Box<dyn RenderStepConfig> {
217        Box::new(self.clone())
218    }
219
220    fn into_render_step(self: Box<Self>) -> Box<dyn RenderStepTrait> {
221        self
222    }
223}
224
225impl RenderStepConfig for RenderStep {
226    fn render_step_type(&self) -> RenderStepType {
227        match self {
228            Self::Types => RenderStepType::Types,
229            Self::TypesSerdeXmlRs { .. } => RenderStepType::Types,
230            Self::TypesSerdeQuickXml => RenderStepType::Types,
231            Self::Defaults => RenderStepType::ExtraImpls,
232            Self::PrefixConstants => RenderStepType::ExtraImpls,
233            Self::NamespaceConstants => RenderStepType::ExtraImpls,
234            Self::WithNamespaceTrait => RenderStepType::ExtraImpls,
235            Self::QuickXmlSerialize { .. } => RenderStepType::ExtraImpls,
236            Self::QuickXmlDeserialize { .. } => RenderStepType::ExtraImpls,
237        }
238    }
239
240    fn boxed_clone(&self) -> Box<dyn RenderStepConfig> {
241        Box::new(self.clone())
242    }
243
244    fn into_render_step(self: Box<Self>) -> Box<dyn RenderStepTrait> {
245        use crate::pipeline::renderer::{
246            DefaultsRenderStep, NamespaceConstantsRenderStep, PrefixConstantsRenderStep,
247            QuickXmlDeserializeRenderStep, QuickXmlSerializeRenderStep,
248            SerdeQuickXmlTypesRenderStep, SerdeXmlRsV7TypesRenderStep, SerdeXmlRsV8TypesRenderStep,
249            TypesRenderStep, WithNamespaceTraitRenderStep,
250        };
251
252        match *self {
253            Self::Types => Box::new(TypesRenderStep),
254            Self::TypesSerdeXmlRs {
255                version: SerdeXmlRsVersion::Version07AndBelow,
256            } => Box::new(SerdeXmlRsV7TypesRenderStep),
257            Self::TypesSerdeXmlRs {
258                version: SerdeXmlRsVersion::Version08AndAbove,
259            } => Box::new(SerdeXmlRsV8TypesRenderStep),
260            Self::TypesSerdeQuickXml => Box::new(SerdeQuickXmlTypesRenderStep),
261            Self::Defaults => Box::new(DefaultsRenderStep),
262            Self::PrefixConstants => Box::new(PrefixConstantsRenderStep::default()),
263            Self::NamespaceConstants => Box::new(NamespaceConstantsRenderStep::default()),
264            Self::WithNamespaceTrait => Box::new(WithNamespaceTraitRenderStep),
265            Self::QuickXmlSerialize {
266                namespaces,
267                default_namespace,
268            } => Box::new(QuickXmlSerializeRenderStep {
269                namespaces,
270                default_namespace,
271            }),
272            Self::QuickXmlDeserialize { boxed_deserializer } => {
273                Box::new(QuickXmlDeserializeRenderStep { boxed_deserializer })
274            }
275        }
276    }
277
278    fn is_mutual_exclusive_to(&self, other: &dyn RenderStepConfig) -> bool {
279        use crate::pipeline::renderer::{
280            DefaultsRenderStep, NamespaceConstantsRenderStep, QuickXmlDeserializeRenderStep,
281            QuickXmlSerializeRenderStep, SerdeQuickXmlTypesRenderStep, SerdeXmlRsV7TypesRenderStep,
282            SerdeXmlRsV8TypesRenderStep, TypesRenderStep, WithNamespaceTraitRenderStep,
283        };
284
285        if self
286            .render_step_type()
287            .is_mutual_exclusive_to(other.render_step_type())
288        {
289            return true;
290        }
291
292        let other_id = other.type_id();
293        let other = (other as &dyn Any).downcast_ref::<Self>();
294
295        match (self, other) {
296            (Self::Types, Some(Self::Types)) => true,
297            (Self::TypesSerdeXmlRs { .. }, Some(Self::TypesSerdeXmlRs { .. })) => true,
298            (Self::TypesSerdeQuickXml, Some(Self::TypesSerdeQuickXml)) => true,
299            (Self::Defaults, Some(Self::Defaults)) => true,
300            (Self::NamespaceConstants, Some(Self::NamespaceConstants)) => true,
301            (Self::WithNamespaceTrait, Some(Self::WithNamespaceTrait)) => true,
302            (Self::QuickXmlSerialize { .. }, Some(Self::QuickXmlSerialize { .. })) => true,
303            (Self::QuickXmlDeserialize { .. }, Some(Self::QuickXmlDeserialize { .. })) => true,
304            (Self::Types, None) => other_id == TypeId::of::<TypesRenderStep>(),
305            (
306                Self::TypesSerdeXmlRs {
307                    version: SerdeXmlRsVersion::Version07AndBelow,
308                },
309                None,
310            ) => other_id == TypeId::of::<SerdeXmlRsV7TypesRenderStep>(),
311            (
312                Self::TypesSerdeXmlRs {
313                    version: SerdeXmlRsVersion::Version08AndAbove,
314                },
315                None,
316            ) => other_id == TypeId::of::<SerdeXmlRsV8TypesRenderStep>(),
317            (Self::TypesSerdeQuickXml, None) => {
318                other_id == TypeId::of::<SerdeQuickXmlTypesRenderStep>()
319            }
320            (Self::Defaults, None) => other_id == TypeId::of::<DefaultsRenderStep>(),
321            (Self::NamespaceConstants, None) => {
322                other_id == TypeId::of::<NamespaceConstantsRenderStep>()
323            }
324            (Self::WithNamespaceTrait, None) => {
325                other_id == TypeId::of::<WithNamespaceTraitRenderStep>()
326            }
327            (Self::QuickXmlSerialize { .. }, None) => {
328                other_id == TypeId::of::<QuickXmlSerializeRenderStep>()
329            }
330            (Self::QuickXmlDeserialize { .. }, None) => {
331                other_id == TypeId::of::<QuickXmlDeserializeRenderStep>()
332            }
333            _ => false,
334        }
335    }
336}
337
338impl RenderStep {
339    /// Return `true` if the passed value identifies the same step, `false` otherwise.
340    #[must_use]
341    pub fn is_same(&self, other: &Self) -> bool {
342        match (self, other) {
343            (
344                Self::Types | Self::TypesSerdeXmlRs { .. } | Self::TypesSerdeQuickXml,
345                Self::Types | Self::TypesSerdeXmlRs { .. } | Self::TypesSerdeQuickXml,
346            )
347            | (Self::Defaults, Self::Defaults)
348            | (Self::NamespaceConstants, Self::NamespaceConstants)
349            | (Self::WithNamespaceTrait, Self::WithNamespaceTrait)
350            | (Self::QuickXmlSerialize { .. }, Self::QuickXmlSerialize { .. })
351            | (Self::QuickXmlDeserialize { .. }, Self::QuickXmlDeserialize { .. }) => true,
352            (_, _) => false,
353        }
354    }
355}
356
357/// Version of `serde-xml-rs` to render the code for.
358#[derive(Debug, Clone, Copy, Eq, PartialEq)]
359pub enum SerdeXmlRsVersion {
360    /// Render code for `serde-xml-rs <= 0.7`.
361    Version07AndBelow,
362
363    /// Render code for `serde-xml-rs >= 0.8`.
364    Version08AndAbove,
365}
366
367/// Defines which additional traits should be implemented by the generated traits
368/// of dynamic types.
369#[derive(Default, Debug)]
370pub enum DynTypeTraits {
371    /// The traits will be detected automatically.
372    #[default]
373    Auto,
374
375    /// List of trait identifiers that will be implemented.
376    Custom(Vec<IdentPath>),
377}