xsd_parser/config/
renderer.rs

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