1mod data;
4mod error;
5mod helper;
6mod misc;
7mod renderer;
8
9use std::collections::{BTreeMap, HashSet, VecDeque};
10use std::fmt::Display;
11
12use proc_macro2::{Ident as Ident2, Literal, TokenStream};
13use quote::{format_ident, quote};
14use tracing::instrument;
15
16use crate::types::{Ident, IdentType, Type, TypeVariant, Types};
17
18pub use self::error::Error;
19pub use self::misc::{BoxFlags, GeneratorFlags, SerdeSupport, TypedefMode};
20
21use self::data::{Context, Request};
22use self::helper::Walk;
23use self::misc::{
24 format_module, format_type_ident, make_type_name, DynTypeTraits, Module, Modules, PendingType,
25 TraitInfos, TypeRef,
26};
27
28#[must_use]
30#[derive(Debug)]
31pub struct Generator<'types> {
32 config: Config<'types>,
33 state: State<'types>,
34}
35
36#[must_use]
42#[derive(Debug)]
43pub struct GeneratorFixed<'types> {
44 config: Config<'types>,
45 state: State<'types>,
46 modules: Modules,
47}
48
49#[derive(Debug)]
50struct Config<'types> {
51 types: &'types Types,
52
53 flags: GeneratorFlags,
54 derive: Vec<Ident2>,
55 postfixes: [String; 8],
56 box_flags: BoxFlags,
57 typedef_mode: TypedefMode,
58 serde_support: SerdeSupport,
59 dyn_type_traits: DynTypeTraits,
60 xsd_parser_crate: Ident2,
61}
62
63#[derive(Debug)]
64struct State<'types> {
65 cache: BTreeMap<Ident, TypeRef>,
66 trait_infos: Option<TraitInfos>,
67 pending: VecDeque<PendingType<'types>>,
68}
69
70impl<'types> Generator<'types> {
73 pub fn new(types: &'types Types) -> Self {
75 let config = Config {
76 types,
77 flags: GeneratorFlags::empty(),
78 derive: vec![format_ident!("Debug"), format_ident!("Clone")],
79 postfixes: [
80 String::from("Type"), String::new(), String::from("ElementType"), String::new(), String::new(), String::new(), String::new(), String::new(), ],
89 box_flags: BoxFlags::AUTO,
90 typedef_mode: TypedefMode::Auto,
91 serde_support: SerdeSupport::None,
92 dyn_type_traits: DynTypeTraits::Auto,
93 xsd_parser_crate: format_ident!("xsd_parser"),
94 };
95 let state = State {
96 cache: BTreeMap::new(),
97 trait_infos: None,
98 pending: VecDeque::new(),
99 };
100
101 Self { config, state }
102 }
103
104 pub fn xsd_parser_crate<S: Display>(mut self, value: S) -> Self {
107 self.config.xsd_parser_crate = format_ident!("{value}");
108
109 self
110 }
111
112 pub fn derive<I>(mut self, value: I) -> Self
123 where
124 I: IntoIterator,
125 I::Item: Display,
126 {
127 self.config.derive = value.into_iter().map(|x| format_ident!("{x}")).collect();
128
129 self
130 }
131
132 pub fn dyn_type_traits<I>(mut self, value: I) -> Self
143 where
144 I: IntoIterator,
145 I::Item: Into<String>,
146 {
147 fn parse_path(s: &str) -> TokenStream {
148 let parts = s.split("::").map(|x| format_ident!("{x}"));
149
150 quote! {
151 #( #parts )*
152 }
153 }
154
155 self.config.dyn_type_traits =
156 DynTypeTraits::Custom(value.into_iter().map(|x| parse_path(&x.into())).collect());
157
158 self
159 }
160
161 pub fn box_flags(mut self, value: BoxFlags) -> Self {
163 self.config.box_flags = value;
164
165 self
166 }
167
168 pub fn typedef_mode(mut self, value: TypedefMode) -> Self {
170 self.config.typedef_mode = value;
171
172 self
173 }
174
175 pub fn serde_support(mut self, value: SerdeSupport) -> Self {
177 self.config.serde_support = value;
178
179 self
180 }
181
182 pub fn flags(mut self, value: GeneratorFlags) -> Self {
184 self.config.flags = value;
185
186 self
187 }
188
189 pub fn with_flags(mut self, value: GeneratorFlags) -> Self {
191 self.config.flags |= value;
192
193 self
194 }
195
196 pub fn with_type_postfix<S: Into<String>>(mut self, type_: IdentType, postfix: S) -> Self {
200 self.config.postfixes[type_ as usize] = postfix.into();
201
202 self
203 }
204
205 pub fn with_type(mut self, ident: Ident) -> Result<Self, Error> {
223 let module_ident = format_module(self.config.types, ident.ns)?;
224 let type_ident = format_ident!("{}", ident.name.to_string());
225
226 let type_ref = TypeRef {
227 ident: ident.clone(),
228 module_ident,
229 type_ident,
230 boxed_elements: HashSet::new(),
231 };
232 self.state.cache.insert(ident, type_ref);
233
234 Ok(self)
235 }
236
237 #[instrument(err, level = "trace", skip(self))]
240 pub fn generate_type(self, ident: Ident) -> Result<GeneratorFixed<'types>, Error> {
241 self.into_fixed().generate_type(ident)
242 }
243
244 pub fn generate_all_types(self) -> Result<GeneratorFixed<'types>, Error> {
251 self.into_fixed().generate_all_types()
252 }
253
254 pub fn into_fixed(self) -> GeneratorFixed<'types> {
256 let Self { mut config, state } = self;
257 let modules = Modules::default();
258
259 if config.flags.intersects(GeneratorFlags::QUICK_XML) {
260 config.flags |= GeneratorFlags::WITH_NAMESPACE_CONSTANTS;
261 }
262
263 GeneratorFixed {
264 config,
265 state,
266 modules,
267 }
268 }
269}
270
271impl<'types> GeneratorFixed<'types> {
272 #[instrument(err, level = "trace", skip(self))]
284 pub fn generate_type(mut self, ident: Ident) -> Result<GeneratorFixed<'types>, Error> {
285 self.state.get_or_create_type_ref(&self.config, ident)?;
286 self.generate_pending()?;
287
288 Ok(self)
289 }
290
291 #[instrument(err, level = "trace", skip(self))]
304 pub fn generate_all_types(mut self) -> Result<Self, Error> {
305 for ident in self.config.types.keys() {
306 if ident.name.is_named() {
307 self.state
308 .get_or_create_type_ref(&self.config, ident.clone())?;
309 }
310 }
311 self.generate_pending()?;
312
313 Ok(self)
314 }
315
316 #[instrument(level = "trace", skip(self))]
320 pub fn finish(mut self) -> TokenStream {
321 let xsd_parser = &self.config.xsd_parser_crate;
322 let with_namespace_constants = self
323 .config
324 .check_flags(GeneratorFlags::WITH_NAMESPACE_CONSTANTS);
325
326 if with_namespace_constants {
327 self.modules
328 .0
329 .entry(None)
330 .or_default()
331 .main
332 .usings([quote!(#xsd_parser::schema::Namespace)]);
333 }
334
335 let namespace_constants = with_namespace_constants
336 .then(|| {
337 self.config.types.modules.values().filter_map(|module| {
338 let ns = module.namespace.as_ref()?;
339 let const_name = module.make_ns_const();
340 let const_name = const_name.ident();
341 let namespace = Literal::byte_string(&ns.0);
342
343 Some(quote! {
344 pub const #const_name: Namespace = Namespace::new_const(#namespace);
345 })
346 })
347 })
348 .into_iter()
349 .flatten();
350
351 let modules = self.modules.0.into_iter().map(|(ns, module)| {
352 let Module {
353 main,
354 quick_xml_serialize,
355 quick_xml_deserialize,
356 } = module;
357
358 let quick_xml_serialize = quick_xml_serialize.map(|code| {
359 quote! {
360 pub mod quick_xml_serialize {
361 #code
362 }
363 }
364 });
365
366 let quick_xml_deserialize = quick_xml_deserialize.map(|code| {
367 quote! {
368 pub mod quick_xml_deserialize {
369 #code
370 }
371 }
372 });
373
374 let code = quote! {
375 #main
376 #quick_xml_serialize
377 #quick_xml_deserialize
378 };
379
380 if let Some(name) =
381 ns.and_then(|ns| format_module(self.config.types, Some(ns)).unwrap())
382 {
383 quote! {
384 pub mod #name {
385 #code
386 }
387 }
388 } else {
389 code
390 }
391 });
392
393 quote! {
394 #( #namespace_constants )*
395
396 #( #modules )*
397 }
398 }
399
400 #[instrument(err, level = "trace", skip(self))]
401 fn generate_pending(&mut self) -> Result<(), Error> {
402 while let Some(args) = self.state.pending.pop_front() {
403 self.generate_type_intern(args)?;
404 }
405
406 Ok(())
407 }
408
409 #[instrument(err, level = "trace", skip(self))]
410 fn generate_type_intern(&mut self, data: PendingType<'types>) -> Result<(), Error> {
411 let PendingType { ty, ident } = data;
412 let Self {
413 config,
414 state,
415 modules,
416 } = self;
417 let req = Request::new(&ident, config, state);
418 let mut ctx = Context::new(&ident, config, modules);
419
420 tracing::debug!("Render type: {ident}");
421
422 match &ty.variant {
423 TypeVariant::BuildIn(_) => (),
424 TypeVariant::Union(x) => req.into_union_type(x)?.render(config, &mut ctx),
425 TypeVariant::Dynamic(x) => req.into_dynamic_type(x)?.render(config, &mut ctx),
426 TypeVariant::Reference(x) => req.into_reference_type(x)?.render(config, &mut ctx),
427 TypeVariant::Enumeration(x) => req.into_enumeration_type(x)?.render(config, &mut ctx),
428 TypeVariant::All(x) => req.into_all_type(x)?.render(config, &mut ctx),
429 TypeVariant::Choice(x) => req.into_choice_type(x)?.render(config, &mut ctx),
430 TypeVariant::Sequence(x) => req.into_sequence_type(x)?.render(config, &mut ctx),
431 TypeVariant::ComplexType(x) => req.into_complex_type(x)?.render(config, &mut ctx),
432 }
433
434 Ok(())
435 }
436}
437
438impl Config<'_> {
439 fn check_flags(&self, flags: GeneratorFlags) -> bool {
440 self.flags.intersects(flags)
441 }
442}
443
444impl<'types> State<'types> {
445 #[instrument(level = "trace", skip(self, config))]
446 fn get_or_create_type_ref(
447 &mut self,
448 config: &Config<'types>,
449 ident: Ident,
450 ) -> Result<&TypeRef, Error> {
451 if !self.cache.contains_key(&ident) {
452 let ty = config
453 .types
454 .get(&ident)
455 .ok_or_else(|| Error::UnknownType(ident.clone()))?;
456 let name = make_type_name(&config.postfixes, ty, &ident);
457 let (module_ident, type_ident) = if let TypeVariant::BuildIn(x) = &ty.variant {
458 (None, format_ident!("{x}"))
459 } else {
460 let use_modules = config.flags.intersects(GeneratorFlags::USE_MODULES);
461 let module_ident =
462 format_module(config.types, use_modules.then_some(ident.ns).flatten())?;
463 let type_ident = format_type_ident(&name, ty.display_name.as_deref());
464
465 (module_ident, type_ident)
466 };
467
468 tracing::debug!("Queue new type generation: {ident}");
469
470 let boxed_elements = get_boxed_elements(&ident, ty, config.types, &self.cache);
471 self.pending.push_back(PendingType {
472 ty,
473 ident: ident.clone(),
474 });
475
476 let type_ref = TypeRef {
477 ident: ident.clone(),
478 type_ident,
479 module_ident,
480 boxed_elements,
481 };
482
483 assert!(self.cache.insert(ident.clone(), type_ref).is_none());
484 }
485
486 Ok(self.cache.get_mut(&ident).unwrap())
487 }
488}
489
490fn get_boxed_elements<'a>(
493 ident: &Ident,
494 mut ty: &'a Type,
495 types: &'a Types,
496 cache: &BTreeMap<Ident, TypeRef>,
497) -> HashSet<Ident> {
498 if let TypeVariant::ComplexType(ci) = &ty.variant {
499 if let Some(type_) = ci.content.as_ref().and_then(|ident| types.get(ident)) {
500 ty = type_;
501 }
502 }
503
504 match &ty.variant {
505 TypeVariant::All(si) | TypeVariant::Choice(si) | TypeVariant::Sequence(si) => si
506 .elements
507 .iter()
508 .filter_map(|f| {
509 if Walk::new(types, cache).is_loop(ident, &f.type_) {
510 Some(f.ident.clone())
511 } else {
512 None
513 }
514 })
515 .collect(),
516 _ => HashSet::new(),
517 }
518}