Skip to main content

xsd_parser/pipeline/renderer/steps/serde/
serde_xml_rs_v7.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 `serde-xml-rs <= 0.7` support.
20#[derive(Debug, Clone, Copy)]
21pub struct SerdeXmlRsV7TypesRenderStep;
22
23impl RenderStep for SerdeXmlRsV7TypesRenderStep {
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_xml_rs_v7(ctx),
32            DataTypeVariant::Dynamic(x) => x.render_type_serde_xml_rs_v7(ctx),
33            DataTypeVariant::Reference(x) => x.render_type_serde_xml_rs_v7(ctx),
34            DataTypeVariant::Enumeration(x) => x.render_type_serde_xml_rs_v7(ctx),
35            DataTypeVariant::Simple(x) => x.render_type_serde_xml_rs_v7(ctx),
36            DataTypeVariant::Complex(x) => x.render_type_serde_xml_rs_v7(ctx),
37        }
38    }
39}
40
41/* UnionData */
42
43impl UnionData<'_> {
44    fn render_type_serde_xml_rs_v7(&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_xml_rs_v7(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_xml_rs_v7(&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_xml_rs_v7(&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_xml_rs_v7(&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_xml_rs_v7(&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_xml_rs_v7(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_xml_rs_v7(&self, ctx: &Context<'_, '_>) -> TokenStream {
222        let Self {
223            meta,
224            s_name,
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
254/* SimpleData */
255
256impl SimpleData<'_> {
257    fn render_type_serde_xml_rs_v7(&self, ctx: &mut Context<'_, '_>) {
258        let Self {
259            occurs,
260            type_ident,
261            target_type,
262            trait_impls,
263            ..
264        } = self;
265
266        let docs = ctx.render_type_docs();
267        let target_type = ctx.resolve_type_for_module(target_type);
268        let target_type = occurs.make_type(ctx, &target_type, false);
269        let extra_attributes = &ctx.data.extra_attributes;
270
271        let derive = get_derive(ctx, []);
272        let trait_impls = render_trait_impls(type_ident, trait_impls);
273
274        let code = quote! {
275            #docs
276            #derive
277            #( #[#extra_attributes] )*
278            pub struct #type_ident(pub #target_type);
279
280            #( #trait_impls )*
281        };
282
283        ctx.current_module().append(code);
284
285        self.render_common_impls(ctx);
286    }
287}
288
289/* ComplexData */
290
291impl ComplexData<'_> {
292    fn render_type_serde_xml_rs_v7(&self, ctx: &mut Context<'_, '_>) {
293        match self {
294            Self::Enum {
295                type_,
296                content_type,
297            } => {
298                type_.render_type_serde_xml_rs_v7(ctx);
299
300                if let Some(content_type) = content_type {
301                    content_type.render_type_serde_xml_rs_v7(ctx);
302                }
303            }
304            Self::Struct {
305                type_,
306                content_type,
307            } => {
308                type_.render_type_serde_xml_rs_v7(ctx);
309
310                if let Some(content_type) = content_type {
311                    content_type.render_type_serde_xml_rs_v7(ctx);
312                }
313            }
314        }
315    }
316}
317
318impl ComplexDataEnum<'_> {
319    fn render_type_serde_xml_rs_v7(&self, ctx: &mut Context<'_, '_>) {
320        let docs = ctx.render_type_docs();
321        let derive = get_derive(ctx, []);
322        let type_ident = &self.type_ident;
323        let trait_impls = render_trait_impls(type_ident, &self.trait_impls);
324        let extra_attributes = &ctx.data.extra_attributes;
325
326        let variants = self
327            .elements
328            .iter()
329            .map(|x| x.render_variant_serde_xml_rs_v7(ctx));
330
331        let code = quote! {
332            #docs
333            #derive
334            #( #[#extra_attributes] )*
335            pub enum #type_ident {
336                #( #variants )*
337            }
338
339            #( #trait_impls )*
340        };
341
342        ctx.current_module().append(code);
343    }
344}
345
346impl ComplexDataStruct<'_> {
347    fn render_type_serde_xml_rs_v7(&self, ctx: &mut Context<'_, '_>) {
348        let docs = ctx.render_type_docs();
349        let derive = get_derive(ctx, []);
350        let type_ident = &self.type_ident;
351        let trait_impls = render_trait_impls(type_ident, &self.trait_impls);
352        let extra_attributes = &ctx.data.extra_attributes;
353
354        let attributes = self
355            .attributes
356            .iter()
357            .map(|x| x.render_field_serde_xml_rs_v7(ctx, type_ident));
358        let fields = self
359            .elements()
360            .iter()
361            .map(|x| x.render_field_serde_xml_rs_v7(ctx));
362        let content = self
363            .content()
364            .as_ref()
365            .and_then(|x| x.render_field_serde_xml_rs_v7(ctx));
366
367        let struct_data = if self.is_unit_struct() {
368            quote!(;)
369        } else {
370            quote! {
371                {
372                    #( #attributes )*
373                    #( #fields )*
374                    #content
375                }
376            }
377        };
378
379        let code = quote! {
380            #docs
381            #derive
382            #( #[#extra_attributes] )*
383            pub struct #type_ident
384                #struct_data
385
386            #( #trait_impls )*
387        };
388
389        ctx.current_module().append(code);
390    }
391}
392
393impl ComplexDataContent<'_> {
394    fn render_field_serde_xml_rs_v7(&self, ctx: &Context<'_, '_>) -> Option<TokenStream> {
395        let target_type = ctx.resolve_type_for_module(&self.target_type);
396        let target_type = self.occurs.make_type(ctx, &target_type, false)?;
397        let extra_attributes = &self.extra_attributes;
398
399        let default =
400            (self.is_empty_string_content(ctx) || self.min_occurs == 0).then(|| quote!(default,));
401
402        Some(quote! {
403            #( #[#extra_attributes] )*
404            #[serde(#default rename = "$value")]
405            pub content: #target_type,
406        })
407    }
408}
409
410impl ComplexDataAttribute<'_> {
411    fn render_field_serde_xml_rs_v7(
412        &self,
413        ctx: &Context<'_, '_>,
414        type_ident: &Ident2,
415    ) -> TokenStream {
416        let Self {
417            tag_name,
418            ident: field_ident,
419            extra_attributes,
420            ..
421        } = self;
422
423        let tag_name = tag_name.get(true);
424
425        let target_type = ctx.resolve_type_for_module(&self.target_type);
426        let target_type = if self.is_option {
427            let option = ctx.resolve_build_in("::core::option::Option");
428
429            quote!(#option<#target_type>)
430        } else {
431            target_type
432        };
433
434        let default = if self.default_value.is_some() {
435            let default_path = format!("{type_ident}::default_{field_ident}");
436
437            quote!(default = #default_path,)
438        } else if self.meta.use_ == Use::Optional {
439            quote!(default,)
440        } else {
441            quote!()
442        };
443
444        let docs = ctx.render_docs(
445            RendererFlags::RENDER_ATTRIBUTE_DOCS,
446            &self.meta.documentation[..],
447        );
448
449        quote! {
450            #docs
451            #( #[#extra_attributes] )*
452            #[serde(#default rename = #tag_name)]
453            pub #field_ident: #target_type,
454        }
455    }
456}
457
458impl ComplexDataElement<'_> {
459    fn render_field_serde_xml_rs_v7(&self, ctx: &Context<'_, '_>) -> TokenStream {
460        let Self {
461            s_name,
462            field_ident,
463            extra_attributes,
464            ..
465        } = self;
466
467        let name = if self.meta().is_text() {
468            "#text"
469        } else {
470            s_name
471        };
472
473        let target_type = ctx.resolve_type_for_module(&self.target_type);
474        let target_type = self
475            .occurs
476            .make_type(ctx, &target_type, self.need_indirection)
477            .unwrap();
478
479        let docs = ctx.render_docs(
480            RendererFlags::RENDER_ELEMENT_DOCS,
481            &self.meta().documentation[..],
482        );
483
484        let default = match self.occurs {
485            Occurs::None | Occurs::Single | Occurs::StaticList(_) => quote!(),
486            Occurs::Optional | Occurs::DynamicList => quote!(default,),
487        };
488
489        quote! {
490            #docs
491            #( #[#extra_attributes] )*
492            #[serde(#default rename = #name)]
493            pub #field_ident: #target_type,
494        }
495    }
496
497    fn render_variant_serde_xml_rs_v7(&self, ctx: &Context<'_, '_>) -> TokenStream {
498        let Self {
499            s_name,
500            variant_ident,
501            extra_attributes,
502            ..
503        } = self;
504
505        let name = if self.meta().is_text() {
506            "#text"
507        } else {
508            s_name
509        };
510
511        let target_type = ctx.resolve_type_for_module(&self.target_type);
512        let target_type = self
513            .occurs
514            .make_type(ctx, &target_type, self.need_indirection);
515
516        let docs = ctx.render_docs(
517            RendererFlags::RENDER_ELEMENT_DOCS,
518            &self.meta().documentation[..],
519        );
520
521        quote! {
522            #docs
523            #( #[#extra_attributes] )*
524            #[serde(rename = #name)]
525            #variant_ident(#target_type),
526        }
527    }
528}