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