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, ExactlyOnce, 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, ExactlyOnce, S>>> {
85    #[doc(hidden)]
86    pub fn hooked(hook: impl Into<Option<OrderingHook<T, B, ExactlyOnce, 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, ExactlyOnce, S>>>
94{
95    fn register_proof(&self, _expr: &syn::Expr) {}
96
97    fn take_hook(&mut self) -> Option<OrderingHook<T, B, ExactlyOnce, 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, ExactlyOnce, 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 = ...`; see [`VerusIdempotentProof`]).
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, ExactlyOnce, 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/// A machine-checked proof of **idempotence**, verified by [Verus](https://verus-lang.github.io/verus/guide/).
172///
173/// Created by the [`verus_proof_idempotent_fold!`], [`verus_proof_idempotent_reduce!`],
174/// [`verus_proof_idempotent_map!`], [`verus_proof_idempotent_filter!`], and
175/// [`verus_proof_idempotent_effect!`] macros, one per closure shape, each generating the
176/// precise obligation that makes a retried (duplicated) element unobservable for that
177/// shape (final accumulator, re-emitted output, retention decision, or captured state,
178/// respectively). The obligation is generated by the macro directly from the *actual
179/// closure body* — it symbolically executes the body on an element once, and on the same
180/// element twice in a row, from equal initial states, and requires the observable
181/// results to be equal — so users never write (and cannot weaken) the assertion. Users
182/// only declare the types involved and, optionally, provide a proof *script* to help the
183/// SMT solver, which is itself checked by Verus.
184///
185/// Combined with a commutativity proof (required on unordered streams), the obligation
186/// also covers duplicates that are not adjacent to the original element, since
187/// commutativity allows moving the duplicate next to it.
188///
189/// When the crate is verified with `cargo verus verify`, Verus checks the obligation
190/// (which also proves the closure body panic-free, e.g. no arithmetic overflow). Under
191/// normal compilation, the proof is erased and this type simply marks the property as
192/// proven. Note that the simulator does not inject retries, so (unlike commutativity)
193/// idempotence claims are not explored by simulation tests at all; a Verus proof is the
194/// only mechanical check. This type only implements [`IdempotentProof`], so it cannot be
195/// used to fulfill a different property (e.g. `commutative = ...`).
196pub struct VerusIdempotentProof {
197    _private: (),
198}
199
200impl VerusIdempotentProof {
201    #[doc(hidden)]
202    pub fn new() -> Self {
203        VerusIdempotentProof { _private: () }
204    }
205}
206
207impl Default for VerusIdempotentProof {
208    fn default() -> Self {
209        Self::new()
210    }
211}
212
213#[sealed::sealed]
214impl IdempotentProof for VerusIdempotentProof {
215    fn register_proof(&self, _expr: &syn::Expr) {}
216}
217
218#[doc(inline)]
219pub use crate::__manual_proof__ as manual_proof;
220
221// Verus only sees items declared inside `verus!`, so under the Verus driver (with the
222// `verus` feature) the function backing `verus_panic!` is declared there.
223// `external_body`: Verus trusts the signature without checking the body (which calls
224// `panic!`, whose vstd specification is `requires false`). The signature has no
225// precondition and the default unwind specification (may unwind), so callers need not
226// prove anything, and since the return type is `!`, nothing after the call is reachable.
227#[cfg(all(verus_keep_ghost, feature = "verus"))]
228vstd::prelude::verus! {
229    #[doc(hidden)]
230    #[verifier::external_body]
231    pub fn __verus_panic() -> ! {
232        panic!("verus_panic! was reached")
233    }
234}
235
236#[doc(inline)]
237pub use crate::__verus_panic__ as verus_panic;
238
239#[cfg(all(verus_keep_ghost, feature = "verus"))]
240#[doc(hidden)]
241#[macro_export]
242macro_rules! __verus_panic__ {
243    // The message arguments are dropped: Verus does not support `format_args!`, and they
244    // would only be evaluated on a path that panics anyway.
245    ($($arg:tt)*) => {
246        $crate::properties::__verus_panic()
247    };
248}
249
250#[cfg(not(all(verus_keep_ghost, feature = "verus")))]
251#[macro_export]
252/// Panics, in a way that **Verus proofs of algebraic properties treat as an acceptable
253/// outcome**. Takes the same arguments as [`panic!`].
254///
255/// A Verus proof (e.g. [`verus_proof_commutative_fold!`]) normally requires the closure body
256/// to be panic-free for every input, which rejects closures such as `*acc += x` (which
257/// panics on overflow) even though they are commutative whenever they complete. Calling
258/// `verus_panic!(...)` instead tells Verus that this path ends the program: the property
259/// only has to hold for executions that do **not** reach it. That matches Hydro's
260/// requirement, since a panicking closure crashes the process rather than producing a
261/// result.
262///
263/// The typical use is to guard an operation that could otherwise panic, so that Verus
264/// knows it cannot fail on the paths that continue:
265///
266/// ```rust,ignore
267/// q!(
268///     |acc, x| {
269///         if *acc > u32::MAX - x {
270///             verus_panic!("sum overflowed");
271///         }
272///         *acc += x; // cannot overflow here, so Verus accepts it
273///     },
274///     commutative = verus_proof_commutative_fold!(acc = u32, item = u32)
275/// )
276/// ```
277///
278/// This is sound because the guard really executes: the closure panics at runtime whenever
279/// the guard condition holds, so a guard that is stricter than necessary is still correct.
280/// A guard that is too weak is caught by Verus, which reports the operation that may still
281/// panic. Unlike `assume(...)` in a proof script, nothing is taken on faith beyond the fact
282/// that `verus_panic!` never returns.
283///
284/// Under normal compilation, this forwards its arguments to [`panic!`]. When verifying
285/// with `cargo verus verify`, the `verus` feature of `hydro_lang` must be enabled; Verus
286/// then sees a call to a function that never returns (the message arguments are not
287/// evaluated by the proof).
288macro_rules! __verus_panic__ {
289    ($($arg:tt)*) => {
290        ::core::panic!($($arg)*)
291    };
292}
293
294#[macro_export]
295/// Fulfills a proof parameter by declaring a human-written justification for why
296/// the algebraic property (e.g. commutativity, idempotence) holds.
297///
298/// The argument must be a doc comment explaining why the property is satisfied.
299///
300/// # Examples
301/// ```rust
302/// # #[cfg(feature = "deploy")] {
303/// # use hydro_lang::prelude::*;
304/// # use hydro_lang::live_collections::stream::NoOrder;
305/// # use futures::StreamExt;
306/// # tokio_test::block_on(hydro_lang::test_util::stream_transform_test(|process| {
307/// # let stream = process.source_iter(q!(vec![1, 2, 3])).weaken_ordering::<NoOrder>();
308/// // stream: [1, 2, 3] (unordered)
309/// stream
310///     .fold(
311///         q!(|| 0),
312///         q!(
313///             |acc, x| *acc += x,
314///             commutative = manual_proof!(/** integer addition is commutative */)
315///         ),
316///     )
317///     .into_stream()
318/// # }, |mut stream| async move {
319/// # assert_eq!(stream.next().await.unwrap(), 6);
320/// # }));
321/// # }
322/// ```
323/// An optional trailing `hook = ...` argument attaches a **simulator ordering hook** to a
324/// commutativity proof (see `hydro_lang::sim::hooks`). The simulator does not trust manual
325/// proofs — it still explores the input ordering — so the hook lets a simulation test
326/// script that exploration:
327///
328/// ```rust,ignore
329/// commutative = manual_proof!(/** set insert is commutative */ hook = my_ordering_hook)
330/// ```
331macro_rules! __manual_proof__ {
332    (
333        $(#[doc = $doc:expr])+hook =
334        $hook:expr,__target =
335        { $($target:tt)* } $(,__captures = [$($captures:ident),*])? $(,)?
336    ) => {
337        $crate::properties::ManualProof::hooked($hook)
338    };
339    ($(#[doc = $doc:expr])+hook = $hook:expr $(,)?) => {
340        $crate::properties::ManualProof::hooked($hook)
341    };
342    (
343        $(#[doc = $doc:expr])+,__target =
344        { $($target:tt)* } $(,__captures = [$($captures:ident),*])? $(,)?
345    ) => {
346        $crate::properties::ManualProof::<()>::unhooked()
347    };
348    ($(#[doc = $doc:expr])+) => {
349        $crate::properties::ManualProof::<()>::unhooked()
350    };
351}
352
353#[doc(inline)]
354pub use crate::__verus_proof_commutative_effect__ as verus_proof_commutative_effect;
355#[doc(inline)]
356pub use crate::__verus_proof_commutative_filter__ as verus_proof_commutative_filter;
357#[doc(inline)]
358pub use crate::__verus_proof_commutative_fold__ as verus_proof_commutative_fold;
359#[doc(inline)]
360pub use crate::__verus_proof_commutative_map__ as verus_proof_commutative_map;
361
362#[macro_export]
363/// Fulfills a `commutative = ...` proof parameter for an **aggregation closure**
364/// (`fold` / `reduce`, shape `|acc, item|` with `acc: &mut A`) with a **Verus-checked
365/// proof of commutativity**.
366///
367/// Users never write the proof obligation (so they cannot get it wrong): this macro
368/// receives the quoted closure itself from `q!` (as a trailing `__target = { ... }`
369/// argument) and generates a Verus function that symbolically executes the *actual
370/// closure body* in both orders — `x` then `y`, and `y` then `x` — starting from equal
371/// accumulators, and asserts that the final accumulators are equal. Verifying this
372/// obligation also proves the closure body panic-free (e.g. no arithmetic overflow).
373/// Users only declare the accumulator and item types:
374///
375/// ```rust,ignore
376/// batch.reduce(q!(
377///     |curr, new| { if new > *curr { *curr = new; } },
378///     commutative = verus_proof_commutative_fold!(acc = u32, item = u32)
379/// ));
380/// ```
381///
382/// If the closure captures (read-only) variables from its environment, re-declare them
383/// (with their runtime types) in a `captures = |...|` clause; the obligation is then
384/// universally quantified over the capture values, which is sound since any particular
385/// execution uses some fixed value. `q!` also passes the closure's capture list (as a
386/// trailing `__captures = [...]` argument), and the macro checks at compile time that
387/// every capture is declared.
388///
389/// An optional `proof = |state, x, y| { ... }` clause supplies a proof *script* to help
390/// the SMT solver, with ghost bindings for the initial accumulator and the two items
391/// (e.g. `proof = |s, x, y| { assert((s | x) | y == (s | y) | x) by (bit_vector); }`).
392/// The script is checked by Verus and cannot weaken the obligation (though, as anywhere
393/// in Verus, `assume` is an explicit soundness escape hatch).
394///
395/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
396/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
397/// macro just produces a [`VerusCommutativeProof`] marker, so the types go through the
398/// ordinary `commutative = ...` mechanism with zero overhead.
399macro_rules! __verus_proof_commutative_fold__ {
400    (
401        acc = $accty:ty, item = $itemty:ty
402        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
403        $(, proof = |$pstate:ident, $px:ident, $py:ident| { $($proof_body:tt)* })?
404        , __target = { $(move)? |$tacc:ident $(: $taccty:ty)?, $titem:ident $(: $titemty:ty)?| $target_body:expr }
405        , __captures = [$($fv:ident),* $(,)?] $(,)?
406    ) => {{
407        /// Checks that every free variable captured by the closure is declared (with its
408        /// type) in the `captures = |...|` clause: within this function, the *only* names
409        /// in scope are the declared captures and the closure parameters, so an
410        /// undeclared capture fails to resolve.
411        #[allow(unused, reason = "only checks name resolution")]
412        fn __hydro_verus_captures_declared($($($cap: $capty),*)?) {
413            $(let $fv = &$fv;)*
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_fold!`:
422                /// applying the closure body with `x` then `y` must yield the same
423                /// accumulator as applying it with `y` then `x`, from any equal starting
424                /// accumulators, for all items and capture values. Verifying this also
425                /// proves the body panic-free.
426                fn __hydro_verus_commutative(
427                    $($($cap: $capty,)*)?
428                    __hydro_acc_xy: $accty,
429                    __hydro_acc_yx: $accty,
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_acc_xy == __hydro_acc_yx,
437                        __hydro_x_0 == __hydro_x_1,
438                        __hydro_y_0 == __hydro_y_1,
439                {
440                    $(
441                        let ghost $pstate = __hydro_acc_xy;
442                        let ghost $px = __hydro_x_0;
443                        let ghost $py = __hydro_y_0;
444                    )?
445                    let mut __hydro_acc_xy = __hydro_acc_xy;
446                    let mut __hydro_acc_yx = __hydro_acc_yx;
447                    { let $tacc = &mut __hydro_acc_xy; let $titem = __hydro_x_0; let _ = { $target_body }; }
448                    { let $tacc = &mut __hydro_acc_xy; let $titem = __hydro_y_0; let _ = { $target_body }; }
449                    { let $tacc = &mut __hydro_acc_yx; let $titem = __hydro_y_1; let _ = { $target_body }; }
450                    { let $tacc = &mut __hydro_acc_yx; let $titem = __hydro_x_1; let _ = { $target_body }; }
451                    $(proof { $($proof_body)* })?
452                    assert(__hydro_acc_xy == __hydro_acc_yx);
453                }
454            }
455        };
456
457        $crate::properties::VerusCommutativeProof::new()
458    }};
459    (
460        $($rest:tt)*
461    ) => {{
462        ::core::compile_error!(
463            "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)`"
464        );
465        $crate::properties::VerusCommutativeProof::new()
466    }};
467}
468
469#[macro_export]
470/// Fulfills a `commutative = ...` proof parameter for a **map-like closure**
471/// (shape `|item| -> out`, e.g. for `map`) that may mutate a captured singleton
472/// reference (from [`Singleton::by_mut`]), with a **Verus-checked proof of
473/// commutativity**.
474///
475/// **What commutativity means for a map closure:** processing any two items in either
476/// order, starting from the same captured state, must (1) leave the captured state in
477/// the same final value, *and* (2) produce the same **multiset of output values** (the
478/// outputs may be swapped in order, but not changed). Both conditions are required for
479/// downstream determinism: outputs that depend on the processing order (e.g. emitting a
480/// running total) are **not** commutative even if the state update is.
481///
482/// The commuting state is the mutable capture, declared (with the type behind the
483/// reference) in the required `captures_mut = |state: S|` clause; additional read-only
484/// captures can be declared in a `captures = |...|` clause. `q!` also passes the
485/// closure's capture list (as a trailing `__captures = [...]` argument), and the macro
486/// checks at compile time that every capture is declared. The `item = ...` type must be
487/// written exactly as the closure receives it.
488///
489/// Users never write the proof obligation: this macro receives the quoted closure itself
490/// from `q!` (as a trailing `__target = { ... }` argument) and generates a Verus function
491/// that symbolically executes the *actual closure body* in both orders — `x` then `y`,
492/// and `y` then `x` — from equal captured states, then asserts that the final states are
493/// equal and that the two runs' outputs are equal as a multiset (pairwise or crossed).
494/// Verifying this also proves the body panic-free.
495///
496/// An optional `proof = |state, x, y| { ... }` clause supplies a proof *script* to help
497/// the SMT solver, with ghost bindings for the initial captured state and the two items.
498/// The script is checked by Verus and cannot weaken the obligation.
499///
500/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
501/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
502/// macro just produces a [`VerusCommutativeProof`] marker.
503///
504/// # Example
505/// ```rust,ignore
506/// let count_mut = my_count.by_mut();
507/// stream.map(q!(
508///     |x| {
509///         *count_mut = count_mut.wrapping_add(x);
510///         x // outputting `*count_mut` here would NOT be commutative!
511///     },
512///     commutative = verus_proof_commutative_map!(
513///         item = i32,
514///         captures_mut = |count_mut: i32|
515///     )
516/// ));
517/// ```
518///
519/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
520macro_rules! __verus_proof_commutative_map__ {
521    (
522        item = $itemty:ty
523        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
524        , captures_mut = |$mcap:ident : $mcapty:ty $(,)?|
525        $(, proof = |$pstate:ident, $px:ident, $py:ident| { $($proof_body:tt)* })?
526        , __target = { $(move)? |$titem:ident $(: $titemty:ty)?| $target_body:expr }
527        , __captures = [$($fv:ident),* $(,)?] $(,)?
528    ) => {{
529        /// Checks that every free variable captured by the closure is declared (with its
530        /// type) in the `captures = |...|` or `captures_mut = |...|` clauses: within this
531        /// function, the *only* names in scope are the declared captures, so an
532        /// undeclared capture fails to resolve.
533        #[allow(unused, reason = "only checks name resolution")]
534        fn __hydro_verus_captures_declared($($($cap: $capty,)*)? $mcap: $mcapty) {
535            $(let $fv = &$fv;)*
536        }
537
538        #[cfg(verus_keep_ghost)]
539        const _: () = {
540            #[allow(unused_imports)]
541            use ::vstd::prelude::*;
542
543            ::vstd::prelude::verus! {
544                /// Commutativity obligation, generated by `verus_proof_commutative_map!`:
545                /// from any equal starting captured states, processing `x` then `y` must
546                /// yield the same final captured state as processing `y` then `x`, and
547                /// the two runs must produce the same multiset of outputs (pairwise or
548                /// crossed equality). Verifying this also proves the body panic-free.
549                fn __hydro_verus_commutative(
550                    $($($cap: $capty,)*)?
551                    __hydro_state_xy: $mcapty,
552                    __hydro_state_yx: $mcapty,
553                    __hydro_x_0: $itemty,
554                    __hydro_x_1: $itemty,
555                    __hydro_y_0: $itemty,
556                    __hydro_y_1: $itemty,
557                )
558                    requires
559                        __hydro_state_xy == __hydro_state_yx,
560                        __hydro_x_0 == __hydro_x_1,
561                        __hydro_y_0 == __hydro_y_1,
562                {
563                    $(
564                        let ghost $pstate = __hydro_state_xy;
565                        let ghost $px = __hydro_x_0;
566                        let ghost $py = __hydro_y_0;
567                    )?
568                    let mut __hydro_state_xy = __hydro_state_xy;
569                    let mut __hydro_state_yx = __hydro_state_yx;
570                    let __hydro_out_xy_x = { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_x_0; $target_body };
571                    let __hydro_out_xy_y = { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_y_0; $target_body };
572                    let __hydro_out_yx_y = { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_y_1; $target_body };
573                    let __hydro_out_yx_x = { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_x_1; $target_body };
574                    $(proof { $($proof_body)* })?
575                    assert(__hydro_state_xy == __hydro_state_yx);
576                    assert(
577                        (__hydro_out_xy_x == __hydro_out_yx_x && __hydro_out_xy_y == __hydro_out_yx_y)
578                        || (__hydro_out_xy_x == __hydro_out_yx_y && __hydro_out_xy_y == __hydro_out_yx_x)
579                    );
580                }
581            }
582        };
583
584        $crate::properties::VerusCommutativeProof::new()
585    }};
586    (
587        $($rest:tt)*
588    ) => {{
589        ::core::compile_error!(
590            "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|)`"
591        );
592        $crate::properties::VerusCommutativeProof::new()
593    }};
594}
595
596#[macro_export]
597/// Fulfills a `commutative = ...` proof parameter for a **filter predicate**
598/// (shape `|item| -> bool` where `item` is received by reference) that may mutate a
599/// captured singleton reference (from [`Singleton::by_mut`]), with a **Verus-checked
600/// proof of commutativity**.
601///
602/// **What commutativity means for a filter predicate:** processing any two items in
603/// either order, starting from the same captured state, must (1) leave the captured
604/// state in the same final value, *and* (2) retain the same **multiset of elements**.
605/// The second condition is essential for soundness: a stateful predicate like a rate
606/// limiter converges to the same state either way, but *which* element passes depends on
607/// the order, which is **not** commutative (unless the elements are equal).
608///
609/// The commuting state is the mutable capture, declared (with the type behind the
610/// reference) in the required `captures_mut = |state: S|` clause; additional read-only
611/// captures can be declared in a `captures = |...|` clause. `q!` also passes the
612/// closure's capture list (as a trailing `__captures = [...]` argument), and the macro
613/// checks at compile time that every capture is declared. The `item = ...` type must be
614/// written exactly as the closure receives it (for `filter`, a reference like `&u32`).
615///
616/// Users never write the proof obligation: this macro receives the quoted closure itself
617/// from `q!` (as a trailing `__target = { ... }` argument) and generates a Verus function
618/// that symbolically executes the *actual predicate body* in both orders — `x` then `y`,
619/// and `y` then `x` — from equal captured states, then asserts that the final states are
620/// equal and that the retained multisets are equal: either the per-item decisions match
621/// across the two orders, or the two items are equal and the number of retained copies
622/// matches. Verifying this also proves the body panic-free.
623///
624/// An optional `proof = |state, x, y| { ... }` clause supplies a proof *script* to help
625/// the SMT solver, with ghost bindings for the initial captured state and the two items.
626/// The script is checked by Verus and cannot weaken the obligation.
627///
628/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
629/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
630/// macro just produces a [`VerusCommutativeProof`] marker.
631///
632/// # Example
633/// ```rust,ignore
634/// let seen_mut = seen_count.by_mut();
635/// stream.filter(q!(
636///     |x| {
637///         *seen_mut = seen_mut.wrapping_add(1);
638///         *x > 1 // the decision must not depend on the mutable state!
639///     },
640///     commutative = verus_proof_commutative_filter!(
641///         item = &u32,
642///         captures_mut = |seen_mut: u32|
643///     )
644/// ));
645/// ```
646///
647/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
648macro_rules! __verus_proof_commutative_filter__ {
649    (
650        item = $itemty:ty
651        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
652        , captures_mut = |$mcap:ident : $mcapty:ty $(,)?|
653        $(, proof = |$pstate:ident, $px:ident, $py:ident| { $($proof_body:tt)* })?
654        , __target = { $(move)? |$titem:ident $(: $titemty:ty)?| $target_body:expr }
655        , __captures = [$($fv:ident),* $(,)?] $(,)?
656    ) => {{
657        /// Checks that every free variable captured by the closure is declared (with its
658        /// type) in the `captures = |...|` or `captures_mut = |...|` clauses: within this
659        /// function, the *only* names in scope are the declared captures, so an
660        /// undeclared capture fails to resolve.
661        #[allow(unused, reason = "only checks name resolution")]
662        fn __hydro_verus_captures_declared($($($cap: $capty,)*)? $mcap: $mcapty) {
663            $(let $fv = &$fv;)*
664        }
665
666        #[cfg(verus_keep_ghost)]
667        const _: () = {
668            #[allow(unused_imports)]
669            use ::vstd::prelude::*;
670
671            ::vstd::prelude::verus! {
672                /// Commutativity obligation, generated by
673                /// `verus_proof_commutative_filter!`: from any equal starting captured
674                /// states, processing `x` then `y` must yield the same final captured
675                /// state as processing `y` then `x`, and the retained multisets must be
676                /// equal: either the per-item decisions match across the two orders, or
677                /// the two items are equal and the retained counts match. Verifying this
678                /// also proves the body panic-free.
679                fn __hydro_verus_commutative(
680                    $($($cap: $capty,)*)?
681                    __hydro_state_xy: $mcapty,
682                    __hydro_state_yx: $mcapty,
683                    __hydro_x_0: $itemty,
684                    __hydro_x_1: $itemty,
685                    __hydro_y_0: $itemty,
686                    __hydro_y_1: $itemty,
687                )
688                    requires
689                        __hydro_state_xy == __hydro_state_yx,
690                        __hydro_x_0 == __hydro_x_1,
691                        __hydro_y_0 == __hydro_y_1,
692                {
693                    $(
694                        let ghost $pstate = __hydro_state_xy;
695                        let ghost $px = __hydro_x_0;
696                        let ghost $py = __hydro_y_0;
697                    )?
698                    let mut __hydro_state_xy = __hydro_state_xy;
699                    let mut __hydro_state_yx = __hydro_state_yx;
700                    let __hydro_keep_xy_x: bool = { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_x_0; $target_body };
701                    let __hydro_keep_xy_y: bool = { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_y_0; $target_body };
702                    let __hydro_keep_yx_y: bool = { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_y_1; $target_body };
703                    let __hydro_keep_yx_x: bool = { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_x_1; $target_body };
704                    $(proof { $($proof_body)* })?
705                    assert(__hydro_state_xy == __hydro_state_yx);
706                    assert(
707                        (__hydro_keep_xy_x == __hydro_keep_yx_x && __hydro_keep_xy_y == __hydro_keep_yx_y)
708                        || (__hydro_x_0 == __hydro_y_0
709                            && (__hydro_keep_xy_x as int) + (__hydro_keep_xy_y as int)
710                                == (__hydro_keep_yx_x as int) + (__hydro_keep_yx_y as int))
711                    );
712                }
713            }
714        };
715
716        $crate::properties::VerusCommutativeProof::new()
717    }};
718    (
719        $($rest:tt)*
720    ) => {{
721        ::core::compile_error!(
722            "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|)`"
723        );
724        $crate::properties::VerusCommutativeProof::new()
725    }};
726}
727
728#[macro_export]
729/// Fulfills a `commutative = ...` proof parameter for a **unit-returning, effectful
730/// closure** (shape `|item| -> ()`, e.g. for `for_each` or `inspect`) that mutates a
731/// captured singleton reference (from [`Singleton::by_mut`]), with a **Verus-checked
732/// proof of commutativity** of the captured-state update.
733///
734/// **What commutativity means for an effectful closure:** processing any two items in
735/// either order, starting from the same captured state, must leave the captured state in
736/// the same final value. Because the closure returns `()` (enforced by this macro; use
737/// [`verus_proof_commutative_map!`] or [`verus_proof_commutative_filter!`] for closures
738/// whose return value is observable), the state is the only observable effect.
739///
740/// The commuting state is the mutable capture, declared (with the type behind the
741/// reference) in the required `captures_mut = |state: S|` clause; additional read-only
742/// captures can be declared in a `captures = |...|` clause. `q!` also passes the
743/// closure's capture list (as a trailing `__captures = [...]` argument), and the macro
744/// checks at compile time that every capture is declared. The `item = ...` type must be
745/// written exactly as the closure receives it (e.g. `&u32` for `inspect`).
746///
747/// Users never write the proof obligation: this macro receives the quoted closure itself
748/// from `q!` (as a trailing `__target = { ... }` argument) and generates a Verus function
749/// that symbolically executes the *actual closure body* in both orders — `x` then `y`,
750/// and `y` then `x` — from equal captured states, and asserts that the final states are
751/// equal. Verifying this also proves the body panic-free.
752///
753/// An optional `proof = |state, x, y| { ... }` clause supplies a proof *script* to help
754/// the SMT solver, with ghost bindings for the initial captured state and the two items.
755/// The script is checked by Verus and cannot weaken the obligation.
756///
757/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
758/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
759/// macro just produces a [`VerusCommutativeProof`] marker.
760///
761/// # Example
762/// ```rust,ignore
763/// let flags_mut = flags.by_mut();
764/// stream.for_each(q!(
765///     |x| { *flags_mut |= x; },
766///     commutative = verus_proof_commutative_effect!(
767///         item = u32,
768///         captures_mut = |flags_mut: u32|,
769///         proof = |s, x, y| { assert(((s | x) | y) == ((s | y) | x)) by (bit_vector); }
770///     )
771/// ));
772/// ```
773///
774/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
775macro_rules! __verus_proof_commutative_effect__ {
776    (
777        item = $itemty:ty
778        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
779        , captures_mut = |$mcap:ident : $mcapty:ty $(,)?|
780        $(, proof = |$pstate:ident, $px:ident, $py:ident| { $($proof_body:tt)* })?
781        , __target = { $(move)? |$titem:ident $(: $titemty:ty)?| $target_body:expr }
782        , __captures = [$($fv:ident),* $(,)?] $(,)?
783    ) => {{
784        /// Checks that every free variable captured by the closure is declared (with its
785        /// type) in the `captures = |...|` or `captures_mut = |...|` clauses: within this
786        /// function, the *only* names in scope are the declared captures, so an
787        /// undeclared capture fails to resolve.
788        #[allow(unused, reason = "only checks name resolution")]
789        fn __hydro_verus_captures_declared($($($cap: $capty,)*)? $mcap: $mcapty) {
790            $(let $fv = &$fv;)*
791        }
792
793        #[cfg(verus_keep_ghost)]
794        const _: () = {
795            #[allow(unused_imports)]
796            use ::vstd::prelude::*;
797
798            ::vstd::prelude::verus! {
799                /// Commutativity obligation, generated by
800                /// `verus_proof_commutative_effect!`: applying the closure body with `x`
801                /// then `y` must yield the same captured state as applying it with `y`
802                /// then `x`, from any equal starting states. The closure must return
803                /// `()`, so the state is the only observable effect. Verifying this also
804                /// proves the body panic-free.
805                fn __hydro_verus_commutative(
806                    $($($cap: $capty,)*)?
807                    __hydro_state_xy: $mcapty,
808                    __hydro_state_yx: $mcapty,
809                    __hydro_x_0: $itemty,
810                    __hydro_x_1: $itemty,
811                    __hydro_y_0: $itemty,
812                    __hydro_y_1: $itemty,
813                )
814                    requires
815                        __hydro_state_xy == __hydro_state_yx,
816                        __hydro_x_0 == __hydro_x_1,
817                        __hydro_y_0 == __hydro_y_1,
818                {
819                    $(
820                        let ghost $pstate = __hydro_state_xy;
821                        let ghost $px = __hydro_x_0;
822                        let ghost $py = __hydro_y_0;
823                    )?
824                    let mut __hydro_state_xy = __hydro_state_xy;
825                    let mut __hydro_state_yx = __hydro_state_yx;
826                    { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_x_0; let __hydro_out: () = { $target_body }; }
827                    { let $mcap = &mut __hydro_state_xy; let $titem = __hydro_y_0; let __hydro_out: () = { $target_body }; }
828                    { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_y_1; let __hydro_out: () = { $target_body }; }
829                    { let $mcap = &mut __hydro_state_yx; let $titem = __hydro_x_1; let __hydro_out: () = { $target_body }; }
830                    $(proof { $($proof_body)* })?
831                    assert(__hydro_state_xy == __hydro_state_yx);
832                }
833            }
834        };
835
836        $crate::properties::VerusCommutativeProof::new()
837    }};
838    (
839        $($rest:tt)*
840    ) => {{
841        ::core::compile_error!(
842            "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|)`"
843        );
844        $crate::properties::VerusCommutativeProof::new()
845    }};
846}
847
848#[doc(inline)]
849pub use crate::__verus_proof_idempotent_effect__ as verus_proof_idempotent_effect;
850#[doc(inline)]
851pub use crate::__verus_proof_idempotent_filter__ as verus_proof_idempotent_filter;
852#[doc(inline)]
853pub use crate::__verus_proof_idempotent_fold__ as verus_proof_idempotent_fold;
854#[doc(inline)]
855pub use crate::__verus_proof_idempotent_map__ as verus_proof_idempotent_map;
856#[doc(inline)]
857pub use crate::__verus_proof_idempotent_reduce__ as verus_proof_idempotent_reduce;
858
859#[macro_export]
860/// Fulfills an `idempotent = ...` proof parameter for a **fold closure** (shape
861/// `|acc, item|` with `acc: &mut A`) with a **Verus-checked proof of idempotence**.
862///
863/// Use [`verus_proof_idempotent_reduce!`] for `reduce`, whose accumulator is seeded with
864/// the first element, which needs an additional obligation.
865///
866/// Users never write the proof obligation (so they cannot get it wrong): this macro
867/// receives the quoted closure itself from `q!` (as a trailing `__target = { ... }`
868/// argument) and generates a Verus function that symbolically executes the *actual
869/// closure body* on an item `x` once, and on `x` twice in a row, starting from equal
870/// accumulators, and asserts that the final accumulators are equal. Verifying this
871/// obligation also proves the closure body panic-free (e.g. no arithmetic overflow).
872/// Users only declare the accumulator and item types:
873///
874/// ```rust,ignore
875/// stream.fold(
876///     q!(|| 0u32),
877///     q!(
878///         |acc, x| { if x > *acc { *acc = x; } },
879///         idempotent = verus_proof_idempotent_fold!(acc = u32, item = u32)
880///     ),
881/// );
882/// ```
883///
884/// Read-only captures are declared in a `captures = |...|` clause, exactly as for
885/// [`verus_proof_commutative_fold!`]; the macro checks at compile time that every capture
886/// is declared.
887///
888/// An optional `proof = |state, x| { ... }` clause supplies a proof *script* to help the
889/// SMT solver, with ghost bindings for the initial accumulator and the item (e.g.
890/// `proof = |s, x| { assert(((s | x) | x) == (s | x)) by (bit_vector); }`). The script is
891/// checked by Verus and cannot weaken the obligation.
892///
893/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
894/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
895/// macro just produces a [`VerusIdempotentProof`] marker.
896macro_rules! __verus_proof_idempotent_fold__ {
897    (
898        acc = $accty:ty, item = $itemty:ty
899        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
900        $(, proof = |$pstate:ident, $px:ident| { $($proof_body:tt)* })?
901        , __target = { $(move)? |$tacc:ident $(: $taccty:ty)?, $titem:ident $(: $titemty:ty)?| $target_body:expr }
902        , __captures = [$($fv:ident),* $(,)?] $(,)?
903    ) => {{
904        /// Checks that every free variable captured by the closure is declared (with its
905        /// type) in the `captures = |...|` clause: within this function, the *only* names
906        /// in scope are the declared captures and the closure parameters, so an
907        /// undeclared capture fails to resolve.
908        #[allow(unused, reason = "only checks name resolution")]
909        fn __hydro_verus_captures_declared($($($cap: $capty),*)?) {
910            $(let $fv = &$fv;)*
911        }
912
913        #[cfg(verus_keep_ghost)]
914        const _: () = {
915            #[allow(unused_imports)]
916            use ::vstd::prelude::*;
917
918            ::vstd::prelude::verus! {
919                /// Idempotence obligation, generated by `verus_proof_idempotent_fold!`:
920                /// applying the closure body with `x` twice in a row must yield the same
921                /// accumulator as applying it once, from any equal starting accumulators,
922                /// for all items and capture values. Verifying this also proves the body
923                /// panic-free.
924                fn __hydro_verus_idempotent(
925                    $($($cap: $capty,)*)?
926                    __hydro_acc_once: $accty,
927                    __hydro_acc_twice: $accty,
928                    __hydro_x_0: $itemty,
929                    __hydro_x_1: $itemty,
930                    __hydro_x_2: $itemty,
931                )
932                    requires
933                        __hydro_acc_once == __hydro_acc_twice,
934                        __hydro_x_0 == __hydro_x_1,
935                        __hydro_x_0 == __hydro_x_2,
936                {
937                    $(
938                        let ghost $pstate = __hydro_acc_once;
939                        let ghost $px = __hydro_x_0;
940                    )?
941                    let mut __hydro_acc_once = __hydro_acc_once;
942                    let mut __hydro_acc_twice = __hydro_acc_twice;
943                    { let $tacc = &mut __hydro_acc_once; let $titem = __hydro_x_0; let _ = { $target_body }; }
944                    { let $tacc = &mut __hydro_acc_twice; let $titem = __hydro_x_1; let _ = { $target_body }; }
945                    { let $tacc = &mut __hydro_acc_twice; let $titem = __hydro_x_2; let _ = { $target_body }; }
946                    $(proof { $($proof_body)* })?
947                    assert(__hydro_acc_once == __hydro_acc_twice);
948                }
949            }
950        };
951
952        $crate::properties::VerusIdempotentProof::new()
953    }};
954    (
955        $($rest:tt)*
956    ) => {{
957        ::core::compile_error!(
958            "verus_proof_idempotent_fold! must be used as a property annotation inside `q!(...)` on a `|acc, item| ...` closure, e.g. `idempotent = verus_proof_idempotent_fold!(acc = u32, item = u32)`"
959        );
960        $crate::properties::VerusIdempotentProof::new()
961    }};
962}
963
964#[macro_export]
965/// Fulfills an `idempotent = ...` proof parameter for a **reduce closure** (shape
966/// `|acc, item|` with `acc: &mut T` and `item: T`) with a **Verus-checked proof of
967/// idempotence**.
968///
969/// `reduce` seeds its accumulator with the first element, so in addition to the
970/// [`verus_proof_idempotent_fold!`] obligation (applying `x` twice in a row equals
971/// applying it once, from any accumulator), this macro also proves the **seed**
972/// obligation: if the first element is duplicated, applying the closure to an
973/// accumulator seeded with `x` and the item `x` must leave the accumulator equal to `x`.
974/// The fold obligation alone does not imply this; for example,
975/// `|acc, x| *acc = max(*acc, x + 1)` satisfies it, but reducing `[a, a]` yields `a + 1`
976/// instead of `a`.
977///
978/// ```rust,ignore
979/// stream.reduce(q!(
980///     |curr, new| { if new > *curr { *curr = new; } },
981///     idempotent = verus_proof_idempotent_reduce!(item = u32)
982/// ));
983/// ```
984///
985/// Read-only captures are declared in a `captures = |...|` clause. An optional
986/// `proof = |state, x| { ... }` script is inserted into both obligations (for the seed
987/// obligation, `state` is bound to the item itself).
988///
989/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
990/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
991/// macro just produces a [`VerusIdempotentProof`] marker.
992macro_rules! __verus_proof_idempotent_reduce__ {
993    (
994        item = $itemty:ty
995        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
996        $(, proof = |$pstate:ident, $px:ident| { $($proof_body:tt)* })?
997        , __target = { $(move)? |$tacc:ident $(: $taccty:ty)?, $titem:ident $(: $titemty:ty)?| $target_body:expr }
998        , __captures = [$($fv:ident),* $(,)?] $(,)?
999    ) => {{
1000        /// Checks that every free variable captured by the closure is declared (with its
1001        /// type) in the `captures = |...|` clause: within this function, the *only* names
1002        /// in scope are the declared captures and the closure parameters, so an
1003        /// undeclared capture fails to resolve.
1004        #[allow(unused, reason = "only checks name resolution")]
1005        fn __hydro_verus_captures_declared($($($cap: $capty),*)?) {
1006            $(let $fv = &$fv;)*
1007        }
1008
1009        #[cfg(verus_keep_ghost)]
1010        const _: () = {
1011            #[allow(unused_imports)]
1012            use ::vstd::prelude::*;
1013
1014            ::vstd::prelude::verus! {
1015                /// Idempotence obligation, generated by `verus_proof_idempotent_reduce!`:
1016                /// applying the closure body with `x` twice in a row must yield the same
1017                /// accumulator as applying it once, from any equal starting accumulators,
1018                /// for all items and capture values. Verifying this also proves the body
1019                /// panic-free.
1020                fn __hydro_verus_idempotent(
1021                    $($($cap: $capty,)*)?
1022                    __hydro_acc_once: $itemty,
1023                    __hydro_acc_twice: $itemty,
1024                    __hydro_x_0: $itemty,
1025                    __hydro_x_1: $itemty,
1026                    __hydro_x_2: $itemty,
1027                )
1028                    requires
1029                        __hydro_acc_once == __hydro_acc_twice,
1030                        __hydro_x_0 == __hydro_x_1,
1031                        __hydro_x_0 == __hydro_x_2,
1032                {
1033                    $(
1034                        let ghost $pstate = __hydro_acc_once;
1035                        let ghost $px = __hydro_x_0;
1036                    )?
1037                    let mut __hydro_acc_once = __hydro_acc_once;
1038                    let mut __hydro_acc_twice = __hydro_acc_twice;
1039                    { let $tacc = &mut __hydro_acc_once; let $titem = __hydro_x_0; let _ = { $target_body }; }
1040                    { let $tacc = &mut __hydro_acc_twice; let $titem = __hydro_x_1; let _ = { $target_body }; }
1041                    { let $tacc = &mut __hydro_acc_twice; let $titem = __hydro_x_2; let _ = { $target_body }; }
1042                    $(proof { $($proof_body)* })?
1043                    assert(__hydro_acc_once == __hydro_acc_twice);
1044                }
1045
1046                /// Seed obligation, generated by `verus_proof_idempotent_reduce!`: when
1047                /// the first element `x` is duplicated, the accumulator is seeded with `x`
1048                /// and then combined with `x`, which must leave it equal to `x`.
1049                fn __hydro_verus_idempotent_seed(
1050                    $($($cap: $capty,)*)?
1051                    __hydro_x_0: $itemty,
1052                    __hydro_x_1: $itemty,
1053                )
1054                    requires
1055                        __hydro_x_0 == __hydro_x_1,
1056                {
1057                    let ghost __hydro_seed = __hydro_x_0;
1058                    $(
1059                        let ghost $pstate = __hydro_x_0;
1060                        let ghost $px = __hydro_x_0;
1061                    )?
1062                    let mut __hydro_acc = __hydro_x_0;
1063                    { let $tacc = &mut __hydro_acc; let $titem = __hydro_x_1; let _ = { $target_body }; }
1064                    $(proof { $($proof_body)* })?
1065                    assert(__hydro_acc == __hydro_seed);
1066                }
1067            }
1068        };
1069
1070        $crate::properties::VerusIdempotentProof::new()
1071    }};
1072    (
1073        $($rest:tt)*
1074    ) => {{
1075        ::core::compile_error!(
1076            "verus_proof_idempotent_reduce! must be used as a property annotation inside `q!(...)` on a `|acc, item| ...` closure, e.g. `idempotent = verus_proof_idempotent_reduce!(item = u32)`"
1077        );
1078        $crate::properties::VerusIdempotentProof::new()
1079    }};
1080}
1081
1082#[macro_export]
1083/// Fulfills an `idempotent = ...` proof parameter for a **map-like closure** (shape
1084/// `|item| -> out`, e.g. for `map`, `filter_map`, or `flat_map_*`) that may mutate a
1085/// captured singleton reference (from [`Singleton::by_mut`]), with a **Verus-checked
1086/// proof of idempotence**.
1087///
1088/// **What idempotence means for a map closure:** processing an item twice in a row,
1089/// starting from the same captured state, must (1) leave the captured state in the same
1090/// final value as processing it once, *and* (2) produce the same output both times as
1091/// processing it once. Because the output stream also has at-least-once semantics, a
1092/// retried element may re-emit its output, but must not emit a *different* one: a closure
1093/// that reports whether an element is new (e.g. `true` then `false`) is **not**
1094/// idempotent even if its state update is.
1095///
1096/// The mutated state is the mutable capture, declared (with the type behind the
1097/// reference) in the required `captures_mut = |state: S|` clause; additional read-only
1098/// captures can be declared in a `captures = |...|` clause. The macro checks at compile
1099/// time that every capture is declared. The `item = ...` type must be written exactly as
1100/// the closure receives it.
1101///
1102/// An optional `proof = |state, x| { ... }` clause supplies a proof *script* to help the
1103/// SMT solver, with ghost bindings for the initial captured state and the item.
1104///
1105/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
1106/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
1107/// macro just produces a [`VerusIdempotentProof`] marker.
1108///
1109/// # Example
1110/// ```rust,ignore
1111/// let max_mut = max_seen.by_mut();
1112/// stream.map(q!(
1113///     |x| {
1114///         if x > *max_mut { *max_mut = x; }
1115///         x // outputting `x > *max_mut` (is this new?) would NOT be idempotent!
1116///     },
1117///     idempotent = verus_proof_idempotent_map!(
1118///         item = u32,
1119///         captures_mut = |max_mut: u32|
1120///     )
1121/// ));
1122/// ```
1123///
1124/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
1125macro_rules! __verus_proof_idempotent_map__ {
1126    (
1127        item = $itemty:ty
1128        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
1129        , captures_mut = |$mcap:ident : $mcapty:ty $(,)?|
1130        $(, proof = |$pstate:ident, $px:ident| { $($proof_body:tt)* })?
1131        , __target = { $(move)? |$titem:ident $(: $titemty:ty)?| $target_body:expr }
1132        , __captures = [$($fv:ident),* $(,)?] $(,)?
1133    ) => {{
1134        /// Checks that every free variable captured by the closure is declared (with its
1135        /// type) in the `captures = |...|` or `captures_mut = |...|` clauses: within this
1136        /// function, the *only* names in scope are the declared captures, so an
1137        /// undeclared capture fails to resolve.
1138        #[allow(unused, reason = "only checks name resolution")]
1139        fn __hydro_verus_captures_declared($($($cap: $capty,)*)? $mcap: $mcapty) {
1140            $(let $fv = &$fv;)*
1141        }
1142
1143        #[cfg(verus_keep_ghost)]
1144        const _: () = {
1145            #[allow(unused_imports)]
1146            use ::vstd::prelude::*;
1147
1148            ::vstd::prelude::verus! {
1149                /// Idempotence obligation, generated by `verus_proof_idempotent_map!`:
1150                /// from any equal starting captured states, processing `x` twice in a
1151                /// row must yield the same final captured state as processing it once,
1152                /// and both outputs of the repeated run must equal the output of the
1153                /// single run. Verifying this also proves the body panic-free.
1154                fn __hydro_verus_idempotent(
1155                    $($($cap: $capty,)*)?
1156                    __hydro_state_once: $mcapty,
1157                    __hydro_state_twice: $mcapty,
1158                    __hydro_x_0: $itemty,
1159                    __hydro_x_1: $itemty,
1160                    __hydro_x_2: $itemty,
1161                )
1162                    requires
1163                        __hydro_state_once == __hydro_state_twice,
1164                        __hydro_x_0 == __hydro_x_1,
1165                        __hydro_x_0 == __hydro_x_2,
1166                {
1167                    $(
1168                        let ghost $pstate = __hydro_state_once;
1169                        let ghost $px = __hydro_x_0;
1170                    )?
1171                    let mut __hydro_state_once = __hydro_state_once;
1172                    let mut __hydro_state_twice = __hydro_state_twice;
1173                    let __hydro_out_once = { let $mcap = &mut __hydro_state_once; let $titem = __hydro_x_0; $target_body };
1174                    let __hydro_out_twice_1 = { let $mcap = &mut __hydro_state_twice; let $titem = __hydro_x_1; $target_body };
1175                    let __hydro_out_twice_2 = { let $mcap = &mut __hydro_state_twice; let $titem = __hydro_x_2; $target_body };
1176                    $(proof { $($proof_body)* })?
1177                    assert(__hydro_state_once == __hydro_state_twice);
1178                    assert(__hydro_out_twice_1 == __hydro_out_once && __hydro_out_twice_2 == __hydro_out_once);
1179                }
1180            }
1181        };
1182
1183        $crate::properties::VerusIdempotentProof::new()
1184    }};
1185    (
1186        $($rest:tt)*
1187    ) => {{
1188        ::core::compile_error!(
1189            "verus_proof_idempotent_map! must be used as a property annotation inside `q!(...)` on a `|item| ...` closure with exactly one `captures_mut` entry, e.g. `idempotent = verus_proof_idempotent_map!(item = u32, captures_mut = |state: u32|)`"
1190        );
1191        $crate::properties::VerusIdempotentProof::new()
1192    }};
1193}
1194
1195#[macro_export]
1196/// Fulfills an `idempotent = ...` proof parameter for a **predicate** (shape
1197/// `|item| -> bool` where `item` is received by reference, e.g. for `filter` or
1198/// `partition`) that may mutate a captured singleton reference (from
1199/// [`Singleton::by_mut`]), with a **Verus-checked proof of idempotence**.
1200///
1201/// **What idempotence means for a predicate:** processing an item twice in a row,
1202/// starting from the same captured state, must (1) leave the captured state in the same
1203/// final value as processing it once, *and* (2) make the same decision both times as
1204/// processing it once. Condition (2) is required for `partition`, where an element
1205/// rejected on retry lands in the *other* output. (For `filter` alone, dropping a retried
1206/// element that was retained the first time would be harmless; this macro
1207/// conservatively rejects it as well.)
1208///
1209/// The mutated state is the mutable capture, declared (with the type behind the
1210/// reference) in the required `captures_mut = |state: S|` clause; additional read-only
1211/// captures can be declared in a `captures = |...|` clause. The macro checks at compile
1212/// time that every capture is declared. The `item = ...` type must be written exactly as
1213/// the closure receives it (a reference like `&u32`).
1214///
1215/// An optional `proof = |state, x| { ... }` clause supplies a proof *script* to help the
1216/// SMT solver, with ghost bindings for the initial captured state and the item.
1217///
1218/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
1219/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
1220/// macro just produces a [`VerusIdempotentProof`] marker.
1221///
1222/// # Example
1223/// ```rust,ignore
1224/// let max_mut = max_seen.by_mut();
1225/// stream.filter(q!(
1226///     |x| {
1227///         if *x > *max_mut { *max_mut = *x; }
1228///         *x > 1 // the decision must not depend on whether `x` was seen before!
1229///     },
1230///     idempotent = verus_proof_idempotent_filter!(
1231///         item = &u32,
1232///         captures_mut = |max_mut: u32|
1233///     )
1234/// ));
1235/// ```
1236///
1237/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
1238macro_rules! __verus_proof_idempotent_filter__ {
1239    (
1240        item = $itemty:ty
1241        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
1242        , captures_mut = |$mcap:ident : $mcapty:ty $(,)?|
1243        $(, proof = |$pstate:ident, $px:ident| { $($proof_body:tt)* })?
1244        , __target = { $(move)? |$titem:ident $(: $titemty:ty)?| $target_body:expr }
1245        , __captures = [$($fv:ident),* $(,)?] $(,)?
1246    ) => {{
1247        /// Checks that every free variable captured by the closure is declared (with its
1248        /// type) in the `captures = |...|` or `captures_mut = |...|` clauses: within this
1249        /// function, the *only* names in scope are the declared captures, so an
1250        /// undeclared capture fails to resolve.
1251        #[allow(unused, reason = "only checks name resolution")]
1252        fn __hydro_verus_captures_declared($($($cap: $capty,)*)? $mcap: $mcapty) {
1253            $(let $fv = &$fv;)*
1254        }
1255
1256        #[cfg(verus_keep_ghost)]
1257        const _: () = {
1258            #[allow(unused_imports)]
1259            use ::vstd::prelude::*;
1260
1261            ::vstd::prelude::verus! {
1262                /// Idempotence obligation, generated by `verus_proof_idempotent_filter!`:
1263                /// from any equal starting captured states, processing `x` twice in a
1264                /// row must yield the same final captured state as processing it once,
1265                /// and both decisions of the repeated run must equal the decision of the
1266                /// single run. Verifying this also proves the body panic-free.
1267                fn __hydro_verus_idempotent(
1268                    $($($cap: $capty,)*)?
1269                    __hydro_state_once: $mcapty,
1270                    __hydro_state_twice: $mcapty,
1271                    __hydro_x_0: $itemty,
1272                    __hydro_x_1: $itemty,
1273                    __hydro_x_2: $itemty,
1274                )
1275                    requires
1276                        __hydro_state_once == __hydro_state_twice,
1277                        __hydro_x_0 == __hydro_x_1,
1278                        __hydro_x_0 == __hydro_x_2,
1279                {
1280                    $(
1281                        let ghost $pstate = __hydro_state_once;
1282                        let ghost $px = __hydro_x_0;
1283                    )?
1284                    let mut __hydro_state_once = __hydro_state_once;
1285                    let mut __hydro_state_twice = __hydro_state_twice;
1286                    let __hydro_keep_once: bool = { let $mcap = &mut __hydro_state_once; let $titem = __hydro_x_0; $target_body };
1287                    let __hydro_keep_twice_1: bool = { let $mcap = &mut __hydro_state_twice; let $titem = __hydro_x_1; $target_body };
1288                    let __hydro_keep_twice_2: bool = { let $mcap = &mut __hydro_state_twice; let $titem = __hydro_x_2; $target_body };
1289                    $(proof { $($proof_body)* })?
1290                    assert(__hydro_state_once == __hydro_state_twice);
1291                    assert(__hydro_keep_twice_1 == __hydro_keep_once && __hydro_keep_twice_2 == __hydro_keep_once);
1292                }
1293            }
1294        };
1295
1296        $crate::properties::VerusIdempotentProof::new()
1297    }};
1298    (
1299        $($rest:tt)*
1300    ) => {{
1301        ::core::compile_error!(
1302            "verus_proof_idempotent_filter! must be used as a property annotation inside `q!(...)` on a `|item| -> bool` closure with exactly one `captures_mut` entry, e.g. `idempotent = verus_proof_idempotent_filter!(item = &u32, captures_mut = |state: u32|)`"
1303        );
1304        $crate::properties::VerusIdempotentProof::new()
1305    }};
1306}
1307
1308#[macro_export]
1309/// Fulfills an `idempotent = ...` proof parameter for a **unit-returning, effectful
1310/// closure** (shape `|item| -> ()`, e.g. for `for_each` or `inspect`) that mutates a
1311/// captured singleton reference (from [`Singleton::by_mut`]), with a **Verus-checked
1312/// proof of idempotence** of the captured-state update.
1313///
1314/// **What idempotence means for an effectful closure:** processing an item twice in a
1315/// row, starting from the same captured state, must leave the captured state in the same
1316/// final value as processing it once. Because the closure returns `()` (enforced by this
1317/// macro; use [`verus_proof_idempotent_map!`] or [`verus_proof_idempotent_filter!`] for
1318/// closures whose return value is observable), the state is the only observable effect.
1319///
1320/// The mutated state is the mutable capture, declared (with the type behind the
1321/// reference) in the required `captures_mut = |state: S|` clause; additional read-only
1322/// captures can be declared in a `captures = |...|` clause. The macro checks at compile
1323/// time that every capture is declared. The `item = ...` type must be written exactly as
1324/// the closure receives it (e.g. `&u32` for `inspect`).
1325///
1326/// An optional `proof = |state, x| { ... }` clause supplies a proof *script* to help the
1327/// SMT solver, with ghost bindings for the initial captured state and the item.
1328///
1329/// The proof is gated on `cfg(verus_keep_ghost)`, so it only exists when the crate is
1330/// compiled by the Verus driver (`cargo verus verify`). Under normal compilation the
1331/// macro just produces a [`VerusIdempotentProof`] marker.
1332///
1333/// # Example
1334/// ```rust,ignore
1335/// let flags_mut = flags.by_mut();
1336/// stream.for_each(q!(
1337///     |x| { *flags_mut |= x; },
1338///     idempotent = verus_proof_idempotent_effect!(
1339///         item = u32,
1340///         captures_mut = |flags_mut: u32|,
1341///         proof = |s, x| { assert(((s | x) | x) == (s | x)) by (bit_vector); }
1342///     )
1343/// ));
1344/// ```
1345///
1346/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
1347macro_rules! __verus_proof_idempotent_effect__ {
1348    (
1349        item = $itemty:ty
1350        $(, captures = |$($cap:ident : $capty:ty),* $(,)?|)?
1351        , captures_mut = |$mcap:ident : $mcapty:ty $(,)?|
1352        $(, proof = |$pstate:ident, $px:ident| { $($proof_body:tt)* })?
1353        , __target = { $(move)? |$titem:ident $(: $titemty:ty)?| $target_body:expr }
1354        , __captures = [$($fv:ident),* $(,)?] $(,)?
1355    ) => {{
1356        /// Checks that every free variable captured by the closure is declared (with its
1357        /// type) in the `captures = |...|` or `captures_mut = |...|` clauses: within this
1358        /// function, the *only* names in scope are the declared captures, so an
1359        /// undeclared capture fails to resolve.
1360        #[allow(unused, reason = "only checks name resolution")]
1361        fn __hydro_verus_captures_declared($($($cap: $capty,)*)? $mcap: $mcapty) {
1362            $(let $fv = &$fv;)*
1363        }
1364
1365        #[cfg(verus_keep_ghost)]
1366        const _: () = {
1367            #[allow(unused_imports)]
1368            use ::vstd::prelude::*;
1369
1370            ::vstd::prelude::verus! {
1371                /// Idempotence obligation, generated by `verus_proof_idempotent_effect!`:
1372                /// applying the closure body with `x` twice in a row must yield the same
1373                /// captured state as applying it once, from any equal starting states.
1374                /// The closure must return `()`, so the state is the only observable
1375                /// effect. Verifying this also proves the body panic-free.
1376                fn __hydro_verus_idempotent(
1377                    $($($cap: $capty,)*)?
1378                    __hydro_state_once: $mcapty,
1379                    __hydro_state_twice: $mcapty,
1380                    __hydro_x_0: $itemty,
1381                    __hydro_x_1: $itemty,
1382                    __hydro_x_2: $itemty,
1383                )
1384                    requires
1385                        __hydro_state_once == __hydro_state_twice,
1386                        __hydro_x_0 == __hydro_x_1,
1387                        __hydro_x_0 == __hydro_x_2,
1388                {
1389                    $(
1390                        let ghost $pstate = __hydro_state_once;
1391                        let ghost $px = __hydro_x_0;
1392                    )?
1393                    let mut __hydro_state_once = __hydro_state_once;
1394                    let mut __hydro_state_twice = __hydro_state_twice;
1395                    { let $mcap = &mut __hydro_state_once; let $titem = __hydro_x_0; let __hydro_out: () = { $target_body }; }
1396                    { let $mcap = &mut __hydro_state_twice; let $titem = __hydro_x_1; let __hydro_out: () = { $target_body }; }
1397                    { let $mcap = &mut __hydro_state_twice; let $titem = __hydro_x_2; let __hydro_out: () = { $target_body }; }
1398                    $(proof { $($proof_body)* })?
1399                    assert(__hydro_state_once == __hydro_state_twice);
1400                }
1401            }
1402        };
1403
1404        $crate::properties::VerusIdempotentProof::new()
1405    }};
1406    (
1407        $($rest:tt)*
1408    ) => {{
1409        ::core::compile_error!(
1410            "verus_proof_idempotent_effect! must be used as a property annotation inside `q!(...)` on a `|item| -> ()` closure with exactly one `captures_mut` entry, e.g. `idempotent = verus_proof_idempotent_effect!(item = u32, captures_mut = |state: u32|)`"
1411        );
1412        $crate::properties::VerusIdempotentProof::new()
1413    }};
1414}
1415
1416/// Marks that the property is not proved.
1417pub enum NotProved {}
1418
1419/// Marks that the property is proven.
1420pub enum Proved {}
1421
1422/// Algebraic properties for an aggregation function of type (T, &mut A) -> ().
1423///
1424/// Commutativity:
1425/// ```rust,ignore
1426/// let mut state = ???;
1427/// f(a, &mut state); f(b, &mut state) // produces same final state as
1428/// f(b, &mut state); f(a, &mut state)
1429/// ```
1430///
1431/// Idempotence:
1432/// ```rust,ignore
1433/// let mut state = ???;
1434/// f(a, &mut state);
1435/// let state1 = *state;
1436/// f(a, &mut state);
1437/// // state1 must be equal to state
1438/// ```
1439///
1440/// For `reduce`, whose accumulator is seeded with the first element, idempotence
1441/// additionally requires that `f(a, &mut a)` leaves the accumulator equal to `a` (the
1442/// first element may itself be duplicated).
1443pub struct AggFuncAlgebra<
1444    T = (),
1445    B: Boundedness = crate::live_collections::boundedness::Unbounded,
1446    Commutative = NotProved,
1447    Idempotent = NotProved,
1448    Monotone = NotProved,
1449    S = OnProcess,
1450>(
1451    Option<Box<dyn CommutativeProof<T, B, S>>>,
1452    Option<Box<dyn IdempotentProof>>,
1453    Option<Box<dyn MonotoneProof>>,
1454    PhantomData<(Commutative, Idempotent, Monotone)>,
1455);
1456
1457impl<T, B: Boundedness, C, I, M, S> AggFuncAlgebra<T, B, C, I, M, S> {
1458    /// Marks the function as being commutative, with the given proof mechanism.
1459    pub fn commutative(
1460        self,
1461        proof: impl CommutativeProof<T, B, S> + 'static,
1462    ) -> AggFuncAlgebra<T, B, Proved, I, M, S> {
1463        AggFuncAlgebra(Some(Box::new(proof)), self.1, self.2, PhantomData)
1464    }
1465
1466    /// Marks the function as being idempotent, with the given proof mechanism.
1467    pub fn idempotent(
1468        self,
1469        proof: impl IdempotentProof + 'static,
1470    ) -> AggFuncAlgebra<T, B, C, Proved, M, S> {
1471        AggFuncAlgebra(self.0, Some(Box::new(proof)), self.2, PhantomData)
1472    }
1473
1474    /// Marks the function as being monotone, with the given proof mechanism.
1475    pub fn monotone(
1476        self,
1477        proof: impl MonotoneProof + 'static,
1478    ) -> AggFuncAlgebra<T, B, C, I, Proved, S> {
1479        AggFuncAlgebra(self.0, self.1, Some(Box::new(proof)), PhantomData)
1480    }
1481
1482    /// Registers the expression with the underlying proof mechanisms, and takes the
1483    /// simulator ordering hook attached to the commutativity proof, if any.
1484    pub(crate) fn register_proof(
1485        self,
1486        expr: &syn::Expr,
1487    ) -> Option<OrderingHook<T, B, ExactlyOnce, S>> {
1488        let mut hook = None;
1489        if let Some(mut comm_proof) = self.0 {
1490            comm_proof.register_proof(expr);
1491            hook = comm_proof.take_hook();
1492        }
1493
1494        if let Some(idem_proof) = self.1 {
1495            idem_proof.register_proof(expr);
1496        }
1497
1498        if let Some(monotone_proof) = self.2 {
1499            monotone_proof.register_proof(expr);
1500        }
1501
1502        hook
1503    }
1504}
1505
1506impl<T, B: Boundedness, C, I, M, S> Property for AggFuncAlgebra<T, B, C, I, M, S> {
1507    type Root = AggFuncAlgebra<T, B, NotProved, NotProved, NotProved, S>;
1508
1509    fn make_root(_target: &mut Option<Self>) -> Self::Root {
1510        AggFuncAlgebra(None, None, None, PhantomData)
1511    }
1512}
1513
1514/// Algebraic properties for a singleton map function of type T -> U.
1515///
1516/// Order-preserving means that if the input grows monotonically, the output also grows monotonically.
1517pub struct SingletonMapFuncAlgebra<
1518    T = (),
1519    B: Boundedness = crate::live_collections::boundedness::Unbounded,
1520    OrderPreserving = NotProved,
1521    Commutative = NotProved,
1522    Idempotent = NotProved,
1523    S = OnProcess,
1524>(
1525    Option<Box<dyn OrderPreservingProof>>,
1526    Option<Box<dyn CommutativeProof<T, B, S>>>,
1527    Option<Box<dyn IdempotentProof>>,
1528    PhantomData<(OrderPreserving, Commutative, Idempotent)>,
1529);
1530
1531impl<T, B: Boundedness, O, C, I, S> SingletonMapFuncAlgebra<T, B, O, C, I, S> {
1532    /// Marks the function as being order-preserving, with the given proof mechanism.
1533    pub fn order_preserving(
1534        self,
1535        proof: impl OrderPreservingProof + 'static,
1536    ) -> SingletonMapFuncAlgebra<T, B, Proved, C, I, S> {
1537        SingletonMapFuncAlgebra(Some(Box::new(proof)), self.1, self.2, PhantomData)
1538    }
1539
1540    /// Marks the function as being commutative, with the given proof mechanism.
1541    pub fn commutative(
1542        self,
1543        proof: impl CommutativeProof<T, B, S> + 'static,
1544    ) -> SingletonMapFuncAlgebra<T, B, O, Proved, I, S> {
1545        SingletonMapFuncAlgebra(self.0, Some(Box::new(proof)), self.2, PhantomData)
1546    }
1547
1548    /// Marks the function as being idempotent, with the given proof mechanism.
1549    pub fn idempotent(
1550        self,
1551        proof: impl IdempotentProof + 'static,
1552    ) -> SingletonMapFuncAlgebra<T, B, O, C, Proved, S> {
1553        SingletonMapFuncAlgebra(self.0, self.1, Some(Box::new(proof)), PhantomData)
1554    }
1555
1556    /// Registers the expression with the underlying proof mechanisms, and takes the
1557    /// simulator ordering hook attached to the commutativity proof, if any.
1558    pub(crate) fn register_proof(
1559        self,
1560        expr: &syn::Expr,
1561    ) -> Option<OrderingHook<T, B, ExactlyOnce, S>> {
1562        if let Some(proof) = self.0 {
1563            proof.register_proof(expr);
1564        }
1565        self.1.and_then(|mut proof| {
1566            proof.register_proof(expr);
1567            proof.take_hook()
1568        })
1569    }
1570}
1571
1572impl<T, B: Boundedness, O, C, I, S> Property for SingletonMapFuncAlgebra<T, B, O, C, I, S> {
1573    type Root = SingletonMapFuncAlgebra<T, B, NotProved, NotProved, NotProved, S>;
1574
1575    fn make_root(_target: &mut Option<Self>) -> Self::Root {
1576        SingletonMapFuncAlgebra(None, None, None, PhantomData)
1577    }
1578}
1579
1580/// Algebraic properties for a stream map function of type T -> U.
1581pub struct StreamMapFuncAlgebra<
1582    T = (),
1583    B: Boundedness = crate::live_collections::boundedness::Unbounded,
1584    Commutative = NotProved,
1585    Idempotent = NotProved,
1586    S = OnProcess,
1587>(
1588    Option<Box<dyn CommutativeProof<T, B, S>>>,
1589    Option<Box<dyn IdempotentProof>>,
1590    PhantomData<(Commutative, Idempotent)>,
1591);
1592
1593impl<T, B: Boundedness, C, I, S> StreamMapFuncAlgebra<T, B, C, I, S> {
1594    /// Marks the function as being commutative, with the given proof mechanism.
1595    pub fn commutative(
1596        self,
1597        proof: impl CommutativeProof<T, B, S> + 'static,
1598    ) -> StreamMapFuncAlgebra<T, B, Proved, I, S> {
1599        StreamMapFuncAlgebra(Some(Box::new(proof)), self.1, PhantomData)
1600    }
1601
1602    /// Marks the function as being idempotent, with the given proof mechanism.
1603    pub fn idempotent(
1604        self,
1605        proof: impl IdempotentProof + 'static,
1606    ) -> StreamMapFuncAlgebra<T, B, C, Proved, S> {
1607        StreamMapFuncAlgebra(self.0, Some(Box::new(proof)), PhantomData)
1608    }
1609
1610    /// Registers the expression with the underlying proof mechanisms, and takes the
1611    /// simulator ordering hook attached to the commutativity proof, if any.
1612    pub(crate) fn register_proof(
1613        self,
1614        expr: &syn::Expr,
1615    ) -> Option<OrderingHook<T, B, ExactlyOnce, S>> {
1616        let hook = self.0.and_then(|mut proof| {
1617            proof.register_proof(expr);
1618            proof.take_hook()
1619        });
1620        if let Some(proof) = self.1 {
1621            proof.register_proof(expr);
1622        }
1623        hook
1624    }
1625}
1626
1627impl<T, B: Boundedness, C, I, S> Property for StreamMapFuncAlgebra<T, B, C, I, S> {
1628    type Root = StreamMapFuncAlgebra<T, B, NotProved, NotProved, S>;
1629
1630    fn make_root(_target: &mut Option<Self>) -> Self::Root {
1631        StreamMapFuncAlgebra(None, None, PhantomData)
1632    }
1633}
1634
1635/// Marker trait identifying that the commutativity property is valid for the given stream ordering.
1636///
1637/// **Definition (aggregations, `|acc: &mut A, item: T|`):** for any accumulator value
1638/// and any two items `x`, `y`, applying the closure with `x` then `y` must produce the
1639/// same final accumulator as applying it with `y` then `x`. This makes the final
1640/// aggregate independent of the (non-deterministic) arrival order; note that
1641/// *intermediate* accumulator values may still differ and must not be observed without
1642/// a non-determinism annotation.
1643#[diagnostic::on_unimplemented(
1644    message = "because the input stream has ordering `{O}`, the closure must demonstrate commutativity",
1645    label = "required for this call",
1646    note = "prove it with a `commutative = manual_proof!(/** why the order does not matter */)` annotation on the closure",
1647    note = "to intentionally process the stream by observing a non-deterministic (shuffled) order of elements, use `.assume_ordering`; this introduces non-determinism, so avoid it unless necessary"
1648)]
1649#[sealed::sealed]
1650pub trait ValidCommutativityFor<O: Ordering> {}
1651#[sealed::sealed]
1652impl ValidCommutativityFor<TotalOrder> for NotProved {}
1653#[sealed::sealed]
1654impl<O: Ordering> ValidCommutativityFor<O> for Proved {}
1655
1656/// Marker trait identifying that the idempotence property is valid for the given stream ordering.
1657///
1658/// **Definition (aggregations, `|acc: &mut A, item: T|`):** for any accumulator value
1659/// and any item `x`, applying the closure with `x` twice in a row must produce the same
1660/// final accumulator as applying it once. For `reduce`, whose accumulator is seeded with
1661/// the first element, applying the closure to an accumulator equal to `x` with the item
1662/// `x` must also leave the accumulator equal to `x`. On unordered streams, combined with
1663/// commutativity, this makes the final aggregate independent of duplicates at any
1664/// position. **Definition (`for_each`, `|item: T|`):** processing an item twice in a row
1665/// must leave the mutably-captured state in the same final value as processing it once.
1666#[diagnostic::on_unimplemented(
1667    message = "because the input stream has retries `{R}`, the closure must demonstrate idempotence",
1668    label = "required for this call",
1669    note = "prove it with an `idempotent = manual_proof!(/** why a repeat does not matter */)` annotation on the closure",
1670    note = "to intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`; this introduces non-determinism, so avoid it unless necessary"
1671)]
1672#[sealed::sealed]
1673pub trait ValidIdempotenceFor<R: Retries> {}
1674#[sealed::sealed]
1675impl ValidIdempotenceFor<ExactlyOnce> for NotProved {}
1676#[sealed::sealed]
1677impl<R: Retries> ValidIdempotenceFor<R> for Proved {}
1678
1679/// Marker trait identifying that the commutativity property is valid for the given stream ordering.
1680///
1681/// A proof is required when the stream is unordered **and** the closure mutably captures
1682/// state (`WAS_MUT`). **Definition (owned-item closures, `|item: T| -> Out`, e.g. `map`
1683/// / `for_each`):** processing any two items in either order must (1) leave the
1684/// mutably-captured state (e.g. [`Singleton::by_mut`] references) in the same final
1685/// value, *and* (2) produce the same **multiset of return values**. Condition (2) is
1686/// required whenever the return value is observable (as in `map`): a closure that
1687/// emits, say, a running total is **not** commutative even if its state update is. For
1688/// `()`-returning closures (as in `for_each`), condition (2) is trivial.
1689///
1690/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
1691#[sealed::sealed]
1692#[diagnostic::on_unimplemented(
1693    message = "because the input stream has ordering `{O}`, the closure must demonstrate commutativity",
1694    label = "required for this call",
1695    note = "prove it with a `commutative = manual_proof!(/** why the order does not matter */)` annotation on the closure",
1696    note = "to intentionally process the stream by observing a non-deterministic (shuffled) order of elements, use `.assume_ordering`; this introduces non-determinism, so avoid it unless necessary"
1697)]
1698pub trait ValidMutCommutativityFor<F: FnMut(In) -> Out, In, Out, O: Ordering, const WAS_MUT: bool> {}
1699#[sealed::sealed]
1700impl<In, Out, F: FnMut(In) -> Out> ValidMutCommutativityFor<F, In, Out, TotalOrder, true>
1701    for NotProved
1702{
1703}
1704#[sealed::sealed]
1705impl<In, Out, F: Fn(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, false>
1706    for NotProved
1707{
1708}
1709#[sealed::sealed]
1710impl<In, Out, F: FnMut(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, true>
1711    for Proved
1712{
1713}
1714#[sealed::sealed]
1715impl<In, Out, F: Fn(In) -> Out, O: Ordering> ValidMutCommutativityFor<F, In, Out, O, false>
1716    for Proved
1717{
1718}
1719
1720/// Marker trait identifying that the idempotence property is valid for the given stream ordering.
1721///
1722/// A proof is required when the stream has retries (`AtLeastOnce`) **and** the closure
1723/// mutably captures state (`WAS_MUT`). **Definition (owned-item closures,
1724/// `|item: T| -> Out`, e.g. `map` / `filter_map` / `flat_map_*`):** processing an item
1725/// twice in a row must (1) leave the mutably-captured state (e.g. [`Singleton::by_mut`]
1726/// references) in the same final value as processing it once, *and* (2) return the same
1727/// value both times as when processing it once. Condition (2) is required because the
1728/// output stream inherits the retries: a retried element may re-emit its output, but must
1729/// not emit a *different* one (e.g. a closure that reports whether an element is new is
1730/// **not** idempotent even if its state update is).
1731///
1732/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
1733#[diagnostic::on_unimplemented(
1734    message = "because the input stream has retries `{R}`, the closure must demonstrate idempotence",
1735    label = "required for this call",
1736    note = "prove it with an `idempotent = manual_proof!(/** why a repeat does not matter */)` annotation on the closure",
1737    note = "to intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`; this introduces non-determinism, so avoid it unless necessary"
1738)]
1739#[sealed::sealed]
1740pub trait ValidMutIdempotenceFor<F: FnMut(In) -> Out, In, Out, R: Retries, const WAS_MUT: bool> {}
1741#[sealed::sealed]
1742impl<In, Out, F: FnMut(In) -> Out> ValidMutIdempotenceFor<F, In, Out, ExactlyOnce, true>
1743    for NotProved
1744{
1745}
1746#[sealed::sealed]
1747impl<In, Out, F: Fn(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, false>
1748    for NotProved
1749{
1750}
1751#[sealed::sealed]
1752impl<In, Out, F: FnMut(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, true>
1753    for Proved
1754{
1755}
1756#[sealed::sealed]
1757impl<In, Out, F: Fn(In) -> Out, R: Retries> ValidMutIdempotenceFor<F, In, Out, R, false>
1758    for Proved
1759{
1760}
1761
1762/// Marker trait for commutativity of closures that borrow their input (`FnMut(&In) -> Out`).
1763///
1764/// A proof is required when the stream is unordered **and** the closure mutably captures
1765/// state (`WAS_MUT`). **Definition (borrowing closures, `|item: &T| -> Out`, e.g.
1766/// `filter` / `inspect`):** processing any two items in either order must (1) leave the
1767/// mutably-captured state (e.g. [`Singleton::by_mut`] references) in the same final
1768/// value, *and* (2) keep the operator's observable output identical as a multiset. For
1769/// `filter`, the outputs are the **retained elements**, so the predicate's decisions
1770/// must not depend on the processing order: a stateful predicate like a rate limiter is
1771/// **not** commutative — its budget converges either way, but *which* element passes
1772/// depends on the order. For `inspect`, the elements pass through unchanged, so only
1773/// condition (1) applies.
1774///
1775/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
1776#[sealed::sealed]
1777#[diagnostic::on_unimplemented(
1778    message = "because the input stream has ordering `{O}`, the closure must demonstrate commutativity",
1779    label = "required for this call",
1780    note = "prove it with a `commutative = manual_proof!(/** why the order does not matter */)` annotation on the closure",
1781    note = "to intentionally process the stream by observing a non-deterministic (shuffled) order of elements, use `.assume_ordering`; this introduces non-determinism, so avoid it unless necessary"
1782)]
1783pub trait ValidMutBorrowCommutativityFor<
1784    F: FnMut(&In) -> Out,
1785    In: ?Sized,
1786    Out,
1787    O: Ordering,
1788    const WAS_MUT: bool,
1789>
1790{
1791}
1792#[sealed::sealed]
1793impl<In: ?Sized, Out, F: FnMut(&In) -> Out>
1794    ValidMutBorrowCommutativityFor<F, In, Out, TotalOrder, true> for NotProved
1795{
1796}
1797#[sealed::sealed]
1798impl<In: ?Sized, Out, F: Fn(&In) -> Out, O: Ordering>
1799    ValidMutBorrowCommutativityFor<F, In, Out, O, false> for NotProved
1800{
1801}
1802#[sealed::sealed]
1803impl<In: ?Sized, Out, F: FnMut(&In) -> Out, O: Ordering>
1804    ValidMutBorrowCommutativityFor<F, In, Out, O, true> for Proved
1805{
1806}
1807#[sealed::sealed]
1808impl<In: ?Sized, Out, F: Fn(&In) -> Out, O: Ordering>
1809    ValidMutBorrowCommutativityFor<F, In, Out, O, false> for Proved
1810{
1811}
1812
1813/// Marker trait for idempotence of closures that borrow their input (`FnMut(&In) -> Out`).
1814///
1815/// A proof is required when the stream has retries (`AtLeastOnce`) **and** the closure
1816/// mutably captures state (`WAS_MUT`). **Definition (borrowing closures,
1817/// `|item: &T| -> Out`, e.g. `filter` / `partition` / `inspect`):** processing an item
1818/// twice in a row must (1) leave the mutably-captured state (e.g. [`Singleton::by_mut`]
1819/// references) in the same final value as processing it once, *and* (2) keep the
1820/// operator's observable output unchanged. For `filter` and `partition`, the predicate
1821/// must return the same decision both times as when processing the item once (for
1822/// `partition`, an element rejected on retry would appear in the *other* output). For
1823/// `inspect`, the elements pass through unchanged, so only condition (1) applies.
1824///
1825/// [`Singleton::by_mut`]: crate::live_collections::singleton::Singleton::by_mut
1826#[diagnostic::on_unimplemented(
1827    message = "because the input stream has retries `{R}`, the closure must demonstrate idempotence",
1828    label = "required for this call",
1829    note = "prove it with an `idempotent = manual_proof!(/** why a repeat does not matter */)` annotation on the closure",
1830    note = "to intentionally process the stream by observing non-deterministic (randomly duplicated) retries, use `.assume_retries`; this introduces non-determinism, so avoid it unless necessary"
1831)]
1832#[sealed::sealed]
1833pub trait ValidMutBorrowIdempotenceFor<
1834    F: FnMut(&In) -> Out,
1835    In: ?Sized,
1836    Out,
1837    R: Retries,
1838    const WAS_MUT: bool,
1839>
1840{
1841}
1842#[sealed::sealed]
1843impl<In: ?Sized, Out, F: FnMut(&In) -> Out>
1844    ValidMutBorrowIdempotenceFor<F, In, Out, ExactlyOnce, true> for NotProved
1845{
1846}
1847#[sealed::sealed]
1848impl<In: ?Sized, Out, F: Fn(&In) -> Out, R: Retries>
1849    ValidMutBorrowIdempotenceFor<F, In, Out, R, false> for NotProved
1850{
1851}
1852#[sealed::sealed]
1853impl<In: ?Sized, Out, F: FnMut(&In) -> Out, R: Retries>
1854    ValidMutBorrowIdempotenceFor<F, In, Out, R, true> for Proved
1855{
1856}
1857#[sealed::sealed]
1858impl<In: ?Sized, Out, F: Fn(&In) -> Out, R: Retries>
1859    ValidMutBorrowIdempotenceFor<F, In, Out, R, false> for Proved
1860{
1861}
1862
1863/// Marker trait identifying the boundedness of a singleton given a monotonicity property of
1864/// an aggregation on a stream.
1865#[sealed::sealed]
1866pub trait ApplyMonotoneStream<P, B2: SingletonBound> {}
1867
1868#[sealed::sealed]
1869impl<B: Boundedness> ApplyMonotoneStream<NotProved, B> for B {}
1870
1871#[sealed::sealed]
1872impl<B: Boundedness> ApplyMonotoneStream<Proved, B::StreamToMonotone> for B {}
1873
1874/// Marker trait identifying the boundedness of a singleton given a monotonicity property of
1875/// an aggregation on a keyed stream.
1876#[sealed::sealed]
1877pub trait ApplyMonotoneKeyedStream<P, B2: KeyedSingletonBound> {}
1878
1879#[sealed::sealed]
1880impl<B: Boundedness> ApplyMonotoneKeyedStream<NotProved, B::KeyedStreamToNonMonotone> for B {}
1881
1882#[sealed::sealed]
1883impl<B: Boundedness> ApplyMonotoneKeyedStream<Proved, B::KeyedStreamToMonotone> for B {}
1884
1885/// Marker trait identifying the boundedness of a singleton after a map operation,
1886/// given an order-preserving property.
1887#[sealed::sealed]
1888pub trait ApplyOrderPreservingSingleton<P, B2: SingletonBound> {}
1889
1890#[sealed::sealed]
1891impl<B: SingletonBound> ApplyOrderPreservingSingleton<NotProved, B::UnderlyingBound> for B {}
1892
1893#[sealed::sealed]
1894impl<B: SingletonBound> ApplyOrderPreservingSingleton<Proved, B> for B {}