1use std::collections::HashSet;
2use std::fmt::{Display, Formatter, Result as FmtResult};
3
4use crate::models::{
5 meta::{
6 AttributeMetaVariant, ElementMetaVariant, ElementMode, MetaType, MetaTypeVariant, MetaTypes,
7 },
8 Ident,
9};
10
11#[derive(Debug)]
20pub struct MetaTypesPrinter<'a> {
21 types: &'a MetaTypes,
22}
23
24#[derive(Default)]
25struct State {
26 level: usize,
27 visit: HashSet<Ident>,
28}
29
30impl<'a> MetaTypesPrinter<'a> {
31 #[must_use]
33 pub fn new(types: &'a MetaTypes) -> Self {
34 Self { types }
35 }
36
37 pub fn print_all(&self, f: &mut Formatter<'_>) -> FmtResult {
43 let mut s = State::default();
44
45 for (ident, ty) in &self.types.items {
46 self.print_type_impl(f, &mut s, ident, ty)?;
47 }
48
49 Ok(())
50 }
51
52 pub fn print_type(&self, ident: &Ident, f: &mut Formatter<'_>) -> FmtResult {
59 let mut s = State::default();
60
61 if let Some(ty) = self.types.items.get(ident) {
62 self.print_type_impl(f, &mut s, ident, ty)?;
63 }
64
65 Ok(())
66 }
67
68 fn resolve_complex_type(
69 &self,
70 f: &mut Formatter<'_>,
71 s: &mut State,
72 ident: &Ident,
73 ) -> FmtResult {
74 if let Some(x) = self.types.items.get(ident) {
75 self.print_type_impl(f, s, ident, x)
76 } else {
77 writeln!(f, "NOT FOUND")?;
78
79 Ok(())
80 }
81 }
82
83 #[allow(clippy::too_many_lines)]
84 fn print_type_impl(
85 &self,
86 f: &mut Formatter<'_>,
87 s: &mut State,
88 ident: &Ident,
89 ty: &MetaType,
90 ) -> FmtResult {
91 macro_rules! indent {
92 ($( $tt:tt )*) => {{
93 write!(f, "{0:1$}", "", 4 * s.level)?;
94 write!(f, $( $tt )*)?;
95 }};
96 }
97
98 macro_rules! indentln {
99 ($( $tt:tt )*) => {{
100 write!(f, "{0:1$}", "", 4 * s.level)?;
101 writeln!(f, $( $tt )*)?;
102 }};
103 }
104
105 macro_rules! write_constrains {
106 ($c:expr) => {{
107 let x = $c;
108
109 s.level += 1;
110
111 indentln!("range={:?}", x.range);
112 indentln!("total_digits={:?}", x.total_digits);
113 indentln!("fraction_digits={:?}", x.fraction_digits);
114 indentln!("patterns={:?}", x.patterns);
115 indentln!("min_length={:?}", x.min_length);
116 indentln!("max_length={:?}", x.max_length);
117 indentln!("whitespace={:?}", x.whitespace);
118
119 s.level -= 1;
120 }};
121 }
122
123 if !s.visit.insert(ident.clone()) {
124 writeln!(f, "LOOP DETECTED ({})", ident.name)?;
125
126 return Ok(());
127 }
128
129 match &ty.variant {
130 MetaTypeVariant::BuildIn(x) => {
131 writeln!(f, "{}: BuildIn", ident)?;
132
133 s.level += 1;
134
135 indentln!("display_name={:?}", &ty.display_name);
136 indentln!("type={x:?}");
137
138 s.level -= 1;
139 }
140 MetaTypeVariant::Custom(x) => {
141 writeln!(f, "{}: Custom", ident)?;
142
143 s.level += 1;
144
145 indentln!("display_name={:?}", &ty.display_name);
146 indentln!("type={x:?}");
147
148 s.level -= 1;
149 }
150 MetaTypeVariant::Union(x) => {
151 writeln!(f, "{}: Union", ident)?;
152
153 s.level += 1;
154
155 indentln!("display_name={:?}", &ty.display_name);
156 indentln!("base={}", x.base);
157 indentln!("constrains:");
158 write_constrains!(&x.constrains);
159 indentln!("types:");
160
161 s.level += 1;
162
163 for ty in &*x.types {
164 indentln!("{}", &ty.type_);
165 }
166
167 s.level -= 2;
168 }
169 MetaTypeVariant::Reference(x) => {
170 writeln!(f, "{}: Reference", ident)?;
171
172 s.level += 1;
173
174 indentln!("display_name={:?}", &ty.display_name);
175 indentln!("min={}", x.min_occurs);
176 indentln!("max={:?}", x.max_occurs);
177 indentln!("nillable={:?}", x.nillable);
178 indentln!("type={}", x.type_);
179
180 s.level -= 1;
181 }
182 MetaTypeVariant::Dynamic(x) => {
183 writeln!(f, "{}: Dynamic", ident)?;
184
185 s.level += 1;
186
187 indentln!("display_name={:?}", &ty.display_name);
188 indentln!(
189 "type={}",
190 x.type_
191 .as_ref()
192 .map_or_else(|| String::from("None"), ToString::to_string)
193 );
194 indentln!("derived_types:");
195
196 s.level += 1;
197
198 for ty in &*x.derived_types {
199 indentln!("{}", ty);
200 }
201
202 s.level -= 2;
203 }
204 MetaTypeVariant::Enumeration(x) => {
205 writeln!(f, "{}: Enumeration", ident)?;
206
207 s.level += 1;
208
209 indentln!("display_name={:?}", &ty.display_name);
210 indentln!("base={}", x.base);
211 indentln!("constrains:");
212 write_constrains!(&x.constrains);
213 indentln!("variants:");
214
215 s.level += 1;
216
217 for var in &*x.variants {
218 indentln!("{}={:?}", var.ident.name, var.use_);
219 }
220
221 s.level -= 2;
222 }
223 MetaTypeVariant::All(x) | MetaTypeVariant::Choice(x) | MetaTypeVariant::Sequence(x) => {
224 match &ty.variant {
225 MetaTypeVariant::All(_) => writeln!(f, "{}: All", ident)?,
226 MetaTypeVariant::Choice(_) => writeln!(f, "{}: Choice", ident)?,
227 MetaTypeVariant::Sequence(_) => writeln!(f, "{}: Sequence", ident)?,
228 _ => (),
229 }
230
231 s.level += 1;
232
233 indentln!("display_name={:?}", &ty.display_name);
234 indentln!("is_mixed={:?}", x.is_mixed);
235
236 for x in &*x.elements {
237 indentln!("element:");
238
239 s.level += 1;
240
241 indentln!("name={}", x.ident.name);
242 indentln!("form={:?}", x.form);
243 indentln!("nillable={:?}", x.nillable);
244 indentln!("min_occurs={}", x.min_occurs);
245 indentln!("max_occurs={:?}", x.max_occurs);
246
247 match &x.variant {
248 ElementMetaVariant::Text => {
249 indentln!("variant=Text");
250 }
251 ElementMetaVariant::Type {
252 type_,
253 mode: ElementMode::Element,
254 } => {
255 indentln!("variant=Type({})", type_);
256 }
257 ElementMetaVariant::Type {
258 type_,
259 mode: ElementMode::Group,
260 } => {
261 indent!("variant=");
262 self.resolve_complex_type(f, s, type_)?;
263 }
264 ElementMetaVariant::Any { meta: x } => {
265 indentln!("variant=Any");
266
267 s.level += 1;
268
269 if let Some(x) = &x.id {
270 indentln!("id={x:?}");
271 }
272 if let Some(x) = &x.namespace {
273 indentln!("namespace={x:?}");
274 }
275 if let Some(x) = &x.not_q_name {
276 indentln!("not_q_name={x:?}");
277 }
278 if let Some(x) = &x.not_namespace {
279 indentln!("not_namespace={x:?}");
280 }
281
282 indentln!("process_contents={:?}", x.process_contents);
283
284 s.level -= 1;
285 }
286 }
287
288 s.level -= 1;
289 }
290
291 s.level -= 1;
292 }
293 MetaTypeVariant::ComplexType(x) => {
294 writeln!(f, "{}: ComplexType", ident)?;
295
296 s.level += 1;
297
298 indentln!("display_name={:?}", &ty.display_name);
299 indentln!("base={}", x.base);
300 indentln!("min_occurs={}", x.min_occurs);
301 indentln!("max_occurs={:?}", x.max_occurs);
302 indentln!("is_dynamic={}", x.is_dynamic);
303 indentln!("is_mixed={:?}", x.is_mixed);
304
305 for x in &*x.attributes {
306 indentln!("attribute:");
307
308 s.level += 1;
309
310 indentln!("name={}", x.ident.name);
311 indentln!("use={:?}", x.use_);
312 indentln!("form={:?}", x.form);
313 indentln!("default={:?}", x.default);
314
315 match &x.variant {
316 AttributeMetaVariant::Type(type_) => indentln!("type=Type({})", type_),
317 AttributeMetaVariant::Any(x) => {
318 indentln!("type=Any");
319
320 s.level += 1;
321
322 if let Some(x) = &x.id {
323 indentln!("id={x:?}");
324 }
325 if let Some(x) = &x.namespace {
326 indentln!("namespace={x:?}");
327 }
328 if let Some(x) = &x.not_q_name {
329 indentln!("not_q_name={x:?}");
330 }
331 if let Some(x) = &x.not_namespace {
332 indentln!("not_namespace={x:?}");
333 }
334
335 indentln!("process_contents={:?}", x.process_contents);
336
337 s.level -= 1;
338 }
339 }
340
341 s.level -= 1;
342 }
343
344 if let Some(content) = &x.content {
345 indent!("content=");
346 self.resolve_complex_type(f, s, content)?;
347 }
348
349 s.level -= 1;
350 }
351 MetaTypeVariant::SimpleType(x) => {
352 writeln!(f, "{}: SimpleType", ident)?;
353
354 s.level += 1;
355
356 indentln!("base={}", x.base);
357 indentln!("is_list={}", x.is_list);
358 indentln!("constrains:");
359 write_constrains!(&x.constrains);
360
361 s.level -= 1;
362 }
363 }
364
365 s.visit.remove(ident);
366
367 Ok(())
368 }
369}
370
371impl Display for MetaTypesPrinter<'_> {
372 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
373 self.print_all(f)
374 }
375}