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::tick::{DeferTick, Tick};
15use crate::location::{Location, NoTick};
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>>,
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    tick.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>> + DeferTick,
95    L: Location<'a> + NoTick,
96>(
97    tick: &Tick<L>,
98) -> (TickCycleHandle<'a, S>, S) {
99    tick.cycle::<S>()
100}
101
102// ============================================================================
103// Default style Slicable implementations
104// ============================================================================
105
106impl<'a, T, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries> Slicable<'a, L>
107    for Default<crate::live_collections::Stream<T, L, B, O, R>>
108{
109    type Slice = crate::live_collections::Stream<T, Tick<L>, Bounded, O, R>;
110    type Backtrace = crate::compile::ir::backtrace::Backtrace;
111
112    fn get_location(&self) -> &L {
113        self.collection.location()
114    }
115    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
116        let out = self.collection.batch(tick, self.nondet);
117        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
118        out
119    }
120}
121
122impl<'a, T, L: Location<'a>, B: SingletonBound> Slicable<'a, L>
123    for Default<crate::live_collections::Singleton<T, L, B>>
124{
125    type Slice = crate::live_collections::Singleton<T, Tick<L>, Bounded>;
126    type Backtrace = crate::compile::ir::backtrace::Backtrace;
127
128    fn get_location(&self) -> &L {
129        self.collection.location()
130    }
131    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
132        let out = self.collection.snapshot(tick, self.nondet);
133        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
134        out
135    }
136}
137
138impl<'a, T, L: Location<'a>, B: Boundedness> Slicable<'a, L>
139    for Default<crate::live_collections::Optional<T, L, B>>
140{
141    type Slice = crate::live_collections::Optional<T, Tick<L>, Bounded>;
142    type Backtrace = crate::compile::ir::backtrace::Backtrace;
143
144    fn get_location(&self) -> &L {
145        self.collection.location()
146    }
147    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
148        let out = self.collection.snapshot(tick, self.nondet);
149        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
150        out
151    }
152}
153
154impl<'a, K, V, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries> Slicable<'a, L>
155    for Default<crate::live_collections::KeyedStream<K, V, L, B, O, R>>
156{
157    type Slice = crate::live_collections::KeyedStream<K, V, Tick<L>, Bounded, O, R>;
158    type Backtrace = crate::compile::ir::backtrace::Backtrace;
159
160    fn get_location(&self) -> &L {
161        self.collection.location()
162    }
163    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
164        let out = self.collection.batch(tick, self.nondet);
165        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
166        out
167    }
168}
169
170impl<'a, K, V, L: Location<'a>, B: KeyedSingletonBound<ValueBound = Unbounded>> Slicable<'a, L>
171    for Default<crate::live_collections::KeyedSingleton<K, V, L, B>>
172{
173    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L>, Bounded>;
174    type Backtrace = crate::compile::ir::backtrace::Backtrace;
175
176    fn get_location(&self) -> &L {
177        self.collection.location()
178    }
179    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
180        let out = self.collection.snapshot(tick, self.nondet);
181        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
182        out
183    }
184}
185
186impl<'a, K, V, L: Location<'a> + NoTick> Slicable<'a, L>
187    for Default<crate::live_collections::KeyedSingleton<K, V, L, BoundedValue>>
188{
189    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L>, Bounded>;
190    type Backtrace = crate::compile::ir::backtrace::Backtrace;
191
192    fn get_location(&self) -> &L {
193        self.collection.location()
194    }
195    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
196        let out = self.collection.batch(tick, self.nondet);
197        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
198        out
199    }
200}
201
202// ============================================================================
203// Atomic style Slicable implementations
204// ============================================================================
205
206impl<'a, T, L: Location<'a> + NoTick, B: Boundedness, O: Ordering, R: Retries> Slicable<'a, L>
207    for Atomic<crate::live_collections::Stream<T, crate::location::Atomic<L>, B, O, R>>
208{
209    type Slice = crate::live_collections::Stream<T, Tick<L>, Bounded, O, R>;
210    type Backtrace = crate::compile::ir::backtrace::Backtrace;
211    fn get_location(&self) -> &L {
212        &self.collection.location().tick.l
213    }
214
215    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
216        let out = self.collection.batch_atomic(tick, self.nondet);
217        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
218        out
219    }
220}
221
222impl<'a, T, L: Location<'a> + NoTick, B: SingletonBound> Slicable<'a, L>
223    for Atomic<crate::live_collections::Singleton<T, crate::location::Atomic<L>, B>>
224{
225    type Slice = crate::live_collections::Singleton<T, Tick<L>, Bounded>;
226    type Backtrace = crate::compile::ir::backtrace::Backtrace;
227    fn get_location(&self) -> &L {
228        &self.collection.location().tick.l
229    }
230
231    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
232        let out = self.collection.snapshot_atomic(tick, self.nondet);
233        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
234        out
235    }
236}
237
238impl<'a, T, L: Location<'a> + NoTick, B: Boundedness> Slicable<'a, L>
239    for Atomic<crate::live_collections::Optional<T, crate::location::Atomic<L>, B>>
240{
241    type Slice = crate::live_collections::Optional<T, Tick<L>, Bounded>;
242    type Backtrace = crate::compile::ir::backtrace::Backtrace;
243    fn get_location(&self) -> &L {
244        &self.collection.location().tick.l
245    }
246
247    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
248        let out = self.collection.snapshot_atomic(tick, self.nondet);
249        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
250        out
251    }
252}
253
254impl<'a, K, V, L: Location<'a> + NoTick, B: Boundedness, O: Ordering, R: Retries> Slicable<'a, L>
255    for Atomic<crate::live_collections::KeyedStream<K, V, crate::location::Atomic<L>, B, O, R>>
256{
257    type Slice = crate::live_collections::KeyedStream<K, V, Tick<L>, Bounded, O, R>;
258    type Backtrace = crate::compile::ir::backtrace::Backtrace;
259    fn get_location(&self) -> &L {
260        &self.collection.location().tick.l
261    }
262
263    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
264        let out = self.collection.batch_atomic(tick, self.nondet);
265        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
266        out
267    }
268}
269
270impl<'a, K, V, L: Location<'a> + NoTick, B: KeyedSingletonBound<ValueBound = Unbounded>>
271    Slicable<'a, L>
272    for Atomic<crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, B>>
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}