xsd_parser/pipeline/renderer/steps/quick_xml/
collect_namespaces.rs1use proc_macro2::{Ident as Ident2, TokenStream};
2use quote::{format_ident, quote};
3
4use crate::config::TypedefMode;
5use crate::models::data::TagName;
6use crate::models::{
7 code::IdentPath,
8 data::{
9 ComplexBase, ComplexData, ComplexDataAttribute, ComplexDataElement, ComplexDataEnum,
10 ComplexDataStruct, DynamicData, EnumerationData, Occurs, ReferenceData, SimpleData,
11 StructMode, UnionData,
12 },
13 schema::xs::FormChoiceType,
14};
15
16use super::super::super::{
17 context::Context, DataTypeVariant, MetaData, RenderStep, RenderStepType,
18};
19
20macro_rules! resolve_ident {
21 ($ctx:ident, $path:expr) => {
22 $ctx.resolve_ident_path($path)
23 };
24}
25
26#[derive(Debug, Clone, Copy)]
33pub struct QuickXmlCollectNamespacesRenderStep;
34
35impl RenderStep for QuickXmlCollectNamespacesRenderStep {
36 fn render_step_type(&self) -> RenderStepType {
37 RenderStepType::ExtraImpls
38 }
39
40 fn initialize(&mut self, meta: &mut MetaData<'_>) {
41 let ident = IdentPath::from_parts(
42 [meta.xsd_parser_types.clone(), format_ident!("quick_xml")],
43 format_ident!("CollectNamespaces"),
44 );
45
46 if !meta.dyn_type_traits.contains(&ident) {
47 meta.dyn_type_traits.push(ident);
48 }
49 }
50
51 fn render_type(&mut self, ctx: &mut Context<'_, '_>) {
52 match &ctx.data.variant {
53 DataTypeVariant::BuildIn(_) | DataTypeVariant::Custom(_) => (),
54 DataTypeVariant::Union(x) => x.render_collect_namespaces(ctx),
55 DataTypeVariant::Dynamic(x) => x.render_collect_namespaces(ctx),
56 DataTypeVariant::Reference(x) => x.render_collect_namespaces(ctx),
57 DataTypeVariant::Enumeration(x) => x.render_collect_namespaces(ctx),
58 DataTypeVariant::Simple(x) => x.render_collect_namespaces(ctx),
59 DataTypeVariant::Complex(x) => x.render_collect_namespaces(ctx),
60 }
61 }
62}
63
64impl UnionData<'_> {
67 pub(crate) fn render_collect_namespaces(&self, ctx: &mut Context<'_, '_>) {
68 ctx.render_collect_namespaces_noop(&self.type_ident);
69 }
70}
71
72impl DynamicData<'_> {
75 pub(crate) fn render_collect_namespaces(&self, ctx: &mut Context<'_, '_>) {
76 let Self { type_ident, .. } = self;
77
78 let bytes_start = resolve_ident!(ctx, "::xsd_parser_types::quick_xml::BytesStart");
79 let collect_namespaces =
80 resolve_ident!(ctx, "::xsd_parser_types::quick_xml::CollectNamespaces");
81 let serialize_helper =
82 resolve_ident!(ctx, "::xsd_parser_types::quick_xml::SerializeHelper");
83
84 let code = quote! {
85 impl #collect_namespaces for #type_ident {
86 fn collect_namespaces(&self, helper: &mut #serialize_helper, bytes: &mut #bytes_start<'_>) {
87 self.0.collect_namespaces(helper, bytes);
88 }
89 }
90 };
91
92 ctx.current_module().append(code);
93 }
94}
95
96impl ReferenceData<'_> {
99 pub(crate) fn render_collect_namespaces(&self, ctx: &mut Context<'_, '_>) {
100 let Self {
101 mode, type_ident, ..
102 } = self;
103
104 if matches!(mode, TypedefMode::Auto | TypedefMode::Typedef) {
105 return;
106 }
107
108 let bytes_start = resolve_ident!(ctx, "::xsd_parser_types::quick_xml::BytesStart");
109 let collect_namespaces =
110 resolve_ident!(ctx, "::xsd_parser_types::quick_xml::CollectNamespaces");
111 let serialize_helper =
112 resolve_ident!(ctx, "::xsd_parser_types::quick_xml::SerializeHelper");
113
114 let code = quote! {
115 impl #collect_namespaces for #type_ident {
116 fn collect_namespaces(&self, helper: &mut #serialize_helper, bytes: &mut #bytes_start<'_>) {
117 self.0.collect_namespaces(helper, bytes);
118 }
119 }
120 };
121
122 ctx.current_module().append(code);
123 }
124}
125
126impl EnumerationData<'_> {
129 pub(crate) fn render_collect_namespaces(&self, ctx: &mut Context<'_, '_>) {
130 ctx.render_collect_namespaces_noop(&self.type_ident);
131 }
132}
133
134impl SimpleData<'_> {
137 pub(crate) fn render_collect_namespaces(&self, ctx: &mut Context<'_, '_>) {
138 ctx.render_collect_namespaces_noop(&self.type_ident);
139 }
140}
141
142impl ComplexData<'_> {
145 pub(crate) fn render_collect_namespaces(&self, ctx: &mut Context<'_, '_>) {
146 match self {
147 Self::Enum {
148 type_,
149 content_type,
150 } => {
151 type_.render_collect_namespaces(ctx);
152
153 if let Some(content_type) = content_type {
154 content_type.render_collect_namespaces(ctx);
155 }
156 }
157 Self::Struct {
158 type_,
159 content_type,
160 } => {
161 type_.render_collect_namespaces(ctx);
162
163 if let Some(content_type) = content_type {
164 content_type.render_collect_namespaces(ctx);
165 }
166 }
167 }
168 }
169}
170
171impl ComplexDataEnum<'_> {
172 fn render_collect_namespaces(&self, ctx: &mut Context<'_, '_>) {
173 let type_ident = &self.type_ident;
174
175 let own_ns = self.render_collect_own_namespace(ctx);
176
177 let variants = self
178 .elements
179 .iter()
180 .map(ComplexDataElement::render_collect_namespaces_match_arm);
181
182 let bytes_start = resolve_ident!(ctx, "::xsd_parser_types::quick_xml::BytesStart");
183 let collect_namespaces =
184 resolve_ident!(ctx, "::xsd_parser_types::quick_xml::CollectNamespaces");
185 let serialize_helper =
186 resolve_ident!(ctx, "::xsd_parser_types::quick_xml::SerializeHelper");
187
188 let code = quote! {
189 impl #collect_namespaces for #type_ident {
190 fn collect_namespaces(&self, helper: &mut #serialize_helper, bytes: &mut #bytes_start<'_>) {
191 #own_ns
192 match self {
193 #( #variants )*
194 }
195 }
196 }
197 };
198
199 ctx.current_module().append(code);
200 }
201}
202
203impl ComplexDataStruct<'_> {
204 fn render_collect_namespaces(&self, ctx: &mut Context<'_, '_>) {
205 let type_ident = &self.type_ident;
206
207 let own_ns = self.render_collect_own_namespace(ctx);
208 let attrib_ns = self.render_collect_attribute_namespaces(ctx);
209
210 let field_calls: Vec<_> = match &self.mode {
211 StructMode::Empty { .. } => Vec::new(),
212 StructMode::Content { .. } => {
213 vec![quote! {
214 self.content.collect_namespaces(helper, bytes);
215 }]
216 }
217 StructMode::All { elements, .. } | StructMode::Sequence { elements, .. } => elements
218 .iter()
219 .map(ComplexDataElement::render_collect_namespaces_field_call)
220 .collect(),
221 };
222
223 let bytes_start = resolve_ident!(ctx, "::xsd_parser_types::quick_xml::BytesStart");
224 let collect_namespaces =
225 resolve_ident!(ctx, "::xsd_parser_types::quick_xml::CollectNamespaces");
226 let serialize_helper =
227 resolve_ident!(ctx, "::xsd_parser_types::quick_xml::SerializeHelper");
228
229 let code = quote! {
230 impl #collect_namespaces for #type_ident {
231 fn collect_namespaces(&self, helper: &mut #serialize_helper, bytes: &mut #bytes_start<'_>) {
232 #own_ns
233 #( #attrib_ns )*
234 #( #field_calls )*
235 }
236 }
237 };
238
239 ctx.current_module().append(code);
240 }
241}
242
243impl ComplexBase<'_> {
244 fn render_collect_own_namespace(&self, ctx: &Context<'_, '_>) -> Option<TokenStream> {
245 self.tag_name.as_ref()?.render_collect_namespace(ctx)
246 }
247}
248
249impl ComplexDataStruct<'_> {
250 fn render_collect_attribute_namespaces(&self, ctx: &Context<'_, '_>) -> Vec<TokenStream> {
251 self.attributes
252 .iter()
253 .filter_map(|attrib| attrib.render_collect_attribute_namespace(ctx))
254 .collect()
255 }
256}
257
258impl ComplexDataAttribute<'_> {
259 fn render_collect_attribute_namespace(&self, ctx: &Context<'_, '_>) -> Option<TokenStream> {
260 self.tag_name.render_collect_namespace(ctx)
261 }
262}
263
264impl ComplexDataElement<'_> {
265 fn render_collect_namespaces_field_call(&self) -> TokenStream {
266 let field_ident = &self.field_ident;
267
268 match self.occurs {
269 Occurs::None => unreachable!(),
270 Occurs::Single => quote! {
271 self.#field_ident.collect_namespaces(helper, bytes);
272 },
273 Occurs::Optional => quote! {
274 if let Some(inner) = &self.#field_ident {
275 inner.collect_namespaces(helper, bytes);
276 }
277 },
278 Occurs::DynamicList | Occurs::StaticList(_) => quote! {
279 for item in &self.#field_ident {
280 item.collect_namespaces(helper, bytes);
281 }
282 },
283 }
284 }
285
286 fn render_collect_namespaces_match_arm(&self) -> TokenStream {
287 let variant_ident = &self.variant_ident;
288
289 match self.occurs {
290 Occurs::None => unreachable!(),
291 Occurs::Single => quote! {
292 Self::#variant_ident(x) => x.collect_namespaces(helper, bytes),
293 },
294 Occurs::Optional => quote! {
295 Self::#variant_ident(x) => {
296 if let Some(inner) = x {
297 inner.collect_namespaces(helper, bytes);
298 }
299 }
300 },
301 Occurs::DynamicList | Occurs::StaticList(_) => quote! {
302 Self::#variant_ident(x) => {
303 for item in x.iter() {
304 item.collect_namespaces(helper, bytes);
305 }
306 }
307 },
308 }
309 }
310}
311
312impl Context<'_, '_> {
315 fn render_collect_namespaces_noop(&mut self, type_ident: &Ident2) {
316 let bytes_start = resolve_ident!(self, "::xsd_parser_types::quick_xml::BytesStart");
317 let collect_namespaces =
318 resolve_ident!(self, "::xsd_parser_types::quick_xml::CollectNamespaces");
319 let serialize_helper =
320 resolve_ident!(self, "::xsd_parser_types::quick_xml::SerializeHelper");
321
322 let code = quote! {
323 impl #collect_namespaces for #type_ident {
324 fn collect_namespaces(&self, _helper: &mut #serialize_helper, _bytes: &mut #bytes_start<'_>) { }
325 }
326 };
327
328 self.current_module().append(code);
329 }
330}
331
332impl TagName<'_> {
333 fn render_collect_namespace(&self, ctx: &Context<'_, '_>) -> Option<TokenStream> {
334 if self.form != FormChoiceType::Qualified {
335 return None;
336 }
337
338 let module = self.module?;
339 let ns = module.make_ns_const()?;
340 let ns_const = ctx.resolve_type_for_module(&ns);
341
342 let prefix = module.make_prefix_const()?;
343 let prefix_const = ctx.resolve_type_for_module(&prefix);
344
345 Some(quote! {
346 helper.write_xmlns(bytes, Some(&#prefix_const), &#ns_const);
347 })
348 }
349}