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