1use 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 SingletonMapFuncAlgebra<
180 OrderPreserving = NotProved,
181 Commutative = NotProved,
182 Idempotent = NotProved,
183>(
184 Option<Box<dyn OrderPreservingProof>>,
185 Option<Box<dyn CommutativeProof>>,
186 Option<Box<dyn IdempotentProof>>,
187 PhantomData<(OrderPreserving, Commutative, Idempotent)>,
188);
189
190impl<O, C, I> SingletonMapFuncAlgebra<O, C, I> {
191 pub fn order_preserving(
193 self,
194 proof: impl OrderPreservingProof + 'static,
195 ) -> SingletonMapFuncAlgebra<Proved, C, I> {
196 SingletonMapFuncAlgebra(Some(Box::new(proof)), self.1, self.2, PhantomData)
197 }
198
199 pub fn commutative(
201 self,
202 proof: impl CommutativeProof + 'static,
203 ) -> SingletonMapFuncAlgebra<O, Proved, I> {
204 SingletonMapFuncAlgebra(self.0, Some(Box::new(proof)), self.2, PhantomData)
205 }
206
207 pub fn idempotent(
209 self,
210 proof: impl IdempotentProof + 'static,
211 ) -> SingletonMapFuncAlgebra<O, C, Proved> {
212 SingletonMapFuncAlgebra(self.0, self.1, Some(Box::new(proof)), PhantomData)
213 }
214
215 pub(crate) fn register_proof(self, expr: &syn::Expr) {
217 if let Some(proof) = self.0 {
218 proof.register_proof(expr);
219 }
220 }
221}
222
223impl<O, C, I> Property for SingletonMapFuncAlgebra<O, C, I> {
224 type Root = SingletonMapFuncAlgebra;
225
226 fn make_root(_target: &mut Option<Self>) -> Self::Root {
227 SingletonMapFuncAlgebra(None, None, None, PhantomData)
228 }
229}
230
231pub struct StreamMapFuncAlgebra<Commutative = NotProved, Idempotent = NotProved>(
233 Option<Box<dyn CommutativeProof>>,
234 Option<Box<dyn IdempotentProof>>,
235 PhantomData<(Commutative, Idempotent)>,
236);
237
238impl<C, I> StreamMapFuncAlgebra<C, I> {
239 pub fn commutative(
241 self,
242 proof: impl CommutativeProof + 'static,
243 ) -> StreamMapFuncAlgebra<Proved, I> {
244 StreamMapFuncAlgebra(Some(Box::new(proof)), self.1, PhantomData)
245 }
246
247 pub fn idempotent(
249 self,
250 proof: impl IdempotentProof + 'static,
251 ) -> StreamMapFuncAlgebra<C, Proved> {
252 StreamMapFuncAlgebra(self.0, Some(Box::new(proof)), PhantomData)
253 }
254
255 pub(crate) fn register_proof(self, expr: &syn::Expr) {
257 if let Some(proof) = self.0 {
258 proof.register_proof(expr);
259 }
260 if let Some(proof) = self.1 {
261 proof.register_proof(expr);
262 }
263 }
264}
265
266impl<C, I> Property for StreamMapFuncAlgebra<C, I> {
267 type Root = StreamMapFuncAlgebra;
268
269 fn make_root(_target: &mut Option<Self>) -> Self::Root {
270 StreamMapFuncAlgebra(None, None, PhantomData)
271 }
272}
273
274#[diagnostic::on_unimplemented(
276 message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
277 label = "required for this call",
278 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."
279)]
280#[sealed::sealed]
281pub trait ValidCommutativityFor<O: Ordering> {}
282#[sealed::sealed]
283impl ValidCommutativityFor<TotalOrder> for NotProved {}
284#[sealed::sealed]
285impl<O: Ordering> ValidCommutativityFor<O> for Proved {}
286
287#[diagnostic::on_unimplemented(
289 message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
290 label = "required for this call",
291 note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
292)]
293#[sealed::sealed]
294pub trait ValidIdempotenceFor<R: Retries> {}
295#[sealed::sealed]
296impl ValidIdempotenceFor<ExactlyOnce> for NotProved {}
297#[sealed::sealed]
298impl<R: Retries> ValidIdempotenceFor<R> for Proved {}
299
300#[sealed::sealed]
302#[diagnostic::on_unimplemented(
303 message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
304 label = "required for this call",
305 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."
306)]
307pub trait ValidMutCommutativityFor<F: FnMut(In) -> Out, In, Out, O: Ordering, const WAS_MUT: bool> {}
308#[sealed::sealed]
309impl<In, Out, F: FnMut(In) -> Out> ValidMutCommutativityFor<F, In, Out, TotalOrder, true>
310 for NotProved
311{
312}
313#[sealed::sealed]
314impl<In, Out, F: Fn(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, false>
315 for NotProved
316{
317}
318#[sealed::sealed]
319impl<In, Out, F: FnMut(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, true>
320 for Proved
321{
322}
323#[sealed::sealed]
324impl<In, Out, F: Fn(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, false>
325 for Proved
326{
327}
328
329#[diagnostic::on_unimplemented(
331 message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
332 label = "required for this call",
333 note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
334)]
335#[sealed::sealed]
336pub trait ValidMutIdempotenceFor<F: FnMut(In) -> Out, In, Out, R: Retries, const WAS_MUT: bool> {}
337#[sealed::sealed]
338impl<In, Out, F: FnMut(In) -> Out> ValidMutIdempotenceFor<F, In, Out, ExactlyOnce, true>
339 for NotProved
340{
341}
342#[sealed::sealed]
343impl<In, Out, F: Fn(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, false>
344 for NotProved
345{
346}
347#[sealed::sealed]
348impl<In, Out, F: FnMut(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, true>
349 for Proved
350{
351}
352#[sealed::sealed]
353impl<In, Out, F: Fn(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, false>
354 for Proved
355{
356}
357
358#[sealed::sealed]
360#[diagnostic::on_unimplemented(
361 message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
362 label = "required for this call",
363 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."
364)]
365pub trait ValidMutBorrowCommutativityFor<
366 F: FnMut(&In) -> Out,
367 In: ?Sized,
368 Out,
369 O: Ordering,
370 const WAS_MUT: bool,
371>
372{
373}
374#[sealed::sealed]
375impl<In: ?Sized, Out, F: FnMut(&In) -> Out>
376 ValidMutBorrowCommutativityFor<F, In, Out, TotalOrder, true> for NotProved
377{
378}
379#[sealed::sealed]
380impl<In: ?Sized, Out, F: Fn(&In) -> Out, O: Ordering>
381 ValidMutBorrowCommutativityFor<F, In, Out, O, false> for NotProved
382{
383}
384#[sealed::sealed]
385impl<In: ?Sized, Out, F: FnMut(&In) -> Out, O: Ordering>
386 ValidMutBorrowCommutativityFor<F, In, Out, O, true> for Proved
387{
388}
389#[sealed::sealed]
390impl<In: ?Sized, Out, F: Fn(&In) -> Out, O: Ordering>
391 ValidMutBorrowCommutativityFor<F, In, Out, O, false> for Proved
392{
393}
394
395#[diagnostic::on_unimplemented(
397 message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
398 label = "required for this call",
399 note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
400)]
401#[sealed::sealed]
402pub trait ValidMutBorrowIdempotenceFor<
403 F: FnMut(&In) -> Out,
404 In: ?Sized,
405 Out,
406 R: Retries,
407 const WAS_MUT: bool,
408>
409{
410}
411#[sealed::sealed]
412impl<In: ?Sized, Out, F: FnMut(&In) -> Out>
413 ValidMutBorrowIdempotenceFor<F, In, Out, ExactlyOnce, true> for NotProved
414{
415}
416#[sealed::sealed]
417impl<In: ?Sized, Out, F: Fn(&In) -> Out, R: Retries>
418 ValidMutBorrowIdempotenceFor<F, In, Out, R, false> for NotProved
419{
420}
421#[sealed::sealed]
422impl<In: ?Sized, Out, F: FnMut(&In) -> Out, R: Retries>
423 ValidMutBorrowIdempotenceFor<F, In, Out, R, true> for Proved
424{
425}
426#[sealed::sealed]
427impl<In: ?Sized, Out, F: Fn(&In) -> Out, R: Retries>
428 ValidMutBorrowIdempotenceFor<F, In, Out, R, false> for Proved
429{
430}
431
432#[sealed::sealed]
435pub trait ApplyMonotoneStream<P, B2: SingletonBound> {}
436
437#[sealed::sealed]
438impl<B: Boundedness> ApplyMonotoneStream<NotProved, B> for B {}
439
440#[sealed::sealed]
441impl<B: Boundedness> ApplyMonotoneStream<Proved, B::StreamToMonotone> for B {}
442
443#[sealed::sealed]
446pub trait ApplyMonotoneKeyedStream<P, B2: KeyedSingletonBound> {}
447
448#[sealed::sealed]
449impl<B: Boundedness> ApplyMonotoneKeyedStream<NotProved, B> for B {}
450
451#[sealed::sealed]
452impl<B: Boundedness> ApplyMonotoneKeyedStream<Proved, B::KeyedStreamToMonotone> for B {}
453
454#[sealed::sealed]
457pub trait ApplyOrderPreservingSingleton<P, B2: SingletonBound> {}
458
459#[sealed::sealed]
460impl<B: SingletonBound> ApplyOrderPreservingSingleton<NotProved, B::UnderlyingBound> for B {}
461
462#[sealed::sealed]
463impl<B: SingletonBound> ApplyOrderPreservingSingleton<Proved, B> for B {}