use crate::oxrdf::{Term, Variable, VariableRef};
use std::fmt;
use std::iter::Zip;
use std::ops::Index;
use std::sync::Arc;
pub struct QuerySolution {
variables: Arc<[Variable]>,
values: Vec<Option<Term>>,
}
impl QuerySolution {
#[inline]
pub fn get(&self, index: impl VariableSolutionIndex) -> Option<&Term> {
self.values.get(index.index(self)?).and_then(Option::as_ref)
}
#[inline]
pub fn len(&self) -> usize {
self.values.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.values.iter().all(Option::is_none)
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (&Variable, &Term)> {
self.into_iter()
}
#[inline]
pub fn values(&self) -> &[Option<Term>] {
&self.values
}
#[inline]
pub fn variables(&self) -> &[Variable] {
&self.variables
}
}
impl<V: Into<Arc<[Variable]>>, S: Into<Vec<Option<Term>>>> From<(V, S)> for QuerySolution {
#[inline]
fn from((v, s): (V, S)) -> Self {
Self {
variables: v.into(),
values: s.into(),
}
}
}
impl<'a> IntoIterator for &'a QuerySolution {
type Item = (&'a Variable, &'a Term);
type IntoIter = Iter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Iter {
inner: self.variables.iter().zip(&self.values),
}
}
}
impl Index<usize> for QuerySolution {
type Output = Term;
#[allow(clippy::panic)]
#[inline]
fn index(&self, index: usize) -> &Self::Output {
self.get(index)
.unwrap_or_else(|| panic!("The column {index} is not set in this solution"))
}
}
impl Index<&str> for QuerySolution {
type Output = Term;
#[allow(clippy::panic)]
#[inline]
fn index(&self, index: &str) -> &Self::Output {
self.get(index)
.unwrap_or_else(|| panic!("The variable ?{index} is not set in this solution"))
}
}
impl Index<VariableRef<'_>> for QuerySolution {
type Output = Term;
#[allow(clippy::panic)]
#[inline]
fn index(&self, index: VariableRef<'_>) -> &Self::Output {
self.get(index)
.unwrap_or_else(|| panic!("The variable {index} is not set in this solution"))
}
}
impl Index<Variable> for QuerySolution {
type Output = Term;
#[inline]
fn index(&self, index: Variable) -> &Self::Output {
self.index(index.as_ref())
}
}
impl Index<&Variable> for QuerySolution {
type Output = Term;
#[inline]
fn index(&self, index: &Variable) -> &Self::Output {
self.index(index.as_ref())
}
}
impl PartialEq for QuerySolution {
fn eq(&self, other: &Self) -> bool {
for (k, v) in self.iter() {
if other.get(k) != Some(v) {
return false;
}
}
for (k, v) in other.iter() {
if self.get(k) != Some(v) {
return false;
}
}
true
}
}
impl Eq for QuerySolution {}
impl fmt::Debug for QuerySolution {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
pub struct Iter<'a> {
inner: Zip<std::slice::Iter<'a, Variable>, std::slice::Iter<'a, Option<Term>>>,
}
impl<'a> Iterator for Iter<'a> {
type Item = (&'a Variable, &'a Term);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
for (variable, value) in &mut self.inner {
if let Some(value) = value {
return Some((variable, value));
}
}
None
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.inner.size_hint().1)
}
}
pub trait VariableSolutionIndex {
fn index(self, solution: &QuerySolution) -> Option<usize>;
}
impl VariableSolutionIndex for usize {
#[inline]
fn index(self, _: &QuerySolution) -> Option<usize> {
Some(self)
}
}
impl VariableSolutionIndex for &str {
#[inline]
fn index(self, solution: &QuerySolution) -> Option<usize> {
solution.variables.iter().position(|v| v.as_str() == self)
}
}
impl VariableSolutionIndex for VariableRef<'_> {
#[inline]
fn index(self, solution: &QuerySolution) -> Option<usize> {
solution.variables.iter().position(|v| *v == self)
}
}
impl VariableSolutionIndex for &Variable {
#[inline]
fn index(self, solution: &QuerySolution) -> Option<usize> {
self.as_ref().index(solution)
}
}
impl VariableSolutionIndex for Variable {
#[inline]
fn index(self, solution: &QuerySolution) -> Option<usize> {
self.as_ref().index(solution)
}
}