xsd_parser/pipeline/generator/
context.rs1use std::ops::Deref;
2
3use proc_macro2::TokenStream;
4use quote::{format_ident, quote};
5
6use crate::config::GeneratorFlags;
7use crate::models::{
8 code::{format_variant_ident, ModuleIdent, ModulePath},
9 data::Occurs,
10 meta::{BuildInMeta, MetaTypeVariant},
11 Ident,
12};
13
14use super::{Error, MetaData, State, TraitInfos, TypeRef};
15
16#[derive(Debug)]
18pub struct Context<'a, 'types> {
19 pub meta: &'a MetaData<'types>,
21
22 pub ident: &'a Ident,
24
25 state: &'a mut State<'types>,
26}
27
28impl<'a, 'types> Context<'a, 'types> {
29 pub(super) fn new(
30 meta: &'a MetaData<'types>,
31 ident: &'a Ident,
32 state: &'a mut State<'types>,
33 ) -> Self {
34 Self { meta, ident, state }
35 }
36
37 pub(super) fn current_module(&self) -> ModuleIdent {
38 ModuleIdent::new(
39 self.meta.types,
40 self.ident,
41 self.check_generator_flags(GeneratorFlags::USE_NAMESPACE_MODULES),
42 self.check_generator_flags(GeneratorFlags::USE_SCHEMA_MODULES),
43 )
44 }
45
46 pub(super) fn current_type_ref(&self) -> &TypeRef {
47 self.state.cache.get(self.ident).unwrap()
48 }
49
50 pub(super) fn get_trait_infos(&mut self) -> &TraitInfos {
51 self.state
52 .trait_infos
53 .get_or_insert_with(|| TraitInfos::new(self.meta.types))
54 }
55
56 pub(super) fn get_or_create_type_ref(&mut self, ident: &Ident) -> Result<&TypeRef, Error> {
57 self.state.get_or_create_type_ref(self.meta, ident)
58 }
59
60 pub(super) fn make_trait_impls(&mut self) -> Result<Vec<TokenStream>, Error> {
61 let ident = self.ident.clone();
62 let current_module = self.current_module();
63 let module_path = ModulePath::from_ident(self.types, current_module);
64
65 self.get_trait_infos()
66 .get(&ident)
67 .into_iter()
68 .flat_map(|info| &info.traits_all)
69 .cloned()
70 .collect::<Vec<_>>()
71 .into_iter()
72 .map(|ident| {
73 let type_ref = self.get_or_create_type_ref(&ident)?;
74 let ident = format_ident!("{}Trait", type_ref.path.ident());
75 let trait_type = (*type_ref.path).clone().with_ident(ident);
76 let trait_ident = trait_type.relative_to(&module_path);
77
78 Ok(trait_ident)
79 })
80 .collect::<Result<Vec<_>, _>>()
81 }
82
83 #[allow(clippy::too_many_lines)]
84 pub(super) fn render_literal(
85 &mut self,
86 current_module: ModuleIdent,
87 default: &str,
88 ident: &Ident,
89 ) -> Result<TokenStream, Error> {
90 let types = self.types;
91 let ty = types
92 .items
93 .get(ident)
94 .ok_or_else(|| Error::UnknownType(ident.clone()))?;
95 let type_ref = self.get_or_create_type_ref(ident)?;
96
97 macro_rules! build_in {
98 ($ty:ty) => {
99 if let Ok(val) = default.parse::<$ty>() {
100 return Ok(quote!(#val));
101 }
102 };
103 }
104
105 match &ty.variant {
106 MetaTypeVariant::BuildIn(BuildInMeta::U8) => build_in!(u8),
107 MetaTypeVariant::BuildIn(BuildInMeta::U16) => build_in!(u16),
108 MetaTypeVariant::BuildIn(BuildInMeta::U32) => build_in!(u32),
109 MetaTypeVariant::BuildIn(BuildInMeta::U64) => build_in!(u64),
110 MetaTypeVariant::BuildIn(BuildInMeta::U128) => build_in!(u128),
111 MetaTypeVariant::BuildIn(BuildInMeta::Usize) => build_in!(usize),
112
113 MetaTypeVariant::BuildIn(BuildInMeta::I8) => build_in!(i8),
114 MetaTypeVariant::BuildIn(BuildInMeta::I16) => build_in!(i16),
115 MetaTypeVariant::BuildIn(BuildInMeta::I32) => build_in!(i32),
116 MetaTypeVariant::BuildIn(BuildInMeta::I64) => build_in!(i64),
117 MetaTypeVariant::BuildIn(BuildInMeta::I128) => build_in!(i128),
118 MetaTypeVariant::BuildIn(BuildInMeta::Isize) => build_in!(isize),
119
120 MetaTypeVariant::BuildIn(BuildInMeta::F32) => build_in!(f32),
121 MetaTypeVariant::BuildIn(BuildInMeta::F64) => build_in!(f64),
122
123 MetaTypeVariant::BuildIn(BuildInMeta::Bool) => {
124 match default.to_ascii_lowercase().as_str() {
125 "true" | "yes" | "1" => return Ok(quote!(true)),
126 "false" | "no" | "0" => return Ok(quote!(false)),
127 _ => (),
128 }
129 }
130 MetaTypeVariant::BuildIn(BuildInMeta::String) => {
131 return Ok(quote!(String::from(#default)));
132 }
133
134 MetaTypeVariant::Custom(x) => {
135 if let Some(x) = x.default(default) {
136 return Ok(x);
137 }
138 }
139
140 MetaTypeVariant::Enumeration(ei) => {
141 let module_path = ModulePath::from_ident(types, current_module);
142 let target_type = type_ref.path.relative_to(&module_path);
143
144 for var in &*ei.variants {
145 if var.type_.is_none() && var.ident.name.as_str() == default {
146 let variant_ident =
147 format_variant_ident(&var.ident.name, var.display_name.as_deref());
148
149 return Ok(quote!(#target_type :: #variant_ident));
150 }
151
152 if let Some(target_ident) = &var.type_ {
153 if let Ok(default) =
154 self.render_literal(current_module, default, target_ident)
155 {
156 let variant_ident = match self.state.cache.get(target_ident) {
157 Some(type_ref) if var.ident.name.is_generated() => {
158 type_ref.path.ident().clone()
159 }
160 _ => format_variant_ident(
161 &var.ident.name,
162 var.display_name.as_deref(),
163 ),
164 };
165
166 return Ok(quote!(#target_type :: #variant_ident(#default)));
167 }
168 }
169 }
170 }
171
172 MetaTypeVariant::Union(ui) => {
173 let module_path = ModulePath::from_ident(types, current_module);
174 let target_type = type_ref.path.relative_to(&module_path);
175
176 for ty in &*ui.types {
177 if let Ok(code) = self.render_literal(current_module, default, &ty.type_) {
178 let variant_ident = match self.state.cache.get(&ty.type_) {
179 Some(type_ref) if ty.type_.name.is_generated() => {
180 type_ref.path.ident().clone()
181 }
182 _ => format_variant_ident(&ty.type_.name, ty.display_name.as_deref()),
183 };
184
185 return Ok(quote! {
186 #target_type :: #variant_ident ( #code )
187 });
188 }
189 }
190 }
191
192 MetaTypeVariant::Reference(ti) => {
193 match Occurs::from_occurs(ti.min_occurs, ti.max_occurs) {
194 Occurs::Single => {
195 return self.render_literal(current_module, default, &ti.type_)
196 }
197 Occurs::DynamicList if default.is_empty() => {
198 let module_path = ModulePath::from_ident(types, current_module);
199 let target_type = type_ref.path.relative_to(&module_path);
200
201 return Ok(quote! { #target_type(Vec::new()) });
202 }
203 _ => (),
204 }
205 }
206
207 MetaTypeVariant::SimpleType(si) => {
208 let module_path = ModulePath::from_ident(types, current_module);
209 let target_type = type_ref.path.relative_to(&module_path);
210 let default = self.render_literal(current_module, default, &si.base)?;
211
212 return Ok(quote! { #target_type(#default) });
213 }
214
215 _ => (),
216 }
217
218 Err(Error::InvalidDefaultValue(
219 ident.clone(),
220 default.to_owned(),
221 ))
222 }
223}
224
225impl<'types> Deref for Context<'_, 'types> {
226 type Target = MetaData<'types>;
227
228 fn deref(&self) -> &Self::Target {
229 self.meta
230 }
231}