1use std::borrow::Cow;
2use std::collections::{BTreeMap, BTreeSet, HashSet};
3use std::ops::Deref;
4
5use bitflags::bitflags;
6use inflector::Inflector;
7use proc_macro2::{Ident as Ident2, TokenStream};
8use quote::{format_ident, quote};
9
10use crate::schema::{MaxOccurs, MinOccurs, NamespaceId};
11use crate::types::{DynamicInfo, Ident, Name, Type, Types};
12
13use super::Error;
14
15bitflags! {
16 #[derive(Debug, Clone, Copy)]
19 pub struct GenerateFlags: u32 {
20 #[doc = include_str!("../../tests/generator/generate_flags/schema.xsd")]
27 #[doc = include_str!("../../tests/generator/generate_flags/expected/empty.rs")]
32 const NONE = 0;
34
35 #[doc = include_str!("../../tests/generator/generate_flags/schema.xsd")]
42 #[doc = include_str!("../../tests/generator/generate_flags/expected/use_modules.rs")]
47 const USE_MODULES = 1 << 0;
49
50 #[doc = include_str!("../../tests/generator/generate_flags/schema.xsd")]
58 #[doc = include_str!("../../tests/generator/generate_flags/expected/flatten_content.rs")]
63 const FLATTEN_CONTENT = 1 << 1;
65
66 const QUICK_XML_SERIALIZE = 1 << 2;
69
70 const QUICK_XML_DESERIALIZE = 1 << 3;
73
74 const QUICK_XML = Self::QUICK_XML_SERIALIZE.bits() | Self::QUICK_XML_DESERIALIZE.bits();
76
77 const WITH_NAMESPACE_TRAIT = 1 << 4;
79 }
80}
81
82bitflags! {
83 #[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
86 pub struct BoxFlags: u32 {
87 #[doc = include_str!("../../tests/generator/box_flags/schema.xsd")]
94 #[doc = include_str!("../../tests/generator/box_flags/expected/auto.rs")]
99 const AUTO = 0;
101
102 #[doc = include_str!("../../tests/generator/box_flags/schema.xsd")]
109 #[doc = include_str!("../../tests/generator/box_flags/expected/enum_elements.rs")]
114 const ENUM_ELEMENTS = 1 << 0;
116
117 #[doc = include_str!("../../tests/generator/box_flags/schema.xsd")]
124 #[doc = include_str!("../../tests/generator/box_flags/expected/struct_elements.rs")]
129 const STRUCT_ELEMENTS = 1 << 1;
131 }
132}
133
134#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
137pub enum ContentMode {
138 #[doc = include_str!("../../tests/generator/content_mode/schema.xsd")]
147 #[doc = include_str!("../../tests/generator/content_mode/expected/auto.rs")]
152 #[default]
154 Auto,
155
156 #[doc = include_str!("../../tests/generator/content_mode/schema.xsd")]
163 #[doc = include_str!("../../tests/generator/content_mode/expected/enum.rs")]
168 Enum,
170
171 #[doc = include_str!("../../tests/generator/content_mode/schema.xsd")]
178 #[doc = include_str!("../../tests/generator/content_mode/expected/struct.rs")]
183 Struct,
185}
186
187#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
189pub enum TypedefMode {
190 #[doc = include_str!("../../tests/generator/typedef_mode/schema.xsd")]
205 #[doc = include_str!("../../tests/generator/typedef_mode/expected/auto.rs")]
210 #[default]
212 Auto,
213
214 #[doc = include_str!("../../tests/generator/typedef_mode/schema.xsd")]
222 #[doc = include_str!("../../tests/generator/typedef_mode/expected/typedef.rs")]
227 Typedef,
229
230 #[doc = include_str!("../../tests/generator/typedef_mode/schema.xsd")]
238 #[doc = include_str!("../../tests/generator/typedef_mode/expected/new_type.rs")]
243 NewType,
245}
246
247#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
250pub enum SerdeSupport {
251 #[doc = include_str!("../../tests/generator/serde_support/schema.xsd")]
258 #[doc = include_str!("../../tests/generator/serde_support/expected/none.rs")]
263 #[default]
265 None,
266
267 #[doc = include_str!("../../tests/generator/serde_support/schema.xsd")]
275 #[doc = include_str!("../../tests/generator/serde_support/expected/quick_xml.rs")]
280 QuickXml,
282
283 #[doc = include_str!("../../tests/generator/serde_support/schema.xsd")]
291 #[doc = include_str!("../../tests/generator/serde_support/expected/serde_xml_rs.rs")]
296 SerdeXmlRs,
298}
299
300impl SerdeSupport {
301 #[must_use]
303 pub fn is_none(&self) -> bool {
304 matches!(self, Self::None)
305 }
306}
307
308#[derive(Default, Debug)]
311pub(super) struct Modules(pub BTreeMap<Option<NamespaceId>, Module>);
312
313impl Modules {
314 pub(super) fn get_mut(&mut self, ns: Option<NamespaceId>) -> &mut Module {
315 self.0.entry(ns).or_default()
316 }
317
318 pub(super) fn add_code(&mut self, ns: Option<NamespaceId>, code: TokenStream) {
319 self.get_mut(ns).code.extend(code);
320 }
321}
322
323#[derive(Default, Debug)]
326pub(super) struct Module {
327 pub code: TokenStream,
328 pub quick_xml_serialize: Option<TokenStream>,
329 pub quick_xml_deserialize: Option<TokenStream>,
330}
331
332#[derive(Debug)]
335pub(super) struct PendingType<'types> {
336 pub ty: &'types Type,
337 pub ident: Ident,
338}
339
340#[derive(Debug)]
343pub(super) struct TypeRef {
344 pub ns: Option<NamespaceId>,
345 pub module_ident: Option<Ident2>,
346 pub type_ident: Ident2,
347 pub flags: StateFlags,
348 pub boxed_elements: HashSet<Ident>,
349}
350
351#[derive(Debug)]
354pub(super) struct TraitInfos(BTreeMap<Ident, TraitInfo>);
355
356impl TraitInfos {
357 #[must_use]
358 pub(super) fn new(types: &Types) -> Self {
359 let mut ret = Self(BTreeMap::new());
360
361 for (base_ident, ty) in types.iter() {
362 let Type::Dynamic(ai) = ty else {
363 continue;
364 };
365
366 for type_ident in &ai.derived_types {
367 ret.0
368 .entry(type_ident.clone())
369 .or_default()
370 .traits_all
371 .insert(base_ident.clone());
372
373 match types.get(type_ident) {
374 Some(Type::Dynamic(DynamicInfo {
375 type_: Some(type_ident),
376 ..
377 })) => {
378 ret.0
379 .entry(type_ident.clone())
380 .or_default()
381 .traits_all
382 .insert(base_ident.clone());
383 }
384 Some(Type::Reference(ri)) if ri.is_single() => {
385 ret.0
386 .entry(ri.type_.clone())
387 .or_default()
388 .traits_all
389 .insert(base_ident.clone());
390 }
391 _ => (),
392 }
393 }
394 }
395
396 for ident in ret.0.keys().cloned().collect::<Vec<_>>() {
397 let mut traits_second_level = BTreeSet::new();
398
399 ret.collect_traits(&ident, 0, &mut traits_second_level);
400
401 let info = ret.0.get_mut(&ident).unwrap();
402 info.traits_direct = info
403 .traits_all
404 .difference(&traits_second_level)
405 .cloned()
406 .collect();
407 }
408
409 ret
410 }
411
412 fn collect_traits(
413 &self,
414 ident: &Ident,
415 depth: usize,
416 traits_second_level: &mut BTreeSet<Ident>,
417 ) {
418 if depth > 1 {
419 traits_second_level.insert(ident.clone());
420 }
421
422 if let Some(info) = self.0.get(ident) {
423 for trait_ in &info.traits_all {
424 self.collect_traits(trait_, depth + 1, traits_second_level);
425 }
426 }
427 }
428}
429
430impl Deref for TraitInfos {
431 type Target = BTreeMap<Ident, TraitInfo>;
432
433 fn deref(&self) -> &Self::Target {
434 &self.0
435 }
436}
437
438#[derive(Default, Debug)]
441pub(super) struct TraitInfo {
442 pub traits_all: BTreeSet<Ident>,
443 pub traits_direct: BTreeSet<Ident>,
444}
445
446bitflags! {
449 #[derive(Debug, Clone, Copy)]
450 pub(super) struct StateFlags: u32 {
451 const HAS_TYPE = 1 << 0;
452 const HAS_IMPL = 1 << 1;
453
454 const HAS_QUICK_XML_SERIALIZE = 1 << 2;
455 const HAS_QUICK_XML_DESERIALIZE = 1 << 3;
456
457 const HAS_QUICK_XML = Self::HAS_QUICK_XML_SERIALIZE.bits() | Self::HAS_QUICK_XML_DESERIALIZE.bits();
458 }
459}
460
461#[derive(Default, Debug, Clone, Copy, Eq, PartialEq)]
464pub(super) enum Occurs {
465 #[default]
466 None,
467 Single,
468 Optional,
469 DynamicList,
470 StaticList(usize),
471}
472
473impl Occurs {
474 pub(super) fn from_occurs(min: MinOccurs, max: MaxOccurs) -> Self {
475 match (min, max) {
476 (0, MaxOccurs::Bounded(0)) => Self::None,
477 (1, MaxOccurs::Bounded(1)) => Self::Single,
478 (0, MaxOccurs::Bounded(1)) => Self::Optional,
479 (a, MaxOccurs::Bounded(b)) if a == b => Self::StaticList(a),
480 (_, _) => Self::DynamicList,
481 }
482 }
483
484 pub(super) fn make_type(
485 self,
486 ident: &TokenStream,
487 need_indirection: bool,
488 ) -> Option<TokenStream> {
489 match self {
490 Self::None => None,
491 Self::Single if need_indirection => Some(quote! { Box<#ident> }),
492 Self::Single => Some(quote! { #ident }),
493 Self::Optional if need_indirection => Some(quote! { Option<Box<#ident>> }),
494 Self::Optional => Some(quote! { Option<#ident> }),
495 Self::DynamicList => Some(quote! { Vec<#ident> }),
496 Self::StaticList(sz) if need_indirection => Some(quote! { [Box<#ident>; #sz] }),
497 Self::StaticList(sz) => Some(quote! { [#ident; #sz] }),
498 }
499 }
500
501 pub(super) fn is_direct(&self) -> bool {
502 matches!(self, Self::Single | Self::Optional | Self::StaticList(_))
503 }
504}
505
506#[derive(Debug, Clone, Copy, Eq, PartialEq)]
509pub(super) enum TypeMode {
510 All,
511 Choice,
512 Sequence,
513 Simple,
514}
515
516#[derive(Default, Debug)]
519pub(super) enum DynTypeTraits {
520 #[default]
521 Auto,
522 Custom(Vec<TokenStream>),
523}
524
525pub(super) fn format_field_name(name: &Name, display_name: Option<&str>) -> Cow<'static, str> {
528 if let Some(display_name) = display_name {
529 return Cow::Owned(display_name.to_snake_case());
530 }
531
532 let ident = name
533 .to_type_name(false, None)
534 .as_str()
535 .unwrap()
536 .to_snake_case();
537
538 match KEYWORDS.binary_search_by(|(key, _)| key.cmp(&ident.as_str())) {
539 Ok(idx) => Cow::Borrowed(KEYWORDS[idx].1),
540 Err(_) => {
541 if ident.starts_with(char::is_numeric) {
542 Cow::Owned(format!("_{ident}"))
543 } else {
544 Cow::Owned(ident)
545 }
546 }
547 }
548}
549
550pub(super) fn format_field_ident(name: &Name, display_name: Option<&str>) -> Ident2 {
551 let ident = format_field_name(name, display_name);
552
553 format_ident!("{ident}")
554}
555
556pub(super) fn format_module_ident(name: &Name) -> Ident2 {
557 format_field_ident(name, None)
558}
559
560pub(super) fn format_type_name(name: &Name, display_name: Option<&str>) -> String {
561 if let Some(display_name) = display_name {
562 return display_name.to_pascal_case();
563 }
564
565 let name = name
566 .to_type_name(false, None)
567 .as_str()
568 .unwrap()
569 .to_pascal_case();
570
571 if name.starts_with(char::is_numeric) {
572 format!("_{name}")
573 } else {
574 name
575 }
576}
577
578pub(super) fn format_type_ident(name: &Name, display_name: Option<&str>) -> Ident2 {
579 let ident = format_type_name(name, display_name);
580
581 format_ident!("{ident}")
582}
583
584pub(super) fn format_variant_ident(name: &Name, display_name: Option<&str>) -> Ident2 {
585 format_type_ident(name, display_name)
586}
587
588pub(super) fn format_module(
589 types: &Types,
590 ns: Option<NamespaceId>,
591) -> Result<Option<Ident2>, Error> {
592 let Some(ns) = ns else {
593 return Ok(None);
594 };
595
596 let module = types.modules.get(&ns).ok_or(Error::UnknownNamespace(ns))?;
597 let Some(name) = &module.name else {
598 return Ok(None);
599 };
600
601 Ok(Some(format_module_ident(name)))
602}
603
604pub(super) fn format_type_ref(current_ns: Option<NamespaceId>, type_: &TypeRef) -> TokenStream {
605 format_type_ref_ex(current_ns, None, &type_.type_ident, type_)
606}
607
608pub(super) fn format_type_ref_ex(
609 current_ns: Option<NamespaceId>,
610 extra: Option<&TokenStream>,
611 type_ident: &Ident2,
612 type_: &TypeRef,
613) -> TokenStream {
614 let module_ident = match (current_ns, type_.ns) {
615 (Some(a), Some(b)) if a != b => Some(&type_.module_ident),
616 (_, _) => None,
617 };
618
619 if let Some(module_ident) = module_ident {
620 quote! {
621 #module_ident #extra :: #type_ident
622 }
623 } else {
624 quote! {
625 #type_ident
626 }
627 }
628}
629
630pub(super) fn make_type_name(postfixes: &[String], ty: &Type, ident: &Ident) -> Name {
631 match (ty, &ident.name) {
632 (Type::Reference(ti), Name::Unnamed { .. }) if ti.type_.name.is_named() => {
633 match Occurs::from_occurs(ti.min_occurs, ti.max_occurs) {
634 Occurs::DynamicList => return Name::new(format!("{}List", ti.type_.name)),
635 Occurs::Optional => return Name::new(format!("{}Opt", ti.type_.name)),
636 _ => (),
637 }
638 }
639 (_, _) => (),
640 };
641
642 let postfix = postfixes
643 .get(ident.type_ as usize)
644 .map_or("", |s| s.as_str());
645
646 match &ident.name {
647 Name::Named(s) if s.ends_with(postfix) => Name::Named(s.clone()),
648 Name::Named(s) => Name::Named(Cow::Owned(format!("{s}{postfix}"))),
649 name => name.to_type_name(false, None),
650 }
651}
652
653const KEYWORDS: &[(&str, &str)] = &[
654 ("abstract", "abstract_"),
655 ("as", "as_"),
656 ("become", "become_"),
657 ("box", "box_"),
658 ("break", "break_"),
659 ("const", "const_"),
660 ("continue", "continue_"),
661 ("crate", "crate_"),
662 ("do", "do_"),
663 ("else", "else_"),
664 ("enum", "enum_"),
665 ("extern", "extern_"),
666 ("false", "false_"),
667 ("final", "final_"),
668 ("fn", "fn_"),
669 ("for", "for_"),
670 ("if", "if_"),
671 ("impl", "impl_"),
672 ("in", "in_"),
673 ("let", "let_"),
674 ("loop", "loop_"),
675 ("macro", "macro_"),
676 ("match", "match_"),
677 ("mod", "mod_"),
678 ("move", "move_"),
679 ("mut", "mut_"),
680 ("override", "override_"),
681 ("priv", "priv_"),
682 ("pub", "pub_"),
683 ("ref", "ref_"),
684 ("return", "return_"),
685 ("self", "self_"),
686 ("Self", "Self_"),
687 ("static", "static_"),
688 ("struct", "struct_"),
689 ("super", "super_"),
690 ("trait", "trait_"),
691 ("true", "true_"),
692 ("try", "try_"),
693 ("type", "type_"),
694 ("typeof", "typeof_"),
695 ("union", "union_"),
696 ("unsafe", "unsafe_"),
697 ("unsized", "unsized_"),
698 ("use", "use_"),
699 ("virtual", "virtual_"),
700 ("where", "where_"),
701 ("while", "while_"),
702 ("yield", "yield_"),
703];