xsd_parser/models/meta/
custom.rs

1//! Contains the [`CustomMeta`] type information and all related types.
2
3use std::fmt::{Debug, Formatter, Result as FmtResult};
4use std::hash::{Hash, Hasher};
5
6use proc_macro2::TokenStream;
7
8/// Type information for a custom defined type.
9pub struct CustomMeta {
10    name: String,
11    include: Option<String>,
12    default: Option<Box<dyn CustomDefaultImpl>>,
13    allow_any: bool,
14}
15
16impl CustomMeta {
17    /// Create a new custom type information with the passed `name`.
18    #[must_use]
19    pub fn new<X>(name: X) -> Self
20    where
21        X: Into<String>,
22    {
23        Self {
24            name: name.into(),
25            include: None,
26            default: None,
27            allow_any: false,
28        }
29    }
30
31    /// Get the name of the custom defined type.
32    #[must_use]
33    pub fn name(&self) -> &str {
34        &self.name
35    }
36
37    /// Get the include path of the custom defined type.
38    #[must_use]
39    pub fn include(&self) -> Option<&str> {
40        self.include.as_deref()
41    }
42
43    /// The the path the type should be included from.
44    ///
45    /// The path should be absolute, or relative to the root of the generated code.
46    #[must_use]
47    pub fn include_from<X>(mut self, include: X) -> Self
48    where
49        X: Into<String>,
50    {
51        self.include = Some(include.into());
52
53        self
54    }
55
56    /// Try to get the default value (as code) for the given string.
57    ///
58    /// This is used to translate default values specified in the XSD schema,
59    /// to suitable rust code.
60    #[must_use]
61    pub fn default(&self, s: &str) -> Option<TokenStream> {
62        self.default.as_ref()?.exec(s)
63    }
64
65    /// Set the handler for the default values for this custom defined type.
66    #[must_use]
67    pub fn with_default<X: CustomDefaultImpl>(mut self, x: X) -> Self {
68        self.default = Some(Box::new(x));
69
70        self
71    }
72
73    /// Returns `true` if this type contains `xs:any` elements, `false` otherwise.
74    #[must_use]
75    pub fn allow_any(&self) -> bool {
76        self.allow_any
77    }
78
79    /// Set wether this custom type contains`xs:any` elements or not.
80    #[must_use]
81    pub fn with_allow_any(mut self, value: bool) -> Self {
82        self.allow_any = value;
83
84        self
85    }
86}
87
88impl Clone for CustomMeta {
89    fn clone(&self) -> Self {
90        Self {
91            name: self.name.clone(),
92            include: self.include.clone(),
93            default: self
94                .default
95                .as_ref()
96                .map(|x| CustomDefaultImpl::clone(&**x)),
97            allow_any: self.allow_any,
98        }
99    }
100}
101
102impl Debug for CustomMeta {
103    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
104        f.debug_struct("CustomType")
105            .field("name", &self.name)
106            .field("include", &self.include)
107            .field("default", &self.default.is_some())
108            .field("allow_any", &self.allow_any)
109            .finish()
110    }
111}
112
113impl Eq for CustomMeta {}
114
115impl PartialEq for CustomMeta {
116    fn eq(&self, other: &Self) -> bool {
117        self.name.eq(&other.name)
118    }
119}
120
121impl Hash for CustomMeta {
122    fn hash<H: Hasher>(&self, state: &mut H) {
123        self.name.hash(state);
124    }
125}
126
127/// Trait that converts the default value of a element specified in the XML
128/// schema to actual default code.
129///
130/// You can add a custom default implementation to your custom type using
131/// [`CustomMeta::with_default`].
132pub trait CustomDefaultImpl: Send + Sync + 'static {
133    /// Try to convert the passed string `s` that contains the default value from
134    /// the XML schema to actual default code. If the value could not be converted
135    /// to code `None` is returned.
136    fn exec(&self, s: &str) -> Option<TokenStream>;
137
138    /// Clone this instance and return it as a box.
139    fn clone(&self) -> Box<dyn CustomDefaultImpl>;
140}
141
142impl<X> CustomDefaultImpl for X
143where
144    X: Fn(&str) -> Option<TokenStream> + Clone + Send + Sync + 'static,
145{
146    fn exec(&self, s: &str) -> Option<TokenStream> {
147        (*self)(s)
148    }
149
150    fn clone(&self) -> Box<dyn CustomDefaultImpl> {
151        Box::new(self.clone())
152    }
153}