hydro_lang/properties/
mod.rs1use std::marker::PhantomData;
4
5use stageleft::properties::Property;
6
7use crate::live_collections::boundedness::Boundedness;
8use crate::live_collections::keyed_singleton::KeyedSingletonBound;
9use crate::live_collections::singleton::SingletonBound;
10use crate::live_collections::stream::{ExactlyOnce, Ordering, Retries, TotalOrder};
11
12#[sealed::sealed]
14pub trait CommutativeProof {
15 fn register_proof(&self, expr: &syn::Expr);
19}
20
21#[sealed::sealed]
23pub trait IdempotentProof {
24 fn register_proof(&self, expr: &syn::Expr);
28}
29
30#[sealed::sealed]
32pub trait MonotoneProof {
33 fn register_proof(&self, expr: &syn::Expr);
37}
38
39#[sealed::sealed]
41pub trait OrderPreservingProof {
42 fn register_proof(&self, expr: &syn::Expr);
46}
47
48#[sealed::sealed]
50pub trait ConsistencyProof {}
51
52pub struct ManualProof();
57#[sealed::sealed]
58impl CommutativeProof for ManualProof {
59 fn register_proof(&self, _expr: &syn::Expr) {}
60}
61#[sealed::sealed]
62impl IdempotentProof for ManualProof {
63 fn register_proof(&self, _expr: &syn::Expr) {}
64}
65#[sealed::sealed]
66impl MonotoneProof for ManualProof {
67 fn register_proof(&self, _expr: &syn::Expr) {}
68}
69#[sealed::sealed]
70impl OrderPreservingProof for ManualProof {
71 fn register_proof(&self, _expr: &syn::Expr) {}
72}
73#[sealed::sealed]
74impl ConsistencyProof for ManualProof {}
75
76#[doc(inline)]
77pub use crate::__manual_proof__ as manual_proof;
78
79#[macro_export]
80macro_rules! __manual_proof__ {
98 ($(#[doc = $doc:expr])+) => {
99 $crate::properties::ManualProof()
100 };
101}
102
103pub enum NotProved {}
105
106pub enum Proved {}
108
109pub struct AggFuncAlgebra<Commutative = NotProved, Idempotent = NotProved, Monotone = NotProved>(
127 Option<Box<dyn CommutativeProof>>,
128 Option<Box<dyn IdempotentProof>>,
129 Option<Box<dyn MonotoneProof>>,
130 PhantomData<(Commutative, Idempotent, Monotone)>,
131);
132
133impl<C, I, M> AggFuncAlgebra<C, I, M> {
134 pub fn commutative(
136 self,
137 proof: impl CommutativeProof + 'static,
138 ) -> AggFuncAlgebra<Proved, I, M> {
139 AggFuncAlgebra(Some(Box::new(proof)), self.1, self.2, PhantomData)
140 }
141
142 pub fn idempotent(self, proof: impl IdempotentProof + 'static) -> AggFuncAlgebra<C, Proved, M> {
144 AggFuncAlgebra(self.0, Some(Box::new(proof)), self.2, PhantomData)
145 }
146
147 pub fn monotone(self, proof: impl MonotoneProof + 'static) -> AggFuncAlgebra<C, I, Proved> {
149 AggFuncAlgebra(self.0, self.1, Some(Box::new(proof)), PhantomData)
150 }
151
152 pub(crate) fn register_proof(self, expr: &syn::Expr) {
154 if let Some(comm_proof) = self.0 {
155 comm_proof.register_proof(expr);
156 }
157
158 if let Some(idem_proof) = self.1 {
159 idem_proof.register_proof(expr);
160 }
161
162 if let Some(monotone_proof) = self.2 {
163 monotone_proof.register_proof(expr);
164 }
165 }
166}
167
168impl<C, I, M> Property for AggFuncAlgebra<C, I, M> {
169 type Root = AggFuncAlgebra;
170
171 fn make_root(_target: &mut Option<Self>) -> Self::Root {
172 AggFuncAlgebra(None, None, None, PhantomData)
173 }
174}
175
176pub struct MapFuncAlgebra<OrderPreserving = NotProved>(
180 Option<Box<dyn OrderPreservingProof>>,
181 PhantomData<OrderPreserving>,
182);
183
184impl<O> MapFuncAlgebra<O> {
185 pub fn order_preserving(
187 self,
188 proof: impl OrderPreservingProof + 'static,
189 ) -> MapFuncAlgebra<Proved> {
190 MapFuncAlgebra(Some(Box::new(proof)), PhantomData)
191 }
192
193 pub(crate) fn register_proof(self, expr: &syn::Expr) {
195 if let Some(proof) = self.0 {
196 proof.register_proof(expr);
197 }
198 }
199}
200
201impl<O> Property for MapFuncAlgebra<O> {
202 type Root = MapFuncAlgebra;
203
204 fn make_root(_target: &mut Option<Self>) -> Self::Root {
205 MapFuncAlgebra(None, PhantomData)
206 }
207}
208
209#[diagnostic::on_unimplemented(
211 message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
212 label = "required for this call",
213 note = "To intentionally process the stream by observing a non-deterministic (shuffled) order of elements, use `.assume_ordering`. This introduces non-determinism so avoid unless necessary."
214)]
215#[sealed::sealed]
216pub trait ValidCommutativityFor<O: Ordering> {}
217#[sealed::sealed]
218impl ValidCommutativityFor<TotalOrder> for NotProved {}
219#[sealed::sealed]
220impl<O: Ordering> ValidCommutativityFor<O> for Proved {}
221
222#[diagnostic::on_unimplemented(
224 message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
225 label = "required for this call",
226 note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
227)]
228#[sealed::sealed]
229pub trait ValidIdempotenceFor<R: Retries> {}
230#[sealed::sealed]
231impl ValidIdempotenceFor<ExactlyOnce> for NotProved {}
232#[sealed::sealed]
233impl<R: Retries> ValidIdempotenceFor<R> for Proved {}
234
235#[sealed::sealed]
238pub trait ApplyMonotoneStream<P, B2: SingletonBound> {}
239
240#[sealed::sealed]
241impl<B: Boundedness> ApplyMonotoneStream<NotProved, B> for B {}
242
243#[sealed::sealed]
244impl<B: Boundedness> ApplyMonotoneStream<Proved, B::StreamToMonotone> for B {}
245
246#[sealed::sealed]
249pub trait ApplyMonotoneKeyedStream<P, B2: KeyedSingletonBound> {}
250
251#[sealed::sealed]
252impl<B: Boundedness> ApplyMonotoneKeyedStream<NotProved, B> for B {}
253
254#[sealed::sealed]
255impl<B: Boundedness> ApplyMonotoneKeyedStream<Proved, B::KeyedStreamToMonotone> for B {}
256
257#[sealed::sealed]
260pub trait ApplyOrderPreservingSingleton<P, B2: SingletonBound> {}
261
262#[sealed::sealed]
263impl<B: SingletonBound> ApplyOrderPreservingSingleton<NotProved, B::UnderlyingBound> for B {}
264
265#[sealed::sealed]
266impl<B: SingletonBound> ApplyOrderPreservingSingleton<Proved, B> for B {}