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

1use proc_macro2::{Ident as Ident2, TokenStream};
2use quote::{format_ident, quote};
3
4use crate::config::{RendererFlags, TypedefMode};
5use crate::models::{
6    data::{
7        ComplexData, ComplexDataAttribute, ComplexDataContent, ComplexDataElement, ComplexDataEnum,
8        ComplexDataStruct, DynamicData, EnumerationData, EnumerationTypeVariant, Occurs,
9        ReferenceData, SimpleData, UnionData, UnionTypeVariant,
10    },
11    meta::{MetaType, MetaTypeVariant},
12    schema::xs::Use,
13    Ident,
14};
15use crate::traits::Naming;
16
17use super::super::super::{Context, DataTypeVariant, RenderStep, RenderStepType};
18use super::super::{format_traits, render_trait_impls};
19use super::{get_derive, get_dyn_type_traits};
20
21/// Implements a [`RenderStep`] that renders rust types of the types defined in
22/// the schema with `serde-xml-rs >= 0.8` support.
23#[derive(Debug, Clone, Copy)]
24pub struct SerdeXmlRsV8TypesRenderStep;
25
26impl RenderStep for SerdeXmlRsV8TypesRenderStep {
27    fn render_step_type(&self) -> RenderStepType {
28        RenderStepType::Types
29    }
30
31    fn render_type(&mut self, ctx: &mut Context<'_, '_>) {
32        match &ctx.data.variant {
33            DataTypeVariant::BuildIn(_) | DataTypeVariant::Custom(_) => (),
34            DataTypeVariant::Union(x) => x.render_type_serde_xml_rs_v8(ctx),
35            DataTypeVariant::Dynamic(x) => x.render_type_serde_xml_rs_v8(ctx),
36            DataTypeVariant::Reference(x) => x.render_type_serde_xml_rs_v8(ctx),
37            DataTypeVariant::Enumeration(x) => x.render_type_serde_xml_rs_v8(ctx),
38            DataTypeVariant::Simple(x) => x.render_type_serde_xml_rs_v8(ctx),
39            DataTypeVariant::Complex(x) => x.render_type_serde_xml_rs_v8(ctx),
40        }
41    }
42}
43
44/* Context */
45
46impl<'types> Context<'_, 'types> {
47    fn get_resolved_complex_content(&self) -> Option<(&'types Ident, &'types MetaType)> {
48        let MetaTypeVariant::ComplexType(cm) = &self.data.meta.variant else {
49            return None;
50        };
51
52        let content_ident = cm.content.as_ref()?;
53
54        self.meta.types.meta.types.get_resolved(content_ident)
55    }
56}
57
58/* Occurs */
59
60impl Occurs {
61    fn array_to_vec(self) -> Self {
62        match self {
63            Self::StaticList(_) => Self::DynamicList,
64            x => x,
65        }
66    }
67}
68
69/* UnionData */
70
71impl UnionData<'_> {
72    fn render_type_serde_xml_rs_v8(&self, ctx: &mut Context<'_, '_>) {
73        let Self {
74            type_ident,
75            trait_impls,
76            variants,
77            ..
78        } = self;
79        let docs = ctx.render_type_docs();
80        let derive = get_derive(ctx, []);
81        let trait_impls = render_trait_impls(type_ident, trait_impls);
82        let variants = variants
83            .iter()
84            .map(|x| x.render_variant_serde_xml_rs_v8(ctx));
85        let extra_attributes = &ctx.data.extra_attributes;
86
87        let code = quote! {
88            #docs
89            #derive
90            #( #[#extra_attributes] )*
91            pub enum #type_ident {
92                #( #variants )*
93            }
94
95            #( #trait_impls )*
96        };
97
98        ctx.current_module().append(code);
99
100        self.render_common_impls(ctx);
101    }
102}
103
104/* UnionTypeVariant */
105
106impl UnionTypeVariant<'_> {
107    fn render_variant_serde_xml_rs_v8(&self, ctx: &Context<'_, '_>) -> TokenStream {
108        let Self {
109            target_type,
110            variant_ident,
111            extra_attributes,
112            ..
113        } = self;
114
115        let target_type = ctx.resolve_type_for_module(target_type);
116
117        quote! {
118            #( #[#extra_attributes] )*
119            #variant_ident ( #target_type ),
120        }
121    }
122}
123
124/* DynamicData */
125
126impl DynamicData<'_> {
127    fn render_type_serde_xml_rs_v8(&self, ctx: &mut Context<'_, '_>) {
128        let Self {
129            type_ident,
130            trait_ident,
131            sub_traits,
132            ..
133        } = self;
134
135        let docs = ctx.render_type_docs();
136        let derive = get_derive(ctx, []);
137        let trait_impls = render_trait_impls(type_ident, &[]);
138        let dyn_traits = sub_traits.as_ref().map_or_else(
139            || get_dyn_type_traits(ctx),
140            |traits| format_traits(traits.iter().map(|x| ctx.resolve_type_for_module(x))),
141        );
142        let extra_attributes = &ctx.data.extra_attributes;
143
144        let box_ = ctx.resolve_build_in("::alloc::boxed::Box");
145
146        let code = quote! {
147            #docs
148            #derive
149            #( #[#extra_attributes] )*
150            pub struct #type_ident(pub #box_<dyn #trait_ident>);
151
152            pub trait #trait_ident: #dyn_traits { }
153
154            #( #trait_impls )*
155        };
156
157        ctx.current_module().append(code);
158    }
159}
160
161/* ReferenceData */
162
163impl ReferenceData<'_> {
164    fn render_type_serde_xml_rs_v8(&self, ctx: &mut Context<'_, '_>) {
165        let Self {
166            mode,
167            occurs,
168            type_ident,
169            target_type,
170            trait_impls,
171            ..
172        } = self;
173
174        let docs = ctx.render_type_docs();
175        let occurs = occurs.array_to_vec();
176        let target_type = ctx.resolve_type_for_module(target_type);
177
178        let code = match mode {
179            TypedefMode::Auto => crate::unreachable!(),
180            TypedefMode::Typedef => {
181                let target_type = occurs.make_type(ctx, &target_type, false);
182                let trait_impls = render_trait_impls(type_ident, trait_impls);
183
184                quote! {
185                    #docs
186                    pub type #type_ident = #target_type;
187
188                    #( #trait_impls )*
189                }
190            }
191            TypedefMode::NewType => {
192                let target_type = occurs.make_type(ctx, &target_type, false);
193                let extra_derive =
194                    matches!(occurs, Occurs::Optional | Occurs::DynamicList).then_some("Default");
195                let derive = get_derive(ctx, extra_derive);
196                let trait_impls = render_trait_impls(type_ident, trait_impls);
197                let extra_attributes = &ctx.data.extra_attributes;
198
199                quote! {
200                    #docs
201                    #derive
202                    #( #[#extra_attributes] )*
203                    pub struct #type_ident(pub #target_type);
204
205                    #( #trait_impls )*
206                }
207            }
208        };
209
210        ctx.current_module().append(code);
211    }
212}
213
214/* EnumerationData */
215
216impl EnumerationData<'_> {
217    fn render_type_serde_xml_rs_v8(&self, ctx: &mut Context<'_, '_>) {
218        let Self {
219            type_ident,
220            variants,
221            trait_impls,
222            ..
223        } = self;
224
225        let values_ident = format_enum_values_ident(&*ctx.meta.types.naming, ctx.ident);
226
227        let docs = ctx.render_type_docs();
228        let derive = get_derive(ctx, []);
229        let trait_impls = render_trait_impls(type_ident, trait_impls);
230        let extra_attributes = &ctx.data.extra_attributes;
231
232        let variants = variants
233            .iter()
234            .map(|d| d.render_variant_serde_xml_rs_v8(ctx))
235            .collect::<Vec<_>>();
236
237        let from = ctx.resolve_build_in("::core::convert::From");
238        let deref = ctx.resolve_build_in("::core::ops::Deref");
239        let deref_mut = ctx.resolve_build_in("::core::ops::DerefMut");
240
241        ctx.add_usings(["::core::ops::Deref", "::core::ops::DerefMut"]);
242
243        let code = quote! {
244            #docs
245            #derive
246            pub struct #type_ident {
247                #[serde(rename = "#text")]
248                pub value: #values_ident,
249            }
250
251            impl #from<#values_ident> for #type_ident {
252                fn from(value: #values_ident) -> Self {
253                    Self { value }
254                }
255            }
256
257            impl #from<#type_ident> for #values_ident {
258                fn from(value: #type_ident) -> Self {
259                    value.value
260                }
261            }
262
263            impl #deref for #type_ident {
264                type Target = #values_ident;
265
266                fn deref(&self) -> &Self::Target {
267                    &self.value
268                }
269            }
270
271            impl #deref_mut for #type_ident {
272                fn deref_mut(&mut self) -> &mut Self::Target {
273                    &mut self.value
274                }
275            }
276
277            #derive
278            #( #[#extra_attributes] )*
279            pub enum #values_ident {
280                #( #variants )*
281            }
282
283            #( #trait_impls )*
284        };
285
286        ctx.current_module().append(code);
287
288        self.render_common_impls(ctx);
289    }
290}
291
292impl EnumerationTypeVariant<'_> {
293    fn render_variant_serde_xml_rs_v8(&self, ctx: &Context<'_, '_>) -> TokenStream {
294        let Self {
295            meta,
296            s_name,
297            variant_ident,
298            target_type,
299            extra_attributes,
300            ..
301        } = self;
302
303        let docs = ctx.render_docs(RendererFlags::RENDER_VARIANT_DOCS, &meta.documentation[..]);
304
305        let target_type = target_type.as_ref().map(|target_type| {
306            let target_type = ctx.resolve_type_for_module(target_type);
307
308            quote!((#target_type))
309        });
310
311        quote! {
312            #docs
313            #( #[#extra_attributes] )*
314            #[serde(rename = #s_name)]
315            #variant_ident #target_type,
316        }
317    }
318}
319
320/* SimpleData */
321
322impl SimpleData<'_> {
323    fn render_type_serde_xml_rs_v8(&self, ctx: &mut Context<'_, '_>) {
324        let Self {
325            occurs,
326            type_ident,
327            target_type,
328            trait_impls,
329            ..
330        } = self;
331
332        let docs = ctx.render_type_docs();
333        let target_type = ctx.resolve_type_for_module(target_type);
334        let target_type = occurs.make_type(ctx, &target_type, false);
335        let extra_attributes = &ctx.data.extra_attributes;
336
337        let derive = get_derive(ctx, []);
338        let trait_impls = render_trait_impls(type_ident, trait_impls);
339
340        let code = quote! {
341            #docs
342            #derive
343            #( #[#extra_attributes] )*
344            pub struct #type_ident(pub #target_type);
345
346            #( #trait_impls )*
347        };
348
349        ctx.current_module().append(code);
350
351        self.render_common_impls(ctx);
352    }
353}
354
355/* ComplexData */
356
357impl ComplexData<'_> {
358    fn render_type_serde_xml_rs_v8(&self, ctx: &mut Context<'_, '_>) {
359        match self {
360            Self::Enum {
361                type_,
362                content_type,
363            } => {
364                type_.render_type_serde_xml_rs_v8(ctx);
365
366                if let Some(content_type) = content_type {
367                    content_type.render_type_serde_xml_rs_v8(ctx);
368                }
369            }
370            Self::Struct {
371                type_,
372                content_type,
373            } => {
374                type_.render_type_serde_xml_rs_v8(ctx);
375
376                if let Some(content_type) = content_type {
377                    content_type.render_type_serde_xml_rs_v8(ctx);
378                }
379            }
380        }
381    }
382}
383
384impl ComplexDataEnum<'_> {
385    fn render_type_serde_xml_rs_v8(&self, ctx: &mut Context<'_, '_>) {
386        let docs = ctx.render_type_docs();
387        let derive = get_derive(ctx, []);
388        let type_ident = &self.type_ident;
389        let trait_impls = render_trait_impls(type_ident, &self.trait_impls);
390        let extra_attributes = &ctx.data.extra_attributes;
391
392        let variants = self
393            .elements
394            .iter()
395            .map(|x| x.render_variant_serde_xml_rs_v8(ctx));
396
397        let code = quote! {
398            #docs
399            #derive
400            #( #[#extra_attributes] )*
401            pub enum #type_ident {
402                #( #variants )*
403            }
404
405            #( #trait_impls )*
406        };
407
408        ctx.current_module().append(code);
409    }
410}
411
412impl ComplexDataStruct<'_> {
413    fn render_type_serde_xml_rs_v8(&self, ctx: &mut Context<'_, '_>) {
414        let docs = ctx.render_type_docs();
415        let derive = get_derive(ctx, []);
416        let type_ident = &self.type_ident;
417        let trait_impls = render_trait_impls(type_ident, &self.trait_impls);
418        let extra_attributes = &ctx.data.extra_attributes;
419
420        let attributes = self
421            .attributes
422            .iter()
423            .map(|x| x.render_field_serde_xml_rs_v8(ctx, type_ident));
424        let fields = self
425            .elements()
426            .iter()
427            .map(|x| x.render_field_serde_xml_rs_v8(ctx));
428        let content = self
429            .content()
430            .as_ref()
431            .and_then(|x| x.render_field_serde_xml_rs_v8(ctx));
432
433        let struct_data = if self.is_unit_struct() {
434            quote!(;)
435        } else {
436            quote! {
437                {
438                    #( #attributes )*
439                    #( #fields )*
440                    #content
441                }
442            }
443        };
444
445        let code = quote! {
446            #docs
447            #derive
448            #( #[#extra_attributes] )*
449            pub struct #type_ident
450                #struct_data
451
452            #( #trait_impls )*
453        };
454
455        ctx.current_module().append(code);
456    }
457}
458
459impl ComplexDataContent<'_> {
460    fn render_field_serde_xml_rs_v8(&self, ctx: &Context<'_, '_>) -> Option<TokenStream> {
461        let target_type = ctx.resolve_type_for_module(&self.target_type);
462        let target_type = self
463            .occurs
464            .array_to_vec()
465            .make_type(ctx, &target_type, false)?;
466        let extra_attributes = &self.extra_attributes;
467
468        let default =
469            (self.is_empty_string_content(ctx) || self.min_occurs == 0).then(|| quote!(default,));
470
471        match ctx
472            .get_resolved_complex_content()
473            .map(|(ident, meta)| (ident, &meta.variant))
474        {
475            Some((ident, MetaTypeVariant::Enumeration(_))) => {
476                let enum_values_type = format_enum_values_ident(&*ctx.meta.types.naming, ident);
477
478                Some(quote! {
479                    #( #[#extra_attributes] )*
480                    #[serde(#default rename = "#text")]
481                    pub content: #enum_values_type,
482                })
483            }
484            Some((_, MetaTypeVariant::BuildIn(_) | MetaTypeVariant::Reference(_))) => {
485                Some(quote! {
486                    #( #[#extra_attributes] )*
487                    #[serde(#default rename = "#text")]
488                    pub content: #target_type,
489                })
490            }
491            None | Some((_, _)) => Some(quote! {
492                #( #[#extra_attributes] )*
493                #[serde(#default rename = "#content")]
494                pub content: #target_type,
495            }),
496        }
497    }
498}
499
500impl ComplexDataAttribute<'_> {
501    fn render_field_serde_xml_rs_v8(
502        &self,
503        ctx: &Context<'_, '_>,
504        type_ident: &Ident2,
505    ) -> TokenStream {
506        let Self {
507            tag_name,
508            ident: field_ident,
509            extra_attributes,
510            ..
511        } = self;
512
513        let tag_name = tag_name.get(true);
514
515        let target_type = ctx.resolve_type_for_module(&self.target_type);
516        let target_type = if self.is_option {
517            let option = ctx.resolve_build_in("::core::option::Option");
518
519            quote!(#option<#target_type>)
520        } else {
521            target_type
522        };
523
524        let default = if self.default_value.is_some() {
525            let default_path = format!("{type_ident}::default_{field_ident}");
526
527            quote!(default = #default_path,)
528        } else if self.meta.use_ == Use::Optional {
529            quote!(default,)
530        } else {
531            quote!()
532        };
533
534        let docs = ctx.render_docs(
535            RendererFlags::RENDER_ATTRIBUTE_DOCS,
536            &self.meta.documentation[..],
537        );
538
539        let name = format!("@{tag_name}");
540
541        quote! {
542            #docs
543            #( #[#extra_attributes] )*
544            #[serde(#default rename = #name)]
545            pub #field_ident: #target_type,
546        }
547    }
548}
549
550impl ComplexDataElement<'_> {
551    fn render_field_serde_xml_rs_v8(&self, ctx: &Context<'_, '_>) -> TokenStream {
552        let Self {
553            tag_name,
554            field_ident,
555            extra_attributes,
556            ..
557        } = self;
558
559        let name = if self.meta().is_text() {
560            "#text".to_owned()
561        } else {
562            tag_name.get(true)
563        };
564
565        let target_type = ctx.resolve_type_for_module(&self.target_type);
566        let target_type = self
567            .occurs
568            .array_to_vec()
569            .make_type(ctx, &target_type, self.need_indirection)
570            .unwrap();
571
572        let docs = ctx.render_docs(
573            RendererFlags::RENDER_ELEMENT_DOCS,
574            &self.meta().documentation[..],
575        );
576
577        let default = match self.occurs.array_to_vec() {
578            Occurs::None | Occurs::Single | Occurs::StaticList(_) => quote!(),
579            Occurs::Optional | Occurs::DynamicList => quote!(default,),
580        };
581
582        quote! {
583            #docs
584            #( #[#extra_attributes] )*
585            #[serde(#default rename = #name)]
586            pub #field_ident: #target_type,
587        }
588    }
589
590    fn render_variant_serde_xml_rs_v8(&self, ctx: &Context<'_, '_>) -> TokenStream {
591        let Self {
592            tag_name,
593            variant_ident,
594            extra_attributes,
595            ..
596        } = self;
597
598        let name = if self.meta().is_text() {
599            "#text".to_owned()
600        } else {
601            tag_name.get(true)
602        };
603
604        let target_type = ctx.resolve_type_for_module(&self.target_type);
605        let target_type =
606            self.occurs
607                .array_to_vec()
608                .make_type(ctx, &target_type, self.need_indirection);
609
610        let docs = ctx.render_docs(
611            RendererFlags::RENDER_ELEMENT_DOCS,
612            &self.meta().documentation[..],
613        );
614
615        quote! {
616            #docs
617            #( #[#extra_attributes] )*
618            #[serde(rename = #name)]
619            #variant_ident(#target_type),
620        }
621    }
622}
623
624fn format_enum_values_ident(naming: &dyn Naming, ident: &Ident) -> Ident2 {
625    let values_ident = naming.format_type_name(ident.name.as_str());
626
627    format_ident!("{values_ident}Value")
628}