parent
cdafcfc2cc
commit
7ed4252ad8
@ -1,3 +1,3 @@ |
||||
pub mod algebra; |
||||
pub mod model; |
||||
pub mod parser; |
||||
pub mod xml_results; |
||||
|
@ -1,64 +0,0 @@ |
||||
use model::*; |
||||
use sparql::algebra::TermOrVariable; |
||||
use sparql::algebra::Variable; |
||||
use std::collections::BTreeMap; |
||||
use std::fmt; |
||||
|
||||
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Hash)] |
||||
pub struct Binding(BTreeMap<Variable, Term>); |
||||
|
||||
impl Binding { |
||||
pub fn insert(&mut self, var: Variable, value: Term) { |
||||
self.0.insert(var, value); |
||||
} |
||||
|
||||
pub fn get<'a>(&'a self, key: &'a Variable) -> Option<&'a Term> { |
||||
self.0.get(key) |
||||
} |
||||
|
||||
pub fn get_or_constant<'a>(&'a self, key: &'a TermOrVariable) -> Option<Term> { |
||||
match key { |
||||
TermOrVariable::NamedNode(node) => Some(node.clone().into()), |
||||
TermOrVariable::Literal(literal) => Some(literal.clone().into()), |
||||
TermOrVariable::Variable(v) => self.get(v).cloned(), |
||||
} |
||||
} |
||||
|
||||
pub fn iter(&self) -> <&BTreeMap<Variable, Term> as IntoIterator>::IntoIter { |
||||
self.0.iter() |
||||
} |
||||
} |
||||
|
||||
impl Default for Binding { |
||||
fn default() -> Self { |
||||
Binding(BTreeMap::default()) |
||||
} |
||||
} |
||||
|
||||
impl IntoIterator for Binding { |
||||
type Item = (Variable, Term); |
||||
type IntoIter = <BTreeMap<Variable, Term> as IntoIterator>::IntoIter; |
||||
|
||||
fn into_iter(self) -> <BTreeMap<Variable, Term> as IntoIterator>::IntoIter { |
||||
self.0.into_iter() |
||||
} |
||||
} |
||||
|
||||
impl<'a> IntoIterator for &'a Binding { |
||||
type Item = (&'a Variable, &'a Term); |
||||
type IntoIter = <&'a BTreeMap<Variable, Term> as IntoIterator>::IntoIter; |
||||
|
||||
fn into_iter(self) -> <&'a BTreeMap<Variable, Term> as IntoIterator>::IntoIter { |
||||
self.0.iter() |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for Binding { |
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
||||
write!(f, "{{")?; |
||||
for (var, val) in self { |
||||
write!(f, " {} → {} ", var, val)?; |
||||
} |
||||
write!(f, "}}") |
||||
} |
||||
} |
@ -0,0 +1,333 @@ |
||||
use errors::*; |
||||
use model::*; |
||||
use quick_xml::events::Event; |
||||
use quick_xml::Reader; |
||||
use sparql::algebra::BindingsIterator; |
||||
use sparql::algebra::QueryResult; |
||||
use sparql::algebra::Variable; |
||||
use std::collections::BTreeMap; |
||||
use std::io::BufRead; |
||||
use std::iter::empty; |
||||
use std::str::FromStr; |
||||
|
||||
pub fn read_xml_results(source: impl BufRead + 'static) -> Result<QueryResult> { |
||||
enum State { |
||||
Start, |
||||
Sparql, |
||||
Head, |
||||
AfterHead, |
||||
Boolean, |
||||
} |
||||
|
||||
let mut reader = Reader::from_reader(source); |
||||
reader.trim_text(true); |
||||
|
||||
let mut buffer = Vec::default(); |
||||
let mut namespace_buffer = Vec::default(); |
||||
let mut variables: Vec<String> = Vec::default(); |
||||
let mut state = State::Start; |
||||
|
||||
//Read header
|
||||
loop { |
||||
let event = { |
||||
let (ns, event) = reader.read_namespaced_event(&mut buffer, &mut namespace_buffer)?; |
||||
if let Some(ns) = ns { |
||||
if ns != b"http://www.w3.org/2005/sparql-results#".as_ref() { |
||||
return Err(format!( |
||||
"Unexpected namespace found in RDF/XML query result: {}", |
||||
reader.decode(ns) |
||||
).into()); |
||||
} |
||||
} |
||||
event |
||||
}; |
||||
match event { |
||||
Event::Start(event) => match state { |
||||
State::Start => { |
||||
if event.name() == b"sparql" { |
||||
state = State::Sparql; |
||||
} else { |
||||
return Err(format!("Expecting <sparql> tag, found {}", reader.decode(event.name())).into()); |
||||
} |
||||
} |
||||
State::Sparql => { |
||||
if event.name() == b"head" { |
||||
state = State::Head; |
||||
} else { |
||||
return Err(format!("Expecting <head> tag, found {}", reader.decode(event.name())).into()); |
||||
} |
||||
} |
||||
State::Head => if event.name() == b"variable" || event.name() == b"link" { |
||||
return Err("<variable> and <link> tag should be autoclosing".into()); |
||||
} else { |
||||
return Err(format!("Expecting <variable> or <link> tag, found {}", reader.decode(event.name())).into()); |
||||
}, |
||||
State::AfterHead => { |
||||
if event.name() == b"boolean" { |
||||
state = State::Boolean |
||||
} else if event.name() == b"results" { |
||||
let mut mapping = BTreeMap::default(); |
||||
for (i,var) in variables.iter().enumerate() { |
||||
mapping.insert(var.as_bytes().to_vec(), i); |
||||
} |
||||
return Ok(QueryResult::Bindings(BindingsIterator::new( |
||||
variables.into_iter().map(Variable::new).collect(), |
||||
Box::new(ResultsIterator { |
||||
reader, |
||||
buffer: Vec::default(), |
||||
namespace_buffer, |
||||
mapping, |
||||
bnodes_map: BTreeMap::default(), |
||||
}), |
||||
))); |
||||
} else if event.name() != b"link" && event.name() != b"results" && event.name() != b"boolean" { |
||||
return Err(format!("Expecting sparql tag, found {}", reader.decode(event.name())).into()); |
||||
} |
||||
} |
||||
State::Boolean => return Err(format!("Unexpected tag inside of <boolean> tag: {}", reader.decode(event.name())).into()) |
||||
}, |
||||
Event::Empty(event) => match state { |
||||
State::Head => { |
||||
if event.name() == b"variable" { |
||||
let name = event.attributes() |
||||
.filter(|attr| attr.is_ok()) |
||||
.map(|attr| attr.unwrap()) |
||||
.find(|attr| attr.key == b"name") |
||||
.ok_or("No name attribute found for the <variable> tag"); |
||||
variables.push(name?.unescape_and_decode_value(&reader)?); |
||||
} else if event.name() == b"link" { |
||||
// no op
|
||||
} else { |
||||
return Err(format!("Expecting <variable> or <link> tag, found {}", reader.decode(event.name())).into()); |
||||
} |
||||
}, |
||||
State::AfterHead => { |
||||
if event.name() == b"results" { |
||||
return Ok(QueryResult::Bindings(BindingsIterator::new( |
||||
variables.into_iter().map(Variable::new).collect(), |
||||
Box::new(empty()), |
||||
))) |
||||
} else { |
||||
return Err(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name())).into()) |
||||
} |
||||
} |
||||
_ => return Err(format!("Unexpected autoclosing tag <{}>", reader.decode(event.name())).into()) |
||||
}, |
||||
Event::Text(event) => { |
||||
let value = event.unescaped()?; |
||||
return match state { |
||||
State::Boolean => { |
||||
return if value.as_ref() == b"true" { |
||||
Ok(QueryResult::Boolean(true)) |
||||
} else if value.as_ref() == b"false" { |
||||
Ok(QueryResult::Boolean(false)) |
||||
} else { |
||||
Err(format!("Unexpected boolean value. Found {}", reader.decode(&value)).into()) |
||||
}; |
||||
} |
||||
_ => Err(format!("Unexpected textual value found: {}", reader.decode(&value)).into()) |
||||
}; |
||||
}, |
||||
Event::End(_) => match state { |
||||
State::Head => state = State::AfterHead, |
||||
_ => { |
||||
return Err("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag".into()); |
||||
} |
||||
}, |
||||
Event::Eof => return Err("Unexpected early file end. All results file should have a <head> and a <result> or <boolean> tag".into()), |
||||
_ => (), |
||||
} |
||||
} |
||||
} |
||||
|
||||
struct ResultsIterator<R: BufRead> { |
||||
reader: Reader<R>, |
||||
buffer: Vec<u8>, |
||||
namespace_buffer: Vec<u8>, |
||||
mapping: BTreeMap<Vec<u8>, usize>, |
||||
bnodes_map: BTreeMap<Vec<u8>, BlankNode>, |
||||
} |
||||
|
||||
impl<R: BufRead> Iterator for ResultsIterator<R> { |
||||
type Item = Result<Vec<Option<Term>>>; |
||||
|
||||
fn next(&mut self) -> Option<Result<Vec<Option<Term>>>> { |
||||
enum State { |
||||
Start, |
||||
Result, |
||||
Binding, |
||||
Uri, |
||||
BNode, |
||||
Literal, |
||||
End, |
||||
} |
||||
let mut state = State::Start; |
||||
|
||||
let mut new_bindings = Vec::default(); |
||||
new_bindings.resize(self.mapping.len(), None); |
||||
|
||||
let mut current_var = None; |
||||
let mut term: Option<Term> = None; |
||||
let mut lang = None; |
||||
let mut datatype = None; |
||||
loop { |
||||
let (ns, event) = match self |
||||
.reader |
||||
.read_namespaced_event(&mut self.buffer, &mut self.namespace_buffer) |
||||
{ |
||||
Ok(v) => v, |
||||
Err(error) => return Some(Err(error.into())), |
||||
}; |
||||
if let Some(ns) = ns { |
||||
if ns != b"http://www.w3.org/2005/sparql-results#".as_ref() { |
||||
return Some(Err(format!( |
||||
"Unexpected namespace found in RDF/XML query result: {}", |
||||
self.reader.decode(ns) |
||||
).into())); |
||||
} |
||||
} |
||||
match event { |
||||
Event::Start(event) => match state { |
||||
State::Start => if event.name() == b"result" { |
||||
state = State::Result; |
||||
} else { |
||||
return Some(Err(format!( |
||||
"Expecting <result>, found {}", |
||||
self.reader.decode(event.name()) |
||||
).into())); |
||||
}, |
||||
State::Result => if event.name() == b"binding" { |
||||
match event |
||||
.attributes() |
||||
.filter(|attr| attr.is_ok()) |
||||
.map(|attr| attr.unwrap()) |
||||
.find(|attr| attr.key == b"name") |
||||
{ |
||||
Some(attr) => match attr.unescaped_value() { |
||||
Ok(var) => current_var = Some(var.to_vec()), |
||||
Err(error) => return Some(Err(error.into())), |
||||
}, |
||||
None => { |
||||
return Some(Err( |
||||
"No name attribute found for the <binding> tag".into() |
||||
)) |
||||
} |
||||
} |
||||
state = State::Binding; |
||||
} else { |
||||
return Some(Err(format!( |
||||
"Expecting <binding>, found {}", |
||||
self.reader.decode(event.name()) |
||||
).into())); |
||||
}, |
||||
State::Binding => { |
||||
if term.is_some() { |
||||
return Some(Err( |
||||
"There is already a value for the current binding".into() |
||||
)); |
||||
} |
||||
if event.name() == b"uri" { |
||||
state = State::Uri; |
||||
} else if event.name() == b"bnode" { |
||||
state = State::BNode; |
||||
} else if event.name() == b"literal" { |
||||
for attr in event.attributes() { |
||||
if let Ok(attr) = attr { |
||||
if attr.key == b"xml:lang" { |
||||
match attr.unescape_and_decode_value(&self.reader) { |
||||
Ok(val) => lang = Some(val), |
||||
Err(error) => return Some(Err(error.into())), |
||||
} |
||||
} else if attr.key == b"datatype" { |
||||
match attr.unescaped_value() { |
||||
Ok(val) => { |
||||
match NamedNode::from_str(&self.reader.decode(&val)) |
||||
{ |
||||
Ok(dt) => datatype = Some(dt), |
||||
Err(error) => return Some(Err(error)), |
||||
} |
||||
} |
||||
Err(error) => return Some(Err(error.into())), |
||||
} |
||||
} |
||||
} |
||||
} |
||||
state = State::Literal; |
||||
} else { |
||||
return Some(Err(format!( |
||||
"Expecting <uri>, <bnode> or <literal> found {}", |
||||
self.reader.decode(event.name()) |
||||
).into())); |
||||
} |
||||
} |
||||
_ => (), |
||||
}, |
||||
Event::Text(event) => match event.unescaped() { |
||||
Ok(data) => match state { |
||||
State::Uri => match NamedNode::from_str(&self.reader.decode(&data)) { |
||||
Ok(named_node) => term = Some(named_node.into()), |
||||
Err(error) => return Some(Err(error)), |
||||
}, |
||||
State::BNode => { |
||||
term = Some( |
||||
self.bnodes_map |
||||
.entry(data.to_vec()) |
||||
.or_insert_with(BlankNode::default) |
||||
.clone() |
||||
.into(), |
||||
) |
||||
} |
||||
State::Literal => { |
||||
let value = self.reader.decode(&data).to_string(); |
||||
term = Some( |
||||
match datatype { |
||||
Some(ref datatype) => { |
||||
Literal::new_typed_literal(value, datatype.clone()) |
||||
} |
||||
None => match lang { |
||||
Some(ref lang) => Literal::new_language_tagged_literal( |
||||
value, |
||||
lang.clone(), |
||||
), |
||||
None => Literal::new_simple_literal(value), |
||||
}, |
||||
}.into(), |
||||
) |
||||
} |
||||
_ => { |
||||
return Some(Err(format!( |
||||
"Unexpected textual value found: {}", |
||||
self.reader.decode(&data) |
||||
).into())) |
||||
} |
||||
}, |
||||
Err(error) => return Some(Err(error.into())), |
||||
}, |
||||
Event::End(_) => match state { |
||||
State::Start => state = State::End, |
||||
State::Result => return Some(Ok(new_bindings)), |
||||
State::Binding => { |
||||
match (¤t_var, &term) { |
||||
(Some(var), Some(term)) => { |
||||
new_bindings[self.mapping[var]] = Some(term.clone()) |
||||
} |
||||
(Some(var), None) => { |
||||
return Some(Err(format!( |
||||
"No variable found for variable {}", |
||||
self.reader.decode(&var) |
||||
).into())) |
||||
} |
||||
_ => return Some(Err("No name found for <binding> tag".into())), |
||||
} |
||||
term = None; |
||||
state = State::Result; |
||||
} |
||||
State::Uri | State::BNode | State::Literal => state = State::Binding, |
||||
_ => (), |
||||
}, |
||||
Event::Eof => return None, |
||||
_ => (), |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,315 @@ |
||||
use errors::*; |
||||
use sparql::algebra::*; |
||||
use std::iter::once; |
||||
use std::iter::Iterator; |
||||
use std::sync::Arc; |
||||
use store::numeric_encoder::EncodedTerm; |
||||
use store::store::EncodedQuadsStore; |
||||
|
||||
type EncodedBinding = Vec<Option<EncodedTerm>>; |
||||
|
||||
struct EncodedBindingsIterator { |
||||
variables: Vec<Variable>, |
||||
iter: Box<dyn Iterator<Item = Result<EncodedBinding>>>, |
||||
} |
||||
|
||||
impl EncodedBindingsIterator { |
||||
fn take(self, n: usize) -> Self { |
||||
EncodedBindingsIterator { |
||||
variables: self.variables, |
||||
iter: Box::new(self.iter.take(n)), |
||||
} |
||||
} |
||||
|
||||
fn skip(self, n: usize) -> Self { |
||||
EncodedBindingsIterator { |
||||
variables: self.variables, |
||||
iter: Box::new(self.iter.skip(n)), |
||||
} |
||||
} |
||||
|
||||
fn project(self, on_variables: Vec<Variable>) -> Self { |
||||
let EncodedBindingsIterator { variables, iter } = self; |
||||
let projection: Vec<(usize, usize)> = on_variables |
||||
.iter() |
||||
.enumerate() |
||||
.flat_map(|(new_pos, v)| slice_key(&variables, v).map(|old_pos| (old_pos, new_pos))) |
||||
.collect(); |
||||
let new_len = on_variables.len(); |
||||
EncodedBindingsIterator { |
||||
variables: on_variables, |
||||
iter: Box::new(iter.map(move |binding| { |
||||
let binding = binding?; |
||||
let mut new_binding = Vec::with_capacity(new_len); |
||||
new_binding.resize(new_len, None); |
||||
for (old_pos, new_pos) in &projection { |
||||
new_binding[*new_pos] = binding[*old_pos]; |
||||
} |
||||
Ok(new_binding) |
||||
})), |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl Default for EncodedBindingsIterator { |
||||
fn default() -> Self { |
||||
EncodedBindingsIterator { |
||||
variables: Vec::default(), |
||||
iter: Box::new(once(Ok(Vec::default()))), |
||||
} |
||||
} |
||||
} |
||||
|
||||
fn slice_key<T: Eq>(slice: &[T], element: &T) -> Option<usize> { |
||||
for (i, item) in slice.iter().enumerate() { |
||||
if item == element { |
||||
return Some(i); |
||||
} |
||||
} |
||||
None |
||||
} |
||||
|
||||
pub struct SparqlEvaluator<S: EncodedQuadsStore> { |
||||
store: Arc<S>, |
||||
} |
||||
|
||||
impl<S: EncodedQuadsStore> SparqlEvaluator<S> { |
||||
pub fn new(store: Arc<S>) -> Self { |
||||
Self { store } |
||||
} |
||||
|
||||
pub fn evaluate(&self, query: &Query) -> Result<QueryResult> { |
||||
match query { |
||||
Query::SelectQuery { algebra, dataset } => { |
||||
Ok(QueryResult::Bindings(self.decode_bindings( |
||||
self.eval_list_pattern(algebra, EncodedBindingsIterator::default())?, |
||||
))) |
||||
} |
||||
_ => unimplemented!(), |
||||
} |
||||
} |
||||
|
||||
fn eval_list_pattern( |
||||
&self, |
||||
pattern: &ListPattern, |
||||
from: EncodedBindingsIterator, |
||||
) -> Result<EncodedBindingsIterator> { |
||||
match pattern { |
||||
ListPattern::Data(bs) => Ok(self.encode_bindings(bs)), |
||||
ListPattern::ToList(l) => self.eval_multi_set_pattern(l, from), |
||||
ListPattern::OrderBy(l, o) => self.eval_list_pattern(l, from), //TODO
|
||||
ListPattern::Project(l, new_variables) => Ok(self |
||||
.eval_list_pattern(l, from)? |
||||
.project(new_variables.to_vec())), |
||||
ListPattern::Distinct(l) => self.eval_list_pattern(l, from), //TODO
|
||||
ListPattern::Reduced(l) => self.eval_list_pattern(l, from), |
||||
ListPattern::Slice(l, start, length) => { |
||||
let mut iter = self.eval_list_pattern(l, from)?; |
||||
if *start > 0 { |
||||
iter = iter.skip(*start); |
||||
} |
||||
if let Some(length) = length { |
||||
iter = iter.take(*length); |
||||
} |
||||
Ok(iter) |
||||
} |
||||
} |
||||
} |
||||
|
||||
fn eval_multi_set_pattern( |
||||
&self, |
||||
pattern: &MultiSetPattern, |
||||
from: EncodedBindingsIterator, |
||||
) -> Result<EncodedBindingsIterator> { |
||||
match pattern { |
||||
MultiSetPattern::BGP(p) => { |
||||
let mut iter = from; |
||||
for pattern in p { |
||||
iter = match pattern { |
||||
TripleOrPathPattern::Triple(pattern) => { |
||||
self.eval_triple_pattern(pattern, iter) |
||||
} |
||||
TripleOrPathPattern::Path(pattern) => self.eval_path_pattern(pattern, iter), |
||||
}?; |
||||
} |
||||
Ok(iter) |
||||
} |
||||
MultiSetPattern::Join(a, b) => { |
||||
self.eval_multi_set_pattern(b, self.eval_multi_set_pattern(a, from)?) |
||||
} |
||||
MultiSetPattern::LeftJoin(a, b, e) => unimplemented!(), |
||||
MultiSetPattern::Filter(e, p) => unimplemented!(), |
||||
MultiSetPattern::Union(a, b) => unimplemented!(), |
||||
MultiSetPattern::Graph(g, p) => unimplemented!(), |
||||
MultiSetPattern::Extend(p, v, e) => unimplemented!(), |
||||
MultiSetPattern::Minus(a, b) => unimplemented!(), |
||||
MultiSetPattern::ToMultiSet(l) => self.eval_list_pattern(l, from), |
||||
MultiSetPattern::Service(n, p, s) => unimplemented!(), |
||||
MultiSetPattern::AggregateJoin(g, a) => unimplemented!(), |
||||
} |
||||
} |
||||
|
||||
fn eval_triple_pattern( |
||||
&self, |
||||
pattern: &TriplePattern, |
||||
from: EncodedBindingsIterator, |
||||
) -> Result<EncodedBindingsIterator> { |
||||
let EncodedBindingsIterator { |
||||
mut variables, |
||||
iter: from_iter, |
||||
} = from; |
||||
let subject = |
||||
self.binding_value_lookup_from_term_or_variable(&pattern.subject, &mut variables)?; |
||||
let predicate = self |
||||
.binding_value_lookup_from_named_node_or_variable(&pattern.predicate, &mut variables)?; |
||||
let object = |
||||
self.binding_value_lookup_from_term_or_variable(&pattern.object, &mut variables)?; |
||||
|
||||
let store = self.store.clone(); |
||||
let variables_len = variables.len(); |
||||
Ok(EncodedBindingsIterator { |
||||
variables, |
||||
iter: Box::new(from_iter.flat_map(move |binding| { |
||||
let result: Box<dyn Iterator<Item = Result<EncodedBinding>>> = match binding { |
||||
Ok(mut binding) => { |
||||
match store.quads_for_pattern( |
||||
subject.get(&binding), |
||||
predicate.get(&binding), |
||||
object.get(&binding), |
||||
None, //TODO
|
||||
) { |
||||
Ok(iter) => Box::new(iter.map(move |quad| { |
||||
let quad = quad?; |
||||
let mut binding = binding.clone(); |
||||
binding.resize(variables_len, None); |
||||
subject.put(quad.subject, &mut binding); |
||||
predicate.put(quad.predicate, &mut binding); |
||||
object.put(quad.object, &mut binding); |
||||
Ok(binding) |
||||
})), |
||||
Err(error) => Box::new(once(Err(error))), |
||||
} |
||||
} |
||||
Err(error) => Box::new(once(Err(error))), |
||||
}; |
||||
result |
||||
})), |
||||
}) |
||||
} |
||||
|
||||
fn eval_path_pattern( |
||||
&self, |
||||
pattern: &PathPattern, |
||||
from: EncodedBindingsIterator, |
||||
) -> Result<EncodedBindingsIterator> { |
||||
unimplemented!() |
||||
} |
||||
|
||||
fn binding_value_lookup_from_term_or_variable( |
||||
&self, |
||||
term_or_variable: &TermOrVariable, |
||||
variables: &mut Vec<Variable>, |
||||
) -> Result<BindingValueLookup> { |
||||
Ok(match term_or_variable { |
||||
TermOrVariable::Term(term) => { |
||||
BindingValueLookup::Constant(self.store.encoder().encode_term(term)?) |
||||
} |
||||
TermOrVariable::Variable(variable) => { |
||||
BindingValueLookup::Variable(match slice_key(variables, variable) { |
||||
Some(key) => key, |
||||
None => { |
||||
variables.push(variable.clone()); |
||||
variables.len() - 1 |
||||
} |
||||
}) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
fn binding_value_lookup_from_named_node_or_variable( |
||||
&self, |
||||
named_node_or_variable: &NamedNodeOrVariable, |
||||
variables: &mut Vec<Variable>, |
||||
) -> Result<BindingValueLookup> { |
||||
Ok(match named_node_or_variable { |
||||
NamedNodeOrVariable::NamedNode(named_node) => { |
||||
BindingValueLookup::Constant(self.store.encoder().encode_named_node(named_node)?) |
||||
} |
||||
NamedNodeOrVariable::Variable(variable) => { |
||||
BindingValueLookup::Variable(match slice_key(variables, variable) { |
||||
Some(key) => key, |
||||
None => { |
||||
variables.push(variable.clone()); |
||||
variables.len() - 1 |
||||
} |
||||
}) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
fn encode_bindings(&self, bindings: &StaticBindings) -> EncodedBindingsIterator { |
||||
let encoder = self.store.encoder(); |
||||
let encoded_values: Vec<Result<EncodedBinding>> = bindings |
||||
.values_iter() |
||||
.map(move |values| { |
||||
let mut result = Vec::with_capacity(values.len()); |
||||
for value in values { |
||||
result.push(match value { |
||||
Some(term) => Some(encoder.encode_term(term)?), |
||||
None => None, |
||||
}); |
||||
} |
||||
Ok(result) |
||||
}).collect(); |
||||
EncodedBindingsIterator { |
||||
variables: bindings.variables().to_vec(), |
||||
iter: Box::new(encoded_values.into_iter()), |
||||
} |
||||
} |
||||
|
||||
fn decode_bindings(&self, iter: EncodedBindingsIterator) -> BindingsIterator { |
||||
let store = self.store.clone(); |
||||
let EncodedBindingsIterator { variables, iter } = iter; |
||||
BindingsIterator::new( |
||||
variables, |
||||
Box::new(iter.map(move |values| { |
||||
let values = values?; |
||||
let encoder = store.encoder(); |
||||
let mut result = Vec::with_capacity(values.len()); |
||||
for value in values { |
||||
result.push(match value { |
||||
Some(term) => Some(encoder.decode_term(term)?), |
||||
None => None, |
||||
}); |
||||
} |
||||
Ok(result) |
||||
})), |
||||
) |
||||
} |
||||
} |
||||
|
||||
#[derive(Clone, Copy)] |
||||
enum BindingValueLookup { |
||||
Constant(EncodedTerm), |
||||
Variable(usize), |
||||
} |
||||
|
||||
impl BindingValueLookup { |
||||
fn get(&self, binding: &[Option<EncodedTerm>]) -> Option<EncodedTerm> { |
||||
match self { |
||||
BindingValueLookup::Constant(term) => Some(*term), |
||||
BindingValueLookup::Variable(v) => if *v < binding.len() { |
||||
binding[*v] |
||||
} else { |
||||
None |
||||
}, |
||||
} |
||||
} |
||||
|
||||
fn put(&self, value: EncodedTerm, binding: &mut EncodedBinding) { |
||||
match self { |
||||
BindingValueLookup::Constant(_) => (), |
||||
BindingValueLookup::Variable(v) => binding[*v] = Some(value), |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue