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        if namespaces == NamespaceSerialization::Dynamic {
281            self = self.with_render_step(RenderStep::QuickXmlCollectNamespaces);
282        }
283
284        self.with_render_steps([
285            RenderStep::NamespaceConstants,
286            RenderStep::QuickXmlSerialize {
287                namespaces,
288                default_namespace,
289            },
290        ])
291    }
292
293    /// Enable code generation for [`quick_xml`] deserialization with the default settings.
294    pub fn with_quick_xml_deserialize(self) -> Self {
295        self.with_quick_xml_deserialize_config(false)
296    }
297
298    /// Enable render steps for [`quick_xml`] deserialization
299    /// with the passed configuration.
300    pub fn with_quick_xml_deserialize_config(self, boxed_deserializer: bool) -> Self {
301        self.with_render_steps([
302            RenderStep::Types,
303            RenderStep::Defaults,
304            RenderStep::NamespaceConstants,
305            RenderStep::QuickXmlDeserialize { boxed_deserializer },
306        ])
307    }
308
309    /// Enable render steps for [`quick_xml`] serialization and deserialization
310    /// with the default settings.
311    pub fn with_quick_xml(self) -> Self {
312        self.with_quick_xml_serialize().with_quick_xml_deserialize()
313    }
314
315    /// Enable render steps for [`quick_xml`] serialization and deserialization
316    /// with the passed configuration.
317    pub fn with_quick_xml_config(
318        self,
319        namespace_serialization: NamespaceSerialization,
320        default_serialize_namespace: Option<Namespace>,
321        boxed_deserializer: bool,
322    ) -> Self {
323        self.with_quick_xml_serialize_config(namespace_serialization, default_serialize_namespace)
324            .with_quick_xml_deserialize_config(boxed_deserializer)
325    }
326
327    /// Enable render steps for types with [`quick_xml`] serde support.
328    pub fn with_serde_quick_xml(mut self) -> Self {
329        self.optimizer.flags |= OptimizerFlags::SERDE;
330
331        self.with_render_steps([RenderStep::TypesSerdeQuickXml, RenderStep::Defaults])
332    }
333
334    /// Enable render steps for types with [`quick_xml`] serde support.
335    pub fn with_serde_xml_rs(mut self, version: SerdeXmlRsVersion) -> Self {
336        self.optimizer.flags |= OptimizerFlags::SERDE;
337
338        self.with_render_steps([
339            RenderStep::TypesSerdeXmlRs { version },
340            RenderStep::Defaults,
341        ])
342    }
343
344    /// Enable support for advanced enums.
345    ///
346    /// Advanced enums will automatically add constants for each enum variant
347    /// using its simple base type. During deserialization, the base type is
348    /// deserialized first and then compared against the defined constants to
349    /// determine the actual enum variant. This is useful for type like `QName`
350    /// where the actual used prefix can change, but the name still refers to
351    /// the object.
352    pub fn with_advanced_enums(self) -> Self {
353        self.with_generator_flags(GeneratorFlags::ADVANCED_ENUMS)
354            .with_render_step(RenderStep::EnumConstants)
355    }
356
357    /// Add a namespace to the parser config.
358    ///
359    /// See [`ParserConfig::namespaces`] for more details.
360    pub fn with_namespace<P, N>(mut self, prefix: P, namespace: N) -> Self
361    where
362        P: Into<NamespacePrefix>,
363        N: Into<Namespace>,
364    {
365        self.parser
366            .namespaces
367            .push((prefix.into(), namespace.into()));
368
369        self
370    }
371
372    /// Add multiple namespaces to the parser config.
373    ///
374    /// See [`ParserConfig::namespaces`] for more details.
375    pub fn with_namespaces<I, P, N>(mut self, namespaces: I) -> Self
376    where
377        I: IntoIterator<Item = (P, N)>,
378        P: Into<NamespacePrefix>,
379        N: Into<Namespace>,
380    {
381        for (prefix, namespace) in namespaces {
382            self.parser
383                .namespaces
384                .push((prefix.into(), namespace.into()));
385        }
386
387        self
388    }
389
390    /// Set the types the code should be generated for.
391    pub fn with_generate<I>(mut self, types: I) -> Self
392    where
393        I: IntoIterator,
394        I::Item: Into<IdentQuadruple>,
395    {
396        self.generator.generate = Generate::Types(types.into_iter().map(Into::into).collect());
397
398        self
399    }
400
401    /// Set the typedef mode for the generator.
402    pub fn with_typedef_mode(mut self, mode: TypedefMode) -> Self {
403        self.generator.typedef_mode = mode;
404
405        self
406    }
407
408    /// Set the traits the generated types should derive from.
409    pub fn with_derive<I>(mut self, derive: I) -> Self
410    where
411        I: IntoIterator,
412        I::Item: Into<String>,
413    {
414        self.renderer.derive = Some(
415            derive
416                .into_iter()
417                .map(Into::into)
418                .filter(|s| !s.is_empty())
419                .collect(),
420        );
421
422        self
423    }
424
425    /// Enable support for `xs:any` types.
426    pub fn with_any_type_support(self) -> Self {
427        self.with_generator_flags(GeneratorFlags::ANY_TYPE_SUPPORT)
428    }
429
430    /// Set the types to use to handle `xs:any` and `xs:anyAttribute` elements.
431    pub fn with_any_types<S, T>(mut self, any_type: S, any_attributes_type: T) -> Self
432    where
433        S: Into<String>,
434        T: Into<String>,
435    {
436        self.generator.any_type = any_type.into();
437        self.generator.any_attributes_type = any_attributes_type.into();
438
439        self.with_any_type_support()
440    }
441
442    /// Enable support for mixed types.
443    pub fn with_mixed_type_support(self) -> Self {
444        self.with_generator_flags(GeneratorFlags::MIXED_TYPE_SUPPORT)
445    }
446
447    /// Set the types to use to handle mixed types and text data.
448    pub fn with_mixed_types<S, T>(mut self, text_type: S, mixed_type: T) -> Self
449    where
450        S: Into<String>,
451        T: Into<String>,
452    {
453        self.generator.text_type = text_type.into();
454        self.generator.mixed_type = mixed_type.into();
455
456        self.with_mixed_type_support()
457    }
458
459    /// Enable support for nillable types.
460    pub fn with_nillable_type_support(self) -> Self {
461        self.with_generator_flags(GeneratorFlags::NILLABLE_TYPE_SUPPORT)
462    }
463
464    /// Set the type to use to handle nillable elements.
465    pub fn with_nillable_type<S>(mut self, nillable_type: S) -> Self
466    where
467        S: Into<String>,
468    {
469        self.generator.nillable_type = nillable_type.into();
470
471        self.with_nillable_type_support()
472    }
473
474    /// Set the [`Naming`] trait that is used to generated names in the interpreter.
475    pub fn with_naming<X>(mut self, naming: X) -> Self
476    where
477        X: Naming + 'static,
478    {
479        self.interpreter.naming = Some(Box::new(naming));
480
481        self
482    }
483
484    /// Add a type to the interpreter.
485    ///
486    /// This can be used to add or overwrite type definitions to the interpreter,
487    /// for example to support `xs:anySimpleType` with a custom type.
488    ///
489    /// # Parameters
490    /// - `ident`: Identifier quadruple for the type to add/overwrite, for example
491    ///   `(IdentType::Type, Namespace::XS, "anySimpleType")` for `xs:anySimpleType`.
492    /// - `meta`: The type definition to use for the specified identifier.
493    pub fn with_type<I, M>(mut self, ident: I, meta: M) -> Self
494    where
495        I: Into<IdentQuadruple>,
496        M: Into<MetaType>,
497    {
498        self.interpreter.types.push((ident.into(), meta.into()));
499
500        self
501    }
502
503    /// Add a type to the interpreter that should be used to handle `xs:anySimpleType`.
504    ///
505    /// This is a convenient method for adding support for `xs:anySimpleType` with a custom type.
506    ///
507    /// # Parameters
508    /// - `path`: The path to the type to use for handling `xs:anySimpleType`, for example
509    ///   `"xsd_parser_types::xml::AnySimpleType"`.
510    pub fn with_xs_any_simple_type<S>(self, path: S) -> Self
511    where
512        S: AsRef<str>,
513    {
514        let path = path.as_ref();
515        let name = path.rsplit_once("::").map_or(path, |(_, name)| name);
516
517        let ident = (IdentType::Type, Namespace::XS, "anySimpleType");
518        let meta = CustomMeta::new(name)
519            .include_from(path)
520            .with_namespace(Namespace::XS)
521            .with_namespace(Namespace::XSI);
522
523        self.with_type(ident, meta)
524    }
525
526    /// Add a type definition for `xs:QName` that uses the `xsd_parser_types::xml::QName` type.
527    pub fn with_qname_type(self) -> Self {
528        self.with_qname_type_from("::xsd_parser_types::xml::QName")
529    }
530
531    /// Add a type definition for `xs:QName` that uses the type defined at the passed `path`.
532    pub fn with_qname_type_from(self, path: &str) -> Self {
533        let name = path.rsplit_once("::").map_or(path, |(_, name)| name);
534
535        let ident = (IdentType::Type, Namespace::XS, "QName");
536        let meta = CustomMeta::new(name)
537            .include_from(path)
538            .with_namespace(Namespace::XS)
539            .with_default(crate::misc::qname_default);
540
541        self.with_type(ident, meta)
542    }
543
544    /// Set the postfix that should be applied to the name of types.
545    ///
546    /// For details please refer to [`GeneratorConfig::type_postfix`].
547    pub fn with_type_postfix<S>(mut self, value: S) -> Self
548    where
549        S: Into<String>,
550    {
551        self.generator.type_postfix.type_ = value.into();
552
553        self
554    }
555
556    /// Set the postfix that should be applied to the name of elements.
557    ///
558    /// For details please refer to [`GeneratorConfig::type_postfix`].
559    pub fn with_element_postfix<S>(mut self, value: S) -> Self
560    where
561        S: Into<String>,
562    {
563        self.generator.type_postfix.element = value.into();
564
565        self
566    }
567
568    /// Set the postfix that should be applied to the name of element types.
569    ///
570    /// For details please refer to [`GeneratorConfig::type_postfix`].
571    pub fn with_element_type_postfix<S>(mut self, value: S) -> Self
572    where
573        S: Into<String>,
574    {
575        self.generator.type_postfix.element_type = value.into();
576
577        self
578    }
579
580    /// Set the postfix that should be applied to the name of nillable content types.
581    ///
582    /// For details please refer to [`GeneratorConfig::type_postfix`].
583    pub fn with_nillable_content_postfix<S>(mut self, value: S) -> Self
584    where
585        S: Into<String>,
586    {
587        self.generator.type_postfix.nillable_content = value.into();
588
589        self
590    }
591
592    /// Set the postfix that should be applied to the name of dynamic elements.
593    ///
594    /// For details please refer to [`GeneratorConfig::type_postfix`].
595    pub fn with_dynamic_element_postfix<S>(mut self, value: S) -> Self
596    where
597        S: Into<String>,
598    {
599        self.generator.type_postfix.dynamic_element = value.into();
600
601        self
602    }
603}
604
605/// Convenient type to not break the public interface.
606///
607/// The type was renamed to [`IdentQuadruple`].
608#[deprecated(note = "Use IdentQuadruple instead")]
609pub type IdentTriple = IdentQuadruple;
610
611/// Identifier that is used inside the config.
612///
613/// Each element in a XML schema is uniquely identified by the following four
614/// values:
615///     - The namespace of the element (or no namespace at all).
616///     - The schema the element was defined in.
617///     - The name of the element.
618///     - The type of element.
619///
620/// This struct is used to bundle these three information to a unique identifier
621/// for an element.
622#[derive(Debug, Clone)]
623pub struct IdentQuadruple {
624    /// Namespace where the type is defined in.
625    pub ns: Option<NamespaceIdent>,
626
627    /// Id of the schema the type is defined in.
628    pub schema: Option<SchemaIdent>,
629
630    /// Name of the type.
631    pub name: String,
632
633    /// Type of the identifier (because pure names are not unique in XSD).
634    pub type_: IdentType,
635}
636
637impl IdentQuadruple {
638    /// Create a new [`IdentQuadruple`] instance from the passed `name` and `type_`.
639    #[inline]
640    #[must_use]
641    pub fn new<S>(name: S, type_: IdentType) -> Self
642    where
643        S: Into<String>,
644    {
645        Self {
646            ns: None,
647            schema: None,
648            name: name.into(),
649            type_,
650        }
651    }
652
653    /// Adds a [`NamespaceIdent`] to this identifier quadruple.
654    #[inline]
655    #[must_use]
656    pub fn with_ns<X>(mut self, ns: X) -> Self
657    where
658        X: Into<NamespaceIdent>,
659    {
660        self.ns = Some(ns.into());
661
662        self
663    }
664
665    /// Adds a [`SchemaIdent`] to this identifier quadruple.
666    #[inline]
667    #[must_use]
668    pub fn with_schema<X>(mut self, schema: X) -> Self
669    where
670        X: Into<SchemaIdent>,
671    {
672        self.schema = Some(schema.into());
673
674        self
675    }
676
677    /// Sets the name of the type that is identified by this identifier quadruple.
678    #[inline]
679    #[must_use]
680    pub fn with_name<X>(mut self, name: X) -> Self
681    where
682        X: Into<String>,
683    {
684        self.name = name.into();
685
686        self
687    }
688
689    /// Sets the identifier type of this identifier quadruple.
690    #[inline]
691    #[must_use]
692    pub fn with_type(mut self, type_: IdentType) -> Self {
693        self.type_ = type_;
694
695        self
696    }
697
698    /// Resolve the quadruple to an actual type identifier that is available in
699    /// the schema.
700    ///
701    /// /// <div class="warning">
702    /// *Caution*
703    /// This may end up in a type with the [`schema`](TypeIdent::schema) not fully
704    /// resolved. This can happen if you specified the wrong schema name, or schema
705    /// location. If you didn't provide a [`SchemaIdent`] at all, the type is resolved
706    /// by it's name, which is also not always successful, if the type is not defined
707    /// in the root of the available schemas.
708    ///
709    /// If you use this to get suitable identifiers to define types for the interpreter
710    /// (see [`with_type`](crate::Interpreter::with_type)), then you are fine, because
711    /// the interpreter will resolve unknown schema IDs by it's own.
712    ///
713    /// If you want to use the resolved identifier for selecting a [`MetaType`]
714    /// from the resulting [`MetaTypes`](crate::MetaTypes) structure created by
715    /// the interpreted, you have to resolve the type additionally using the
716    /// [`IdentCache`](crate::IdentCache), which is also returned by the
717    /// [`Interpreter`](crate::Interpreter)
718    /// (see [`exec_interpreter_with_ident_cache`](crate::exec_interpreter_with_ident_cache)).
719    /// </div>
720    ///
721    /// # Errors
722    ///
723    /// Returns an error if the namespace or the namespace prefix could not be
724    /// resolved.
725    pub fn resolve(self, schemas: &Schemas) -> Result<TypeIdent, InterpreterError> {
726        let Self {
727            ns,
728            schema,
729            name,
730            type_,
731        } = self;
732
733        let name = Name::new_named(name);
734
735        let ns = match ns {
736            None | Some(NamespaceIdent::Anonymous) => schemas
737                .resolve_namespace(&None)
738                .ok_or(InterpreterError::AnonymousNamespaceIsUndefined)?,
739            Some(NamespaceIdent::Id(ns)) => ns,
740            Some(NamespaceIdent::Prefix(prefix)) => schemas
741                .resolve_prefix(&prefix)
742                .ok_or(InterpreterError::UnknownNamespacePrefix(prefix))?,
743            #[allow(clippy::unnecessary_literal_unwrap)]
744            Some(NamespaceIdent::Namespace(ns)) => {
745                let ns = Some(ns);
746
747                schemas
748                    .resolve_namespace(&ns)
749                    .ok_or_else(|| InterpreterError::UnknownNamespace(ns.unwrap()))?
750            }
751        };
752
753        let schema = match schema {
754            None => schemas
755                .get_namespace_info(&ns)
756                .and_then(|x| {
757                    if x.schemas.len() == 1 {
758                        Some(x.schemas[0])
759                    } else {
760                        None
761                    }
762                })
763                .or_else(|| schemas.resolve_schema(ns, name.as_str(), type_))
764                .unwrap_or(SchemaId::UNKNOWN),
765            Some(SchemaIdent::Id(schema)) => schema,
766            Some(SchemaIdent::Name(s)) => schemas
767                .schemas()
768                .find(|(_, info)| matches!(&info.name, Some(name) if *name == s))
769                .map_or(SchemaId::UNKNOWN, |(id, _)| *id),
770            Some(SchemaIdent::Location(url)) => schemas
771                .schemas()
772                .find(|(_, info)| matches!(&info.location, Some(location) if *location == url))
773                .map_or(SchemaId::UNKNOWN, |(id, _)| *id),
774        };
775
776        Ok(TypeIdent {
777            ns,
778            schema,
779            name,
780            type_,
781        })
782    }
783}
784
785impl<X> From<(IdentType, X)> for IdentQuadruple
786where
787    X: AsRef<str>,
788{
789    fn from((type_, ident): (IdentType, X)) -> Self {
790        let ident = ident.as_ref();
791        let (prefix, name) = ident
792            .split_once(':')
793            .map_or((None, ident), |(a, b)| (Some(a), b));
794        let ns = prefix.map(|x| NamespaceIdent::prefix(x.as_bytes().to_owned()));
795        let name = name.to_owned();
796        let schema = None;
797
798        Self {
799            ns,
800            schema,
801            name,
802            type_,
803        }
804    }
805}
806
807impl<N, X> From<(IdentType, N, X)> for IdentQuadruple
808where
809    N: Into<NamespaceIdent>,
810    X: Into<String>,
811{
812    fn from((type_, ns, name): (IdentType, N, X)) -> Self {
813        Self::from((type_, Some(ns), name))
814    }
815}
816
817impl<N, X> From<(IdentType, Option<N>, X)> for IdentQuadruple
818where
819    N: Into<NamespaceIdent>,
820    X: Into<String>,
821{
822    fn from((type_, ns, name): (IdentType, Option<N>, X)) -> Self {
823        let ns = ns.map(Into::into);
824        let name = name.into();
825        let schema = None;
826
827        Self {
828            ns,
829            schema,
830            name,
831            type_,
832        }
833    }
834}
835
836impl<N, S, X> From<(IdentType, N, S, X)> for IdentQuadruple
837where
838    N: Into<NamespaceIdent>,
839    S: Into<SchemaIdent>,
840    X: Into<String>,
841{
842    fn from((type_, ns, schema, name): (IdentType, N, S, X)) -> Self {
843        Self::from((type_, Some(ns), Some(schema), name))
844    }
845}
846
847impl<N, S, X> From<(IdentType, Option<N>, S, X)> for IdentQuadruple
848where
849    N: Into<NamespaceIdent>,
850    S: Into<SchemaIdent>,
851    X: Into<String>,
852{
853    fn from((type_, ns, schema, name): (IdentType, Option<N>, S, X)) -> Self {
854        Self::from((type_, ns, Some(schema), name))
855    }
856}
857
858impl<N, S, X> From<(IdentType, N, Option<S>, X)> for IdentQuadruple
859where
860    N: Into<NamespaceIdent>,
861    S: Into<SchemaIdent>,
862    X: Into<String>,
863{
864    fn from((type_, ns, schema, name): (IdentType, N, Option<S>, X)) -> Self {
865        Self::from((type_, Some(ns), schema, name))
866    }
867}
868
869impl<N, S, X> From<(IdentType, Option<N>, Option<S>, X)> for IdentQuadruple
870where
871    N: Into<NamespaceIdent>,
872    S: Into<SchemaIdent>,
873    X: Into<String>,
874{
875    fn from((type_, ns, schema, name): (IdentType, Option<N>, Option<S>, X)) -> Self {
876        let ns = ns.map(Into::into);
877        let schema = schema.map(Into::into);
878        let name = name.into();
879
880        Self {
881            ns,
882            schema,
883            name,
884            type_,
885        }
886    }
887}
888
889/// Identifies a namespace by either it's id, it's known prefix or it's namespace.
890///
891/// Used in [`IdentQuadruple`].
892#[derive(Debug, Clone)]
893pub enum NamespaceIdent {
894    /// Identifies the anonymous namespace.
895    Anonymous,
896
897    /// Use the actual id the namespace is identified with.
898    Id(NamespaceId),
899
900    /// Uses a namespace prefix to refer to a specific namespace in the schema.
901    Prefix(NamespacePrefix),
902
903    /// Uses the full namespace to refer to a specific namespace in the schema.
904    Namespace(Namespace),
905}
906
907impl NamespaceIdent {
908    /// Creates a new [`NamespaceIdent::Id`] instance from the passed `value`.
909    #[inline]
910    #[must_use]
911    pub fn id(value: NamespaceId) -> Self {
912        Self::Id(value)
913    }
914
915    /// Creates a new [`NamespaceIdent::Prefix`] instance from the passed `value`.
916    #[inline]
917    #[must_use]
918    pub fn prefix<X>(value: X) -> Self
919    where
920        NamespacePrefix: From<X>,
921    {
922        Self::Prefix(NamespacePrefix::from(value))
923    }
924
925    /// Creates a new [`NamespaceIdent::Namespace`] instance from the passed `value`.
926    #[inline]
927    #[must_use]
928    pub fn namespace<X>(value: X) -> Self
929    where
930        Namespace: From<X>,
931    {
932        Self::Namespace(Namespace::from(value))
933    }
934}
935
936impl From<NamespaceId> for NamespaceIdent {
937    #[inline]
938    fn from(value: NamespaceId) -> Self {
939        Self::Id(value)
940    }
941}
942
943impl From<Namespace> for NamespaceIdent {
944    #[inline]
945    fn from(value: Namespace) -> Self {
946        Self::Namespace(value)
947    }
948}
949
950impl From<NamespacePrefix> for NamespaceIdent {
951    #[inline]
952    fn from(value: NamespacePrefix) -> Self {
953        Self::Prefix(value)
954    }
955}
956
957/// Identifies a schema by either it's id, it's name or it's location.
958///
959/// Used in [`IdentQuadruple`].
960#[derive(Debug, Clone)]
961pub enum SchemaIdent {
962    /// Identify the schema by it's [`SchemaId`].
963    Id(SchemaId),
964
965    /// Identify the schema by it's name.
966    Name(String),
967
968    /// Identify the schema by it's location.
969    Location(Url),
970}
971
972impl SchemaIdent {
973    /// Creates a new [`SchemaIdent::Id`] instance from the passed `value`.
974    #[inline]
975    #[must_use]
976    pub fn id(value: SchemaId) -> Self {
977        Self::Id(value)
978    }
979
980    /// Creates a new [`SchemaIdent::Name`] instance from the passed `value`.
981    #[inline]
982    #[must_use]
983    pub fn name<X>(value: X) -> Self
984    where
985        X: Into<String>,
986    {
987        Self::Name(value.into())
988    }
989
990    /// Creates a new [`SchemaIdent::Location`] instance from the passed `value`.
991    #[inline]
992    #[must_use]
993    pub fn location<X>(value: X) -> Self
994    where
995        X: Into<Url>,
996    {
997        Self::Location(value.into())
998    }
999}
1000
1001impl From<SchemaId> for SchemaIdent {
1002    #[inline]
1003    fn from(value: SchemaId) -> Self {
1004        Self::Id(value)
1005    }
1006}
1007
1008impl From<String> for SchemaIdent {
1009    #[inline]
1010    fn from(value: String) -> Self {
1011        Self::Name(value)
1012    }
1013}
1014
1015impl From<Url> for SchemaIdent {
1016    #[inline]
1017    fn from(value: Url) -> Self {
1018        Self::Location(value)
1019    }
1020}
1021
1022impl Schemas {
1023    fn resolve_schema(&self, ns: NamespaceId, name: &str, type_: IdentType) -> Option<SchemaId> {
1024        let ns_info = self.get_namespace_info(&ns)?;
1025
1026        for schema in &ns_info.schemas {
1027            let Some(schema_info) = self.get_schema(schema) else {
1028                continue;
1029            };
1030
1031            for c in &schema_info.schema.content {
1032                match (type_, c) {
1033                    (IdentType::Element, SchemaContent::Element(x)) if matches!(&x.name, Some(n) if n == name) => {
1034                        return Some(*schema)
1035                    }
1036                    (IdentType::Type, SchemaContent::SimpleType(x)) if matches!(&x.name, Some(n) if n == name) => {
1037                        return Some(*schema)
1038                    }
1039                    (IdentType::Type, SchemaContent::ComplexType(x)) if matches!(&x.name, Some(n) if n == name) => {
1040                        return Some(*schema)
1041                    }
1042                    (_, _) => (),
1043                }
1044            }
1045        }
1046
1047        None
1048    }
1049}