oxrdf/
variable.rs

1use std::cmp::Ordering;
2use std::fmt;
3
4/// A [SPARQL query](https://www.w3.org/TR/sparql11-query/) owned variable.
5///
6/// The default string formatter is returning a SPARQL compatible representation:
7/// ```
8/// use oxrdf::{Variable, VariableNameParseError};
9///
10/// assert_eq!("?foo", Variable::new("foo")?.to_string());
11/// # Result::<_,VariableNameParseError>::Ok(())
12/// ```
13#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
14pub struct Variable {
15    name: String,
16}
17
18impl Variable {
19    /// Creates a variable name from a unique identifier.
20    ///
21    /// The variable identifier must be valid according to the SPARQL grammar.
22    pub fn new(name: impl Into<String>) -> Result<Self, VariableNameParseError> {
23        let name = name.into();
24        validate_variable_identifier(&name)?;
25        Ok(Self::new_unchecked(name))
26    }
27
28    /// Creates a variable name from a unique identifier without validation.
29    ///
30    /// It is the caller's responsibility to ensure that `id` is a valid blank node identifier
31    /// according to the SPARQL grammar.
32    ///
33    /// [`Variable::new()`] is a safe version of this constructor and should be used for untrusted data.
34    #[inline]
35    pub fn new_unchecked(name: impl Into<String>) -> Self {
36        Self { name: name.into() }
37    }
38
39    #[inline]
40    pub fn as_str(&self) -> &str {
41        &self.name
42    }
43
44    #[inline]
45    pub fn into_string(self) -> String {
46        self.name
47    }
48
49    #[inline]
50    pub fn as_ref(&self) -> VariableRef<'_> {
51        VariableRef { name: &self.name }
52    }
53}
54
55impl fmt::Display for Variable {
56    #[inline]
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        self.as_ref().fmt(f)
59    }
60}
61
62/// A [SPARQL query](https://www.w3.org/TR/sparql11-query/) borrowed variable.
63///
64/// The default string formatter is returning a SPARQL compatible representation:
65/// ```
66/// use oxrdf::{VariableNameParseError, VariableRef};
67///
68/// assert_eq!("?foo", VariableRef::new("foo")?.to_string());
69/// # Result::<_,VariableNameParseError>::Ok(())
70/// ```
71#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash)]
72pub struct VariableRef<'a> {
73    name: &'a str,
74}
75
76impl<'a> VariableRef<'a> {
77    /// Creates a variable name from a unique identifier.
78    ///
79    /// The variable identifier must be valid according to the SPARQL grammar.
80    pub fn new(name: &'a str) -> Result<Self, VariableNameParseError> {
81        validate_variable_identifier(name)?;
82        Ok(Self::new_unchecked(name))
83    }
84
85    /// Creates a variable name from a unique identifier without validation.
86    ///
87    /// It is the caller's responsibility to ensure that `id` is a valid blank node identifier
88    /// according to the SPARQL grammar.
89    ///
90    /// [`Variable::new()`] is a safe version of this constructor and should be used for untrusted data.
91    #[inline]
92    pub const fn new_unchecked(name: &'a str) -> Self {
93        Self { name }
94    }
95
96    #[inline]
97    pub const fn as_str(self) -> &'a str {
98        self.name
99    }
100
101    #[inline]
102    pub fn into_string(self) -> String {
103        self.name.to_owned()
104    }
105
106    #[inline]
107    pub fn into_owned(self) -> Variable {
108        Variable {
109            name: self.name.to_owned(),
110        }
111    }
112}
113
114impl fmt::Display for VariableRef<'_> {
115    #[inline]
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        write!(f, "?{}", self.name)
118    }
119}
120
121impl<'a> From<&'a Variable> for VariableRef<'a> {
122    #[inline]
123    fn from(variable: &'a Variable) -> Self {
124        variable.as_ref()
125    }
126}
127
128impl<'a> From<VariableRef<'a>> for Variable {
129    #[inline]
130    fn from(variable: VariableRef<'a>) -> Self {
131        variable.into_owned()
132    }
133}
134
135impl PartialEq<Variable> for VariableRef<'_> {
136    #[inline]
137    fn eq(&self, other: &Variable) -> bool {
138        *self == other.as_ref()
139    }
140}
141
142impl PartialEq<VariableRef<'_>> for Variable {
143    #[inline]
144    fn eq(&self, other: &VariableRef<'_>) -> bool {
145        self.as_ref() == *other
146    }
147}
148
149impl PartialOrd<Variable> for VariableRef<'_> {
150    #[inline]
151    fn partial_cmp(&self, other: &Variable) -> Option<Ordering> {
152        self.partial_cmp(&other.as_ref())
153    }
154}
155
156impl PartialOrd<VariableRef<'_>> for Variable {
157    #[inline]
158    fn partial_cmp(&self, other: &VariableRef<'_>) -> Option<Ordering> {
159        self.as_ref().partial_cmp(other)
160    }
161}
162
163fn validate_variable_identifier(id: &str) -> Result<(), VariableNameParseError> {
164    let mut chars = id.chars();
165    let front = chars.next().ok_or(VariableNameParseError)?;
166    match front {
167        '0'..='9'
168        | '_'
169        | ':'
170        | 'A'..='Z'
171        | 'a'..='z'
172        | '\u{00C0}'..='\u{00D6}'
173        | '\u{00D8}'..='\u{00F6}'
174        | '\u{00F8}'..='\u{02FF}'
175        | '\u{0370}'..='\u{037D}'
176        | '\u{037F}'..='\u{1FFF}'
177        | '\u{200C}'..='\u{200D}'
178        | '\u{2070}'..='\u{218F}'
179        | '\u{2C00}'..='\u{2FEF}'
180        | '\u{3001}'..='\u{D7FF}'
181        | '\u{F900}'..='\u{FDCF}'
182        | '\u{FDF0}'..='\u{FFFD}'
183        | '\u{10000}'..='\u{EFFFF}' => (),
184        _ => return Err(VariableNameParseError),
185    }
186    for c in chars {
187        match c {
188            '0'..='9'
189            | '\u{00B7}'
190            | '\u{0300}'..='\u{036F}'
191            | '\u{203F}'..='\u{2040}'
192            | '_'
193            | 'A'..='Z'
194            | 'a'..='z'
195            | '\u{00C0}'..='\u{00D6}'
196            | '\u{00D8}'..='\u{00F6}'
197            | '\u{00F8}'..='\u{02FF}'
198            | '\u{0370}'..='\u{037D}'
199            | '\u{037F}'..='\u{1FFF}'
200            | '\u{200C}'..='\u{200D}'
201            | '\u{2070}'..='\u{218F}'
202            | '\u{2C00}'..='\u{2FEF}'
203            | '\u{3001}'..='\u{D7FF}'
204            | '\u{F900}'..='\u{FDCF}'
205            | '\u{FDF0}'..='\u{FFFD}'
206            | '\u{10000}'..='\u{EFFFF}' => (),
207            _ => return Err(VariableNameParseError),
208        }
209    }
210    Ok(())
211}
212
213/// An error raised during [`Variable`] name validation.
214#[derive(Debug, thiserror::Error)]
215#[error("The variable name is invalid")]
216pub struct VariableNameParseError;