From 5fa23ea928f5bcee49b65810b3837b31f10226ae Mon Sep 17 00:00:00 2001 From: Simon Johnston Date: Wed, 2 Oct 2024 09:29:39 -0700 Subject: [PATCH] refactor: remove ref types --- rdftk_core/src/lib.rs | 10 +- rdftk_core/src/model/data_set/mod.rs | 126 ++---- rdftk_core/src/model/features.rs | 94 +++-- rdftk_core/src/model/graph/mapping.rs | 155 +++++-- rdftk_core/src/model/graph/mod.rs | 452 +++++++++++++++------ rdftk_core/src/model/graph/named.rs | 209 ---------- rdftk_core/src/model/graph/skolem.rs | 59 --- rdftk_core/src/model/literal/data_type.rs | 120 ------ rdftk_core/src/model/literal/factory.rs | 122 ------ rdftk_core/src/model/literal/mod.rs | 288 ++++++++++--- rdftk_core/src/model/mod.rs | 40 +- rdftk_core/src/model/qname.rs | 224 ---------- rdftk_core/src/model/statement/bnode.rs | 61 +-- rdftk_core/src/model/statement/factory.rs | 152 ------- rdftk_core/src/model/statement/mod.rs | 339 ++++++++++------ rdftk_core/src/model/statement/object.rs | 227 ++++++----- rdftk_core/src/model/statement/subject.rs | 235 +++++------ rdftk_core/src/simple/data_set.rs | 82 ++-- rdftk_core/src/simple/graph.rs | 197 +++------ rdftk_core/src/simple/indexed.rs | 203 ++++----- rdftk_core/src/simple/literal.rs | 184 +++++++-- rdftk_core/src/simple/mapping.rs | 128 ------ rdftk_core/src/simple/mod.rs | 58 ++- rdftk_core/src/simple/resource.rs | 178 ++++---- rdftk_core/src/simple/statement.rs | 202 +++++++++ rdftk_core/src/simple/statement/mod.rs | 225 ---------- rdftk_core/src/simple/statement/object.rs | 109 ----- rdftk_core/src/simple/statement/subject.rs | 94 ----- rdftk_core/tests/data_sets.rs | 10 + rdftk_core/tests/graphs.rs | 237 +++++------ rdftk_core/tests/literals.rs | 20 +- rdftk_core/tests/prefix_mappings.rs | 60 +-- rdftk_core/tests/qnames.rs | 3 +- rdftk_core/tests/resources.rs | 35 +- rdftk_core/tests/statements.rs | 42 +- 35 files changed, 2085 insertions(+), 2895 deletions(-) delete mode 100644 rdftk_core/src/model/graph/named.rs delete mode 100644 rdftk_core/src/model/graph/skolem.rs delete mode 100644 rdftk_core/src/model/literal/data_type.rs delete mode 100644 rdftk_core/src/model/literal/factory.rs delete mode 100644 rdftk_core/src/model/qname.rs delete mode 100644 rdftk_core/src/model/statement/factory.rs delete mode 100644 rdftk_core/src/simple/mapping.rs create mode 100644 rdftk_core/src/simple/statement.rs delete mode 100644 rdftk_core/src/simple/statement/mod.rs delete mode 100644 rdftk_core/src/simple/statement/object.rs delete mode 100644 rdftk_core/src/simple/statement/subject.rs create mode 100644 rdftk_core/tests/data_sets.rs diff --git a/rdftk_core/src/lib.rs b/rdftk_core/src/lib.rs index aeddb79..e3e30a7 100644 --- a/rdftk_core/src/lib.rs +++ b/rdftk_core/src/lib.rs @@ -26,17 +26,19 @@ * # Example * * ```rust +* use rdftk_core::model::literal::LiteralFactory; * use rdftk_core::model::statement::{ -* ObjectNode, Statement, StatementList, SubjectNode, +* ObjectNode, Statement, SubjectNode, StatementFactory, * }; * use rdftk_core::simple; +* use rdftk_core::simple::statement::SimpleStatement; * use rdftk_iri::Iri; * use std::rc::Rc; * use std::str::FromStr; * -* let mut statements: StatementList = Default::default(); -* let factory = simple::statement::statement_factory(); -* let literals = simple::literal::literal_factory(); +* let mut statements: Vec = Default::default(); +* let factory = simple::statement::SimpleStatementFactory::default(); +* let literals = simple::literal::SimpleLiteralFactory::default(); * * statements.push(factory.statement( * factory.named_subject( diff --git a/rdftk_core/src/model/data_set/mod.rs b/rdftk_core/src/model/data_set/mod.rs index 1f3f05a..41cf93c 100644 --- a/rdftk_core/src/model/data_set/mod.rs +++ b/rdftk_core/src/model/data_set/mod.rs @@ -6,13 +6,12 @@ Additional semantics taken from [RDF 1.1 TriG](https://www.w3.org/TR/trig/), _RD # Example ```rust -use rdftk_core::model::data_set::{DataSet, DataSetRef}; -use rdftk_core::model::graph::NamedGraphRef; -use rdftk_core::model::statement::StatementRef; +use rdftk_core::model::data_set::DataSet; +use rdftk_core::model::graph::Graph; +use rdftk_core::model::statement::Statement; -fn simple_dataset_writer(data_set: &DataSetRef) +fn simple_dataset_writer(data_set: &impl DataSet) { - let data_set = data_set.borrow(); if let Some(graph) = data_set.default_graph() { simple_graph_writer(graph); } @@ -21,16 +20,15 @@ fn simple_dataset_writer(data_set: &DataSetRef) } } -fn simple_graph_writer(graph: &NamedGraphRef) +fn simple_graph_writer(graph: &impl Graph) { - let graph = graph.borrow(); if graph.is_named() { println!("{} {{", graph.name().unwrap()); } else { println!("{{"); } for statement in graph.statements() { - println!(" {}", statement); + println!(" {:?}", statement); } println!("}}"); } @@ -39,62 +37,14 @@ fn simple_graph_writer(graph: &NamedGraphRef) */ use crate::model::features::Featured; -use crate::model::graph::named::GraphNameRef; -use crate::model::graph::named::NamedGraphRef; -use crate::model::graph::GraphFactoryRef; +use crate::model::graph::{Graph, GraphName}; use crate::model::Provided; -use std::cell::RefCell; use std::fmt::Debug; -use std::rc::Rc; -use std::sync::Arc; // ------------------------------------------------------------------------------------------------ -// Public Types +// Public Types ❱ Data Set // ------------------------------------------------------------------------------------------------ -/// -/// A data set factory provides an interface to create a new data set. This allows for -/// implementations where underlying shared resources are required and so may be owned by the -/// factory. -/// -pub trait DataSetFactory: Debug + Provided { - /// - /// Create a new graph instance. - /// - fn data_set(&self) -> DataSetRef; - - /// - /// Create a new graph instance from the given statements and prefix mappings. - /// - fn data_set_from(&self, graphs: Vec) -> DataSetRef { - let data_set = self.data_set(); - { - let mut data_set = data_set.borrow_mut(); - for graph in graphs { - data_set.insert(graph); - } - } - data_set - } - - // -------------------------------------------------------------------------------------------- - // Other Factories - // -------------------------------------------------------------------------------------------- - - /// - /// Return the factory that creates graphs managed by data set's of this kind. - /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. - /// - fn graph_factory(&self) -> GraphFactoryRef; -} - -/// -/// The reference type for a graph factory returned by a graph. -/// -pub type DataSetFactoryRef = Arc; - /// /// A `DataSet` is a mapping from `GraphName` to `Graph`; this introduces the notion of a named graph /// although in actuality the graph itself is not named as the name is the key within the data set. @@ -102,6 +52,8 @@ pub type DataSetFactoryRef = Arc; /// `MutableDataSet` trait for mutation. /// pub trait DataSet: Debug + Featured { + type Graph: Graph; + /// /// Returns `true` if there are no graphs in this data set, else `false`. /// @@ -112,7 +64,7 @@ pub trait DataSet: Debug + Featured { /// fn len(&self) -> usize; - fn contains_graph(&self, name: &Option) -> bool; + fn contains_graph(&self, name: &Option) -> bool; /// /// Return `true` if this data set has a default graph, else `false`. @@ -124,72 +76,80 @@ pub trait DataSet: Debug + Featured { /// /// Return `true` if this data set has a graph with the provided name, else `false`. /// - fn has_graph_named(&self, name: &GraphNameRef) -> bool { + fn has_graph_named(&self, name: &GraphName) -> bool { self.contains_graph(&Some(name.clone())) } /// /// Return the default graph for this data set, if it exists. /// - fn default_graph(&self) -> Option<&NamedGraphRef> { + fn default_graph(&self) -> Option<&Self::Graph> { self.graph(&None) } /// /// Return the graph with the provided name from this data set, if it exists. /// - fn graph_named(&self, name: &GraphNameRef) -> Option<&NamedGraphRef> { + fn graph_named(&self, name: &GraphName) -> Option<&Self::Graph> { self.graph(&Some(name.clone())) } - fn graph(&self, name: &Option) -> Option<&NamedGraphRef>; + fn graph(&self, name: &Option) -> Option<&Self::Graph>; - fn graph_mut(&mut self, name: &Option) -> Option<&mut NamedGraphRef>; + fn graph_mut(&mut self, name: &Option) -> Option<&mut Self::Graph>; /// /// Return an iterator over all graphs. /// - fn graphs(&self) -> Box + '_>; + fn graphs(&self) -> impl Iterator; /// /// Insert a new graph with it's associated name into the data set. /// - fn insert(&mut self, graph: NamedGraphRef); + fn insert(&mut self, graph: Self::Graph); /// /// Add all the graphs from the provided vector. /// - fn extend(&mut self, graphs: Vec); + fn extend(&mut self, graphs: Vec); /// /// Remove the graph with the provided name from this data set. This operation has no effect if /// no such graph is present. /// - fn remove(&mut self, named: &Option); + fn remove(&mut self, named: &Option); /// /// Remove all graphs from this data set. /// fn clear(&mut self); +} +// ------------------------------------------------------------------------------------------------ +// Public Types ❱ Factories +// ------------------------------------------------------------------------------------------------ + +/// +/// A data set factory provides an interface to create a new data set. This allows for +/// implementations where underlying shared resources are required and so may be owned by the +/// factory. +/// +pub trait DataSetFactory: Debug + Provided { + type Graph: Graph; + type DataSet: DataSet; /// - /// Return the factory that creates data sets using the same provider as `self`. - /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. + /// Create a new graph instance. /// - fn factory(&self) -> DataSetFactoryRef; + fn data_set(&self) -> Self::DataSet; /// - /// Return the factory that creates graphs managed by data set's of this kind. - /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. + /// Create a new graph instance from the given statements and prefix mappings. /// - fn graph_factory(&self) -> GraphFactoryRef; + fn data_set_from(&self, graphs: Vec) -> Self::DataSet { + let mut data_set = self.data_set(); + for graph in graphs { + data_set.insert(graph); + } + data_set + } } - -/// -/// The reference type for a graph data set. -/// -pub type DataSetRef = Rc>; diff --git a/rdftk_core/src/model/features.rs b/rdftk_core/src/model/features.rs index 661dce8..6421ffc 100644 --- a/rdftk_core/src/model/features.rs +++ b/rdftk_core/src/model/features.rs @@ -7,16 +7,18 @@ More detailed description, with ```rust use rdftk_core::model::features::{Featured, FEATURE_GRAPH_DUPLICATES}; -use rdftk_core::simple::graph::graph_factory; +use rdftk_core::model::graph::GraphFactory; +use rdftk_core::simple::graph::SimpleGraphFactory; -let graph = graph_factory().graph(); +let simple = SimpleGraphFactory::default(); +let graph = simple.graph(); -println!("Allows Duplicates: {}", graph.borrow().supports_feature(&FEATURE_GRAPH_DUPLICATES)); +println!("Allows Duplicates: {}", graph.supports_feature(&FEATURE_GRAPH_DUPLICATES)); ``` */ use lazy_static::lazy_static; -use rdftk_iri::{Iri, IriRef}; +use rdftk_iri::Iri; use std::str::FromStr; // ------------------------------------------------------------------------------------------------ @@ -31,7 +33,7 @@ pub trait Featured { /// /// Return true if this instance, or factory, supports the feature identified by the Iri. /// - fn supports_feature(&self, feature: &IriRef) -> bool; + fn supports_feature(&self, feature: &Iri) -> bool; } lazy_static! { @@ -44,103 +46,109 @@ lazy_static! { /// If true, a data set's default graph is a combination of all named graphs. This implies /// that `set_default_graph` and `unset_default_graph` have no effect. /// - pub static ref FEATURE_COMBINED_DEFAULT: IriRef = IriRef::from( + pub static ref FEATURE_COMBINED_DEFAULT: Iri = Iri::from_str("http://rust-rdftk.dev/feature/model.data_set/combined_default").unwrap() - ); + ; // -------------------------------------------------------------------------------------------- // Graph/Statement features // -------------------------------------------------------------------------------------------- + /// + /// Denotes that this graph allows names. + /// + pub static ref FEATURE_GRAPH_ALLOWS_NAMED: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/graph/named").unwrap(); + /// /// Denotes that this graph accepts duplicate statements. /// - pub static ref FEATURE_GRAPH_DUPLICATES: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/graph/duplicates").unwrap()); + pub static ref FEATURE_GRAPH_DUPLICATES: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/graph/duplicates").unwrap(); /// /// This graph, or corresponding statement, supports /// [RDF-star](https://w3c.github.io/rdf-star/cg-spec/editors_draft.html). /// - pub static ref FEATURE_RDF_STAR: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/graph/rdf_star").unwrap()); + pub static ref FEATURE_RDF_STAR: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/graph/rdf_star").unwrap(); /// /// This graph, or corresponding statement, supports /// [N3 Formula](https://www.w3.org/TeamSubmission/n3/#Quoting) /// - pub static ref FEATURE_N3_FORMULAE: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/graph/n3_formulae").unwrap()); + pub static ref FEATURE_N3_FORMULAE: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/graph/n3_formulae").unwrap(); // -------------------------------------------------------------------------------------------- // Index features // -------------------------------------------------------------------------------------------- /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_SUBJECT: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/index/subject").unwrap()); + pub static ref FEATURE_IDX_SUBJECT: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/index/subject").unwrap(); /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_PREDICATE: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/index/predicate").unwrap()); + pub static ref FEATURE_IDX_PREDICATE: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/index/predicate").unwrap(); /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_OBJECT: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/index/object").unwrap()); + pub static ref FEATURE_IDX_OBJECT: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/index/object").unwrap(); /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_SUBJECT_PREDICATE: IriRef = IriRef::from( + pub static ref FEATURE_IDX_SUBJECT_PREDICATE: Iri = Iri::from_str("http://rust-rdftk.dev/feature/index/subject_predicate").unwrap() - ); + ; /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_SUBJECT_PREDICATE_OBJECT: IriRef = IriRef::from( + pub static ref FEATURE_IDX_SUBJECT_PREDICATE_OBJECT: Iri = Iri::from_str("http://rust-rdftk.dev/feature/index/subject_predicate_object").unwrap() - ); + ; /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_SUBJECT_OBJECT: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/index/subject_object").unwrap()); + pub static ref FEATURE_IDX_SUBJECT_OBJECT: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/index/subject_object").unwrap(); /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_PREDICATE_OBJECT: IriRef = IriRef::from( + pub static ref FEATURE_IDX_PREDICATE_OBJECT: Iri = Iri::from_str("http://rust-rdftk.dev/feature/index/predicate_object").unwrap() - ); + ; /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_GRAPH: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/index/graph").unwrap()); + pub static ref FEATURE_IDX_GRAPH: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/index/graph").unwrap(); /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_SUBJECT_GRAPH: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/index/subject_graph").unwrap()); + pub static ref FEATURE_IDX_SUBJECT_GRAPH: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/index/subject_graph").unwrap(); /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_PREDICATE_GRAPH: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/index/predicate_graph").unwrap()); + pub static ref FEATURE_IDX_PREDICATE_GRAPH: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/index/predicate_graph").unwrap(); /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_OBJECT_GRAPH: IriRef = - IriRef::from(Iri::from_str("http://rust-rdftk.dev/feature/index/object_graph").unwrap()); + pub static ref FEATURE_IDX_OBJECT_GRAPH: Iri = + Iri::from_str("http://rust-rdftk.dev/feature/index/object_graph").unwrap(); /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_SUBJECT_PREDICATE_GRAPH: IriRef = IriRef::from( + pub static ref FEATURE_IDX_SUBJECT_PREDICATE_GRAPH: Iri = Iri::from_str("http://rust-rdftk.dev/feature/index/subject_predicate_graph").unwrap() - ); + ; /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_SUBJECT_PREDICATE_OBJECT_GRAPH: IriRef = IriRef::from( + pub static ref FEATURE_IDX_SUBJECT_PREDICATE_OBJECT_GRAPH: Iri = Iri::from_str("http://rust-rdftk.dev/feature/index/subject_predicate_object_graph") .unwrap() - ); + ; /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_SUBJECT_OBJECT_GRAPH: IriRef = IriRef::from( + pub static ref FEATURE_IDX_SUBJECT_OBJECT_GRAPH: Iri = Iri::from_str("http://rust-rdftk.dev/feature/index/subject_object_graph").unwrap() - ); + ; /// Used to determine whether a specific index combination is supported. - pub static ref FEATURE_IDX_PREDICATE_OBJECT_GRAPH: IriRef = IriRef::from( + pub static ref FEATURE_IDX_PREDICATE_OBJECT_GRAPH: Iri = Iri::from_str("http://rust-rdftk.dev/feature/index/predicate_object_graph").unwrap() - ); + ; } diff --git a/rdftk_core/src/model/graph/mapping.rs b/rdftk_core/src/model/graph/mapping.rs index 272671b..dad2c66 100644 --- a/rdftk_core/src/model/graph/mapping.rs +++ b/rdftk_core/src/model/graph/mapping.rs @@ -3,26 +3,45 @@ A trait for the prefix mappings required by the `Graph` trait. Prefix mappings c graph to provide more readable serialization forms. */ -use crate::model::qname::QName; -use rdftk_iri::{IriRef, Name}; +use bimap::BiHashMap; +use rdftk_iri::{Iri, IriExtra, Name, QName}; use rdftk_names::{dc, foaf, owl, rdf, rdfs, xsd}; -use std::cell::RefCell; use std::fmt::Debug; -use std::rc::Rc; // ------------------------------------------------------------------------------------------------ // Public Types // ------------------------------------------------------------------------------------------------ /// -/// The prefix used to denote the default namespace in the prefix mapping. +/// Implementation of a mapping from a prefix `Name` to an `Iri`. Prefix mappings are commonly used +/// in the serialization of graphs. /// -pub const DEFAULT_PREFIX: &str = ""; +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct PrefixMapping { + map: BiHashMap, Iri>, +} + +// ------------------------------------------------------------------------------------------------ +// Public Functions +// ------------------------------------------------------------------------------------------------ /// -/// Prefix mappings are used in the serialization of graphs. +/// Create a new prefix mapping instance with the RDF, RDF Schema, and XML Namespace mappings. /// -pub trait PrefixMappings: Debug { +#[inline] +pub fn common_mappings() -> PrefixMapping { + PrefixMapping::default() + .with_owl() + .with_rdf() + .with_rdfs() + .with_xsd() +} + +// ------------------------------------------------------------------------------------------------ +// Implementations +// ------------------------------------------------------------------------------------------------ + +impl PrefixMapping { // -------------------------------------------------------------------------------------------- // Constructors // -------------------------------------------------------------------------------------------- @@ -30,7 +49,7 @@ pub trait PrefixMappings: Debug { /// /// Construct a new mapping instance with the provided default namespace. /// - fn with_default(self, iri: IriRef) -> Self + pub fn with_default(self, iri: Iri) -> Self where Self: Sized, { @@ -39,10 +58,34 @@ pub trait PrefixMappings: Debug { mut_self } + /// + /// Include the common "dcterms" mapping. + /// + pub fn with_dcterms(self) -> Self + where + Self: Sized, + { + let mut mut_self = self; + mut_self.insert_dcterms(); + mut_self + } + + /// + /// Include the common "foaf" mapping. + /// + pub fn with_foaf(self) -> Self + where + Self: Sized, + { + let mut mut_self = self; + mut_self.insert_foaf(); + mut_self + } + /// /// Include the common "owl" mapping. /// - fn with_owl(self) -> Self + pub fn with_owl(self) -> Self where Self: Sized, { @@ -54,7 +97,7 @@ pub trait PrefixMappings: Debug { /// /// Include the common "rdf" mapping. /// - fn with_rdf(self) -> Self + pub fn with_rdf(self) -> Self where Self: Sized, { @@ -66,7 +109,7 @@ pub trait PrefixMappings: Debug { /// /// Include the common "rdfs" mapping. /// - fn with_rdfs(self) -> Self + pub fn with_rdfs(self) -> Self where Self: Sized, { @@ -78,7 +121,7 @@ pub trait PrefixMappings: Debug { /// /// Include the common "xsd" (XML Schema Data types) mapping. /// - fn with_xsd(self) -> Self + pub fn with_xsd(self) -> Self where Self: Sized, { @@ -94,66 +137,84 @@ pub trait PrefixMappings: Debug { /// /// Returns `true` if there are no mappings in this instance, else `false`. /// - fn is_empty(&self) -> bool; + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } /// /// Return the number of mappings in this instance. /// - fn len(&self) -> usize; + pub fn len(&self) -> usize { + self.map.len() + } /// /// Get the default namespace mapping, if present. /// - fn get_default_namespace(&self) -> Option<&IriRef>; + pub fn get_default_namespace(&self) -> Option<&Iri> { + self.map.get_by_left(&None) + } /// /// Set the default namespace mapping. /// - fn set_default_namespace(&mut self, iri: IriRef); + pub fn set_default_namespace(&mut self, iri: Iri) { + let _ = self.map.insert(None, iri); + } - fn remove_default_namespace(&mut self); + pub fn remove_default_namespace(&mut self) { + let _ = self.map.remove_by_left(&None); + } /// /// Get the namespace Iri associated with this provided prefix, if present. /// - fn get_namespace(&self, prefix: &Name) -> Option<&IriRef>; + pub fn get_namespace(&self, prefix: &Name) -> Option<&Iri> { + self.map.get_by_left(&Some(prefix.clone())) + } /// /// Get the prefix associated with this provided namespace URI, if present. /// - fn get_prefix(&self, namespace: &IriRef) -> Option<&Option>; + pub fn get_prefix(&self, namespace: &Iri) -> Option<&Option> { + self.map.get_by_right(namespace) + } /// /// Return an iterator over the contained mappings. /// - fn mappings<'a>(&'a self) -> Box, &'a IriRef)> + 'a>; + pub fn mappings<'a>(&'a self) -> Box, &'a Iri)> + 'a> { + Box::new(self.map.iter()) + } /// /// Insert a mapping from the prefix string to the namespace Iri. /// - fn insert(&mut self, prefix: Name, iri: IriRef); + pub fn insert(&mut self, prefix: Name, iri: Iri) { + let _ = self.map.insert(Some(prefix), iri); + } - fn insert_owl(&mut self) { + pub fn insert_owl(&mut self) { self.insert(owl::default_prefix().clone(), owl::namespace().clone()); } - fn insert_rdf(&mut self) { + pub fn insert_rdf(&mut self) { self.insert(rdf::default_prefix().clone(), rdf::namespace().clone()); } - fn insert_rdfs(&mut self) { + pub fn insert_rdfs(&mut self) { self.insert(rdfs::default_prefix().clone(), rdfs::namespace().clone()); } - fn insert_xsd(&mut self) { + pub fn insert_xsd(&mut self) { self.insert(xsd::default_prefix().clone(), xsd::namespace().clone()); } - fn insert_foaf(&mut self) { + pub fn insert_foaf(&mut self) { self.insert(foaf::default_prefix().clone(), foaf::namespace().clone()); } - fn insert_dcterms(&mut self) { + pub fn insert_dcterms(&mut self) { self.insert( dc::terms::default_prefix().clone(), dc::terms::namespace().clone(), @@ -163,12 +224,16 @@ pub trait PrefixMappings: Debug { /// /// Remove a mapping for the provided prefix. This operation has no effect if no mapping is present. /// - fn remove(&mut self, prefix: &Name); + pub fn remove(&mut self, prefix: &Name) { + let _ = self.map.remove_by_left(&Some(prefix.clone())); + } /// /// Remove all mappings from this instance. /// - fn clear(&mut self); + pub fn clear(&mut self) { + self.map.clear(); + } // -------------------------------------------------------------------------------------------- // QName Mapping @@ -177,15 +242,31 @@ pub trait PrefixMappings: Debug { /// /// Expand a qname into an Iri, if possible. /// - fn expand(&self, qname: &QName) -> Option; + pub fn expand(&self, qname: &QName) -> Option { + let prefix = if let Some(prefix) = qname.prefix() { + self.get_namespace(prefix) + } else { + self.get_default_namespace() + }; + match prefix { + None => None, + Some(namespace) => namespace.make_name(qname.name().clone()), + } + } /// /// Compress an Iri into a qname, if possible. /// - fn compress(&self, iri: &IriRef) -> Option; + pub fn compress(&self, iri: &Iri) -> Option { + let (iri, name) = if let Some((iri, name)) = iri.split() { + (iri, name) + } else { + return None; + }; + match self.get_prefix(&iri) { + None => None, + Some(None) => Some(QName::new_unqualified(name).unwrap()), + Some(Some(prefix)) => Some(QName::new(prefix.clone(), name).unwrap()), + } + } } - -/// -/// The actual object storage type, reference counted for memory management. -/// -pub type PrefixMappingRef = Rc>; diff --git a/rdftk_core/src/model/graph/mod.rs b/rdftk_core/src/model/graph/mod.rs index dd4cd6c..4fbd5c2 100644 --- a/rdftk_core/src/model/graph/mod.rs +++ b/rdftk_core/src/model/graph/mod.rs @@ -7,9 +7,11 @@ any backing storage. ```rust use rdftk_core::model::graph::Graph; -use rdftk_core::model::statement::StatementRef; +use rdftk_core::model::statement::Statement; -fn simple_graph_writer(graph: &impl Graph) +fn simple_graph_writer(graph: &G) +where + ::Statement: std::fmt::Display, { for statement in graph.statements() { println!("{}", statement); @@ -18,79 +20,33 @@ fn simple_graph_writer(graph: &impl Graph) ``` */ +use crate::error::Error; use crate::model::features::Featured; -use crate::model::literal::LiteralFactoryRef; -use crate::model::statement::{ - ObjectNodeRef, StatementFactoryRef, StatementList, StatementRef, SubjectNodeRef, -}; +use crate::model::statement::{BlankNode, ObjectNode, Statement, SubjectNode}; use crate::model::Provided; -use named::GraphNameRef; -use rdftk_iri::IriRef; -use std::cell::RefCell; -use std::collections::HashSet; -use std::fmt::Debug; -use std::rc::Rc; -use std::sync::Arc; +use rdftk_iri::IriExtra; +use rdftk_iri::{Iri, Name}; +use std::collections::{HashMap, HashSet}; +use std::fmt::{Debug, Display, Formatter}; +use std::hash::Hash; +use std::str::FromStr; // ------------------------------------------------------------------------------------------------ -// Public Types +// Public Types ❱ Graph Names // ------------------------------------------------------------------------------------------------ /// -/// A graph factory provides an interface to create a new graph. This allows for implementations -/// where underlying shared resources are required and so may be owned by the factory. -/// -/// The method for getting the initial factory instance is not specified here. By convention -/// implementors *may* provide a function `graph_factory` in the root module for their crate. +/// This type denotes the identifier for a graph in a data set; a graph name MUST be either an Iri +/// or a blank node. /// -pub trait GraphFactory: Debug + Provided { - /// - /// Create a new graph instance. - /// - fn graph(&self) -> GraphRef; - - /// - /// Create a new named graph instance. - /// - fn named_graph(&self, name: Option) -> NamedGraphRef; - - /// - /// Create a new graph instance from the given statements and prefix mappings. - /// - fn graph_from( - &self, - statements: &[StatementRef], - prefix_mappings: Option, - ) -> GraphRef; - - /// - /// Create a new graph instance from the given statements and prefix mappings. - /// - fn named_graph_from( - &self, - name: Option, - statements: &[StatementRef], - prefix_mappings: Option, - ) -> NamedGraphRef; - - // -------------------------------------------------------------------------------------------- - // Other Factories - // -------------------------------------------------------------------------------------------- - - /// - /// Return the factory that creates statements using the same provider as `self`. - /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. - /// - fn statement_factory(&self) -> StatementFactoryRef; +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum GraphName { + BNode(BlankNode), + Iri(Iri), } -/// -/// The actual object storage type, reference counted for memory management. -/// -pub type GraphFactoryRef = Arc; - +// ------------------------------------------------------------------------------------------------ +// Public Types ❱ Graphs // ------------------------------------------------------------------------------------------------ /// @@ -99,6 +55,9 @@ pub type GraphFactoryRef = Arc; /// `MutableGraph` trait for mutation. /// pub trait Graph: Debug + Featured { + type Literal: Literal + Eq + Hash; + type Statement: Statement + Eq + Hash; + /// /// Returns `true` if there are no statements in this graph, else `false`. /// @@ -110,24 +69,43 @@ pub trait Graph: Debug + Featured { fn len(&self) -> usize; // -------------------------------------------------------------------------------------------- - // Query + // Name // -------------------------------------------------------------------------------------------- /// - /// Returns `true` if this graph contains any statement with the provided subject, else `false`. + /// Returns `true` if this graph instance has a name. /// - fn contains_subject(&self, subject: &SubjectNodeRef) -> bool; + fn is_named(&self) -> bool { + self.name().is_some() + } /// - /// Returns `true` if this graph contains any statement with the provided Iri as subject, else - /// `false`. + /// Return the name of this graph. /// - fn contains_individual(&self, subject: &IriRef) -> bool; + fn name(&self) -> Option<&GraphName>; + + /// + /// Set the name of this graph. + /// + fn set_name(&mut self, name: GraphName); + + /// + /// Remove the name of this graph. + fn unset_name(&mut self); + + // -------------------------------------------------------------------------------------------- + // Query + // -------------------------------------------------------------------------------------------- + + /// + /// Returns `true` if this graph contains any statement with the provided subject, else `false`. + /// + fn contains_subject(&self, subject: &SubjectNode) -> bool; /// /// Returns `true` if this graph contains the provided statement, else `false`. /// - fn contains(&self, statement: &StatementRef) -> bool { + fn contains(&self, statement: &Self::Statement) -> bool { !self .matches( Some(statement.subject()), @@ -143,9 +121,9 @@ pub trait Graph: Debug + Featured { /// fn contains_all( &self, - subject: &SubjectNodeRef, - predicate: &IriRef, - object: &ObjectNodeRef, + subject: &SubjectNode, + predicate: &Iri, + object: &ObjectNode, ) -> bool { !self .matches(Some(subject), Some(predicate), Some(object)) @@ -158,10 +136,10 @@ pub trait Graph: Debug + Featured { /// fn matches( &self, - subject: Option<&SubjectNodeRef>, - predicate: Option<&IriRef>, - object: Option<&ObjectNodeRef>, - ) -> HashSet<&StatementRef>; + subject: Option<&SubjectNode>, + predicate: Option<&Iri>, + object: Option<&ObjectNode>, + ) -> HashSet<&Self::Statement>; // -------------------------------------------------------------------------------------------- // Iterators @@ -170,18 +148,18 @@ pub trait Graph: Debug + Featured { /// /// Return an iterator over all the statements in the graph. /// - fn statements<'a>(&'a self) -> Box + 'a>; + fn statements(&self) -> impl Iterator; /// /// Return a set of all subjects in the graph, note that this is a set so that it removes /// duplicates. /// - fn subjects(&self) -> HashSet<&SubjectNodeRef>; + fn subjects(&self) -> HashSet<&SubjectNode>; /// /// Return a set of all subjects that are not blank nodes /// - fn node_subjects(&self) -> HashSet<&SubjectNodeRef> { + fn node_subjects(&self) -> HashSet<&SubjectNode> { self.subjects() .into_iter() .filter(|s| !s.is_blank()) @@ -191,7 +169,7 @@ pub trait Graph: Debug + Featured { /// /// Return a set of all subjects that are blank nodes /// - fn blank_node_subjects(&self) -> HashSet<&SubjectNodeRef> { + fn blank_node_subjects(&self) -> HashSet<&SubjectNode> { self.subjects() .into_iter() .filter(|s| s.is_blank()) @@ -202,25 +180,32 @@ pub trait Graph: Debug + Featured { /// Return a set of all predicate in the graph, note that this is a set so that it removes /// duplicates. /// - fn predicates(&self) -> HashSet<&IriRef>; + fn predicates(&self) -> HashSet<&Iri>; /// /// Return a set of all predicate referenced by the provided subject in graph, note that /// this is a set so that it removes duplicates. /// - fn predicates_for(&self, subject: &SubjectNodeRef) -> HashSet<&IriRef>; + fn predicates_for( + &self, + subject: &SubjectNode, + ) -> HashSet<&Iri>; /// /// Return a set of all objects in the graph, note that this is a set so that it removes /// duplicates. /// - fn objects(&self) -> HashSet<&ObjectNodeRef>; + fn objects(&self) -> HashSet<&ObjectNode>; /// /// Return a set of all objects referenced by the provided subject and predicate in the graph, /// note that this is a set so that it removes duplicates. /// - fn objects_for(&self, subject: &SubjectNodeRef, predicate: &IriRef) -> HashSet<&ObjectNodeRef>; + fn objects_for( + &self, + subject: &SubjectNode, + predicate: &Iri, + ) -> HashSet<&ObjectNode>; // -------------------------------------------------------------------------------------------- // Namespace Management @@ -229,40 +214,12 @@ pub trait Graph: Debug + Featured { /// /// Returns the set of prefix mappings held by the graph. /// - fn prefix_mappings(&self) -> PrefixMappingRef; + fn prefix_mappings(&self) -> PrefixMapping; /// /// Set the prefix mappings held by the graph. /// - fn set_prefix_mappings(&mut self, mappings: PrefixMappingRef); - - // -------------------------------------------------------------------------------------------- - // Factories - // -------------------------------------------------------------------------------------------- - - /// - /// Return the factory that creates graphs using the same provider as `self`. - /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. - /// - fn factory(&self) -> GraphFactoryRef; - - /// - /// Return the factory that creates statements using the same provider as `self`. - /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. - /// - fn statement_factory(&self) -> StatementFactoryRef; - - /// - /// Return the factory that creates literals using the same provider as `self`. - /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. - /// - fn literal_factory(&self) -> LiteralFactoryRef; + fn set_prefix_mappings(&mut self, mappings: PrefixMapping); // -------------------------------------------------------------------------------------------- // Mutators @@ -271,12 +228,12 @@ pub trait Graph: Debug + Featured { /// /// Return an iterator over all the statements in the graph. /// - fn statements_mut<'a>(&'a mut self) -> Box + 'a>; + fn statements_mut(&mut self) -> impl Iterator; /// /// Insert a new statement into the graph. /// - fn insert(&mut self, statement: StatementRef); + fn insert(&mut self, statement: Self::Statement); /// /// Merge another graph into this one. Note that the graphs are required to have the same @@ -293,38 +250,275 @@ pub trait Graph: Debug + Featured { /// This method does nothing if this graph has does not support the feature /// `FEATURE_GRAPH_DUPLICATES` and will therefore always return an empty list. /// - fn dedup(&mut self) -> StatementList; + fn dedup(&mut self) -> Vec; /// /// Remove any statement that matches the provided. If a graph has duplicates this method does /// not differentiate between them. /// - fn remove(&mut self, statement: &StatementRef); + fn remove(&mut self, statement: &Self::Statement); /// /// Remove all statements from this graph that have the provided subject. /// - fn remove_all_for(&mut self, subject: &SubjectNodeRef) -> StatementList; + fn remove_all_for( + &mut self, + subject: &SubjectNode, + ) -> Vec; /// /// Remove all statements from this graph. /// fn clear(&mut self); + + /// + /// Replace all blank nodes with new, unique Iris. This creates a new graph and leaves the initial + /// graph unchanged. The base Iri is used to create identifiers, it's path will be replaced + /// entirely by a well-known format. + /// + /// For example, given the following input graph with blank nodes: + /// + /// ```ttl + /// _:B0f21 . + /// _:B0f21 "My" . + /// _:B0f21 "Name" . + /// ``` + /// + /// the call to `skolemize`, + /// + /// ```rust,ignore + /// let base = Iri::from_str("https://example.com/me").unwrap(); + /// graph.skolemize(&base) + /// ``` + /// + /// results in a new graph containing replacement IRIs. + /// + /// ```ttl + /// + /// + /// . + /// + /// + /// "My" . + /// + /// + /// "Name" . + /// ``` + fn skolemize( + self, + base: &Iri, + graph_factory: &F1, + statement_factory: &F2, + ) -> Result + where + F1: GraphFactory, + F2: StatementFactory, + Self: Sized, + { + let mut mapping: HashMap = Default::default(); + + let mut new_graph = graph_factory.graph(); + + for statement in self.statements() { + let mut new_statement = statement.clone(); + if let Some(blank) = new_statement.subject().as_blank() { + if !mapping.contains_key(blank) { + let _ = mapping.insert(blank.clone(), base.genid()?); + } + let name = mapping.get(blank).unwrap().clone(); + let subject = statement_factory.named_subject(name); + new_statement.set_subject(subject); + } + if let Some(blank) = new_statement.object().as_blank() { + if !mapping.contains_key(blank) { + let _ = mapping.insert(blank.clone(), base.genid()?); + } + let name = mapping.get(blank).unwrap().clone(); + let object = statement_factory.named_object(name); + new_statement.set_object(object); + } + new_graph.insert(new_statement); + } + + Ok(new_graph) + } } +// ------------------------------------------------------------------------------------------------ +// Public Types ❱ Factories +// ------------------------------------------------------------------------------------------------ + /// -/// The actual object storage type, reference counted for memory management. +/// A graph factory provides an interface to create a new graph. This allows for implementations +/// where underlying shared resources are required and so may be owned by the factory. +/// +/// The method for getting the initial factory instance is not specified here. By convention +/// implementors *may* provide a function `graph_factory` in the root module for their crate. /// -pub type GraphRef = Rc>; +pub trait GraphFactory: Debug + Provided { + type Literal: Literal; + type Statement: Statement; + type Graph: Graph; + + /// + /// Create a new graph instance. + /// + fn graph(&self) -> Self::Graph; + + /// + /// Create a new named graph instance. + /// + fn named_graph(&self, name: Option) -> Self::Graph; + + /// + /// Create a new graph instance from the given statements and prefix mappings. + /// + fn graph_from( + &self, + statements: &[Self::Statement], + prefix_mappings: Option, + ) -> Self::Graph; + + /// + /// Create a new graph instance from the given statements and prefix mappings. + /// + fn named_graph_from( + &self, + name: Option, + statements: &[Self::Statement], + prefix_mappings: Option, + ) -> Self::Graph; +} + +// ------------------------------------------------------------------------------------------------ +// Implementations ❱ Graph Names +// ------------------------------------------------------------------------------------------------ + +impl Display for GraphName { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match &self { + Self::BNode(node) => format!("_:{}", node), + Self::Iri(iri) => format!("<{}>", iri), + } + ) + } +} + +impl From for GraphName { + fn from(name: Name) -> Self { + Self::BNode(BlankNode::from(name)) + } +} + +impl From<&Name> for GraphName { + fn from(name: &Name) -> Self { + Self::BNode(BlankNode::from(name)) + } +} + +impl From for GraphName { + fn from(name: BlankNode) -> Self { + Self::BNode(name) + } +} + +impl From<&BlankNode> for GraphName { + fn from(name: &BlankNode) -> Self { + Self::BNode(name.clone()) + } +} + +impl From for GraphName { + fn from(name: Iri) -> Self { + Self::Iri(name) + } +} + +impl From<&Iri> for GraphName { + fn from(name: &Iri) -> Self { + Self::Iri(name.clone()) + } +} + +impl> From> for GraphName { + fn from(value: SubjectNode) -> Self { + match value { + SubjectNode::Blank(v) => Self::BNode(v.clone()), + SubjectNode::Resource(v) => Self::Iri(v.clone()), + _ => unreachable!(), + } + } +} + +impl GraphName { + /// + /// Construct a new graph name, as a blank node with a randomly assigned name. + /// + pub fn blank() -> Self { + Self::BNode(BlankNode::generate()) + } + + /// + /// Construct a new graph name, as a blank node with the specified name. + /// + pub fn blank_named(name: S) -> Result + where + S: AsRef, + { + Ok(Self::BNode(BlankNode::from_str(name.as_ref())?)) + } + + /// + /// Construct a new graph name, with an Iri naming a resource. + /// + pub fn named(name: Iri) -> Self { + Self::Iri(name) + } + + /// + /// Return `true` if this graph name is a blank node, else `false`. + /// + pub fn is_blank(&self) -> bool { + matches!(self, Self::BNode(_)) + } + + /// + /// Return a blank node string, if `self.is_blank()`, else `None`. + /// + pub fn as_blank(&self) -> Option<&BlankNode> { + match &self { + Self::BNode(s) => Some(s), + _ => None, + } + } + + /// + /// Return `true` if this graph name is an Iri, else `false`. + /// + pub fn is_iri(&self) -> bool { + matches!(self, Self::Iri(_)) + } + + /// + /// Return a named node Iri, if `self.is_iri()`, else `None`. + /// + pub fn as_iri(&self) -> Option<&Iri> { + match &self { + Self::Iri(u) => Some(u), + _ => None, + } + } +} // ------------------------------------------------------------------------------------------------ // Modules // ------------------------------------------------------------------------------------------------ pub mod mapping; -pub use mapping::{PrefixMappingRef, PrefixMappings}; - -pub mod named; -pub use named::NamedGraphRef; +pub use mapping::PrefixMapping; -pub mod skolem; +use super::literal::Literal; +use super::statement::StatementFactory; diff --git a/rdftk_core/src/model/graph/named.rs b/rdftk_core/src/model/graph/named.rs deleted file mode 100644 index 9b925d1..0000000 --- a/rdftk_core/src/model/graph/named.rs +++ /dev/null @@ -1,209 +0,0 @@ -/*! -An extension to the core `Graph` to support named graphs. The semantics of a named graph has been -derived from [RDF 1.1 TriG](https://www.w3.org/TR/trig/), _RDF Dataset Language_, and -[RDF 1.1: On Semantics of RDF Datasets](https://www.w3.org/TR/rdf11-datasets/). -*/ - -use crate::model::graph::Graph; -use crate::model::statement::{BlankNode, BlankNodeRef, SubjectNodeRef}; -use rdftk_iri::{Iri, IriRef, Name as NodeName}; -use std::cell::RefCell; -use std::fmt::{Display, Formatter}; -use std::rc::Rc; - -// ------------------------------------------------------------------------------------------------ -// Public Types ❱ Graph Names -// ------------------------------------------------------------------------------------------------ - -/// -/// This type denotes the identifier for a graph in a data set; a graph name MUST be either an Iri -/// or a blank node. -/// -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct GraphName(Name); - -/// -/// The actual graph name storage type, reference counted for memory management. -/// -pub type GraphNameRef = Rc; - -// ------------------------------------------------------------------------------------------------ -// Public Types ❱ Named Graphs -// ------------------------------------------------------------------------------------------------ - -/// -/// A named graph has an associated IRI or blank node that provided an identity for the graph -/// itself. -/// -pub trait NamedGraph: Graph { - /// - /// Returns `true` if this graph instance has a name. - /// - fn is_named(&self) -> bool { - self.name().is_some() - } - - /// - /// Return the name of this graph. - /// - fn name(&self) -> Option<&GraphNameRef>; - - /// - /// Set the name of this graph. - /// - fn set_name(&mut self, name: GraphNameRef); - - /// - /// Remove the name of this graph. - fn unset_name(&mut self); -} - -/// -/// The actual object storage type, reference counted for memory management. -/// -pub type NamedGraphRef = Rc>; - -// ------------------------------------------------------------------------------------------------ -// Private Types ❱ Graph Names -// ------------------------------------------------------------------------------------------------ - -#[allow(clippy::upper_case_acronyms)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -enum Name { - BNode(BlankNodeRef), - Iri(IriRef), -} - -// ------------------------------------------------------------------------------------------------ -// Implementations ❱ Graph Names -// ------------------------------------------------------------------------------------------------ - -impl Display for GraphName { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match &self.0 { - Name::BNode(node) => format!("_:{}", node), - Name::Iri(iri) => format!("<{}>", iri), - } - ) - } -} - -impl From for GraphName { - fn from(name: NodeName) -> Self { - GraphName(Name::BNode(BlankNode::from(name).into())) - } -} - -impl From<&NodeName> for GraphName { - fn from(name: &NodeName) -> Self { - GraphName(Name::BNode(BlankNode::from(name).into())) - } -} - -impl From for GraphName { - fn from(name: BlankNode) -> Self { - GraphName(Name::BNode(name.into())) - } -} - -impl From for GraphName { - fn from(name: BlankNodeRef) -> Self { - GraphName(Name::BNode(name)) - } -} - -impl From<&BlankNodeRef> for GraphName { - fn from(name: &BlankNodeRef) -> Self { - GraphName(Name::BNode(name.clone())) - } -} - -impl From for GraphName { - fn from(name: Iri) -> Self { - GraphName(Name::Iri(name.into())) - } -} - -impl From for GraphName { - fn from(name: IriRef) -> Self { - GraphName(Name::Iri(name)) - } -} - -impl From<&IriRef> for GraphName { - fn from(name: &IriRef) -> Self { - GraphName(Name::Iri(name.clone())) - } -} - -impl From for GraphName { - fn from(value: SubjectNodeRef) -> Self { - if let Some(blank) = value.as_blank() { - GraphName(Name::BNode(blank.clone())) - } else if let Some(iri) = value.as_iri() { - GraphName(Name::Iri(iri.clone())) - } else { - unreachable!() - } - } -} - -impl GraphName { - /// - /// Construct a new graph name, as a blank node with a randomly assigned name. - /// - pub fn blank() -> Self { - Self::from(BlankNode::generate()) - } - - /// - /// Construct a new graph name, as a blank node with the specified name. - /// - pub fn blank_named(name: NodeName) -> Self { - Self::from(name) - } - - /// - /// Construct a new graph name, with an Iri naming a resource. - /// - pub fn named(name: IriRef) -> Self { - Self::from(name) - } - - /// - /// Return `true` if this graph name is a blank node, else `false`. - /// - pub fn is_blank(&self) -> bool { - matches!(self.0, Name::BNode(_)) - } - - /// - /// Return a blank node string, if `self.is_blank()`, else `None`. - /// - pub fn as_blank(&self) -> Option<&BlankNode> { - match &self.0 { - Name::BNode(s) => Some(s), - _ => None, - } - } - - /// - /// Return `true` if this graph name is an Iri, else `false`. - /// - pub fn is_iri(&self) -> bool { - matches!(self.0, Name::Iri(_)) - } - - /// - /// Return a named node Iri, if `self.is_iri()`, else `None`. - /// - pub fn as_iri(&self) -> Option<&IriRef> { - match &self.0 { - Name::Iri(u) => Some(u), - _ => None, - } - } -} diff --git a/rdftk_core/src/model/graph/skolem.rs b/rdftk_core/src/model/graph/skolem.rs deleted file mode 100644 index dc895d3..0000000 --- a/rdftk_core/src/model/graph/skolem.rs +++ /dev/null @@ -1,59 +0,0 @@ -/*! -Support for the Skolemization process of a graph. For more details on the process, see -[Skolemization (Informative)](https://www.w3.org/TR/rdf11-mt/#skolemization-informative) -and [Replacing Blank Nodes with IRIs](https://www.w3.org/TR/rdf11-concepts/#section-skolemization). - -*/ - -use crate::error::{invalid_state_error, Error}; -use crate::model::graph::{Graph, GraphRef}; -use crate::model::statement::{BlankNodeRef, StatementRef}; -use rdftk_iri::{genid, IriRef}; -use std::collections::HashMap; -use std::rc::Rc; - -// ------------------------------------------------------------------------------------------------ -// Public Functions -// ------------------------------------------------------------------------------------------------ - -/// -/// Replace all blank nodes with new, unique Iris. This creates a new graph and leaves the initial -/// graph unchanged. The base Iri is used to create identifiers, it's path will be replaced -/// entirely by a well-known format. -/// -pub fn skolemize(graph: &impl Graph, base: &IriRef) -> Result { - let mut mapping: HashMap = Default::default(); - - let factory = graph.factory(); - - let new_graph = factory.graph(); - - for statement in graph.statements() { - let factory = graph.statement_factory(); - let mut new_statement: StatementRef = statement.clone(); - let mut_statement = match Rc::get_mut(&mut new_statement) { - None => return invalid_state_error().into(), - Some(st) => st, - }; - if let Some(blank) = mut_statement.subject().as_blank() { - if !mapping.contains_key(blank) { - let _ = mapping.insert(blank.clone(), genid(base)?); - } - let name = mapping.get(blank).unwrap().clone(); - let subject = factory.named_subject(name); - mut_statement.set_subject(subject); - } - if let Some(blank) = mut_statement.object().as_blank() { - if !mapping.contains_key(blank) { - let _ = mapping.insert(blank.clone(), genid(base)?); - } - let name = mapping.get(blank).unwrap().clone(); - let object = factory.named_object(name); - mut_statement.set_object(object); - } - let mut mut_graph = new_graph.borrow_mut(); - mut_graph.insert(new_statement); - } - - Ok(new_graph) -} diff --git a/rdftk_core/src/model/literal/data_type.rs b/rdftk_core/src/model/literal/data_type.rs deleted file mode 100644 index 3857e92..0000000 --- a/rdftk_core/src/model/literal/data_type.rs +++ /dev/null @@ -1,120 +0,0 @@ -use rdftk_iri::IriRef; -use rdftk_names::{rdf, xsd}; - -// ------------------------------------------------------------------------------------------------ -// Public Types -// ------------------------------------------------------------------------------------------------ - -/// -/// The set of known datatypes based on XML Schema, part 2. -/// -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum DataType { - /// Denotes a literal of type `xsd::string`. - String, - /// Denotes a literal of type `xsd::qname`. - QName, - /// Denotes a literal of type `xsd::anyURI`. - #[allow(clippy::upper_case_acronyms)] - Iri, - /// Denotes a literal of type `xsd::boolean`. - Boolean, - /// Denotes a literal of type `xsd::float`. - Float, - /// Denotes a literal of type `xsd::double`. - Double, - /// Denotes a literal of type `xsd::long`. - Long, - /// Denotes a literal of type `xsd::int`. - Int, - /// Denotes a literal of type `xsd::short`. - Short, - /// Denotes a literal of type `xsd::byte`. - Byte, - /// Denotes a literal of type `xsd::unsignedLong`. - UnsignedLong, - /// Denotes a literal of type `xsd::unsignedInt`. - UnsignedInt, - /// Denotes a literal of type `xsd::unsignedShort`. - UnsignedShort, - /// Denotes a literal of type `xsd::unsignedByte`. - UnsignedByte, - /// Denotes a literal of type `xsd::duration`. - Duration, - /// Denotes an escaped string containing XML content. - XmlLiteral, - /// Denotes a literal where the type is indicated by the provided `Iri`. - Other(IriRef), -} - -// ------------------------------------------------------------------------------------------------ -// Implementations -// ------------------------------------------------------------------------------------------------ - -impl From for DataType { - fn from(iri: IriRef) -> Self { - if &iri == xsd::string() { - DataType::String - } else if &iri == xsd::q_name() { - DataType::QName - } else if &iri == xsd::any_uri() { - DataType::Iri - } else if &iri == xsd::boolean() { - DataType::Boolean - } else if &iri == xsd::float() { - DataType::Float - } else if &iri == xsd::double() { - DataType::Double - } else if &iri == xsd::long() { - DataType::Long - } else if &iri == xsd::int() { - DataType::Int - } else if &iri == xsd::short() { - DataType::Short - } else if &iri == xsd::byte() { - DataType::Byte - } else if &iri == xsd::unsigned_long() { - DataType::UnsignedLong - } else if &iri == xsd::unsigned_int() { - DataType::UnsignedInt - } else if &iri == xsd::unsigned_short() { - DataType::UnsignedShort - } else if &iri == xsd::unsigned_byte() { - DataType::UnsignedByte - } else if &iri == xsd::duration() { - DataType::Duration - } else if &iri == rdf::xml_literal() { - DataType::XmlLiteral - } else { - DataType::Other(iri) - } - } -} - -impl DataType { - /// - /// Return the Iri representing this data type. Primarily these are the XML Schema data types - /// used for literal values. - /// - pub fn as_iri(&self) -> &IriRef { - match &self { - DataType::String => xsd::string(), - DataType::QName => xsd::q_name(), - DataType::Iri => xsd::any_uri(), - DataType::Boolean => xsd::boolean(), - DataType::Float => xsd::float(), - DataType::Double => xsd::double(), - DataType::Long => xsd::long(), - DataType::Int => xsd::int(), - DataType::Short => xsd::short(), - DataType::Byte => xsd::byte(), - DataType::UnsignedLong => xsd::unsigned_long(), - DataType::UnsignedInt => xsd::unsigned_int(), - DataType::UnsignedShort => xsd::unsigned_short(), - DataType::UnsignedByte => xsd::unsigned_byte(), - DataType::Duration => xsd::duration(), - DataType::XmlLiteral => rdf::xml_literal(), - DataType::Other(iri) => iri, - } - } -} diff --git a/rdftk_core/src/model/literal/factory.rs b/rdftk_core/src/model/literal/factory.rs deleted file mode 100644 index 8be3c46..0000000 --- a/rdftk_core/src/model/literal/factory.rs +++ /dev/null @@ -1,122 +0,0 @@ -/*! -Graphs may have mechanisms to cache commonly used values, or those with significant storage -overhead. In such cases they provide a value factory that should be used to construct new values -for use in the associated graph. It is possible that all graphs provided by some graph store share -a common value factory by store rather than by graph. -*/ - -use crate::error::Result; -use crate::model::literal::{DataType, LanguageTag, LiteralRef}; -use crate::model::Provided; -use rdftk_iri::IriRef; -use std::fmt::Debug; -use std::str::FromStr; -use std::sync::Arc; -use std::time::Duration; - -// ------------------------------------------------------------------------------------------------ -// Public Types -// ------------------------------------------------------------------------------------------------ - -/// -/// A value factory can be used to provide previously cached values rather than creating duplicates -/// within a graph. -/// -pub trait LiteralFactory: Debug + Provided { - /// Returns a cached *untyped* literal value with the provided string. - fn literal(&self, v: &str) -> LiteralRef; - - /// Returns a cached literal value with the provided string and language. - fn with_language(&self, v: &str, lang: LanguageTag) -> LiteralRef; - - /// Returns a cached literal value with the provided string and language. - fn with_language_str(&self, v: &str, lang: &str) -> Result { - Ok(self.with_language(v, LanguageTag::from_str(lang)?)) - } - - /// Returns a cached literal value with the provided string and data type. - fn with_data_type(&self, v: &str, data_type: DataType) -> LiteralRef; - - /// Returns a cached literal value with the provided string. - fn string(&self, v: &str) -> LiteralRef { - self.with_data_type(v, DataType::String) - } - - /// Returns a cached literal value with the provided QName. - fn qname(&self, v: &str) -> LiteralRef { - self.with_data_type(v, DataType::QName) - } - - /// Returns a cached literal value with the provided Iri. - fn uri(&self, v: &IriRef) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::Iri) - } - - /// Returns a cached literal value with the provided boolean. - fn boolean(&self, v: bool) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::Boolean) - } - - /// Returns a cached literal value with the provided float. - fn float(&self, v: f32) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::Float) - } - - /// Returns a cached literal value with the provided double. - fn double(&self, v: f64) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::Double) - } - - /// Returns a cached literal value with the provided long. - fn long(&self, v: i64) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::Long) - } - - /// Returns a cached literal value with the provided int. - fn int(&self, v: i32) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::Int) - } - - /// Returns a cached literal value with the provided short. - fn short(&self, v: i16) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::Short) - } - - /// Returns a cached literal value with the provided byte. - fn byte(&self, v: i8) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::Byte) - } - - /// Returns a cached literal value with the provided unsigned long. - fn unsigned_long(&self, v: u64) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::UnsignedLong) - } - - /// Returns a cached literal value with the provided unsigned int. - fn unsigned_int(&self, v: u32) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::UnsignedInt) - } - - /// Returns a cached literal value with the provided unsigned short. - fn unsigned_short(&self, v: u16) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::UnsignedShort) - } - - /// Returns a cached literal value with the provided unsigned byte. - fn unsigned_byte(&self, v: u8) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::UnsignedByte) - } - - /// Returns a cached literal value with the provided duration. - fn duration(&self, v: Duration) -> LiteralRef { - self.chrono_duration(chrono::Duration::from_std(v).unwrap()) - } - - /// Returns a cached literal value with the provided duration. - #[cfg(feature = "chrono_types")] - fn chrono_duration(&self, v: chrono::Duration) -> LiteralRef { - self.with_data_type(&v.to_string(), DataType::Duration) - } -} - -pub type LiteralFactoryRef = Arc; diff --git a/rdftk_core/src/model/literal/mod.rs b/rdftk_core/src/model/literal/mod.rs index ad86055..79d5721 100644 --- a/rdftk_core/src/model/literal/mod.rs +++ b/rdftk_core/src/model/literal/mod.rs @@ -11,11 +11,11 @@ * # Example * * ```rust -* use rdftk_core::model::literal::{Literal, DataType}; -* use rdftk_core::simple::literal::literal_factory; +* use rdftk_core::model::literal::{Literal, LiteralFactory, DataType}; +* use rdftk_core::simple::literal::SimpleLiteralFactory; * use std::time::Duration; * -* let factory = literal_factory(); +* let factory = SimpleLiteralFactory::default(); * * let string_literal = factory.literal("string value"); * assert_eq!(string_literal.lexical_form(), "string value"); @@ -39,12 +39,24 @@ * assert_eq!(duration_literal.data_type(), Some(&DataType::Duration)); * ``` * +* Graphs may have mechanisms to cache commonly used values, or those with significant storage +* overhead. In such cases they provide a value factory that should be used to construct new values +* for use in the associated graph. It is possible that all graphs provided by some graph store share +* a common value factory by store rather than by graph. */ -use crate::model::Equiv; -use std::fmt::{Debug, Display, Formatter}; -use std::hash::{Hash, Hasher}; -use std::rc::Rc; +use crate::error::Result; +use crate::model::Provided; +use rdftk_iri::Iri; +use rdftk_names::{rdf, xsd}; +use std::fmt::Debug; +use std::hash::Hash; +use std::str::FromStr; +use std::time::Duration; + +// ------------------------------------------------------------------------------------------------ +// Public Types ❱ Literals +// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ // Public Types @@ -53,10 +65,52 @@ use std::rc::Rc; // Re-export this pub use language_tags::LanguageTag; +/// +/// The set of known datatypes based on XML Schema, part 2. +/// +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum DataType { + /// Denotes a literal of type `xsd::string`. + String, + /// Denotes a literal of type `xsd::qname`. + QName, + /// Denotes a literal of type `xsd::anyURI`. + #[allow(clippy::upper_case_acronyms)] + Iri, + /// Denotes a literal of type `xsd::boolean`. + Boolean, + /// Denotes a literal of type `xsd::float`. + Float, + /// Denotes a literal of type `xsd::double`. + Double, + /// Denotes a literal of type `xsd::long`. + Long, + /// Denotes a literal of type `xsd::int`. + Int, + /// Denotes a literal of type `xsd::short`. + Short, + /// Denotes a literal of type `xsd::byte`. + Byte, + /// Denotes a literal of type `xsd::unsignedLong`. + UnsignedLong, + /// Denotes a literal of type `xsd::unsignedInt`. + UnsignedInt, + /// Denotes a literal of type `xsd::unsignedShort`. + UnsignedShort, + /// Denotes a literal of type `xsd::unsignedByte`. + UnsignedByte, + /// Denotes a literal of type `xsd::duration`. + Duration, + /// Denotes an escaped string containing XML content. + XmlLiteral, + /// Denotes a literal where the type is indicated by the provided `Iri`. + Other(Iri), +} + /// /// This trait describes an RDF literal which may be the object of a statement. /// -pub trait Literal: Debug { +pub trait Literal: Clone + Debug + Provided { /// Return the lexical form of this literal. fn lexical_form(&self) -> &String; @@ -77,78 +131,186 @@ pub trait Literal: Debug { /// Return this literal's language tag, if present. /// fn language(&self) -> Option<&LanguageTag>; - - /// - /// Return the factory that creates literals using the same provider as `self`. - /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. - /// - fn factory(&self) -> LiteralFactoryRef; } +// ------------------------------------------------------------------------------------------------ +// Public Types ❱ Factories +// ------------------------------------------------------------------------------------------------ + /// -/// The actual object storage type, reference counted for memory management. +/// A value factory can be used to provide previously cached values rather than creating duplicates +/// within a graph. /// -pub type LiteralRef = Rc; +pub trait LiteralFactory: Debug + Provided { + type Literal: Literal; -// ------------------------------------------------------------------------------------------------ -// Implementations -// ------------------------------------------------------------------------------------------------ + /// Returns a cached *untyped* literal value with the provided string. + fn literal(&self, v: &str) -> Self::Literal; -impl PartialEq for dyn Literal { - fn eq(&self, other: &dyn Literal) -> bool { - self.lexical_form() == other.lexical_form() - && self.data_type() == other.data_type() - && self.language() == other.language() + /// Returns a cached literal value with the provided string and language. + fn with_language(&self, v: &str, lang: LanguageTag) -> Self::Literal; + + /// Returns a cached literal value with the provided string and language. + fn with_language_str(&self, v: &str, lang: &str) -> Result { + Ok(self.with_language(v, LanguageTag::from_str(lang)?)) } -} -impl Eq for dyn Literal {} + /// Returns a cached literal value with the provided string and data type. + fn with_data_type(&self, v: &str, data_type: DataType) -> Self::Literal; -impl Hash for dyn Literal { - fn hash(&self, state: &mut H) { - self.lexical_form().hash(state); - self.data_type().hash(state); - self.language().hash(state); + /// Returns a cached literal value with the provided string and data type IRI. + fn with_data_type_iri(&self, v: &str, data_type: Iri) -> Self::Literal; + + /// Returns a cached literal value with the provided string. + fn string(&self, v: &str) -> Self::Literal { + self.with_data_type(v, DataType::String) } -} -impl Display for dyn Literal { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self.data_type() { - // Some(DataType::String) => write!(f, "\"{}\"", self.lexical_form()), - Some(DataType::Iri) => write!(f, "<{}>", self.lexical_form()), - // Some(DataType::Boolean) => write!(f, "{}", self.lexical_form()), - _ => { - write!( - f, - "\"{}\"{}", - self.lexical_form(), - match (self.data_type(), self.language()) { - (Some(data_type), None) => format!("^^<{}>", data_type.as_iri()), - (None, Some(language)) => format!("@{}", language), - _ => String::new(), - } - ) - } - } + /// Returns a cached literal value with the provided QName. + fn qname(&self, v: &str) -> Self::Literal { + self.with_data_type(v, DataType::QName) + } + + /// Returns a cached literal value with the provided Iri. + fn uri(&self, v: &Iri) -> Self::Literal { + self.with_data_type(v.as_ref(), DataType::Iri) + } + + /// Returns a cached literal value with the provided boolean. + fn boolean(&self, v: bool) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::Boolean) + } + + /// Returns a cached literal value with the provided float. + fn float(&self, v: f32) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::Float) } -} -impl Equiv for dyn Literal { - fn eqv(&self, other: &String) -> bool { - self.lexical_form() == other && self.data_type() == Some(&DataType::String) - || self.data_type().is_none() + /// Returns a cached literal value with the provided double. + fn double(&self, v: f64) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::Double) + } + + /// Returns a cached literal value with the provided long. + fn long(&self, v: i64) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::Long) + } + + /// Returns a cached literal value with the provided int. + fn int(&self, v: i32) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::Int) + } + + /// Returns a cached literal value with the provided short. + fn short(&self, v: i16) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::Short) + } + + /// Returns a cached literal value with the provided byte. + fn byte(&self, v: i8) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::Byte) + } + + /// Returns a cached literal value with the provided unsigned long. + fn unsigned_long(&self, v: u64) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::UnsignedLong) + } + + /// Returns a cached literal value with the provided unsigned int. + fn unsigned_int(&self, v: u32) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::UnsignedInt) + } + + /// Returns a cached literal value with the provided unsigned short. + fn unsigned_short(&self, v: u16) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::UnsignedShort) + } + + /// Returns a cached literal value with the provided unsigned byte. + fn unsigned_byte(&self, v: u8) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::UnsignedByte) + } + + /// Returns a cached literal value with the provided duration. + fn duration(&self, v: Duration) -> Self::Literal { + self.chrono_duration(chrono::Duration::from_std(v).unwrap()) + } + + /// Returns a cached literal value with the provided duration. + #[cfg(feature = "chrono_types")] + fn chrono_duration(&self, v: chrono::Duration) -> Self::Literal { + self.with_data_type(&v.to_string(), DataType::Duration) } } // ------------------------------------------------------------------------------------------------ -// Modules +// Implementations ❱ Data Types // ------------------------------------------------------------------------------------------------ -mod data_type; -pub use data_type::*; +impl From for DataType { + fn from(iri: Iri) -> Self { + if &iri == xsd::string() { + DataType::String + } else if &iri == xsd::q_name() { + DataType::QName + } else if &iri == xsd::any_uri() { + DataType::Iri + } else if &iri == xsd::boolean() { + DataType::Boolean + } else if &iri == xsd::float() { + DataType::Float + } else if &iri == xsd::double() { + DataType::Double + } else if &iri == xsd::long() { + DataType::Long + } else if &iri == xsd::int() { + DataType::Int + } else if &iri == xsd::short() { + DataType::Short + } else if &iri == xsd::byte() { + DataType::Byte + } else if &iri == xsd::unsigned_long() { + DataType::UnsignedLong + } else if &iri == xsd::unsigned_int() { + DataType::UnsignedInt + } else if &iri == xsd::unsigned_short() { + DataType::UnsignedShort + } else if &iri == xsd::unsigned_byte() { + DataType::UnsignedByte + } else if &iri == xsd::duration() { + DataType::Duration + } else if &iri == rdf::xml_literal() { + DataType::XmlLiteral + } else { + DataType::Other(iri) + } + } +} -mod factory; -pub use factory::*; +impl DataType { + /// + /// Return the Iri representing this data type. Primarily these are the XML Schema data types + /// used for literal values. + /// + pub fn as_iri(&self) -> &Iri { + match &self { + DataType::String => xsd::string(), + DataType::QName => xsd::q_name(), + DataType::Iri => xsd::any_uri(), + DataType::Boolean => xsd::boolean(), + DataType::Float => xsd::float(), + DataType::Double => xsd::double(), + DataType::Long => xsd::long(), + DataType::Int => xsd::int(), + DataType::Short => xsd::short(), + DataType::Byte => xsd::byte(), + DataType::UnsignedLong => xsd::unsigned_long(), + DataType::UnsignedInt => xsd::unsigned_int(), + DataType::UnsignedShort => xsd::unsigned_short(), + DataType::UnsignedByte => xsd::unsigned_byte(), + DataType::Duration => xsd::duration(), + DataType::XmlLiteral => rdf::xml_literal(), + DataType::Other(iri) => iri, + } + } +} diff --git a/rdftk_core/src/model/mod.rs b/rdftk_core/src/model/mod.rs index cf3f343..c14c1a6 100644 --- a/rdftk_core/src/model/mod.rs +++ b/rdftk_core/src/model/mod.rs @@ -20,21 +20,29 @@ pub trait Provided { fn provider_id(&self) -> &'static str; } -/// -/// Denotes equivalence between Self and some other type. Equivalence is a very specific, -/// non-symmetric, non-transitive, directed type to type equality. -/// -pub trait Equiv -where - T: Sized, -{ - /// Returns `true` if `other` is equivalent to `self`, else `false`. - fn eqv(&self, other: &T) -> bool; - - /// Returns `true` if `other` is **not** equivalent to `self`, else `false`. - fn not_eqv(&self, other: &T) -> bool { - !self.eqv(other) - } +pub trait Implementation { + type Literal: literal::Literal; + type Statement: statement::Statement; + type Graph: graph::Graph; + type DataSet: data_set::DataSet; + + fn data_set_factory( + &self, + ) -> &impl data_set::DataSetFactory; + + fn graph_factory( + &self, + ) -> &impl graph::GraphFactory< + Literal = Self::Literal, + Statement = Self::Statement, + Graph = Self::Graph, + >; + + fn statement_factory( + &self, + ) -> &impl statement::StatementFactory; + + fn literal_factory(&self) -> &impl literal::LiteralFactory; } // ------------------------------------------------------------------------------------------------ @@ -65,6 +73,4 @@ pub mod graph; pub mod literal; -pub mod qname; - pub mod statement; diff --git a/rdftk_core/src/model/qname.rs b/rdftk_core/src/model/qname.rs deleted file mode 100644 index 4cbb4f8..0000000 --- a/rdftk_core/src/model/qname.rs +++ /dev/null @@ -1,224 +0,0 @@ -/*! -* Qualified names, names with the form `{prefix}:{name}` are used in a number of common serialization -* forms and use many of the same production rules as those for XML. -* -* # Example -* -* ```rust -* use rdftk_core::model::qname::QName; -* use rdftk_iri::Name; -* use std::str::FromStr; -* -* let prefixed: QName = "prefix:name".parse().expect("parse error"); -* let un_prefixed: QName = "name".parse().expect("parse error"); -* -* let prefixed: QName = QName::new( -* Name::new_unchecked("prefix"), -* Name::new_unchecked("name"), -* ).unwrap(); -* let un_prefixed: QName = QName::new_unqualified(Name::new_unchecked("name")).unwrap(); -* -* assert!(QName::from_str("").is_err()); -* assert!(QName::from_str("hello world").is_err()); -* ``` -* -* # Specification -- QName -* -* 1. -* 2. -* 3. -* -* From (1): -* -* ```text -* /* Attribute Names for Namespace Declaration */ -* -* [4] NCName ::= Name - (Char* ':' Char*) /* An XML Name, minus the ":" */ -* -* /* Qualified Name */ -* -* [7] QName ::= PrefixedName -* | UnprefixedName -* [8] PrefixedName ::= Prefix ':' LocalPart -* [9] UnprefixedName ::= LocalPart -* [10] Prefix ::= NCName -* [11] LocalPart ::= NCName -* ``` -* -* From (2): -* -* ```text -* -* [4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] -* | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] -* | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] -* | [#x10000-#xEFFFF] -* [4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] -* | [#x203F-#x2040] -* [5] Name ::= NameStartChar (NameChar)* -* ``` -* -* # Specification -- Curie -* -* 1. -* -* ```text -* safe_curie := '[' curie ']' -* -* curie := [ [ prefix ] ':' ] reference -* -* prefix := NCName -* -* reference := irelative-ref (as defined in IRI) -* ``` -* -* Note that while the empty string matches the production for curie above, an empty string is NOT a -* valid CURIE. The CURIE prefix '_' is reserved for use by languages that support RDF. For this -* reason, the prefix '_' SHOULD be avoided by authors. -* -*/ - -use crate::error::{empty_qname_error, invalid_qname_error, Error as RdfError}; -use crate::model::statement::BLANK_NODE_NAMESPACE; -use rdftk_iri::{Name, NameParser}; -use std::fmt::{Display, Formatter}; -use std::str::FromStr; - -// ------------------------------------------------------------------------------------------------ -// Public Types -// ------------------------------------------------------------------------------------------------ - -/// -/// QNames are valid identifiers with an optional prefix identifier. e.g. "`xsd:integer`", -/// "`rdfs:Class`", "`:subPropertyOf`". -/// -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct QName { - prefix: Option, - name: Name, -} - -// ------------------------------------------------------------------------------------------------ -// Implementations -// ------------------------------------------------------------------------------------------------ - -const NAME_ONLY: usize = 1; -const PREFIX_AND_NAME: usize = 2; - -impl Display for QName { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}:{}", - if let Some(prefix) = &self.prefix { - prefix.to_string() - } else { - String::new() - }, - &self.name - ) - } -} - -impl FromStr for QName { - type Err = RdfError; - - fn from_str(s: &str) -> Result { - let name_parser = NameParser::Xml; - if s.is_empty() { - empty_qname_error().into() - } else { - let parts: Vec<&str> = s.split(':').collect(); - match parts.len() { - NAME_ONLY => { - let name = *parts.first().unwrap(); - if Name::is_valid_str(name, name_parser) { - Ok(QName { - prefix: None, - name: Name::from_str(name)?, - }) - } else { - invalid_qname_error(s).into() - } - } - PREFIX_AND_NAME => { - let prefix = *parts.first().unwrap(); - let name = *parts.get(1).unwrap(); - if Name::is_valid_str(prefix, name_parser) - && Name::is_valid_str(name, name_parser) - { - Ok(QName { - prefix: Some(Name::from_str(prefix)?), - name: Name::from_str(name)?, - }) - } else { - invalid_qname_error(s).into() - } - } - _ => invalid_qname_error(s).into(), - } - } - } -} - -impl QName { - /// Construct a new qualified QName: "`{prefix}:{name}`". This will return an error if either - /// the prefix or name is empty or is an invalid QName part. - pub fn new(prefix: Name, name: Name) -> Result { - Ok(Self::new_unchecked(Some(prefix), name)) - } - - /// Construct a new unqualified QName: "`:{name}`". This will return an error if either - /// the name is empty or is an invalid QName part. - pub fn new_unqualified(name: Name) -> Result { - Ok(Self::new_unchecked(None, name)) - } - - /// Construct a new QName **without** any validation checks on the given values. - pub fn new_unchecked(prefix: Option, name: Name) -> Self { - Self { prefix, name } - } - - /// Construct a new blank node as a QName. - pub fn new_blank(name: Name) -> Result { - Ok(Self::new_unchecked( - Some(Name::new_unchecked(BLANK_NODE_NAMESPACE)), - name, - )) - } - - /// Returns `true` if this QName is a blank node, else `false`. - pub fn is_blank(&self) -> bool { - self.prefix - .as_ref() - .map(|p| p.as_ref() == BLANK_NODE_NAMESPACE) - .is_some() - } - - /// Returns `true` if this QName has a prefix, else `false`. - pub fn has_prefix(&self) -> bool { - self.prefix.is_some() - } - - /// Returns the prefix part of this QName, if present. - pub fn prefix(&self) -> Option<&Name> { - self.prefix.as_ref() - } - - /// Returns the name part of this QName. - pub fn name(&self) -> &Name { - &self.name - } - - /// Format this QName as a Curie string. - pub fn as_curie(&self) -> String { - format!( - "[{}:{}]", - match &self.prefix { - None => "", - Some(prefix) => prefix.as_ref(), - }, - &self.name - ) - } -} diff --git a/rdftk_core/src/model/statement/bnode.rs b/rdftk_core/src/model/statement/bnode.rs index 72c949a..208f4cc 100644 --- a/rdftk_core/src/model/statement/bnode.rs +++ b/rdftk_core/src/model/statement/bnode.rs @@ -1,8 +1,5 @@ -use crate::model::qname::QName; -use rdftk_iri::Name; -use std::fmt::{Debug, Display, Formatter}; -use std::hash::Hash; -use std::rc::Rc; +use rdftk_iri::{Name, NameParser, QName}; +use std::fmt::{Display, Formatter}; use std::str::FromStr; use unique_id::sequence::SequenceGenerator as IDGenerator; use unique_id::Generator; @@ -17,11 +14,6 @@ use unique_id::Generator; #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct BlankNode(String); -/// -/// A reference counted wrapper around a [`BlankNode`] instance. -/// -pub type BlankNodeRef = Rc; - // ------------------------------------------------------------------------------------------------ // Public Values // ------------------------------------------------------------------------------------------------ @@ -50,7 +42,7 @@ impl FromStr for BlankNode { type Err = crate::error::Error; fn from_str(s: &str) -> std::result::Result { - if Self::is_valid_str(s) { + if BlankNode::is_valid_str(s) { Ok(Self(s.into())) } else { Err(crate::error::Error::InvalidBlankNodeName { name: s.into() }) @@ -101,8 +93,12 @@ impl BlankNode { /// `false`. Note that this function will accept simple names, or those /// with the reserved prefix `"_:"`. /// - pub fn is_valid_str(s: &str) -> bool { - is_bnode_name(if let Some(s) = s.strip_prefix(BLANK_NODE_PREFIX) { + pub fn is_valid_str(s: S) -> bool + where + S: AsRef, + { + let s: &str = s.as_ref(); + NameParser::BlankNode.is_valid_str(if let Some(s) = s.strip_prefix(BLANK_NODE_PREFIX) { s } else { s @@ -117,42 +113,3 @@ impl BlankNode { QName::new_blank(Name::new_unchecked(&self.0)).unwrap() } } - -// ------------------------------------------------------------------------------------------------ -// Private Functions -// ------------------------------------------------------------------------------------------------ - -pub(crate) fn is_bnode_name_start_char(c: char) -> bool { - c == ':' - || c.is_ascii_digit() - || c.is_ascii_uppercase() - || c == '_' - || c.is_ascii_lowercase() - || ('\u{C0}'..='\u{D6}').contains(&c) - || ('\u{D8}'..='\u{F6}').contains(&c) - || ('\u{0F8}'..='\u{2FF}').contains(&c) - || ('\u{370}'..='\u{37D}').contains(&c) - || ('\u{037F}'..='\u{1FFF}').contains(&c) - || ('\u{200C}'..='\u{200D}').contains(&c) - || ('\u{2070}'..='\u{218F}').contains(&c) - || ('\u{2C00}'..='\u{2FEF}').contains(&c) - || ('\u{3001}'..='\u{D7FF}').contains(&c) - || ('\u{F900}'..='\u{FDCF}').contains(&c) - || ('\u{FDF0}'..='\u{FFFD}').contains(&c) - || ('\u{10000}'..='\u{EFFFF}').contains(&c) -} - -pub(crate) fn is_bnode_name_char(c: char) -> bool { - is_bnode_name_start_char(c) - || c == '-' - || c == '.' - || c == '\u{B7}' - || ('\u{0300}'..='\u{036F}').contains(&c) - || ('\u{203F}'..='\u{2040}').contains(&c) -} - -pub(crate) fn is_bnode_name(s: &str) -> bool { - !s.is_empty() - && s.starts_with(is_bnode_name_start_char) - && s[1..].chars().all(is_bnode_name_char) -} diff --git a/rdftk_core/src/model/statement/factory.rs b/rdftk_core/src/model/statement/factory.rs deleted file mode 100644 index d56fb9d..0000000 --- a/rdftk_core/src/model/statement/factory.rs +++ /dev/null @@ -1,152 +0,0 @@ -use crate::error::Result; -use crate::model::literal::{LiteralFactoryRef, LiteralRef}; -use crate::model::statement::{BlankNodeRef, ObjectNodeRef, StatementRef, SubjectNodeRef}; -use crate::model::Provided; -use rdftk_iri::IriRef; -use std::fmt::Debug; -use std::str::FromStr; -use std::sync::Arc; - -use super::BlankNode; - -// ------------------------------------------------------------------------------------------------ -// Public Types -// ------------------------------------------------------------------------------------------------ - -/// -/// This trait provides a factory for construction of statements, and statement components. -/// -pub trait StatementFactory: Debug + Provided { - // -------------------------------------------------------------------------------------------- - // Whole statements - // -------------------------------------------------------------------------------------------- - - /// - /// Construct a new statement reference from the provided subject, predicate, and object. - /// - fn statement( - &self, - subject: SubjectNodeRef, - predicate: IriRef, - object: ObjectNodeRef, - ) -> Result; - - /// - /// Construct a new statement reference from the provided subject, predicate, and object. - /// - fn statement_with_predicate( - &self, - subject: StatementRef, - predicate: IriRef, - object: ObjectNodeRef, - ) -> Result; - - /// - /// Construct a new statement reference from the provided subject, predicate, and object. - /// - fn statement_with_object( - &self, - subject: StatementRef, - object: ObjectNodeRef, - ) -> Result; - - // -------------------------------------------------------------------------------------------- - // Subject nodes - // -------------------------------------------------------------------------------------------- - - /// - /// Construct a new subject node reference, as a blank node with a randomly assigned name. - /// - fn blank_subject_new(&self) -> SubjectNodeRef { - self.blank_subject(BlankNode::generate().into()) - } - - /// - /// Construct a new subject node reference, from the provided node. - /// - fn blank_subject(&self, name: BlankNodeRef) -> SubjectNodeRef; - - /// - /// Construct a new subject node reference, as a blank node with the specified name. - /// - fn blank_subject_named(&self, name: &str) -> Result { - Ok(self.blank_subject(BlankNode::from_str(name)?.into())) - } - - /// - /// Construct a new subject node, with an Iri naming a resource. - /// - fn named_subject(&self, name: IriRef) -> SubjectNodeRef; - - /// - /// Construct a new subject node, where the subject **is an** existing statement. This is - /// an extension specified by [RDF-star](https://w3c.github.io/rdf-star/cg-spec/editors_draft.html). - /// - fn statement_subject(&self, st: StatementRef) -> SubjectNodeRef; - - /// - /// Return a new subject node reference, which refers to this object. - /// - fn object_as_subject(&self, obj: ObjectNodeRef) -> Option; - - // -------------------------------------------------------------------------------------------- - // Object nodes - // -------------------------------------------------------------------------------------------- - - /// - /// Construct a new object node reference, as a blank node with a randomly assigned name. - /// - fn blank_object_new(&self) -> ObjectNodeRef { - self.blank_object(BlankNode::generate().into()) - } - - /// - /// Construct a new object node reference, as a blank node with the specified name. - /// - fn blank_object(&self, name: BlankNodeRef) -> ObjectNodeRef; - - /// - /// Construct a new object node reference, as a blank node with the specified name. - /// - fn blank_object_named(&self, name: &str) -> Result { - Ok(self.blank_object(BlankNode::from_str(name)?.into())) - } - - /// - /// Construct a new object node, with an Iri naming a resource. - /// - fn named_object(&self, name: IriRef) -> ObjectNodeRef; - - /// - /// Construct a new object node, with with a literal value. - /// - fn literal_object(&self, value: LiteralRef) -> ObjectNodeRef; - - /// - /// Construct a new object node, where the subject **is an** existing statement. This is - /// an extension specified by [RDF-star](https://w3c.github.io/rdf-star/cg-spec/editors_draft.html). - /// - fn statement_object(&self, st: StatementRef) -> ObjectNodeRef; - - /// - /// Return a new object node reference, which refers to this subject. - /// - fn subject_as_object(&self, st: SubjectNodeRef) -> ObjectNodeRef; - - // -------------------------------------------------------------------------------------------- - // Other Factories - // -------------------------------------------------------------------------------------------- - - /// - /// Return the factory that creates literals using the same provider as `self`. - /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. - /// - fn literal_factory(&self) -> LiteralFactoryRef; -} - -/// -/// A reference counted wrapper around a [`StatementFactory`] instance. -/// -pub type StatementFactoryRef = Arc; diff --git a/rdftk_core/src/model/statement/mod.rs b/rdftk_core/src/model/statement/mod.rs index e1ef5fd..1486293 100644 --- a/rdftk_core/src/model/statement/mod.rs +++ b/rdftk_core/src/model/statement/mod.rs @@ -14,23 +14,26 @@ * * * ```rust -* use rdftk_core::model::statement::{Statement, StatementList}; -* use rdftk_core::simple::statement::statement_factory; -* use rdftk_core::simple::literal::literal_factory; +* use rdftk_core::model::Implementation; +* use rdftk_core::model::literal::LiteralFactory; +* use rdftk_core::model::statement::{Statement, StatementFactory}; +* use rdftk_core::simple::Implementation as SimpleImplementation; +* use rdftk_core::simple::statement::SimpleStatement; * use rdftk_iri::Iri; * use std::rc::Rc; * use std::str::FromStr; * -* let factory = statement_factory(); -* let literals = literal_factory(); -* let mut statements: StatementList = Default::default(); +* let factories = SimpleImplementation::default(); +* let statement_factory = factories.statement_factory(); +* let literal_factory = factories.literal_factory(); +* let mut statements: Vec = Default::default(); * -* statements.push(factory.statement( -* factory.named_subject( +* statements.push(statement_factory.statement( +* statement_factory.named_subject( * Iri::from_str("http://en.wikipedia.org/wiki/Tony_Benn").unwrap().into() * ), * Iri::from_str("http://purl.org/dc/elements/1.1/title").unwrap().into(), -* factory.literal_object(literals.string("Tony Benn")), +* statement_factory.literal_object(literal_factory.string("Tony Benn")), * ).unwrap()); * ``` * @@ -41,180 +44,263 @@ use crate::error::Result; use crate::model::features::Featured; -use crate::model::literal::LiteralFactoryRef; -use rdftk_iri::IriRef; +use crate::model::literal::Literal; +use crate::model::Provided; +use rdftk_iri::Iri; use rdftk_names::rdf; -use std::fmt::{Debug, Display, Formatter}; -use std::hash::{Hash, Hasher}; -use std::rc::Rc; +use std::fmt::Debug; +use std::str::FromStr; +use std::sync::Arc; // ------------------------------------------------------------------------------------------------ -// Public Types +// Public Types ❱ Graphs // ------------------------------------------------------------------------------------------------ /// /// This trait models an RDF statement. /// -pub trait Statement: Debug + Featured { +pub trait Statement: Clone + Debug + Featured + Provided { + type Literal: Literal; + /// /// Return the subject of this statement. /// - fn subject(&self) -> &SubjectNodeRef; + fn subject(&self) -> &SubjectNode; /// /// Set the value of this statement's subject. /// - fn set_subject(&mut self, subject: SubjectNodeRef); + fn set_subject(&mut self, subject: SubjectNode); /// /// Return the predicate of this statement. /// - fn predicate(&self) -> &IriRef; + fn predicate(&self) -> &Iri; /// /// Set the value of this statement's predicate. /// - fn set_predicate(&mut self, predicate: IriRef); + fn set_predicate(&mut self, predicate: Iri); /// /// Return the object of this statement. /// - fn object(&self) -> &ObjectNodeRef; + fn object(&self) -> &ObjectNode; /// /// Set the value of this statement's object. /// - fn set_object(&mut self, object: ObjectNodeRef); + fn set_object(&mut self, object: ObjectNode); // -------------------------------------------------------------------------------------------- - // Factories + // Other // -------------------------------------------------------------------------------------------- /// - /// Return the factory that creates statements using the same provider as `self`. + /// This statement is considered nested if *either* subject or object is itself a statement + /// ([RDF-star](https://w3c.github.io/rdf-star/cg-spec/editors_draft.html)) + /// + fn is_nested(&self) -> bool { + self.subject().is_statement() || self.object().is_statement() + } /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. + /// Reify a single statement, returning the list of resulting statements. /// - fn factory(&self) -> StatementFactoryRef; + #[allow(clippy::type_complexity)] + fn reify>( + &self, + statement_factory: &F, + ) -> Result<(SubjectNode, Vec)> + where + Self: Sized, + { + let mut statements: Vec = Default::default(); + let new_subject = statement_factory.blank_subject_new(); + statements.push(statement_factory.statement( + new_subject.clone(), + rdf::a_type().clone(), + statement_factory.named_object(rdf::statement().clone()), + )?); + if let Some(statement) = self.subject().as_statement() { + let nested = statement.reify(statement_factory)?; + statements.extend(nested.1); + statements.push(statement_factory.statement( + new_subject.clone(), + rdf::subject().clone(), + statement_factory.subject_as_object(nested.0), + )?); + } else { + statements.push(statement_factory.statement( + new_subject.clone(), + rdf::subject().clone(), + statement_factory.subject_as_object(self.subject().clone()), + )?); + } + statements.push(statement_factory.statement( + new_subject.clone(), + rdf::predicate().clone(), + statement_factory.named_object(self.predicate().clone()), + )?); + if let Some(statement) = self.object().as_statement() { + let nested = statement.reify(statement_factory)?; + statements.extend(nested.1); + statements.push(statement_factory.statement( + new_subject.clone(), + rdf::object().clone(), + statement_factory.subject_as_object(nested.0), + )?); + } else { + statements.push(statement_factory.statement( + new_subject.clone(), + rdf::object().clone(), + self.object().clone(), + )?); + } + Ok((new_subject, statements)) + } +} + +// ------------------------------------------------------------------------------------------------ +// Public Types ❱ Factories +// ------------------------------------------------------------------------------------------------ + +/// +/// This trait provides a factory for construction of statements, and statement components. +/// +pub trait StatementFactory: Debug + Provided { + type Literal: Literal; + type Statement: Statement; + + // -------------------------------------------------------------------------------------------- + // Whole statements + // -------------------------------------------------------------------------------------------- /// - /// Return the factory that creates literals using the same provider as `self`. + /// Construct a new statement reference from the provided subject, predicate, and object. /// - /// Note that this uses Arc as a reference as factories are explicitly intended for cross-thread - /// usage. + fn statement( + &self, + subject: SubjectNode, + predicate: Iri, + object: ObjectNode, + ) -> Result; + /// - fn literal_factory(&self) -> LiteralFactoryRef; + /// Construct a new statement reference from the provided subject, predicate, and object. + /// + fn statement_with_predicate( + &self, + subject: Self::Statement, + predicate: Iri, + object: ObjectNode, + ) -> Result; + + /// + /// Construct a new statement reference from the provided subject, predicate, and object. + /// + fn statement_with_object( + &self, + subject: Self::Statement, + object: ObjectNode, + ) -> Result; + // -------------------------------------------------------------------------------------------- + // Subject nodes // -------------------------------------------------------------------------------------------- /// - /// This statement is considered nested if *either* subject or object is itself a statement - /// ([RDF-star](https://w3c.github.io/rdf-star/cg-spec/editors_draft.html)) + /// Construct a new subject node reference, as a blank node with a randomly assigned name. /// - fn is_nested(&self) -> bool { - self.subject().is_statement() || self.object().is_statement() + fn blank_subject_new(&self) -> SubjectNode { + self.blank_subject(BlankNode::generate()) } -} -/// -/// A reference counted wrapper around a [`Statement`] instance. -/// -pub type StatementRef = Rc; + /// + /// Construct a new subject node reference, from the provided node. + /// + fn blank_subject(&self, name: BlankNode) -> SubjectNode; -/// -/// A list of statements, this can be used to pass non-graph sets of statements. -/// -pub type StatementList = Vec; + /// + /// Construct a new subject node reference, as a blank node with the specified name. + /// + fn blank_subject_named( + &self, + name: &str, + ) -> Result> { + Ok(self.blank_subject(BlankNode::from_str(name)?)) + } -// ------------------------------------------------------------------------------------------------ -// Public Functions -// ------------------------------------------------------------------------------------------------ + /// + /// Construct a new subject node, with an Iri naming a resource. + /// + fn named_subject(&self, name: Iri) -> SubjectNode; -/// -/// Reify a single statement, returning the list of resulting statements. -/// -pub fn reify_statement( - st: &StatementRef, - factory: &StatementFactoryRef, -) -> Result<(SubjectNodeRef, Vec)> { - let mut statements: Vec = Default::default(); - let new_subject = factory.blank_subject_new(); - statements.push(factory.statement( - new_subject.clone(), - rdf::a_type().clone(), - factory.named_object(rdf::statement().clone()), - )?); - if st.subject().is_statement() { - let nested = reify_statement(st.subject().as_statement().unwrap(), factory)?; - statements.extend(nested.1); - statements.push(factory.statement( - new_subject.clone(), - rdf::subject().clone(), - factory.subject_as_object(nested.0), - )?); - } else { - statements.push(factory.statement( - new_subject.clone(), - rdf::subject().clone(), - factory.subject_as_object(st.subject().clone()), - )?); - } - statements.push(factory.statement( - new_subject.clone(), - rdf::predicate().clone(), - factory.named_object(st.predicate().clone()), - )?); - if st.object().is_statement() { - let nested = reify_statement(st.object().as_statement().unwrap(), factory)?; - statements.extend(nested.1); - statements.push(factory.statement( - new_subject.clone(), - rdf::object().clone(), - factory.subject_as_object(nested.0), - )?); - } else { - statements.push(factory.statement( - new_subject.clone(), - rdf::object().clone(), - st.object().clone(), - )?); - } - Ok((new_subject, statements)) -} + /// + /// Construct a new subject node, where the subject **is an** existing statement. This is + /// an extension specified by [RDF-star](https://w3c.github.io/rdf-star/cg-spec/editors_draft.html). + /// + fn statement_subject( + &self, + st: Arc, + ) -> SubjectNode; -// ------------------------------------------------------------------------------------------------ -// Implementations -// ------------------------------------------------------------------------------------------------ + /// + /// Return a new subject node reference, which refers to this object. + /// + fn object_as_subject( + &self, + obj: ObjectNode, + ) -> Option>; -impl PartialEq for dyn Statement { - fn eq(&self, other: &dyn Statement) -> bool { - self.subject() == other.subject() - && self.predicate() == other.predicate() - && self.object() == other.object() - } -} + // -------------------------------------------------------------------------------------------- + // Object nodes + // -------------------------------------------------------------------------------------------- -impl Eq for dyn Statement {} - -impl Display for dyn Statement { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{} <{}> {}", - &self.subject().to_string(), - &self.predicate().to_string(), - &self.object().to_string(), - ) + /// + /// Construct a new object node reference, as a blank node with a randomly assigned name. + /// + fn blank_object_new(&self) -> ObjectNode { + self.blank_object(BlankNode::generate()) } -} -impl Hash for dyn Statement { - fn hash(&self, state: &mut H) { - self.subject().hash(state); - self.predicate().hash(state); - self.object().hash(state); + /// + /// Construct a new object node reference, as a blank node with the specified name. + /// + fn blank_object(&self, name: BlankNode) -> ObjectNode; + + /// + /// Construct a new object node reference, as a blank node with the specified name. + /// + fn blank_object_named(&self, name: &str) -> Result> { + Ok(self.blank_object(BlankNode::from_str(name)?)) } + + /// + /// Construct a new object node, with an Iri naming a resource. + /// + fn named_object(&self, name: Iri) -> ObjectNode; + + /// + /// Construct a new object node, with with a literal value. + /// + fn literal_object(&self, value: Self::Literal) -> ObjectNode; + + /// + /// Construct a new object node, where the subject **is an** existing statement. This is + /// an extension specified by [RDF-star](https://w3c.github.io/rdf-star/cg-spec/editors_draft.html). + /// + fn statement_object( + &self, + st: Arc, + ) -> ObjectNode; + + /// + /// Return a new object node reference, which refers to this subject. + /// + fn subject_as_object( + &self, + st: SubjectNode, + ) -> ObjectNode; } // ------------------------------------------------------------------------------------------------ @@ -224,9 +310,6 @@ impl Hash for dyn Statement { mod bnode; pub use bnode::*; -mod factory; -pub use factory::*; - mod subject; pub use subject::*; diff --git a/rdftk_core/src/model/statement/object.rs b/rdftk_core/src/model/statement/object.rs index 101c10d..da08c7a 100644 --- a/rdftk_core/src/model/statement/object.rs +++ b/rdftk_core/src/model/statement/object.rs @@ -1,129 +1,174 @@ -use crate::model::literal::LiteralRef; -use crate::model::statement::{BlankNodeRef, StatementRef, SubjectNode, BLANK_NODE_NAMESPACE}; -use crate::model::Equiv; -use rdftk_iri::IriRef; -use std::fmt::{Display, Formatter}; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; -use std::rc::Rc; +use crate::model::literal::Literal; +use crate::model::statement::{BlankNode, Statement}; +use rdftk_iri::Iri; +use std::fmt::{Debug, Display, Formatter}; +use std::sync::Arc; + +use super::BLANK_NODE_NAMESPACE; // ------------------------------------------------------------------------------------------------ // Public Types // ------------------------------------------------------------------------------------------------ -/// -/// This trait models the *object* component of an RDF statement. -/// -pub trait ObjectNode: SubjectNode { - /// - /// Return `true` if this object is a literal value, else `false`. - /// - fn is_literal(&self) -> bool { - self.as_literal().is_some() - } - - /// - /// Return a literal value, if `self.is_literal()`, else `None`. - /// - fn as_literal(&self) -> Option<&LiteralRef>; +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum ObjectNode +where + L: Literal, + T: Statement, +{ + Blank(BlankNode), + Resource(Iri), + Literal(L), + Statement(Arc), } -/// -/// A reference counted wrapper around a [`ObjectNode`] instance. -/// -pub type ObjectNodeRef = Rc; - // ------------------------------------------------------------------------------------------------ // Implementations // ------------------------------------------------------------------------------------------------ -impl PartialEq for dyn ObjectNode { - fn eq(&self, other: &dyn ObjectNode) -> bool { - if self.is_blank() && other.is_blank() { - let lhs = self.as_blank().unwrap(); - let rhs = other.as_blank().unwrap(); - lhs == rhs - } else if self.is_iri() && other.is_iri() { - let lhs = self.as_iri().unwrap(); - let rhs = other.as_iri().unwrap(); - lhs == rhs - } else if self.is_statement() && other.is_statement() { - let lhs = self.as_statement().unwrap(); - let rhs = other.as_statement().unwrap(); - lhs == rhs - } else if self.is_literal() && other.is_literal() { - let lhs = self.as_literal().unwrap(); - let rhs = other.as_literal().unwrap(); - lhs == rhs - } else { - false - } +impl> From for ObjectNode { + fn from(v: BlankNode) -> Self { + Self::Blank(v) + } +} + +impl> From<&BlankNode> for ObjectNode { + fn from(v: &BlankNode) -> Self { + Self::Blank(v.clone()) } } -impl Eq for dyn ObjectNode {} +impl> From for ObjectNode { + fn from(v: Iri) -> Self { + Self::Resource(v) + } +} + +impl> From<&Iri> for ObjectNode { + fn from(v: &Iri) -> Self { + Self::Resource(v.clone()) + } +} -impl Hash for dyn ObjectNode { - fn hash(&self, state: &mut H) { - self.as_blank().hash(state); - self.as_iri().hash(state); - self.as_statement().hash(state); - self.as_literal().hash(state); +impl> From for ObjectNode { + fn from(v: L) -> Self { + Self::Literal(v) } } -impl Display for dyn ObjectNode { +impl> From> for ObjectNode { + fn from(v: Arc) -> Self { + Self::Statement(v) + } +} + +// ------------------------------------------------------------------------------------------------ + +impl + Display> Display for ObjectNode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - if let Some(node) = self.as_blank() { - write!(f, "{}:{}", BLANK_NODE_NAMESPACE, node) - } else if let Some(iri) = self.as_iri() { - write!(f, "<{}>", iri) - } else if let Some(literal) = self.as_literal() { - write!(f, "{}", literal) - } else if let Some(st) = self.as_statement() { - write!(f, "<< {} >>", st.deref()) - } else { - unreachable!() + match self { + Self::Blank(node) => write!(f, "{}:{}", BLANK_NODE_NAMESPACE, node), + Self::Resource(iri) => write!(f, "<{}>", iri), + Self::Literal(lit) => write!(f, "{}", lit), + Self::Statement(st) => write!(f, "<< {} >>", st), } } } -impl Equiv for dyn ObjectNode { - fn eqv(&self, other: &BlankNodeRef) -> bool { - if let Some(value) = self.as_blank() { - value == other - } else { - false +// ------------------------------------------------------------------------------------------------ + +impl> PartialEq for ObjectNode { + fn eq(&self, other: &BlankNode) -> bool { + match self { + Self::Blank(value) => value == other, + _ => false, } } } -impl Equiv for dyn ObjectNode { - fn eqv(&self, other: &IriRef) -> bool { - if let Some(value) = self.as_iri() { - value == other - } else { - false +impl> PartialEq for ObjectNode { + fn eq(&self, other: &Iri) -> bool { + match self { + Self::Resource(value) => value == other, + _ => false, } } } -impl Equiv for dyn ObjectNode { - fn eqv(&self, other: &StatementRef) -> bool { - if let Some(value) = self.as_statement() { - value == other - } else { - false +impl> PartialEq for ObjectNode { + fn eq(&self, other: &L) -> bool { + match self { + Self::Literal(value) => value == other, + _ => false, } } } -impl Equiv for dyn ObjectNode { - fn eqv(&self, other: &LiteralRef) -> bool { - if let Some(value) = self.as_literal() { - value == other - } else { - false +// +// This results in an error due to duplication with impl above, but not sure why. +// +//impl + PartialEq> PartialEq for ObjectNode { +// fn eq(&self, other: &T) -> bool { +// match self { +// Self::Statement(value) => as Borrow>::borrow(value) == other.borrow(), +// _ => false, +// } +// } +//} + +// ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ + +impl> ObjectNode { + pub fn is_blank(&self) -> bool { + matches!(self, Self::Blank(_)) + } + + pub fn as_blank(&self) -> Option<&BlankNode> { + match &self { + Self::Blank(v) => Some(v), + _ => None, + } + } + + pub fn is_resource(&self) -> bool { + matches!(self, Self::Resource(_)) + } + + pub fn as_resource(&self) -> Option<&Iri> { + match &self { + Self::Resource(v) => Some(v), + _ => None, + } + } + + pub fn is_literal(&self) -> bool { + matches!(self, Self::Literal(_)) + } + + pub fn as_literal(&self) -> Option<&L> { + match &self { + Self::Literal(v) => Some(v), + _ => None, + } + } + + pub fn is_statement(&self) -> bool { + matches!(self, Self::Statement(_)) + } + + pub fn as_statement(&self) -> Option> { + match &self { + Self::Statement(v) => Some(v.clone()), + _ => None, + } + } + + pub fn provider_id(&self) -> Option<&'static str> { + match self { + Self::Literal(v) => Some(v.provider_id()), + Self::Statement(v) => Some(v.provider_id()), + _ => None, } } } diff --git a/rdftk_core/src/model/statement/subject.rs b/rdftk_core/src/model/statement/subject.rs index 93334df..e2c76d2 100644 --- a/rdftk_core/src/model/statement/subject.rs +++ b/rdftk_core/src/model/statement/subject.rs @@ -1,175 +1,148 @@ -use crate::model::statement::{BlankNodeRef, StatementRef, BLANK_NODE_NAMESPACE}; -use crate::model::{Equiv, Provided}; -use rdftk_iri::IriRef; -use std::cmp::Ordering; +use super::BLANK_NODE_NAMESPACE; +use crate::model::literal::Literal; +use crate::model::statement::{BlankNode, Statement}; +use rdftk_iri::Iri; +use std::borrow::Borrow; use std::fmt::{Debug, Display, Formatter}; -use std::hash::{Hash, Hasher}; -use std::ops::Deref; -use std::rc::Rc; +use std::sync::Arc; // ------------------------------------------------------------------------------------------------ // Public Types // ------------------------------------------------------------------------------------------------ -/// -/// This trait models the *subject* component of an RDF statement. -/// -pub trait SubjectNode: Debug + Provided { - // -------------------------------------------------------------------------------------------- - // Inner type checks/accessors - // -------------------------------------------------------------------------------------------- - - /// - /// Return `true` if this subject is a blank node, else `false`. - /// - fn is_blank(&self) -> bool { - self.as_blank().is_some() - } - - /// - /// Return a blank node string, if `self.is_blank()`, else `None`. - /// - fn as_blank(&self) -> Option<&BlankNodeRef>; - - /// - /// Return `true` if this subject is an Iri, else `false`. - /// - fn is_iri(&self) -> bool { - self.as_iri().is_some() - } - - /// - /// Return a named node Iri, if `self.is_iri()`, else `None`. - /// - fn as_iri(&self) -> Option<&IriRef>; - - /// - /// Return `true` if this subject is an [RDF-star](https://w3c.github.io/rdf-star/cg-spec/editors_draft.html) statement, else `false`. - /// - fn is_statement(&self) -> bool { - self.as_statement().is_some() - } - - /// - /// Return a statement reference, if `self.is_statement()`, else `None`. - /// - fn as_statement(&self) -> Option<&StatementRef>; +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum SubjectNode +where + L: Literal, + T: Statement + Clone, +{ + Blank(BlankNode), + Resource(Iri), + Statement(Arc), } -/// -/// A reference counted wrapper around a [`SubjectNode`] instance. -/// -pub type SubjectNodeRef = Rc; - // ------------------------------------------------------------------------------------------------ // Implementations // ------------------------------------------------------------------------------------------------ -impl PartialEq for dyn SubjectNode { - fn eq(&self, other: &dyn SubjectNode) -> bool { - if self.is_blank() && other.is_blank() { - let lhs = self.as_blank().unwrap(); - let rhs = other.as_blank().unwrap(); - lhs == rhs - } else if self.is_iri() && other.is_iri() { - let lhs = self.as_iri().unwrap(); - let rhs = other.as_iri().unwrap(); - lhs == rhs - } else if self.is_statement() && other.is_statement() { - let lhs = self.as_statement().unwrap(); - let rhs = other.as_statement().unwrap(); - lhs == rhs - } else { - false - } +impl> From for SubjectNode { + fn from(v: BlankNode) -> Self { + Self::Blank(v) + } +} + +impl> From<&BlankNode> for SubjectNode { + fn from(v: &BlankNode) -> Self { + Self::Blank(v.clone()) + } +} + +impl> From for SubjectNode { + fn from(v: Iri) -> Self { + Self::Resource(v) } } -impl Eq for dyn SubjectNode {} +impl> From<&Iri> for SubjectNode { + fn from(v: &Iri) -> Self { + Self::Resource(v.clone()) + } +} + +impl> From> for SubjectNode { + fn from(v: Arc) -> Self { + Self::Statement(v) + } +} -impl Hash for dyn SubjectNode { - fn hash(&self, state: &mut H) { - self.as_blank().hash(state); - self.as_iri().hash(state); - self.as_statement().hash(state); +impl> From for SubjectNode { + fn from(v: T) -> Self { + Self::Statement(Arc::new(v)) } } -impl Display for dyn SubjectNode { +// ------------------------------------------------------------------------------------------------ + +impl + Display> Display for SubjectNode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - if let Some(node) = self.as_blank() { - write!(f, "{}:{}", BLANK_NODE_NAMESPACE, node) - } else if let Some(iri) = self.as_iri() { - write!(f, "<{}>", iri) - } else if let Some(st) = self.as_statement() { - write!(f, "<< {} >>", st.deref()) - } else { - unreachable!() + match self { + Self::Blank(node) => write!(f, "{}:{}", BLANK_NODE_NAMESPACE, node), + Self::Resource(iri) => write!(f, "<{}>", iri), + Self::Statement(st) => write!(f, "<< {} >>", st), } } } -impl Equiv for dyn SubjectNode { - fn eqv(&self, other: &BlankNodeRef) -> bool { - if let Some(value) = self.as_blank() { - value == other - } else { - false +// ------------------------------------------------------------------------------------------------ + +impl> PartialEq for SubjectNode { + fn eq(&self, other: &BlankNode) -> bool { + match self { + Self::Blank(value) => value == other, + _ => false, } } } -impl Equiv for dyn SubjectNode { - fn eqv(&self, other: &IriRef) -> bool { - if let Some(value) = self.as_iri() { - value == other - } else { - false +impl> PartialEq for SubjectNode { + fn eq(&self, other: &Iri) -> bool { + match self { + Self::Resource(value) => value == other, + _ => false, } } } -impl Equiv for dyn SubjectNode { - fn eqv(&self, other: &StatementRef) -> bool { - if let Some(value) = self.as_statement() { - value == other - } else { - false +impl + PartialEq> PartialEq for SubjectNode { + fn eq(&self, other: &T) -> bool { + match self { + Self::Statement(value) => as Borrow>::borrow(value) == other.borrow(), + _ => false, } } } -impl PartialOrd for dyn SubjectNode { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) +// ------------------------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------------------------ + +impl> SubjectNode { + pub fn is_blank(&self) -> bool { + matches!(self, Self::Blank(_)) } -} -impl Ord for dyn SubjectNode { - fn cmp(&self, other: &Self) -> Ordering { - if self.is_iri() && other.is_iri() { - if let Some(iri) = self.as_iri() { - if let Some(other_iri) = other.as_iri() { - return iri.cmp(other_iri); - } - } + pub fn as_blank(&self) -> Option<&BlankNode> { + match &self { + Self::Blank(s) => Some(s), + _ => None, } - if self.is_blank() && other.is_blank() { - if let Some(blank) = self.as_blank() { - if let Some(other_blank) = other.as_blank() { - return blank.cmp(other_blank); - } - } + } + + pub fn is_resource(&self) -> bool { + matches!(self, Self::Resource(_)) + } + + pub fn as_resource(&self) -> Option<&Iri> { + match &self { + Self::Resource(u) => Some(u), + _ => None, } - if self.is_statement() && other.is_statement() { - todo!("sorting rdf-star statements is not yet supported"); + } + + pub fn is_statement(&self) -> bool { + matches!(self, Self::Statement(_)) + } + + pub fn as_statement(&self) -> Option> { + match &self { + Self::Statement(st) => Some(st.clone()), + _ => None, } - if self.is_iri() { - Ordering::Less - } else if self.is_blank() { - Ordering::Greater - } else { - Ordering::Less + } + + pub fn provider_id(&self) -> Option<&'static str> { + match self { + Self::Statement(v) => Some(v.provider_id()), + _ => None, } } } diff --git a/rdftk_core/src/simple/data_set.rs b/rdftk_core/src/simple/data_set.rs index e243aa3..2183155 100644 --- a/rdftk_core/src/simple/data_set.rs +++ b/rdftk_core/src/simple/data_set.rs @@ -2,17 +2,13 @@ Simple, in-memory implementation of the `DataSet` and `DataSetFactory` traits. */ -use crate::model::data_set::{DataSet, DataSetFactory, DataSetFactoryRef, DataSetRef}; +use super::graph::SimpleGraph; +use crate::model::data_set::{DataSet, DataSetFactory}; use crate::model::features::Featured; -use crate::model::graph::{named::GraphNameRef, GraphFactoryRef, NamedGraphRef}; +use crate::model::graph::{Graph, GraphName}; use crate::model::Provided; -use crate::simple::graph_factory; -use lazy_static::lazy_static; -use rdftk_iri::IriRef; -use std::cell::RefCell; +use rdftk_iri::Iri; use std::collections::HashMap; -use std::rc::Rc; -use std::sync::Arc; // ------------------------------------------------------------------------------------------------ // Public Types @@ -23,33 +19,14 @@ use std::sync::Arc; /// #[derive(Clone, Debug)] pub struct SimpleDataSet { - graphs: HashMap, NamedGraphRef>, + graphs: HashMap, SimpleGraph>, } -// ------------------------------------------------------------------------------------------------ -// Public Functions -// ------------------------------------------------------------------------------------------------ - -/// -/// Retrieve the `DataSet` factory for `simple::SimpleDataSet` instances. -/// -pub fn data_set_factory() -> DataSetFactoryRef { - FACTORY.clone() -} - -// ------------------------------------------------------------------------------------------------ -// Private Types -// ------------------------------------------------------------------------------------------------ - /// /// Simple, in-memory implementation of the `DataSetFactory` trait. /// -#[derive(Clone, Debug)] -struct SimpleDataSetFactory {} - -lazy_static! { - static ref FACTORY: Arc = Arc::new(SimpleDataSetFactory {}); -} +#[derive(Clone, Debug, Default)] +pub struct SimpleDataSetFactory {} // ------------------------------------------------------------------------------------------------ // Implementations @@ -62,26 +39,27 @@ impl Provided for SimpleDataSetFactory { } impl DataSetFactory for SimpleDataSetFactory { - fn data_set(&self) -> DataSetRef { - Rc::new(RefCell::new(SimpleDataSet { - graphs: Default::default(), - })) - } + type Graph = SimpleGraph; + type DataSet = SimpleDataSet; - fn graph_factory(&self) -> GraphFactoryRef { - graph_factory() + fn data_set(&self) -> Self::DataSet { + SimpleDataSet { + graphs: Default::default(), + } } } // ------------------------------------------------------------------------------------------------ impl Featured for SimpleDataSet { - fn supports_feature(&self, _feature: &IriRef) -> bool { + fn supports_feature(&self, _feature: &Iri) -> bool { false } } impl DataSet for SimpleDataSet { + type Graph = SimpleGraph; + fn is_empty(&self) -> bool { self.graphs.is_empty() } @@ -94,19 +72,19 @@ impl DataSet for SimpleDataSet { // Accessors // -------------------------------------------------------------------------------------------- - fn contains_graph(&self, name: &Option) -> bool { + fn contains_graph(&self, name: &Option) -> bool { self.graphs.contains_key(name) } - fn graph(&self, name: &Option) -> Option<&NamedGraphRef> { + fn graph(&self, name: &Option) -> Option<&Self::Graph> { self.graphs.get(name) } - fn graph_mut(&mut self, name: &Option) -> Option<&mut NamedGraphRef> { + fn graph_mut(&mut self, name: &Option) -> Option<&mut Self::Graph> { self.graphs.get_mut(name) } - fn graphs(&self) -> Box + '_> { + fn graphs(&self) -> impl Iterator { Box::from(self.graphs.values()) } @@ -114,32 +92,20 @@ impl DataSet for SimpleDataSet { // Mutators // -------------------------------------------------------------------------------------------- - fn insert(&mut self, graph: NamedGraphRef) { - let graph_name = graph.borrow().name().cloned(); + fn insert(&mut self, graph: Self::Graph) { + let graph_name = graph.name().cloned(); let _ = self.graphs.insert(graph_name, graph); } - fn extend(&mut self, graphs: Vec) { + fn extend(&mut self, graphs: Vec) { graphs.into_iter().for_each(|g| self.insert(g)) } - fn remove(&mut self, name: &Option) { + fn remove(&mut self, name: &Option) { let _ = self.graphs.remove(name); } fn clear(&mut self) { self.graphs.clear(); } - - // -------------------------------------------------------------------------------------------- - // Factories - // -------------------------------------------------------------------------------------------- - - fn factory(&self) -> DataSetFactoryRef { - data_set_factory() - } - - fn graph_factory(&self) -> GraphFactoryRef { - graph_factory() - } } diff --git a/rdftk_core/src/simple/graph.rs b/rdftk_core/src/simple/graph.rs index 0d1cf02..dfd36ef 100644 --- a/rdftk_core/src/simple/graph.rs +++ b/rdftk_core/src/simple/graph.rs @@ -3,27 +3,14 @@ Simple, in-memory implementation of the `Graph` and `GraphFactory` traits. */ use crate::model::features::{Featured, FEATURE_GRAPH_DUPLICATES, FEATURE_RDF_STAR}; -use crate::model::graph::named::{GraphNameRef, NamedGraph}; -use crate::model::graph::{ - Graph, GraphFactory, GraphFactoryRef, GraphRef, NamedGraphRef, PrefixMappingRef, -}; -use crate::model::literal::LiteralFactoryRef; -use crate::model::statement::{ - ObjectNodeRef, StatementFactoryRef, StatementList, StatementRef, SubjectNodeRef, -}; +use crate::model::graph::{Graph, GraphFactory, GraphName, PrefixMapping}; +use crate::model::statement::Statement; use crate::model::Provided; -use crate::simple::literal::literal_factory; -use crate::simple::statement::statement_factory; -use lazy_static::lazy_static; -use rdftk_iri::IriRef; -use std::cell::RefCell; +use crate::simple::literal::SimpleLiteral; +use crate::simple::statement::{SimpleObjectNode, SimpleStatement, SimpleSubjectNode}; +use rdftk_iri::Iri; use std::collections::HashSet; -use std::iter::FromIterator; use std::ops::Deref; -use std::rc::Rc; -use std::sync::Arc; - -use super::mapping::default_mappings; // ------------------------------------------------------------------------------------------------ // Public Types @@ -34,35 +21,16 @@ use super::mapping::default_mappings; /// #[derive(Clone, Debug)] pub struct SimpleGraph { - name: Option, - statements: StatementList, - mappings: PrefixMappingRef, + name: Option, + statements: Vec, + mappings: PrefixMapping, } -// ------------------------------------------------------------------------------------------------ -// Public Functions -// ------------------------------------------------------------------------------------------------ - -/// -/// Retrieve the `GraphFactory` factory for `simple::SimpleGraph` instances. -/// -pub fn graph_factory() -> GraphFactoryRef { - FACTORY.clone() -} - -// ------------------------------------------------------------------------------------------------ -// Private Types -// ------------------------------------------------------------------------------------------------ - /// /// Simple, in-memory implementation of the `GraphFactory` trait. /// #[derive(Clone, Debug, Default)] -struct SimpleGraphFactory {} - -lazy_static! { - static ref FACTORY: Arc = Arc::new(SimpleGraphFactory::default()); -} +pub struct SimpleGraphFactory {} // ------------------------------------------------------------------------------------------------ // Implementations @@ -75,55 +43,47 @@ impl Provided for SimpleGraphFactory { } impl GraphFactory for SimpleGraphFactory { - fn graph(&self) -> GraphRef { - Rc::from(RefCell::from(self.create(None, &[], None))) + type Literal = SimpleLiteral; + type Statement = SimpleStatement; + type Graph = SimpleGraph; + + fn graph(&self) -> SimpleGraph { + self.create(None, &[], None) } - fn named_graph(&self, name: Option) -> crate::model::graph::NamedGraphRef { - Rc::from(RefCell::from(self.create(name, &[], None))) + fn named_graph(&self, name: Option) -> SimpleGraph { + self.create(name, &[], None) } fn graph_from( &self, - statements: &[StatementRef], - prefix_mappings: Option, - ) -> GraphRef { - Rc::from(RefCell::from(self.create( - None, - statements, - prefix_mappings, - ))) + statements: &[SimpleStatement], + prefix_mappings: Option, + ) -> Self::Graph { + self.create(None, statements, prefix_mappings) } fn named_graph_from( &self, - name: Option, - statements: &[StatementRef], - prefix_mappings: Option, - ) -> NamedGraphRef { - Rc::from(RefCell::from(self.create( - name, - statements, - prefix_mappings, - ))) - } - - fn statement_factory(&self) -> StatementFactoryRef { - statement_factory() + name: Option, + statements: &[SimpleStatement], + prefix_mappings: Option, + ) -> Self::Graph { + self.create(name, statements, prefix_mappings) } } impl SimpleGraphFactory { fn create( &self, - name: Option, - statements: &[StatementRef], - prefix_mappings: Option, + name: Option, + statements: &[SimpleStatement], + prefix_mappings: Option, ) -> SimpleGraph { let mut graph = SimpleGraph { name, statements: statements.to_vec(), - mappings: prefix_mappings.unwrap_or_else(|| default_mappings()), + mappings: prefix_mappings.unwrap_or_default(), }; for st in statements { @@ -134,15 +94,18 @@ impl SimpleGraphFactory { } } -// ------------------------------------------------------------------------------------------------ +// ---------------------------------------------------------------------------------------- impl Featured for SimpleGraph { - fn supports_feature(&self, feature: &IriRef) -> bool { + fn supports_feature(&self, feature: &Iri) -> bool { feature == FEATURE_GRAPH_DUPLICATES.deref() || feature == FEATURE_RDF_STAR.deref() } } impl Graph for SimpleGraph { + type Literal = SimpleLiteral; + type Statement = SimpleStatement; + fn is_empty(&self) -> bool { self.statements.is_empty() } @@ -151,22 +114,16 @@ impl Graph for SimpleGraph { self.statements.len() } - fn contains_subject(&self, subject: &SubjectNodeRef) -> bool { + fn contains_subject(&self, subject: &SimpleSubjectNode) -> bool { self.statements.iter().any(|st| st.subject() == subject) } - fn contains_individual(&self, subject: &IriRef) -> bool { - let factory = self.statement_factory(); - let subject = factory.named_subject(subject.clone()); - self.contains_subject(&subject) - } - fn matches( &self, - subject: Option<&SubjectNodeRef>, - predicate: Option<&IriRef>, - object: Option<&ObjectNodeRef>, - ) -> HashSet<&StatementRef> { + subject: Option<&SimpleSubjectNode>, + predicate: Option<&Iri>, + object: Option<&SimpleObjectNode>, + ) -> HashSet<&Self::Statement> { self.statements .iter() .filter(|st| { @@ -177,19 +134,19 @@ impl Graph for SimpleGraph { .collect() } - fn statements<'a>(&'a self) -> Box + 'a> { + fn statements(&self) -> impl Iterator { Box::new(self.statements.iter()) } - fn subjects(&self) -> HashSet<&SubjectNodeRef> { + fn subjects(&self) -> HashSet<&SimpleSubjectNode> { self.statements.iter().map(|st| st.subject()).collect() } - fn predicates(&self) -> HashSet<&IriRef> { + fn predicates(&self) -> HashSet<&Iri> { self.statements.iter().map(|st| st.predicate()).collect() } - fn predicates_for(&self, subject: &SubjectNodeRef) -> HashSet<&IriRef> { + fn predicates_for(&self, subject: &SimpleSubjectNode) -> HashSet<&Iri> { self.statements .iter() .filter_map(|st| { @@ -202,11 +159,15 @@ impl Graph for SimpleGraph { .collect() } - fn objects(&self) -> HashSet<&ObjectNodeRef> { + fn objects(&self) -> HashSet<&SimpleObjectNode> { self.statements.iter().map(|st| st.object()).collect() } - fn objects_for(&self, subject: &SubjectNodeRef, predicate: &IriRef) -> HashSet<&ObjectNodeRef> { + fn objects_for( + &self, + subject: &SimpleSubjectNode, + predicate: &Iri, + ) -> HashSet<&SimpleObjectNode> { self.statements .iter() .filter_map(|st| { @@ -219,31 +180,19 @@ impl Graph for SimpleGraph { .collect() } - fn prefix_mappings(&self) -> PrefixMappingRef { + fn prefix_mappings(&self) -> PrefixMapping { self.mappings.clone() } - fn set_prefix_mappings(&mut self, mappings: PrefixMappingRef) { + fn set_prefix_mappings(&mut self, mappings: PrefixMapping) { self.mappings = mappings; } - fn factory(&self) -> GraphFactoryRef { - graph_factory() + fn statements_mut(&mut self) -> impl Iterator { + self.statements.iter_mut() } - fn statement_factory(&self) -> StatementFactoryRef { - statement_factory() - } - - fn literal_factory(&self) -> LiteralFactoryRef { - literal_factory() - } - - fn statements_mut<'a>(&'a mut self) -> Box + 'a> { - Box::new(self.statements.iter_mut()) - } - - fn insert(&mut self, statement: StatementRef) { + fn insert(&mut self, statement: SimpleStatement) { self.statements.push(statement); } @@ -251,9 +200,9 @@ impl Graph for SimpleGraph { other.statements().for_each(|st| self.insert(st.clone())) } - fn dedup(&mut self) -> StatementList { + fn dedup(&mut self) -> Vec { let (keep, discard) = self.statements.iter().fold( - (HashSet::::default(), StatementList::default()), + (HashSet::::default(), Vec::default()), |(mut keep, mut discard), st| { if keep.contains(st) { discard.push(st.clone()); @@ -263,11 +212,11 @@ impl Graph for SimpleGraph { (keep, discard) }, ); - self.statements = StatementList::from_iter(keep); + self.statements = Vec::from_iter(keep); discard } - fn remove(&mut self, statement: &StatementRef) { + fn remove(&mut self, statement: &SimpleStatement) { for (idx, st) in self.statements.iter().enumerate() { if st == statement { let _ = self.statements.remove(idx); @@ -276,10 +225,10 @@ impl Graph for SimpleGraph { } } - fn remove_all_for(&mut self, subject: &SubjectNodeRef) -> StatementList { + fn remove_all_for(&mut self, subject: &SimpleSubjectNode) -> Vec { let (keep, discard) = self.statements.iter().fold( - (StatementList::default(), StatementList::default()), - |(mut keep, mut discard), st| { + (Default::default(), Default::default()), + |(mut keep, mut discard): (Vec, Vec), st| { if st.subject() == subject { keep.push(st.clone()); } else { @@ -295,14 +244,12 @@ impl Graph for SimpleGraph { fn clear(&mut self) { self.statements.clear() } -} -impl NamedGraph for SimpleGraph { - fn name(&self) -> Option<&GraphNameRef> { + fn name(&self) -> Option<&GraphName> { self.name.as_ref() } - fn set_name(&mut self, name: GraphNameRef) { + fn set_name(&mut self, name: GraphName) { self.name = Some(name); } @@ -310,19 +257,3 @@ impl NamedGraph for SimpleGraph { self.name = None; } } - -impl SimpleGraph { - /// - /// Return a reference to the current instance as a [`Graph`]. - /// - pub fn as_graph(&self) -> &impl Graph { - self - } - - /// - /// Return a reference to the current instance as a [`Named'\'Graph`]. - /// - pub fn as_named_graph(&self) -> &impl NamedGraph { - self - } -} diff --git a/rdftk_core/src/simple/indexed.rs b/rdftk_core/src/simple/indexed.rs index c22ec4a..64745ce 100644 --- a/rdftk_core/src/simple/indexed.rs +++ b/rdftk_core/src/simple/indexed.rs @@ -7,26 +7,16 @@ use crate::model::features::{ Featured, FEATURE_GRAPH_DUPLICATES, FEATURE_IDX_OBJECT, FEATURE_IDX_PREDICATE, FEATURE_IDX_SUBJECT, FEATURE_RDF_STAR, }; -use crate::model::graph::named::{GraphNameRef, NamedGraph}; -use crate::model::graph::{Graph, GraphFactory, GraphFactoryRef, GraphRef, PrefixMappingRef}; -use crate::model::literal::LiteralFactoryRef; -use crate::model::statement::{ - ObjectNodeRef, StatementFactoryRef, StatementList, StatementRef, SubjectNodeRef, -}; +use crate::model::graph::{Graph, GraphFactory, GraphName, PrefixMapping}; +use crate::model::statement::Statement; use crate::model::Provided; -use crate::simple::literal::literal_factory; -use crate::simple::statement::statement_factory; -use lazy_static::lazy_static; -use rdftk_iri::IriRef; -use std::cell::RefCell; +use crate::simple::literal::SimpleLiteral; +use crate::simple::statement::{SimpleObjectNode, SimpleStatement, SimpleSubjectNode}; +use rdftk_iri::Iri; use std::collections::{HashMap, HashSet}; use std::hash::Hash; use std::iter::FromIterator; use std::ops::Deref; -use std::rc::Rc; -use std::sync::Arc; - -use super::mapping::default_mappings; // ------------------------------------------------------------------------------------------------ // Public Types @@ -37,39 +27,19 @@ use super::mapping::default_mappings; /// #[derive(Clone, Debug)] pub struct IndexedSimpleGraph { - name: Option, - statements: StatementList, - mappings: PrefixMappingRef, - s_index: HashMap, - p_index: HashMap, - o_index: HashMap, + name: Option, + statements: Vec, + mappings: PrefixMapping, + s_index: HashMap>, + p_index: HashMap>, + o_index: HashMap>, } -// ------------------------------------------------------------------------------------------------ -// Public Functions -// ------------------------------------------------------------------------------------------------ - -/// -/// Retrieve the `GraphFactory` factory for `simple::SimpleGraph` instances. -/// -pub fn graph_factory() -> GraphFactoryRef { - FACTORY.clone() -} - -// ------------------------------------------------------------------------------------------------ -// Private Types -// ------------------------------------------------------------------------------------------------ - /// /// Simple, in-memory implementation of the `GraphFactory` trait. /// #[derive(Clone, Debug, Default)] -struct IndexedSimpleGraphFactory {} - -lazy_static! { - static ref FACTORY: Arc = - Arc::new(IndexedSimpleGraphFactory::default()); -} +pub struct IndexedSimpleGraphFactory {} // ------------------------------------------------------------------------------------------------ // Implementations @@ -82,58 +52,47 @@ impl Provided for IndexedSimpleGraphFactory { } impl GraphFactory for IndexedSimpleGraphFactory { - fn graph(&self) -> GraphRef { - Rc::from(RefCell::from(self.create(None, &[], None))) + type Literal = SimpleLiteral; + type Statement = SimpleStatement; + type Graph = IndexedSimpleGraph; + + fn graph(&self) -> Self::Graph { + self.create(None, &[], None) } - fn named_graph( - &self, - name: Option, - ) -> crate::model::graph::NamedGraphRef { - Rc::from(RefCell::from(self.create(name, &[], None))) + fn named_graph(&self, name: Option) -> Self::Graph { + self.create(name, &[], None) } fn graph_from( &self, - statements: &[StatementRef], - prefix_mappings: Option, - ) -> GraphRef { - Rc::from(RefCell::from(self.create( - None, - statements, - prefix_mappings, - ))) + statements: &[Self::Statement], + prefix_mappings: Option, + ) -> Self::Graph { + self.create(None, statements, prefix_mappings) } fn named_graph_from( &self, - name: Option, - statements: &[StatementRef], - prefix_mappings: Option, - ) -> crate::model::graph::NamedGraphRef { - Rc::from(RefCell::from(self.create( - name, - statements, - prefix_mappings, - ))) - } - - fn statement_factory(&self) -> StatementFactoryRef { - statement_factory() + name: Option, + statements: &[SimpleStatement], + prefix_mappings: Option, + ) -> Self::Graph { + self.create(name, statements, prefix_mappings) } } impl IndexedSimpleGraphFactory { fn create( &self, - name: Option, - statements: &[StatementRef], - prefix_mappings: Option, + name: Option, + statements: &[SimpleStatement], + prefix_mappings: Option, ) -> IndexedSimpleGraph { let mut graph = IndexedSimpleGraph { name, statements: statements.to_vec(), - mappings: prefix_mappings.unwrap_or_else(|| default_mappings()), + mappings: prefix_mappings.unwrap_or_default(), s_index: Default::default(), p_index: Default::default(), o_index: Default::default(), @@ -150,7 +109,7 @@ impl IndexedSimpleGraphFactory { // ------------------------------------------------------------------------------------------------ impl Featured for IndexedSimpleGraph { - fn supports_feature(&self, feature: &IriRef) -> bool { + fn supports_feature(&self, feature: &Iri) -> bool { feature == FEATURE_GRAPH_DUPLICATES.deref() || feature == FEATURE_RDF_STAR.deref() || feature == FEATURE_IDX_SUBJECT.deref() @@ -160,6 +119,9 @@ impl Featured for IndexedSimpleGraph { } impl Graph for IndexedSimpleGraph { + type Literal = SimpleLiteral; + type Statement = SimpleStatement; + fn is_empty(&self) -> bool { self.statements.is_empty() } @@ -168,23 +130,17 @@ impl Graph for IndexedSimpleGraph { self.statements.len() } - fn contains_subject(&self, subject: &SubjectNodeRef) -> bool { + fn contains_subject(&self, subject: &SimpleSubjectNode) -> bool { self.s_index.contains_key(subject) } - fn contains_individual(&self, subject: &IriRef) -> bool { - let factory = self.statement_factory(); - let subject = factory.named_subject(subject.clone()); - self.contains_subject(&subject) - } - fn matches( &self, - subject: Option<&SubjectNodeRef>, - predicate: Option<&IriRef>, - object: Option<&ObjectNodeRef>, - ) -> HashSet<&StatementRef> { - let s_sts: HashSet<&StatementRef> = subject + subject: Option<&SimpleSubjectNode>, + predicate: Option<&Iri>, + object: Option<&SimpleObjectNode>, + ) -> HashSet<&Self::Statement> { + let s_sts: HashSet<&Self::Statement> = subject .map(|subject| { self.s_index .get(subject) @@ -192,7 +148,7 @@ impl Graph for IndexedSimpleGraph { .unwrap_or_default() }) .unwrap_or_default(); - let p_sts: HashSet<&StatementRef> = predicate + let p_sts: HashSet<&Self::Statement> = predicate .map(|predicate| { self.p_index .get(predicate) @@ -200,7 +156,7 @@ impl Graph for IndexedSimpleGraph { .unwrap_or_default() }) .unwrap_or_default(); - let o_sts: HashSet<&StatementRef> = object + let o_sts: HashSet<&Self::Statement> = object .map(|object| { self.o_index .get(object) @@ -211,67 +167,59 @@ impl Graph for IndexedSimpleGraph { s_sts .intersection(&p_sts) .cloned() - .collect::>() + .collect::>() .intersection(&o_sts) .cloned() - .collect::>() + .collect::>() } - fn statements<'a>(&'a self) -> Box + 'a> { - Box::new(self.statements.iter()) + fn statements(&self) -> impl Iterator { + self.statements.iter() } - fn subjects(&self) -> HashSet<&SubjectNodeRef> { + fn subjects(&self) -> HashSet<&SimpleSubjectNode> { self.s_index.keys().collect() } - fn predicates(&self) -> HashSet<&IriRef> { + fn predicates(&self) -> HashSet<&Iri> { self.p_index.keys().collect() } - fn predicates_for(&self, subject: &SubjectNodeRef) -> HashSet<&IriRef> { + fn predicates_for(&self, subject: &SimpleSubjectNode) -> HashSet<&Iri> { self.s_index .get(subject) .map(|sts| sts.iter().map(|st| st.predicate()).collect()) .unwrap_or_default() } - fn objects(&self) -> HashSet<&ObjectNodeRef> { + fn objects(&self) -> HashSet<&SimpleObjectNode> { self.o_index.keys().collect() } - fn objects_for(&self, subject: &SubjectNodeRef, predicate: &IriRef) -> HashSet<&ObjectNodeRef> { + fn objects_for( + &self, + subject: &SimpleSubjectNode, + predicate: &Iri, + ) -> HashSet<&SimpleObjectNode> { self.matches(Some(subject), Some(predicate), None) .iter() .map(|st| st.object()) .collect() } - fn prefix_mappings(&self) -> PrefixMappingRef { + fn prefix_mappings(&self) -> PrefixMapping { self.mappings.clone() } - fn set_prefix_mappings(&mut self, mappings: PrefixMappingRef) { + fn set_prefix_mappings(&mut self, mappings: PrefixMapping) { self.mappings = mappings; } - fn factory(&self) -> GraphFactoryRef { - graph_factory() - } - - fn statement_factory(&self) -> StatementFactoryRef { - statement_factory() - } - - fn literal_factory(&self) -> LiteralFactoryRef { - literal_factory() - } - - fn statements_mut<'a>(&'a mut self) -> Box + 'a> { + fn statements_mut(&mut self) -> impl Iterator { Box::new(self.statements.iter_mut()) } - fn insert(&mut self, statement: StatementRef) { + fn insert(&mut self, statement: Self::Statement) { match self.s_index.get_mut(statement.subject()) { None => { let _ = self @@ -312,9 +260,12 @@ impl Graph for IndexedSimpleGraph { other.statements().for_each(|st| self.insert(st.clone())) } - fn dedup(&mut self) -> StatementList { + fn dedup(&mut self) -> Vec { let (keep, discard) = self.statements.iter().fold( - (HashSet::::default(), StatementList::default()), + ( + HashSet::::default(), + Vec::::default(), + ), |(mut keep, mut discard), st| { if keep.contains(st) { discard.push(st.clone()); @@ -324,14 +275,14 @@ impl Graph for IndexedSimpleGraph { (keep, discard) }, ); - self.statements = keep.into_iter().collect::(); + self.statements = keep.into_iter().collect::>(); for st in &discard { self.remove_indices_for(st); } discard } - fn remove(&mut self, statement: &StatementRef) { + fn remove(&mut self, statement: &Self::Statement) { for (idx, st) in self.statements.iter().enumerate() { if st == statement { let _ = self.statements.remove(idx); @@ -341,8 +292,8 @@ impl Graph for IndexedSimpleGraph { } } - fn remove_all_for(&mut self, subject: &SubjectNodeRef) -> StatementList { - let sts: Option = self.s_index.get(subject).map(|sts| sts.to_vec()); + fn remove_all_for(&mut self, subject: &SimpleSubjectNode) -> Vec { + let sts: Option> = self.s_index.get(subject).map(|sts| sts.to_vec()); if let Some(sts) = sts { for st in &sts { self.remove(st) @@ -359,14 +310,12 @@ impl Graph for IndexedSimpleGraph { self.p_index.clear(); self.o_index.clear(); } -} -impl NamedGraph for IndexedSimpleGraph { - fn name(&self) -> Option<&GraphNameRef> { + fn name(&self) -> Option<&GraphName> { self.name.as_ref() } - fn set_name(&mut self, name: GraphNameRef) { + fn set_name(&mut self, name: GraphName) { self.name = Some(name); } @@ -376,16 +325,16 @@ impl NamedGraph for IndexedSimpleGraph { } impl IndexedSimpleGraph { - fn remove_indices_for(&mut self, statement: &StatementRef) { + fn remove_indices_for(&mut self, statement: &SimpleStatement) { Self::remove_from_index(statement, statement.subject(), &mut self.s_index); Self::remove_from_index(statement, statement.predicate(), &mut self.p_index); Self::remove_from_index(statement, statement.object(), &mut self.o_index); } fn remove_from_index( - statement: &StatementRef, + statement: &SimpleStatement, key: &T, - index: &mut HashMap, + index: &mut HashMap>, ) { let _ = index.get_mut(key).map(|sts| { sts.iter().position(|st| st == statement).map(|idx| { diff --git a/rdftk_core/src/simple/literal.rs b/rdftk_core/src/simple/literal.rs index d3c6059..fd099bf 100644 --- a/rdftk_core/src/simple/literal.rs +++ b/rdftk_core/src/simple/literal.rs @@ -1,14 +1,14 @@ /*! Simple, in-memory implementation of the `Literal` and `LiteralFactory` traits. */ +use std::fmt::{Display, Formatter}; +use std::hash::Hash; + use crate::model::features::Featured; -use crate::model::literal::{DataType, Literal, LiteralFactory, LiteralFactoryRef, LiteralRef}; +use crate::model::literal::{DataType, Literal, LiteralFactory}; use crate::model::Provided; use language_tags::LanguageTag; -use lazy_static::lazy_static; -use rdftk_iri::IriRef; -use std::rc::Rc; -use std::sync::Arc; +use rdftk_iri::Iri; // ------------------------------------------------------------------------------------------------ // Public Types @@ -17,37 +17,18 @@ use std::sync::Arc; /// /// Simple, in-memory implementation of the `Literal` trait. /// -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug)] pub struct SimpleLiteral { lexical_form: String, data_type: Option, language: Option, } -// ------------------------------------------------------------------------------------------------ -// Public Functions -// ------------------------------------------------------------------------------------------------ - -/// -/// Retrieve the `LiteralFactory` factory for simple `simple::SimpleLiteral` instances. -/// -pub fn literal_factory() -> LiteralFactoryRef { - FACTORY.clone() -} - -// ------------------------------------------------------------------------------------------------ -// Private Types -// ------------------------------------------------------------------------------------------------ - /// /// Simple, in-memory implementation of the `LiteralFactory` trait. /// #[derive(Clone, Debug, Default)] -struct SimpleLiteralFactory {} - -lazy_static! { - static ref FACTORY: Arc = Arc::new(SimpleLiteralFactory::default()); -} +pub struct SimpleLiteralFactory {} // ------------------------------------------------------------------------------------------------ // Implementations @@ -60,34 +41,44 @@ impl Provided for SimpleLiteralFactory { } impl Featured for SimpleLiteralFactory { - fn supports_feature(&self, _: &IriRef) -> bool { + fn supports_feature(&self, _: &Iri) -> bool { false } } impl LiteralFactory for SimpleLiteralFactory { - fn literal(&self, v: &str) -> LiteralRef { - Rc::new(SimpleLiteral { + type Literal = SimpleLiteral; + + fn literal(&self, v: &str) -> Self::Literal { + SimpleLiteral { lexical_form: escape_string(v), data_type: None, language: None, - }) + } } - fn with_language(&self, v: &str, lang: LanguageTag) -> LiteralRef { - Rc::new(SimpleLiteral { + fn with_language(&self, v: &str, lang: LanguageTag) -> Self::Literal { + SimpleLiteral { lexical_form: escape_string(v), data_type: None, language: Some(lang), - }) + } } - fn with_data_type(&self, v: &str, data_type: DataType) -> LiteralRef { - Rc::new(SimpleLiteral { + fn with_data_type(&self, v: &str, data_type: DataType) -> Self::Literal { + SimpleLiteral { lexical_form: escape_string(v), data_type: Some(data_type), language: None, - }) + } + } + + fn with_data_type_iri(&self, v: &str, data_type: Iri) -> Self::Literal { + SimpleLiteral { + lexical_form: escape_string(v), + data_type: Some(DataType::Other(data_type)), + language: None, + } } } @@ -113,12 +104,129 @@ impl Literal for SimpleLiteral { fn language(&self) -> Option<&LanguageTag> { self.language.as_ref() } +} + +impl Display for SimpleLiteral { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.data_type() { + // Some(DataType::String) => write!(f, "\"{}\"", self.lexical_form()), + Some(DataType::Iri) => write!(f, "<{}>", self.lexical_form()), + // Some(DataType::Boolean) => write!(f, "{}", self.lexical_form()), + _ => { + write!( + f, + "\"{}\"{}", + self.lexical_form(), + match (self.data_type(), self.language()) { + (Some(data_type), None) => format!("^^<{}>", data_type.as_iri()), + (None, Some(language)) => format!("@{}", language), + _ => String::new(), + } + ) + } + } + } +} + +impl Provided for SimpleLiteral { + fn provider_id(&self) -> &'static str { + super::PROVIDER_ID + } +} + +impl PartialEq for SimpleLiteral { + fn eq(&self, other: &Self) -> bool { + self.lexical_form == other.lexical_form + && self.data_type == other.data_type + && self.language == other.language + } +} + +impl PartialEq for SimpleLiteral { + fn eq(&self, other: &String) -> bool { + self.lexical_form() == other + && (self.data_type().is_none() || self.data_type() == Some(&DataType::String)) + } +} + +impl PartialEq for SimpleLiteral { + fn eq(&self, other: &str) -> bool { + self.lexical_form() == other + && (self.data_type().is_none() || self.data_type() == Some(&DataType::String)) + } +} + +// Name + +// QName + +impl PartialEq for SimpleLiteral { + fn eq(&self, other: &Iri) -> bool { + *self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Iri) + } +} + +impl PartialEq for SimpleLiteral { + fn eq(&self, other: &bool) -> bool { + *self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Boolean) + } +} + +impl PartialEq for SimpleLiteral { + fn eq(&self, other: &f32) -> bool { + *self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Float) + } +} + +impl PartialEq for SimpleLiteral { + fn eq(&self, other: &f64) -> bool { + *self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Double) + } +} + +// Long + +// Into + +// Short + +impl PartialEq for SimpleLiteral { + fn eq(&self, other: &i8) -> bool { + *self.lexical_form() == other.to_string() && self.data_type() == Some(&DataType::Byte) + } +} - fn factory(&self) -> LiteralFactoryRef { - literal_factory() +// Unsigned Long + +// Unsigned Into + +// Unsigned Short + +impl PartialEq for SimpleLiteral { + fn eq(&self, other: &u8) -> bool { + *self.lexical_form() == other.to_string() + && self.data_type() == Some(&DataType::UnsignedByte) } } +// Duration + +// Xml Literal + +impl Eq for SimpleLiteral {} + +impl Hash for SimpleLiteral { + fn hash(&self, state: &mut H) { + self.lexical_form.hash(state); + self.data_type.hash(state); + self.language.hash(state); + } +} + +// ------------------------------------------------------------------------------------------------ +// Private Functions +// ------------------------------------------------------------------------------------------------ + fn escape_string(value: &str) -> String { let formatted = format!("{:?}", value); formatted[1..formatted.len() - 1].to_string() diff --git a/rdftk_core/src/simple/mapping.rs b/rdftk_core/src/simple/mapping.rs deleted file mode 100644 index 4952d85..0000000 --- a/rdftk_core/src/simple/mapping.rs +++ /dev/null @@ -1,128 +0,0 @@ -/*! -Simple, in-memory implementation of the `PrefixMappings` trait. -*/ - -use crate::model::graph::{PrefixMappingRef, PrefixMappings}; -use crate::model::qname::QName; -use bimap::BiHashMap; -use rdftk_iri::{IriExtra, IriRef, Name}; -use std::cell::RefCell; -use std::rc::Rc; - -// ------------------------------------------------------------------------------------------------ -// Public Functions -// ------------------------------------------------------------------------------------------------ - -/// -/// Create a new prefix mapping instance with default mappings. -/// -#[inline] -pub fn default_mappings() -> PrefixMappingRef { - SimplePrefixMappings::default().into() -} - -/// -/// Create a new prefix mapping instance with the RDF, RDF Schema, and XML Namespace mappings. -/// -#[inline] -pub fn common_mappings() -> PrefixMappingRef { - SimplePrefixMappings::default() - .with_owl() - .with_rdf() - .with_rdfs() - .with_xsd() - .into() -} - -// ------------------------------------------------------------------------------------------------ -// Private Types -// ------------------------------------------------------------------------------------------------ - -/// -/// Simple, in-memory implementation of the `PrefixMappings` trait. -/// -#[derive(Clone, Debug, Default)] -struct SimplePrefixMappings { - map: BiHashMap, IriRef>, -} - -// ------------------------------------------------------------------------------------------------ -// Implementations -// ------------------------------------------------------------------------------------------------ - -impl From for PrefixMappingRef { - fn from(v: SimplePrefixMappings) -> Self { - Rc::new(RefCell::new(v)) - } -} - -impl PrefixMappings for SimplePrefixMappings { - fn is_empty(&self) -> bool { - self.map.is_empty() - } - - fn len(&self) -> usize { - self.map.len() - } - - fn get_default_namespace(&self) -> Option<&IriRef> { - self.map.get_by_left(&None) - } - - fn set_default_namespace(&mut self, iri: IriRef) { - let _ = self.map.insert(None, iri); - } - - fn remove_default_namespace(&mut self) { - let _ = self.map.remove_by_left(&None); - } - - fn get_namespace(&self, prefix: &Name) -> Option<&IriRef> { - self.map.get_by_left(&Some(prefix.clone())) - } - - fn get_prefix(&self, namespace: &IriRef) -> Option<&Option> { - self.map.get_by_right(namespace) - } - - fn mappings<'a>(&'a self) -> Box, &'a IriRef)> + 'a> { - Box::new(self.map.iter()) - } - - fn insert(&mut self, prefix: Name, iri: IriRef) { - let _ = self.map.insert(Some(prefix), iri); - } - - fn remove(&mut self, prefix: &Name) { - let _ = self.map.remove_by_left(&Some(prefix.clone())); - } - - fn clear(&mut self) { - self.map.clear(); - } - - fn expand(&self, qname: &QName) -> Option { - let prefix = if let Some(prefix) = qname.prefix() { - self.get_namespace(prefix) - } else { - self.get_default_namespace() - }; - match prefix { - None => None, - Some(namespace) => namespace.make_name(qname.name().clone()).map(IriRef::from), - } - } - - fn compress(&self, iri: &IriRef) -> Option { - let (iri, name) = if let Some((iri, name)) = iri.split() { - (iri, name) - } else { - return None; - }; - match self.get_prefix(&IriRef::from(iri)) { - None => None, - Some(None) => Some(QName::new_unqualified(name).unwrap()), - Some(Some(prefix)) => Some(QName::new(prefix.clone(), name).unwrap()), - } - } -} diff --git a/rdftk_core/src/simple/mod.rs b/rdftk_core/src/simple/mod.rs index 5d98b21..ecaeea0 100644 --- a/rdftk_core/src/simple/mod.rs +++ b/rdftk_core/src/simple/mod.rs @@ -9,6 +9,8 @@ This module contains the types implementing the abstract RDF model described in // Public Types // ------------------------------------------------------------------------------------------------ +use std::marker::PhantomData; + /// /// The identifier for the simple model provider. /// @@ -20,22 +22,70 @@ pub const PROVIDER_ID: &str = concat!( env!("CARGO_PKG_VERSION") ); +#[derive(Clone, Debug, Default)] +pub struct Implementation { + private: PhantomData, +} + +// ------------------------------------------------------------------------------------------------ +// Implementations +// ------------------------------------------------------------------------------------------------ + +impl crate::model::Implementation for Implementation { + type Literal = literal::SimpleLiteral; + type Statement = statement::SimpleStatement; + type Graph = graph::SimpleGraph; + type DataSet = data_set::SimpleDataSet; + + fn data_set_factory( + &self, + ) -> &impl crate::model::data_set::DataSetFactory + { + const FACTORY: data_set::SimpleDataSetFactory = data_set::SimpleDataSetFactory {}; + &FACTORY + } + + fn graph_factory( + &self, + ) -> &impl crate::model::graph::GraphFactory< + Literal = Self::Literal, + Statement = Self::Statement, + Graph = Self::Graph, + > { + const FACTORY: graph::SimpleGraphFactory = graph::SimpleGraphFactory {}; + &FACTORY + } + + fn statement_factory( + &self, + ) -> &impl crate::model::statement::StatementFactory< + Literal = Self::Literal, + Statement = Self::Statement, + > { + const FACTORY: statement::SimpleStatementFactory = statement::SimpleStatementFactory {}; + &FACTORY + } + + fn literal_factory( + &self, + ) -> &impl crate::model::literal::LiteralFactory { + const FACTORY: literal::SimpleLiteralFactory = literal::SimpleLiteralFactory {}; + &FACTORY + } +} + // ------------------------------------------------------------------------------------------------ // Modules // ------------------------------------------------------------------------------------------------ pub mod data_set; -pub use data_set::data_set_factory; pub mod graph; -pub use graph::graph_factory; pub mod indexed; pub mod literal; -pub mod mapping; - pub mod resource; pub mod statement; diff --git a/rdftk_core/src/simple/resource.rs b/rdftk_core/src/simple/resource.rs index e101746..5677348 100644 --- a/rdftk_core/src/simple/resource.rs +++ b/rdftk_core/src/simple/resource.rs @@ -20,12 +20,14 @@ * writing out or constructing a `Graph` instance. * * ```rust -* use rdftk_core::simple::literal::literal_factory; +* use rdftk_core::model::Implementation; +* use rdftk_core::model::literal::LiteralFactory; +* use rdftk_core::simple::Implementation as SimpleImplementation; * use rdftk_core::simple::resource::Resource; +* use rdftk_core::simple::statement::SimpleStatement; * use rdftk_iri::Iri; * use rdftk_names::{dc::elements as dc, foaf, rdf}; * use std::str::FromStr; -* use rdftk_core::model::statement::StatementList; * * fn contact(name: &str) -> Iri { * Iri::from_str(&format!( @@ -35,20 +37,23 @@ * .unwrap() * } * +* let implementation = SimpleImplementation::default(); +* let literal_factory = implementation.literal_factory(); +* * let resource = * Resource::named(Iri::from_str("http://en.wikipedia.org/wiki/Tony_Benn").unwrap().into()) -* .value_of(dc::publisher().clone(), literal_factory().literal("Wikipedia")) -* .value_of(dc::title().clone(), literal_factory().literal("Tony Benn")) +* .value_of(dc::publisher().clone(), literal_factory.literal("Wikipedia")) +* .value_of(dc::title().clone(), literal_factory.literal("Tony Benn")) * .resource( * dc::description().clone(), * Resource::blank() * .resource_named(rdf::a_type().clone(), foaf::person().clone()) -* .value_of(foaf::name().clone(), literal_factory().literal("Tony Benn")) +* .value_of(foaf::name().clone(), literal_factory.literal("Tony Benn")) * .to_owned(), * ) * .to_owned(); * -* let sts: StatementList = resource.into(); +* let sts: Vec = resource.into(); * assert_eq!(sts.len(), 5); * * for st in sts { @@ -70,15 +75,14 @@ */ use crate::error::{provider_mismatch_error, Result}; -use crate::model::literal::{DataType, LiteralFactoryRef, LiteralRef}; -use crate::model::statement::{StatementFactoryRef, StatementList, SubjectNodeRef}; -use crate::simple; -use crate::simple::literal::literal_factory; +use crate::model::literal::{DataType, LiteralFactory}; +use crate::model::statement::StatementFactory; +use crate::model::Provided; +use crate::simple::literal::{SimpleLiteral, SimpleLiteralFactory}; +use crate::simple::statement::{SimpleStatement, SimpleStatementFactory, SimpleSubjectNode}; use language_tags::LanguageTag; -use rdftk_iri::IriRef; +use rdftk_iri::Iri; use rdftk_names::rdf; -use simple::statement::statement_factory; -use std::cell::RefCell; use std::collections::HashMap; use std::str::FromStr; @@ -91,10 +95,10 @@ use std::str::FromStr; /// #[derive(Clone, Debug)] pub struct Resource { - subject: SubjectNodeRef, - statement_factory: StatementFactoryRef, - literal_factory: LiteralFactoryRef, - predicates: HashMap>>, + subject: SimpleSubjectNode, + statement_factory: SimpleStatementFactory, + literal_factory: SimpleLiteralFactory, + predicates: HashMap>, } /// @@ -102,7 +106,7 @@ pub struct Resource { /// #[derive(Clone, Debug)] pub struct Predicate { - name: IriRef, + name: Iri, objects: Vec, } @@ -114,8 +118,8 @@ pub struct Predicate { enum ResourceObject { Resource(Resource), Resources(Container), - Literal(LiteralRef), - Literals(Container), + Literal(SimpleLiteral), + Literals(Container), } #[derive(Clone, Debug)] @@ -123,7 +127,7 @@ enum ContainerKind { Alt, Bag, Seq, - Other(IriRef), + Other(Iri), } #[derive(Clone, Debug)] @@ -140,7 +144,7 @@ impl Predicate { /// /// Construct a new Predicate instance with the provided `Iri` name. /// - pub fn new(name: IriRef) -> Self { + pub fn new(name: Iri) -> Self { Self { name, objects: Default::default(), @@ -152,7 +156,7 @@ impl Predicate { /// /// Add a new property object, a literal value, to this predicate. /// - pub fn property(&mut self, value: LiteralRef) -> &mut Self { + pub fn property(&mut self, value: SimpleLiteral) -> &mut Self { self.objects.push(ResourceObject::Literal(value)); self } @@ -162,7 +166,7 @@ impl Predicate { /// /// The value of this property object is a container denoting the provided values as alternatives. /// - pub fn property_alternatives(&mut self, values: &[LiteralRef]) -> &mut Self { + pub fn property_alternatives(&mut self, values: &[SimpleLiteral]) -> &mut Self { self.objects.push(ResourceObject::Literals(Container { kind: ContainerKind::Alt, values: values.to_vec(), @@ -174,7 +178,7 @@ impl Predicate { /// The value of this property object is a container denoting the provided values as an /// unordered bag. /// - pub fn property_bag(&mut self, values: &[LiteralRef]) -> &mut Self { + pub fn property_bag(&mut self, values: &[SimpleLiteral]) -> &mut Self { self.objects.push(ResourceObject::Literals(Container { kind: ContainerKind::Bag, values: values.to_vec(), @@ -186,7 +190,7 @@ impl Predicate { /// The value of this property object is a container denoting the provided values as an ordered /// sequence. /// - pub fn property_sequence(&mut self, values: &[LiteralRef]) -> &mut Self { + pub fn property_sequence(&mut self, values: &[SimpleLiteral]) -> &mut Self { self.objects.push(ResourceObject::Literals(Container { kind: ContainerKind::Seq, values: values.to_vec(), @@ -198,7 +202,7 @@ impl Predicate { /// The value of this property object is a container of the provided values with a specified /// type. /// - pub fn property_container(&mut self, values: &[LiteralRef], kind: IriRef) -> &mut Self { + pub fn property_container(&mut self, values: &[SimpleLiteral], kind: Iri) -> &mut Self { self.objects.push(ResourceObject::Literals(Container { kind: ContainerKind::Other(kind), values: values.to_vec(), @@ -220,7 +224,7 @@ impl Predicate { /// /// Add a new resource object, an Iri, to this predicate. /// - pub fn resource_named(&mut self, name: IriRef) -> &mut Self { + pub fn resource_named(&mut self, name: Iri) -> &mut Self { self.objects .push(ResourceObject::Resource(Resource::named(name))); self @@ -275,7 +279,7 @@ impl Predicate { /// The value of this resource object is a container of the provided values with a specified /// type. /// - pub fn resource_container(&mut self, values: &[Resource], kind: IriRef) -> &mut Self { + pub fn resource_container(&mut self, values: &[Resource], kind: Iri) -> &mut Self { self.objects.push(ResourceObject::Resources(Container { kind: ContainerKind::Other(kind), values: values.to_vec(), @@ -286,9 +290,9 @@ impl Predicate { // ------------------------------------------------------------------------------------------------ -impl From for StatementList { +impl From for Vec { fn from(resource: Resource) -> Self { - let mut sts: StatementList = Vec::default(); + let mut sts = Vec::default(); flatten(&resource, &mut sts); sts } @@ -299,12 +303,16 @@ impl Resource { /// Construct a new `Resource` with the subject cloned from an existing /// [`SubjectNode`](../statement/struct.SubjectNode.html). /// - pub fn new(subject: SubjectNodeRef) -> Self { - assert_eq!(subject.provider_id(), simple::PROVIDER_ID); + pub fn new(subject: SimpleSubjectNode) -> Self { + if let Some(subject_id) = subject.provider_id() { + if subject_id != crate::simple::PROVIDER_ID { + panic!("Invalid subject provider {subject_id}.") + } + } Self { subject, - statement_factory: statement_factory(), - literal_factory: literal_factory(), + statement_factory: Default::default(), + literal_factory: Default::default(), predicates: Default::default(), } } @@ -314,37 +322,38 @@ impl Resource { /// [`SubjectNode`](../statement/struct.SubjectNode.html). /// pub fn with_factories( - subject: SubjectNodeRef, - statement_factory: StatementFactoryRef, - literal_factory: LiteralFactoryRef, + subject: SimpleSubjectNode, + statement_factory: SimpleStatementFactory, + literal_factory: SimpleLiteralFactory, ) -> Result { if statement_factory.provider_id() != literal_factory.provider_id() { - provider_mismatch_error( + return provider_mismatch_error( statement_factory.provider_id(), literal_factory.provider_id(), ) - .into() - } else if subject.provider_id() != statement_factory.provider_id() { - provider_mismatch_error(subject.provider_id(), statement_factory.provider_id()).into() - } else { - Ok(Self { - subject, - statement_factory, - literal_factory, - predicates: Default::default(), - }) + .into(); + } else if let Some(subject_id) = subject.provider_id() { + if subject_id != crate::simple::PROVIDER_ID { + return provider_mismatch_error(subject_id, statement_factory.provider_id()).into(); + } } + Ok(Self { + subject, + statement_factory, + literal_factory, + predicates: Default::default(), + }) } /// /// Construct a new `Resource` with a new blank node as the subject. /// pub fn blank() -> Self { - let statement_factory = statement_factory(); + let statement_factory = SimpleStatementFactory::default(); Self { subject: statement_factory.blank_subject_new(), statement_factory, - literal_factory: literal_factory(), + literal_factory: Default::default(), predicates: Default::default(), } } @@ -353,11 +362,11 @@ impl Resource { /// Construct a new `Resource` with a named blank node as the subject. /// pub fn blank_named(name: &str) -> Self { - let statement_factory = statement_factory(); + let statement_factory = SimpleStatementFactory::default(); Self { subject: statement_factory.blank_subject_named(name).unwrap(), statement_factory, - literal_factory: literal_factory(), + literal_factory: Default::default(), predicates: Default::default(), } } @@ -365,12 +374,12 @@ impl Resource { /// /// Construct a new `Resource` with the provided `Iri` as the subject. /// - pub fn named(name: IriRef) -> Self { - let statement_factory = statement_factory(); + pub fn named(name: Iri) -> Self { + let statement_factory = SimpleStatementFactory::default(); Self { subject: statement_factory.named_subject(name), statement_factory, - literal_factory: literal_factory(), + literal_factory: Default::default(), predicates: Default::default(), } } @@ -382,7 +391,7 @@ impl Resource { /// #[inline] pub fn is_a_resource(&self) -> bool { - self.subject.is_iri() + self.subject.is_resource() } /// @@ -411,28 +420,28 @@ impl Resource { /// /// Add a new property predicate with a literal value to this resource. /// - pub fn property(&mut self, predicate: IriRef, value: LiteralRef) -> &mut Self { + pub fn property(&mut self, predicate: Iri, value: SimpleLiteral) -> &mut Self { self.literal(predicate, value) } /// /// Add a new property predicate with a literal value to this resource. /// - pub fn value_of(&mut self, predicate: IriRef, value: LiteralRef) -> &mut Self { + pub fn value_of(&mut self, predicate: Iri, value: SimpleLiteral) -> &mut Self { self.literal(predicate, value) } /// /// Add a new property predicate with a literal value to this resource. /// - pub fn literal(&mut self, predicate: IriRef, value: LiteralRef) -> &mut Self { + pub fn literal(&mut self, predicate: Iri, value: SimpleLiteral) -> &mut Self { self.insert(predicate, ResourceObject::Literal(value)) } /// /// Add a new property predicate with a literal value to this resource. /// - pub fn literal_str(&mut self, predicate: IriRef, value: &str) -> &mut Self { + pub fn literal_str(&mut self, predicate: Iri, value: &str) -> &mut Self { let value = self.literal_factory.literal(value); self.insert(predicate, ResourceObject::Literal(value)) } @@ -442,7 +451,7 @@ impl Resource { /// pub fn literal_typed_str( &mut self, - predicate: IriRef, + predicate: Iri, value: &str, data_type: DataType, ) -> &mut Self { @@ -455,7 +464,7 @@ impl Resource { /// pub fn literal_language_str( &mut self, - predicate: IriRef, + predicate: Iri, value: &str, language: LanguageTag, ) -> &mut Self { @@ -468,7 +477,7 @@ impl Resource { /// pub fn literal_language_str_str( &mut self, - predicate: IriRef, + predicate: Iri, value: &str, language: &str, ) -> &mut Self { @@ -483,7 +492,7 @@ impl Resource { /// /// The value of this property predicate is a container denoting the provided values as alternatives. /// - pub fn property_alternatives(&mut self, predicate: IriRef, values: &[LiteralRef]) -> &mut Self { + pub fn property_alternatives(&mut self, predicate: Iri, values: &[SimpleLiteral]) -> &mut Self { self.insert( predicate, ResourceObject::Literals(Container { @@ -497,7 +506,7 @@ impl Resource { /// The value of this property predicate is a container denoting the provided values as an /// unordered bag. /// - pub fn property_bag(&mut self, predicate: IriRef, values: &[LiteralRef]) -> &mut Self { + pub fn property_bag(&mut self, predicate: Iri, values: &[SimpleLiteral]) -> &mut Self { self.insert( predicate, ResourceObject::Literals(Container { @@ -511,7 +520,7 @@ impl Resource { /// The value of this property predicate is a container denoting the provided values as an ordered /// sequence. /// - pub fn property_sequence(&mut self, predicate: IriRef, values: &[LiteralRef]) -> &mut Self { + pub fn property_sequence(&mut self, predicate: Iri, values: &[SimpleLiteral]) -> &mut Self { self.insert( predicate, ResourceObject::Literals(Container { @@ -527,9 +536,9 @@ impl Resource { /// pub fn property_container( &mut self, - predicate: IriRef, - values: &[LiteralRef], - kind: IriRef, + predicate: Iri, + values: &[SimpleLiteral], + kind: Iri, ) -> &mut Self { self.insert( predicate, @@ -545,7 +554,7 @@ impl Resource { /// /// Add a new resource predicate, a blank node, to this predicate. /// - pub fn resource_blank_named(&mut self, predicate: IriRef, name: &str) -> &mut Self { + pub fn resource_blank_named(&mut self, predicate: Iri, name: &str) -> &mut Self { self.insert( predicate, ResourceObject::Resource(Resource::blank_named(name)), @@ -555,14 +564,14 @@ impl Resource { /// /// Add a new resource predicate, an Iri, to this predicate. /// - pub fn resource_named(&mut self, predicate: IriRef, name: IriRef) -> &mut Self { + pub fn resource_named(&mut self, predicate: Iri, name: Iri) -> &mut Self { self.insert(predicate, ResourceObject::Resource(Resource::named(name))) } /// /// Add a new resource predicate, another resource, to this predicate. /// - pub fn resource(&mut self, predicate: IriRef, resource: Resource) -> &mut Self { + pub fn resource(&mut self, predicate: Iri, resource: Resource) -> &mut Self { self.insert(predicate, ResourceObject::Resource(resource)) } @@ -571,7 +580,7 @@ impl Resource { /// /// The value of this resource predicate is a container denoting the provided values as alternatives. /// - pub fn resource_alternatives(&mut self, predicate: IriRef, values: &[Resource]) -> &mut Self { + pub fn resource_alternatives(&mut self, predicate: Iri, values: &[Resource]) -> &mut Self { self.insert( predicate, ResourceObject::Resources(Container { @@ -585,7 +594,7 @@ impl Resource { /// The value of this resource predicate is a container denoting the provided values as an /// unordered bag. /// - pub fn resource_bag(&mut self, predicate: IriRef, values: &[Resource]) -> &mut Self { + pub fn resource_bag(&mut self, predicate: Iri, values: &[Resource]) -> &mut Self { self.insert( predicate, ResourceObject::Resources(Container { @@ -599,7 +608,7 @@ impl Resource { /// The value of this resource predicate is a container denoting the provided values as an ordered /// sequence. /// - pub fn resource_sequence(&mut self, predicate: IriRef, values: &[Resource]) -> &mut Self { + pub fn resource_sequence(&mut self, predicate: Iri, values: &[Resource]) -> &mut Self { self.insert( predicate, ResourceObject::Resources(Container { @@ -615,9 +624,9 @@ impl Resource { /// pub fn resource_container( &mut self, - predicate: IriRef, + predicate: Iri, values: &[Resource], - kind: IriRef, + kind: Iri, ) -> &mut Self { self.insert( predicate, @@ -633,7 +642,7 @@ impl Resource { /// /// Set the RDF type (classifier) of this resource. /// - pub fn instance_of(&mut self, name: IriRef) -> &mut Self { + pub fn instance_of(&mut self, name: Iri) -> &mut Self { self.insert( rdf::a_type().clone(), ResourceObject::Resource(Resource::named(name)), @@ -642,14 +651,14 @@ impl Resource { // -------------------------------------------------------------------------------------------- - fn insert(&mut self, predicate: IriRef, object: ResourceObject) -> &mut Self { + fn insert(&mut self, predicate: Iri, object: ResourceObject) -> &mut Self { if !self.predicates.contains_key(&predicate) { let _ = self .predicates - .insert(predicate.clone(), RefCell::default()); + .insert(predicate.clone(), Default::default()); } - let values = self.predicates.get(&predicate).unwrap(); - values.borrow_mut().push(object); + let values = self.predicates.get_mut(&predicate).unwrap(); + values.push(object); self } } @@ -669,10 +678,9 @@ impl ResourceObject { // Private Functions // ------------------------------------------------------------------------------------------------ -fn flatten(resource: &Resource, sts: &mut StatementList) { +fn flatten(resource: &Resource, sts: &mut Vec) { let subject = &resource.subject; for (predicate, objects) in &resource.predicates { - let objects = objects.borrow(); for object in objects.iter() { if object.is_container() { //

{, [values]} becomes: diff --git a/rdftk_core/src/simple/statement.rs b/rdftk_core/src/simple/statement.rs new file mode 100644 index 0000000..77f257e --- /dev/null +++ b/rdftk_core/src/simple/statement.rs @@ -0,0 +1,202 @@ +/*! +Simple, in-memory implementation of the `Statement` and `StatementFactory` traits. +*/ + +use crate::error::{provider_mismatch_error, Result}; +use crate::model::features::Featured; +use crate::model::features::FEATURE_RDF_STAR; +use crate::model::statement::{BlankNode, ObjectNode, Statement, StatementFactory, SubjectNode}; +use crate::model::Provided; +use crate::simple::literal::SimpleLiteral; +use rdftk_iri::Iri; +use std::fmt::{Display, Formatter}; +use std::ops::Deref; +use std::sync::Arc; + +// ------------------------------------------------------------------------------------------------ +// Public Types +// ------------------------------------------------------------------------------------------------ + +pub type SimpleSubjectNode = SubjectNode; + +pub type SimpleObjectNode = ObjectNode; + +/// +/// Simple, in-memory implementation of the `Statement` trait. +/// +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct SimpleStatement { + subject: SimpleSubjectNode, + predicate: Iri, + object: SimpleObjectNode, +} + +/// +/// Simple, in-memory implementation of the `StatementFactory` trait. +/// +#[derive(Clone, Debug, Default)] +pub struct SimpleStatementFactory {} + +// ------------------------------------------------------------------------------------------------ +// Implementations +// ------------------------------------------------------------------------------------------------ + +impl Provided for SimpleStatementFactory { + fn provider_id(&self) -> &'static str { + crate::simple::PROVIDER_ID + } +} + +impl StatementFactory for SimpleStatementFactory { + type Literal = SimpleLiteral; + type Statement = SimpleStatement; + + fn statement( + &self, + subject: SimpleSubjectNode, + predicate: Iri, + object: ObjectNode, + ) -> Result { + if let Some(subject_id) = subject.provider_id() { + if self.provider_id() != subject_id { + return provider_mismatch_error(self.provider_id(), subject_id).into(); + } + } else if let Some(object_id) = object.provider_id() { + if self.provider_id() != object_id { + return provider_mismatch_error(self.provider_id(), object_id).into(); + } + } + Ok(SimpleStatement { + subject, + predicate, + object, + }) + } + + fn statement_with_predicate( + &self, + subject: Self::Statement, + predicate: Iri, + object: SimpleObjectNode, + ) -> Result { + self.statement(subject.subject().clone(), predicate, object) + } + + fn statement_with_object( + &self, + subject: Self::Statement, + object: SimpleObjectNode, + ) -> Result { + self.statement( + subject.subject().clone(), + subject.predicate().clone(), + object, + ) + } + + fn blank_subject(&self, node: BlankNode) -> SimpleSubjectNode { + SubjectNode::from(node) + } + + fn named_subject(&self, name: Iri) -> SimpleSubjectNode { + SubjectNode::from(name) + } + + fn statement_subject(&self, st: Arc) -> SimpleSubjectNode { + SubjectNode::from(st) + } + + fn object_as_subject(&self, obj: SimpleObjectNode) -> Option { + match obj { + ObjectNode::Blank(v) => Some(self.blank_subject(v.clone())), + ObjectNode::Resource(v) => Some(self.named_subject(v.clone())), + ObjectNode::Statement(v) => Some(self.statement_subject(v.clone())), + ObjectNode::Literal(_) => None, + } + } + + fn blank_object(&self, name: BlankNode) -> SimpleObjectNode { + ObjectNode::from(name) + } + + fn named_object(&self, name: Iri) -> SimpleObjectNode { + ObjectNode::from(name) + } + + fn literal_object(&self, value: SimpleLiteral) -> SimpleObjectNode { + ObjectNode::from(value) + } + + fn statement_object(&self, st: Arc) -> SimpleObjectNode { + ObjectNode::from(st) + } + + fn subject_as_object( + &self, + sub: SimpleSubjectNode, + ) -> ObjectNode { + match sub { + SubjectNode::Blank(v) => self.blank_object(v.clone()), + SubjectNode::Resource(v) => self.named_object(v.clone()), + SubjectNode::Statement(v) => self.statement_object(v.clone()), + } + } +} + +// ------------------------------------------------------------------------------------------------ + +impl Featured for SimpleStatement { + fn supports_feature(&self, feature: &Iri) -> bool { + feature == FEATURE_RDF_STAR.deref() + } +} + +impl Statement for SimpleStatement { + type Literal = SimpleLiteral; + + fn subject(&self) -> &SimpleSubjectNode { + &self.subject + } + + fn set_subject(&mut self, subject: SimpleSubjectNode) { + self.subject = subject; + } + + fn predicate(&self) -> &Iri { + &self.predicate + } + + fn set_predicate(&mut self, predicate: Iri) { + self.predicate = predicate; + } + + fn object(&self) -> &SimpleObjectNode { + &self.object + } + + fn set_object(&mut self, object: SimpleObjectNode) { + self.object = object; + } + + fn is_nested(&self) -> bool { + self.subject().is_statement() || self.object().is_statement() + } +} + +impl Display for SimpleStatement { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{} <{}> {}", + &self.subject().to_string(), + &self.predicate().to_string(), + &self.object().to_string(), + ) + } +} + +impl Provided for SimpleStatement { + fn provider_id(&self) -> &'static str { + super::PROVIDER_ID + } +} diff --git a/rdftk_core/src/simple/statement/mod.rs b/rdftk_core/src/simple/statement/mod.rs deleted file mode 100644 index 4af3a40..0000000 --- a/rdftk_core/src/simple/statement/mod.rs +++ /dev/null @@ -1,225 +0,0 @@ -/*! -Simple, in-memory implementation of the `Statement` and `StatementFactory` traits. -*/ - -use crate::error::{provider_mismatch_error, Result}; -use crate::model::features::Featured; -use crate::model::features::FEATURE_RDF_STAR; -use crate::model::literal::{LiteralFactoryRef, LiteralRef}; -use crate::model::statement::{ - BlankNodeRef, ObjectNodeRef, Statement, StatementFactory, StatementFactoryRef, StatementRef, - SubjectNodeRef, -}; -use crate::model::Provided; -use crate::simple::literal::literal_factory; -use lazy_static::lazy_static; -use rdftk_iri::IriRef; -use std::ops::Deref; -use std::rc::Rc; -use std::sync::Arc; - -// ------------------------------------------------------------------------------------------------ -// Public Types -// ------------------------------------------------------------------------------------------------ - -/// -/// Simple, in-memory implementation of the `Statement` trait. -/// -#[derive(Clone, Debug)] -pub struct SimpleStatement { - subject: SubjectNodeRef, - predicate: IriRef, - object: ObjectNodeRef, -} - -// ------------------------------------------------------------------------------------------------ -// Public Functions -// ------------------------------------------------------------------------------------------------ - -/// -/// Retrieve the `Statement` factory for `simple::SimpleStatement` instances. -/// -pub fn statement_factory() -> StatementFactoryRef { - FACTORY.clone() -} - -// ------------------------------------------------------------------------------------------------ -// Private Types -// ------------------------------------------------------------------------------------------------ - -/// -/// Simple, in-memory implementation of the `StatementFactory` trait. -/// -#[derive(Clone, Debug)] -struct SimpleStatementFactory {} - -lazy_static! { - static ref FACTORY: Arc = Arc::new(SimpleStatementFactory {}); -} - -// ------------------------------------------------------------------------------------------------ -// Implementations -// ------------------------------------------------------------------------------------------------ - -impl Provided for SimpleStatementFactory { - fn provider_id(&self) -> &'static str { - crate::simple::PROVIDER_ID - } -} - -impl StatementFactory for SimpleStatementFactory { - fn statement( - &self, - subject: SubjectNodeRef, - predicate: IriRef, - object: ObjectNodeRef, - ) -> Result { - if self.provider_id() == subject.provider_id() && self.provider_id() == object.provider_id() - { - Ok(Rc::new(SimpleStatement { - subject, - predicate, - object, - })) - } else { - provider_mismatch_error(self.provider_id(), object.provider_id()).into() - } - } - - fn statement_with_predicate( - &self, - subject: StatementRef, - predicate: IriRef, - object: ObjectNodeRef, - ) -> Result { - self.statement(subject.subject().clone(), predicate, object) - } - - fn statement_with_object( - &self, - subject: StatementRef, - object: ObjectNodeRef, - ) -> Result { - self.statement( - subject.subject().clone(), - subject.predicate().clone(), - object, - ) - } - - fn blank_subject(&self, node: BlankNodeRef) -> SubjectNodeRef { - Rc::new(SimpleSubjectNode::from(node)) - } - - fn named_subject(&self, name: IriRef) -> SubjectNodeRef { - Rc::new(SimpleSubjectNode::from(name)) - } - - fn statement_subject(&self, st: StatementRef) -> SubjectNodeRef { - Rc::new(SimpleSubjectNode::from(st)) - } - - fn object_as_subject(&self, obj: ObjectNodeRef) -> Option { - if let Some(blank) = obj.as_blank() { - return Some(self.blank_subject(blank.clone())); - } - if let Some(iri) = obj.as_iri() { - return Some(self.named_subject(iri.clone())); - } - if let Some(st) = obj.as_statement() { - return Some(self.statement_subject(st.clone())); - } - None - } - - fn blank_object(&self, name: BlankNodeRef) -> ObjectNodeRef { - Rc::new(SimpleObjectNode::from(name)) - } - - fn named_object(&self, name: IriRef) -> ObjectNodeRef { - Rc::new(SimpleObjectNode::from(name)) - } - - fn literal_object(&self, value: LiteralRef) -> ObjectNodeRef { - Rc::new(SimpleObjectNode::from(value)) - } - - fn statement_object(&self, st: StatementRef) -> ObjectNodeRef { - Rc::new(SimpleObjectNode::from(st)) - } - - fn subject_as_object(&self, sub: SubjectNodeRef) -> ObjectNodeRef { - if let Some(blank) = sub.as_blank() { - return self.blank_object(blank.clone()); - } - if let Some(iri) = sub.as_iri() { - return self.named_object(iri.clone()); - } - if let Some(st) = sub.as_statement() { - return self.statement_object(st.clone()); - } - unreachable!() - } - - fn literal_factory(&self) -> LiteralFactoryRef { - literal_factory() - } -} - -// ------------------------------------------------------------------------------------------------ - -impl Featured for SimpleStatement { - fn supports_feature(&self, feature: &IriRef) -> bool { - feature == FEATURE_RDF_STAR.deref() - } -} - -impl Statement for SimpleStatement { - fn subject(&self) -> &SubjectNodeRef { - &self.subject - } - - fn set_subject(&mut self, subject: SubjectNodeRef) { - self.subject = subject; - } - - fn predicate(&self) -> &IriRef { - &self.predicate - } - - fn set_predicate(&mut self, predicate: IriRef) { - self.predicate = predicate; - } - - fn object(&self) -> &ObjectNodeRef { - &self.object - } - - fn set_object(&mut self, object: ObjectNodeRef) { - self.object = object; - } - - fn factory(&self) -> StatementFactoryRef { - statement_factory() - } - - fn literal_factory(&self) -> LiteralFactoryRef { - literal_factory() - } - - fn is_nested(&self) -> bool { - self.subject().is_statement() || self.object().is_statement() - } -} - -// ------------------------------------------------------------------------------------------------ -// Modules -// ------------------------------------------------------------------------------------------------ - -#[doc(hidden)] -pub mod subject; -pub use subject::SimpleSubjectNode; - -#[doc(hidden)] -pub mod object; -pub use object::SimpleObjectNode; diff --git a/rdftk_core/src/simple/statement/object.rs b/rdftk_core/src/simple/statement/object.rs deleted file mode 100644 index fe65444..0000000 --- a/rdftk_core/src/simple/statement/object.rs +++ /dev/null @@ -1,109 +0,0 @@ -use crate::model::literal::LiteralRef; -use crate::model::statement::{BlankNodeRef, ObjectNode, StatementRef, SubjectNode}; -use crate::model::Provided; -use rdftk_iri::IriRef; - -// ------------------------------------------------------------------------------------------------ -// Public Types -// ------------------------------------------------------------------------------------------------ - -/// -/// Simple, in-memory implementation of the `ObjectNode` trait. -/// -#[derive(Clone, Debug)] -pub struct SimpleObjectNode(Object); - -// ------------------------------------------------------------------------------------------------ -// Private Types -// ------------------------------------------------------------------------------------------------ - -#[allow(clippy::upper_case_acronyms)] -#[derive(Clone, Debug)] -enum Object { - BNode(BlankNodeRef), - Iri(IriRef), - Literal(LiteralRef), - Star(StatementRef), -} - -// ------------------------------------------------------------------------------------------------ -// Implementations -// ------------------------------------------------------------------------------------------------ - -impl From for SimpleObjectNode { - fn from(v: BlankNodeRef) -> Self { - Self(Object::BNode(v)) - } -} - -impl From for SimpleObjectNode { - fn from(v: IriRef) -> Self { - Self(Object::Iri(v)) - } -} - -impl From for SimpleObjectNode { - fn from(v: LiteralRef) -> Self { - Self(Object::Literal(v)) - } -} - -impl From for SimpleObjectNode { - fn from(v: StatementRef) -> Self { - Self(Object::Star(v)) - } -} - -impl Provided for SimpleObjectNode { - fn provider_id(&self) -> &'static str { - crate::simple::PROVIDER_ID - } -} - -impl SubjectNode for SimpleObjectNode { - fn is_blank(&self) -> bool { - matches!(self.0, Object::BNode(_)) - } - - fn as_blank(&self) -> Option<&BlankNodeRef> { - match &self.0 { - Object::BNode(s) => Some(s), - _ => None, - } - } - - fn is_iri(&self) -> bool { - matches!(self.0, Object::Iri(_)) - } - - fn as_iri(&self) -> Option<&IriRef> { - match &self.0 { - Object::Iri(u) => Some(u), - _ => None, - } - } - - fn is_statement(&self) -> bool { - matches!(self.0, Object::Star(_)) - } - - fn as_statement(&self) -> Option<&StatementRef> { - match &self.0 { - Object::Star(st) => Some(st), - _ => None, - } - } -} - -impl ObjectNode for SimpleObjectNode { - fn is_literal(&self) -> bool { - matches!(self.0, Object::Literal(_)) - } - - fn as_literal(&self) -> Option<&LiteralRef> { - match &self.0 { - Object::Literal(l) => Some(l), - _ => None, - } - } -} diff --git a/rdftk_core/src/simple/statement/subject.rs b/rdftk_core/src/simple/statement/subject.rs deleted file mode 100644 index a956eda..0000000 --- a/rdftk_core/src/simple/statement/subject.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::model::statement::{BlankNodeRef, StatementRef, SubjectNode}; -use crate::model::Provided; -use rdftk_iri::IriRef; - -// ------------------------------------------------------------------------------------------------ -// Public Types -// ------------------------------------------------------------------------------------------------ - -/// -/// Simple, in-memory implementation of the `SubjectNode` trait. -/// -#[derive(Clone, Debug)] -pub struct SimpleSubjectNode(Subject); - -// ------------------------------------------------------------------------------------------------ -// Private Types -// ------------------------------------------------------------------------------------------------ - -#[allow(clippy::upper_case_acronyms)] -#[derive(Clone, Debug)] -enum Subject { - BNode(BlankNodeRef), - Iri(IriRef), - Star(StatementRef), -} - -// ------------------------------------------------------------------------------------------------ -// Implementations -// ------------------------------------------------------------------------------------------------ - -impl From for SimpleSubjectNode { - fn from(v: BlankNodeRef) -> Self { - Subject::BNode(v).into() - } -} - -impl From for SimpleSubjectNode { - fn from(v: IriRef) -> Self { - Subject::Iri(v).into() - } -} - -impl From for SimpleSubjectNode { - fn from(v: StatementRef) -> Self { - Subject::Star(v).into() - } -} - -impl From for SimpleSubjectNode { - fn from(value: Subject) -> Self { - Self(value) - } -} - -impl Provided for SimpleSubjectNode { - fn provider_id(&self) -> &'static str { - crate::simple::PROVIDER_ID - } -} - -impl SubjectNode for SimpleSubjectNode { - fn is_blank(&self) -> bool { - matches!(self.0, Subject::BNode(_)) - } - - fn as_blank(&self) -> Option<&BlankNodeRef> { - match &self.0 { - Subject::BNode(s) => Some(s), - _ => None, - } - } - - fn is_iri(&self) -> bool { - matches!(self.0, Subject::Iri(_)) - } - - fn as_iri(&self) -> Option<&IriRef> { - match &self.0 { - Subject::Iri(u) => Some(u), - _ => None, - } - } - - fn is_statement(&self) -> bool { - matches!(self.0, Subject::Star(_)) - } - - fn as_statement(&self) -> Option<&StatementRef> { - match &self.0 { - Subject::Star(st) => Some(st), - _ => None, - } - } -} diff --git a/rdftk_core/tests/data_sets.rs b/rdftk_core/tests/data_sets.rs new file mode 100644 index 0000000..21cc711 --- /dev/null +++ b/rdftk_core/tests/data_sets.rs @@ -0,0 +1,10 @@ +use rdftk_core::model::data_set::{DataSet, DataSetFactory}; +use rdftk_core::simple::data_set::SimpleDataSetFactory; + +#[test] +fn test_create_data_set() { + let factory = SimpleDataSetFactory::default(); + let data_set = factory.data_set(); + + assert_eq!(data_set.len(), 0); +} diff --git a/rdftk_core/tests/graphs.rs b/rdftk_core/tests/graphs.rs index c98693d..ba1dca3 100644 --- a/rdftk_core/tests/graphs.rs +++ b/rdftk_core/tests/graphs.rs @@ -1,148 +1,117 @@ -use parameterized::parameterized; -use rdftk_core::model::graph::{GraphFactoryRef, GraphRef}; -use rdftk_core::simple::graph::graph_factory as simple_graph_factory; -use rdftk_core::simple::indexed::graph_factory as indexed_graph_factory; -use rdftk_core::simple::mapping::default_mappings; -use rdftk_core::simple::PROVIDER_ID; -use rdftk_iri::{Iri, IriRef}; +use rdftk_core::model::graph::{Graph, GraphFactory, PrefixMapping}; +use rdftk_core::model::literal::LiteralFactory; +use rdftk_core::model::statement::StatementFactory; +use rdftk_core::model::Implementation; +use rdftk_core::simple::graph::SimpleGraph; +use rdftk_core::simple::literal::SimpleLiteral; +use rdftk_core::simple::statement::SimpleStatement; +use rdftk_core::simple::Implementation as SimpleImplementation; +use rdftk_iri::Iri; use std::str::FromStr; -pub fn tony_benn_graph(graph_factory: GraphFactoryRef) -> GraphRef { - let mappings = default_mappings(); - - { - let mut mut_mappings = mappings.borrow_mut(); - mut_mappings.insert_rdf(); - mut_mappings.insert_dcterms(); - mut_mappings.insert_foaf(); - } - - let graph = graph_factory.graph(); - - { - let mut ref_graph = graph.borrow_mut(); - - ref_graph.set_prefix_mappings(mappings); - - let st_factory = ref_graph.statement_factory(); - let lit_factory = ref_graph.literal_factory(); - - let subject_iri = - IriRef::from(Iri::from_str("http://en.wikipedia.org/wiki/Tony_Benn").unwrap()); - - ref_graph.insert( - st_factory - .statement( - st_factory.named_subject(subject_iri.clone()), - IriRef::from(Iri::from_str("http://purl.org/dc/elements/1.1/title").unwrap()), - st_factory.literal_object(lit_factory.literal("Tony Benn")), - ) - .unwrap(), - ); - ref_graph.insert( - st_factory - .statement( - st_factory.named_subject(subject_iri.clone()), - IriRef::from( - Iri::from_str("http://purl.org/dc/elements/1.1/publisher").unwrap(), - ), - st_factory.literal_object(lit_factory.literal("Wikipedia")), - ) - .unwrap(), - ); - ref_graph.insert( - st_factory - .statement( - st_factory.named_subject(subject_iri), - IriRef::from( - Iri::from_str("http://purl.org/dc/elements/1.1/description").unwrap(), - ), - st_factory.blank_object_named("B1").unwrap(), - ) - .unwrap(), - ); - ref_graph.insert( - st_factory - .statement( - st_factory.blank_subject_named("B1").unwrap(), - IriRef::from(Iri::from_str("http://xmlns.com/foaf/0.1/name").unwrap()), - st_factory.literal_object(lit_factory.literal("Tony Benn")), - ) - .unwrap(), - ); - ref_graph.insert( - st_factory - .statement( - st_factory.blank_subject_named("B1").unwrap(), - IriRef::from( - Iri::from_str("http://www.w3.org/1999/02/22-rdf-syntax-ns#type").unwrap(), - ), - st_factory.named_object( - Iri::from_str("http://xmlns.com/foaf/0.1/Person") - .unwrap() - .into(), - ), - ) - .unwrap(), - ); - } +pub fn tony_benn_graph( + factory: &impl Implementation< + Graph = SimpleGraph, + Statement = SimpleStatement, + Literal = SimpleLiteral, + >, +) -> SimpleGraph { + let mappings = PrefixMapping::default() + .with_rdf() + .with_dcterms() + .with_foaf(); + + let mut graph = factory.graph_factory().graph(); + + graph.set_prefix_mappings(mappings); + + let st_factory = factory.statement_factory(); + let lit_factory = factory.literal_factory(); + + let subject_iri = Iri::from_str("http://en.wikipedia.org/wiki/Tony_Benn").unwrap(); + + graph.insert( + st_factory + .statement( + st_factory.named_subject(subject_iri.clone()), + Iri::from_str("http://purl.org/dc/elements/1.1/title").unwrap(), + st_factory.literal_object(lit_factory.literal("Tony Benn")), + ) + .unwrap(), + ); + graph.insert( + st_factory + .statement( + st_factory.named_subject(subject_iri.clone()), + Iri::from_str("http://purl.org/dc/elements/1.1/publisher").unwrap(), + st_factory.literal_object(lit_factory.literal("Wikipedia")), + ) + .unwrap(), + ); + graph.insert( + st_factory + .statement( + st_factory.named_subject(subject_iri), + Iri::from_str("http://purl.org/dc/elements/1.1/description").unwrap(), + st_factory.blank_object_named("B1").unwrap(), + ) + .unwrap(), + ); + graph.insert( + st_factory + .statement( + st_factory.blank_subject_named("B1").unwrap(), + Iri::from_str("http://xmlns.com/foaf/0.1/name").unwrap(), + st_factory.literal_object(lit_factory.literal("Tony Benn")), + ) + .unwrap(), + ); + graph.insert( + st_factory + .statement( + st_factory.blank_subject_named("B1").unwrap(), + Iri::from_str("http://www.w3.org/1999/02/22-rdf-syntax-ns#type").unwrap(), + st_factory.named_object(Iri::from_str("http://xmlns.com/foaf/0.1/Person").unwrap()), + ) + .unwrap(), + ); graph } -#[parameterized(graph_factory = { simple_graph_factory(), indexed_graph_factory()})] -fn graph_len(graph_factory: GraphFactoryRef) { - let graph = tony_benn_graph(graph_factory); - let graph = graph.borrow(); +#[test] +fn test_simple_graph_len() { + let implementation = SimpleImplementation::default(); + let graph = tony_benn_graph(&implementation); assert_eq!(graph.len(), 5); } -#[parameterized(graph_factory = { simple_graph_factory(), indexed_graph_factory()})] -fn graph_provider(graph_factory: GraphFactoryRef) { - let graph = tony_benn_graph(graph_factory); - let graph = graph.borrow(); - - assert_eq!(graph.factory().provider_id(), PROVIDER_ID); -} - -#[parameterized(graph_factory = { simple_graph_factory(), indexed_graph_factory()})] -fn graph_contains_individual(graph_factory: GraphFactoryRef) { - let graph = tony_benn_graph(graph_factory); - let graph = graph.borrow(); - - { - let subject_iri = - IriRef::from(Iri::from_str("http://en.wikipedia.org/wiki/Tony_Benn").unwrap()); - - assert!(graph.contains_individual(&subject_iri)); - } +#[test] +fn test_simple_graph_contains_individual() { + let implementation = SimpleImplementation::default(); + let graph = tony_benn_graph(&implementation); - { - let subject_iri = - IriRef::from(Iri::from_str("http://en.wikipedia.org/wiki/Harold_Wilson").unwrap()); + let subject_iri = Iri::from_str("http://en.wikipedia.org/wiki/Tony_Benn").unwrap(); + assert!(graph.contains_subject(&subject_iri.into())); - assert!(!graph.contains_individual(&subject_iri)); - } + let subject_iri = Iri::from_str("http://en.wikipedia.org/wiki/Harold_Wilson").unwrap(); + assert!(!graph.contains_subject(&subject_iri.into())); } -#[parameterized(graph_factory = { simple_graph_factory(), indexed_graph_factory()})] -fn graph_contains_subject(graph_factory: GraphFactoryRef) { - let graph = tony_benn_graph(graph_factory); - let graph = graph.borrow(); - - { - let subject_iri = - IriRef::from(Iri::from_str("http://en.wikipedia.org/wiki/Tony_Benn").unwrap()); - let subject = graph.statement_factory().named_subject(subject_iri); - - assert!(graph.contains_subject(&subject)); - } - - { - let subject_iri = - IriRef::from(Iri::from_str("http://en.wikipedia.org/wiki/Harold_Wilson").unwrap()); - let subject = graph.statement_factory().named_subject(subject_iri); - - assert!(!graph.contains_subject(&subject)); - } +#[test] +fn test_simple_graph_contains_subject() { + let implementation = SimpleImplementation::default(); + let graph = tony_benn_graph(&implementation); + + let subject_iri = Iri::from_str("http://en.wikipedia.org/wiki/Tony_Benn").unwrap(); + let subject = implementation + .statement_factory() + .named_subject(subject_iri); + assert!(graph.contains_subject(&subject)); + + let subject_iri = Iri::from_str("http://en.wikipedia.org/wiki/Harold_Wilson").unwrap(); + let subject = implementation + .statement_factory() + .named_subject(subject_iri); + assert!(!graph.contains_subject(&subject)); } diff --git a/rdftk_core/tests/literals.rs b/rdftk_core/tests/literals.rs index 5a88643..729a556 100644 --- a/rdftk_core/tests/literals.rs +++ b/rdftk_core/tests/literals.rs @@ -1,9 +1,11 @@ -use rdftk_core::simple::literal::literal_factory; +use rdftk_core::model::literal::Literal; +use rdftk_core::model::literal::LiteralFactory; +use rdftk_core::simple::literal::SimpleLiteralFactory; use std::time::Duration; #[test] fn untyped() { - let literals = literal_factory(); + let literals = SimpleLiteralFactory::default(); let value = literals.literal("a string"); assert!(!value.has_data_type()); assert!(!value.has_language()); @@ -13,7 +15,7 @@ fn untyped() { #[test] fn needs_escape() { - let literals = literal_factory(); + let literals = SimpleLiteralFactory::default(); let value = literals.literal(r#"\ta "string"#); assert!(!value.has_data_type()); assert!(!value.has_language()); @@ -23,7 +25,7 @@ fn needs_escape() { #[test] fn string_with_language() { - let literals = literal_factory(); + let literals = SimpleLiteralFactory::default(); let value = literals.with_language_str("a string", "en-us").unwrap(); assert!(!value.has_data_type()); assert!(value.has_language()); @@ -33,7 +35,7 @@ fn string_with_language() { #[test] fn typed_as_string() { - let literals = literal_factory(); + let literals = SimpleLiteralFactory::default(); let value = literals.string("a string"); assert!(value.has_data_type()); assert!(!value.has_language()); @@ -46,7 +48,7 @@ fn typed_as_string() { #[test] fn typed_as_boolean() { - let literals = literal_factory(); + let literals = SimpleLiteralFactory::default(); let value = literals.boolean(true); assert!(value.has_data_type()); assert!(!value.has_language()); @@ -59,7 +61,7 @@ fn typed_as_boolean() { #[test] fn typed_as_long() { - let literals = literal_factory(); + let literals = SimpleLiteralFactory::default(); let value = literals.long(1); assert!(value.has_data_type()); assert!(!value.has_language()); @@ -72,7 +74,7 @@ fn typed_as_long() { #[test] fn typed_as_ulong() { - let literals = literal_factory(); + let literals = SimpleLiteralFactory::default(); let value = literals.unsigned_long(1); assert!(value.has_data_type()); assert!(!value.has_language()); @@ -85,7 +87,7 @@ fn typed_as_ulong() { #[test] fn typed_as_duration() { - let literals = literal_factory(); + let literals = SimpleLiteralFactory::default(); let duration = Duration::from_secs(63542); let value = literals.duration(duration); println!("Duration Out: {}", value); diff --git a/rdftk_core/tests/prefix_mappings.rs b/rdftk_core/tests/prefix_mappings.rs index 32427f5..d58c3d1 100644 --- a/rdftk_core/tests/prefix_mappings.rs +++ b/rdftk_core/tests/prefix_mappings.rs @@ -1,24 +1,14 @@ -use rdftk_core::model::graph::PrefixMappingRef; -use rdftk_core::model::qname::QName; -use rdftk_core::simple::mapping::common_mappings; -use rdftk_iri::{Iri, IriRef, Name}; +use rdftk_core::model::graph::{mapping::common_mappings, PrefixMapping}; +use rdftk_iri::{Iri, Name, QName}; use std::str::FromStr; -fn make_mappings() -> PrefixMappingRef { - let mappings = common_mappings(); - { - let mut mut_mappings = mappings.borrow_mut(); - mut_mappings.set_default_namespace(IriRef::from( - Iri::from_str("http://xmlns.com/foaf/0.1/").unwrap(), - )); - } - mappings +fn make_mappings() -> PrefixMapping { + common_mappings().with_default(Iri::from_str("http://xmlns.com/foaf/0.1/").unwrap()) } #[test] fn test_construct_mappings() { let mappings = make_mappings(); - let mappings = mappings.borrow(); assert_eq!(mappings.len(), 5); @@ -40,40 +30,30 @@ fn test_construct_mappings() { #[test] fn test_mapping_expand() { - let mappings = make_mappings(); + let mut mappings = make_mappings(); - { - let mut mut_mappings = mappings.borrow_mut(); - mut_mappings.insert( - Name::new_unchecked("foo"), - IriRef::from(Iri::from_str("http://example.com/schema/foo/1.0/").unwrap()), - ); - } + mappings.insert( + Name::new_unchecked("foo"), + Iri::from_str("http://example.com/schema/foo/1.0/").unwrap(), + ); - let mappings = mappings.borrow(); assert_eq!( mappings.expand(&QName::new_unchecked( Some(Name::new_unchecked("rdf")), Name::new_unchecked("Bag") )), - Some(IriRef::from( - Iri::from_str("http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag").unwrap() - )) + Some(Iri::from_str("http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag").unwrap()) ); assert_eq!( mappings.expand(&QName::new_unchecked(None, Name::new_unchecked("knows"))), - Some(IriRef::from( - Iri::from_str("http://xmlns.com/foaf/0.1/knows").unwrap() - )) + Some(Iri::from_str("http://xmlns.com/foaf/0.1/knows").unwrap()) ); assert_eq!( mappings.expand(&QName::new_unchecked( Some(Name::new_unchecked("foo")), Name::new_unchecked("Bar") )), - Some(IriRef::from( - Iri::from_str("http://example.com/schema/foo/1.0/Bar").unwrap() - )) + Some(Iri::from_str("http://example.com/schema/foo/1.0/Bar").unwrap()) ); assert_eq!( @@ -88,27 +68,23 @@ fn test_mapping_expand() { #[test] fn test_mapping_compress() { let mappings = make_mappings(); - let mappings = mappings.borrow(); assert_eq!( - mappings.compress(&IriRef::from( - Iri::from_str("http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag").unwrap() - )), + mappings + .compress(&Iri::from_str("http://www.w3.org/1999/02/22-rdf-syntax-ns#Bag").unwrap()), Some(QName::new_unchecked( Some(Name::new_unchecked("rdf")), Name::new_unchecked("Bag") )) ); assert_eq!( - mappings.compress(&IriRef::from( - Iri::from_str("http://xmlns.com/foaf/0.1/knows").unwrap() - )), + mappings.compress(&Iri::from_str("http://xmlns.com/foaf/0.1/knows").unwrap()), Some(QName::new_unchecked(None, Name::new_unchecked("knows"))) ); assert_eq!( - mappings.compress(&IriRef::from( - Iri::from_str("http://www.w3.org/2003/01/geo/wgs84_pos#SpatialThing").unwrap() - )), + mappings.compress( + &Iri::from_str("http://www.w3.org/2003/01/geo/wgs84_pos#SpatialThing").unwrap() + ), None ); } diff --git a/rdftk_core/tests/qnames.rs b/rdftk_core/tests/qnames.rs index 0bebd6a..fc31907 100644 --- a/rdftk_core/tests/qnames.rs +++ b/rdftk_core/tests/qnames.rs @@ -1,5 +1,4 @@ -use rdftk_core::model::qname::QName; -use rdftk_iri::Name; +use rdftk_iri::{Name, QName}; use std::str::FromStr; #[test] diff --git a/rdftk_core/tests/resources.rs b/rdftk_core/tests/resources.rs index cb0f260..326e9a7 100644 --- a/rdftk_core/tests/resources.rs +++ b/rdftk_core/tests/resources.rs @@ -1,35 +1,28 @@ -use rdftk_core::model::statement::StatementList; -use rdftk_core::simple::resource::Resource; -use rdftk_iri::{Iri, IriRef}; +use rdftk_core::simple::{resource::Resource, statement::SimpleStatement}; +use rdftk_iri::Iri; use std::str::FromStr; -fn contact(name: &str) -> IriRef { +fn contact(name: &str) -> Iri { Iri::from_str(&format!( "http://www.w3.org/2000/10/swap/pim/contact#{}", name )) .unwrap() - .into() } #[test] fn wikipedia_example_01() { - let resource = Resource::named( - Iri::from_str("http://www.w3.org/People/EM/contact#me") - .unwrap() - .into(), - ) - .literal_str(contact("fullName"), "Eric Miller") - .resource_named( - contact("mailbox"), - Iri::from_str("mailto:e.miller123(at)example") - .unwrap() - .into(), - ) - .literal_str(contact("personalTitle"), "Dr.") - .instance_of(contact("Person")) - .to_owned(); - let sts: StatementList = resource.into(); + let resource = + Resource::named(Iri::from_str("http://www.w3.org/People/EM/contact#me").unwrap()) + .literal_str(contact("fullName"), "Eric Miller") + .resource_named( + contact("mailbox"), + Iri::from_str("mailto:e.miller123(at)example").unwrap(), + ) + .literal_str(contact("personalTitle"), "Dr.") + .instance_of(contact("Person")) + .to_owned(); + let sts: Vec = resource.into(); assert_eq!(sts.len(), 4); for st in sts { println!("{}", st); diff --git a/rdftk_core/tests/statements.rs b/rdftk_core/tests/statements.rs index cbd5dcd..f41f317 100644 --- a/rdftk_core/tests/statements.rs +++ b/rdftk_core/tests/statements.rs @@ -1,14 +1,14 @@ -use rdftk_core::model::literal::DataType; -use rdftk_core::model::statement::reify_statement; -use rdftk_core::simple::literal::literal_factory; -use rdftk_core::simple::statement::statement_factory; +use rdftk_core::model::literal::{DataType, LiteralFactory}; +use rdftk_core::model::statement::{Statement, StatementFactory}; +use rdftk_core::simple::literal::SimpleLiteralFactory; +use rdftk_core::simple::statement::SimpleStatementFactory; use rdftk_iri::Iri; use rdftk_names::{rdf, rdfs}; use std::str::FromStr; #[test] fn make_a_statement() { - let factory = statement_factory(); + let factory = SimpleStatementFactory::default(); let st = factory .statement( factory.blank_subject_named("B01").unwrap(), @@ -21,7 +21,7 @@ fn make_a_statement() { #[test] fn reify_a_statement() { - let factory = statement_factory(); + let factory = SimpleStatementFactory::default(); let st = factory .statement( factory.blank_subject_named("B01").unwrap(), @@ -29,13 +29,13 @@ fn reify_a_statement() { factory.named_object(rdfs::class().clone()), ) .unwrap(); - let sts = reify_statement(&st, &factory).unwrap(); + let sts = st.reify(&factory).unwrap(); assert_eq!(sts.1.len(), 4); } #[test] fn reify_nested_statement() { - let factory = statement_factory(); + let factory = SimpleStatementFactory::default(); let st = factory .statement( @@ -47,14 +47,14 @@ fn reify_nested_statement() { let st = factory .statement( - factory.statement_subject(st), + factory.statement_subject(st.into()), rdf::a_type().clone(), factory.named_object(rdf::statement().clone()), ) .unwrap(); println!("{}", st); - let sts = reify_statement(&st, &factory).unwrap(); + let sts = st.reify(&factory).unwrap(); for st in &sts.1 { println!("{}", st); } @@ -64,8 +64,8 @@ fn reify_nested_statement() { #[test] fn make_literal_statement() { - let factory = statement_factory(); - let literals = literal_factory(); + let factory = SimpleStatementFactory::default(); + let literals = SimpleLiteralFactory::default(); let st = factory .statement( factory.blank_subject_named("B01").unwrap(), @@ -81,8 +81,8 @@ fn make_literal_statement() { #[test] fn make_typed_literal_statement() { - let factory = statement_factory(); - let literals = literal_factory(); + let factory = SimpleStatementFactory::default(); + let literals = SimpleLiteralFactory::default(); let st = factory .statement( factory.blank_subject_named("B01").unwrap(), @@ -98,24 +98,22 @@ fn make_typed_literal_statement() { #[test] fn make_an_embedded_statement() { - let factory = statement_factory(); + let factory = SimpleStatementFactory::default(); // <<...>> let about = factory .statement( - factory.named_subject(Iri::from_str("http://example.org/s").unwrap().into()), - Iri::from_str("http://example.org/p").unwrap().into(), - factory.named_object(Iri::from_str("http://example.org/o").unwrap().into()), + factory.named_subject(Iri::from_str("http://example.org/s").unwrap()), + Iri::from_str("http://example.org/p").unwrap(), + factory.named_object(Iri::from_str("http://example.org/o").unwrap()), ) .unwrap(); let st = factory .statement( factory.blank_subject_named("a").unwrap(), - Iri::from_str("http://example.org/v/occurenceOf") - .unwrap() - .into(), - factory.statement_object(about), + Iri::from_str("http://example.org/v/occurenceOf").unwrap(), + factory.statement_object(about.into()), ) .unwrap();