Skip to main content

xsd/
type.rs

1// This is free and unencumbered software released into the public domain.
2
3use crate::{DecimalType, DecimalValue, PrimitiveType, PrimitiveValue};
4use core::{fmt, str::FromStr};
5use phf::phf_map;
6
7#[cfg(feature = "alloc")]
8use ::alloc::{borrow::Cow, format, string::String, vec::Vec};
9
10/// An XSD datatype.
11///
12/// Currently supports the primitive datatypes and the derived `xsd:decimal`
13/// datatypes.
14///
15/// [`Display`](core::fmt::Display) writes the datatype's local name, or the
16/// stored name or IRI for [`Type::Other`].
17///
18/// See: <https://www.w3.org/TR/xmlschema-2/#built-in-datatypes>
19#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
20#[cfg_attr(
21    feature = "borsh",
22    derive(borsh::BorshSerialize, borsh::BorshDeserialize)
23)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub enum Type {
26    Primitive(PrimitiveType),
27
28    Decimal(DecimalType),
29
30    #[cfg(feature = "alloc")]
31    Other(String),
32    #[cfg(not(feature = "alloc"))]
33    Other(&'static str),
34}
35
36impl Type {
37    pub fn name(&self) -> &str {
38        use Type::*;
39        match self {
40            Decimal(t) => t.name(),
41            Primitive(t) => t.name(),
42            Other(s) => s.as_ref(),
43        }
44    }
45
46    pub fn curie(&self) -> &str {
47        use Type::*;
48        match self {
49            Decimal(t) => t.curie(),
50            Primitive(t) => t.curie(),
51            Other(s) => s.as_ref(), // FIXME
52        }
53    }
54
55    /// Returns the datatype IRI. Requires the `alloc` feature.
56    ///
57    /// Local names are expanded in the XSD namespace. Stored names containing
58    /// `:` are treated as absolute IRIs and returned unchanged, without validation
59    /// or prefix resolution.
60    #[cfg(feature = "alloc")]
61    pub fn iri_string(&self) -> Cow<'_, str> {
62        let name = self.name();
63        if name.contains(':') {
64            Cow::Borrowed(name)
65        } else {
66            Cow::Owned(format!("{}{}", crate::BASE_URI, name))
67        }
68    }
69
70    pub fn base_type(&self) -> Option<Type> {
71        use Type::*;
72        match self {
73            Decimal(t) => t.base_type().map(Decimal),
74            Primitive(_) => None,
75            Other(_) => None,
76        }
77    }
78
79    #[cfg(feature = "alloc")]
80    pub fn base_types(&self) -> Vec<Type> {
81        use Type::*;
82        match self {
83            Decimal(t) => t.base_types().into_iter().map(Decimal).collect(),
84            Primitive(_) => Vec::new(),
85            Other(_) => Vec::new(),
86        }
87    }
88}
89
90impl fmt::Display for Type {
91    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92        f.write_str(self.name())
93    }
94}
95
96impl FromStr for Type {
97    type Err = (); // TODO
98
99    fn from_str(input: &str) -> Result<Self, Self::Err> {
100        match TYPES.get(input) {
101            Some(&t) => Ok(t.clone()),
102            None => Err(()),
103        }
104    }
105}
106
107impl From<&Type> for Type {
108    fn from(input: &Type) -> Self {
109        input.clone()
110    }
111}
112
113#[cfg(all(feature = "oxrdf", feature = "alloc"))]
114impl From<oxrdf::NamedNode> for Type {
115    fn from(input: oxrdf::NamedNode) -> Self {
116        let input_iri = input.as_str();
117        if let Some(input_name) = input_iri.strip_prefix(crate::BASE_URI) {
118            return Type::from(input_name);
119        }
120        Type::Other(input_iri.into()) // TODO
121    }
122}
123
124#[cfg(feature = "alloc")]
125impl From<&str> for Type {
126    fn from(input: &str) -> Self {
127        match TYPES.get(input) {
128            Some(&t) => t.clone(),
129            None => Type::Other(input.into()),
130        }
131    }
132}
133
134#[cfg(not(feature = "alloc"))]
135impl From<&'static str> for Type {
136    fn from(input: &'static str) -> Self {
137        match TYPES.get(input) {
138            Some(&t) => t.clone(),
139            None => Type::Other(input.into()),
140        }
141    }
142}
143
144impl From<DecimalType> for Type {
145    fn from(input: DecimalType) -> Self {
146        Self::Decimal(input)
147    }
148}
149
150impl From<DecimalValue> for Type {
151    fn from(input: DecimalValue) -> Self {
152        Self::Decimal(input.r#type())
153    }
154}
155
156impl From<PrimitiveType> for Type {
157    fn from(input: PrimitiveType) -> Self {
158        Self::Primitive(input)
159    }
160}
161
162impl From<PrimitiveValue> for Type {
163    fn from(input: PrimitiveValue) -> Self {
164        Self::Primitive(input.r#type())
165    }
166}
167
168/// A PHF map from XSD typenames to datatypes.
169pub static TYPES: phf::Map<&'static str, &'static Type> = phf_map! {
170    "QName" => &QNAME,
171    "anyURI" => &ANY_URI,
172    "base64Binary" => &BASE64_BINARY,
173    "boolean" => &BOOLEAN,
174    "byte" => &BYTE,
175    "date" => &DATE,
176    "dateTime" => &DATE_TIME,
177    "decimal" => &DECIMAL,
178    "double" => &DOUBLE,
179    "duration" => &DURATION,
180    "float" => &FLOAT,
181    "gDay" => &G_DAY,
182    "gMonth" => &G_MONTH,
183    "gMonthDay" => &G_MONTH_DAY,
184    "gYear" => &G_YEAR,
185    "gYearMonth" => &G_YEAR_MONTH,
186    "hexBinary" => &HEX_BINARY,
187    "int" => &INT,
188    "integer" => &INTEGER,
189    "long" => &LONG,
190    "short" => &SHORT,
191    "string" => &STRING,
192    "time" => &TIME,
193};
194
195/// The `xsd:QName` primitive datatype.
196pub const QNAME: Type = Type::Primitive(PrimitiveType::QName);
197
198/// The `xsd:anyURI` primitive datatype.
199pub const ANY_URI: Type = Type::Primitive(PrimitiveType::AnyUri);
200
201/// The `xsd:base64Binary` primitive datatype.
202pub const BASE64_BINARY: Type = Type::Primitive(PrimitiveType::Base64Binary);
203
204/// The `xsd:boolean` primitive datatype.
205pub const BOOLEAN: Type = Type::Primitive(PrimitiveType::Boolean);
206
207/// The `xsd:byte` derived datatype.
208pub const BYTE: Type = Type::Decimal(DecimalType::Byte);
209
210/// The `xsd:date` primitive datatype.
211pub const DATE: Type = Type::Primitive(PrimitiveType::Date);
212
213/// The `xsd:dateTime` primitive datatype.
214pub const DATE_TIME: Type = Type::Primitive(PrimitiveType::DateTime);
215
216/// The `xsd:decimal` primitive datatype.
217pub const DECIMAL: Type = Type::Decimal(DecimalType::Decimal);
218
219/// The `xsd:double` primitive datatype.
220pub const DOUBLE: Type = Type::Primitive(PrimitiveType::Double);
221
222/// The `xsd:duration` primitive datatype.
223pub const DURATION: Type = Type::Primitive(PrimitiveType::Duration);
224
225/// The `xsd:float` primitive datatype.
226pub const FLOAT: Type = Type::Primitive(PrimitiveType::Float);
227
228/// The `xsd:gDay` primitive datatype.
229pub const G_DAY: Type = Type::Primitive(PrimitiveType::GDay);
230
231/// The `xsd:gMonth` primitive datatype.
232pub const G_MONTH: Type = Type::Primitive(PrimitiveType::GMonth);
233
234/// The `xsd:gMonthDay` primitive datatype.
235pub const G_MONTH_DAY: Type = Type::Primitive(PrimitiveType::GMonthDay);
236
237/// The `xsd:gYear` primitive datatype.
238pub const G_YEAR: Type = Type::Primitive(PrimitiveType::GYear);
239
240/// The `xsd:gYearMonth` primitive datatype.
241pub const G_YEAR_MONTH: Type = Type::Primitive(PrimitiveType::GYearMonth);
242
243/// The `xsd:hexBinary` primitive datatype.
244pub const HEX_BINARY: Type = Type::Primitive(PrimitiveType::HexBinary);
245
246/// The `xsd:int` derived datatype.
247pub const INT: Type = Type::Decimal(DecimalType::Int);
248
249/// The `xsd:integer` derived datatype.
250pub const INTEGER: Type = Type::Decimal(DecimalType::Integer);
251
252/// The `xsd:long` derived datatype.
253pub const LONG: Type = Type::Decimal(DecimalType::Long);
254
255/// The `xsd:short` derived datatype.
256pub const SHORT: Type = Type::Decimal(DecimalType::Short);
257
258/// The `xsd:string` primitive datatype.
259pub const STRING: Type = Type::Primitive(PrimitiveType::String);
260
261/// The `xsd:time` primitive datatype.
262pub const TIME: Type = Type::Primitive(PrimitiveType::Time);