Skip to main content

xsd_parser/pipeline/renderer/steps/
with_namespace_trait.rs

1use proc_macro2::{Ident as Ident2, TokenStream};
2use quote::quote;
3
4use crate::config::TypedefMode;
5use crate::models::data::{
6    ComplexData, ComplexDataEnum, ComplexDataStruct, DynamicData, EnumerationData, ReferenceData,
7    SimpleData, UnionData,
8};
9
10use super::super::{Context, DataTypeVariant, RenderStep, RenderStepType};
11
12/// Implements a [`RenderStep`] that renders the [`WithNamespace`](xsd_parser_types::WithNamespace)
13/// trait for each type defined in the schema.
14#[derive(Debug, Clone, Copy)]
15pub struct WithNamespaceTraitRenderStep;
16
17impl RenderStep for WithNamespaceTraitRenderStep {
18    fn render_step_type(&self) -> RenderStepType {
19        RenderStepType::ExtraImpls
20    }
21
22    fn render_type(&mut self, ctx: &mut Context<'_, '_>) {
23        match &ctx.data.variant {
24            DataTypeVariant::BuildIn(_) | DataTypeVariant::Custom(_) => (),
25            DataTypeVariant::Union(x) => x.render_with_namespace_trait(ctx),
26            DataTypeVariant::Dynamic(x) => x.render_with_namespace_trait(ctx),
27            DataTypeVariant::Reference(x) => x.render_with_namespace_trait(ctx),
28            DataTypeVariant::Enumeration(x) => x.render_with_namespace_trait(ctx),
29            DataTypeVariant::Simple(x) => x.render_with_namespace_trait(ctx),
30            DataTypeVariant::Complex(x) => x.render_with_namespace_trait(ctx),
31        }
32    }
33}
34
35/* UnionData */
36
37impl UnionData<'_> {
38    pub(crate) fn render_with_namespace_trait(&self, ctx: &mut Context<'_, '_>) {
39        if let Some(code) = render_trait_with_namespace(ctx, &self.type_ident) {
40            ctx.current_module().append(code);
41        }
42    }
43}
44
45/* DynamicData */
46
47impl DynamicData<'_> {
48    pub(crate) fn render_with_namespace_trait(&self, ctx: &mut Context<'_, '_>) {
49        if let Some(code) = render_trait_with_namespace(ctx, &self.type_ident) {
50            ctx.current_module().append(code);
51        }
52    }
53}
54
55/* ReferenceData */
56
57impl ReferenceData<'_> {
58    pub(crate) fn render_with_namespace_trait(&self, ctx: &mut Context<'_, '_>) {
59        // Skip generating impl for type aliases - they share the underlying type's impl.
60        // Only newtypes (tuple structs) need their own impl.
61        if self.mode == TypedefMode::Typedef {
62            return;
63        }
64
65        if let Some(code) = render_trait_with_namespace(ctx, &self.type_ident) {
66            ctx.current_module().append(code);
67        }
68    }
69}
70
71/* EnumerationData */
72
73impl EnumerationData<'_> {
74    pub(crate) fn render_with_namespace_trait(&self, ctx: &mut Context<'_, '_>) {
75        if let Some(code) = render_trait_with_namespace(ctx, &self.type_ident) {
76            ctx.current_module().append(code);
77        }
78    }
79}
80
81/* SimpleData */
82
83impl SimpleData<'_> {
84    pub(crate) fn render_with_namespace_trait(&self, ctx: &mut Context<'_, '_>) {
85        if let Some(code) = render_trait_with_namespace(ctx, &self.type_ident) {
86            ctx.current_module().append(code);
87        }
88    }
89}
90
91/* ComplexData */
92
93impl ComplexData<'_> {
94    pub(crate) fn render_with_namespace_trait(&self, ctx: &mut Context<'_, '_>) {
95        match self {
96            Self::Enum {
97                type_,
98                content_type,
99            } => {
100                type_.render_with_namespace_trait(ctx);
101
102                if let Some(content_type) = content_type {
103                    content_type.render_with_namespace_trait(ctx);
104                }
105            }
106            Self::Struct {
107                type_,
108                content_type,
109            } => {
110                type_.render_with_namespace_trait(ctx);
111
112                if let Some(content_type) = content_type {
113                    content_type.render_with_namespace_trait(ctx);
114                }
115            }
116        }
117    }
118}
119
120impl ComplexDataEnum<'_> {
121    fn render_with_namespace_trait(&self, ctx: &mut Context<'_, '_>) {
122        if let Some(code) = render_trait_with_namespace(ctx, &self.type_ident) {
123            ctx.current_module().append(code);
124        }
125    }
126}
127
128impl ComplexDataStruct<'_> {
129    fn render_with_namespace_trait(&self, ctx: &mut Context<'_, '_>) {
130        if let Some(code) = render_trait_with_namespace(ctx, &self.type_ident) {
131            ctx.current_module().append(code);
132        }
133    }
134}
135
136fn render_trait_with_namespace(ctx: &Context<'_, '_>, type_ident: &Ident2) -> Option<TokenStream> {
137    let ns = ctx.ident.ns;
138    let module = ctx.types.meta.types.modules.get(&ns)?;
139    let xsd_parser_types = &ctx.xsd_parser_types;
140
141    let (prefix, namespace) = match (&module.prefix, &module.namespace) {
142        (Some(prefix), Some(namespace)) => {
143            let prefix = prefix.as_str();
144            let namespace = namespace.to_string();
145
146            (quote!(Some(#prefix)), quote!(Some(#namespace)))
147        }
148        (None, Some(namespace)) => {
149            let namespace = namespace.to_string();
150
151            (quote!(None), quote!(Some(#namespace)))
152        }
153        (_, None) => (quote!(None), quote!(None)),
154    };
155
156    let str_ = ctx.resolve_build_in("::core::primitive::str");
157    let option = ctx.resolve_build_in("::core::option::Option");
158
159    Some(quote! {
160        impl #xsd_parser_types::WithNamespace for #type_ident {
161            fn prefix() -> #option<&'static #str_> {
162                #prefix
163            }
164
165            fn namespace() -> #option<&'static #str_> {
166                #namespace
167            }
168        }
169    })
170}