Skip to main content

hydro_lang/properties/
mod.rs

1//! Types for reasoning about algebraic properties for Rust closures.
2
3use 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};
11use crate::sim_hooks::{OnProcess, OrderingHook};
12
13/// A trait for proof mechanisms that can validate commutativity.
14///
15/// `T` and `B` name the element type and boundedness of the stream the commutative
16/// function consumes. The simulator does not trust commutativity proofs — it still
17/// explores the input ordering — so a proof may carry an [`OrderingHook`] for scripting
18/// that exploration, surfaced through [`Self::take_hook`]. `S` is the hook's
19/// [scope](crate::sim_hooks#hook-scopes).
20#[sealed::sealed]
21pub trait CommutativeProof<T, B: Boundedness, S = OnProcess> {
22    /// Registers the expression with the proof mechanism.
23    ///
24    /// This should not perform any blocking analysis; it is only intended to record the expression for later processing.
25    fn register_proof(&self, expr: &syn::Expr);
26
27    /// Takes the simulator ordering hook attached to this proof, if any.
28    fn take_hook(&mut self) -> Option<OrderingHook<T, B, S>>;
29}
30
31/// A trait for proof mechanisms that can validate idempotence.
32#[sealed::sealed]
33pub trait IdempotentProof {
34    /// Registers the expression with the proof mechanism.
35    ///
36    /// This should not perform any blocking analysis; it is only intended to record the expression for later processing.
37    fn register_proof(&self, expr: &syn::Expr);
38}
39
40/// A trait for proof mechanisms that can validate monotonicity.
41#[sealed::sealed]
42pub trait MonotoneProof {
43    /// Registers the expression with the proof mechanism.
44    ///
45    /// This should not perform any blocking analysis; it is only intended to record the expression for later processing.
46    fn register_proof(&self, expr: &syn::Expr);
47}
48
49/// A trait for proof mechanisms that can validate order-preservation (monotonicity of a map function).
50#[sealed::sealed]
51pub trait OrderPreservingProof {
52    /// Registers the expression with the proof mechanism.
53    ///
54    /// This should not perform any blocking analysis; it is only intended to record the expression for later processing.
55    fn register_proof(&self, expr: &syn::Expr);
56}
57
58/// A trait for proof mechanisms that can validate consistency of a collection.
59#[sealed::sealed]
60pub trait ConsistencyProof {}
61
62/// A hand-written human proof of the correctness property.
63///
64/// To create a manual proof, use the [`manual_proof!`] macro, which takes in a doc comment
65/// explaining why the property holds.
66///
67/// Manual proofs are not trusted by the simulator, which still explores the guarded
68/// non-determinism. `H` is the simulator hook payload (like [`crate::nondet::NonDet`]) so a
69/// commutativity proof can carry an ordering hook for scripting that exploration.
70pub struct ManualProof<H = ()> {
71    hook: H,
72}
73
74impl<H> ManualProof<H> {
75    #[doc(hidden)]
76    pub fn unhooked() -> Self
77    where
78        H: Default,
79    {
80        ManualProof { hook: H::default() }
81    }
82}
83
84impl<T, B: Boundedness, S> ManualProof<Option<OrderingHook<T, B, S>>> {
85    #[doc(hidden)]
86    pub fn hooked(hook: impl Into<Option<OrderingHook<T, B, S>>>) -> Self {
87        ManualProof { hook: hook.into() }
88    }
89}
90
91#[sealed::sealed]
92impl<T, B: Boundedness, S> CommutativeProof<T, B, S>
93    for ManualProof<Option<OrderingHook<T, B, S>>>
94{
95    fn register_proof(&self, _expr: &syn::Expr) {}
96
97    fn take_hook(&mut self) -> Option<OrderingHook<T, B, S>> {
98        self.hook.take()
99    }
100}
101
102#[sealed::sealed]
103impl<T, B: Boundedness, S> CommutativeProof<T, B, S> for ManualProof {
104    fn register_proof(&self, _expr: &syn::Expr) {}
105
106    fn take_hook(&mut self) -> Option<OrderingHook<T, B, S>> {
107        None
108    }
109}
110#[sealed::sealed]
111impl IdempotentProof for ManualProof {
112    fn register_proof(&self, _expr: &syn::Expr) {}
113}
114#[sealed::sealed]
115impl MonotoneProof for ManualProof {
116    fn register_proof(&self, _expr: &syn::Expr) {}
117}
118#[sealed::sealed]
119impl OrderPreservingProof for ManualProof {
120    fn register_proof(&self, _expr: &syn::Expr) {}
121}
122#[sealed::sealed]
123impl ConsistencyProof for ManualProof {}
124
125/// A machine-checked proof of **commutativity**, verified by [Verus](https://verus-lang.github.io/verus/guide/).
126///
127/// Created by the [`verus_proof_commutative_fold!`], [`verus_proof_commutative_map!`],
128/// [`verus_proof_commutative_filter!`], and [`verus_proof_commutative_effect!`] macros,
129/// one per closure shape, each generating the precise obligation that makes reordering
130/// unobservable for that shape (final accumulator, output multiset, retained multiset,
131/// or captured state, respectively). The obligation is generated by the macro directly
132/// from the *actual closure body* — it symbolically executes the body in both orders
133/// (`x` then `y`, and `y` then `x`) from equal initial states and requires the
134/// observable results to be equal — so users never write (and cannot weaken) the
135/// assertion. Users only declare the types involved and, optionally, provide a proof
136/// *script* to help the SMT solver, which is itself checked by Verus.
137///
138/// When the crate is verified with `cargo verus verify`, Verus checks the obligation
139/// (which also proves the closure body panic-free, e.g. no arithmetic overflow). Under
140/// normal compilation, the proof is erased and this type simply marks the property as
141/// proven. This type only implements [`CommutativeProof`], so it cannot be used to
142/// fulfill a different property (e.g. `idempotent = ...`).
143pub struct VerusCommutativeProof {
144    _private: (),
145}
146
147impl VerusCommutativeProof {
148    #[doc(hidden)]
149    pub fn new() -> Self {
150        VerusCommutativeProof { _private: () }
151    }
152}
153
154impl Default for VerusCommutativeProof {
155    fn default() -> Self {
156        Self::new()
157    }
158}
159
160#[sealed::sealed]
161impl<T, B: Boundedness, S> CommutativeProof<T, B, S> for VerusCommutativeProof {
162    fn register_proof(&self, _expr: &syn::Expr) {}
163
164    fn take_hook(&mut self) -> Option<OrderingHook<T, B, S>> {
165        // Verus proofs are still not trusted by the simulator, which explores the
166        // input ordering on its own; no scripting hook is attached.
167        None
168    }
169}
170
171#[doc(inline)]
172pub use crate::__manual_proof__ as manual_proof;
173
174#[macro_export]
175/// Fulfills a proof parameter by declaring a human-written justification for why
176/// the algebraic property (e.g. commutativity, idempotence) holds.
177///
178/// The argument must be a doc comment explaining why the property is satisfied.
179///
180/// # Examples
181/// ```rust
182/// # #[cfg(feature = "deploy")] {
183/// # use hydro_lang::prelude::*;
184/// # use hydro_lang::live_collections::stream::NoOrder;
185/// # use futures::StreamExt;
186/// # tokio_test::block_on(hydro_lang::test_util::stream_transform_test(|process| {
187/// # let stream = process.source_iter(q!(vec![1, 2, 3])).weaken_ordering::<NoOrder>();
188/// // stream: [1, 2, 3] (unordered)
189/// stream
190///     .fold(
191///         q!(|| 0),
192///         q!(
193///             |acc, x| *acc += x,
194///             commutative = manual_proof!(/** integer addition is commutative */)
195///         ),
196///     )
197///     .into_stream()
198/// # }, |mut stream| async move {
199/// # assert_eq!(stream.next().await.unwrap(), 6);
200/// # }));
201/// # }
202/// ```
203/// An optional trailing `hook = ...` argument attaches a **simulator ordering hook** to a
204/// commutativity proof (see `hydro_lang::sim::hooks`). The simulator does not trust manual
205/// proofs — it still explores the input ordering — so the hook lets a simulation test
206/// script that exploration:
207///
208/// ```rust,ignore
209/// commutative = manual_proof!(/** set insert is commutative */ hook = my_ordering_hook)
210/// ```
211macro_rules! __manual_proof__ {
212    (
213        $(#[doc = $doc:expr])+hook =
214        $hook:expr,__target =
215        { $($target:tt)* } $(,__captures = [$($captures:ident),*])? $(,)?
216    ) => {
217        $crate::properties::ManualProof::hooked($hook)
218    };
219    ($(#[doc = $doc:expr])+hook = $hook:expr $(,)?) => {
220        $crate::properties::ManualProof::hooked($hook)
221    };
222    (
223        $(#[doc = $doc:expr])+,__target =
224        { $($target:tt)* } $(,__captures = [$($captures:ident),*])? $(,)?
225    ) => {
226        $crate::properties::ManualProof::<()>::unhooked()
227    };
228    ($(#[doc = $doc:expr])+) => {
229        $crate::properties::ManualProof::<()>::unhooked()
230    };
231}
232
233#[doc(inline)]
234pub use crate::__verus_proof_commutative_effect__ as verus_proof_commutative_effect;
235#[doc(inline)]
236pub use crate::__verus_proof_commutative_filter__ as verus_proof_commutative_filter;
237#[doc(inline)]
238pub use crate::__verus_proof_commutative_fold__ as verus_proof_commutative_fold;
239#[doc(inline)]
240pub use crate::__verus_proof_commutative_map__ as verus_proof_commutative_map;
241
242#[macro_export]
243/// Fulfills a `commutative = ...` proof parameter for an **aggregation closure**
244/// (`fold` / `reduce`, shape `|acc, item|` with `acc: &mut A`) with a **Verus-checked
245/// proof of commutativity**.
246///
247/// Users never write the proof obligation (so they cannot get it wrong): this macro
248/// receives the quoted closure itself from `q!` (as a trailing `__target = { ... }`
249/// argument) and generates a Verus function that symbolically executes the *actual
250/// closure body* in both orders — `x` then `y`, and `y` then `x` — starting from equal
251/// accumulators, and asserts that the final accumulators are equal. Verifying this
252/// obligation also proves the closure body panic-free (e.g. no arithmetic overflow).
253/// Users only declare the accumulator and item types:
254///
255/// ```rust,ignore
256/// batch.reduce(q!(
257///     |curr, new| { if new > *curr { *curr = new; } },
258///     commutative = verus_proof_commutative_fold!(acc = u32, item = u32)
259/// ));
260/// ```
261///
262/// If the closure captures (read-only) variables from its environment, re-declare them
263/// (with their runtime types) in a `captures = |...|` clause; the obligation is then
264/// universally quantified over the capture values, which is sound since any particular
265/// execution uses some fixed value. `q!` also passes the closure's capture list (as a
266/// trailing `__captures = [...]` argument), and the macro checks at compile time that
267/// every capture is declared.
268///
269/// An optional `proof = |state, x, y| { ... }` clause supplies a proof *script* to help
270/// the SMT solver, with ghost bindings for the initial accumulator and the two items
271/// (e.g. `proof = |s, x, y| { assert((s | x) | y == (s | y) | x) by (bit_vector); }`).
272/// The script is checked by Verus and cannot weaken the obligation (though, as anywhere
273/// in Verus, `assume` is an explicit soundness escape hatch).
274///
275/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
276/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
277/// macro just produces a [`VerusCommutativeProof`] marker, so the types go through the
278/// ordinary `commutative = ...` mechanism with zero overhead.
279macro_rules! __verus_proof_commutative_fold__ {
280    (
281        acc = $accty:ty, item = $itemty:ty
282        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
283        $(, proof = |$pstate:ident, $px:ident, $py:ident| { $($proof_body:tt)* })?
284        , __target = { $(move)? |$tacc:ident $(: $taccty:ty)?, $titem:ident $(: $titemty:ty)?| $target_body:expr }
285        , __captures = [$($fv:ident),* $(,)?] $(,)?
286    ) => {{
287        /// Checks that every free variable captured by the closure is declared (with its
288        /// type) in the `captures = |...|` clause: within this function, the *only* names
289        /// in scope are the declared captures and the closure parameters, so an
290        /// undeclared capture fails to resolve.
291        #[allow(unused, reason = "only checks name resolution")]
292        fn __hydro_verus_captures_declared($($($cap: $capty),*)?) {
293            $(let $fv = &$fv;)*
294        }
295        #[cfg(verus_keep_ghost)]
296        const _: () = {
297            #[allow(unused_imports)]
298            use ::vstd::prelude::*;
299
300            ::vstd::prelude::verus! {
301                /// Commutativity obligation, generated by `verus_proof_commutative_fold!`:
302                /// applying the closure body with `x` then `y` must yield the same
303                /// accumulator as applying it with `y` then `x`, from any equal starting
304                /// accumulators, for all items and capture values. Verifying this also
305                /// proves the body panic-free.
306                fn __hydro_verus_commutative(
307                    $($($cap: $capty,)*)?
308                    __hydro_acc_xy: $accty,
309                    __hydro_acc_yx: $accty,
310                    __hydro_x_0: $itemty,
311                    __hydro_x_1: $itemty,
312                    __hydro_y_0: $itemty,
313                    __hydro_y_1: $itemty,
314                )
315                    requires
316                        __hydro_acc_xy == __hydro_acc_yx,
317                        __hydro_x_0 == __hydro_x_1,
318                        __hydro_y_0 == __hydro_y_1,
319                {
320                    $(
321                        let ghost $pstate = __hydro_acc_xy;
322                        let ghost $px = __hydro_x_0;
323                        let ghost $py = __hydro_y_0;
324                    )?
325                    let mut __hydro_acc_xy = __hydro_acc_xy;
326                    let mut __hydro_acc_yx = __hydro_acc_yx;
327                    { let $tacc = &mut __hydro_acc_xy; let $titem = __hydro_x_0; let _ = { $target_body }; }
328                    { let $tacc = &mut __hydro_acc_xy; let $titem = __hydro_y_0; let _ = { $target_body }; }
329                    { let $tacc = &mut __hydro_acc_yx; let $titem = __hydro_y_1; let _ = { $target_body }; }
330                    { let $tacc = &mut __hydro_acc_yx; let $titem = __hydro_x_1; let _ = { $target_body }; }
331                    $(proof { $($proof_body)* })?
332                    assert(__hydro_acc_xy == __hydro_acc_yx);
333                }
334            }
335        };
336
337        $crate::properties::VerusCommutativeProof::new()
338    }};
339    (
340        $($rest:tt)*
341    ) => {{
342        ::core::compile_error!(
343            "verus_proof_commutative_fold! must be used as a property annotation inside `q!(...)` on a `|acc, item| ...` closure, e.g. `commutative = verus_proof_commutative_fold!(acc = u32, item = u32)`"
344        );
345        $crate::properties::VerusCommutativeProof::new()
346    }};
347}
348
349#[macro_export]
350/// Fulfills a `commutative = ...` proof parameter for a **map-like closure**
351/// (shape `|item| -> out`, e.g. for `map`) that may mutate a captured singleton
352/// reference (from [`Singleton::by_mut`]), with a **Verus-checked proof of
353/// commutativity**.
354///
355/// **What commutativity means for a map closure:** processing any two items in either
356/// order, starting from the same captured state, must (1) leave the captured state in
357/// the same final value, *and* (2) produce the same **multiset of output values** (the
358/// outputs may be swapped in order, but not changed). Both conditions are required for
359/// downstream determinism: outputs that depend on the processing order (e.g. emitting a
360/// running total) are **not** commutative even if the state update is.
361///
362/// The commuting state is the mutable capture, declared (with the type behind the
363/// reference) in the required `captures_mut = |state: S|` clause; additional read-only
364/// captures can be declared in a `captures = |...|` clause. `q!` also passes the
365/// closure's capture list (as a trailing `__captures = [...]` argument), and the macro
366/// checks at compile time that every capture is declared. The `item = ...` type must be
367/// written exactly as the closure receives it.
368///
369/// Users never write the proof obligation: this macro receives the quoted closure itself
370/// from `q!` (as a trailing `__target = { ... }` argument) and generates a Verus function
371/// that symbolically executes the *actual closure body* in both orders — `x` then `y`,
372/// and `y` then `x` — from equal captured states, then asserts that the final states are
373/// equal and that the two runs' outputs are equal as a multiset (pairwise or crossed).
374/// Verifying this also proves the body panic-free.
375///
376/// An optional `proof = |state, x, y| { ... }` clause supplies a proof *script* to help
377/// the SMT solver, with ghost bindings for the initial captured state and the two items.
378/// The script is checked by Verus and cannot weaken the obligation.
379///
380/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
381/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
382/// macro just produces a [`VerusCommutativeProof`] marker.
383///
384/// # Example
385/// ```rust,ignore
386/// let count_mut = my_count.by_mut();
387/// stream.map(q!(
388///     |x| {
389///         *count_mut = count_mut.wrapping_add(x);
390///         x // outputting `*count_mut` here would NOT be commutative!
391///     },
392///     commutative = verus_proof_commutative_map!(
393///         item = i32,
394///         captures_mut = |count_mut: i32|
395///     )
396/// ));
397/// ```
398///
399/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
400macro_rules! __verus_proof_commutative_map__ {
401    (
402        item = $itemty:ty
403        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
404        , captures_mut = |$mcap:ident : $mcapty:ty $(,)?|
405        $(, proof = |$pstate:ident, $px:ident, $py:ident| { $($proof_body:tt)* })?
406        , __target = { $(move)? |$titem:ident $(: $titemty:ty)?| $target_body:expr }
407        , __captures = [$($fv:ident),* $(,)?] $(,)?
408    ) => {{
409        /// Checks that every free variable captured by the closure is declared (with its
410        /// type) in the `captures = |...|` or `captures_mut = |...|` clauses: within this
411        /// function, the *only* names in scope are the declared captures, so an
412        /// undeclared capture fails to resolve.
413        #[allow(unused, reason = "only checks name resolution")]
414        fn __hydro_verus_captures_declared($($($cap: $capty,)*)? $mcap: $mcapty) {
415            $(let $fv = &$fv;)*
416        }
417
418        #[cfg(verus_keep_ghost)]
419        const _: () = {
420            #[allow(unused_imports)]
421            use ::vstd::prelude::*;
422
423            ::vstd::prelude::verus! {
424                /// Commutativity obligation, generated by `verus_proof_commutative_map!`:
425                /// from any equal starting captured states, processing `x` then `y` must
426                /// yield the same final captured state as processing `y` then `x`, and
427                /// the two runs must produce the same multiset of outputs (pairwise or
428                /// crossed equality). Verifying this also proves the body panic-free.
429                fn __hydro_verus_commutative(
430                    $($($cap: $capty,)*)?
431                    __hydro_state_xy: $mcapty,
432                    __hydro_state_yx: $mcapty,
433                    __hydro_x_0: $itemty,
434                    __hydro_x_1: $itemty,
435                    __hydro_y_0: $itemty,
436                    __hydro_y_1: $itemty,
437                )
438                    requires
439                        __hydro_state_xy == __hydro_state_yx,
440                        __hydro_x_0 == __hydro_x_1,
441                        __hydro_y_0 == __hydro_y_1,
442                {
443                    $(
444                        let ghost $pstate = __hydro_state_xy;
445                        let ghost $px = __hydro_x_0;
446                        let ghost $py = __hydro_y_0;
447                    )?
448                    let mut __hydro_state_xy = __hydro_state_xy;
449                    let mut __hydro_state_yx = __hydro_state_yx;
450                    let __hydro_out_xy_x = { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_x_0; $target_body };
451                    let __hydro_out_xy_y = { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_y_0; $target_body };
452                    let __hydro_out_yx_y = { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_y_1; $target_body };
453                    let __hydro_out_yx_x = { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_x_1; $target_body };
454                    $(proof { $($proof_body)* })?
455                    assert(__hydro_state_xy == __hydro_state_yx);
456                    assert(
457                        (__hydro_out_xy_x == __hydro_out_yx_x && __hydro_out_xy_y == __hydro_out_yx_y)
458                        || (__hydro_out_xy_x == __hydro_out_yx_y && __hydro_out_xy_y == __hydro_out_yx_x)
459                    );
460                }
461            }
462        };
463
464        $crate::properties::VerusCommutativeProof::new()
465    }};
466    (
467        $($rest:tt)*
468    ) => {{
469        ::core::compile_error!(
470            "verus_proof_commutative_map! must be used as a property annotation inside `q!(...)` on a `|item| ...` closure with exactly one `captures_mut` entry, e.g. `commutative = verus_proof_commutative_map!(item = u32, captures_mut = |state: u32|)`"
471        );
472        $crate::properties::VerusCommutativeProof::new()
473    }};
474}
475
476#[macro_export]
477/// Fulfills a `commutative = ...` proof parameter for a **filter predicate**
478/// (shape `|item| -> bool` where `item` is received by reference) that may mutate a
479/// captured singleton reference (from [`Singleton::by_mut`]), with a **Verus-checked
480/// proof of commutativity**.
481///
482/// **What commutativity means for a filter predicate:** processing any two items in
483/// either order, starting from the same captured state, must (1) leave the captured
484/// state in the same final value, *and* (2) retain the same **multiset of elements**.
485/// The second condition is essential for soundness: a stateful predicate like a rate
486/// limiter converges to the same state either way, but *which* element passes depends on
487/// the order, which is **not** commutative (unless the elements are equal).
488///
489/// The commuting state is the mutable capture, declared (with the type behind the
490/// reference) in the required `captures_mut = |state: S|` clause; additional read-only
491/// captures can be declared in a `captures = |...|` clause. `q!` also passes the
492/// closure's capture list (as a trailing `__captures = [...]` argument), and the macro
493/// checks at compile time that every capture is declared. The `item = ...` type must be
494/// written exactly as the closure receives it (for `filter`, a reference like `&u32`).
495///
496/// Users never write the proof obligation: this macro receives the quoted closure itself
497/// from `q!` (as a trailing `__target = { ... }` argument) and generates a Verus function
498/// that symbolically executes the *actual predicate body* in both orders — `x` then `y`,
499/// and `y` then `x` — from equal captured states, then asserts that the final states are
500/// equal and that the retained multisets are equal: either the per-item decisions match
501/// across the two orders, or the two items are equal and the number of retained copies
502/// matches. Verifying this also proves the body panic-free.
503///
504/// An optional `proof = |state, x, y| { ... }` clause supplies a proof *script* to help
505/// the SMT solver, with ghost bindings for the initial captured state and the two items.
506/// The script is checked by Verus and cannot weaken the obligation.
507///
508/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
509/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
510/// macro just produces a [`VerusCommutativeProof`] marker.
511///
512/// # Example
513/// ```rust,ignore
514/// let seen_mut = seen_count.by_mut();
515/// stream.filter(q!(
516///     |x| {
517///         *seen_mut = seen_mut.wrapping_add(1);
518///         *x > 1 // the decision must not depend on the mutable state!
519///     },
520///     commutative = verus_proof_commutative_filter!(
521///         item = &u32,
522///         captures_mut = |seen_mut: u32|
523///     )
524/// ));
525/// ```
526///
527/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
528macro_rules! __verus_proof_commutative_filter__ {
529    (
530        item = $itemty:ty
531        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
532        , captures_mut = |$mcap:ident : $mcapty:ty $(,)?|
533        $(, proof = |$pstate:ident, $px:ident, $py:ident| { $($proof_body:tt)* })?
534        , __target = { $(move)? |$titem:ident $(: $titemty:ty)?| $target_body:expr }
535        , __captures = [$($fv:ident),* $(,)?] $(,)?
536    ) => {{
537        /// Checks that every free variable captured by the closure is declared (with its
538        /// type) in the `captures = |...|` or `captures_mut = |...|` clauses: within this
539        /// function, the *only* names in scope are the declared captures, so an
540        /// undeclared capture fails to resolve.
541        #[allow(unused, reason = "only checks name resolution")]
542        fn __hydro_verus_captures_declared($($($cap: $capty,)*)? $mcap: $mcapty) {
543            $(let $fv = &$fv;)*
544        }
545
546        #[cfg(verus_keep_ghost)]
547        const _: () = {
548            #[allow(unused_imports)]
549            use ::vstd::prelude::*;
550
551            ::vstd::prelude::verus! {
552                /// Commutativity obligation, generated by
553                /// `verus_proof_commutative_filter!`: from any equal starting captured
554                /// states, processing `x` then `y` must yield the same final captured
555                /// state as processing `y` then `x`, and the retained multisets must be
556                /// equal: either the per-item decisions match across the two orders, or
557                /// the two items are equal and the retained counts match. Verifying this
558                /// also proves the body panic-free.
559                fn __hydro_verus_commutative(
560                    $($($cap: $capty,)*)?
561                    __hydro_state_xy: $mcapty,
562                    __hydro_state_yx: $mcapty,
563                    __hydro_x_0: $itemty,
564                    __hydro_x_1: $itemty,
565                    __hydro_y_0: $itemty,
566                    __hydro_y_1: $itemty,
567                )
568                    requires
569                        __hydro_state_xy == __hydro_state_yx,
570                        __hydro_x_0 == __hydro_x_1,
571                        __hydro_y_0 == __hydro_y_1,
572                {
573                    $(
574                        let ghost $pstate = __hydro_state_xy;
575                        let ghost $px = __hydro_x_0;
576                        let ghost $py = __hydro_y_0;
577                    )?
578                    let mut __hydro_state_xy = __hydro_state_xy;
579                    let mut __hydro_state_yx = __hydro_state_yx;
580                    let __hydro_keep_xy_x: bool = { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_x_0; $target_body };
581                    let __hydro_keep_xy_y: bool = { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_y_0; $target_body };
582                    let __hydro_keep_yx_y: bool = { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_y_1; $target_body };
583                    let __hydro_keep_yx_x: bool = { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_x_1; $target_body };
584                    $(proof { $($proof_body)* })?
585                    assert(__hydro_state_xy == __hydro_state_yx);
586                    assert(
587                        (__hydro_keep_xy_x == __hydro_keep_yx_x && __hydro_keep_xy_y == __hydro_keep_yx_y)
588                        || (__hydro_x_0 == __hydro_y_0
589                            && (__hydro_keep_xy_x as int) + (__hydro_keep_xy_y as int)
590                                == (__hydro_keep_yx_x as int) + (__hydro_keep_yx_y as int))
591                    );
592                }
593            }
594        };
595
596        $crate::properties::VerusCommutativeProof::new()
597    }};
598    (
599        $($rest:tt)*
600    ) => {{
601        ::core::compile_error!(
602            "verus_proof_commutative_filter! must be used as a property annotation inside `q!(...)` on a `|item| -> bool` closure with exactly one `captures_mut` entry, e.g. `commutative = verus_proof_commutative_filter!(item = &u32, captures_mut = |state: u32|)`"
603        );
604        $crate::properties::VerusCommutativeProof::new()
605    }};
606}
607
608#[macro_export]
609/// Fulfills a `commutative = ...` proof parameter for a **unit-returning, effectful
610/// closure** (shape `|item| -> ()`, e.g. for `for_each` or `inspect`) that mutates a
611/// captured singleton reference (from [`Singleton::by_mut`]), with a **Verus-checked
612/// proof of commutativity** of the captured-state update.
613///
614/// **What commutativity means for an effectful closure:** processing any two items in
615/// either order, starting from the same captured state, must leave the captured state in
616/// the same final value. Because the closure returns `()` (enforced by this macro; use
617/// [`verus_proof_commutative_map!`] or [`verus_proof_commutative_filter!`] for closures
618/// whose return value is observable), the state is the only observable effect.
619///
620/// The commuting state is the mutable capture, declared (with the type behind the
621/// reference) in the required `captures_mut = |state: S|` clause; additional read-only
622/// captures can be declared in a `captures = |...|` clause. `q!` also passes the
623/// closure's capture list (as a trailing `__captures = [...]` argument), and the macro
624/// checks at compile time that every capture is declared. The `item = ...` type must be
625/// written exactly as the closure receives it (e.g. `&u32` for `inspect`).
626///
627/// Users never write the proof obligation: this macro receives the quoted closure itself
628/// from `q!` (as a trailing `__target = { ... }` argument) and generates a Verus function
629/// that symbolically executes the *actual closure body* in both orders — `x` then `y`,
630/// and `y` then `x` — from equal captured states, and asserts that the final states are
631/// equal. Verifying this also proves the body panic-free.
632///
633/// An optional `proof = |state, x, y| { ... }` clause supplies a proof *script* to help
634/// the SMT solver, with ghost bindings for the initial captured state and the two items.
635/// The script is checked by Verus and cannot weaken the obligation.
636///
637/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
638/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
639/// macro just produces a [`VerusCommutativeProof`] marker.
640///
641/// # Example
642/// ```rust,ignore
643/// let flags_mut = flags.by_mut();
644/// stream.for_each(q!(
645///     |x| { *flags_mut |= x; },
646///     commutative = verus_proof_commutative_effect!(
647///         item = u32,
648///         captures_mut = |flags_mut: u32|,
649///         proof = |s, x, y| { assert(((s | x) | y) == ((s | y) | x)) by (bit_vector); }
650///     )
651/// ));
652/// ```
653///
654/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
655macro_rules! __verus_proof_commutative_effect__ {
656    (
657        item = $itemty:ty
658        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
659        , captures_mut = |$mcap:ident : $mcapty:ty $(,)?|
660        $(, proof = |$pstate:ident, $px:ident, $py:ident| { $($proof_body:tt)* })?
661        , __target = { $(move)? |$titem:ident $(: $titemty:ty)?| $target_body:expr }
662        , __captures = [$($fv:ident),* $(,)?] $(,)?
663    ) => {{
664        /// Checks that every free variable captured by the closure is declared (with its
665        /// type) in the `captures = |...|` or `captures_mut = |...|` clauses: within this
666        /// function, the *only* names in scope are the declared captures, so an
667        /// undeclared capture fails to resolve.
668        #[allow(unused, reason = "only checks name resolution")]
669        fn __hydro_verus_captures_declared($($($cap: $capty,)*)? $mcap: $mcapty) {
670            $(let $fv = &$fv;)*
671        }
672
673        #[cfg(verus_keep_ghost)]
674        const _: () = {
675            #[allow(unused_imports)]
676            use ::vstd::prelude::*;
677
678            ::vstd::prelude::verus! {
679                /// Commutativity obligation, generated by
680                /// `verus_proof_commutative_effect!`: applying the closure body with `x`
681                /// then `y` must yield the same captured state as applying it with `y`
682                /// then `x`, from any equal starting states. The closure must return
683                /// `()`, so the state is the only observable effect. Verifying this also
684                /// proves the body panic-free.
685                fn __hydro_verus_commutative(
686                    $($($cap: $capty,)*)?
687                    __hydro_state_xy: $mcapty,
688                    __hydro_state_yx: $mcapty,
689                    __hydro_x_0: $itemty,
690                    __hydro_x_1: $itemty,
691                    __hydro_y_0: $itemty,
692                    __hydro_y_1: $itemty,
693                )
694                    requires
695                        __hydro_state_xy == __hydro_state_yx,
696                        __hydro_x_0 == __hydro_x_1,
697                        __hydro_y_0 == __hydro_y_1,
698                {
699                    $(
700                        let ghost $pstate = __hydro_state_xy;
701                        let ghost $px = __hydro_x_0;
702                        let ghost $py = __hydro_y_0;
703                    )?
704                    let mut __hydro_state_xy = __hydro_state_xy;
705                    let mut __hydro_state_yx = __hydro_state_yx;
706                    { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_x_0; let __hydro_out: () = { $target_body }; }
707                    { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_y_0; let __hydro_out: () = { $target_body }; }
708                    { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_y_1; let __hydro_out: () = { $target_body }; }
709                    { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_x_1; let __hydro_out: () = { $target_body }; }
710                    $(proof { $($proof_body)* })?
711                    assert(__hydro_state_xy == __hydro_state_yx);
712                }
713            }
714        };
715
716        $crate::properties::VerusCommutativeProof::new()
717    }};
718    (
719        $($rest:tt)*
720    ) => {{
721        ::core::compile_error!(
722            "verus_proof_commutative_effect! must be used as a property annotation inside `q!(...)` on a `|item| -> ()` closure with exactly one `captures_mut` entry, e.g. `commutative = verus_proof_commutative_effect!(item = u32, captures_mut = |state: u32|)`"
723        );
724        $crate::properties::VerusCommutativeProof::new()
725    }};
726}
727
728/// Marks that the property is not proved.
729pub enum NotProved {}
730
731/// Marks that the property is proven.
732pub enum Proved {}
733
734/// Algebraic properties for an aggregation function of type (T, &mut A) -> ().
735///
736/// Commutativity:
737/// ```rust,ignore
738/// let mut state = ???;
739/// f(a, &mut state); f(b, &mut state) // produces same final state as
740/// f(b, &mut state); f(a, &mut state)
741/// ```
742///
743/// Idempotence:
744/// ```rust,ignore
745/// let mut state = ???;
746/// f(a, &mut state);
747/// let state1 = *state;
748/// f(a, &mut state);
749/// // state1 must be equal to state
750/// ```
751pub struct AggFuncAlgebra<
752    T = (),
753    B: Boundedness = crate::live_collections::boundedness::Unbounded,
754    Commutative = NotProved,
755    Idempotent = NotProved,
756    Monotone = NotProved,
757    S = OnProcess,
758>(
759    Option<Box<dyn CommutativeProof<T, B, S>>>,
760    Option<Box<dyn IdempotentProof>>,
761    Option<Box<dyn MonotoneProof>>,
762    PhantomData<(Commutative, Idempotent, Monotone)>,
763);
764
765impl<T, B: Boundedness, C, I, M, S> AggFuncAlgebra<T, B, C, I, M, S> {
766    /// Marks the function as being commutative, with the given proof mechanism.
767    pub fn commutative(
768        self,
769        proof: impl CommutativeProof<T, B, S> + 'static,
770    ) -> AggFuncAlgebra<T, B, Proved, I, M, S> {
771        AggFuncAlgebra(Some(Box::new(proof)), self.1, self.2, PhantomData)
772    }
773
774    /// Marks the function as being idempotent, with the given proof mechanism.
775    pub fn idempotent(
776        self,
777        proof: impl IdempotentProof + 'static,
778    ) -> AggFuncAlgebra<T, B, C, Proved, M, S> {
779        AggFuncAlgebra(self.0, Some(Box::new(proof)), self.2, PhantomData)
780    }
781
782    /// Marks the function as being monotone, with the given proof mechanism.
783    pub fn monotone(
784        self,
785        proof: impl MonotoneProof + 'static,
786    ) -> AggFuncAlgebra<T, B, C, I, Proved, S> {
787        AggFuncAlgebra(self.0, self.1, Some(Box::new(proof)), PhantomData)
788    }
789
790    /// Registers the expression with the underlying proof mechanisms, and takes the
791    /// simulator ordering hook attached to the commutativity proof, if any.
792    pub(crate) fn register_proof(self, expr: &syn::Expr) -> Option<OrderingHook<T, B, S>> {
793        let mut hook = None;
794        if let Some(mut comm_proof) = self.0 {
795            comm_proof.register_proof(expr);
796            hook = comm_proof.take_hook();
797        }
798
799        if let Some(idem_proof) = self.1 {
800            idem_proof.register_proof(expr);
801        }
802
803        if let Some(monotone_proof) = self.2 {
804            monotone_proof.register_proof(expr);
805        }
806
807        hook
808    }
809}
810
811impl<T, B: Boundedness, C, I, M, S> Property for AggFuncAlgebra<T, B, C, I, M, S> {
812    type Root = AggFuncAlgebra<T, B, NotProved, NotProved, NotProved, S>;
813
814    fn make_root(_target: &mut Option<Self>) -> Self::Root {
815        AggFuncAlgebra(None, None, None, PhantomData)
816    }
817}
818
819/// Algebraic properties for a singleton map function of type T -> U.
820///
821/// Order-preserving means that if the input grows monotonically, the output also grows monotonically.
822pub struct SingletonMapFuncAlgebra<
823    T = (),
824    B: Boundedness = crate::live_collections::boundedness::Unbounded,
825    OrderPreserving = NotProved,
826    Commutative = NotProved,
827    Idempotent = NotProved,
828    S = OnProcess,
829>(
830    Option<Box<dyn OrderPreservingProof>>,
831    Option<Box<dyn CommutativeProof<T, B, S>>>,
832    Option<Box<dyn IdempotentProof>>,
833    PhantomData<(OrderPreserving, Commutative, Idempotent)>,
834);
835
836impl<T, B: Boundedness, O, C, I, S> SingletonMapFuncAlgebra<T, B, O, C, I, S> {
837    /// Marks the function as being order-preserving, with the given proof mechanism.
838    pub fn order_preserving(
839        self,
840        proof: impl OrderPreservingProof + 'static,
841    ) -> SingletonMapFuncAlgebra<T, B, Proved, C, I, S> {
842        SingletonMapFuncAlgebra(Some(Box::new(proof)), self.1, self.2, PhantomData)
843    }
844
845    /// Marks the function as being commutative, with the given proof mechanism.
846    pub fn commutative(
847        self,
848        proof: impl CommutativeProof<T, B, S> + 'static,
849    ) -> SingletonMapFuncAlgebra<T, B, O, Proved, I, S> {
850        SingletonMapFuncAlgebra(self.0, Some(Box::new(proof)), self.2, PhantomData)
851    }
852
853    /// Marks the function as being idempotent, with the given proof mechanism.
854    pub fn idempotent(
855        self,
856        proof: impl IdempotentProof + 'static,
857    ) -> SingletonMapFuncAlgebra<T, B, O, C, Proved, S> {
858        SingletonMapFuncAlgebra(self.0, self.1, Some(Box::new(proof)), PhantomData)
859    }
860
861    /// Registers the expression with the underlying proof mechanisms, and takes the
862    /// simulator ordering hook attached to the commutativity proof, if any.
863    pub(crate) fn register_proof(self, expr: &syn::Expr) -> Option<OrderingHook<T, B, S>> {
864        if let Some(proof) = self.0 {
865            proof.register_proof(expr);
866        }
867        self.1.and_then(|mut proof| {
868            proof.register_proof(expr);
869            proof.take_hook()
870        })
871    }
872}
873
874impl<T, B: Boundedness, O, C, I, S> Property for SingletonMapFuncAlgebra<T, B, O, C, I, S> {
875    type Root = SingletonMapFuncAlgebra<T, B, NotProved, NotProved, NotProved, S>;
876
877    fn make_root(_target: &mut Option<Self>) -> Self::Root {
878        SingletonMapFuncAlgebra(None, None, None, PhantomData)
879    }
880}
881
882/// Algebraic properties for a stream map function of type T -> U.
883pub struct StreamMapFuncAlgebra<
884    T = (),
885    B: Boundedness = crate::live_collections::boundedness::Unbounded,
886    Commutative = NotProved,
887    Idempotent = NotProved,
888    S = OnProcess,
889>(
890    Option<Box<dyn CommutativeProof<T, B, S>>>,
891    Option<Box<dyn IdempotentProof>>,
892    PhantomData<(Commutative, Idempotent)>,
893);
894
895impl<T, B: Boundedness, C, I, S> StreamMapFuncAlgebra<T, B, C, I, S> {
896    /// Marks the function as being commutative, with the given proof mechanism.
897    pub fn commutative(
898        self,
899        proof: impl CommutativeProof<T, B, S> + 'static,
900    ) -> StreamMapFuncAlgebra<T, B, Proved, I, S> {
901        StreamMapFuncAlgebra(Some(Box::new(proof)), self.1, PhantomData)
902    }
903
904    /// Marks the function as being idempotent, with the given proof mechanism.
905    pub fn idempotent(
906        self,
907        proof: impl IdempotentProof + 'static,
908    ) -> StreamMapFuncAlgebra<T, B, C, Proved, S> {
909        StreamMapFuncAlgebra(self.0, Some(Box::new(proof)), PhantomData)
910    }
911
912    /// Registers the expression with the underlying proof mechanisms, and takes the
913    /// simulator ordering hook attached to the commutativity proof, if any.
914    pub(crate) fn register_proof(self, expr: &syn::Expr) -> Option<OrderingHook<T, B, S>> {
915        let hook = self.0.and_then(|mut proof| {
916            proof.register_proof(expr);
917            proof.take_hook()
918        });
919        if let Some(proof) = self.1 {
920            proof.register_proof(expr);
921        }
922        hook
923    }
924}
925
926impl<T, B: Boundedness, C, I, S> Property for StreamMapFuncAlgebra<T, B, C, I, S> {
927    type Root = StreamMapFuncAlgebra<T, B, NotProved, NotProved, S>;
928
929    fn make_root(_target: &mut Option<Self>) -> Self::Root {
930        StreamMapFuncAlgebra(None, None, PhantomData)
931    }
932}
933
934/// Marker trait identifying that the commutativity property is valid for the given stream ordering.
935///
936/// **Definition (aggregations, `|acc: &mut A, item: T|`):** for any accumulator value
937/// and any two items `x`, `y`, applying the closure with `x` then `y` must produce the
938/// same final accumulator as applying it with `y` then `x`. This makes the final
939/// aggregate independent of the (non-deterministic) arrival order; note that
940/// *intermediate* accumulator values may still differ and must not be observed without
941/// a non-determinism annotation.
942#[diagnostic::on_unimplemented(
943    message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
944    label = "required for this call",
945    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."
946)]
947#[sealed::sealed]
948pub trait ValidCommutativityFor<O: Ordering> {}
949#[sealed::sealed]
950impl ValidCommutativityFor<TotalOrder> for NotProved {}
951#[sealed::sealed]
952impl<O: Ordering> ValidCommutativityFor<O> for Proved {}
953
954/// Marker trait identifying that the idempotence property is valid for the given stream ordering.
955#[diagnostic::on_unimplemented(
956    message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
957    label = "required for this call",
958    note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
959)]
960#[sealed::sealed]
961pub trait ValidIdempotenceFor<R: Retries> {}
962#[sealed::sealed]
963impl ValidIdempotenceFor<ExactlyOnce> for NotProved {}
964#[sealed::sealed]
965impl<R: Retries> ValidIdempotenceFor<R> for Proved {}
966
967/// Marker trait identifying that the commutativity property is valid for the given stream ordering.
968///
969/// A proof is required when the stream is unordered **and** the closure mutably captures
970/// state (`WAS_MUT`). **Definition (owned-item closures, `|item: T| -> Out`, e.g. `map`
971/// / `for_each`):** processing any two items in either order must (1) leave the
972/// mutably-captured state (e.g. [`Singleton::by_mut`] references) in the same final
973/// value, *and* (2) produce the same **multiset of return values**. Condition (2) is
974/// required whenever the return value is observable (as in `map`): a closure that
975/// emits, say, a running total is **not** commutative even if its state update is. For
976/// `()`-returning closures (as in `for_each`), condition (2) is trivial.
977///
978/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
979#[sealed::sealed]
980#[diagnostic::on_unimplemented(
981    message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
982    label = "required for this call",
983    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."
984)]
985pub trait ValidMutCommutativityFor<F: FnMut(In) -> Out, In, Out, O: Ordering, const WAS_MUT: bool> {}
986#[sealed::sealed]
987impl<In, Out, F: FnMut(In) -> Out> ValidMutCommutativityFor<F, In, Out, TotalOrder, true>
988    for NotProved
989{
990}
991#[sealed::sealed]
992impl<In, Out, F: Fn(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, false>
993    for NotProved
994{
995}
996#[sealed::sealed]
997impl<In, Out, F: FnMut(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, true>
998    for Proved
999{
1000}
1001#[sealed::sealed]
1002impl<In, Out, F: Fn(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, false>
1003    for Proved
1004{
1005}
1006
1007/// Marker trait identifying that the idempotence property is valid for the given stream ordering.
1008#[diagnostic::on_unimplemented(
1009    message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
1010    label = "required for this call",
1011    note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
1012)]
1013#[sealed::sealed]
1014pub trait ValidMutIdempotenceFor<F: FnMut(In) -> Out, In, Out, R: Retries, const WAS_MUT: bool> {}
1015#[sealed::sealed]
1016impl<In, Out, F: FnMut(In) -> Out> ValidMutIdempotenceFor<F, In, Out, ExactlyOnce, true>
1017    for NotProved
1018{
1019}
1020#[sealed::sealed]
1021impl<In, Out, F: Fn(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, false>
1022    for NotProved
1023{
1024}
1025#[sealed::sealed]
1026impl<In, Out, F: FnMut(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, true>
1027    for Proved
1028{
1029}
1030#[sealed::sealed]
1031impl<In, Out, F: Fn(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, false>
1032    for Proved
1033{
1034}
1035
1036/// Marker trait for commutativity of closures that borrow their input (`FnMut(&In) -> Out`).
1037///
1038/// A proof is required when the stream is unordered **and** the closure mutably captures
1039/// state (`WAS_MUT`). **Definition (borrowing closures, `|item: &T| -> Out`, e.g.
1040/// `filter` / `inspect`):** processing any two items in either order must (1) leave the
1041/// mutably-captured state (e.g. [`Singleton::by_mut`] references) in the same final
1042/// value, *and* (2) keep the operator's observable output identical as a multiset. For
1043/// `filter`, the outputs are the **retained elements**, so the predicate's decisions
1044/// must not depend on the processing order: a stateful predicate like a rate limiter is
1045/// **not** commutative — its budget converges either way, but *which* element passes
1046/// depends on the order. For `inspect`, the elements pass through unchanged, so only
1047/// condition (1) applies.
1048///
1049/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
1050#[sealed::sealed]
1051#[diagnostic::on_unimplemented(
1052    message = "Because the input stream has ordering `{O}`, the closure must demonstrate commutativity with a `commutative = ...` annotation.",
1053    label = "required for this call",
1054    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."
1055)]
1056pub trait ValidMutBorrowCommutativityFor<
1057    F: FnMut(&In) -> Out,
1058    In: ?Sized,
1059    Out,
1060    O: Ordering,
1061    const WAS_MUT: bool,
1062>
1063{
1064}
1065#[sealed::sealed]
1066impl<In: ?Sized, Out, F: FnMut(&In) -> Out>
1067    ValidMutBorrowCommutativityFor<F, In, Out, TotalOrder, true> for NotProved
1068{
1069}
1070#[sealed::sealed]
1071impl<In: ?Sized, Out, F: Fn(&In) -> Out, O: Ordering>
1072    ValidMutBorrowCommutativityFor<F, In, Out, O, false> for NotProved
1073{
1074}
1075#[sealed::sealed]
1076impl<In: ?Sized, Out, F: FnMut(&In) -> Out, O: Ordering>
1077    ValidMutBorrowCommutativityFor<F, In, Out, O, true> for Proved
1078{
1079}
1080#[sealed::sealed]
1081impl<In: ?Sized, Out, F: Fn(&In) -> Out, O: Ordering>
1082    ValidMutBorrowCommutativityFor<F, In, Out, O, false> for Proved
1083{
1084}
1085
1086/// Marker trait for idempotence of closures that borrow their input (`FnMut(&In) -> Out`).
1087#[diagnostic::on_unimplemented(
1088    message = "Because the input stream has retries `{R}`, the closure must demonstrate idempotence with an `idempotent = ...` annotation.",
1089    label = "required for this call",
1090    note = "To intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`. This introduces non-determinism so avoid unless necessary."
1091)]
1092#[sealed::sealed]
1093pub trait ValidMutBorrowIdempotenceFor<
1094    F: FnMut(&In) -> Out,
1095    In: ?Sized,
1096    Out,
1097    R: Retries,
1098    const WAS_MUT: bool,
1099>
1100{
1101}
1102#[sealed::sealed]
1103impl<In: ?Sized, Out, F: FnMut(&In) -> Out>
1104    ValidMutBorrowIdempotenceFor<F, In, Out, ExactlyOnce, true> for NotProved
1105{
1106}
1107#[sealed::sealed]
1108impl<In: ?Sized, Out, F: Fn(&In) -> Out, R: Retries>
1109    ValidMutBorrowIdempotenceFor<F, In, Out, R, false> for NotProved
1110{
1111}
1112#[sealed::sealed]
1113impl<In: ?Sized, Out, F: FnMut(&In) -> Out, R: Retries>
1114    ValidMutBorrowIdempotenceFor<F, In, Out, R, true> for Proved
1115{
1116}
1117#[sealed::sealed]
1118impl<In: ?Sized, Out, F: Fn(&In) -> Out, R: Retries>
1119    ValidMutBorrowIdempotenceFor<F, In, Out, R, false> for Proved
1120{
1121}
1122
1123/// Marker trait identifying the boundedness of a singleton given a monotonicity property of
1124/// an aggregation on a stream.
1125#[sealed::sealed]
1126pub trait ApplyMonotoneStream<P, B2: SingletonBound> {}
1127
1128#[sealed::sealed]
1129impl<B: Boundedness> ApplyMonotoneStream<NotProved, B> for B {}
1130
1131#[sealed::sealed]
1132impl<B: Boundedness> ApplyMonotoneStream<Proved, B::StreamToMonotone> for B {}
1133
1134/// Marker trait identifying the boundedness of a singleton given a monotonicity property of
1135/// an aggregation on a keyed stream.
1136#[sealed::sealed]
1137pub trait ApplyMonotoneKeyedStream<P, B2: KeyedSingletonBound> {}
1138
1139#[sealed::sealed]
1140impl<B: Boundedness> ApplyMonotoneKeyedStream<NotProved, B::KeyedStreamToNonMonotone> for B {}
1141
1142#[sealed::sealed]
1143impl<B: Boundedness> ApplyMonotoneKeyedStream<Proved, B::KeyedStreamToMonotone> for B {}
1144
1145/// Marker trait identifying the boundedness of a singleton after a map operation,
1146/// given an order-preserving property.
1147#[sealed::sealed]
1148pub trait ApplyOrderPreservingSingleton<P, B2: SingletonBound> {}
1149
1150#[sealed::sealed]
1151impl<B: SingletonBound> ApplyOrderPreservingSingleton<NotProved, B::UnderlyingBound> for B {}
1152
1153#[sealed::sealed]
1154impl<B: SingletonBound> ApplyOrderPreservingSingleton<Proved, B> for B {}