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
48pub struct ManualProof();
53#[sealed::sealed]
54impl CommutativeProof for ManualProof {
55 fn register_proof(&self, _expr: &syn::Expr) {}
56}
57#[sealed::sealed]
58impl IdempotentProof for ManualProof {
59 fn register_proof(&self, _expr: &syn::Expr) {}
60}
61#[sealed::sealed]
62impl MonotoneProof for ManualProof {
63 fn register_proof(&self, _expr: &syn::Expr) {}
64}
65#[sealed::sealed]
66impl OrderPreservingProof for ManualProof {
67 fn register_proof(&self, _expr: &syn::Expr) {}
68}
69
70#[doc(inline)]
71pub use crate::__manual_proof__ as manual_proof;
72
73#[macro_export]
74macro_rules! __manual_proof__ {
92 ($(#[doc = $doc:expr])+) => {
93 $crate::properties::ManualProof()
94 };
95}
96
97pub enum NotProved {}
99
100pub enum Proved {}
102
103pub struct AggFuncAlgebra<Commutative = NotProved, Idempotent = NotProved, Monotone = NotProved>(
121 Option<Box<dyn CommutativeProof>>,
122 Option<Box<dyn IdempotentProof>>,
123 Option<Box<dyn MonotoneProof>>,
124 PhantomData<(Commutative, Idempotent, Monotone)>,
125);
126
127impl<C, I, M> AggFuncAlgebra<C, I, M> {
128 pub fn commutative(
130 self,
131 proof: impl CommutativeProof + 'static,
132 ) -> AggFuncAlgebra<Proved, I, M> {
133 AggFuncAlgebra(Some(Box::new(proof)), self.1, self.2, PhantomData)
134 }
135
136 pub fn idempotent(self, proof: impl IdempotentProof + 'static) -> AggFuncAlgebra<C, Proved, M> {
138 AggFuncAlgebra(self.0, Some(Box::new(proof)), self.2, PhantomData)
139 }
140
141 pub fn monotone(self, proof: impl MonotoneProof + 'static) -> AggFuncAlgebra<C, I, Proved> {
143 AggFuncAlgebra(self.0, self.1, Some(Box::new(proof)), PhantomData)
144 }
145
146 pub(crate) fn register_proof(self, expr: &syn::Expr) {
148 if let Some(comm_proof) = self.0 {
149 comm_proof.register_proof(expr);
150 }
151
152 if let Some(idem_proof) = self.1 {
153 idem_proof.register_proof(expr);
154 }
155
156 if let Some(monotone_proof) = self.2 {
157 monotone_proof.register_proof(expr);
158 }
159 }
160}
161
162impl<C, I, M> Property for AggFuncAlgebra<C, I, M> {
163 type Root = AggFuncAlgebra;
164
165 fn make_root(_target: &mut Option<Self>) -> Self::Root {
166 AggFuncAlgebra(None, None, None, PhantomData)
167 }
168}
169
170pub struct MapFuncAlgebra<OrderPreserving = NotProved>(
174 Option<Box<dyn OrderPreservingProof>>,
175 PhantomData<OrderPreserving>,
176);
177
178impl<O> MapFuncAlgebra<O> {
179 pub fn order_preserving(
181 self,
182 proof: impl OrderPreservingProof + 'static,
183 ) -> MapFuncAlgebra<Proved> {
184 MapFuncAlgebra(Some(Box::new(proof)), PhantomData)
185 }
186
187 pub(crate) fn register_proof(self, expr: &syn::Expr) {
189 if let Some(proof) = self.0 {
190 proof.register_proof(expr);
191 }
192 }
193}
194
195impl<O> Property for MapFuncAlgebra<O> {
196 type Root = MapFuncAlgebra;
197
198 fn make_root(_target: &mut Option<Self>) -> Self::Root {
199 MapFuncAlgebra(None, PhantomData)
200 }
201}
202
203#[diagnostic::on_unimplemented(
205 message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
206 label = "required for this call",
207 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."
208)]
209#[sealed::sealed]
210pub trait ValidCommutativityFor<O: Ordering> {}
211#[sealed::sealed]
212impl ValidCommutativityFor<TotalOrder> for NotProved {}
213#[sealed::sealed]
214impl<O: Ordering> ValidCommutativityFor<O> for Proved {}
215
216#[diagnostic::on_unimplemented(
218 message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
219 label = "required for this call",
220 note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
221)]
222#[sealed::sealed]
223pub trait ValidIdempotenceFor<R: Retries> {}
224#[sealed::sealed]
225impl ValidIdempotenceFor<ExactlyOnce> for NotProved {}
226#[sealed::sealed]
227impl<R: Retries> ValidIdempotenceFor<R> for Proved {}
228
229#[sealed::sealed]
232pub trait ApplyMonotoneStream<P, B2: SingletonBound> {}
233
234#[sealed::sealed]
235impl<B: Boundedness> ApplyMonotoneStream<NotProved, B> for B {}
236
237#[sealed::sealed]
238impl<B: Boundedness> ApplyMonotoneStream<Proved, B::StreamToMonotone> for B {}
239
240#[sealed::sealed]
243pub trait ApplyMonotoneKeyedStream<P, B2: KeyedSingletonBound> {}
244
245#[sealed::sealed]
246impl<B: Boundedness> ApplyMonotoneKeyedStream<NotProved, B> for B {}
247
248#[sealed::sealed]
249impl<B: Boundedness> ApplyMonotoneKeyedStream<Proved, B::KeyedStreamToMonotone> for B {}
250
251#[sealed::sealed]
254pub trait ApplyOrderPreservingSingleton<P, B2: SingletonBound> {}
255
256#[sealed::sealed]
257impl<B: SingletonBound> ApplyOrderPreservingSingleton<NotProved, B::UnderlyingBound> for B {}
258
259#[sealed::sealed]
260impl<B: SingletonBound> ApplyOrderPreservingSingleton<Proved, B> for B {}