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

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