diff --git a/lib/src/model/blank_node.rs b/lib/src/model/blank_node.rs index 4126d5ac..1afceb0c 100644 --- a/lib/src/model/blank_node.rs +++ b/lib/src/model/blank_node.rs @@ -1,11 +1,12 @@ +use rand::random; use rio_api::model as rio; use std::fmt; +use std::io::Write; use std::str; -use uuid::Uuid; /// A RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node). /// -/// This implementation enforces that the blank node id is an UUID to easily ensure +/// This implementation enforces that the blank node id is a uniquely generated ID to easily ensure /// that it is not possible for two blank nodes to share an id. /// /// The common way to create a new blank node is to use the `Default::default` trait method. @@ -15,19 +16,26 @@ use uuid::Uuid; /// #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] pub struct BlankNode { - uuid: Uuid, + id: u128, str: [u8; 32], } impl BlankNode { + /// Creates a blank node from a unique id + pub(crate) fn new_from_unique_id(id: u128) -> Self { + let mut str = [0; 32]; + write!(&mut str[..], "{:x}", id).unwrap(); + Self { id, str } + } + /// Returns the underlying ID of this blank node pub fn as_str(&self) -> &str { str::from_utf8(&self.str).unwrap() } - /// Returns the underlying UUID of this blank node - pub fn uuid(&self) -> Uuid { - self.uuid + /// Returns the underlying ID of this blank node + pub(crate) fn id(&self) -> u128 { + self.id } } @@ -40,15 +48,7 @@ impl fmt::Display for BlankNode { impl Default for BlankNode { /// Builds a new RDF [blank node](https://www.w3.org/TR/rdf11-concepts/#dfn-blank-node) with a unique id fn default() -> Self { - Self::from(Uuid::new_v4()) - } -} - -impl From for BlankNode { - fn from(id: Uuid) -> Self { - let mut str = [0; 32]; - id.to_simple().encode_lower(&mut str); - Self { uuid: id, str } + Self::new_from_unique_id(random::()) } } diff --git a/lib/src/sparql/algebra.rs b/lib/src/sparql/algebra.rs index 0af8c0a2..f194f046 100644 --- a/lib/src/sparql/algebra.rs +++ b/lib/src/sparql/algebra.rs @@ -770,9 +770,7 @@ impl<'a> fmt::Display for SparqlGraphPattern<'a> { SparqlGraphPattern(&*a), SparqlGraphPattern(&*b), ), - GraphPattern::Graph(g, p) => { - write!(f, "GRAPH {} {{ {} }}", g, SparqlGraphPattern(&*p),) - } + GraphPattern::Graph(g, p) => write!(f, "GRAPH {} {{ {} }}", g, SparqlGraphPattern(&*p),), GraphPattern::Extend(p, v, e) => write!( f, "{} BIND({} AS {})", diff --git a/lib/src/sparql/eval.rs b/lib/src/sparql/eval.rs index 01011f7c..cb9b998e 100644 --- a/lib/src/sparql/eval.rs +++ b/lib/src/sparql/eval.rs @@ -40,7 +40,7 @@ type EncodedTuplesIterator<'a> = Box> + pub struct SimpleEvaluator { dataset: DatasetView, - bnodes_map: Mutex>, + bnodes_map: Mutex>, base_iri: Option>, now: DateTime, } @@ -872,19 +872,21 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { if let EncodedTerm::StringLiteral { value_id } = self.eval_expression(id, tuple)? { - Some(EncodedTerm::BlankNode( - *self + Some(EncodedTerm::BlankNode { + id: *self .bnodes_map .lock() .ok()? .entry(value_id) - .or_insert_with(Uuid::new_v4), - )) + .or_insert_with(random::), + }) } else { None } } - None => Some(EncodedTerm::BlankNode(Uuid::new_v4())), + None => Some(EncodedTerm::BlankNode { + id: random::(), + }), }, PlanExpression::Rand => Some(random::().into()), PlanExpression::Abs(e) => match self.eval_expression(e, tuple)? { @@ -1411,7 +1413,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { match term { EncodedTerm::DefaultGraph => None, EncodedTerm::NamedNode { iri_id } => Some(iri_id), - EncodedTerm::BlankNode(_) => None, + EncodedTerm::BlankNode { .. } => None, EncodedTerm::StringLiteral { value_id } | EncodedTerm::LangStringLiteral { value_id, .. } | EncodedTerm::TypedLiteral { value_id, .. } => Some(value_id), @@ -1584,7 +1586,7 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { match a { EncodedTerm::DefaultGraph | EncodedTerm::NamedNode { .. } - | EncodedTerm::BlankNode(_) + | EncodedTerm::BlankNode { .. } | EncodedTerm::LangStringLiteral { .. } => Some(a == b), EncodedTerm::StringLiteral { value_id: a } => match b { EncodedTerm::StringLiteral { value_id: b } => Some(a == b), @@ -1706,8 +1708,8 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { fn cmp_terms(&self, a: Option, b: Option) -> Ordering { match (a, b) { (Some(a), Some(b)) => match a { - EncodedTerm::BlankNode(a) => { - if let EncodedTerm::BlankNode(b) = b { + EncodedTerm::BlankNode { id: a } => { + if let EncodedTerm::BlankNode { id: b } = b { a.cmp(&b) } else { Ordering::Less @@ -1717,11 +1719,13 @@ impl<'a, S: StoreConnection + 'a> SimpleEvaluator { EncodedTerm::NamedNode { iri_id: b } => { self.compare_str_ids(a, b).unwrap_or(Ordering::Equal) } - EncodedTerm::BlankNode(_) => Ordering::Greater, + EncodedTerm::BlankNode { .. } => Ordering::Greater, _ => Ordering::Less, }, a => match b { - EncodedTerm::NamedNode { .. } | EncodedTerm::BlankNode(_) => Ordering::Greater, + EncodedTerm::NamedNode { .. } | EncodedTerm::BlankNode { .. } => { + Ordering::Greater + } b => self.partial_cmp_literals(a, b).unwrap_or(Ordering::Equal), }, }, diff --git a/lib/src/sparql/model.rs b/lib/src/sparql/model.rs index 3e27a0e7..0e1a60dd 100644 --- a/lib/src/sparql/model.rs +++ b/lib/src/sparql/model.rs @@ -3,12 +3,12 @@ use crate::sparql::json_results::write_json_results; use crate::sparql::xml_results::{read_xml_results, write_xml_results}; use crate::{FileSyntax, GraphSyntax, Result}; use failure::format_err; +use rand::random; use rio_api::formatter::TriplesFormatter; use rio_turtle::{NTriplesFormatter, TurtleFormatter}; use rio_xml::RdfXmlFormatter; use std::fmt; use std::io::{BufRead, Write}; -use uuid::Uuid; /// Results of a [SPARQL query](https://www.w3.org/TR/sparql11-query/) pub enum QueryResult<'a> { @@ -145,8 +145,8 @@ impl<'a> BindingsIterator<'a> { #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] pub enum Variable { Variable { name: String }, - BlankNode { id: Uuid }, - Internal { id: Uuid }, + BlankNode { id: u128 }, + Internal { id: u128 }, } impl Variable { @@ -173,22 +173,24 @@ impl fmt::Display for Variable { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Variable::Variable { name } => write!(f, "?{}", name), - Variable::BlankNode { id } => write!(f, "_:{}", id.to_simple()), - Variable::Internal { id } => write!(f, "?{}", id.to_simple()), + Variable::BlankNode { id } => write!(f, "_:{:x}", id), + Variable::Internal { id } => write!(f, "?{:x}", id), } } } impl Default for Variable { fn default() -> Self { - Variable::Internal { id: Uuid::new_v4() } + Variable::Internal { + id: random::(), + } } } impl From for Variable { fn from(blank_node: BlankNode) -> Self { Variable::BlankNode { - id: blank_node.uuid(), + id: blank_node.id(), } } } diff --git a/lib/src/store/numeric_encoder.rs b/lib/src/store/numeric_encoder.rs index 2af46ad7..d81718e7 100644 --- a/lib/src/store/numeric_encoder.rs +++ b/lib/src/store/numeric_encoder.rs @@ -9,6 +9,7 @@ use failure::format_err; use failure::Backtrace; use failure::Fail; use ordered_float::OrderedFloat; +use rand::random; use rio_api::model as rio; use rust_decimal::Decimal; use std::collections::{BTreeMap, HashMap}; @@ -19,7 +20,6 @@ use std::ops::Deref; use std::str; use std::sync::PoisonError; use std::sync::RwLock; -use uuid::Uuid; const EMPTY_STRING_ID: u64 = 0; const RDF_LANG_STRING_ID: u64 = 1; @@ -184,7 +184,7 @@ pub const ENCODED_XSD_DATE_TIME_NAMED_NODE: EncodedTerm = EncodedTerm::NamedNode pub enum EncodedTerm { DefaultGraph, NamedNode { iri_id: u64 }, - BlankNode(Uuid), + BlankNode { id: u128 }, StringLiteral { value_id: u64 }, LangStringLiteral { value_id: u64, language_id: u64 }, TypedLiteral { value_id: u64, datatype_id: u64 }, @@ -210,7 +210,7 @@ impl EncodedTerm { pub fn is_blank_node(&self) -> bool { match self { - EncodedTerm::BlankNode(_) => true, + EncodedTerm::BlankNode { .. } => true, _ => false, } } @@ -260,7 +260,7 @@ impl EncodedTerm { match self { EncodedTerm::DefaultGraph { .. } => TYPE_DEFAULT_GRAPH_ID, EncodedTerm::NamedNode { .. } => TYPE_NAMED_NODE_ID, - EncodedTerm::BlankNode(_) => TYPE_BLANK_NODE_ID, + EncodedTerm::BlankNode { .. } => TYPE_BLANK_NODE_ID, EncodedTerm::StringLiteral { .. } => TYPE_STRING_LITERAL, EncodedTerm::LangStringLiteral { .. } => TYPE_LANG_STRING_LITERAL_ID, EncodedTerm::TypedLiteral { .. } => TYPE_TYPED_LITERAL_ID, @@ -365,7 +365,7 @@ impl From for EncodedTerm { impl From for EncodedTerm { fn from(node: BlankNode) -> Self { - EncodedTerm::BlankNode(node.uuid()) + EncodedTerm::BlankNode { id: node.id() } } } @@ -410,11 +410,9 @@ impl TermReader for R { TYPE_NAMED_NODE_ID => Ok(EncodedTerm::NamedNode { iri_id: self.read_u64::()?, }), - TYPE_BLANK_NODE_ID => { - let mut uuid_buffer = [0 as u8; 16]; - self.read_exact(&mut uuid_buffer)?; - Ok(EncodedTerm::BlankNode(Uuid::from_bytes(uuid_buffer))) - } + TYPE_BLANK_NODE_ID => Ok(EncodedTerm::BlankNode { + id: self.read_u128::()?, + }), TYPE_LANG_STRING_LITERAL_ID => Ok(EncodedTerm::LangStringLiteral { language_id: self.read_u64::()?, value_id: self.read_u64::()?, @@ -576,7 +574,7 @@ impl TermWriter for W { match term { EncodedTerm::DefaultGraph => {} EncodedTerm::NamedNode { iri_id } => self.write_u64::(iri_id)?, - EncodedTerm::BlankNode(id) => self.write_all(id.as_bytes())?, + EncodedTerm::BlankNode { id } => self.write_u128::(id)?, EncodedTerm::StringLiteral { value_id } => { self.write_u64::(value_id)?; } @@ -686,7 +684,9 @@ impl Encoder { } pub fn encode_blank_node(&self, blank_node: &BlankNode) -> Result { - Ok(EncodedTerm::BlankNode(blank_node.uuid())) + Ok(EncodedTerm::BlankNode { + id: blank_node.id(), + }) } pub fn encode_literal(&self, literal: &Literal) -> Result { @@ -742,14 +742,14 @@ impl Encoder { pub fn encode_rio_blank_node( &self, blank_node: rio::BlankNode, - bnodes_map: &mut HashMap, + bnodes_map: &mut HashMap, ) -> Result { - Ok(if let Some(uuid) = bnodes_map.get(blank_node.id) { - EncodedTerm::BlankNode(*uuid) + Ok(if let Some(id) = bnodes_map.get(blank_node.id) { + EncodedTerm::BlankNode { id: *id } } else { - let uuid = Uuid::new_v4(); - bnodes_map.insert(blank_node.id.to_owned(), uuid); - EncodedTerm::BlankNode(uuid) + let id = random::(); + bnodes_map.insert(blank_node.id.to_owned(), id); + EncodedTerm::BlankNode { id } }) } @@ -813,7 +813,7 @@ impl Encoder { pub fn encode_rio_named_or_blank_node( &self, term: rio::NamedOrBlankNode, - bnodes_map: &mut HashMap, + bnodes_map: &mut HashMap, ) -> Result { match term { rio::NamedOrBlankNode::NamedNode(named_node) => self.encode_rio_named_node(named_node), @@ -826,7 +826,7 @@ impl Encoder { pub fn encode_rio_term( &self, term: rio::Term, - bnodes_map: &mut HashMap, + bnodes_map: &mut HashMap, ) -> Result { match term { rio::Term::NamedNode(named_node) => self.encode_rio_named_node(named_node), @@ -838,7 +838,7 @@ impl Encoder { pub fn encode_rio_quad( &self, quad: rio::Quad, - bnodes_map: &mut HashMap, + bnodes_map: &mut HashMap, ) -> Result { Ok(EncodedQuad { subject: self.encode_rio_named_or_blank_node(quad.subject, bnodes_map)?, @@ -855,7 +855,7 @@ impl Encoder { &self, triple: rio::Triple, graph_name: EncodedTerm, - bnodes_map: &mut HashMap, + bnodes_map: &mut HashMap, ) -> Result { Ok(EncodedQuad { subject: self.encode_rio_named_or_blank_node(triple.subject, bnodes_map)?, @@ -939,7 +939,7 @@ impl Encoder { EncodedTerm::NamedNode { iri_id } => { Ok(NamedNode::new_from_string(self.get_str(iri_id)?).into()) } - EncodedTerm::BlankNode(id) => Ok(BlankNode::from(id).into()), + EncodedTerm::BlankNode { id } => Ok(BlankNode::new_from_unique_id(id).into()), EncodedTerm::StringLiteral { value_id } => { Ok(Literal::new_simple_literal(self.get_str(value_id)?).into()) }