Skip to content

Commit

Permalink
Merge 4ffe3f3 into feeca61
Browse files Browse the repository at this point in the history
  • Loading branch information
pchampin committed Apr 17, 2020
2 parents feeca61 + 4ffe3f3 commit 301c613
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 0 deletions.
108 changes: 108 additions & 0 deletions term/src/_trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//! Experimenting with a `Term` trait#[derive(Eq, PartialEq)]


use crate::mown_str::MownStr;

/// A trait for types that can be used as terms
pub trait Term: std::fmt::Debug {
fn kind(&self) -> TermKind;
fn value(&self) -> MownStr;
fn datatype(&self) -> Option<MownStr>;
fn language(&self) -> Option<MownStr>;
fn absolute(&self) -> bool {
todo!()
// provide default impl here,
// checking kind() and, depending, value() or datatype()
}
}

/// An enum of all kinds of terms
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum TermKind {
Iri,
Literal,
BNode,
Variable,
}

/// A function that can compare any two terms
///
/// If you want to avoid monomorphization, use term_eq_dyn instead
pub fn term_eq<T1: Term + ?Sized, T2: Term + ?Sized>(t1: &T1, t2: &T2) -> bool {
t1.kind() == t2.kind() && t1.value() == t2.value() && (t1.kind() != TermKind::Literal || t1.language() == t2.language() && t1.datatype() == t2.datatype())
}
/// A function that can compare any two terms
///
/// If you want to avoid trait objects, use term_eq instead
pub fn term_eq_dyn(t1: &dyn Term, t2: &dyn Term) -> bool {
term_eq(t1, t2)
}

/// A trait for types that can be created from any term
pub trait FromTerm {
fn from_term<T: Term>(other: &T) -> Self;
}

/// A trait for types that can be created from some terms
pub trait TryFromTerm: Sized {
fn try_from_term<T: Term>(other: &T) -> Result<Self, TermConversionError>;
}

#[derive(Debug, thiserror::Error)]
pub enum TermConversionError {
#[error("Unsupported term kind {0:?}")]
UnsupportedTermKind(TermKind),
#[error("Invalid lexical value {0:?}")]
InvalidLexicalValue(String),
}
use TermConversionError::*;

//

/// Native types (such as i32) can also implement Term and friends
impl Term for i32 {
fn kind(&self) -> TermKind { TermKind::Literal }
fn value(&self) -> MownStr { format!("{}", self).into() }
fn datatype(&self) -> Option<MownStr> { Some(XSD_INTEGER) }
fn language(&self) -> Option<MownStr> { None }
}

impl TryFromTerm for i32 {
fn try_from_term<T: Term>(other: &T) -> Result<Self, TermConversionError> {
if other.kind() != TermKind::Literal {
Err(UnsupportedTermKind(other.kind()))
} else {
other.value().parse::<i32>().map_err(|_| TermConversionError::InvalidLexicalValue(other.value().into()))
}
}
}
const XSD_INTEGER: MownStr = MownStr::Ref("http://www.w3.org/2001/XMLSchema#integer");

//

/// Suffixed Iri (as produced by a Namespace object, for example)
#[derive(Clone, Debug)]
pub struct SuffixedIri<'a> {
ns: &'a str,
suffix: Box<str>,
}
// TODO constructor that checks the validity of the ns and suffix
// as well as constructor taking a MownIri for ns, avoiding the check

impl<'a> Term for SuffixedIri<'a> {
fn kind(&self) -> TermKind { TermKind::Iri }
fn value(&self) -> MownStr { format!("{}{}", self.ns, self.suffix).into() }
fn datatype(&self) -> Option<MownStr> { None }
fn language(&self) -> Option<MownStr> { None }
}

//

/// Simple type implemeting
pub enum MyTerm {
Iri(Box<str>),
BNode(Box<str>),
Literal(Box<str>, Box<str>),
Variable(Box<str>),
}
// TODO impl Term
1 change: 1 addition & 0 deletions term/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ use self::mown_str::MownStr;
mod _display;
mod _error;
mod _graph_name_matcher; // is 'pub use'd by module 'matcher'
mod _trait;
pub use self::_error::*;

/// Generic type for RDF terms.
Expand Down
7 changes: 7 additions & 0 deletions term/src/mown_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,13 @@ impl<'a> MownStr<'a> {
Own(b) => T::from(b),
}
}
/// Makes a new MownStr that owns a copy if this one
pub fn as_own<'b>(&self) -> MownStr<'b> {
match self {
Ref(r) => Box::<str>::from(*r).into(),
Own(b) => b.clone().into(),
}
}
}

#[cfg(test)]
Expand Down

0 comments on commit 301c613

Please sign in to comment.