Skip to main content

hydro_lang/live_collections/sliced/
style.rs

1//! Styled wrappers for live collections used with the `sliced!` macro.
2//!
3//! This module provides wrapper types that store both a collection and its associated
4//! non-determinism guard, allowing the nondet to be properly passed through during slicing.
5
6use super::Slicable;
7#[cfg(stageleft_runtime)]
8use crate::forward_handle::{CycleCollection, CycleCollectionWithInitial};
9use crate::forward_handle::{TickCycle, TickCycleHandle};
10use crate::live_collections::boundedness::{Bounded, Boundedness, Unbounded};
11use crate::live_collections::keyed_singleton::{BoundedValue, KeyedSingletonBound};
12use crate::live_collections::singleton::SingletonBound;
13use crate::live_collections::stream::{Ordering, Retries};
14use crate::location::Location;
15use crate::location::tick::{DeferTick, Tick};
16use crate::nondet::NonDet;
17
18/// Default style wrapper that stores a collection and its non-determinism guard.
19///
20/// This is used by the `sliced!` macro when no explicit style is specified.
21pub struct Default<T> {
22    pub(crate) collection: T,
23    pub(crate) nondet: NonDet,
24}
25
26impl<T> Default<T> {
27    /// Creates a new default-styled wrapper.
28    pub fn new(collection: T, nondet: NonDet) -> Self {
29        Self { collection, nondet }
30    }
31}
32
33/// Helper function for unstyled `use` in `sliced!` macro - wraps the collection in Default style.
34#[doc(hidden)]
35pub fn default<T>(t: T, nondet: NonDet) -> Default<T> {
36    Default::new(t, nondet)
37}
38
39/// Atomic style wrapper that stores a collection and its non-determinism guard.
40///
41/// This is used by the `sliced!` macro when `use::atomic(...)` is specified.
42pub struct Atomic<T> {
43    pub(crate) collection: T,
44    pub(crate) nondet: NonDet,
45}
46
47impl<T> Atomic<T> {
48    /// Creates a new atomic-styled wrapper.
49    pub fn new(collection: T, nondet: NonDet) -> Self {
50        Self { collection, nondet }
51    }
52}
53
54/// Wraps a live collection to be treated atomically during slicing.
55pub fn atomic<T>(t: T, nondet: NonDet) -> Atomic<T> {
56    Atomic::new(t, nondet)
57}
58
59/// Creates a stateful cycle with an initial value for use in `sliced!`.
60///
61/// The initial value is computed from a closure that receives the location
62/// for the body of the slice.
63///
64/// The initial value is used on the first iteration, and subsequent iterations receive
65/// the value assigned to the mutable binding at the end of the previous iteration.
66#[cfg(stageleft_runtime)]
67#[expect(
68    private_bounds,
69    reason = "only Hydro collections can implement CycleCollectionWithInitial"
70)]
71pub fn state<
72    'a,
73    S: CycleCollectionWithInitial<'a, TickCycle, Location = Tick<L::DropConsistency>>,
74    L: Location<'a>,
75>(
76    tick: &Tick<L>,
77    initial_fn: impl FnOnce(&Tick<L>) -> S,
78) -> (TickCycleHandle<'a, S>, S) {
79    let initial = initial_fn(tick);
80    initial.location().clone().cycle_with_initial(initial)
81}
82
83/// Creates a stateful cycle without an initial value for use in `sliced!`.
84///
85/// On the first iteration, the state will be null/empty. Subsequent iterations receive
86/// the value assigned to the mutable binding at the end of the previous iteration.
87#[cfg(stageleft_runtime)]
88#[expect(
89    private_bounds,
90    reason = "only Hydro collections can implement CycleCollection"
91)]
92pub fn state_null<
93    'a,
94    S: CycleCollection<'a, TickCycle, Location = Tick<L::DropConsistency>> + DeferTick,
95    L: Location<'a>,
96>(
97    tick: &Tick<L>,
98) -> (TickCycleHandle<'a, S>, S) {
99    tick.cycle::<S, _>()
100}
101
102// ============================================================================
103// Default style Slicable implementations
104//
105// All of these drop consistency because they are performing non-deterministic
106// batching / snapshotting.
107// ============================================================================
108
109impl<'a, T, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
110    Slicable<'a, L::DropConsistency> for Default<crate::live_collections::Stream<T, L, B, O, R>>
111{
112    type Slice = crate::live_collections::Stream<T, Tick<L::DropConsistency>, Bounded, O, R>;
113    type Backtrace = crate::compile::ir::backtrace::Backtrace;
114
115    fn get_location(&self) -> L::DropConsistency {
116        self.collection.location().drop_consistency()
117    }
118    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
119        let out = self.collection.batch(tick, self.nondet);
120        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
121        out
122    }
123}
124
125impl<'a, T, L: Location<'a>, B: SingletonBound> Slicable<'a, L::DropConsistency>
126    for Default<crate::live_collections::Singleton<T, L, B>>
127{
128    type Slice = crate::live_collections::Singleton<T, Tick<L::DropConsistency>, Bounded>;
129    type Backtrace = crate::compile::ir::backtrace::Backtrace;
130
131    fn get_location(&self) -> L::DropConsistency {
132        self.collection.location().drop_consistency()
133    }
134    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
135        let out = self.collection.snapshot(tick, self.nondet);
136        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
137        out
138    }
139}
140
141impl<'a, T, L: Location<'a>, B: Boundedness> Slicable<'a, L::DropConsistency>
142    for Default<crate::live_collections::Optional<T, L, B>>
143{
144    type Slice = crate::live_collections::Optional<T, Tick<L::DropConsistency>, Bounded>;
145    type Backtrace = crate::compile::ir::backtrace::Backtrace;
146
147    fn get_location(&self) -> L::DropConsistency {
148        self.collection.location().drop_consistency()
149    }
150    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
151        let out = self.collection.snapshot(tick, self.nondet);
152        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
153        out
154    }
155}
156
157impl<'a, K, V, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
158    Slicable<'a, L::DropConsistency>
159    for Default<crate::live_collections::KeyedStream<K, V, L, B, O, R>>
160{
161    type Slice =
162        crate::live_collections::KeyedStream<K, V, Tick<L::DropConsistency>, Bounded, O, R>;
163    type Backtrace = crate::compile::ir::backtrace::Backtrace;
164
165    fn get_location(&self) -> L::DropConsistency {
166        self.collection.location().drop_consistency()
167    }
168    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
169        let out = self.collection.batch(tick, self.nondet);
170        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
171        out
172    }
173}
174
175impl<'a, K, V, L: Location<'a>, B: KeyedSingletonBound<ValueBound = Unbounded>>
176    Slicable<'a, L::DropConsistency>
177    for Default<crate::live_collections::KeyedSingleton<K, V, L, B>>
178{
179    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
180    type Backtrace = crate::compile::ir::backtrace::Backtrace;
181
182    fn get_location(&self) -> L::DropConsistency {
183        self.collection.location().drop_consistency()
184    }
185    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
186        let out = self.collection.snapshot(tick, self.nondet);
187        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
188        out
189    }
190}
191
192impl<'a, K, V, L: Location<'a>> Slicable<'a, L::DropConsistency>
193    for Default<crate::live_collections::KeyedSingleton<K, V, L, BoundedValue>>
194{
195    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
196    type Backtrace = crate::compile::ir::backtrace::Backtrace;
197
198    fn get_location(&self) -> L::DropConsistency {
199        self.collection.location().drop_consistency()
200    }
201    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
202        let out = self.collection.batch(tick, self.nondet);
203        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
204        out
205    }
206}
207
208// ============================================================================
209// Atomic style Slicable implementations
210// ============================================================================
211
212impl<'a, T, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
213    Slicable<'a, L::DropConsistency>
214    for Atomic<crate::live_collections::Stream<T, crate::location::Atomic<L>, B, O, R>>
215{
216    type Slice = crate::live_collections::Stream<T, Tick<L::DropConsistency>, Bounded, O, R>;
217    type Backtrace = crate::compile::ir::backtrace::Backtrace;
218    fn get_location(&self) -> L::DropConsistency {
219        self.collection.location().tick.l.drop_consistency()
220    }
221
222    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
223        let out = self.collection.batch_atomic(tick, self.nondet);
224        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
225        out
226    }
227}
228
229impl<'a, T, L: Location<'a>, B: SingletonBound> Slicable<'a, L::DropConsistency>
230    for Atomic<crate::live_collections::Singleton<T, crate::location::Atomic<L>, B>>
231{
232    type Slice = crate::live_collections::Singleton<T, Tick<L::DropConsistency>, Bounded>;
233    type Backtrace = crate::compile::ir::backtrace::Backtrace;
234    fn get_location(&self) -> L::DropConsistency {
235        self.collection.location().tick.l.drop_consistency()
236    }
237
238    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
239        let out = self.collection.snapshot_atomic(tick, self.nondet);
240        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
241        out
242    }
243}
244
245impl<'a, T, L: Location<'a>, B: Boundedness> Slicable<'a, L::DropConsistency>
246    for Atomic<crate::live_collections::Optional<T, crate::location::Atomic<L>, B>>
247{
248    type Slice = crate::live_collections::Optional<T, Tick<L::DropConsistency>, Bounded>;
249    type Backtrace = crate::compile::ir::backtrace::Backtrace;
250    fn get_location(&self) -> L::DropConsistency {
251        self.collection.location().tick.l.drop_consistency()
252    }
253
254    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
255        let out = self.collection.snapshot_atomic(tick, self.nondet);
256        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
257        out
258    }
259}
260
261impl<'a, K, V, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
262    Slicable<'a, L::DropConsistency>
263    for Atomic<crate::live_collections::KeyedStream<K, V, crate::location::Atomic<L>, B, O, R>>
264{
265    type Slice =
266        crate::live_collections::KeyedStream<K, V, Tick<L::DropConsistency>, Bounded, O, R>;
267    type Backtrace = crate::compile::ir::backtrace::Backtrace;
268    fn get_location(&self) -> L::DropConsistency {
269        self.collection.location().tick.l.drop_consistency()
270    }
271
272    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
273        let out = self.collection.batch_atomic(tick, self.nondet);
274        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
275        out
276    }
277}
278
279impl<'a, K, V, L: Location<'a>, B: KeyedSingletonBound<ValueBound = Unbounded>>
280    Slicable<'a, L::DropConsistency>
281    for Atomic<crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, B>>
282{
283    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
284    type Backtrace = crate::compile::ir::backtrace::Backtrace;
285    fn get_location(&self) -> L::DropConsistency {
286        self.collection.location().tick.l.drop_consistency()
287    }
288
289    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
290        let out = self.collection.snapshot_atomic(tick, self.nondet);
291        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
292        out
293    }
294}
295
296impl<'a, K, V, L: Location<'a>> Slicable<'a, L::DropConsistency>
297    for Atomic<
298        crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, BoundedValue>,
299    >
300{
301    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
302    type Backtrace = crate::compile::ir::backtrace::Backtrace;
303    fn get_location(&self) -> L::DropConsistency {
304        self.collection.location().tick.l.drop_consistency()
305    }
306
307    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
308        let out = self.collection.batch_atomic(tick, self.nondet);
309        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
310        out
311    }
312}