diff --git a/Cargo.toml b/Cargo.toml index e84ba659..5ca6ade6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,8 @@ default-members=[".", "horned-bin"] [workspace.dependencies] indexmap="1.0.2" -pretty_rdf="0.4.0" +##pretty_rdf={path="./pretty_rdf"} +pretty_rdf="0.5.0" rio_api="0.7.1" rio_xml="0.7.3" diff --git a/src/curie.rs b/src/curie.rs new file mode 100644 index 00000000..7fd4b3ab --- /dev/null +++ b/src/curie.rs @@ -0,0 +1 @@ +pub use curie::*; \ No newline at end of file diff --git a/src/io/owx/reader.rs b/src/io/owx/reader.rs index 025c87b5..2e99f8fa 100644 --- a/src/io/owx/reader.rs +++ b/src/io/owx/reader.rs @@ -6,13 +6,14 @@ use quick_xml::name::ResolveResult::Bound; use crate::error::*; use crate::io::ParserConfiguration; use crate::model::*; +use crate::vocab::Facet; use crate::vocab::Namespace::*; use crate::vocab::OWL2Datatype; -use crate::vocab::WithIRI; use crate::{ontology::set::SetOntology, vocab::OWL}; use std::borrow::Cow; use std::collections::BTreeSet; +use std::convert::TryFrom; use std::io::BufRead; use quick_xml::events::BytesEnd; @@ -299,7 +300,7 @@ fn error_missing_element(tag: &[u8], r: &mut Read) fn is_owl(res: &ResolveResult) -> bool { if let Bound(ns) = res { - ns.as_ref() == OWL.iri_b() + ns.as_ref() == OWL.as_bytes() } else { false } @@ -658,7 +659,7 @@ fn object_cardinality_restriction( .map_err(|_s| HornedError::invalid("Failed to parse int"))?, ope, Box::new(match vce.len() { - 0 => r.build.class(OWL::Thing.iri_str()).into(), + 0 => r.build.class(OWL::Thing.as_ref()).into(), 1 => vce.remove(0), _ => return Err(error_unexpected_tag(end_tag, r)), }), @@ -681,7 +682,7 @@ fn data_cardinality_restriction( .map_err(|_s| HornedError::invalid("Failed to parse int"))?, dp, match vdr.len() { - 0 => r.build.datatype(OWL2Datatype::RDFSLiteral.iri_str()).into(), + 0 => r.build.datatype(OWL2Datatype::Literal.as_ref()).into(), 1 => vdr.remove(0), _ => return Err(error_unexpected_tag(end_tag, r)), }, @@ -994,16 +995,15 @@ from_start! { from_start! { FacetRestriction, r, e, { - let f = get_attr_value_bytes(e, b"facet")?; - let f = f.ok_or_else( - || error_missing_attribute("facet", r) - )?; + let f = get_attr_value_bytes(e, b"facet")? + .ok_or_else(|| error_missing_attribute("facet", r))?; Ok( FacetRestriction { - f: Facet::var_b(&f) - .ok_or_else( - || error_unknown_entity("facet", &f, r))?, + f: Facet::try_from(f.as_ref()) + .map_err(|_| error_unknown_entity("facet", &f, r))?, + // .ok_or_else( + // || error_unknown_entity("facet", &f, r))?, l: from_next(r)? } ) @@ -1945,7 +1945,7 @@ pub mod test { } = cl { assert!(match dr { - DataRange::Datatype(dt) => dt.is_s(&OWL2Datatype::RDFSLiteral.iri_s()[..]), + DataRange::Datatype(dt) => dt.is_s(OWL2Datatype::Literal.as_ref()), _ => false, }); } else { diff --git a/src/io/owx/writer.rs b/src/io/owx/writer.rs index 13815c4f..fe9352ff 100644 --- a/src/io/owx/writer.rs +++ b/src/io/owx/writer.rs @@ -5,7 +5,7 @@ use crate::model::Kinded; use crate::model::*; use crate::ontology::indexed::ForIndex; use crate::vocab::Namespace::*; -use crate::{ontology::component_mapped::ComponentMappedOntology, vocab::WithIRI}; +use crate::ontology::component_mapped::ComponentMappedOntology; use quick_xml::events::BytesDecl; use quick_xml::events::BytesEnd; @@ -240,10 +240,11 @@ where // let mut elem = BytesStart::owned_name("Ontology"); let mut elem = BytesStart::new("Ontology"); - elem.push_attribute((b"xmlns" as &[u8], OWL.iri_b())); + elem.push_attribute((b"xmlns" as &[u8], OWL.as_bytes())); let id = o.i().the_ontology_id_or_default(); iri_maybe(&mut elem, "xml:base", &id.iri); + // Render XML Namespaces. for pre in m.mappings() { elem.push_attribute((format!("xmlns:{}", pre.0).as_bytes(),pre.1.as_bytes())); @@ -856,7 +857,7 @@ render! { let mut open = BytesStart::new("FacetRestriction"); // Got the facet IRI from vocab open.push_attribute(("facet", - &self.f.iri_s()[..])); + self.f.as_ref())); self.l.within_tag(w, m, open)?; Ok(()) diff --git a/src/io/rdf/reader.rs b/src/io/rdf/reader.rs index f54cafa8..2d25e144 100644 --- a/src/io/rdf/reader.rs +++ b/src/io/rdf/reader.rs @@ -4,13 +4,12 @@ use rio_api::{ }; use Term::*; -use crate::{error::HornedError, io::ParserConfiguration}; +use crate::{error::HornedError, io::ParserConfiguration, vocab::Facet}; use crate::model::*; use crate::{model::Literal, ontology::component_mapped::ComponentMappedOntology}; use crate::ontology::indexed::ForIndex; use crate::vocab::is_annotation_builtin; -use crate::vocab::WithIRI; use crate::vocab::OWL as VOWL; use crate::vocab::OWL2Datatype; use crate::vocab::RDF as VRDF; @@ -194,37 +193,53 @@ impl From> for OrTerm { } } -fn vocab_lookup() -> HashMap<&'static str, Term> { - let mut m = HashMap::default(); +/// Creates a lookup [HashMap] for OWL, RDF, RDFS and Facet vocabularies. +fn vocab_lookup() -> HashMap> { + // Preallocate capacity, as we know at compile-time how many elements will + // be stored in the hashmaps. + // 87 = #OWL variants - 1 + #RDF variants + #RDFS variants + #Facet variants + let mut lookup_map = HashMap::with_capacity(87); - for v in VOWL::all() { - match v { - // Skip the builtin properties or we have to treat them separately - VOWL::TopDataProperty => None, - _ => m.insert(v.iri_s().as_str(), Term::OWL(v)), - }; - } + lookup_map.extend( + VOWL::all() + .into_iter() + .filter_map(|variant| match variant { + // Skip the builtin properties or we have to treat them separately + VOWL::TopDataProperty => None, // | + // VOWL::TopObjectProperty | + // VOWL::Thing | + // VOWL::Nothing => None, + _ => Some((variant.underlying(), Term::OWL(variant))) + }) + ); - for v in VRDFS::all() { - m.insert(v.iri_s().as_str(), Term::RDFS(v)); - } + lookup_map.extend( + VRDFS::all() + .into_iter() + .map(|variant| (variant.underlying(), Term::RDFS(variant))) + ); - for v in VRDF::all() { - m.insert(v.iri_s().as_str(), Term::RDF(v)); - } + lookup_map.extend( + VRDF::all() + .into_iter() + .map(|variant| (variant.underlying(), Term::RDF(variant))) + ); - for v in Facet::all() { - m.insert(v.iri_s().as_str(), Term::FacetTerm(v)); - } - m + lookup_map.extend( + Facet::all() + .into_iter() + .map(|variant| (variant.underlying(), Term::FacetTerm(variant))) + ); + + lookup_map } fn to_term_nn<'a, A: ForIRI>( nn: &'a NamedNode, - m: &HashMap<&str, Term>, + m: &HashMap>, b: &Build, ) -> Term { - if let Some(term) = m.get(&nn.iri) { + if let Some(term) = m.get(nn.iri) { return term.clone(); } Term::Iri(b.iri(nn.iri)) @@ -261,7 +276,7 @@ fn to_term_lt<'a, A: ForIRI>(lt: &'a rio_api::model::Literal, b: &Build) -> T fn to_term_nnb<'a, A: ForIRI>( nnb: &'a Subject, - m: &HashMap<&str, Term>, + m: &HashMap>, b: &Build, ) -> Term { match nnb { @@ -271,7 +286,7 @@ fn to_term_nnb<'a, A: ForIRI>( } } -fn to_term<'a, A: ForIRI>(t: &'a RioTerm, m: &HashMap<&str, Term>, b: &Build) -> Term { +fn to_term<'a, A: ForIRI>(t: &'a RioTerm, m: &HashMap>, b: &Build) -> Term { match t { rio_api::model::Term::NamedNode(iri) => to_term_nn(iri, m, b), rio_api::model::Term::BlankNode(id) => to_term_bn(id), @@ -642,11 +657,11 @@ impl<'a, A: ForIRI, AA: ForIndex> OntologyParser<'a, A, AA> { // We assume that anything passed to here is an // annotation built in type [s, RDFS(rdfs), b] => { - let iri = self.b.iri(rdfs.iri_str()); + let iri = self.b.iri(rdfs.as_ref()); self.annotation(&[s.clone(), Term::Iri(iri), b.clone()]) } [s, OWL(owl), b] => { - let iri = self.b.iri(owl.iri_str()); + let iri = self.b.iri(owl.as_ref()); self.annotation(&[s.clone(), Term::Iri(iri), b.clone()]) } [_, Iri(p), ob @ Term::Literal(_)] => Annotation { @@ -1017,7 +1032,7 @@ impl<'a, A: ForIRI, AA: ForIndex> OntologyParser<'a, A, AA> { ) -> Option> { match term { Term::OWL(vowl) => { - let iri = self.b.iri(vowl.iri_str()); + let iri = self.b.iri(vowl.as_ref()); self.find_property_kind(&Term::Iri(iri), ic) } Term::Iri(iri) => match self.find_declaration_kind(iri, ic) { @@ -1206,7 +1221,7 @@ impl<'a, A: ForIRI, AA: ForIndex> OntologyParser<'a, A, AA> { { n:self.fetch_u32(literal)?, ope: ope, - bce: self.b.class(VOWL::Thing.iri_str()).into() + bce: self.b.class(VOWL::Thing).into() } }, PropertyExpression::DataProperty(dp) => { @@ -1214,7 +1229,7 @@ impl<'a, A: ForIRI, AA: ForIndex> OntologyParser<'a, A, AA> { { n:self.fetch_u32(literal)?, dp: dp, - dr: self.b.datatype(OWL2Datatype::RDFSLiteral.iri_str()).into(), + dr: self.b.datatype(OWL2Datatype::Literal).into(), } } _ => { @@ -1246,7 +1261,7 @@ impl<'a, A: ForIRI, AA: ForIndex> OntologyParser<'a, A, AA> { { n:self.fetch_u32(literal)?, ope: pr.into(), - bce: self.b.class(VOWL::Thing.iri_str()).into() + bce: self.b.class(VOWL::Thing).into() } } } @@ -1273,7 +1288,7 @@ impl<'a, A: ForIRI, AA: ForIndex> OntologyParser<'a, A, AA> { { n:self.fetch_u32(literal)?, ope: pr.into(), - bce: self.b.class(VOWL::Thing.iri_str()).into() + bce: self.b.class(VOWL::Thing).into() } } } diff --git a/src/io/rdf/writer.rs b/src/io/rdf/writer.rs index b8cfafbe..587f04fd 100644 --- a/src/io/rdf/writer.rs +++ b/src/io/rdf/writer.rs @@ -3,7 +3,7 @@ use crate::{ error::HornedError, model::*, ontology::component_mapped::ComponentMappedOntology, - vocab::{is_thing, Vocab, WithIRI, OWL, RDF, RDFS, XSD}, + vocab::{Vocab, OWL, RDF, RDFS, XSD}, }; use crate::ontology::indexed::ForIndex; @@ -81,7 +81,7 @@ impl NodeGenerator { /// Return an cached version of PNamedNode value. fn cache_rc>(&mut self, v: V) -> A { - let voc: &str = v.into().iri_s(); + let voc: &str = &v.into(); if let Some(rc) = self.b.get(voc) { return rc.clone(); } @@ -1118,7 +1118,7 @@ fn obj_cardinality, W: Write>( ); if let ClassExpression::Class(ref cl) = *ce { - if is_thing(&cl.0) { + if cl.is_thing() { triples!(f, bn.clone(), unqual, node_n); return Ok(bn); } diff --git a/src/lib.rs b/src/lib.rs index ac5405a2..9600017e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ extern crate quick_xml; pub mod adaptor; pub mod collection; +pub mod curie; pub mod error; pub mod io; pub mod model; diff --git a/src/model.rs b/src/model.rs index d2a538f1..566024ad 100644 --- a/src/model.rs +++ b/src/model.rs @@ -102,6 +102,8 @@ use std::ops::Deref; use std::rc::Rc; use std::sync::Arc; +use crate::vocab::Facet; + /// An /// [IRI](https://en.wikipedia.org/wiki/Internationalized_Resource_Identifier) /// is an internationalized version of an URI/URL. @@ -531,6 +533,17 @@ named! { NamedIndividual } +impl Class { + + pub fn is_thing(&self) -> bool { + self.0.as_ref() == crate::vocab::OWL::Thing.as_ref() + } + + pub fn is_nothing(&self) -> bool { + self.0.as_ref() == crate::vocab::OWL::Nothing.as_ref() + } +} + #[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)] pub struct AnonymousIndividual(pub A); @@ -1507,21 +1520,6 @@ pub struct FacetRestriction { pub l: Literal, } -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Facet { - Length, - MinLength, - MaxLength, - Pattern, - MinInclusive, - MinExclusive, - MaxInclusive, - MaxExclusive, - TotalDigits, - FractionDigits, - LangRange, -} - #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum DataRange { Datatype(Datatype), diff --git a/src/ontology/declaration_mapped.rs b/src/ontology/declaration_mapped.rs index 5c63ecc5..0a68c24d 100644 --- a/src/ontology/declaration_mapped.rs +++ b/src/ontology/declaration_mapped.rs @@ -141,7 +141,7 @@ mod test { use super::DeclarationMappedIndex; use crate::model::{AnnotatedComponent, Build, NamedEntity, NamedEntityKind, RcStr}; use crate::ontology::indexed::OntologyIndex; - use crate::vocab::{WithIRI, OWL}; + use crate::vocab::OWL; fn stuff() -> ( AnnotatedComponent, AnnotatedComponent, @@ -198,7 +198,7 @@ mod test { let d = DeclarationMappedIndex::new_rc(); let b = Build::new_rc(); assert_eq!( - d.declaration_kind(&b.iri(OWL::TopDataProperty.iri_str())), + d.declaration_kind(&b.iri(OWL::TopDataProperty.as_ref())), Some(NamedEntityKind::DataProperty) ); } diff --git a/src/visitor.rs b/src/visitor.rs index 5ca4a68e..1c61a0d6 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -1,5 +1,6 @@ use crate::model::*; use crate::ontology::set::SetOntology; +use crate::vocab::Facet; use std::collections::BTreeSet; use std::marker::PhantomData; diff --git a/src/vocab.rs b/src/vocab.rs index 9336afc2..277de377 100644 --- a/src/vocab.rs +++ b/src/vocab.rs @@ -1,300 +1,262 @@ -//! Standard Vocabularies for OWL -use self::Namespace::*; +//! Core RDF vocabularies used in the OWL2 RDF format. use enum_meta::*; use crate::error::invalid; use crate::error::HornedError; use crate::model::Build; -use crate::model::Facet; use crate::model::ForIRI; use crate::model::NamedEntity; use crate::model::NamedEntityKind; use crate::model::IRI; use std::borrow::Borrow; +use std::convert::TryFrom; +use std::str::FromStr; + +macro_rules! vocabulary_traits { + ($($enum_type:ident),+; $return_type:ty + ) => { + + $( + impl TryFrom<&[u8]> for $enum_type { + type Error = HornedError; + + fn try_from(value: &[u8]) -> Result { + $enum_type::all() + .into_iter() + .find_map(|variant| { + if variant.as_bytes() == value { + Some(variant) + } else { + None + } + }).ok_or_else(|| invalid!("Unknown {} variant: {:?}", stringify!{$enum_type}, value)) + } + } + impl std::str::FromStr for $enum_type { + type Err = HornedError; -pub trait WithIRI<'a>: Meta<&'a IRIString> { - /// Return a string representation of the IRI associated with this - /// entity. - fn iri_s(&self) -> &'a String { - &self.meta().0 - } + fn from_str(s: &str) -> Result { + $enum_type::try_from(s.as_bytes()) + } + } - fn iri_b(&self) -> &'a [u8] { - self.meta().0.as_bytes() - } + impl TryFrom<&str> for $enum_type { + type Error = HornedError; - fn iri_str(&self) -> &'a str { - &self.meta().0[..] - } + fn try_from(value: &str) -> Result { + $enum_type::from_str(value) + } + } - fn var_s(tag: &'a str) -> Option { - Self::var_b(tag.as_bytes()) - } + impl std::ops::Deref for $enum_type { + type Target = $return_type; - fn var_b(tag: &'a [u8]) -> Option { - for v in Self::all() { - if tag == v.iri_b() { - return Some(v); + fn deref(&self) -> &Self::Target { + self.meta() + } } - } - None - } + + impl Borrow for $enum_type { + fn borrow(&self) -> &str { + self.meta().as_ref() + } + } + )+ + }; } -pub struct IRIString(String); +macro_rules! vocabulary_type { + ($(#[$attr:meta])* $enum_type:ident, $return_type:ty, $storage:ident, [$(($ns:ident, $variant:ident, $first_lowercase:expr)),*]) => { -impl<'a, T> WithIRI<'a> for T where T: Meta<&'a IRIString> {} + $(#[$attr]) * + #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] + pub enum $enum_type { + $( + $variant, + )* + } -fn to_meta(s: &str) -> IRIString { - IRIString(s.to_string()) -} + impl $enum_type { + fn get_iri(self) -> IRI { + + let mut iri_str = String::new(); + $( + iri_str.push_str(Namespace::$ns.as_ref()); + )? + + match self { + $( + $enum_type::$variant => { + let mut iri_str = String::from(Namespace::$ns.as_ref()); + let mut variant_str = String::from(stringify!($variant)); + if $first_lowercase { + let tail = variant_str.split_off(1); + variant_str.make_ascii_lowercase(); + variant_str.push_str(&tail); + } + iri_str.push_str(&variant_str); + IRI(iri_str) + } + )*, + } + } + } + + lazy_meta! { + $enum_type, IRI, $storage; + $( + $variant, $enum_type::get_iri($enum_type::$variant); + )* + + } -fn extend<'a, I>(i: I, s: &'a str) -> IRIString -where - I: WithIRI<'a>, -{ - to_meta(&format!("{}{}", i.iri_s(), s)) + vocabulary_traits! { $enum_type; $return_type } + } } +/// [Namespaces](https://www.w3.org/TR/2004/REC-owl-guide-20040210/#Namespaces) +/// that are typically used within an OWL document. #[derive(Debug, Eq, PartialEq)] pub enum Namespace { + /// Ontology Web Language OWL, + /// Resource Description Framework RDF, + /// RDF Schema RDFS, + /// XML Schema datatype XSD, } -lazy_meta! { - Namespace, IRIString, METANS; - OWL, to_meta("http://www.w3.org/2002/07/owl#"); - RDF, to_meta("http://www.w3.org/1999/02/22-rdf-syntax-ns#"); - RDFS, to_meta("http://www.w3.org/2000/01/rdf-schema#"); - XSD, to_meta("http://www.w3.org/2001/XMLSchema#"); -} - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum RDF { - First, - List, - Nil, - Rest, - Type, +vocabulary_traits! { + Namespace; + IRI } lazy_meta! { - RDF, IRIString, METARDF; - First, extend(RDF, "first"); - List, extend(RDF, "List"); - Nil, extend(RDF, "nil"); - Rest, extend(RDF, "rest"); - Type, extend(RDF, "type"); -} - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum RDFS { - Comment, - Datatype, - Domain, - IsDefinedBy, - Label, - Range, - SeeAlso, - SubClassOf, - SubPropertyOf, + Namespace, IRI, METANS; + OWL, IRI(String::from("http://www.w3.org/2002/07/owl#")); + RDF, IRI(String::from("http://www.w3.org/1999/02/22-rdf-syntax-ns#")); + RDFS, IRI(String::from("http://www.w3.org/2000/01/rdf-schema#")); + XSD, IRI(String::from("http://www.w3.org/2001/XMLSchema#")); +} + +vocabulary_type! { + /// RDF Collections vocabulary. + RDF, IRI, METARDF, [ + (RDF, List, false), + (RDF, First, true), + (RDF, Nil, true), + (RDF, Rest, true), + (RDF, Type, true) + ] +} + +vocabulary_type! { + RDFS, IRI, METARDFS, [ + (RDFS, Comment, true), + (RDFS, Datatype, false), + (RDFS, Domain, true), + (RDFS, IsDefinedBy, true), + (RDFS, Label, true), + (RDFS, Range, true), + (RDFS, SeeAlso, true), + (RDFS, SubClassOf, true), + (RDFS, SubPropertyOf, true) + ] } impl RDFS { pub fn is_builtin(&self) -> bool { - matches!{ - self, - RDFS::Label | RDFS::Comment | RDFS::SeeAlso | RDFS::IsDefinedBy + match &self { + RDFS::Label | RDFS::Comment | RDFS::SeeAlso | RDFS::IsDefinedBy => true, + _ => false, } } } -lazy_meta! { - RDFS, IRIString, METARDFS; - Comment, extend(RDFS, "comment"); - Datatype, extend(RDFS, "Datatype"); - Domain, extend(RDFS, "domain"); - IsDefinedBy, extend(RDFS, "isDefinedBy"); - Label, extend(RDFS, "label"); - Range, extend(RDFS, "range"); - SeeAlso, extend(RDFS, "seeAlso"); - SubClassOf, extend(RDFS, "subClassOf"); - SubPropertyOf, extend(RDFS, "subPropertyOf"); -} - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum OWL { - AllDifferent, - AllDisjointProperties, - AllValuesFrom, - AnnotatedProperty, - AnnotatedSource, - AnnotatedTarget, - AnnotationProperty, - AssertionProperty, - AsymmetricProperty, - Axiom, - Cardinality, - Class, - ComplementOf, - DatatypeComplementOf, - DatatypeProperty, - DifferentFrom, - DisjointUnionOf, - DisjointWith, - DistinctMembers, - EquivalentClass, - EquivalentProperty, - FunctionalProperty, - HasKey, - HasSelf, - HasValue, - Imports, - IntersectionOf, - InverseFunctionalProperty, - InverseOf, - IrreflexiveProperty, - MaxCardinality, - MaxQualifiedCardinality, - Members, - MinCardinality, - MinQualifiedCardinality, - NamedIndividual, - NegativePropertyAssertion, - Nothing, - ObjectProperty, - OnClass, - OnDataRange, - OnDatatype, - OneOf, - OnProperty, - Ontology, - QualifiedCardinality, - PropertyChainAxiom, - PropertyDisjointWith, - ReflexiveProperty, - Restriction, - SameAs, - SourceIndividual, - SomeValuesFrom, - SymmetricProperty, - TargetIndividual, - TargetValue, - TopDataProperty, - TopObjectProperty, - Thing, - TransitiveProperty, - UnionOf, - VersionIRI, - WithRestrictions, -} - -lazy_meta! { - OWL, IRIString, METAOWL; - - AllDifferent, extend(OWL, "AllDifferent"); - AllDisjointProperties, extend(OWL, "AllDisjointProperties"); - AllValuesFrom, extend(OWL, "allValuesFrom"); - AnnotatedProperty, extend(OWL, "annotatedProperty"); - AnnotatedSource, extend(OWL, "annotatedSource"); - AnnotatedTarget, extend(OWL, "annotatedTarget"); - AnnotationProperty, extend(OWL, "AnnotationProperty"); - AssertionProperty, extend(OWL, "assertionProperty"); - AsymmetricProperty, extend(OWL, "AsymmetricProperty"); - Axiom, extend(OWL, "Axiom"); - Class, extend(OWL, "Class"); - ComplementOf, extend(OWL, "complementOf"); - DatatypeComplementOf, extend(OWL, "datatypeComplementOf"); - DatatypeProperty, extend(OWL, "DatatypeProperty"); - DifferentFrom, extend(OWL, "differentFrom"); - DisjointUnionOf, extend(OWL, "disjointUnionOf"); - DisjointWith, extend(OWL, "disjointWith"); - DistinctMembers, extend(OWL, "distinctMembers"); - Cardinality, extend(OWL, "cardinality"); - EquivalentClass, extend(OWL, "equivalentClass"); - EquivalentProperty, extend(OWL, "equivalentProperty"); - FunctionalProperty, extend(OWL, "FunctionalProperty"); - Imports, extend(OWL, "imports"); - IntersectionOf, extend(OWL, "intersectionOf"); - InverseFunctionalProperty, extend(OWL, "InverseFunctionalProperty"); - InverseOf, extend(OWL, "inverseOf"); - IrreflexiveProperty, extend(OWL, "IrreflexiveProperty"); - HasKey, extend(OWL, "hasKey"); - HasSelf, extend(OWL, "hasSelf"); - HasValue, extend(OWL, "hasValue"); - MaxCardinality, extend(OWL, "maxCardinality"); - MaxQualifiedCardinality, extend(OWL, "maxQualifiedCardinality"); - Members, extend(OWL, "members"); - MinCardinality, extend(OWL, "minCardinality"); - MinQualifiedCardinality, extend(OWL, "minQualifiedCardinality"); - NamedIndividual, extend(OWL, "NamedIndividual"); - NegativePropertyAssertion, extend(OWL, "NegativePropertyAssertion"); - Nothing, extend(OWL, "Nothing"); - ObjectProperty, extend(OWL, "ObjectProperty"); - OnClass, extend(OWL, "onClass"); - OnDataRange, extend(OWL, "onDataRange"); - OnDatatype, extend(OWL, "onDatatype"); - OneOf, extend(OWL, "oneOf"); - OnProperty, extend(OWL, "onProperty"); - Ontology, extend(OWL, "Ontology"); - PropertyChainAxiom, extend(OWL, "propertyChainAxiom"); - PropertyDisjointWith, extend(OWL, "propertyDisjointWith"); - QualifiedCardinality, extend(OWL, "qualifiedCardinality"); - ReflexiveProperty, extend(OWL, "ReflexiveProperty"); - Restriction, extend(OWL, "Restriction"); - SameAs, extend(OWL, "sameAs"); - SourceIndividual, extend(OWL, "sourceIndividual"); - SomeValuesFrom, extend(OWL, "someValuesFrom"); - SymmetricProperty, extend(OWL, "SymmetricProperty"); - TargetIndividual, extend(OWL, "targetIndividual"); - TargetValue, extend(OWL, "targetValue"); - Thing, extend(OWL, "Thing"); - TopDataProperty, extend(OWL, "topDataProperty"); - TopObjectProperty, extend(OWL, "topObjectProperty"); - TransitiveProperty, extend(OWL, "TransitiveProperty"); - UnionOf, extend(OWL, "unionOf"); - VersionIRI, extend(OWL, "versionIRI"); - WithRestrictions, extend(OWL, "withRestrictions"); -} - -pub fn is_thing(iri: &IRI) -> bool { - iri.as_ref() == OWL::Thing.iri_s() -} - -pub fn is_nothing(iri: &IRI) -> bool { - iri.as_ref() == OWL::Nothing.iri_s() -} - +vocabulary_type! { + OWL, IRI, METAOWL, [ + (OWL, AllDifferent, false), + (OWL, AllDisjointProperties, false), + (OWL, AllValuesFrom, true), + (OWL, AnnotatedProperty, true), + (OWL, AnnotatedSource, true), + (OWL, AnnotatedTarget, true), + (OWL, AnnotationProperty, false), + (OWL, AssertionProperty, true), + (OWL, AsymmetricProperty, false), + (OWL, Axiom, false), + (OWL, Cardinality, true), + (OWL, Class, false), + (OWL, ComplementOf, true), + (OWL, DatatypeComplementOf, true), + (OWL, DatatypeProperty, false), + (OWL, DifferentFrom, true), + (OWL, DisjointUnionOf, true), + (OWL, DisjointWith, true), + (OWL, DistinctMembers, true), + (OWL, EquivalentClass, true), + (OWL, EquivalentProperty, true), + (OWL, FunctionalProperty, false), + (OWL, HasKey, true), + (OWL, HasSelf, true), + (OWL, HasValue, true), + (OWL, Imports, true), + (OWL, IntersectionOf, true), + (OWL, InverseFunctionalProperty, false), + (OWL, InverseOf, true), + (OWL, IrreflexiveProperty, false), + (OWL, MaxCardinality, true), + (OWL, MaxQualifiedCardinality, true), + (OWL, Members, true), + (OWL, MinCardinality, true), + (OWL, MinQualifiedCardinality, true), + (OWL, NamedIndividual, false), + (OWL, NegativePropertyAssertion, false), + (OWL, Nothing, false), + (OWL, ObjectProperty, false), + (OWL, OnClass, true), + (OWL, OnDataRange, true), + (OWL, OnDatatype, true), + (OWL, OneOf, true), + (OWL, OnProperty, true), + (OWL, Ontology, false), + (OWL, QualifiedCardinality, true), + (OWL, PropertyChainAxiom, true), + (OWL, PropertyDisjointWith, true), + (OWL, ReflexiveProperty, false), + (OWL, Restriction, false), + (OWL, SameAs, true), + (OWL, SourceIndividual, true), + (OWL, SomeValuesFrom, true), + (OWL, SymmetricProperty, false), + (OWL, TargetIndividual, true), + (OWL, TargetValue, true), + (OWL, TopDataProperty, true), + (OWL, TopObjectProperty, true), + (OWL, Thing, false), + (OWL, TransitiveProperty, false), + (OWL, UnionOf, true), + (OWL, VersionIRI, true), + (OWL, WithRestrictions, true) + ] +} + +/// Returns a [NamedEntityKind] if the IRI points to a built-in entity, otherwise [None]. pub fn to_built_in_entity(iri: &IRI) -> Option { let ir = iri.as_ref(); match ir { - _ if ir == OWL::TopDataProperty.iri_s() => Some(NamedEntityKind::DataProperty), - _ if ir == OWL::TopObjectProperty.iri_s() => Some(NamedEntityKind::ObjectProperty), + _ if ir == OWL::TopDataProperty.as_ref() => Some(NamedEntityKind::DataProperty), + _ if ir == OWL::TopObjectProperty.as_ref() => Some(NamedEntityKind::ObjectProperty), + _ if ir == OWL::Thing.as_ref() => Some(NamedEntityKind::Class), + _ if ir == OWL::Nothing.as_ref() => Some(NamedEntityKind::Class), _ => None, } } -#[test] -fn meta_testing() { - assert_eq!("http://www.w3.org/2002/07/owl#", OWL.iri_s()); - assert_eq!(b"http://www.w3.org/2002/07/owl#", OWL.iri_b()); - - assert_eq!( - Namespace::var_s("http://www.w3.org/2002/07/owl#").unwrap(), - OWL - ); - - assert_eq!( - Namespace::var_b(b"http://www.w3.org/2002/07/owl#").unwrap(), - OWL - ); -} - pub fn entity_for_iri>( type_iri: S, entity_iri: S, @@ -306,155 +268,74 @@ pub fn entity_for_iri>( return Ok(b.datatype(entity_iri).into()); } - if type_iri.borrow().len() < 30 { - return Err(invalid!( - "IRI is not for a type of entity:{:?}", + match &type_iri.borrow().strip_prefix(Namespace::OWL.as_ref()) { + Some("Class") => Ok(b.class(entity_iri).into()), + Some("ObjectProperty") => Ok(b.object_property(entity_iri).into()), + Some("DatatypeProperty") => Ok(b.data_property(entity_iri).into()), + Some("AnnotationProperty") => Ok(b.annotation_property(entity_iri).into()), + Some("NamedIndividual") => Ok(b.named_individual(entity_iri).into()), + _ => Err(invalid!( + "IRI is not a type of entity:{:?}", type_iri.borrow() - )); + )), } - - Ok(match &type_iri.borrow()[30..] { - "Class" => b.class(entity_iri).into(), - "ObjectProperty" => b.object_property(entity_iri).into(), - "DatatypeProperty" => b.data_property(entity_iri).into(), - "AnnotationProperty" => b.annotation_property(entity_iri).into(), - "NamedIndividual" => b.named_individual(entity_iri).into(), - _ => { - return Err(invalid!( - "IRI is not a type of entity:{:?}", - type_iri.borrow() - )); - } - }) } -#[test] -pub fn test_entity_for_iri() { - let b = Build::new_rc(); - - assert!(entity_for_iri( - "http://www.w3.org/2002/07/owl#Class", - "http://www.example.com", - &b - ) - .is_ok()); - assert!(entity_for_iri( - "http://www.w3.org/2002/07/owl#Fred", - "http://www.example.com", - &b - ) - .is_err()); +vocabulary_type! { + OWL2Datatype, + IRI, + METAOWL2DATATYPE, + [(RDFS, Literal, false)] } -pub enum OWL2Datatype { - RDFSLiteral, +vocabulary_type! { + AnnotationBuiltIn, IRI, METAANNOTATIONBUILTIN, [ + (RDFS, Label, true), + (RDFS, Comment, true), + (RDFS, SeeAlso, true), + (RDFS, IsDefinedBy, true), + (OWL, Deprecated, true), + (OWL, VersionInfo, true), + (OWL, PriorVersion, true), + (OWL, BackwardCompatibleWith, true), + (OWL, IncompatibleWith, true) + ] } -lazy_meta! { - OWL2Datatype, IRIString, METAOWL2DATATYPE; - RDFSLiteral, extend(RDFS, "Literal") +#[inline] +pub fn is_annotation_builtin>(iri: A) -> bool { + AnnotationBuiltIn::from_str(iri.as_ref()).is_ok() + // AnnotationBuiltIn::all() + // .iter() + // .any(|item| item.as_ref() == iri.as_ref()) } -pub enum AnnotationBuiltIn { - LABEL, - COMMENT, - SEEALSO, - ISDEFINEDBY, - DEPRECATED, - VERSIONINFO, - PRIORVERSION, - BACKWARDCOMPATIBLEWITH, - INCOMPATIBLEWITH, +vocabulary_type! { + Facet, IRI, METAFACET, [ + (XSD, Length, true), + (XSD, MinLength, true), + (XSD, MaxLength, true), + (XSD, Pattern, true), + (XSD, MinInclusive, true), + (XSD, MinExclusive, true), + (XSD, MaxInclusive, true), + (XSD, MaxExclusive, true), + (XSD, TotalDigits, true), + (XSD, FractionDigits, true), + (RDF, LangRange, true) + ] } -lazy_meta! { - AnnotationBuiltIn, IRIString, METAANNOTATIONBUILTIN; - LABEL, extend(RDFS, "label"); - COMMENT, extend(RDFS, "comment"); - SEEALSO, extend(RDFS, "seeAlso"); - ISDEFINEDBY, extend(RDFS, "isDefinedBy"); - DEPRECATED, extend(OWL, "deprecated"); - VERSIONINFO, extend(OWL, "versionInfo"); - PRIORVERSION, extend(OWL, "priorVersion"); - BACKWARDCOMPATIBLEWITH, extend(OWL, "backwardCompatibleWith"); - INCOMPATIBLEWITH, extend(OWL, "incompatibleWith"); +vocabulary_type! { + XSD, IRI, METAXSD, [ + (XSD, Boolean, true), + (XSD, NonNegativeInteger, true) + ] } -pub fn is_annotation_builtin>(iri: A) -> bool { - for meta in AnnotationBuiltIn::all() { - if meta.iri_str() == iri.as_ref() { - return true; - } - } - false -} - -#[test] -fn annotation_builtin() { - assert!(is_annotation_builtin( - &"http://www.w3.org/2002/07/owl#deprecated".to_string() - )); - assert!(is_annotation_builtin( - &"http://www.w3.org/2000/01/rdf-schema#comment".to_string() - )); - assert!(!is_annotation_builtin( - &"http://www.w3.org/2002/07/owl#fred".to_string() - )); -} - -lazy_meta! { - Facet, IRIString, METAFACET; - Length, extend(XSD, "length"); - MinLength, extend(XSD, "minLength"); - MaxLength, extend(XSD, "maxLength"); - Pattern, extend(XSD, "pattern"); - MinInclusive, extend(XSD, "minInclusive"); - MinExclusive, extend(XSD, "minExclusive"); - MaxInclusive, extend(XSD, "maxInclusive"); - MaxExclusive, extend(XSD, "maxExclusive"); - TotalDigits, extend(XSD, "totalDigits"); - FractionDigits, extend(XSD, "fractionDigits"); - LangRange, extend(RDF, "langRange"); -} - -#[test] -fn facet_meta() { - assert_eq!( - Facet::MinLength.iri_s(), - "http://www.w3.org/2001/XMLSchema#minLength" - ); - - assert_eq!( - Facet::Pattern.iri_s(), - "http://www.w3.org/2001/XMLSchema#pattern" - ); - - assert_eq!( - Facet::var_s("http://www.w3.org/2001/XMLSchema#pattern").unwrap(), - Facet::Pattern - ); - - assert_eq!( - Facet::var_b(b"http://www.w3.org/2001/XMLSchema#minExclusive").unwrap(), - Facet::MinExclusive - ); -} - -pub enum XSD { - Boolean, - NonNegativeInteger, -} - -pub fn is_xsd_datatype>(iri:A) -> bool { - //TODO. This is over-simplistic - iri.as_ref().starts_with("http://www.w3.org/2001/XMLSchema") -} - - -lazy_meta! { - XSD, IRIString, METAXSD; - Boolean, extend(XSD, "boolean"); - NonNegativeInteger, extend(XSD, "nonNegativeInteger") +pub fn is_xsd_datatype>(iri: A) -> bool { + // This only checks that the IRI starts with the XSD namespace. + iri.as_ref().starts_with(Namespace::XSD.as_ref()) } pub enum Vocab { @@ -466,8 +347,13 @@ pub enum Vocab { Namespace(Namespace), } -impl<'a> Meta<&'a IRIString> for Vocab { - fn meta(&self) -> &'a IRIString { +vocabulary_traits! { + Vocab; + IRI +} + +impl<'a> Meta<&'a IRI> for Vocab { + fn meta(&self) -> &'a IRI { match self { Self::Facet(facet) => facet.meta(), Self::RDF(rdf) => rdf.meta(), @@ -479,7 +365,22 @@ impl<'a> Meta<&'a IRIString> for Vocab { } fn all() -> Vec { - todo!() + let facet_all = Facet::all().into_iter().map(|variant| Self::Facet(variant)); + let rdf_all = RDF::all().into_iter().map(|variant| Self::RDF(variant)); + let rdfs_all = RDFS::all().into_iter().map(|variant| Self::RDFS(variant)); + let owl_all = OWL::all().into_iter().map(|variant| Self::OWL(variant)); + let xsd_all = XSD::all().into_iter().map(|variant| Self::XSD(variant)); + let ns_all = Namespace::all() + .into_iter() + .map(|variant| Self::Namespace(variant)); + + facet_all + .chain(rdf_all) + .chain(rdfs_all) + .chain(owl_all) + .chain(xsd_all) + .chain(ns_all) + .collect() } } @@ -518,3 +419,425 @@ impl From for Vocab { Self::XSD(xsd) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_meta_rdf() { + assert_eq!( + RDF::First.as_ref(), + "http://www.w3.org/1999/02/22-rdf-syntax-ns#first" + ); + assert_eq!( + RDF::List.as_ref(), + "http://www.w3.org/1999/02/22-rdf-syntax-ns#List" + ); + assert_eq!( + RDF::Nil.as_ref(), + "http://www.w3.org/1999/02/22-rdf-syntax-ns#nil" + ); + assert_eq!( + RDF::Rest.as_ref(), + "http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" + ); + assert_eq!( + RDF::Type.as_ref(), + "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" + ); + } + + #[test] + fn test_meta_rdfs() { + assert_eq!( + RDFS::Comment.as_ref(), + "http://www.w3.org/2000/01/rdf-schema#comment" + ); + assert_eq!( + RDFS::Datatype.as_ref(), + "http://www.w3.org/2000/01/rdf-schema#Datatype" + ); + assert_eq!( + RDFS::Domain.as_ref(), + "http://www.w3.org/2000/01/rdf-schema#domain" + ); + assert_eq!( + RDFS::IsDefinedBy.as_ref(), + "http://www.w3.org/2000/01/rdf-schema#isDefinedBy" + ); + assert_eq!( + RDFS::Label.as_ref(), + "http://www.w3.org/2000/01/rdf-schema#label" + ); + assert_eq!( + RDFS::Range.as_ref(), + "http://www.w3.org/2000/01/rdf-schema#range" + ); + assert_eq!( + RDFS::SeeAlso.as_ref(), + "http://www.w3.org/2000/01/rdf-schema#seeAlso" + ); + assert_eq!( + RDFS::SubClassOf.as_ref(), + "http://www.w3.org/2000/01/rdf-schema#subClassOf" + ); + assert_eq!( + RDFS::SubPropertyOf.as_ref(), + "http://www.w3.org/2000/01/rdf-schema#subPropertyOf" + ); + } + + #[test] + fn test_meta_owl() { + assert_eq!( + OWL::AllDifferent.as_ref(), + "http://www.w3.org/2002/07/owl#AllDifferent" + ); + assert_eq!( + OWL::AllDisjointProperties.as_ref(), + "http://www.w3.org/2002/07/owl#AllDisjointProperties" + ); + assert_eq!( + OWL::AllValuesFrom.as_ref(), + "http://www.w3.org/2002/07/owl#allValuesFrom" + ); + assert_eq!( + OWL::AnnotatedProperty.as_ref(), + "http://www.w3.org/2002/07/owl#annotatedProperty" + ); + assert_eq!( + OWL::AnnotatedSource.as_ref(), + "http://www.w3.org/2002/07/owl#annotatedSource" + ); + assert_eq!( + OWL::AnnotatedTarget.as_ref(), + "http://www.w3.org/2002/07/owl#annotatedTarget" + ); + assert_eq!( + OWL::AnnotationProperty.as_ref(), + "http://www.w3.org/2002/07/owl#AnnotationProperty" + ); + assert_eq!( + OWL::AssertionProperty.as_ref(), + "http://www.w3.org/2002/07/owl#assertionProperty" + ); + assert_eq!( + OWL::AsymmetricProperty.as_ref(), + "http://www.w3.org/2002/07/owl#AsymmetricProperty" + ); + assert_eq!(OWL::Axiom.as_ref(), "http://www.w3.org/2002/07/owl#Axiom"); + assert_eq!( + OWL::Cardinality.as_ref(), + "http://www.w3.org/2002/07/owl#cardinality" + ); + assert_eq!(OWL::Class.as_ref(), "http://www.w3.org/2002/07/owl#Class"); + assert_eq!( + OWL::ComplementOf.as_ref(), + "http://www.w3.org/2002/07/owl#complementOf" + ); + assert_eq!( + OWL::DatatypeComplementOf.as_ref(), + "http://www.w3.org/2002/07/owl#datatypeComplementOf" + ); + assert_eq!( + OWL::DatatypeProperty.as_ref(), + "http://www.w3.org/2002/07/owl#DatatypeProperty" + ); + assert_eq!( + OWL::DifferentFrom.as_ref(), + "http://www.w3.org/2002/07/owl#differentFrom" + ); + assert_eq!( + OWL::DisjointUnionOf.as_ref(), + "http://www.w3.org/2002/07/owl#disjointUnionOf" + ); + assert_eq!( + OWL::DisjointWith.as_ref(), + "http://www.w3.org/2002/07/owl#disjointWith" + ); + assert_eq!( + OWL::DistinctMembers.as_ref(), + "http://www.w3.org/2002/07/owl#distinctMembers" + ); + assert_eq!( + OWL::EquivalentClass.as_ref(), + "http://www.w3.org/2002/07/owl#equivalentClass" + ); + assert_eq!( + OWL::EquivalentProperty.as_ref(), + "http://www.w3.org/2002/07/owl#equivalentProperty" + ); + assert_eq!( + OWL::FunctionalProperty.as_ref(), + "http://www.w3.org/2002/07/owl#FunctionalProperty" + ); + assert_eq!(OWL::HasKey.as_ref(), "http://www.w3.org/2002/07/owl#hasKey"); + assert_eq!( + OWL::HasValue.as_ref(), + "http://www.w3.org/2002/07/owl#hasValue" + ); + assert_eq!( + OWL::Imports.as_ref(), + "http://www.w3.org/2002/07/owl#imports" + ); + assert_eq!( + OWL::IntersectionOf.as_ref(), + "http://www.w3.org/2002/07/owl#intersectionOf" + ); + assert_eq!( + OWL::InverseFunctionalProperty.as_ref(), + "http://www.w3.org/2002/07/owl#InverseFunctionalProperty" + ); + assert_eq!( + OWL::InverseOf.as_ref(), + "http://www.w3.org/2002/07/owl#inverseOf" + ); + assert_eq!( + OWL::IrreflexiveProperty.as_ref(), + "http://www.w3.org/2002/07/owl#IrreflexiveProperty" + ); + assert_eq!( + OWL::MaxCardinality.as_ref(), + "http://www.w3.org/2002/07/owl#maxCardinality" + ); + assert_eq!( + OWL::MaxQualifiedCardinality.as_ref(), + "http://www.w3.org/2002/07/owl#maxQualifiedCardinality" + ); + assert_eq!( + OWL::Members.as_ref(), + "http://www.w3.org/2002/07/owl#members" + ); + assert_eq!( + OWL::MinCardinality.as_ref(), + "http://www.w3.org/2002/07/owl#minCardinality" + ); + assert_eq!( + OWL::MinQualifiedCardinality.as_ref(), + "http://www.w3.org/2002/07/owl#minQualifiedCardinality" + ); + assert_eq!( + OWL::NamedIndividual.as_ref(), + "http://www.w3.org/2002/07/owl#NamedIndividual" + ); + assert_eq!( + OWL::NegativePropertyAssertion.as_ref(), + "http://www.w3.org/2002/07/owl#NegativePropertyAssertion" + ); + assert_eq!( + OWL::Nothing.as_ref(), + "http://www.w3.org/2002/07/owl#Nothing" + ); + assert_eq!( + OWL::ObjectProperty.as_ref(), + "http://www.w3.org/2002/07/owl#ObjectProperty" + ); + assert_eq!( + OWL::OnClass.as_ref(), + "http://www.w3.org/2002/07/owl#onClass" + ); + assert_eq!( + OWL::OnDataRange.as_ref(), + "http://www.w3.org/2002/07/owl#onDataRange" + ); + assert_eq!( + OWL::OnDatatype.as_ref(), + "http://www.w3.org/2002/07/owl#onDatatype" + ); + assert_eq!(OWL::OneOf.as_ref(), "http://www.w3.org/2002/07/owl#oneOf"); + assert_eq!( + OWL::OnProperty.as_ref(), + "http://www.w3.org/2002/07/owl#onProperty" + ); + assert_eq!( + OWL::Ontology.as_ref(), + "http://www.w3.org/2002/07/owl#Ontology" + ); + assert_eq!( + OWL::QualifiedCardinality.as_ref(), + "http://www.w3.org/2002/07/owl#qualifiedCardinality" + ); + assert_eq!( + OWL::PropertyChainAxiom.as_ref(), + "http://www.w3.org/2002/07/owl#propertyChainAxiom" + ); + assert_eq!( + OWL::PropertyDisjointWith.as_ref(), + "http://www.w3.org/2002/07/owl#propertyDisjointWith" + ); + assert_eq!( + OWL::ReflexiveProperty.as_ref(), + "http://www.w3.org/2002/07/owl#ReflexiveProperty" + ); + assert_eq!( + OWL::Restriction.as_ref(), + "http://www.w3.org/2002/07/owl#Restriction" + ); + assert_eq!(OWL::SameAs.as_ref(), "http://www.w3.org/2002/07/owl#sameAs"); + assert_eq!( + OWL::SourceIndividual.as_ref(), + "http://www.w3.org/2002/07/owl#sourceIndividual" + ); + assert_eq!( + OWL::SomeValuesFrom.as_ref(), + "http://www.w3.org/2002/07/owl#someValuesFrom" + ); + assert_eq!( + OWL::SymmetricProperty.as_ref(), + "http://www.w3.org/2002/07/owl#SymmetricProperty" + ); + assert_eq!( + OWL::TargetIndividual.as_ref(), + "http://www.w3.org/2002/07/owl#targetIndividual" + ); + assert_eq!( + OWL::TargetValue.as_ref(), + "http://www.w3.org/2002/07/owl#targetValue" + ); + assert_eq!( + OWL::TopDataProperty.as_ref(), + "http://www.w3.org/2002/07/owl#topDataProperty" + ); + assert_eq!( + OWL::TopObjectProperty.as_ref(), + "http://www.w3.org/2002/07/owl#topObjectProperty" + ); + assert_eq!(OWL::Thing.as_ref(), "http://www.w3.org/2002/07/owl#Thing"); + assert_eq!( + OWL::TransitiveProperty.as_ref(), + "http://www.w3.org/2002/07/owl#TransitiveProperty" + ); + assert_eq!( + OWL::UnionOf.as_ref(), + "http://www.w3.org/2002/07/owl#unionOf" + ); + assert_eq!( + OWL::VersionIRI.as_ref(), + "http://www.w3.org/2002/07/owl#versionIRI" + ); + assert_eq!( + OWL::WithRestrictions.as_ref(), + "http://www.w3.org/2002/07/owl#withRestrictions" + ); + } + + #[test] + fn test_namespace_try_from() { + assert_eq!("http://www.w3.org/2002/07/owl#", Namespace::OWL.as_ref()); + assert_eq!(b"http://www.w3.org/2002/07/owl#", Namespace::OWL.as_bytes()); + + assert!(Namespace::from_str("http://www.w3.org/2002/07/owl#").is_ok()); + assert!(Namespace::from_str("http://www.example.org/2002/07/owl#").is_err()); + + assert!(Namespace::try_from(b"http://www.w3.org/2002/07/owl#".as_ref()).is_ok()); + assert!(Namespace::try_from(b"http://www.example.org/2002/07/owl#".as_ref()).is_err()); + } + + #[test] + fn test_to_built_in_entity() { + let builder = Build::new_rc(); + let iri_top_dp = builder.iri(OWL::TopDataProperty.as_ref()); + let iri_top_op = builder.iri(OWL::TopObjectProperty.as_ref()); + let iri_thing = builder.iri(OWL::Thing.as_ref()); + let iri_nothing = builder.iri(OWL::Nothing.as_ref()); + assert_eq!( + to_built_in_entity(&iri_top_dp), + Some(NamedEntityKind::DataProperty) + ); + assert_eq!( + to_built_in_entity(&iri_top_op), + Some(NamedEntityKind::ObjectProperty) + ); + assert_eq!(to_built_in_entity(&iri_thing), Some(NamedEntityKind::Class)); + assert_eq!( + to_built_in_entity(&iri_nothing), + Some(NamedEntityKind::Class) + ); + } + + #[test] + pub fn test_entity_for_iri() { + let b = Build::new_rc(); + + assert!(entity_for_iri( + "http://www.w3.org/2002/07/owl#Class", + "http://www.example.com", + &b + ) + .is_ok()); + assert!(entity_for_iri( + "http://www.w3.org/2002/07/owl#Fred", + "http://www.example.com", + &b + ) + .is_err()); + } + + #[test] + pub fn test_namespace_in_entity_for_iri() { + let b = Build::new_rc(); + + assert!(entity_for_iri( + "http://www.w3.org/2002/07/low#Class", + "http://www.example.com", + &b + ) + .is_err()); + assert!(entity_for_iri( + "abcdefghijklmnopqrstuvwxyz123#Class", + "http://www.example.com", + &b + ) + .is_err()); + } + + #[test] + fn test_meta_annotation_builtin() { + // Method can accept `str`ings... + assert!(is_annotation_builtin( + "http://www.w3.org/2002/07/owl#deprecated" + )); + // ...and `String`s. + assert!(is_annotation_builtin( + &"http://www.w3.org/2000/01/rdf-schema#comment".to_string() + )); + assert!(!is_annotation_builtin( + &"http://www.w3.org/2002/07/owl#fred".to_string() + )); + } + + #[test] + fn test_meta_facet() { + assert_eq!( + Facet::MinLength.as_ref(), + "http://www.w3.org/2001/XMLSchema#minLength" + ); + + assert_eq!( + Facet::Pattern.as_ref(), + "http://www.w3.org/2001/XMLSchema#pattern" + ); + + assert_eq!( + Facet::try_from("http://www.w3.org/2001/XMLSchema#pattern").unwrap(), + Facet::Pattern + ); + + assert_eq!( + Facet::try_from(b"http://www.w3.org/2001/XMLSchema#minExclusive".as_ref()).unwrap(), + Facet::MinExclusive + ); + } + + #[test] + fn test_is_xsd_datatype() { + assert!(is_xsd_datatype( + "http://www.w3.org/2001/XMLSchema#nonNegativeInteger" + )); + assert!(!is_xsd_datatype( + "http://www.w3.org/2001/XMLSchemaaa#nonNegativeInteger" + )); + assert!(!is_xsd_datatype("http://www.w3.org/2001/XMLSchema.pdf")); + } +}