Skip to main content

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