Fork of https://github.com/oxigraph/oxigraph.git for the purpose of NextGraph project
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
3.4 KiB
122 lines
3.4 KiB
3 years ago
|
use std::error::Error;
|
||
|
use std::fmt;
|
||
|
|
||
|
/// A [SPARQL query](https://www.w3.org/TR/sparql11-query/) variable.
|
||
|
///
|
||
|
/// ```
|
||
|
/// use oxrdf::{Variable, VariableNameParseError};
|
||
|
///
|
||
|
/// assert_eq!(
|
||
|
/// "?foo",
|
||
|
/// Variable::new("foo")?.to_string()
|
||
|
/// );
|
||
|
/// # Result::<_,VariableNameParseError>::Ok(())
|
||
|
/// ```
|
||
|
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)]
|
||
|
pub struct Variable {
|
||
|
name: String,
|
||
|
}
|
||
|
|
||
|
impl Variable {
|
||
|
/// Creates a variable name from a unique identifier.
|
||
|
///
|
||
|
/// The variable identifier must be valid according to the SPARQL grammar.
|
||
|
pub fn new(name: impl Into<String>) -> Result<Self, VariableNameParseError> {
|
||
|
let name = name.into();
|
||
|
validate_variable_identifier(&name)?;
|
||
|
Ok(Self::new_unchecked(name))
|
||
|
}
|
||
|
|
||
|
/// Creates a variable name from a unique identifier without validation.
|
||
|
///
|
||
|
/// It is the caller's responsibility to ensure that `id` is a valid blank node identifier
|
||
|
/// according to the SPARQL grammar.
|
||
|
///
|
||
|
/// [`Variable::new()`] is a safe version of this constructor and should be used for untrusted data.
|
||
|
#[inline]
|
||
|
pub fn new_unchecked(name: impl Into<String>) -> Self {
|
||
|
Self { name: name.into() }
|
||
|
}
|
||
|
|
||
|
#[inline]
|
||
|
pub fn as_str(&self) -> &str {
|
||
|
&self.name
|
||
|
}
|
||
|
|
||
|
#[inline]
|
||
|
pub fn into_string(self) -> String {
|
||
|
self.name
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl fmt::Display for Variable {
|
||
|
#[inline]
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
write!(f, "?{}", self.name)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn validate_variable_identifier(id: &str) -> Result<(), VariableNameParseError> {
|
||
|
let mut chars = id.chars();
|
||
|
let front = chars.next().ok_or(VariableNameParseError {})?;
|
||
|
match front {
|
||
|
'0'..='9'
|
||
|
| '_'
|
||
|
| ':'
|
||
|
| 'A'..='Z'
|
||
|
| 'a'..='z'
|
||
|
| '\u{00C0}'..='\u{00D6}'
|
||
|
| '\u{00D8}'..='\u{00F6}'
|
||
|
| '\u{00F8}'..='\u{02FF}'
|
||
|
| '\u{0370}'..='\u{037D}'
|
||
|
| '\u{037F}'..='\u{1FFF}'
|
||
|
| '\u{200C}'..='\u{200D}'
|
||
|
| '\u{2070}'..='\u{218F}'
|
||
|
| '\u{2C00}'..='\u{2FEF}'
|
||
|
| '\u{3001}'..='\u{D7FF}'
|
||
|
| '\u{F900}'..='\u{FDCF}'
|
||
|
| '\u{FDF0}'..='\u{FFFD}'
|
||
|
| '\u{10000}'..='\u{EFFFF}' => (),
|
||
|
_ => return Err(VariableNameParseError {}),
|
||
|
}
|
||
|
for c in chars {
|
||
|
match c {
|
||
|
'0'..='9'
|
||
|
| '\u{00B7}'
|
||
|
| '\u{00300}'..='\u{036F}'
|
||
|
| '\u{203F}'..='\u{2040}'
|
||
|
| '_'
|
||
|
| 'A'..='Z'
|
||
|
| 'a'..='z'
|
||
|
| '\u{00C0}'..='\u{00D6}'
|
||
|
| '\u{00D8}'..='\u{00F6}'
|
||
|
| '\u{00F8}'..='\u{02FF}'
|
||
|
| '\u{0370}'..='\u{037D}'
|
||
|
| '\u{037F}'..='\u{1FFF}'
|
||
|
| '\u{200C}'..='\u{200D}'
|
||
|
| '\u{2070}'..='\u{218F}'
|
||
|
| '\u{2C00}'..='\u{2FEF}'
|
||
|
| '\u{3001}'..='\u{D7FF}'
|
||
|
| '\u{F900}'..='\u{FDCF}'
|
||
|
| '\u{FDF0}'..='\u{FFFD}'
|
||
|
| '\u{10000}'..='\u{EFFFF}' => (),
|
||
|
_ => return Err(VariableNameParseError {}),
|
||
|
}
|
||
|
}
|
||
|
Ok(())
|
||
|
}
|
||
|
|
||
|
/// An error raised during [`Variable`] name validation.
|
||
|
#[allow(missing_copy_implementations)]
|
||
|
#[derive(Debug)]
|
||
|
pub struct VariableNameParseError {}
|
||
|
|
||
|
impl fmt::Display for VariableNameParseError {
|
||
|
#[inline]
|
||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
write!(f, "The variable name is invalid")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Error for VariableNameParseError {}
|