diff --git a/src/io/rdf/reader.rs b/src/io/rdf/reader.rs index f7b2a83..ee76ca8 100644 --- a/src/io/rdf/reader.rs +++ b/src/io/rdf/reader.rs @@ -1,5 +1,5 @@ use rio_api::{ - model::{BlankNode, NamedNode, Subject}, + model::{BlankNode, NamedNode, Subject, Triple}, parser::TriplesParser, }; use Term::*; @@ -25,10 +25,10 @@ use crate::{ vocab::RDFS as VRDFS, }; -use std::collections::HashMap; use std::io::BufRead; use std::io::Cursor; use std::{collections::BTreeSet, convert::TryFrom}; +use std::{collections::HashMap, convert::TryInto}; type RioTerm<'a> = ::rio_api::model::Term<'a>; @@ -58,33 +58,33 @@ pub enum Term { Literal(Literal), } -impl From for Term { - fn from(value: VOWL) -> Self { - Self::OWL(value) +impl From<&VOWL> for Term { + fn from(value: &VOWL) -> Self { + Self::OWL(value.clone()) } } -impl From for Term { - fn from(value: VRDF) -> Self { - Self::RDF(value) +impl From<&VRDF> for Term { + fn from(value: &VRDF) -> Self { + Self::RDF(value.clone()) } } -impl From for Term { - fn from(value: VRDFS) -> Self { - Self::RDFS(value) +impl From<&VRDFS> for Term { + fn from(value: &VRDFS) -> Self { + Self::RDFS(value.clone()) } } -impl From for Term { - fn from(value: VSWRL) -> Self { - Self::SWRL(value) +impl From<&VSWRL> for Term { + fn from(value: &VSWRL) -> Self { + Self::SWRL(value.clone()) } } -impl From for Term { - fn from(value: Facet) -> Self { - Self::FacetTerm(value) +impl From<&Facet> for Term { + fn from(value: &Facet) -> Self { + Self::FacetTerm(value.clone()) } } @@ -106,10 +106,10 @@ impl From> for Term { } } -impl TryFrom for Term { +impl TryFrom<&crate::vocab::Vocab> for Term { type Error = HornedError; - fn try_from(value: crate::vocab::Vocab) -> Result { + fn try_from(value: &crate::vocab::Vocab) -> Result { match value { crate::vocab::Vocab::Facet(facet) => Ok(facet.into()), crate::vocab::Vocab::RDF(rdf) => Ok(rdf.into()), @@ -121,12 +121,6 @@ impl TryFrom for Term { } } -impl Term { - fn try_into_vocab_term(s: &str) -> Result { - s.parse::().and_then(Term::try_from) - } -} - #[derive(Clone, Debug, Eq, PartialEq)] enum OrTerm { Term(Term), @@ -145,57 +139,93 @@ impl From> for OrTerm { } } -fn to_term_nn(nn: &NamedNode, b: &Build) -> Term { - if let Ok(term) = Term::try_into_vocab_term(nn.iri) { - term - } else { - Term::Iri(b.iri(nn.iri)) +impl TryFrom<&NamedNode<'_>> for Term { + type Error = HornedError; + + fn try_from(value: &NamedNode<'_>) -> Result { + if let Some(res) = Vocab::lookup(value.iri) { + Term::try_from(res) + } else { + Err(HornedError::invalid(value.iri)) + } } } -fn to_term_bn(nn: &BlankNode) -> Term { - Term::BNode(BNode(nn.id.to_string().into())) +impl TryFrom<&NamedNode<'_>> for crate::vocab::XSD { + type Error = HornedError; + + fn try_from(value: &NamedNode<'_>) -> Result { + value.iri.parse::() + } } -fn to_term_lt(lt: &rio_api::model::Literal, b: &Build) -> Term { - match lt { - rio_api::model::Literal::Simple { value } => Term::Literal(Literal::Simple { - literal: value.to_string(), - }), - rio_api::model::Literal::LanguageTaggedString { value, language } => { - Term::Literal(Literal::Language { - literal: value.to_string(), - lang: language.to_string(), - }) +impl Build { + fn to_term_bn(nn: &BlankNode) -> Term { + Term::BNode(BNode(nn.id.to_string().into())) + } + + fn to_pos_triple(&self, rio_triple: Triple, pos: usize) -> PosTriple { + PosTriple( + [ + self.to_term_bnn(&rio_triple.subject), + self.to_term_nn(&rio_triple.predicate), + self.to_term(&rio_triple.object), + ], + pos, + ) + } + + fn to_term(&self, t: &RioTerm) -> Term { + match t { + rio_api::model::Term::NamedNode(iri) => self.to_term_nn(iri), + rio_api::model::Term::BlankNode(id) => Self::to_term_bn(id), + rio_api::model::Term::Literal(l) => self.to_term_lt(l), + rio_api::model::Term::Triple(_) => { + unimplemented!("Triple subjects are not implemented") + } } - rio_api::model::Literal::Typed { value, datatype } - if datatype.iri == "http://www.w3.org/2001/XMLSchema#string" => - { - Term::Literal(Literal::Simple { - literal: value.to_string(), - }) + } + + fn to_term_bnn(&self, subj: &Subject) -> Term { + match subj { + Subject::NamedNode(nn) => self.to_term_nn(nn), + Subject::BlankNode(bn) => Self::to_term_bn(bn), + Subject::Triple(_) => unimplemented!("Triple subjects are not implemented"), } - rio_api::model::Literal::Typed { value, datatype } => Term::Literal(Literal::Datatype { - literal: value.to_string(), - datatype_iri: b.iri(datatype.iri), - }), } -} -fn to_term_nnb(nnb: &Subject, b: &Build) -> Term { - match nnb { - Subject::NamedNode(nn) => to_term_nn(nn, b), - Subject::BlankNode(bn) => to_term_bn(bn), - Subject::Triple(_) => unimplemented!("Triple subjects are not implemented"), + fn to_term_nn(&self, nn: &NamedNode) -> Term { + if let Ok(term) = nn.try_into() { + term + } else { + Term::Iri(self.iri(nn.iri)) + } } -} -fn to_term(t: &RioTerm, b: &Build) -> Term { - match t { - rio_api::model::Term::NamedNode(iri) => to_term_nn(iri, b), - rio_api::model::Term::BlankNode(id) => to_term_bn(id), - rio_api::model::Term::Literal(l) => to_term_lt(l, b), - rio_api::model::Term::Triple(_) => unimplemented!("Triple subjects are not implemented"), + fn to_term_lt(&self, lt: &rio_api::model::Literal) -> Term { + match lt { + rio_api::model::Literal::Simple { value } => Term::Literal(Literal::Simple { + literal: value.to_string(), + }), + rio_api::model::Literal::LanguageTaggedString { value, language } => { + Term::Literal(Literal::Language { + literal: value.to_string(), + lang: language.to_string(), + }) + } + rio_api::model::Literal::Typed { value, datatype } => { + if let Ok(crate::vocab::XSD::String) = datatype.try_into() { + Term::Literal(Literal::Simple { + literal: value.to_string(), + }) + } else { + Term::Literal(Literal::Datatype { + literal: value.to_string(), + datatype_iri: self.iri(datatype.iri), + }) + } + } + } } } @@ -403,14 +433,7 @@ impl<'a, A: ForIRI, AA: ForIndex> OntologyParser<'a, A, AA> { let mut triples = vec![]; let last_pos = std::cell::Cell::new(0); let mut on_triple = |rio_triple: rio_api::model::Triple| -> Result<_, HornedError> { - triples.push(PosTriple( - [ - to_term_nnb(&rio_triple.subject, b), - to_term_nn(&rio_triple.predicate, b), - to_term(&rio_triple.object, b), - ], - last_pos.get(), - )); + triples.push(b.to_pos_triple(rio_triple, last_pos.get())); Ok(()) }; diff --git a/src/vocab.rs b/src/vocab.rs index d4aeeaf..0c7e58a 100644 --- a/src/vocab.rs +++ b/src/vocab.rs @@ -11,12 +11,14 @@ use crate::model::{NamedOWLEntity, NamedOWLEntityKind}; use std::borrow::Borrow; use std::convert::TryFrom; use std::str::FromStr; +use std::sync::OnceLock; macro_rules! vocabulary_traits { ($($enum_type:ident),+; $return_type:ty ) => { $( + impl TryFrom<&[u8]> for $enum_type { type Error = HornedError; @@ -84,16 +86,12 @@ macro_rules! vocabulary_type { } impl $enum_type { - fn get_iri(self) -> IRI { - - let mut iri_str = String::new(); - $( - iri_str.push_str(Namespace::$ns.as_ref()); - )? + fn get_iri(self) -> IRI { match self { $( $enum_type::$variant => { + dbg!(&self); let mut iri_str = String::from(Namespace::$ns.as_ref()); let mut variant_str = String::from(stringify!($variant)); if $first_lowercase { @@ -109,6 +107,19 @@ macro_rules! vocabulary_type { } } + impl $enum_type { + fn lookup() -> &'static HashMap<&'static [u8],$enum_type> { + static STORAGE: OnceLock> = OnceLock::new(); + STORAGE.get_or_init(|| { + let mut hm = HashMap::new(); + $( + hm.insert($enum_type::$variant.meta().deref().as_bytes(), $enum_type::$variant); + )* + hm + }) + } + } + lazy_meta! { $enum_type, IRI, $storage; $( @@ -336,7 +347,8 @@ vocabulary_type! { vocabulary_type! { XSD, IRI, METAXSD, [ (XSD, Boolean, true), - (XSD, NonNegativeInteger, true) + (XSD, NonNegativeInteger, true), + (XSD, String, true) ] } @@ -385,6 +397,55 @@ vocabulary_traits! { IRI } +impl Vocab { + fn lookup_table() -> &'static HashMap<&'static str, Self> { + static STORAGE: OnceLock> = OnceLock::new(); + STORAGE.get_or_init(|| { + let mut hm = HashMap::new(); + hm.extend( + Facet::all() + .into_iter() + .map(|val| (val.meta().deref(), Self::Facet(val))), + ); + hm.extend( + RDF::all() + .into_iter() + .map(|val| (val.meta().deref(), Self::RDF(val))), + ); + hm.extend( + RDFS::all() + .into_iter() + .map(|val| (val.meta().deref(), Self::RDFS(val))), + ); + hm.extend( + OWL::all() + .into_iter() + .map(|val| (val.meta().deref(), Self::OWL(val))), + ); + hm.extend( + SWRL::all() + .into_iter() + .map(|val| (val.meta().deref(), Self::SWRL(val))), + ); + hm.extend( + XSD::all() + .into_iter() + .map(|val| (val.meta().deref(), Self::XSD(val))), + ); + hm.extend( + Namespace::all() + .into_iter() + .map(|val| (val.meta().deref(), Self::Namespace(val))), + ); + hm + }) + } + + pub fn lookup(s: &str) -> Option<&Vocab> { + Self::lookup_table().get(s) + } +} + impl<'a> Meta<&'a IRI> for Vocab { fn meta(&self) -> &'a IRI { match self {