parent
1800d6deca
commit
53a5a7df10
@ -0,0 +1,30 @@ |
||||
use std::fmt; |
||||
use std::ops::Deref; |
||||
use uuid::Uuid; |
||||
|
||||
/// A RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node)
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] |
||||
pub struct BlankNode { |
||||
id: Uuid, |
||||
} |
||||
|
||||
impl Deref for BlankNode { |
||||
type Target = Uuid; |
||||
|
||||
fn deref(&self) -> &Uuid { |
||||
&self.id |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for BlankNode { |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
write!(f, "_:{}", self.id) |
||||
} |
||||
} |
||||
|
||||
impl Default for BlankNode { |
||||
/// Builds a new RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node) with a unique id
|
||||
fn default() -> Self { |
||||
BlankNode { id: Uuid::new_v4() } |
||||
} |
||||
} |
@ -0,0 +1,140 @@ |
||||
use model::named_node::NamedNode; |
||||
use model::vocab::rdf; |
||||
use model::vocab::xsd; |
||||
use std::borrow::Cow; |
||||
use std::fmt; |
||||
use std::option::Option; |
||||
use utils::Escaper; |
||||
|
||||
/// A RDF [literal](https://www.w3.org/TR/rdf11-concepts/#dfn-literal)
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] |
||||
pub enum Literal { |
||||
SimpleLiteral(String), |
||||
String(String), |
||||
LanguageTaggedString { value: String, language: String }, |
||||
Boolean(bool), |
||||
TypedLiteral { value: String, datatype: NamedNode }, |
||||
} |
||||
|
||||
impl Literal { |
||||
/// Builds a RDF [simple literal](https://www.w3.org/TR/rdf11-concepts/#dfn-simple-literal)
|
||||
pub fn new_simple_literal(value: impl Into<String>) -> Self { |
||||
Literal::SimpleLiteral(value.into()) |
||||
} |
||||
|
||||
/// Builds a RDF [literal](https://www.w3.org/TR/rdf11-concepts/#dfn-literal) with a [datatype](https://www.w3.org/TR/rdf11-concepts/#dfn-datatype-iri)
|
||||
pub fn new_typed_literal(value: impl Into<String>, datatype: impl Into<NamedNode>) -> Self { |
||||
//TODO: proper casts
|
||||
Literal::TypedLiteral { |
||||
value: value.into(), |
||||
datatype: datatype.into(), |
||||
} |
||||
} |
||||
|
||||
/// Builds a RDF [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string)
|
||||
pub fn new_language_tagged_literal( |
||||
value: impl Into<String>, |
||||
language: impl Into<String>, |
||||
) -> Self { |
||||
Literal::LanguageTaggedString { |
||||
value: value.into(), |
||||
language: language.into(), |
||||
} |
||||
} |
||||
|
||||
/// The literal [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form)
|
||||
pub fn value<'a>(&'a self) -> Cow<'a, String> { |
||||
match self { |
||||
Literal::SimpleLiteral(value) => Cow::Borrowed(value), |
||||
Literal::String(value) => Cow::Borrowed(value), |
||||
Literal::LanguageTaggedString { value, .. } => Cow::Borrowed(value), |
||||
Literal::Boolean(value) => Cow::Owned(value.to_string()), |
||||
Literal::TypedLiteral { value, .. } => Cow::Borrowed(value), |
||||
} |
||||
} |
||||
|
||||
/// The literal [language tag](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tag) if it is a [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string)
|
||||
pub fn language(&self) -> Option<&str> { |
||||
match self { |
||||
Literal::LanguageTaggedString { language, .. } => Some(language), |
||||
_ => None, |
||||
} |
||||
} |
||||
|
||||
/// The literal [datatype](https://www.w3.org/TR/rdf11-concepts/#dfn-datatype-iri)
|
||||
/// The datatype of [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string) is always http://www.w3.org/1999/02/22-rdf-syntax-ns#langString
|
||||
pub fn datatype(&self) -> &NamedNode { |
||||
match self { |
||||
Literal::SimpleLiteral(_) => &xsd::STRING, |
||||
Literal::String(_) => &xsd::STRING, |
||||
Literal::LanguageTaggedString { .. } => &rdf::LANG_STRING, |
||||
Literal::Boolean(_) => &xsd::BOOLEAN, |
||||
Literal::TypedLiteral { datatype, .. } => datatype, |
||||
} |
||||
} |
||||
|
||||
pub fn is_plain(&self) -> bool { |
||||
match self { |
||||
Literal::SimpleLiteral(_) => true, |
||||
Literal::LanguageTaggedString { .. } => true, |
||||
_ => false, |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for Literal { |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
if self.is_plain() { |
||||
self.language() |
||||
.map(|lang| write!(f, "\"{}\"@{}", self.value().escape(), lang)) |
||||
.unwrap_or_else(|| write!(f, "\"{}\"", self.value().escape())) |
||||
} else { |
||||
write!(f, "\"{}\"^^{}", self.value().escape(), self.datatype()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl<'a> From<&'a str> for Literal { |
||||
fn from(value: &'a str) -> Self { |
||||
Literal::String(value.into()) |
||||
} |
||||
} |
||||
|
||||
impl From<String> for Literal { |
||||
fn from(value: String) -> Self { |
||||
Literal::String(value) |
||||
} |
||||
} |
||||
|
||||
impl From<bool> for Literal { |
||||
fn from(value: bool) -> Self { |
||||
Literal::Boolean(value) |
||||
} |
||||
} |
||||
|
||||
impl From<usize> for Literal { |
||||
fn from(value: usize) -> Self { |
||||
Literal::TypedLiteral { |
||||
value: value.to_string(), |
||||
datatype: xsd::INTEGER.clone(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<f32> for Literal { |
||||
fn from(value: f32) -> Self { |
||||
Literal::TypedLiteral { |
||||
value: value.to_string(), |
||||
datatype: xsd::FLOAT.clone(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<f64> for Literal { |
||||
fn from(value: f64) -> Self { |
||||
Literal::TypedLiteral { |
||||
value: value.to_string(), |
||||
datatype: xsd::DOUBLE.clone(), |
||||
} |
||||
} |
||||
} |
@ -1,2 +1,17 @@ |
||||
pub mod data; |
||||
///! Implements data structures for https://www.w3.org/TR/rdf11-concepts/
|
||||
///! Inspired by [RDFjs](http://rdf.js.org/)
|
||||
mod blank_node; |
||||
mod literal; |
||||
mod named_node; |
||||
mod triple; |
||||
pub mod vocab; |
||||
|
||||
pub use model::blank_node::BlankNode; |
||||
pub use model::literal::Literal; |
||||
pub use model::named_node::NamedNode; |
||||
pub use model::triple::NamedOrBlankNode; |
||||
pub use model::triple::Quad; |
||||
pub use model::triple::QuadLike; |
||||
pub use model::triple::Term; |
||||
pub use model::triple::Triple; |
||||
pub use model::triple::TripleLike; |
||||
|
@ -0,0 +1,57 @@ |
||||
use std::fmt; |
||||
use std::ops::Deref; |
||||
use std::str::FromStr; |
||||
use std::sync::Arc; |
||||
use url::ParseError; |
||||
use url::Url; |
||||
|
||||
/// A RDF [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri)
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] |
||||
pub struct NamedNode { |
||||
iri: Arc<Url>, |
||||
} |
||||
|
||||
impl fmt::Display for NamedNode { |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
write!(f, "<{}>", self.iri) |
||||
} |
||||
} |
||||
|
||||
impl NamedNode { |
||||
/// Builds a RDF [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri)
|
||||
pub fn new(iri: impl Into<Url>) -> Self { |
||||
Self { |
||||
iri: Arc::new(iri.into()), |
||||
} |
||||
} |
||||
|
||||
pub fn value(&self) -> &str { |
||||
self.iri.as_str() |
||||
} |
||||
|
||||
pub fn url(&self) -> &Url { |
||||
&self.iri |
||||
} |
||||
} |
||||
|
||||
impl Deref for NamedNode { |
||||
type Target = Url; |
||||
|
||||
fn deref(&self) -> &Url { |
||||
&self.iri |
||||
} |
||||
} |
||||
|
||||
impl From<Url> for NamedNode { |
||||
fn from(url: Url) -> Self { |
||||
Self { iri: Arc::new(url) } |
||||
} |
||||
} |
||||
|
||||
impl FromStr for NamedNode { |
||||
type Err = ParseError; |
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> { |
||||
Ok(NamedNode::new(Url::parse(s)?)) |
||||
} |
||||
} |
@ -1,235 +1,7 @@ |
||||
use std::borrow::Cow; |
||||
///! Implements data structures for https://www.w3.org/TR/rdf11-concepts/
|
||||
///! Inspired by [RDFjs](http://rdf.js.org/)
|
||||
use model::blank_node::BlankNode; |
||||
use model::literal::Literal; |
||||
use model::named_node::NamedNode; |
||||
use std::fmt; |
||||
use std::ops::Deref; |
||||
use std::option::Option; |
||||
use std::str::FromStr; |
||||
use std::sync::Arc; |
||||
use url::ParseError; |
||||
use url::Url; |
||||
use utils::Escaper; |
||||
use uuid::Uuid; |
||||
|
||||
/// A RDF [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri)
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] |
||||
pub struct NamedNode { |
||||
iri: Arc<Url>, |
||||
} |
||||
|
||||
impl NamedNode { |
||||
/// Builds a RDF [IRI](https://www.w3.org/TR/rdf11-concepts/#dfn-iri)
|
||||
pub fn new(iri: impl Into<Url>) -> Self { |
||||
Self { |
||||
iri: Arc::new(iri.into()), |
||||
} |
||||
} |
||||
|
||||
pub fn value(&self) -> &str { |
||||
self.iri.as_str() |
||||
} |
||||
|
||||
pub fn url(&self) -> &Url { |
||||
&self.iri |
||||
} |
||||
} |
||||
|
||||
impl Deref for NamedNode { |
||||
type Target = Url; |
||||
|
||||
fn deref(&self) -> &Url { |
||||
&self.iri |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for NamedNode { |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
write!(f, "<{}>", self.iri) |
||||
} |
||||
} |
||||
|
||||
impl FromStr for NamedNode { |
||||
type Err = ParseError; |
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> { |
||||
Ok(NamedNode::new(Url::parse(s)?)) |
||||
} |
||||
} |
||||
|
||||
/// A RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node)
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] |
||||
pub struct BlankNode { |
||||
id: Uuid, |
||||
} |
||||
|
||||
impl Deref for BlankNode { |
||||
type Target = Uuid; |
||||
|
||||
fn deref(&self) -> &Uuid { |
||||
&self.id |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for BlankNode { |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
write!(f, "_:{}", self.id) |
||||
} |
||||
} |
||||
|
||||
impl Default for BlankNode { |
||||
/// Builds a new RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node) with a unique id
|
||||
fn default() -> Self { |
||||
BlankNode { id: Uuid::new_v4() } |
||||
} |
||||
} |
||||
|
||||
/// A RDF [literal](https://www.w3.org/TR/rdf11-concepts/#dfn-literal)
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] |
||||
pub enum Literal { |
||||
SimpleLiteral(String), |
||||
String(String), |
||||
LanguageTaggedString { value: String, language: String }, |
||||
Boolean(bool), |
||||
TypedLiteral { value: String, datatype: NamedNode }, |
||||
} |
||||
|
||||
lazy_static! { |
||||
static ref XSD_BOOLEAN: NamedNode = |
||||
NamedNode::from_str("http://www.w3.org/2001/XMLSchema#boolean").unwrap(); |
||||
static ref XSD_DOUBLE: NamedNode = |
||||
NamedNode::from_str("http://www.w3.org/2001/XMLSchema#double").unwrap(); |
||||
static ref XSD_FLOAT: NamedNode = |
||||
NamedNode::from_str("http://www.w3.org/2001/XMLSchema#float").unwrap(); |
||||
static ref XSD_INTEGER: NamedNode = |
||||
NamedNode::from_str("http://www.w3.org/2001/XMLSchema#integer").unwrap(); |
||||
static ref XSD_STRING: NamedNode = |
||||
NamedNode::from_str("http://www.w3.org/2001/XMLSchema#string").unwrap(); |
||||
static ref RDF_LANG_STRING: NamedNode = |
||||
NamedNode::from_str("http://www.w3.org/1999/02/22-rdf-syntax-ns#langString").unwrap(); |
||||
} |
||||
|
||||
impl Literal { |
||||
/// Builds a RDF [simple literal](https://www.w3.org/TR/rdf11-concepts/#dfn-simple-literal)
|
||||
pub fn new_simple_literal(value: impl Into<String>) -> Self { |
||||
Literal::SimpleLiteral(value.into()) |
||||
} |
||||
|
||||
/// Builds a RDF [literal](https://www.w3.org/TR/rdf11-concepts/#dfn-literal) with a [datatype](https://www.w3.org/TR/rdf11-concepts/#dfn-datatype-iri)
|
||||
pub fn new_typed_literal(value: impl Into<String>, datatype: impl Into<NamedNode>) -> Self { |
||||
//TODO: proper casts
|
||||
Literal::TypedLiteral { |
||||
value: value.into(), |
||||
datatype: datatype.into(), |
||||
} |
||||
} |
||||
|
||||
/// Builds a RDF [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string)
|
||||
pub fn new_language_tagged_literal( |
||||
value: impl Into<String>, |
||||
language: impl Into<String>, |
||||
) -> Self { |
||||
Literal::LanguageTaggedString { |
||||
value: value.into(), |
||||
language: language.into(), |
||||
} |
||||
} |
||||
|
||||
/// The literal [lexical form](https://www.w3.org/TR/rdf11-concepts/#dfn-lexical-form)
|
||||
pub fn value<'a>(&'a self) -> Cow<'a, String> { |
||||
match self { |
||||
Literal::SimpleLiteral(value) => Cow::Borrowed(value), |
||||
Literal::String(value) => Cow::Borrowed(value), |
||||
Literal::LanguageTaggedString { value, .. } => Cow::Borrowed(value), |
||||
Literal::Boolean(value) => Cow::Owned(value.to_string()), |
||||
Literal::TypedLiteral { value, .. } => Cow::Borrowed(value), |
||||
} |
||||
} |
||||
|
||||
/// The literal [language tag](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tag) if it is a [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string)
|
||||
pub fn language(&self) -> Option<&str> { |
||||
match self { |
||||
Literal::LanguageTaggedString { language, .. } => Some(language), |
||||
_ => None, |
||||
} |
||||
} |
||||
|
||||
/// The literal [datatype](https://www.w3.org/TR/rdf11-concepts/#dfn-datatype-iri)
|
||||
/// The datatype of [language-tagged string](https://www.w3.org/TR/rdf11-concepts/#dfn-language-tagged-string) is always http://www.w3.org/1999/02/22-rdf-syntax-ns#langString
|
||||
pub fn datatype(&self) -> &NamedNode { |
||||
match self { |
||||
Literal::SimpleLiteral(_) => &XSD_STRING, |
||||
Literal::String(_) => &XSD_STRING, |
||||
Literal::LanguageTaggedString { .. } => &RDF_LANG_STRING, |
||||
Literal::Boolean(_) => &XSD_BOOLEAN, |
||||
Literal::TypedLiteral { datatype, .. } => datatype, |
||||
} |
||||
} |
||||
|
||||
pub fn is_plain(&self) -> bool { |
||||
match self { |
||||
Literal::SimpleLiteral(_) => true, |
||||
Literal::LanguageTaggedString { .. } => true, |
||||
_ => false, |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for Literal { |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
if self.is_plain() { |
||||
self.language() |
||||
.map(|lang| write!(f, "\"{}\"@{}", self.value().escape(), lang)) |
||||
.unwrap_or_else(|| write!(f, "\"{}\"", self.value().escape())) |
||||
} else { |
||||
write!(f, "\"{}\"^^{}", self.value().escape(), self.datatype()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl<'a> From<&'a str> for Literal { |
||||
fn from(value: &'a str) -> Self { |
||||
Literal::String(value.into()) |
||||
} |
||||
} |
||||
|
||||
impl From<String> for Literal { |
||||
fn from(value: String) -> Self { |
||||
Literal::String(value) |
||||
} |
||||
} |
||||
|
||||
impl From<bool> for Literal { |
||||
fn from(value: bool) -> Self { |
||||
Literal::Boolean(value) |
||||
} |
||||
} |
||||
|
||||
impl From<usize> for Literal { |
||||
fn from(value: usize) -> Self { |
||||
Literal::TypedLiteral { |
||||
value: value.to_string(), |
||||
datatype: XSD_INTEGER.clone(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<f32> for Literal { |
||||
fn from(value: f32) -> Self { |
||||
Literal::TypedLiteral { |
||||
value: value.to_string(), |
||||
datatype: XSD_FLOAT.clone(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl From<f64> for Literal { |
||||
fn from(value: f64) -> Self { |
||||
Literal::TypedLiteral { |
||||
value: value.to_string(), |
||||
datatype: XSD_DOUBLE.clone(), |
||||
} |
||||
} |
||||
} |
||||
|
||||
/// The union of [IRIs](https://www.w3.org/TR/rdf11-concepts/#dfn-iri) and [blank nodes](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node).
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] |
Loading…
Reference in new issue