Skip to main content

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/// <div class="warning">
135/// *Caution*
136/// Some render steps are incompatible to each other (e.g. only
137/// one `TypesXXX` step should be used, because they render the general type
138/// structure). While other render steps depend on each other (e.g. `QuickXmlXXX`
139/// depends on `Types` and `NamespaceConstants`).
140/// </div>
141#[derive(Debug, Clone)]
142pub enum RenderStep {
143    /// Step to render the pure types.
144    Types,
145
146    /// Step to render the types with `serde-xml-rs` support.
147    TypesSerdeXmlRs {
148        /// Version of `serde-xml-rs` to render the code for.
149        version: SerdeXmlRsVersion,
150    },
151
152    /// Step to render the types with `quick_xml` serde support.
153    TypesSerdeQuickXml,
154
155    /// Renderer to render associated methods that return the default values
156    /// of the different fields of a struct.
157    Defaults,
158
159    /// Renderer to add constants for the namespaces to the generated code.
160    NamespaceConstants,
161
162    /// Renderer to add constants for each variant of an enumeration using its simple base type.
163    EnumConstants,
164
165    /// Renderer to add constants for the namespace prefixes to the generated code.
166    PrefixConstants,
167
168    /// Renderer that adds the [`WithNamespace`](xsd_parser_types::WithNamespace) trait to
169    /// the generated types.
170    WithNamespaceTrait,
171
172    /// Renderer that renders code for the `quick_xml` serializer of the
173    /// different types.
174    QuickXmlSerialize {
175        /// Whether to add namespaces to the root element during serialization or not.
176        namespaces: NamespaceSerialization,
177
178        /// Default namespace to use for the serialization.
179        default_namespace: Option<Namespace>,
180    },
181
182    /// Renderer that renders code for the `quick_xml` deserializer of the
183    /// different types.
184    QuickXmlDeserialize {
185        /// Whether to box the deserializer or not.
186        ///
187        /// For more details have a look at [`QuickXmlDeserializeRenderer::boxed_deserializer`](crate::pipeline::renderer::QuickXmlDeserializeRenderStep::boxed_deserializer).
188        boxed_deserializer: bool,
189    },
190}
191
192/// Helper trait to deal with custom render steps.
193pub trait RenderStepConfig: Debug + Any {
194    /// Returns a boxed clone of the current object.
195    fn boxed_clone(&self) -> Box<dyn RenderStepConfig>;
196
197    /// Creates the actual render step and returned it as a box.
198    fn into_render_step(self: Box<Self>) -> Box<dyn RenderStepTrait>;
199
200    /// Returns the type of this render step.
201    fn render_step_type(&self) -> RenderStepType {
202        RenderStepType::Undefined
203    }
204
205    /// Returns `true` if `self` is mutual exclusive to `other`, `false` otherwise.
206    fn is_mutual_exclusive_to(&self, other: &dyn RenderStepConfig) -> bool {
207        self.type_id() == other.type_id()
208            || self
209                .render_step_type()
210                .is_mutual_exclusive_to(other.render_step_type())
211    }
212}
213
214impl<X> RenderStepConfig for X
215where
216    X: RenderStepTrait + Clone + Any + 'static,
217{
218    fn render_step_type(&self) -> RenderStepType {
219        X::render_step_type(self)
220    }
221
222    fn boxed_clone(&self) -> Box<dyn RenderStepConfig> {
223        Box::new(self.clone())
224    }
225
226    fn into_render_step(self: Box<Self>) -> Box<dyn RenderStepTrait> {
227        self
228    }
229}
230
231impl RenderStepConfig for RenderStep {
232    fn render_step_type(&self) -> RenderStepType {
233        match self {
234            Self::Types => RenderStepType::Types,
235            Self::TypesSerdeXmlRs { .. } => RenderStepType::Types,
236            Self::TypesSerdeQuickXml => RenderStepType::Types,
237            Self::Defaults => RenderStepType::ExtraImpls,
238            Self::EnumConstants => RenderStepType::ExtraImpls,
239            Self::PrefixConstants => RenderStepType::ExtraImpls,
240            Self::NamespaceConstants => RenderStepType::ExtraImpls,
241            Self::WithNamespaceTrait => RenderStepType::ExtraImpls,
242            Self::QuickXmlSerialize { .. } => RenderStepType::ExtraImpls,
243            Self::QuickXmlDeserialize { .. } => RenderStepType::ExtraImpls,
244        }
245    }
246
247    fn boxed_clone(&self) -> Box<dyn RenderStepConfig> {
248        Box::new(self.clone())
249    }
250
251    fn into_render_step(self: Box<Self>) -> Box<dyn RenderStepTrait> {
252        use crate::pipeline::renderer::{
253            DefaultsRenderStep, EnumConstantsRenderStep, NamespaceConstantsRenderStep,
254            PrefixConstantsRenderStep, QuickXmlDeserializeRenderStep, QuickXmlSerializeRenderStep,
255            SerdeQuickXmlTypesRenderStep, SerdeXmlRsV7TypesRenderStep, SerdeXmlRsV8TypesRenderStep,
256            TypesRenderStep, WithNamespaceTraitRenderStep,
257        };
258
259        match *self {
260            Self::Types => Box::new(TypesRenderStep),
261            Self::TypesSerdeXmlRs {
262                version: SerdeXmlRsVersion::Version07AndBelow,
263            } => Box::new(SerdeXmlRsV7TypesRenderStep),
264            Self::TypesSerdeXmlRs {
265                version: SerdeXmlRsVersion::Version08AndAbove,
266            } => Box::new(SerdeXmlRsV8TypesRenderStep),
267            Self::TypesSerdeQuickXml => Box::new(SerdeQuickXmlTypesRenderStep),
268            Self::Defaults => Box::new(DefaultsRenderStep),
269            Self::EnumConstants => Box::new(EnumConstantsRenderStep),
270            Self::PrefixConstants => Box::new(PrefixConstantsRenderStep::default()),
271            Self::NamespaceConstants => Box::new(NamespaceConstantsRenderStep::default()),
272            Self::WithNamespaceTrait => Box::new(WithNamespaceTraitRenderStep),
273            Self::QuickXmlSerialize {
274                namespaces,
275                default_namespace,
276            } => Box::new(QuickXmlSerializeRenderStep {
277                namespaces,
278                default_namespace,
279            }),
280            Self::QuickXmlDeserialize { boxed_deserializer } => {
281                Box::new(QuickXmlDeserializeRenderStep { boxed_deserializer })
282            }
283        }
284    }
285
286    fn is_mutual_exclusive_to(&self, other: &dyn RenderStepConfig) -> bool {
287        use crate::pipeline::renderer::{
288            DefaultsRenderStep, NamespaceConstantsRenderStep, QuickXmlDeserializeRenderStep,
289            QuickXmlSerializeRenderStep, SerdeQuickXmlTypesRenderStep, SerdeXmlRsV7TypesRenderStep,
290            SerdeXmlRsV8TypesRenderStep, TypesRenderStep, WithNamespaceTraitRenderStep,
291        };
292
293        if self
294            .render_step_type()
295            .is_mutual_exclusive_to(other.render_step_type())
296        {
297            return true;
298        }
299
300        let other_id = other.type_id();
301        let other = (other as &dyn Any).downcast_ref::<Self>();
302
303        match (self, other) {
304            (Self::Types, Some(Self::Types)) => true,
305            (Self::TypesSerdeXmlRs { .. }, Some(Self::TypesSerdeXmlRs { .. })) => true,
306            (Self::TypesSerdeQuickXml, Some(Self::TypesSerdeQuickXml)) => true,
307            (Self::Defaults, Some(Self::Defaults)) => true,
308            (Self::NamespaceConstants, Some(Self::NamespaceConstants)) => true,
309            (Self::WithNamespaceTrait, Some(Self::WithNamespaceTrait)) => true,
310            (Self::QuickXmlSerialize { .. }, Some(Self::QuickXmlSerialize { .. })) => true,
311            (Self::QuickXmlDeserialize { .. }, Some(Self::QuickXmlDeserialize { .. })) => true,
312            (Self::Types, None) => other_id == TypeId::of::<TypesRenderStep>(),
313            (
314                Self::TypesSerdeXmlRs {
315                    version: SerdeXmlRsVersion::Version07AndBelow,
316                },
317                None,
318            ) => other_id == TypeId::of::<SerdeXmlRsV7TypesRenderStep>(),
319            (
320                Self::TypesSerdeXmlRs {
321                    version: SerdeXmlRsVersion::Version08AndAbove,
322                },
323                None,
324            ) => other_id == TypeId::of::<SerdeXmlRsV8TypesRenderStep>(),
325            (Self::TypesSerdeQuickXml, None) => {
326                other_id == TypeId::of::<SerdeQuickXmlTypesRenderStep>()
327            }
328            (Self::Defaults, None) => other_id == TypeId::of::<DefaultsRenderStep>(),
329            (Self::NamespaceConstants, None) => {
330                other_id == TypeId::of::<NamespaceConstantsRenderStep>()
331            }
332            (Self::WithNamespaceTrait, None) => {
333                other_id == TypeId::of::<WithNamespaceTraitRenderStep>()
334            }
335            (Self::QuickXmlSerialize { .. }, None) => {
336                other_id == TypeId::of::<QuickXmlSerializeRenderStep>()
337            }
338            (Self::QuickXmlDeserialize { .. }, None) => {
339                other_id == TypeId::of::<QuickXmlDeserializeRenderStep>()
340            }
341            _ => false,
342        }
343    }
344}
345
346impl RenderStep {
347    /// Return `true` if the passed value identifies the same step, `false` otherwise.
348    #[must_use]
349    pub fn is_same(&self, other: &Self) -> bool {
350        match (self, other) {
351            (
352                Self::Types | Self::TypesSerdeXmlRs { .. } | Self::TypesSerdeQuickXml,
353                Self::Types | Self::TypesSerdeXmlRs { .. } | Self::TypesSerdeQuickXml,
354            )
355            | (Self::Defaults, Self::Defaults)
356            | (Self::NamespaceConstants, Self::NamespaceConstants)
357            | (Self::WithNamespaceTrait, Self::WithNamespaceTrait)
358            | (Self::QuickXmlSerialize { .. }, Self::QuickXmlSerialize { .. })
359            | (Self::QuickXmlDeserialize { .. }, Self::QuickXmlDeserialize { .. }) => true,
360            (_, _) => false,
361        }
362    }
363}
364
365/// Version of `serde-xml-rs` to render the code for.
366#[derive(Debug, Clone, Copy, Eq, PartialEq)]
367pub enum SerdeXmlRsVersion {
368    /// Render code for `serde-xml-rs <= 0.7`.
369    Version07AndBelow,
370
371    /// Render code for `serde-xml-rs >= 0.8`.
372    Version08AndAbove,
373}
374
375/// Defines which additional traits should be implemented by the generated traits
376/// of dynamic types.
377#[derive(Default, Debug)]
378pub enum DynTypeTraits {
379    /// The traits will be detected automatically.
380    #[default]
381    Auto,
382
383    /// List of trait identifiers that will be implemented.
384    Custom(Vec<IdentPath>),
385}