use core::panic;
use crate::id::id_from_value;
use crate::id::id_into_value;
use crate::id::ID_LEN;
use crate::query::Binding;
use crate::query::Constraint;
use crate::query::Variable;
use crate::query::VariableId;
use crate::query::VariableSet;
use crate::trible::TribleSet;
use crate::inline::encodings::genid::GenId;
use crate::inline::RawInline;
use crate::inline::InlineEncoding;
use crate::inline::INLINE_LEN;
pub struct TribleSetConstraint {
variable_e: VariableId,
variable_a: VariableId,
variable_v: VariableId,
set: TribleSet,
}
impl TribleSetConstraint {
pub fn new<V: InlineEncoding>(
variable_e: Variable<GenId>,
variable_a: Variable<GenId>,
variable_v: Variable<V>,
set: TribleSet,
) -> Self {
TribleSetConstraint {
variable_e: variable_e.index,
variable_a: variable_a.index,
variable_v: variable_v.index,
set,
}
}
}
impl<'a> Constraint<'a> for TribleSetConstraint {
fn variables(&self) -> VariableSet {
let mut variables = VariableSet::new_empty();
variables.set(self.variable_e);
variables.set(self.variable_a);
variables.set(self.variable_v);
variables
}
fn estimate(&self, variable: VariableId, binding: &Binding) -> Option<usize> {
if self.variable_e != variable && self.variable_a != variable && self.variable_v != variable
{
return None;
}
let e_var = self.variable_e == variable;
let a_var = self.variable_a == variable;
let v_var = self.variable_v == variable;
let e_bound = if let Some(e) = binding.get(self.variable_e) {
let Some(e) = id_from_value(e) else {
return Some(0);
};
Some(e)
} else {
None
};
let a_bound = if let Some(a) = binding.get(self.variable_a) {
let Some(a) = id_from_value(a) else {
return Some(0);
};
Some(a)
} else {
None
};
let v_bound = binding.get(self.variable_v);
Some(match (e_bound, a_bound, v_bound, e_var, a_var, v_var) {
(None, None, None, true, false, false) => self.set.eav.segmented_len(&[0; 0]),
(None, None, None, false, true, false) => self.set.aev.segmented_len(&[0; 0]),
(None, None, None, false, false, true) => self.set.vea.segmented_len(&[0; 0]),
(Some(e), None, None, false, true, false) => {
let mut prefix = [0u8; ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&e[..]);
self.set.eav.segmented_len(&prefix)
}
(Some(e), None, None, false, false, true) => {
let mut prefix = [0u8; ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&e[..]);
self.set.eva.segmented_len(&prefix)
}
(None, Some(a), None, true, false, false) => {
let mut prefix = [0u8; ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&a[..]);
self.set.aev.segmented_len(&prefix)
}
(None, Some(a), None, false, false, true) => {
let mut prefix = [0u8; ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&a[..]);
self.set.ave.segmented_len(&prefix)
}
(None, None, Some(v), true, false, false) => {
let mut prefix = [0u8; INLINE_LEN];
prefix[0..INLINE_LEN].copy_from_slice(&v[..]);
self.set.vea.segmented_len(&prefix)
}
(None, None, Some(v), false, true, false) => {
let mut prefix = [0u8; INLINE_LEN];
prefix[0..INLINE_LEN].copy_from_slice(&v[..]);
self.set.vae.segmented_len(&prefix)
}
(None, Some(a), Some(v), true, false, false) => {
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&a);
prefix[ID_LEN..ID_LEN + INLINE_LEN].copy_from_slice(v);
self.set.ave.segmented_len(&prefix)
}
(Some(e), None, Some(v), false, true, false) => {
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&e);
prefix[ID_LEN..ID_LEN + INLINE_LEN].copy_from_slice(v);
self.set.eva.segmented_len(&prefix)
}
(Some(e), Some(a), None, false, false, true) => {
let mut prefix = [0u8; ID_LEN + ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&e);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&a);
self.set.eav.segmented_len(&prefix)
}
(_, Some(a), _, true, false, true) => {
let mut prefix = [0u8; ID_LEN];
prefix.copy_from_slice(&a[..]);
self.set.aev.segmented_len(&prefix)
}
(_, None, _, true, false, true) => {
self.set.eav.segmented_len(&[0; 0])
}
(_, _, Some(v), true, true, false) => {
let mut prefix = [0u8; INLINE_LEN];
prefix.copy_from_slice(&v[..]);
self.set.vae.segmented_len(&prefix)
}
(_, _, None, true, true, false) => {
self.set.aev.segmented_len(&[0; 0])
}
(Some(e), _, _, false, true, true) => {
let mut prefix = [0u8; ID_LEN];
prefix.copy_from_slice(&e[..]);
self.set.eav.segmented_len(&prefix)
}
(None, _, _, false, true, true) => {
self.set.aev.segmented_len(&[0; 0])
}
(_, _, _, true, true, true) => {
self.set.eav.segmented_len(&[0; 0])
}
_ => panic!("TribleSetConstraint: unreachable position-bound combo"),
} as usize)
}
fn propose(&self, variable: VariableId, binding: &Binding, proposals: &mut Vec<RawInline>) {
let e_var = self.variable_e == variable;
let a_var = self.variable_a == variable;
let v_var = self.variable_v == variable;
let e_bound = if let Some(e) = binding.get(self.variable_e) {
let Some(e) = id_from_value(e) else {
return;
};
Some(e)
} else {
None
};
let a_bound = if let Some(a) = binding.get(self.variable_a) {
let Some(a) = id_from_value(a) else {
return;
};
Some(a)
} else {
None
};
let v_bound = binding.get(self.variable_v);
match (e_bound, a_bound, v_bound, e_var, a_var, v_var) {
(None, None, None, true, false, false) => {
self.set.eav.infixes(&[0; 0], &mut |e: &[u8; 16]| {
proposals.push(id_into_value(e))
});
}
(None, None, None, false, true, false) => {
self.set.aev.infixes(&[0; 0], &mut |a: &[u8; 16]| {
proposals.push(id_into_value(a))
});
}
(None, None, None, false, false, true) => {
self.set
.vea
.infixes(&[0; 0], &mut |&v: &[u8; 32]| proposals.push(v));
}
(Some(e), None, None, false, true, false) => {
self.set
.eav
.infixes(&e, &mut |a: &[u8; 16]| proposals.push(id_into_value(a)));
}
(Some(e), None, None, false, false, true) => {
self.set
.eva
.infixes(&e, &mut |&v: &[u8; 32]| proposals.push(v));
}
(None, Some(a), None, true, false, false) => {
self.set
.aev
.infixes(&a, &mut |e: &[u8; 16]| proposals.push(id_into_value(e)));
}
(None, Some(a), None, false, false, true) => {
self.set
.ave
.infixes(&a, &mut |&v: &[u8; 32]| proposals.push(v));
}
(None, None, Some(v), true, false, false) => {
self.set
.vea
.infixes(v, &mut |e: &[u8; 16]| proposals.push(id_into_value(e)));
}
(None, None, Some(v), false, true, false) => {
self.set
.vae
.infixes(v, &mut |a: &[u8; 16]| proposals.push(id_into_value(a)));
}
(None, Some(a), Some(v), true, false, false) => {
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&a[..]);
prefix[ID_LEN..ID_LEN + INLINE_LEN].copy_from_slice(&v[..]);
self.set.ave.infixes(&prefix, &mut |e: &[u8; 16]| {
proposals.push(id_into_value(e))
});
}
(Some(e), None, Some(v), false, true, false) => {
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&e[..]);
prefix[ID_LEN..ID_LEN + INLINE_LEN].copy_from_slice(&v[..]);
self.set.eva.infixes(&prefix, &mut |a: &[u8; 16]| {
proposals.push(id_into_value(a))
});
}
(Some(e), Some(a), None, false, false, true) => {
let mut prefix = [0u8; ID_LEN + ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&e[..]);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&a[..]);
self.set
.eav
.infixes(&prefix, &mut |&v: &[u8; 32]| proposals.push(v));
}
(_, Some(a), _, true, false, true) => {
self.set.aev.infixes(&a, &mut |e: &[u8; 16]| {
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(e);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&a[..]);
prefix[ID_LEN + ID_LEN..].copy_from_slice(&id_into_value(e));
if self.set.eav.has_prefix(&prefix) {
proposals.push(id_into_value(e));
}
});
}
(_, None, _, true, false, true) => {
self.set.eav.infixes(&[0; 0], &mut |e: &[u8; 16]| {
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(e);
prefix[ID_LEN..].copy_from_slice(&id_into_value(e));
if self.set.eva.has_prefix(&prefix) {
proposals.push(id_into_value(e));
}
});
}
(_, _, Some(v), true, true, false) => {
self.set.vae.infixes(v, &mut |a: &[u8; 16]| {
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(a);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(a);
prefix[ID_LEN + ID_LEN..].copy_from_slice(&v[..]);
if self.set.eav.has_prefix(&prefix) {
proposals.push(id_into_value(a));
}
});
}
(_, _, None, true, true, false) => {
self.set.aev.infixes(&[0; 0], &mut |a: &[u8; 16]| {
let mut prefix = [0u8; ID_LEN + ID_LEN];
prefix[0..ID_LEN].copy_from_slice(a);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(a);
if self.set.eav.has_prefix(&prefix) {
proposals.push(id_into_value(a));
}
});
}
(Some(e), _, _, false, true, true) => {
self.set.eav.infixes(&e, &mut |a: &[u8; 16]| {
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&e[..]);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(a);
prefix[ID_LEN + ID_LEN..].copy_from_slice(&id_into_value(a));
if self.set.eav.has_prefix(&prefix) {
proposals.push(id_into_value(a));
}
});
}
(None, _, _, false, true, true) => {
self.set.aev.infixes(&[0; 0], &mut |a: &[u8; 16]| {
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(a);
prefix[ID_LEN..].copy_from_slice(&id_into_value(a));
if self.set.ave.has_prefix(&prefix) {
proposals.push(id_into_value(a));
}
});
}
(_, _, _, true, true, true) => {
self.set.eav.infixes(&[0; 0], &mut |e: &[u8; 16]| {
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(e);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(e);
prefix[ID_LEN + ID_LEN..].copy_from_slice(&id_into_value(e));
if self.set.eav.has_prefix(&prefix) {
proposals.push(id_into_value(e));
}
});
}
_ => panic!("TribleSetConstraint: unreachable position-bound combo"),
}
}
fn confirm(&self, variable: VariableId, binding: &Binding, proposals: &mut Vec<RawInline>) {
let e_var = self.variable_e == variable;
let a_var = self.variable_a == variable;
let v_var = self.variable_v == variable;
let e_bound = if let Some(e) = binding.get(self.variable_e) {
let Some(e) = id_from_value(e) else {
proposals.clear();
return;
};
Some(e)
} else {
None
};
let a_bound = if let Some(a) = binding.get(self.variable_a) {
let Some(a) = id_from_value(a) else {
proposals.clear();
return;
};
Some(a)
} else {
None
};
let v_bound = binding.get(self.variable_v);
match (e_bound, a_bound, v_bound, e_var, a_var, v_var) {
(None, None, None, true, false, false) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else {
return false;
};
self.set.eav.has_prefix(&id)
}),
(None, None, None, false, true, false) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else {
return false;
};
self.set.aev.has_prefix(&id)
}),
(None, None, None, false, false, true) => {
proposals.retain(|value| self.set.vea.has_prefix(value))
}
(Some(e), None, None, false, true, false) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else {
return false;
};
let mut prefix = [0u8; ID_LEN + ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&e[..]);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&id);
self.set.eav.has_prefix(&prefix)
}),
(Some(e), None, None, false, false, true) => proposals.retain(|value| {
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&e[..]);
prefix[ID_LEN..ID_LEN + INLINE_LEN].copy_from_slice(value);
self.set.eva.has_prefix(&prefix)
}),
(None, Some(a), None, true, false, false) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else {
return false;
};
let mut prefix = [0u8; ID_LEN + ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&a[..]);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&id);
self.set.aev.has_prefix(&prefix)
}),
(None, Some(a), None, false, false, true) => proposals.retain(|value| {
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&a[..]);
prefix[ID_LEN..ID_LEN + INLINE_LEN].copy_from_slice(value);
self.set.ave.has_prefix(&prefix)
}),
(None, None, Some(v), true, false, false) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else {
return false;
};
let mut prefix = [0u8; INLINE_LEN + ID_LEN];
prefix[0..INLINE_LEN].copy_from_slice(&v[..]);
prefix[INLINE_LEN..INLINE_LEN + ID_LEN].copy_from_slice(&id);
self.set.vea.has_prefix(&prefix)
}),
(None, None, Some(v), false, true, false) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else {
return false;
};
let mut prefix = [0u8; INLINE_LEN + ID_LEN];
prefix[0..INLINE_LEN].copy_from_slice(&v[..]);
prefix[INLINE_LEN..INLINE_LEN + ID_LEN].copy_from_slice(&id);
self.set.vae.has_prefix(&prefix)
}),
(None, Some(a), Some(v), true, false, false) => proposals.retain(|value: &[u8; 32]| {
let Some(id) = id_from_value(value) else {
return false;
};
let mut prefix = [0u8; ID_LEN + INLINE_LEN + ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&a);
prefix[ID_LEN..ID_LEN + INLINE_LEN].copy_from_slice(v);
prefix[ID_LEN + INLINE_LEN..ID_LEN + INLINE_LEN + ID_LEN].copy_from_slice(&id);
self.set.ave.has_prefix(&prefix)
}),
(Some(e), None, Some(v), false, true, false) => proposals.retain(|value: &[u8; 32]| {
let Some(id) = id_from_value(value) else {
return false;
};
let mut prefix = [0u8; ID_LEN + INLINE_LEN + ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&e);
prefix[ID_LEN..ID_LEN + INLINE_LEN].copy_from_slice(v);
prefix[ID_LEN + INLINE_LEN..ID_LEN + INLINE_LEN + ID_LEN].copy_from_slice(&id);
self.set.eva.has_prefix(&prefix)
}),
(Some(e), Some(a), None, false, false, true) => proposals.retain(|value: &[u8; 32]| {
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&e);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&a);
prefix[ID_LEN + ID_LEN..ID_LEN + ID_LEN + INLINE_LEN].copy_from_slice(value);
self.set.eav.has_prefix(&prefix)
}),
(_, Some(a), _, true, false, true) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else { return false; };
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&id);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&a[..]);
prefix[ID_LEN + ID_LEN..].copy_from_slice(&id_into_value(&id));
self.set.eav.has_prefix(&prefix)
}),
(_, None, _, true, false, true) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else { return false; };
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&id);
prefix[ID_LEN..].copy_from_slice(&id_into_value(&id));
self.set.eva.has_prefix(&prefix)
}),
(_, _, Some(v), true, true, false) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else { return false; };
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&id);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&id);
prefix[ID_LEN + ID_LEN..].copy_from_slice(&v[..]);
self.set.eav.has_prefix(&prefix)
}),
(_, _, None, true, true, false) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else { return false; };
let mut prefix = [0u8; ID_LEN + ID_LEN];
prefix[0..ID_LEN].copy_from_slice(&id);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&id);
self.set.eav.has_prefix(&prefix)
}),
(Some(e), _, _, false, true, true) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else { return false; };
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&e);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&id);
prefix[ID_LEN + ID_LEN..].copy_from_slice(&id_into_value(&id));
self.set.eav.has_prefix(&prefix)
}),
(None, _, _, false, true, true) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else { return false; };
let mut prefix = [0u8; ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&id);
prefix[ID_LEN..].copy_from_slice(&id_into_value(&id));
self.set.ave.has_prefix(&prefix)
}),
(_, _, _, true, true, true) => proposals.retain(|value| {
let Some(id) = id_from_value(value) else { return false; };
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&id);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&id);
prefix[ID_LEN + ID_LEN..].copy_from_slice(&id_into_value(&id));
self.set.eav.has_prefix(&prefix)
}),
_ => panic!("invalid trible constraint state"),
}
}
fn satisfied(&self, binding: &Binding) -> bool {
let e = binding.get(self.variable_e);
let a = binding.get(self.variable_a);
let v = binding.get(self.variable_v);
match (e, a, v) {
(Some(e_raw), Some(a_raw), Some(v_raw)) => {
let Some(e) = id_from_value(e_raw) else {
return false;
};
let Some(a) = id_from_value(a_raw) else {
return false;
};
let mut prefix = [0u8; ID_LEN + ID_LEN + INLINE_LEN];
prefix[0..ID_LEN].copy_from_slice(&e);
prefix[ID_LEN..ID_LEN + ID_LEN].copy_from_slice(&a);
prefix[ID_LEN + ID_LEN..].copy_from_slice(v_raw);
self.set.eav.has_prefix(&prefix)
}
_ => true,
}
}
}
#[cfg(test)]
mod tests {
use crate::find;
use crate::id::rngid;
use crate::query::TriblePattern;
use crate::query::Variable;
use crate::trible::Trible;
use crate::trible::TribleSet;
use crate::inline::encodings::UnknownInline;
use crate::inline::Inline;
#[test]
fn constant() {
let mut set = TribleSet::new();
set.insert(&Trible::new(
&rngid(),
&rngid(),
&Inline::<UnknownInline>::new([0; 32]),
));
let q = find! {
(e: Inline<_>, a: Inline<_>, v: Inline<_>),
set.pattern(e, a, v as Variable<UnknownInline>)
};
let r: Vec<_> = q.collect();
assert_eq!(1, r.len())
}
#[test]
fn self_edge_pattern_e_eq_v() {
use crate::inline::encodings::genid::GenId;
use crate::and;
fn id_as_inline(id: &[u8; 16]) -> Inline<GenId> {
let mut bytes = [0u8; 32];
bytes[16..32].copy_from_slice(id);
Inline::<GenId>::new(bytes)
}
let mut set = TribleSet::new();
let a = rngid();
let self1 = rngid();
let self2 = rngid();
let self3 = rngid();
let other = rngid();
for x in [&self1, &self2, &self3] {
set.insert(&Trible::new(x, &a, &id_as_inline(x)));
}
set.insert(&Trible::new(&self1, &a, &id_as_inline(&other)));
set.insert(&Trible::new(&other, &a, &id_as_inline(&self2)));
let q = find! {
(x: Inline<GenId>, attr: Inline<GenId>),
set.pattern(x, attr, x)
};
let r: Vec<_> = q.collect();
assert_eq!(3, r.len(), "expected 3 self-edges, got {}", r.len());
let q = find! {
(x: Inline<GenId>, attr: Inline<GenId>),
and!(
attr.is(id_as_inline(&a)),
set.pattern(x, attr, x)
)
};
let r: Vec<_> = q.collect();
assert_eq!(3, r.len(), "expected 3 self-edges with bound attr, got {}", r.len());
}
#[test]
fn entity_attr_dup_pattern() {
use crate::inline::encodings::genid::GenId;
fn id_as_inline(id: &[u8; 16]) -> Inline<GenId> {
let mut bytes = [0u8; 32];
bytes[16..32].copy_from_slice(id);
Inline::<GenId>::new(bytes)
}
let mut set = TribleSet::new();
let dup1 = rngid();
let dup2 = rngid();
let other = rngid();
let v1 = rngid();
let v2 = rngid();
set.insert(&Trible::new(&dup1, &dup1, &id_as_inline(&v1)));
set.insert(&Trible::new(&dup2, &dup2, &id_as_inline(&v2)));
set.insert(&Trible::new(&dup1, &other, &id_as_inline(&v1)));
set.insert(&Trible::new(&other, &dup1, &id_as_inline(&v1)));
let q = find! {
(x: Inline<GenId>, val: Inline<GenId>),
set.pattern(x, x, val)
};
let r: Vec<_> = q.collect();
assert_eq!(2, r.len(), "expected 2 entity-attr dups, got {}", r.len());
}
#[test]
fn attr_value_dup_pattern() {
use crate::inline::encodings::genid::GenId;
fn id_as_inline(id: &[u8; 16]) -> Inline<GenId> {
let mut bytes = [0u8; 32];
bytes[16..32].copy_from_slice(id);
Inline::<GenId>::new(bytes)
}
let mut set = TribleSet::new();
let dup1 = rngid(); let dup2 = rngid();
let other_attr = rngid();
let e1 = rngid();
let e2 = rngid();
let e3 = rngid();
set.insert(&Trible::new(&e1, &dup1, &id_as_inline(&dup1)));
set.insert(&Trible::new(&e2, &dup2, &id_as_inline(&dup2)));
set.insert(&Trible::new(&e3, &dup1, &id_as_inline(&dup2)));
set.insert(&Trible::new(&e3, &other_attr, &id_as_inline(&dup1)));
let q = find! {
(e: Inline<GenId>, x: Inline<GenId>),
set.pattern(e, x, x)
};
let r: Vec<_> = q.collect();
assert_eq!(2, r.len(), "expected 2 attr-value dups, got {}", r.len());
}
#[test]
fn all_three_same_pattern() {
use crate::inline::encodings::genid::GenId;
fn id_as_inline(id: &[u8; 16]) -> Inline<GenId> {
let mut bytes = [0u8; 32];
bytes[16..32].copy_from_slice(id);
Inline::<GenId>::new(bytes)
}
let mut set = TribleSet::new();
let xxx1 = rngid();
let xxx2 = rngid();
let other = rngid();
set.insert(&Trible::new(&xxx1, &xxx1, &id_as_inline(&xxx1)));
set.insert(&Trible::new(&xxx2, &xxx2, &id_as_inline(&xxx2)));
set.insert(&Trible::new(&xxx1, &xxx1, &id_as_inline(&other)));
set.insert(&Trible::new(&xxx2, &other, &id_as_inline(&xxx2)));
set.insert(&Trible::new(&other, &xxx1, &id_as_inline(&xxx1)));
let q = find! {
(x: Inline<GenId>),
set.pattern(x, x, x)
};
let r: Vec<_> = q.collect();
assert_eq!(2, r.len(), "expected 2 self-self-self triples, got {}", r.len());
}
}