use crate::id::id_from_value;
use crate::id::id_into_value;
use crate::id::ID_LEN;
use crate::inline::InlineEncoding;
use crate::inline::INLINE_LEN;
use crate::patch::IdentitySchema;
use crate::patch::PATCH;
use super::Binding;
use super::Constraint;
use super::ContainsConstraint;
use super::Frontier;
use super::Variable;
use super::VariableId;
use super::VariableSet;
use crate::query::Candidates;
use crate::query::ProposalBuffer;
pub struct PatchValueConstraint<'a, T: InlineEncoding> {
variable: Variable<T>,
patch: &'a PATCH<INLINE_LEN, IdentitySchema, ()>,
}
impl<'a, T: InlineEncoding> PatchValueConstraint<'a, T> {
pub fn new(variable: Variable<T>, patch: &'a PATCH<INLINE_LEN, IdentitySchema, ()>) -> Self {
PatchValueConstraint { variable, patch }
}
}
impl<'a, S: InlineEncoding> Constraint<'a> for PatchValueConstraint<'a, S> {
fn variables(&self) -> VariableSet {
VariableSet::new_singleton(self.variable.index)
}
fn estimate(&self, variable: VariableId, _binding: &Binding) -> Option<usize> {
if self.variable.index == variable {
Some(self.patch.len() as usize)
} else {
None
}
}
fn propose(
&self,
variable: VariableId,
frontier: &Frontier<'_>,
proposals: &mut ProposalBuffer,
) {
if self.variable.index == variable {
for row in 0..frontier.len() {
proposals.open(row as u32);
self.patch
.infixes(&[0; 0], &mut |&k: &[u8; 32]| proposals.push(k));
}
}
}
fn confirm(&self, variable: VariableId, _frontier: &Frontier<'_>, cands: &mut Candidates<'_>) {
if self.variable.index == variable {
for i in 0..cands.len() {
let v = &cands.values()[i];
if cands.is_live(i) && !self.patch.has_prefix(v) {
cands.kill(i);
}
}
}
}
}
impl<'a, S: InlineEncoding> ContainsConstraint<'a, S>
for &'a PATCH<INLINE_LEN, IdentitySchema, ()>
{
type Constraint = PatchValueConstraint<'a, S>;
fn has(self, v: Variable<S>) -> Self::Constraint {
PatchValueConstraint::new(v, self)
}
}
pub struct PatchIdConstraint<S>
where
S: InlineEncoding,
{
variable: Variable<S>,
patch: PATCH<ID_LEN, IdentitySchema, ()>,
}
impl<S> PatchIdConstraint<S>
where
S: InlineEncoding,
{
pub fn new(variable: Variable<S>, patch: PATCH<ID_LEN, IdentitySchema, ()>) -> Self {
PatchIdConstraint { variable, patch }
}
}
impl<'a, S> Constraint<'a> for PatchIdConstraint<S>
where
S: InlineEncoding,
{
fn variables(&self) -> VariableSet {
VariableSet::new_singleton(self.variable.index)
}
fn estimate(&self, variable: VariableId, _binding: &Binding) -> Option<usize> {
if self.variable.index == variable {
Some(self.patch.len() as usize)
} else {
None
}
}
fn propose(
&self,
variable: VariableId,
frontier: &Frontier<'_>,
proposals: &mut ProposalBuffer,
) {
if self.variable.index == variable {
for row in 0..frontier.len() {
proposals.open(row as u32);
self.patch.infixes(&[0; 0], &mut |id: &[u8; 16]| {
proposals.push(id_into_value(id))
});
}
}
}
fn confirm(&self, variable: VariableId, _frontier: &Frontier<'_>, cands: &mut Candidates<'_>) {
if self.variable.index != variable {
return;
}
for i in 0..cands.len() {
if !cands.is_live(i) {
continue;
}
let v = &cands.values()[i];
let keep = if let Some(id) = id_from_value(v) {
self.patch.has_prefix(&id)
} else {
false
};
if !keep {
cands.kill(i);
}
}
}
}
impl<'a, S: InlineEncoding> ContainsConstraint<'a, S> for PATCH<ID_LEN, IdentitySchema, ()> {
type Constraint = PatchIdConstraint<S>;
fn has(self, v: Variable<S>) -> Self::Constraint {
PatchIdConstraint::new(v, self)
}
}