xsd_parser/
config.rs

1//! Contains the [`Config`] structures for the [`generate`](super::generate) method.
2
3use std::path::PathBuf;
4
5use bitflags::bitflags;
6use url::Url;
7
8pub use crate::generator::{BoxFlags, GeneratorFlags, SerdeSupport, TypedefMode};
9pub use crate::schema::{Namespace, NamespacePrefix};
10pub use crate::types::{IdentType, Type};
11
12use crate::schema::Schemas;
13use crate::types::{Ident, Name};
14use crate::InterpreterError;
15
16/// Configuration structure for the [`generate`](super::generate) method.
17#[must_use]
18#[derive(Default, Debug, Clone)]
19pub struct Config {
20    /// Configuration for the schema parser.
21    pub parser: ParserConfig,
22
23    /// Configuration for the schema interpreter.
24    pub interpreter: InterpreterConfig,
25
26    /// Configuration for the type information optimizer.
27    pub optimizer: OptimizerConfig,
28
29    /// Configuration for the code generator.
30    pub generator: GeneratorConfig,
31}
32
33/// Configuration for the schema parser.
34#[derive(Debug, Clone)]
35pub struct ParserConfig {
36    /// List of resolvers to use for resolving referenced schemas.
37    pub resolver: Vec<Resolver>,
38
39    /// List of namespaces to add to the parser before the schemas are loaded.
40    ///
41    /// See [`with_namespace`](crate::Parser::with_namespace) for more details.
42    pub namespaces: Vec<(NamespacePrefix, Namespace)>,
43
44    /// List of schemas to load.
45    pub schemas: Vec<Schema>,
46
47    /// Additional flags to control the parser.
48    pub flags: ParserFlags,
49
50    /// Wether to enable the debug output and where to write it to.
51    pub debug_output: Option<PathBuf>,
52}
53
54/// Configuration for the schema interpreter.
55#[derive(Debug, Clone)]
56pub struct InterpreterConfig {
57    /// List of user defined types to add to the interpreter before the schemas
58    /// are actually interpreted.
59    ///
60    /// See [`with_type`](crate::Interpreter::with_type) for more details.
61    pub types: Vec<(IdentTriple, Type)>,
62
63    /// Additional flags to control the interpreter.
64    pub flags: InterpreterFlags,
65
66    /// Wether to enable the debug output and where to write it to.
67    pub debug_output: Option<PathBuf>,
68}
69
70/// Configuration for the type information optimizer.
71#[derive(Debug, Clone)]
72pub struct OptimizerConfig {
73    /// Additional flags to control the optimizer.
74    pub flags: OptimizerFlags,
75
76    /// Wether to enable the debug output and where to write it to.
77    pub debug_output: Option<PathBuf>,
78}
79
80/// Configuration for the code generator.
81#[derive(Debug, Clone)]
82pub struct GeneratorConfig {
83    /// Types to add to the generator before the actual code is generated.
84    ///
85    /// See [`with_type`](crate::Generator::with_type) for more details.
86    pub types: Vec<IdentTriple>,
87
88    /// Sets the traits the generated types should derive from.
89    ///
90    /// See [`derive`](crate::Generator::derive) for more details.
91    pub derive: Option<Vec<String>>,
92
93    /// Set the traits that should be implemented by dynamic types.
94    ///
95    /// See [`dyn_type_traits`](crate::Generator::dyn_type_traits) for more details.
96    pub dyn_type_traits: Option<Vec<String>>,
97
98    /// Postfixes that should be applied to the name of the different generated
99    /// types.
100    ///
101    /// See [`with_type_postfix`](crate::Generator::with_type_postfix) for more details.
102    pub type_postfix: TypePostfix,
103
104    /// Tell the generator how to deal with boxing.
105    pub box_flags: BoxFlags,
106
107    /// Tells the generator how to deal with type definitions.
108    pub typedef_mode: TypedefMode,
109
110    /// Tells the generator how to generate code for the [`serde`] crate.
111    pub serde_support: SerdeSupport,
112
113    /// Specify which types the generator should generate code for.
114    pub generate: Generate,
115
116    /// Additional flags to control the generator.
117    pub flags: GeneratorFlags,
118
119    /// Name of the `xsd-parser` crate that is used for the generated code.
120    pub xsd_parser: String,
121}
122
123/// Postfixed that will be added to the different types generated by the code generator.
124#[derive(Debug, Clone)]
125pub struct TypePostfix {
126    /// Postfix added to normal types (like `xs:simpleType` or `xs:complexType`).
127    pub type_: String,
128
129    /// Postfixes added to elements (like `xs:element`).
130    pub element: String,
131
132    /// Postfixes added to inline types if elements (like `xs:element`).
133    pub element_type: String,
134}
135
136/// Configuration for the resolver used in [`ParserConfig`].
137#[derive(Debug, Clone)]
138pub enum Resolver {
139    /// Resolver that is used to resolve ewb resources (like `http://...` or `https://...`).
140    #[cfg(feature = "web-resolver")]
141    Web,
142
143    /// Resolver that is used to resolve local resources from disk (like `./local-schema.xsd` or `file://...`).
144    File,
145}
146
147/// Configuration for the schemas to load used in [`ParserConfig`].
148#[derive(Debug, Clone)]
149pub enum Schema {
150    /// Load a schema from the provided URL.
151    Url(Url),
152
153    /// Load a schema from the provided file path.
154    File(PathBuf),
155
156    /// Load the schema from the provided string.
157    Schema(String),
158}
159
160/// Configuration which types the [`Generator`](crate::Generator) should generate
161/// code for used in [`GeneratorConfig`].
162#[derive(Debug, Clone)]
163pub enum Generate {
164    /// The generator will generate code for all types of the schemas.
165    All,
166
167    /// List of identifiers the generator will generate code for.
168    Types(Vec<IdentTriple>),
169}
170
171/// Identifier that is used inside the config.
172#[derive(Debug, Clone)]
173pub struct IdentTriple {
174    /// Namespace the type is defined in.
175    pub ns: Option<NamespaceIdent>,
176
177    /// Name of the type.
178    pub name: String,
179
180    /// Type of the identifier (because pure names are not unique in XSD).
181    pub type_: IdentType,
182}
183
184/// Identifies a namespace by either it's known prefix or by the namespace directly.
185#[derive(Debug, Clone)]
186pub enum NamespaceIdent {
187    /// Uses a namespace prefix to refer to a specific namespace in the schema.
188    Prefix(NamespacePrefix),
189
190    /// Uses the full namespace to refer to a specific namespace in the schema.
191    Namespace(Namespace),
192}
193
194bitflags! {
195    /// Flags to control the [`Parser`](crate::Parser).
196    #[derive(Debug, Clone)]
197    pub struct ParserFlags: u32 {
198        /// Whether the parser should resolve `xs:include` and `xs:import` elements
199        /// or not.
200        ///
201        /// See [`resolve_includes`](crate::Parser::resolve_includes) for details.
202        const RESOLVE_INCLUDES = 1 << 0;
203
204        /// Whether to add the default namespaces to the parser or not.
205        ///
206        /// See [`with_default_namespaces`](crate::Parser::with_default_namespaces) for details.
207        const DEFAULT_NAMESPACES = 1 << 1;
208    }
209}
210
211bitflags! {
212    /// Flags to control the [`Interpreter`](crate::Interpreter).
213    #[derive(Debug, Clone)]
214    pub struct InterpreterFlags: u32 {
215        /// Whether to add the build-in types to the interpreter or not.
216        ///
217        /// See [`with_buildin_types`](crate::Interpreter::with_buildin_types) for details.
218        const BUILDIN_TYPES = 1 << 0;
219
220        /// Whether to add the default types definitions to the interpreter or not.
221        ///
222        /// See [`with_default_typedefs`](crate::Interpreter::with_default_typedefs) for details.
223        const DEFAULT_TYPEDEFS = 1 << 1;
224
225        /// Whether to add a default type definitions for `xs:anyType` or not.
226        ///
227        /// See [`with_xs_any_type`](crate::Interpreter::with_xs_any_type) for details.
228        const WITH_XS_ANY_TYPE = 1 << 2;
229    }
230}
231
232bitflags! {
233    /// Flags to control the [`Optimizer`](crate::Optimizer).
234    #[derive(Debug, Clone)]
235    pub struct OptimizerFlags: u32 {
236        /// Whether to remove empty enum variants or not.
237        ///
238        /// See [`remove_empty_enum_variants`](crate::Optimizer::remove_empty_enum_variants) for details.
239        const REMOVE_EMPTY_ENUM_VARIANTS = 1 << 0;
240
241        /// Whether to remove empty enums or not.
242        ///
243        /// See [`remove_empty_enums`](crate::Optimizer::remove_empty_enums) for details.
244        const REMOVE_EMPTY_ENUMS = 1 << 1;
245
246        /// Whether to remove duplicate union variants or not.
247        ///
248        /// See [`remove_duplicate_union_variants`](crate::Optimizer::remove_duplicate_union_variants) for details.
249        const REMOVE_DUPLICATE_UNION_VARIANTS = 1 << 2;
250
251        /// Whether to remove empty unions or not.
252        ///
253        /// See [`remove_empty_unions`](crate::Optimizer::remove_empty_unions) for details.
254        const REMOVE_EMPTY_UNIONS = 1 << 3;
255
256        /// Whether to use the unrestricted base type of a type or not.
257        ///
258        /// See [`use_unrestricted_base_type`](crate::Optimizer::use_unrestricted_base_type) for details.
259        const USE_UNRESTRICTED_BASE_TYPE = 1 << 4;
260
261        /// Whether to convert dynamic types to choices or not.
262        ///
263        /// See [`convert_dynamic_to_choice`](crate::Optimizer::convert_dynamic_to_choice) for details.
264        const CONVERT_DYNAMIC_TO_CHOICE = 1 << 5;
265
266        /// Whether to flatten the content of complex types or not.
267        ///
268        /// See [`flatten_complex_types`](crate::Optimizer::flatten_complex_types) for details.
269        const FLATTEN_COMPLEX_TYPES = 1 << 6;
270
271        /// Whether to flatten unions or not.
272        ///
273        /// See [`flatten_unions`](crate::Optimizer::flatten_unions) for details.
274        const FLATTEN_UNIONS = 1 << 7;
275
276        /// Whether to merge enumerations and unions or not.
277        ///
278        /// See [`merge_enum_unions`](crate::Optimizer::merge_enum_unions) for details.
279        const MERGE_ENUM_UNIONS = 1 << 8;
280
281        /// Whether to resolve type definitions or not.
282        ///
283        /// See [`resolve_typedefs`](crate::Optimizer::resolve_typedefs) for details.
284        const RESOLVE_TYPEDEFS = 1 << 9;
285
286        /// Whether to remove duplicate types or not.
287        ///
288        /// See [`remove_duplicates`](crate::Optimizer::remove_duplicates) for details.
289        const REMOVE_DUPLICATES = 1 << 10;
290
291        /// Group that contains all necessary optimization that should be applied
292        /// if code with [`serde`] support should be rendered.
293        const SERDE =  Self::FLATTEN_COMPLEX_TYPES.bits()
294            | Self::FLATTEN_UNIONS.bits()
295            | Self::MERGE_ENUM_UNIONS.bits();
296
297        /// Wether to merge the cardinality of a complex choice type or not.
298        ///
299        /// See [`merge_choice_cardinalities`](crate::Optimizer::merge_choice_cardinalities) for details.
300        const MERGE_CHOICE_CARDINALITIES = 1 << 11;
301    }
302}
303
304impl Config {
305    /// Set interpreter flags to the config.
306    pub fn set_interpreter_flags(mut self, flags: InterpreterFlags) -> Self {
307        self.interpreter.flags = flags;
308
309        self
310    }
311
312    /// Add code interpreter flags to the config.
313    pub fn with_interpreter_flags(mut self, flags: InterpreterFlags) -> Self {
314        self.interpreter.flags.insert(flags);
315
316        self
317    }
318
319    /// Remove code interpreter flags to the config.
320    pub fn without_interpreter_flags(mut self, flags: InterpreterFlags) -> Self {
321        self.interpreter.flags.remove(flags);
322
323        self
324    }
325
326    /// Set optimizer flags to the config.
327    pub fn set_optimizer_flags(mut self, flags: OptimizerFlags) -> Self {
328        self.optimizer.flags = flags;
329
330        self
331    }
332
333    /// Add optimizer flags to the config.
334    pub fn with_optimizer_flags(mut self, flags: OptimizerFlags) -> Self {
335        self.optimizer.flags.insert(flags);
336
337        self
338    }
339
340    /// Remove optimizer flags to the config.
341    pub fn without_optimizer_flags(mut self, flags: OptimizerFlags) -> Self {
342        self.optimizer.flags.remove(flags);
343
344        self
345    }
346
347    /// Set generator flags to the config.
348    pub fn set_generator_flags(mut self, flags: GeneratorFlags) -> Self {
349        self.generator.flags = flags;
350
351        self
352    }
353
354    /// Add code generator flags to the config.
355    pub fn with_generator_flags(mut self, flags: GeneratorFlags) -> Self {
356        self.generator.flags.insert(flags);
357
358        self
359    }
360
361    /// Remove code generator flags to the config.
362    pub fn without_generator_flags(mut self, flags: GeneratorFlags) -> Self {
363        self.generator.flags.remove(flags);
364
365        self
366    }
367
368    /// Set boxing flags to the code generator config.
369    pub fn set_box_flags(mut self, flags: BoxFlags) -> Self {
370        self.generator.box_flags = flags;
371
372        self
373    }
374
375    /// Add boxing flags to the code generator config.
376    pub fn with_box_flags(mut self, flags: BoxFlags) -> Self {
377        self.generator.box_flags.insert(flags);
378
379        self
380    }
381
382    /// Remove boxing flags to the code generator config.
383    pub fn without_box_flags(mut self, flags: BoxFlags) -> Self {
384        self.generator.box_flags.remove(flags);
385
386        self
387    }
388
389    /// Enable code generation for [`quick_xml`] serialization and deserialization.
390    pub fn with_quick_xml(mut self) -> Self {
391        self.generator.flags |= GeneratorFlags::QUICK_XML;
392
393        self
394    }
395
396    /// Set the [`serde`] support.
397    pub fn with_serde_support(mut self, serde_support: SerdeSupport) -> Self {
398        self.generator.serde_support = serde_support;
399
400        if self.generator.serde_support != SerdeSupport::None {
401            self.optimizer.flags |= OptimizerFlags::SERDE;
402        }
403
404        self
405    }
406
407    /// Set the types the code should be generated for.
408    pub fn with_generate<I>(mut self, types: I) -> Self
409    where
410        I: IntoIterator,
411        I::Item: Into<IdentTriple>,
412    {
413        self.generator.generate = Generate::Types(types.into_iter().map(Into::into).collect());
414
415        self
416    }
417
418    /// Set the typedef mode for the generator.
419    pub fn with_typedef_mode(mut self, mode: TypedefMode) -> Self {
420        self.generator.typedef_mode = mode;
421
422        self
423    }
424
425    /// Set the traits the generated types should derive from.
426    pub fn with_derive<I>(mut self, derive: I) -> Self
427    where
428        I: IntoIterator,
429        I::Item: Into<String>,
430    {
431        self.generator.derive = Some(
432            derive
433                .into_iter()
434                .map(Into::into)
435                .filter(|s| !s.is_empty())
436                .collect(),
437        );
438
439        self
440    }
441}
442
443impl Default for ParserConfig {
444    fn default() -> Self {
445        Self {
446            resolver: vec![Resolver::File],
447            schemas: vec![],
448            namespaces: vec![],
449            flags: ParserFlags::RESOLVE_INCLUDES | ParserFlags::DEFAULT_NAMESPACES,
450            debug_output: None,
451        }
452    }
453}
454
455impl Default for InterpreterConfig {
456    fn default() -> Self {
457        Self {
458            types: vec![],
459            debug_output: None,
460            flags: InterpreterFlags::BUILDIN_TYPES
461                | InterpreterFlags::DEFAULT_TYPEDEFS
462                | InterpreterFlags::WITH_XS_ANY_TYPE,
463        }
464    }
465}
466
467impl Default for OptimizerConfig {
468    fn default() -> Self {
469        Self {
470            debug_output: None,
471            flags: OptimizerFlags::REMOVE_EMPTY_ENUM_VARIANTS
472                | OptimizerFlags::REMOVE_EMPTY_ENUMS
473                | OptimizerFlags::REMOVE_DUPLICATE_UNION_VARIANTS
474                | OptimizerFlags::REMOVE_EMPTY_UNIONS,
475        }
476    }
477}
478
479impl Default for GeneratorConfig {
480    fn default() -> Self {
481        Self {
482            types: vec![],
483            derive: None,
484            type_postfix: TypePostfix::default(),
485            dyn_type_traits: None,
486            box_flags: BoxFlags::AUTO,
487            typedef_mode: TypedefMode::Auto,
488            serde_support: SerdeSupport::None,
489            generate: Generate::All,
490            flags: GeneratorFlags::empty(),
491            xsd_parser: "xsd_parser".into(),
492        }
493    }
494}
495
496impl Default for TypePostfix {
497    fn default() -> Self {
498        Self {
499            type_: String::from("Type"),
500            element: String::new(),
501            element_type: String::from("ElementType"),
502        }
503    }
504}
505
506/* IdentTriple */
507
508impl IdentTriple {
509    /// Resolve the triple to an actual type that is available in the schema.
510    ///
511    /// # Errors
512    ///
513    /// Returns an error if the namespace or the namespace prefix could not be
514    /// resolved.
515    pub fn resolve(self, schemas: &Schemas) -> Result<Ident, InterpreterError> {
516        let ns = match self.ns {
517            None => None,
518            Some(NamespaceIdent::Prefix(prefix)) => Some(
519                schemas
520                    .resolve_prefix(&prefix)
521                    .ok_or(InterpreterError::UnknownNamespacePrefix(prefix))?,
522            ),
523            #[allow(clippy::unnecessary_literal_unwrap)]
524            Some(NamespaceIdent::Namespace(ns)) => {
525                let ns = Some(ns);
526                Some(
527                    schemas
528                        .resolve_namespace(&ns)
529                        .ok_or_else(|| InterpreterError::UnknownNamespace(ns.unwrap()))?,
530                )
531            }
532        };
533
534        Ok(Ident {
535            ns,
536            name: Name::new(self.name),
537            type_: self.type_,
538        })
539    }
540}
541
542impl<X> From<(IdentType, X)> for IdentTriple
543where
544    X: AsRef<str>,
545{
546    fn from((type_, ident): (IdentType, X)) -> Self {
547        let ident = ident.as_ref();
548        let (prefix, name) = ident
549            .split_once(':')
550            .map_or((None, ident), |(a, b)| (Some(a), b));
551        let ns = prefix.map(|x| NamespaceIdent::prefix(x.as_bytes().to_owned()));
552        let name = name.to_owned();
553
554        Self { ns, name, type_ }
555    }
556}
557
558impl<N, X> From<(IdentType, N, X)> for IdentTriple
559where
560    N: Into<Option<NamespaceIdent>>,
561    X: Into<String>,
562{
563    fn from((type_, ns, name): (IdentType, N, X)) -> Self {
564        let ns = ns.into();
565        let name = name.into();
566
567        Self { ns, name, type_ }
568    }
569}
570
571/* NamespaceIdent */
572
573impl NamespaceIdent {
574    /// Creates a new [`NamespaceIdent::Prefix`] instance from the passed `value`.
575    pub fn prefix<X>(value: X) -> Self
576    where
577        NamespacePrefix: From<X>,
578    {
579        Self::Prefix(NamespacePrefix::from(value))
580    }
581
582    /// Creates a new [`NamespaceIdent::Namespace`] instance from the passed `value`.
583    pub fn namespace<X>(value: X) -> Self
584    where
585        Namespace: From<X>,
586    {
587        Self::Namespace(Namespace::from(value))
588    }
589}
590
591impl From<Namespace> for NamespaceIdent {
592    fn from(value: Namespace) -> Self {
593        Self::Namespace(value)
594    }
595}
596
597impl From<NamespacePrefix> for NamespaceIdent {
598    fn from(value: NamespacePrefix) -> Self {
599        Self::Prefix(value)
600    }
601}