Skip to main content

xsd_parser/config/
mod.rs

1//! Contains the [`Config`] structures for the [`generate`](super::generate) method.
2
3mod generator;
4mod interpreter;
5mod optimizer;
6mod parser;
7mod renderer;
8
9use url::Url;
10
11pub use xsd_parser_types::misc::{Namespace, NamespacePrefix};
12
13pub use crate::models::{meta::MetaType, schema::NamespaceId, IdentType, Name, TypeIdent};
14
15use crate::models::{
16    meta::CustomMeta,
17    schema::{xs::SchemaContent, SchemaId, Schemas},
18};
19use crate::pipeline::renderer::NamespaceSerialization;
20use crate::traits::Naming;
21use crate::InterpreterError;
22
23pub use self::generator::{
24    BoxFlags, Generate, GeneratorConfig, GeneratorFlags, TypePostfix, TypedefMode,
25};
26pub use self::interpreter::{InterpreterConfig, InterpreterFlags};
27pub use self::optimizer::{OptimizerConfig, OptimizerFlags};
28pub use self::parser::{ParserConfig, ParserFlags, Resolver, Schema};
29pub use self::renderer::{
30    DynTypeTraits, RenderStep, RenderStepConfig, RendererConfig, RendererFlags, SerdeXmlRsVersion,
31};
32
33/// Configuration structure for the [`generate`](super::generate) method.
34#[must_use]
35#[derive(Default, Debug, Clone)]
36pub struct Config {
37    /// Configuration for the schema parser.
38    pub parser: ParserConfig,
39
40    /// Configuration for the schema interpreter.
41    pub interpreter: InterpreterConfig,
42
43    /// Configuration for the type information optimizer.
44    pub optimizer: OptimizerConfig,
45
46    /// Configuration for the code generator.
47    pub generator: GeneratorConfig,
48
49    /// Configuration for the code renderer.
50    pub renderer: RendererConfig,
51}
52
53impl Config {
54    /// Adds the passed `schema` to the list of schemas to parse.
55    pub fn with_schema<T>(mut self, schema: T) -> Self
56    where
57        T: Into<Schema>,
58    {
59        self.parser.schemas.push(schema.into());
60
61        self
62    }
63
64    /// Adds the passed `schemas` to the list of schemas to parse.
65    pub fn with_schemas<I>(mut self, schemas: I) -> Self
66    where
67        I: IntoIterator,
68        I::Item: Into<Schema>,
69    {
70        for schema in schemas {
71            self = self.with_schema(schema.into());
72        }
73
74        self
75    }
76
77    /// Set parser flags to the config.
78    pub fn set_parser_flags(mut self, flags: ParserFlags) -> Self {
79        self.parser.flags = flags;
80
81        self
82    }
83
84    /// Add parser flags to the config.
85    pub fn with_parser_flags(mut self, flags: ParserFlags) -> Self {
86        self.parser.flags.insert(flags);
87
88        self
89    }
90
91    /// Remove parser flags to the config.
92    pub fn without_parser_flags(mut self, flags: ParserFlags) -> Self {
93        self.parser.flags.remove(flags);
94
95        self
96    }
97
98    /// Set interpreter flags to the config.
99    pub fn set_interpreter_flags(mut self, flags: InterpreterFlags) -> Self {
100        self.interpreter.flags = flags;
101
102        self
103    }
104
105    /// Add code interpreter flags to the config.
106    pub fn with_interpreter_flags(mut self, flags: InterpreterFlags) -> Self {
107        self.interpreter.flags.insert(flags);
108
109        self
110    }
111
112    /// Remove code interpreter flags to the config.
113    pub fn without_interpreter_flags(mut self, flags: InterpreterFlags) -> Self {
114        self.interpreter.flags.remove(flags);
115
116        self
117    }
118
119    /// Set optimizer flags to the config.
120    pub fn set_optimizer_flags(mut self, flags: OptimizerFlags) -> Self {
121        self.optimizer.flags = flags;
122
123        self
124    }
125
126    /// Add optimizer flags to the config.
127    pub fn with_optimizer_flags(mut self, flags: OptimizerFlags) -> Self {
128        self.optimizer.flags.insert(flags);
129
130        self
131    }
132
133    /// Remove optimizer flags to the config.
134    pub fn without_optimizer_flags(mut self, flags: OptimizerFlags) -> Self {
135        self.optimizer.flags.remove(flags);
136
137        self
138    }
139
140    /// Set generator flags to the config.
141    pub fn set_generator_flags(mut self, flags: GeneratorFlags) -> Self {
142        self.generator.flags = flags;
143
144        self
145    }
146
147    /// Add code generator flags to the config.
148    pub fn with_generator_flags(mut self, flags: GeneratorFlags) -> Self {
149        self.generator.flags.insert(flags);
150
151        self
152    }
153
154    /// Remove code generator flags to the config.
155    pub fn without_generator_flags(mut self, flags: GeneratorFlags) -> Self {
156        self.generator.flags.remove(flags);
157
158        self
159    }
160
161    /// Set renderer flags to the config.
162    pub fn set_renderer_flags(mut self, flags: RendererFlags) -> Self {
163        self.renderer.flags = flags;
164
165        self
166    }
167
168    /// Add code renderer flags to the config.
169    pub fn with_renderer_flags(mut self, flags: RendererFlags) -> Self {
170        self.renderer.flags.insert(flags);
171
172        self
173    }
174
175    /// Remove code renderer flags to the config.
176    pub fn without_renderer_flags(mut self, flags: RendererFlags) -> Self {
177        self.renderer.flags.remove(flags);
178
179        self
180    }
181
182    /// Set boxing flags to the code generator config.
183    pub fn set_box_flags(mut self, flags: BoxFlags) -> Self {
184        self.generator.box_flags = flags;
185
186        self
187    }
188
189    /// Add boxing flags to the code generator config.
190    pub fn with_box_flags(mut self, flags: BoxFlags) -> Self {
191        self.generator.box_flags.insert(flags);
192
193        self
194    }
195
196    /// Remove boxing flags to the code generator config.
197    pub fn without_box_flags(mut self, flags: BoxFlags) -> Self {
198        self.generator.box_flags.remove(flags);
199
200        self
201    }
202
203    /// Adds the passed `step` to the config.
204    ///
205    /// If the same type of renderer was already added,
206    /// it is replaced by the new one.
207    pub fn with_render_step<T>(mut self, step: T) -> Self
208    where
209        T: RenderStepConfig + 'static,
210    {
211        let step = Box::new(step);
212        let mut index = 0;
213        let mut position = None;
214
215        // Find the position to place the new step and remove any other mutual exclusive step
216        self.renderer.steps.retain(|x| {
217            let mut remove = x.is_mutual_exclusive_to(&*step) || step.is_mutual_exclusive_to(&**x);
218
219            if remove && position.is_none() {
220                remove = false;
221                position = Some(index);
222            }
223
224            index += 1;
225
226            !remove
227        });
228
229        // Insert at the found position or append
230        if let Some(pos) = position {
231            self.renderer.steps[pos] = step;
232        } else {
233            self.renderer.steps.push(step);
234        }
235
236        self
237    }
238
239    /// Add multiple renderers to the generator config.
240    ///
241    /// See [`with_render_step`](Self::with_render_step) for details.
242    pub fn with_render_steps<I>(mut self, steps: I) -> Self
243    where
244        I: IntoIterator,
245        I::Item: RenderStepConfig + 'static,
246    {
247        for step in steps {
248            self = self.with_render_step(step);
249        }
250
251        self
252    }
253
254    /// Enable code generation for [`quick_xml`] serialization.
255    pub fn with_quick_xml_serialize(self) -> Self {
256        self.with_render_steps([
257            RenderStep::Types,
258            RenderStep::Defaults,
259            RenderStep::PrefixConstants,
260            RenderStep::NamespaceConstants,
261            RenderStep::QuickXmlSerialize {
262                namespaces: NamespaceSerialization::Global,
263                default_namespace: None,
264            },
265        ])
266    }
267
268    /// Enable code generation for [`quick_xml`] serialization.
269    pub fn with_quick_xml_serialize_config(
270        mut self,
271        namespaces: NamespaceSerialization,
272        default_namespace: Option<Namespace>,
273    ) -> Self {
274        self = self.with_render_steps([RenderStep::Types, RenderStep::Defaults]);
275
276        if namespaces != NamespaceSerialization::None {
277            self = self.with_render_step(RenderStep::PrefixConstants);
278        }
279
280        self.with_render_steps([
281            RenderStep::NamespaceConstants,
282            RenderStep::QuickXmlSerialize {
283                namespaces,
284                default_namespace,
285            },
286        ])
287    }
288
289    /// Enable code generation for [`quick_xml`] deserialization with the default settings.
290    pub fn with_quick_xml_deserialize(self) -> Self {
291        self.with_quick_xml_deserialize_config(false)
292    }
293
294    /// Enable render steps for [`quick_xml`] deserialization
295    /// with the passed configuration.
296    pub fn with_quick_xml_deserialize_config(self, boxed_deserializer: bool) -> Self {
297        self.with_render_steps([
298            RenderStep::Types,
299            RenderStep::Defaults,
300            RenderStep::NamespaceConstants,
301            RenderStep::QuickXmlDeserialize { boxed_deserializer },
302        ])
303    }
304
305    /// Enable render steps for [`quick_xml`] serialization and deserialization
306    /// with the default settings.
307    pub fn with_quick_xml(self) -> Self {
308        self.with_quick_xml_serialize().with_quick_xml_deserialize()
309    }
310
311    /// Enable render steps for [`quick_xml`] serialization and deserialization
312    /// with the passed configuration.
313    pub fn with_quick_xml_config(
314        self,
315        namespace_serialization: NamespaceSerialization,
316        default_serialize_namespace: Option<Namespace>,
317        boxed_deserializer: bool,
318    ) -> Self {
319        self.with_quick_xml_serialize_config(namespace_serialization, default_serialize_namespace)
320            .with_quick_xml_deserialize_config(boxed_deserializer)
321    }
322
323    /// Enable render steps for types with [`quick_xml`] serde support.
324    pub fn with_serde_quick_xml(mut self) -> Self {
325        self.optimizer.flags |= OptimizerFlags::SERDE;
326
327        self.with_render_steps([RenderStep::TypesSerdeQuickXml, RenderStep::Defaults])
328    }
329
330    /// Enable render steps for types with [`quick_xml`] serde support.
331    pub fn with_serde_xml_rs(mut self, version: SerdeXmlRsVersion) -> Self {
332        self.optimizer.flags |= OptimizerFlags::SERDE;
333
334        self.with_render_steps([
335            RenderStep::TypesSerdeXmlRs { version },
336            RenderStep::Defaults,
337        ])
338    }
339
340    /// Enable support for advanced enums.
341    ///
342    /// Advanced enums will automatically add constants for each enum variant
343    /// using its simple base type. During deserialization, the base type is
344    /// deserialized first and then compared against the defined constants to
345    /// determine the actual enum variant. This is useful for type like `QName`
346    /// where the actual used prefix can change, but the name still refers to
347    /// the object.
348    pub fn with_advanced_enums(self) -> Self {
349        self.with_generator_flags(GeneratorFlags::ADVANCED_ENUMS)
350            .with_render_step(RenderStep::EnumConstants)
351    }
352
353    /// Add a namespace to the parser config.
354    ///
355    /// See [`ParserConfig::namespaces`] for more details.
356    pub fn with_namespace<P, N>(mut self, prefix: P, namespace: N) -> Self
357    where
358        P: Into<NamespacePrefix>,
359        N: Into<Namespace>,
360    {
361        self.parser
362            .namespaces
363            .push((prefix.into(), namespace.into()));
364
365        self
366    }
367
368    /// Add multiple namespaces to the parser config.
369    ///
370    /// See [`ParserConfig::namespaces`] for more details.
371    pub fn with_namespaces<I, P, N>(mut self, namespaces: I) -> Self
372    where
373        I: IntoIterator<Item = (P, N)>,
374        P: Into<NamespacePrefix>,
375        N: Into<Namespace>,
376    {
377        for (prefix, namespace) in namespaces {
378            self.parser
379                .namespaces
380                .push((prefix.into(), namespace.into()));
381        }
382
383        self
384    }
385
386    /// Set the types the code should be generated for.
387    pub fn with_generate<I>(mut self, types: I) -> Self
388    where
389        I: IntoIterator,
390        I::Item: Into<IdentQuadruple>,
391    {
392        self.generator.generate = Generate::Types(types.into_iter().map(Into::into).collect());
393
394        self
395    }
396
397    /// Set the typedef mode for the generator.
398    pub fn with_typedef_mode(mut self, mode: TypedefMode) -> Self {
399        self.generator.typedef_mode = mode;
400
401        self
402    }
403
404    /// Set the traits the generated types should derive from.
405    pub fn with_derive<I>(mut self, derive: I) -> Self
406    where
407        I: IntoIterator,
408        I::Item: Into<String>,
409    {
410        self.renderer.derive = Some(
411            derive
412                .into_iter()
413                .map(Into::into)
414                .filter(|s| !s.is_empty())
415                .collect(),
416        );
417
418        self
419    }
420
421    /// Enable support for `xs:any` types.
422    pub fn with_any_type_support(self) -> Self {
423        self.with_generator_flags(GeneratorFlags::ANY_TYPE_SUPPORT)
424    }
425
426    /// Set the types to use to handle `xs:any` and `xs:anyAttribute` elements.
427    pub fn with_any_types<S, T>(mut self, any_type: S, any_attributes_type: T) -> Self
428    where
429        S: Into<String>,
430        T: Into<String>,
431    {
432        self.generator.any_type = any_type.into();
433        self.generator.any_attributes_type = any_attributes_type.into();
434
435        self.with_any_type_support()
436    }
437
438    /// Enable support for mixed types.
439    pub fn with_mixed_type_support(self) -> Self {
440        self.with_generator_flags(GeneratorFlags::MIXED_TYPE_SUPPORT)
441    }
442
443    /// Set the types to use to handle mixed types and text data.
444    pub fn with_mixed_types<S, T>(mut self, text_type: S, mixed_type: T) -> Self
445    where
446        S: Into<String>,
447        T: Into<String>,
448    {
449        self.generator.text_type = text_type.into();
450        self.generator.mixed_type = mixed_type.into();
451
452        self.with_mixed_type_support()
453    }
454
455    /// Enable support for nillable types.
456    pub fn with_nillable_type_support(self) -> Self {
457        self.with_generator_flags(GeneratorFlags::NILLABLE_TYPE_SUPPORT)
458    }
459
460    /// Set the type to use to handle nillable elements.
461    pub fn with_nillable_type<S>(mut self, nillable_type: S) -> Self
462    where
463        S: Into<String>,
464    {
465        self.generator.nillable_type = nillable_type.into();
466
467        self.with_nillable_type_support()
468    }
469
470    /// Set the [`Naming`] trait that is used to generated names in the interpreter.
471    pub fn with_naming<X>(mut self, naming: X) -> Self
472    where
473        X: Naming + 'static,
474    {
475        self.interpreter.naming = Some(Box::new(naming));
476
477        self
478    }
479
480    /// Add a type to the interpreter.
481    ///
482    /// This can be used to add or overwrite type definitions to the interpreter,
483    /// for example to support `xs:anySimpleType` with a custom type.
484    ///
485    /// # Parameters
486    /// - `ident`: Identifier quadruple for the type to add/overwrite, for example
487    ///   `(IdentType::Type, Namespace::XS, "anySimpleType")` for `xs:anySimpleType`.
488    /// - `meta`: The type definition to use for the specified identifier.
489    pub fn with_type<I, M>(mut self, ident: I, meta: M) -> Self
490    where
491        I: Into<IdentQuadruple>,
492        M: Into<MetaType>,
493    {
494        self.interpreter.types.push((ident.into(), meta.into()));
495
496        self
497    }
498
499    /// Add a type to the interpreter that should be used to handle `xs:anySimpleType`.
500    ///
501    /// This is a convenient method for adding support for `xs:anySimpleType` with a custom type.
502    ///
503    /// # Parameters
504    /// - `path`: The path to the type to use for handling `xs:anySimpleType`, for example
505    ///   `"xsd_parser_types::xml::AnySimpleType"`.
506    pub fn with_xs_any_simple_type<S>(self, path: S) -> Self
507    where
508        S: AsRef<str>,
509    {
510        let path = path.as_ref();
511        let name = path.rsplit_once("::").map_or(path, |(_, name)| name);
512
513        let ident = (IdentType::Type, Namespace::XS, "anySimpleType");
514        let meta = CustomMeta::new(name)
515            .include_from(path)
516            .with_namespace(Namespace::XS)
517            .with_namespace(Namespace::XSI);
518
519        self.with_type(ident, meta)
520    }
521
522    /// Add a type definition for `xs:QName` that uses the `xsd_parser_types::xml::QName` type.
523    pub fn with_qname_type(self) -> Self {
524        self.with_qname_type_from("::xsd_parser_types::xml::QName")
525    }
526
527    /// Add a type definition for `xs:QName` that uses the type defined at the passed `path`.
528    pub fn with_qname_type_from(self, path: &str) -> Self {
529        let name = path.rsplit_once("::").map_or(path, |(_, name)| name);
530
531        let ident = (IdentType::Type, Namespace::XS, "QName");
532        let meta = CustomMeta::new(name)
533            .include_from(path)
534            .with_namespace(Namespace::XS)
535            .with_default(crate::misc::qname_default);
536
537        self.with_type(ident, meta)
538    }
539
540    /// Set the postfix that should be applied to the name of types.
541    ///
542    /// For details please refer to [`GeneratorConfig::type_postfix`].
543    pub fn with_type_postfix<S>(mut self, value: S) -> Self
544    where
545        S: Into<String>,
546    {
547        self.generator.type_postfix.type_ = value.into();
548
549        self
550    }
551
552    /// Set the postfix that should be applied to the name of elements.
553    ///
554    /// For details please refer to [`GeneratorConfig::type_postfix`].
555    pub fn with_element_postfix<S>(mut self, value: S) -> Self
556    where
557        S: Into<String>,
558    {
559        self.generator.type_postfix.element = value.into();
560
561        self
562    }
563
564    /// Set the postfix that should be applied to the name of element types.
565    ///
566    /// For details please refer to [`GeneratorConfig::type_postfix`].
567    pub fn with_element_type_postfix<S>(mut self, value: S) -> Self
568    where
569        S: Into<String>,
570    {
571        self.generator.type_postfix.element_type = value.into();
572
573        self
574    }
575
576    /// Set the postfix that should be applied to the name of nillable content types.
577    ///
578    /// For details please refer to [`GeneratorConfig::type_postfix`].
579    pub fn with_nillable_content_postfix<S>(mut self, value: S) -> Self
580    where
581        S: Into<String>,
582    {
583        self.generator.type_postfix.nillable_content = value.into();
584
585        self
586    }
587
588    /// Set the postfix that should be applied to the name of dynamic elements.
589    ///
590    /// For details please refer to [`GeneratorConfig::type_postfix`].
591    pub fn with_dynamic_element_postfix<S>(mut self, value: S) -> Self
592    where
593        S: Into<String>,
594    {
595        self.generator.type_postfix.dynamic_element = value.into();
596
597        self
598    }
599}
600
601/// Convenient type to not break the public interface.
602///
603/// The type was renamed to [`IdentQuadruple`].
604#[deprecated(note = "Use IdentQuadruple instead")]
605pub type IdentTriple = IdentQuadruple;
606
607/// Identifier that is used inside the config.
608///
609/// Each element in a XML schema is uniquely identified by the following four
610/// values:
611///     - The namespace of the element (or no namespace at all).
612///     - The schema the element was defined in.
613///     - The name of the element.
614///     - The type of element.
615///
616/// This struct is used to bundle these three information to a unique identifier
617/// for an element.
618#[derive(Debug, Clone)]
619pub struct IdentQuadruple {
620    /// Namespace where the type is defined in.
621    pub ns: Option<NamespaceIdent>,
622
623    /// Id of the schema the type is defined in.
624    pub schema: Option<SchemaIdent>,
625
626    /// Name of the type.
627    pub name: String,
628
629    /// Type of the identifier (because pure names are not unique in XSD).
630    pub type_: IdentType,
631}
632
633impl IdentQuadruple {
634    /// Create a new [`IdentQuadruple`] instance from the passed `name` and `type_`.
635    #[inline]
636    #[must_use]
637    pub fn new<S>(name: S, type_: IdentType) -> Self
638    where
639        S: Into<String>,
640    {
641        Self {
642            ns: None,
643            schema: None,
644            name: name.into(),
645            type_,
646        }
647    }
648
649    /// Adds a [`NamespaceIdent`] to this identifier quadruple.
650    #[inline]
651    #[must_use]
652    pub fn with_ns<X>(mut self, ns: X) -> Self
653    where
654        X: Into<NamespaceIdent>,
655    {
656        self.ns = Some(ns.into());
657
658        self
659    }
660
661    /// Adds a [`SchemaIdent`] to this identifier quadruple.
662    #[inline]
663    #[must_use]
664    pub fn with_schema<X>(mut self, schema: X) -> Self
665    where
666        X: Into<SchemaIdent>,
667    {
668        self.schema = Some(schema.into());
669
670        self
671    }
672
673    /// Sets the name of the type that is identified by this identifier quadruple.
674    #[inline]
675    #[must_use]
676    pub fn with_name<X>(mut self, name: X) -> Self
677    where
678        X: Into<String>,
679    {
680        self.name = name.into();
681
682        self
683    }
684
685    /// Sets the identifier type of this identifier quadruple.
686    #[inline]
687    #[must_use]
688    pub fn with_type(mut self, type_: IdentType) -> Self {
689        self.type_ = type_;
690
691        self
692    }
693
694    /// Resolve the quadruple to an actual type identifier that is available in
695    /// the schema.
696    ///
697    /// /// <div class="warning">
698    /// *Caution*
699    /// This may end up in a type with the [`schema`](TypeIdent::schema) not fully
700    /// resolved. This can happen if you specified the wrong schema name, or schema
701    /// location. If you didn't provide a [`SchemaIdent`] at all, the type is resolved
702    /// by it's name, which is also not always successful, if the type is not defined
703    /// in the root of the available schemas.
704    ///
705    /// If you use this to get suitable identifiers to define types for the interpreter
706    /// (see [`with_type`](crate::Interpreter::with_type)), then you are fine, because
707    /// the interpreter will resolve unknown schema IDs by it's own.
708    ///
709    /// If you want to use the resolved identifier for selecting a [`MetaType`]
710    /// from the resulting [`MetaTypes`](crate::MetaTypes) structure created by
711    /// the interpreted, you have to resolve the type additionally using the
712    /// [`IdentCache`](crate::IdentCache), which is also returned by the
713    /// [`Interpreter`](crate::Interpreter)
714    /// (see [`exec_interpreter_with_ident_cache`](crate::exec_interpreter_with_ident_cache)).
715    /// </div>
716    ///
717    /// # Errors
718    ///
719    /// Returns an error if the namespace or the namespace prefix could not be
720    /// resolved.
721    pub fn resolve(self, schemas: &Schemas) -> Result<TypeIdent, InterpreterError> {
722        let Self {
723            ns,
724            schema,
725            name,
726            type_,
727        } = self;
728
729        let name = Name::new_named(name);
730
731        let ns = match ns {
732            None | Some(NamespaceIdent::Anonymous) => schemas
733                .resolve_namespace(&None)
734                .ok_or(InterpreterError::AnonymousNamespaceIsUndefined)?,
735            Some(NamespaceIdent::Id(ns)) => ns,
736            Some(NamespaceIdent::Prefix(prefix)) => schemas
737                .resolve_prefix(&prefix)
738                .ok_or(InterpreterError::UnknownNamespacePrefix(prefix))?,
739            #[allow(clippy::unnecessary_literal_unwrap)]
740            Some(NamespaceIdent::Namespace(ns)) => {
741                let ns = Some(ns);
742
743                schemas
744                    .resolve_namespace(&ns)
745                    .ok_or_else(|| InterpreterError::UnknownNamespace(ns.unwrap()))?
746            }
747        };
748
749        let schema = match schema {
750            None => schemas
751                .get_namespace_info(&ns)
752                .and_then(|x| {
753                    if x.schemas.len() == 1 {
754                        Some(x.schemas[0])
755                    } else {
756                        None
757                    }
758                })
759                .or_else(|| schemas.resolve_schema(ns, name.as_str(), type_))
760                .unwrap_or(SchemaId::UNKNOWN),
761            Some(SchemaIdent::Id(schema)) => schema,
762            Some(SchemaIdent::Name(s)) => schemas
763                .schemas()
764                .find(|(_, info)| matches!(&info.name, Some(name) if *name == s))
765                .map_or(SchemaId::UNKNOWN, |(id, _)| *id),
766            Some(SchemaIdent::Location(url)) => schemas
767                .schemas()
768                .find(|(_, info)| matches!(&info.location, Some(location) if *location == url))
769                .map_or(SchemaId::UNKNOWN, |(id, _)| *id),
770        };
771
772        Ok(TypeIdent {
773            ns,
774            schema,
775            name,
776            type_,
777        })
778    }
779}
780
781impl<X> From<(IdentType, X)> for IdentQuadruple
782where
783    X: AsRef<str>,
784{
785    fn from((type_, ident): (IdentType, X)) -> Self {
786        let ident = ident.as_ref();
787        let (prefix, name) = ident
788            .split_once(':')
789            .map_or((None, ident), |(a, b)| (Some(a), b));
790        let ns = prefix.map(|x| NamespaceIdent::prefix(x.as_bytes().to_owned()));
791        let name = name.to_owned();
792        let schema = None;
793
794        Self {
795            ns,
796            schema,
797            name,
798            type_,
799        }
800    }
801}
802
803impl<N, X> From<(IdentType, N, X)> for IdentQuadruple
804where
805    N: Into<NamespaceIdent>,
806    X: Into<String>,
807{
808    fn from((type_, ns, name): (IdentType, N, X)) -> Self {
809        Self::from((type_, Some(ns), name))
810    }
811}
812
813impl<N, X> From<(IdentType, Option<N>, X)> for IdentQuadruple
814where
815    N: Into<NamespaceIdent>,
816    X: Into<String>,
817{
818    fn from((type_, ns, name): (IdentType, Option<N>, X)) -> Self {
819        let ns = ns.map(Into::into);
820        let name = name.into();
821        let schema = None;
822
823        Self {
824            ns,
825            schema,
826            name,
827            type_,
828        }
829    }
830}
831
832impl<N, S, X> From<(IdentType, N, S, X)> for IdentQuadruple
833where
834    N: Into<NamespaceIdent>,
835    S: Into<SchemaIdent>,
836    X: Into<String>,
837{
838    fn from((type_, ns, schema, name): (IdentType, N, S, X)) -> Self {
839        Self::from((type_, Some(ns), Some(schema), name))
840    }
841}
842
843impl<N, S, X> From<(IdentType, Option<N>, S, X)> for IdentQuadruple
844where
845    N: Into<NamespaceIdent>,
846    S: Into<SchemaIdent>,
847    X: Into<String>,
848{
849    fn from((type_, ns, schema, name): (IdentType, Option<N>, S, X)) -> Self {
850        Self::from((type_, ns, Some(schema), name))
851    }
852}
853
854impl<N, S, X> From<(IdentType, N, Option<S>, X)> for IdentQuadruple
855where
856    N: Into<NamespaceIdent>,
857    S: Into<SchemaIdent>,
858    X: Into<String>,
859{
860    fn from((type_, ns, schema, name): (IdentType, N, Option<S>, X)) -> Self {
861        Self::from((type_, Some(ns), schema, name))
862    }
863}
864
865impl<N, S, X> From<(IdentType, Option<N>, Option<S>, X)> for IdentQuadruple
866where
867    N: Into<NamespaceIdent>,
868    S: Into<SchemaIdent>,
869    X: Into<String>,
870{
871    fn from((type_, ns, schema, name): (IdentType, Option<N>, Option<S>, X)) -> Self {
872        let ns = ns.map(Into::into);
873        let schema = schema.map(Into::into);
874        let name = name.into();
875
876        Self {
877            ns,
878            schema,
879            name,
880            type_,
881        }
882    }
883}
884
885/// Identifies a namespace by either it's id, it's known prefix or it's namespace.
886///
887/// Used in [`IdentQuadruple`].
888#[derive(Debug, Clone)]
889pub enum NamespaceIdent {
890    /// Identifies the anonymous namespace.
891    Anonymous,
892
893    /// Use the actual id the namespace is identified with.
894    Id(NamespaceId),
895
896    /// Uses a namespace prefix to refer to a specific namespace in the schema.
897    Prefix(NamespacePrefix),
898
899    /// Uses the full namespace to refer to a specific namespace in the schema.
900    Namespace(Namespace),
901}
902
903impl NamespaceIdent {
904    /// Creates a new [`NamespaceIdent::Id`] instance from the passed `value`.
905    #[inline]
906    #[must_use]
907    pub fn id(value: NamespaceId) -> Self {
908        Self::Id(value)
909    }
910
911    /// Creates a new [`NamespaceIdent::Prefix`] instance from the passed `value`.
912    #[inline]
913    #[must_use]
914    pub fn prefix<X>(value: X) -> Self
915    where
916        NamespacePrefix: From<X>,
917    {
918        Self::Prefix(NamespacePrefix::from(value))
919    }
920
921    /// Creates a new [`NamespaceIdent::Namespace`] instance from the passed `value`.
922    #[inline]
923    #[must_use]
924    pub fn namespace<X>(value: X) -> Self
925    where
926        Namespace: From<X>,
927    {
928        Self::Namespace(Namespace::from(value))
929    }
930}
931
932impl From<NamespaceId> for NamespaceIdent {
933    #[inline]
934    fn from(value: NamespaceId) -> Self {
935        Self::Id(value)
936    }
937}
938
939impl From<Namespace> for NamespaceIdent {
940    #[inline]
941    fn from(value: Namespace) -> Self {
942        Self::Namespace(value)
943    }
944}
945
946impl From<NamespacePrefix> for NamespaceIdent {
947    #[inline]
948    fn from(value: NamespacePrefix) -> Self {
949        Self::Prefix(value)
950    }
951}
952
953/// Identifies a schema by either it's id, it's name or it's location.
954///
955/// Used in [`IdentQuadruple`].
956#[derive(Debug, Clone)]
957pub enum SchemaIdent {
958    /// Identify the schema by it's [`SchemaId`].
959    Id(SchemaId),
960
961    /// Identify the schema by it's name.
962    Name(String),
963
964    /// Identify the schema by it's location.
965    Location(Url),
966}
967
968impl SchemaIdent {
969    /// Creates a new [`SchemaIdent::Id`] instance from the passed `value`.
970    #[inline]
971    #[must_use]
972    pub fn id(value: SchemaId) -> Self {
973        Self::Id(value)
974    }
975
976    /// Creates a new [`SchemaIdent::Name`] instance from the passed `value`.
977    #[inline]
978    #[must_use]
979    pub fn name<X>(value: X) -> Self
980    where
981        X: Into<String>,
982    {
983        Self::Name(value.into())
984    }
985
986    /// Creates a new [`SchemaIdent::Location`] instance from the passed `value`.
987    #[inline]
988    #[must_use]
989    pub fn location<X>(value: X) -> Self
990    where
991        X: Into<Url>,
992    {
993        Self::Location(value.into())
994    }
995}
996
997impl From<SchemaId> for SchemaIdent {
998    #[inline]
999    fn from(value: SchemaId) -> Self {
1000        Self::Id(value)
1001    }
1002}
1003
1004impl From<String> for SchemaIdent {
1005    #[inline]
1006    fn from(value: String) -> Self {
1007        Self::Name(value)
1008    }
1009}
1010
1011impl From<Url> for SchemaIdent {
1012    #[inline]
1013    fn from(value: Url) -> Self {
1014        Self::Location(value)
1015    }
1016}
1017
1018impl Schemas {
1019    fn resolve_schema(&self, ns: NamespaceId, name: &str, type_: IdentType) -> Option<SchemaId> {
1020        let ns_info = self.get_namespace_info(&ns)?;
1021
1022        for schema in &ns_info.schemas {
1023            let Some(schema_info) = self.get_schema(schema) else {
1024                continue;
1025            };
1026
1027            for c in &schema_info.schema.content {
1028                match (type_, c) {
1029                    (IdentType::Element, SchemaContent::Element(x)) if matches!(&x.name, Some(n) if n == name) => {
1030                        return Some(*schema)
1031                    }
1032                    (IdentType::Type, SchemaContent::SimpleType(x)) if matches!(&x.name, Some(n) if n == name) => {
1033                        return Some(*schema)
1034                    }
1035                    (IdentType::Type, SchemaContent::ComplexType(x)) if matches!(&x.name, Some(n) if n == name) => {
1036                        return Some(*schema)
1037                    }
1038                    (_, _) => (),
1039                }
1040            }
1041        }
1042
1043        None
1044    }
1045}