xsd_parser/pipeline/generator/
context.rs1use std::collections::BTreeMap;
2use std::ops::Deref;
3
4use bit_set::BitSet;
5use proc_macro2::{Literal, TokenStream};
6use quote::{format_ident, quote};
7use xsd_parser_types::xml::NamespacesShared;
8
9use crate::config::GeneratorFlags;
10use crate::models::{
11 code::{ModuleIdent, ModulePath},
12 data::Occurs,
13 meta::{BuildInMeta, MetaTypeVariant},
14 schema::xs::Use,
15 TypeIdent,
16};
17use crate::pipeline::generator::ValueGeneratorMode;
18use crate::pipeline::renderer::{Context as RendererContext, ValueRendererBox};
19
20use super::{Error, MetaData, State, TraitInfos, TypeRef};
21
22#[derive(Debug)]
24pub struct Context<'a, 'types> {
25 pub meta: &'a MetaData<'types>,
27
28 pub ident: &'a TypeIdent,
30
31 state: &'a mut State<'types>,
32 reachable: BitSet<u64>,
33 namespaces: Vec<NamespacesShared<'static>>,
34}
35
36impl<'a, 'types> Context<'a, 'types> {
37 #[must_use]
39 pub fn namespaces(&self) -> Option<&NamespacesShared<'static>> {
40 self.namespaces.last()
41 }
42
43 pub(super) fn new(
44 meta: &'a MetaData<'types>,
45 ident: &'a TypeIdent,
46 state: &'a mut State<'types>,
47 ) -> Self {
48 let reachable = state.loop_detection.get_reachable(&state.cache, ident);
49
50 Self {
51 meta,
52 ident,
53 state,
54 reachable,
55 namespaces: Vec::new(),
56 }
57 }
58
59 pub(super) fn current_module(&self) -> ModuleIdent {
60 ModuleIdent::new(
61 self.meta.types,
62 self.ident,
63 self.check_generator_flags(GeneratorFlags::USE_NAMESPACE_MODULES),
64 self.check_generator_flags(GeneratorFlags::USE_SCHEMA_MODULES),
65 )
66 }
67
68 pub(super) fn current_type_ref(&self) -> &TypeRef {
69 self.state.cache.get(self.ident).unwrap()
70 }
71
72 pub(super) fn get_trait_infos(&mut self) -> &TraitInfos {
73 self.state
74 .trait_infos
75 .get_or_insert_with(|| TraitInfos::new(self.meta.types))
76 }
77
78 pub(super) fn get_or_create_type_ref(&mut self, ident: &TypeIdent) -> Result<&TypeRef, Error> {
79 let type_ref = self.state.get_or_create_type_ref_mut(self.meta, ident)?;
80
81 Ok(type_ref)
82 }
83
84 pub(super) fn get_or_create_type_ref_for_value(
85 &mut self,
86 ident: &TypeIdent,
87 by_value: bool,
88 ) -> Result<&TypeRef, Error> {
89 let type_ref = self.state.get_or_create_type_ref_mut(self.meta, ident)?;
90
91 if by_value {
92 type_ref.reachable.union_with(&self.reachable);
93 }
94
95 Ok(type_ref)
96 }
97
98 pub(super) fn get_or_create_type_ref_for_element(
99 &mut self,
100 ident: &TypeIdent,
101 by_value: bool,
102 ) -> Result<(&TypeRef, bool), Error> {
103 let boxed = by_value && need_box(&mut self.reachable, &self.state.cache, self.meta, ident);
104 let type_ref = self.state.get_or_create_type_ref_mut(self.meta, ident)?;
105
106 if !boxed {
107 type_ref.reachable.union_with(&self.reachable);
108 }
109
110 Ok((type_ref, boxed))
111 }
112
113 pub(super) fn make_trait_impls(&mut self) -> Result<Vec<TokenStream>, Error> {
114 let ident = self.ident.clone();
115 let current_module = self.current_module();
116 let module_path = ModulePath::from_ident(self.types, current_module);
117
118 self.get_trait_infos()
119 .get(&ident)
120 .into_iter()
121 .flat_map(|info| &info.traits_all)
122 .cloned()
123 .collect::<Vec<_>>()
124 .into_iter()
125 .map(|ident| {
126 let type_ref = self.get_or_create_type_ref(&ident)?;
127 let ident = format_ident!("{}Trait", type_ref.path.ident());
128 let trait_type = (*type_ref.path).clone().with_ident(ident);
129 let trait_ident = trait_type.relative_to(&module_path);
130
131 Ok(trait_ident)
132 })
133 .collect::<Result<Vec<_>, _>>()
134 }
135
136 #[allow(clippy::too_many_lines)]
137 pub(super) fn make_value_renderer(
138 &mut self,
139 ident: &TypeIdent,
140 value: &str,
141 mode: ValueGeneratorMode,
142 ) -> Result<ValueRendererBox, Error> {
143 use ValueGeneratorMode::Constant as C;
144 use ValueGeneratorMode::Value as V;
145
146 let types = self.types;
147 let ty = types
148 .items
149 .get(ident)
150 .ok_or_else(|| Error::UnknownType(ident.clone()))?;
151 let type_ref = self.get_or_create_type_ref(ident)?;
152
153 macro_rules! build_in {
154 ($ty:ty) => {
155 if let Ok(val) = value.parse::<$ty>() {
156 return Ok(Box::new(if mode == ValueGeneratorMode::Literal {
157 let val = Literal::byte_string(value.as_bytes());
158
159 quote!(#val)
160 } else {
161 quote!(#val)
162 }));
163 }
164 };
165 }
166
167 match (mode, &ty.variant) {
168 (_, MetaTypeVariant::BuildIn(BuildInMeta::U8)) => build_in!(u8),
169 (_, MetaTypeVariant::BuildIn(BuildInMeta::U16)) => build_in!(u16),
170 (_, MetaTypeVariant::BuildIn(BuildInMeta::U32)) => build_in!(u32),
171 (_, MetaTypeVariant::BuildIn(BuildInMeta::U64)) => build_in!(u64),
172 (_, MetaTypeVariant::BuildIn(BuildInMeta::U128)) => build_in!(u128),
173 (_, MetaTypeVariant::BuildIn(BuildInMeta::Usize)) => build_in!(usize),
174
175 (_, MetaTypeVariant::BuildIn(BuildInMeta::I8)) => build_in!(i8),
176 (_, MetaTypeVariant::BuildIn(BuildInMeta::I16)) => build_in!(i16),
177 (_, MetaTypeVariant::BuildIn(BuildInMeta::I32)) => build_in!(i32),
178 (_, MetaTypeVariant::BuildIn(BuildInMeta::I64)) => build_in!(i64),
179 (_, MetaTypeVariant::BuildIn(BuildInMeta::I128)) => build_in!(i128),
180 (_, MetaTypeVariant::BuildIn(BuildInMeta::Isize)) => build_in!(isize),
181
182 (C | V, MetaTypeVariant::BuildIn(BuildInMeta::F32)) => build_in!(f32),
183 (C | V, MetaTypeVariant::BuildIn(BuildInMeta::F64)) => build_in!(f64),
184
185 (C | V, MetaTypeVariant::BuildIn(BuildInMeta::Bool)) => {
186 match value.to_ascii_lowercase().as_str() {
187 "true" | "yes" | "1" => return Ok(Box::new(quote!(true))),
188 "false" | "no" | "0" => return Ok(Box::new(quote!(false))),
189 _ => (),
190 }
191 }
192 (_, MetaTypeVariant::BuildIn(BuildInMeta::Str)) => {
193 return Ok(Box::new(if mode == ValueGeneratorMode::Literal {
194 let val = Literal::byte_string(value.as_bytes());
195
196 quote!(#val)
197 } else {
198 quote!(#value)
199 }));
200 }
201 (V, MetaTypeVariant::BuildIn(BuildInMeta::String)) => {
202 let value = value.to_string();
203 let string = self
204 .get_or_create_type_ref(&TypeIdent::STRING)?
205 .path
206 .clone();
207
208 return Ok(Box::new(move |ctx: &RendererContext<'_, '_>| {
209 let string = ctx.resolve_type_for_module(&string);
210
211 quote!(#string::from(#value))
212 }));
213 }
214
215 (mode, MetaTypeVariant::Custom(x)) => {
216 if let Some(default) = &x.default {
217 return default.exec(self, value, mode);
218 }
219 }
220
221 (mode, MetaTypeVariant::Enumeration(ei)) => {
222 let target_type = type_ref.path.clone();
223
224 for var in &*ei.variants {
225 if var.type_.is_none() && var.ident.name.as_str() == value {
226 let variant_ident = self
227 .types
228 .naming
229 .format_variant_ident(&var.ident.name, var.display_name.as_deref());
230
231 return Ok(Box::new(move |ctx: &RendererContext<'_, '_>| {
232 let target_type = ctx.resolve_type_for_module(&target_type);
233
234 quote!(#target_type :: #variant_ident)
235 }));
236 }
237
238 if let Some(target_ident) = &var.type_ {
239 if let Ok(inner) = self.make_value_renderer(target_ident, value, mode) {
240 let variant_ident = match self.state.cache.get(target_ident) {
241 Some(type_ref) if var.ident.name.is_generated() => {
242 type_ref.path.ident().clone()
243 }
244 _ => self.types.naming.format_variant_ident(
245 &var.ident.name,
246 var.display_name.as_deref(),
247 ),
248 };
249
250 return Ok(Box::new(move |ctx: &RendererContext<'_, '_>| {
251 let inner = inner.render(ctx);
252 let target_type = ctx.resolve_type_for_module(&target_type);
253
254 quote!(#target_type :: #variant_ident(#inner))
255 }));
256 }
257 }
258 }
259 }
260
261 (mode, MetaTypeVariant::Union(ui)) => {
262 let target_type = type_ref.path.clone();
263
264 for ty in &*ui.types {
265 if let Ok(inner) = self.make_value_renderer(&ty.type_, value, mode) {
266 let variant_ident = match self.state.cache.get(&ty.type_) {
267 Some(type_ref) if ty.type_.name.is_generated() => {
268 type_ref.path.ident().clone()
269 }
270 _ => self
271 .types
272 .naming
273 .format_variant_ident(&ty.type_.name, ty.display_name.as_deref()),
274 };
275
276 return Ok(Box::new(move |ctx: &RendererContext<'_, '_>| {
277 let inner = inner.render(ctx);
278 let target_type = ctx.resolve_type_for_module(&target_type);
279
280 quote!(#target_type :: #variant_ident ( #inner ))
281 }));
282 }
283 }
284 }
285
286 (mode, MetaTypeVariant::Reference(ti)) => {
287 match Occurs::from_occurs(ti.min_occurs, ti.max_occurs) {
288 Occurs::Single => return self.make_value_renderer(&ti.type_, value, mode),
289 Occurs::DynamicList
290 if value.is_empty() && mode == ValueGeneratorMode::Value =>
291 {
292 let target_type = type_ref.path.clone();
293
294 return Ok(Box::new(move |ctx: &RendererContext<'_, '_>| {
295 let vec = ctx.resolve_build_in("::alloc::vec::Vec");
296 let target_type = ctx.resolve_type_for_module(&target_type);
297
298 quote! { #target_type(#vec::new()) }
299 }));
300 }
301 _ => (),
302 }
303 }
304
305 (mode, MetaTypeVariant::SimpleType(si)) => {
306 let target_type = type_ref.path.clone();
307 let inner = self.make_value_renderer(&si.base, value, mode)?;
308
309 return Ok(Box::new(move |ctx: &RendererContext<'_, '_>| {
310 let inner = inner.render(ctx);
311 let target_type = ctx.resolve_type_for_module(&target_type);
312
313 quote! { #target_type(#inner) }
314 }));
315 }
316
317 _ => (),
318 }
319
320 Err(Error::InvalidDefaultValue {
321 ident: ident.clone(),
322 value: value.to_owned(),
323 mode,
324 })
325 }
326
327 pub(super) fn push_namespaces(&mut self, namespaces: NamespacesShared<'static>) {
328 self.namespaces.push(namespaces);
329 }
330
331 pub(super) fn pop_namespaces(&mut self) {
332 self.namespaces.pop();
333 }
334}
335
336impl<'types> Deref for Context<'_, 'types> {
337 type Target = MetaData<'types>;
338
339 fn deref(&self) -> &Self::Target {
340 self.meta
341 }
342}
343
344fn need_box(
345 reachable: &mut BitSet<u64>,
346 cache: &BTreeMap<TypeIdent, TypeRef>,
347 meta: &MetaData<'_>,
348 ident: &TypeIdent,
349) -> bool {
350 let Some(ty) = meta.types.items.get(ident) else {
351 return false;
352 };
353
354 let Some(type_ref) = cache.get(ident) else {
355 return false;
356 };
357
358 if !reachable.insert(type_ref.id) {
359 return true;
360 }
361
362 let mut ret = false;
363
364 match &ty.variant {
365 MetaTypeVariant::Reference(x) => {
366 let occurs = Occurs::from_occurs(x.min_occurs, x.max_occurs);
367
368 if occurs.is_direct() {
369 ret = need_box(reachable, cache, meta, &x.type_);
370 }
371 }
372 MetaTypeVariant::Union(x) => {
373 for var in x.types.iter() {
374 ret = ret || need_box(reachable, cache, meta, &var.type_);
375 }
376 }
377 MetaTypeVariant::Enumeration(x) => {
378 for var in x.variants.iter() {
379 if let Some(type_) = &var.type_ {
380 if var.use_ != Use::Prohibited {
381 ret = ret || need_box(reachable, cache, meta, type_);
382 }
383 }
384 }
385 }
386 MetaTypeVariant::All(_)
387 | MetaTypeVariant::Choice(_)
388 | MetaTypeVariant::Sequence(_)
389 | MetaTypeVariant::ComplexType(_)
390 | MetaTypeVariant::Dynamic(_)
391 | MetaTypeVariant::SimpleType(_)
392 | MetaTypeVariant::BuildIn(_)
393 | MetaTypeVariant::Custom(_) => (),
394 }
395
396 reachable.remove(type_ref.id);
397
398 ret
399}