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::NoConsistency>>,
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::NoConsistency>> + DeferTick,
95    L: Location<'a>,
96>(
97    tick: &Tick<L>,
98) -> (TickCycleHandle<'a, S>, S) {
99    tick.drop_consistency().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::NoConsistency>
107    for Default<crate::live_collections::Stream<T, L, B, O, R>>
108{
109    type Slice = crate::live_collections::Stream<T, Tick<L::NoConsistency>, Bounded, O, R>;
110    type Backtrace = crate::compile::ir::backtrace::Backtrace;
111
112    fn get_location(&self) -> L::NoConsistency {
113        self.collection.location().drop_consistency()
114    }
115    fn slice(self, tick: &Tick<L::NoConsistency>, 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::NoConsistency>
123    for Default<crate::live_collections::Singleton<T, L, B>>
124{
125    type Slice = crate::live_collections::Singleton<T, Tick<L::NoConsistency>, Bounded>;
126    type Backtrace = crate::compile::ir::backtrace::Backtrace;
127
128    fn get_location(&self) -> L::NoConsistency {
129        self.collection.location().drop_consistency()
130    }
131    fn slice(self, tick: &Tick<L::NoConsistency>, 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::NoConsistency>
139    for Default<crate::live_collections::Optional<T, L, B>>
140{
141    type Slice = crate::live_collections::Optional<T, Tick<L::NoConsistency>, Bounded>;
142    type Backtrace = crate::compile::ir::backtrace::Backtrace;
143
144    fn get_location(&self) -> L::NoConsistency {
145        self.collection.location().drop_consistency()
146    }
147    fn slice(self, tick: &Tick<L::NoConsistency>, 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>
155    Slicable<'a, L::NoConsistency>
156    for Default<crate::live_collections::KeyedStream<K, V, L, B, O, R>>
157{
158    type Slice = crate::live_collections::KeyedStream<K, V, Tick<L::NoConsistency>, Bounded, O, R>;
159    type Backtrace = crate::compile::ir::backtrace::Backtrace;
160
161    fn get_location(&self) -> L::NoConsistency {
162        self.collection.location().drop_consistency()
163    }
164    fn slice(self, tick: &Tick<L::NoConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
165        let out = self.collection.batch(tick, self.nondet);
166        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
167        out
168    }
169}
170
171impl<'a, K, V, L: Location<'a>, B: KeyedSingletonBound<ValueBound = Unbounded>>
172    Slicable<'a, L::NoConsistency>
173    for Default<crate::live_collections::KeyedSingleton<K, V, L, B>>
174{
175    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::NoConsistency>, Bounded>;
176    type Backtrace = crate::compile::ir::backtrace::Backtrace;
177
178    fn get_location(&self) -> L::NoConsistency {
179        self.collection.location().drop_consistency()
180    }
181    fn slice(self, tick: &Tick<L::NoConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
182        let out = self.collection.snapshot(tick, self.nondet);
183        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
184        out
185    }
186}
187
188impl<'a, K, V, L: Location<'a>> Slicable<'a, L::NoConsistency>
189    for Default<crate::live_collections::KeyedSingleton<K, V, L, BoundedValue>>
190{
191    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::NoConsistency>, Bounded>;
192    type Backtrace = crate::compile::ir::backtrace::Backtrace;
193
194    fn get_location(&self) -> L::NoConsistency {
195        self.collection.location().drop_consistency()
196    }
197    fn slice(self, tick: &Tick<L::NoConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
198        let out = self.collection.batch(tick, self.nondet);
199        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
200        out
201    }
202}
203
204// ============================================================================
205// Atomic style Slicable implementations
206// ============================================================================
207
208impl<'a, T, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries> Slicable<'a, L::NoConsistency>
209    for Atomic<crate::live_collections::Stream<T, crate::location::Atomic<L>, B, O, R>>
210{
211    type Slice = crate::live_collections::Stream<T, Tick<L::NoConsistency>, Bounded, O, R>;
212    type Backtrace = crate::compile::ir::backtrace::Backtrace;
213    fn get_location(&self) -> L::NoConsistency {
214        self.collection.location().tick.l.drop_consistency()
215    }
216
217    fn slice(self, tick: &Tick<L::NoConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
218        let out = self.collection.batch_atomic(tick, self.nondet);
219        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
220        out
221    }
222}
223
224impl<'a, T, L: Location<'a>, B: SingletonBound> Slicable<'a, L::NoConsistency>
225    for Atomic<crate::live_collections::Singleton<T, crate::location::Atomic<L>, B>>
226{
227    type Slice = crate::live_collections::Singleton<T, Tick<L::NoConsistency>, Bounded>;
228    type Backtrace = crate::compile::ir::backtrace::Backtrace;
229    fn get_location(&self) -> L::NoConsistency {
230        self.collection.location().tick.l.drop_consistency()
231    }
232
233    fn slice(self, tick: &Tick<L::NoConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
234        let out = self.collection.snapshot_atomic(tick, self.nondet);
235        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
236        out
237    }
238}
239
240impl<'a, T, L: Location<'a>, B: Boundedness> Slicable<'a, L::NoConsistency>
241    for Atomic<crate::live_collections::Optional<T, crate::location::Atomic<L>, B>>
242{
243    type Slice = crate::live_collections::Optional<T, Tick<L::NoConsistency>, Bounded>;
244    type Backtrace = crate::compile::ir::backtrace::Backtrace;
245    fn get_location(&self) -> L::NoConsistency {
246        self.collection.location().tick.l.drop_consistency()
247    }
248
249    fn slice(self, tick: &Tick<L::NoConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
250        let out = self.collection.snapshot_atomic(tick, self.nondet);
251        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
252        out
253    }
254}
255
256impl<'a, K, V, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
257    Slicable<'a, L::NoConsistency>
258    for Atomic<crate::live_collections::KeyedStream<K, V, crate::location::Atomic<L>, B, O, R>>
259{
260    type Slice = crate::live_collections::KeyedStream<K, V, Tick<L::NoConsistency>, Bounded, O, R>;
261    type Backtrace = crate::compile::ir::backtrace::Backtrace;
262    fn get_location(&self) -> L::NoConsistency {
263        self.collection.location().tick.l.drop_consistency()
264    }
265
266    fn slice(self, tick: &Tick<L::NoConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
267        let out = self.collection.batch_atomic(tick, self.nondet);
268        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
269        out
270    }
271}
272
273impl<'a, K, V, L: Location<'a>, B: KeyedSingletonBound<ValueBound = Unbounded>>
274    Slicable<'a, L::NoConsistency>
275    for Atomic<crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, B>>
276{
277    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::NoConsistency>, Bounded>;
278    type Backtrace = crate::compile::ir::backtrace::Backtrace;
279    fn get_location(&self) -> L::NoConsistency {
280        self.collection.location().tick.l.drop_consistency()
281    }
282
283    fn slice(self, tick: &Tick<L::NoConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
284        let out = self.collection.snapshot_atomic(tick, self.nondet);
285        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
286        out
287    }
288}
289
290impl<'a, K, V, L: Location<'a>> Slicable<'a, L::NoConsistency>
291    for Atomic<
292        crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, BoundedValue>,
293    >
294{
295    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::NoConsistency>, Bounded>;
296    type Backtrace = crate::compile::ir::backtrace::Backtrace;
297    fn get_location(&self) -> L::NoConsistency {
298        self.collection.location().tick.l.drop_consistency()
299    }
300
301    fn slice(self, tick: &Tick<L::NoConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
302        let out = self.collection.batch_atomic(tick, self.nondet);
303        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
304        out
305    }
306}