use std::fmt::{Display, Formatter};
use std::str::FromStr;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Prefix {
Default,
Some(String),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PrefixedName {
prefix: Prefix,
name: String,
}
impl Default for Prefix {
fn default() -> Self {
Self::Default
}
}
impl Display for Prefix {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Prefix::Default => String::new(),
Prefix::Some(prefix) => prefix.to_owned(),
}
)
}
}
impl FromStr for Prefix {
type Err = IriError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::new(s)
}
}
impl Prefix {
pub fn new(prefix: &str) -> IriResult<Self> {
if prefix.is_empty() {
Err(ErrorKind::EmptyPrefixedName.into())
} else if !Self::is_valid(prefix) {
Err(ErrorKind::InvalidPrefixedName(prefix.to_string()).into())
} else {
Ok(Self::Some(prefix.to_string()))
}
}
pub fn is_default(&self) -> bool {
matches!(*self, Prefix::Default)
}
pub fn is_some(&self) -> bool {
matches!(*self, Prefix::Some(_))
}
pub fn contains(&self, p: &str) -> bool {
match self {
Prefix::Default => false,
Prefix::Some(prefix) => prefix == p,
}
}
pub fn as_ref(&self) -> Option<&String> {
match *self {
Prefix::Some(ref x) => Some(x),
Prefix::Default => None,
}
}
pub fn as_mut(&mut self) -> Option<&mut String> {
match *self {
Prefix::Some(ref mut x) => Some(x),
Prefix::Default => None,
}
}
pub fn unwrap(self) -> String {
match self {
Prefix::Some(val) => val,
Prefix::Default => panic!("called `Prefix::unwrap()` on a `Default` value"),
}
}
pub fn is_valid(prefix: &str) -> bool {
true
}
}
const NAME_ONLY: usize = 1;
const PREFIX_AND_NAME: usize = 2;
impl Display for PrefixedName {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}:{}",
match &self.prefix {
Prefix::Default => String::new(),
Prefix::Some(prefix) => prefix.to_owned(),
},
&self.name
)
}
}
impl FromStr for PrefixedName {
type Err = IriError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
Err(ErrorKind::EmptyPrefixedName.into())
} else {
let parts: Vec<&str> = s.split(':').collect();
match parts.len() {
NAME_ONLY => {
let name = *parts.get(0).unwrap();
if is_xml_name(name) {
Ok(PrefixedName {
prefix: Default::default(),
name: name.to_string(),
})
} else {
Err(ErrorKind::InvalidPrefixedName(s.to_string()).into())
}
}
PREFIX_AND_NAME => {
let prefix = *parts.get(0).unwrap();
let name = *parts.get(1).unwrap();
if is_xml_ncname(prefix) && is_xml_ncname(name) {
Ok(PrefixedName {
prefix: Prefix::Some(prefix.to_string()),
name: name.to_string(),
})
} else {
Err(ErrorKind::InvalidPrefixedName(s.to_string()).into())
}
}
_ => Err(ErrorKind::InvalidPrefixedName(s.to_string()).into()),
}
}
}
}
impl ValidateStr for PrefixedName {}
impl PrefixedName {
pub fn new(name: &str) -> Self {
assert!(is_xml_name(name));
Self {
prefix: Default::default(),
name: name.to_string(),
}
}
pub fn with_prefix(prefix: &str, name: &str) -> Self {
assert!(is_xml_name(prefix));
assert!(is_xml_name(name));
Self {
prefix: Prefix::Some(prefix.to_string()),
name: name.to_string(),
}
}
pub fn prefix(&self) -> &Prefix {
&self.prefix
}
pub fn name(&self) -> &String {
&self.name
}
pub fn as_curie(&self) -> Option<String> {
None
}
pub fn as_qname(&self) -> Option<String> {
None
}
}
fn is_sparql_prefixed_name(s: &str) -> bool {}
fn is_sparql_pname_ns(s: &str) -> bool {}
fn is_sparql_pname_ln(s: &str) -> bool {}
pub fn is_xml_name_start_char(c: char) -> bool {
c == ':'
|| (c >= 'A' && c <= 'Z')
|| c == '_'
|| (c >= 'a' && c <= 'z')
|| (c >= '\u{C0}' && c <= '\u{D6}')
|| (c >= '\u{D8}' && c <= '\u{F6}')
|| (c >= '\u{0F8}' && c <= '\u{2FF}')
|| (c >= '\u{370}' && c <= '\u{37D}')
|| (c >= '\u{037F}' && c <= '\u{1FFF}')
|| (c >= '\u{200C}' && c <= '\u{200D}')
|| (c >= '\u{2070}' && c <= '\u{218F}')
|| (c >= '\u{2C00}' && c <= '\u{2FEF}')
|| (c >= '\u{3001}' && c <= '\u{D7FF}')
|| (c >= '\u{F900}' && c <= '\u{FDCF}')
|| (c >= '\u{FDF0}' && c <= '\u{FFFD}')
|| (c >= '\u{10000}' && c <= '\u{EFFFF}')
}
fn is_xml_name_char(c: char) -> bool {
is_xml_name_start_char(c)
|| c == '-'
|| c == '.'
|| (c >= '0' && c <= '9')
|| c == '\u{B7}'
|| (c >= '\u{0300}' && c <= '\u{036F}')
|| (c >= '\u{203F}' && c <= '\u{2040}')
}
fn is_xml_ncname(s: &str) -> bool {
!s.is_empty()
&& s.starts_with(is_xml_name_start_char)
&& s[1..].chars().all(|c| is_xml_name_char(c) && c == ':')
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_qname() {
let pre_name = PrefixedName::new("foo");
assert_eq!(pre_name.to_string(), "foo".to_string());
assert_eq!(pre_name.as_curie(), Some("[:foo]".to_string()));
assert_eq!(pre_name.as_qname(), Some("foo".to_string()));
let pre_name = PrefixedName::with_prefix("rdf", "foo");
assert_eq!(pre_name.to_string(), "rdf:foo".to_string());
assert_eq!(pre_name.as_curie(), Some("[rdf:foo]".to_string()));
assert_eq!(pre_name.as_qname(), Some("rdf:foo".to_string()));
}
#[test]
fn test_qname_from_str() {
let pre_name = PrefixedName::from_str("foo");
assert!(pre_name.is_ok());
assert_eq!(pre_name.unwrap().to_string(), "foo".to_string());
let pre_name = PrefixedName::from_str("rdf:foo");
assert!(pre_name.is_ok());
assert_eq!(pre_name.unwrap().to_string(), "rdf:foo".to_string());
}
#[test]
fn test_qname_from_str_fail() {
let pre_name = PrefixedName::from_str("");
assert!(pre_name.is_err());
let pre_name = PrefixedName::from_str("rdf foo");
assert!(pre_name.is_err());
let pre_name = PrefixedName::from_str(":foo");
assert!(pre_name.is_err());
let pre_name = PrefixedName::from_str("rdf::foo:bar");
assert!(pre_name.is_err());
}
}