xsd_parser/pipeline/renderer/steps/serde/
quick_xml.rs

1use proc_macro2::{Ident as Ident2, TokenStream};
2use quote::quote;
3
4use crate::config::{RendererFlags, TypedefMode};
5use crate::models::{
6    data::{
7        ComplexData, ComplexDataAttribute, ComplexDataContent, ComplexDataElement, ComplexDataEnum,
8        ComplexDataStruct, CustomData, DynamicData, EnumerationData, EnumerationTypeVariant,
9        Occurs, ReferenceData, SimpleData, UnionData, UnionTypeVariant,
10    },
11    schema::xs::Use,
12};
13
14use super::super::super::{Context, DataTypeVariant, RenderStep, RenderStepType};
15use super::super::{format_traits, render_trait_impls};
16use super::{get_derive, get_dyn_type_traits};
17
18/// Implements a [`RenderStep`] that renders rust types of the types defined in
19/// the schema with `quick-xml` support.
20#[derive(Debug, Clone, Copy)]
21pub struct SerdeQuickXmlTypesRenderStep;
22
23impl RenderStep for SerdeQuickXmlTypesRenderStep {
24    fn render_step_type(&self) -> RenderStepType {
25        RenderStepType::Types
26    }
27
28    fn render_type(&mut self, ctx: &mut Context<'_, '_>) {
29        match &ctx.data.variant {
30            DataTypeVariant::BuildIn(_) => (),
31            DataTypeVariant::Custom(x) => x.render_type_serde_quick_xml(ctx),
32            DataTypeVariant::Union(x) => x.render_type_serde_quick_xml(ctx),
33            DataTypeVariant::Dynamic(x) => x.render_type_serde_quick_xml(ctx),
34            DataTypeVariant::Reference(x) => x.render_type_serde_quick_xml(ctx),
35            DataTypeVariant::Enumeration(x) => x.render_type_serde_quick_xml(ctx),
36            DataTypeVariant::Simple(x) => x.render_type_serde_quick_xml(ctx),
37            DataTypeVariant::Complex(x) => x.render_type_serde_quick_xml(ctx),
38        }
39    }
40}
41
42/* CustomType */
43
44impl CustomData<'_> {
45    fn render_type_serde_quick_xml(&self, ctx: &mut Context<'_, '_>) {
46        let Some(include) = self.meta.include() else {
47            return;
48        };
49
50        ctx.add_usings([include]);
51    }
52}
53
54/* UnionData */
55
56impl UnionData<'_> {
57    fn render_type_serde_quick_xml(&self, ctx: &mut Context<'_, '_>) {
58        let Self {
59            type_ident,
60            trait_impls,
61            variants,
62            ..
63        } = self;
64        let docs = ctx.render_type_docs();
65        let derive = get_derive(ctx, []);
66        let trait_impls = render_trait_impls(type_ident, trait_impls);
67        let variants = variants
68            .iter()
69            .map(|x| x.render_variant_serde_quick_xml(ctx));
70
71        let code = quote! {
72            #docs
73            #derive
74            pub enum #type_ident {
75                #( #variants )*
76            }
77
78            #( #trait_impls )*
79        };
80
81        ctx.current_module().append(code);
82    }
83}
84
85/* UnionTypeVariant */
86
87impl UnionTypeVariant<'_> {
88    fn render_variant_serde_quick_xml(&self, ctx: &Context<'_, '_>) -> TokenStream {
89        let Self {
90            target_type,
91            variant_ident,
92            ..
93        } = self;
94
95        let target_type = ctx.resolve_type_for_module(target_type);
96
97        quote! {
98            #variant_ident ( #target_type ),
99        }
100    }
101}
102
103/* DynamicData */
104
105impl DynamicData<'_> {
106    fn render_type_serde_quick_xml(&self, ctx: &mut Context<'_, '_>) {
107        let Self {
108            type_ident,
109            trait_ident,
110            sub_traits,
111            ..
112        } = self;
113
114        let docs = ctx.render_type_docs();
115        let derive = get_derive(ctx, []);
116        let trait_impls = render_trait_impls(type_ident, &[]);
117        let dyn_traits = sub_traits.as_ref().map_or_else(
118            || get_dyn_type_traits(ctx),
119            |traits| format_traits(traits.iter().map(|x| ctx.resolve_type_for_module(x))),
120        );
121
122        let code = quote! {
123            #docs
124            #derive
125            pub struct #type_ident(pub Box<dyn #trait_ident>);
126
127            pub trait #trait_ident: #dyn_traits { }
128
129            #( #trait_impls )*
130        };
131
132        ctx.current_module().append(code);
133    }
134}
135
136/* ReferenceData */
137
138impl ReferenceData<'_> {
139    fn render_type_serde_quick_xml(&self, ctx: &mut Context<'_, '_>) {
140        let Self {
141            mode,
142            occurs,
143            type_ident,
144            target_type,
145            trait_impls,
146            ..
147        } = self;
148
149        let docs = ctx.render_type_docs();
150        let target_type = ctx.resolve_type_for_module(target_type);
151
152        let code = match mode {
153            TypedefMode::Auto => crate::unreachable!(),
154            TypedefMode::Typedef => {
155                let target_type = occurs.make_type(&target_type, false);
156
157                quote! {
158                    #docs
159                    pub type #type_ident = #target_type;
160                }
161            }
162            TypedefMode::NewType => {
163                let target_type = occurs.make_type(&target_type, false);
164                let extra_derive =
165                    matches!(occurs, Occurs::Optional | Occurs::DynamicList).then_some("Default");
166                let derive = get_derive(ctx, extra_derive);
167                let trait_impls = render_trait_impls(type_ident, trait_impls);
168
169                quote! {
170                    #docs
171                    #derive
172                    pub struct #type_ident(pub #target_type);
173
174                    #( #trait_impls )*
175                }
176            }
177        };
178
179        ctx.current_module().append(code);
180    }
181}
182
183/* EnumerationData */
184
185impl EnumerationData<'_> {
186    fn render_type_serde_quick_xml(&self, ctx: &mut Context<'_, '_>) {
187        let Self {
188            type_ident,
189            variants,
190            trait_impls,
191            ..
192        } = self;
193
194        let docs = ctx.render_type_docs();
195        let derive = get_derive(ctx, []);
196        let trait_impls = render_trait_impls(type_ident, trait_impls);
197
198        let variants = variants
199            .iter()
200            .map(|d| d.render_variant_serde_quick_xml(ctx))
201            .collect::<Vec<_>>();
202
203        let code = quote! {
204            #docs
205            #derive
206            pub enum #type_ident {
207                #( #variants )*
208            }
209
210            #( #trait_impls )*
211        };
212
213        ctx.current_module().append(code);
214    }
215}
216
217impl EnumerationTypeVariant<'_> {
218    fn render_variant_serde_quick_xml(&self, ctx: &Context<'_, '_>) -> TokenStream {
219        let Self {
220            s_name,
221            meta,
222            variant_ident,
223            target_type,
224            ..
225        } = self;
226
227        let docs = ctx.render_docs(RendererFlags::RENDER_VARIANT_DOCS, &meta.documentation[..]);
228
229        let serde = if meta.type_.is_some() {
230            quote!(#[serde(other)])
231        } else {
232            quote!(#[serde(rename = #s_name)])
233        };
234
235        let target_type = target_type.as_ref().map(|target_type| {
236            let target_type = ctx.resolve_type_for_module(target_type);
237
238            quote!((#target_type))
239        });
240
241        quote! {
242            #docs
243            #serde
244            #variant_ident #target_type,
245        }
246    }
247}
248
249impl SimpleData<'_> {
250    fn render_type_serde_quick_xml(&self, ctx: &mut Context<'_, '_>) {
251        let Self {
252            occurs,
253            type_ident,
254            target_type,
255            trait_impls,
256            ..
257        } = self;
258
259        let docs = ctx.render_type_docs();
260        let target_type = ctx.resolve_type_for_module(target_type);
261        let target_type = occurs.make_type(&target_type, false);
262
263        let derive = get_derive(ctx, []);
264        let trait_impls = render_trait_impls(type_ident, trait_impls);
265
266        let code = quote! {
267            #docs
268            #derive
269            pub struct #type_ident(pub #target_type);
270
271            #( #trait_impls )*
272        };
273
274        ctx.current_module().append(code);
275
276        self.render_common_impls(ctx);
277    }
278}
279
280/* ComplexData */
281
282impl ComplexData<'_> {
283    fn render_type_serde_quick_xml(&self, ctx: &mut Context<'_, '_>) {
284        match self {
285            Self::Enum {
286                type_,
287                content_type,
288            } => {
289                type_.render_type_serde_quick_xml(ctx);
290
291                if let Some(content_type) = content_type {
292                    content_type.render_type_serde_quick_xml(ctx);
293                }
294            }
295            Self::Struct {
296                type_,
297                content_type,
298            } => {
299                type_.render_type_serde_quick_xml(ctx);
300
301                if let Some(content_type) = content_type {
302                    content_type.render_type_serde_quick_xml(ctx);
303                }
304            }
305        }
306    }
307}
308
309impl ComplexDataEnum<'_> {
310    fn render_type_serde_quick_xml(&self, ctx: &mut Context<'_, '_>) {
311        let docs = ctx.render_type_docs();
312        let derive = get_derive(ctx, []);
313        let type_ident = &self.type_ident;
314        let trait_impls = render_trait_impls(type_ident, &self.trait_impls);
315
316        let variants = self
317            .elements
318            .iter()
319            .map(|x| x.render_variant_serde_quick_xml(ctx));
320
321        let code = quote! {
322            #docs
323            #derive
324            pub enum #type_ident {
325                #( #variants )*
326            }
327
328            #( #trait_impls )*
329        };
330
331        ctx.current_module().append(code);
332    }
333}
334
335impl ComplexDataStruct<'_> {
336    fn render_type_serde_quick_xml(&self, ctx: &mut Context<'_, '_>) {
337        let docs = ctx.render_type_docs();
338        let derive = get_derive(ctx, []);
339        let type_ident = &self.type_ident;
340        let trait_impls = render_trait_impls(type_ident, &self.trait_impls);
341
342        let attributes = self
343            .attributes
344            .iter()
345            .map(|x| x.render_field_serde_quick_xml(ctx, type_ident));
346        let fields = self
347            .elements()
348            .iter()
349            .map(|x| x.render_field_serde_quick_xml(ctx));
350        let content = self
351            .content()
352            .as_ref()
353            .and_then(|x| x.render_field_serde_quick_xml(ctx));
354
355        let struct_data = if self.is_unit_struct() {
356            quote!(;)
357        } else {
358            quote! {
359                {
360                    #( #attributes )*
361                    #( #fields )*
362                    #content
363                }
364            }
365        };
366
367        let code = quote! {
368            #docs
369            #derive
370            pub struct #type_ident
371                #struct_data
372
373            #( #trait_impls )*
374        };
375
376        ctx.current_module().append(code);
377    }
378}
379
380impl ComplexDataContent<'_> {
381    fn render_field_serde_quick_xml(&self, ctx: &Context<'_, '_>) -> Option<TokenStream> {
382        let target_type = ctx.resolve_type_for_module(&self.target_type);
383        let target_type = self.occurs.make_type(&target_type, false)?;
384
385        let default =
386            (self.is_empty_string_content(ctx) || self.min_occurs == 0).then(|| quote!(default,));
387        let name = if self.is_simple() { "$text" } else { "$value" };
388
389        Some(quote! {
390            #[serde(#default rename = #name)]
391            pub content: #target_type,
392        })
393    }
394}
395
396impl ComplexDataAttribute<'_> {
397    fn render_field_serde_quick_xml(
398        &self,
399        ctx: &Context<'_, '_>,
400        type_ident: &Ident2,
401    ) -> TokenStream {
402        let Self {
403            ident: field_ident,
404            s_name,
405            ..
406        } = self;
407
408        let name = format!("@{s_name}");
409
410        let target_type = ctx.resolve_type_for_module(&self.target_type);
411        let target_type = if self.is_option {
412            quote!(Option<#target_type>)
413        } else {
414            target_type
415        };
416
417        let default = if self.default_value.is_some() {
418            let default_path = format!("{type_ident}::default_{field_ident}");
419
420            quote!(default = #default_path,)
421        } else if self.meta.use_ == Use::Optional {
422            quote!(default,)
423        } else {
424            quote!()
425        };
426
427        let docs = ctx.render_docs(
428            RendererFlags::RENDER_ATTRIBUTE_DOCS,
429            &self.meta.documentation[..],
430        );
431
432        quote! {
433            #docs
434            #[serde(#default rename = #name)]
435            pub #field_ident: #target_type,
436        }
437    }
438}
439
440impl ComplexDataElement<'_> {
441    fn render_field_serde_quick_xml(&self, ctx: &Context<'_, '_>) -> TokenStream {
442        let Self {
443            s_name,
444            field_ident,
445            ..
446        } = self;
447
448        let name = if self.meta().is_text() {
449            "$text"
450        } else {
451            s_name
452        };
453
454        let target_type = ctx.resolve_type_for_module(&self.target_type);
455        let target_type = self
456            .occurs
457            .make_type(&target_type, self.need_indirection)
458            .unwrap();
459
460        let docs = ctx.render_docs(
461            RendererFlags::RENDER_ELEMENT_DOCS,
462            &self.meta().documentation[..],
463        );
464
465        let default = match self.occurs {
466            Occurs::None | Occurs::Single | Occurs::StaticList(_) => quote!(),
467            Occurs::Optional | Occurs::DynamicList => quote!(default,),
468        };
469
470        quote! {
471            #docs
472            #[serde(#default rename = #name)]
473            pub #field_ident: #target_type,
474        }
475    }
476
477    fn render_variant_serde_quick_xml(&self, ctx: &Context<'_, '_>) -> TokenStream {
478        let Self {
479            s_name,
480            variant_ident,
481            ..
482        } = self;
483
484        let name = if self.meta().is_text() {
485            "$text"
486        } else {
487            s_name
488        };
489
490        let target_type = ctx.resolve_type_for_module(&self.target_type);
491        let target_type = self.occurs.make_type(&target_type, self.need_indirection);
492
493        let docs = ctx.render_docs(
494            RendererFlags::RENDER_ELEMENT_DOCS,
495            &self.meta().documentation[..],
496        );
497
498        quote! {
499            #docs
500            #[serde(rename = #name)]
501            #variant_ident(#target_type),
502        }
503    }
504}