Skip to main content

triblespace_core/query/
patchconstraint.rs

1use crate::id::id_from_value;
2use crate::id::id_into_value;
3use crate::id::ID_LEN;
4use crate::patch::IdentitySchema;
5use crate::patch::PATCH;
6use crate::value::RawValue;
7use crate::value::ValueSchema;
8use crate::value::VALUE_LEN;
9
10use super::Binding;
11use super::Constraint;
12use super::ContainsConstraint;
13use super::Variable;
14use super::VariableId;
15use super::VariableSet;
16
17/// Constrains a variable to full-width values present in a [`PATCH`].
18///
19/// Proposals enumerate every entry; confirmations check prefix membership.
20pub struct PatchValueConstraint<'a, T: ValueSchema> {
21    variable: Variable<T>,
22    patch: &'a PATCH<VALUE_LEN, IdentitySchema, ()>,
23}
24
25impl<'a, T: ValueSchema> PatchValueConstraint<'a, T> {
26    /// Creates a constraint that restricts `variable` to values in `patch`.
27    pub fn new(variable: Variable<T>, patch: &'a PATCH<VALUE_LEN, IdentitySchema, ()>) -> Self {
28        PatchValueConstraint { variable, patch }
29    }
30}
31
32impl<'a, S: ValueSchema> Constraint<'a> for PatchValueConstraint<'a, S> {
33    fn variables(&self) -> VariableSet {
34        VariableSet::new_singleton(self.variable.index)
35    }
36
37    fn estimate(&self, variable: VariableId, _binding: &Binding) -> Option<usize> {
38        if self.variable.index == variable {
39            Some(self.patch.len() as usize)
40        } else {
41            None
42        }
43    }
44
45    fn propose(&self, variable: VariableId, _binding: &Binding, proposals: &mut Vec<RawValue>) {
46        if self.variable.index == variable {
47            self.patch
48                .infixes(&[0; 0], &mut |&k: &[u8; 32]| proposals.push(k));
49        }
50    }
51
52    fn confirm(&self, variable: VariableId, _binding: &Binding, proposals: &mut Vec<RawValue>) {
53        if self.variable.index == variable {
54            proposals.retain(|v| self.patch.has_prefix(v));
55        }
56    }
57}
58
59impl<'a, S: ValueSchema> ContainsConstraint<'a, S> for &'a PATCH<VALUE_LEN, IdentitySchema, ()> {
60    type Constraint = PatchValueConstraint<'a, S>;
61
62    fn has(self, v: Variable<S>) -> Self::Constraint {
63        PatchValueConstraint::new(v, self)
64    }
65}
66
67/// Constrains a variable to ID-width values present in a [`PATCH`].
68///
69/// Like [`PatchValueConstraint`] but for 16-byte identifiers. Values are
70/// converted between the ID representation and the 32-byte value
71/// representation automatically.
72pub struct PatchIdConstraint<S>
73where
74    S: ValueSchema,
75{
76    variable: Variable<S>,
77    patch: PATCH<ID_LEN, IdentitySchema, ()>,
78}
79
80impl<S> PatchIdConstraint<S>
81where
82    S: ValueSchema,
83{
84    /// Creates a constraint that restricts `variable` to IDs in `patch`.
85    pub fn new(variable: Variable<S>, patch: PATCH<ID_LEN, IdentitySchema, ()>) -> Self {
86        PatchIdConstraint { variable, patch }
87    }
88}
89
90impl<'a, S> Constraint<'a> for PatchIdConstraint<S>
91where
92    S: ValueSchema,
93{
94    fn variables(&self) -> VariableSet {
95        VariableSet::new_singleton(self.variable.index)
96    }
97
98    fn estimate(&self, variable: VariableId, _binding: &Binding) -> Option<usize> {
99        if self.variable.index == variable {
100            Some(self.patch.len() as usize)
101        } else {
102            None
103        }
104    }
105
106    fn propose(&self, variable: VariableId, _binding: &Binding, proposals: &mut Vec<RawValue>) {
107        if self.variable.index == variable {
108            self.patch.infixes(&[0; 0], &mut |id: &[u8; 16]| {
109                proposals.push(id_into_value(id))
110            });
111        }
112    }
113
114    fn confirm(&self, _variable: VariableId, _binding: &Binding, proposals: &mut Vec<RawValue>) {
115        proposals.retain(|v| {
116            if let Some(id) = id_from_value(v) {
117                self.patch.has_prefix(&id)
118            } else {
119                false
120            }
121        });
122    }
123}
124
125impl<'a, S: ValueSchema> ContainsConstraint<'a, S> for PATCH<ID_LEN, IdentitySchema, ()> {
126    type Constraint = PatchIdConstraint<S>;
127
128    fn has(self, v: Variable<S>) -> Self::Constraint {
129        PatchIdConstraint::new(v, self)
130    }
131}