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