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
115    fn preferred_tick(&self) -> Option<Tick<L>> {
116        None
117    }
118
119    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
120        let out = self.collection.batch(tick, self.nondet);
121        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
122        out
123    }
124}
125
126impl<'a, T, L: Location<'a>, B: Boundedness> Slicable<'a, L>
127    for Default<crate::live_collections::Singleton<T, L, B>>
128{
129    type Slice = crate::live_collections::Singleton<T, Tick<L>, Bounded>;
130    type Backtrace = crate::compile::ir::backtrace::Backtrace;
131
132    fn get_location(&self) -> &L {
133        self.collection.location()
134    }
135
136    fn preferred_tick(&self) -> Option<Tick<L>> {
137        None
138    }
139
140    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
141        let out = self.collection.snapshot(tick, self.nondet);
142        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
143        out
144    }
145}
146
147impl<'a, T, L: Location<'a>, B: Boundedness> Slicable<'a, L>
148    for Default<crate::live_collections::Optional<T, L, B>>
149{
150    type Slice = crate::live_collections::Optional<T, Tick<L>, Bounded>;
151    type Backtrace = crate::compile::ir::backtrace::Backtrace;
152
153    fn get_location(&self) -> &L {
154        self.collection.location()
155    }
156
157    fn preferred_tick(&self) -> Option<Tick<L>> {
158        None
159    }
160
161    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
162        let out = self.collection.snapshot(tick, self.nondet);
163        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
164        out
165    }
166}
167
168impl<'a, K, V, L: Location<'a>, O: Ordering, R: Retries> Slicable<'a, L>
169    for Default<crate::live_collections::KeyedStream<K, V, L, Unbounded, O, R>>
170{
171    type Slice = crate::live_collections::KeyedStream<K, V, Tick<L>, Bounded, O, R>;
172    type Backtrace = crate::compile::ir::backtrace::Backtrace;
173
174    fn get_location(&self) -> &L {
175        self.collection.location()
176    }
177
178    fn preferred_tick(&self) -> Option<Tick<L>> {
179        None
180    }
181
182    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
183        let out = self.collection.batch(tick, self.nondet);
184        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
185        out
186    }
187}
188
189impl<'a, K, V, L: Location<'a>> Slicable<'a, L>
190    for Default<crate::live_collections::KeyedSingleton<K, V, L, Unbounded>>
191{
192    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L>, Bounded>;
193    type Backtrace = crate::compile::ir::backtrace::Backtrace;
194
195    fn get_location(&self) -> &L {
196        self.collection.location()
197    }
198
199    fn preferred_tick(&self) -> Option<Tick<L>> {
200        None
201    }
202
203    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
204        let out = self.collection.snapshot(tick, self.nondet);
205        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
206        out
207    }
208}
209
210impl<'a, K, V, L: Location<'a> + NoTick> Slicable<'a, L>
211    for Default<crate::live_collections::KeyedSingleton<K, V, L, BoundedValue>>
212{
213    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L>, Bounded>;
214    type Backtrace = crate::compile::ir::backtrace::Backtrace;
215
216    fn get_location(&self) -> &L {
217        self.collection.location()
218    }
219
220    fn preferred_tick(&self) -> Option<Tick<L>> {
221        None
222    }
223
224    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
225        let out = self.collection.batch(tick, self.nondet);
226        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
227        out
228    }
229}
230
231// ============================================================================
232// Atomic style Slicable implementations
233// ============================================================================
234
235impl<'a, T, L: Location<'a> + NoTick, O: Ordering, R: Retries> Slicable<'a, L>
236    for Atomic<crate::live_collections::Stream<T, crate::location::Atomic<L>, Unbounded, O, R>>
237{
238    type Slice = crate::live_collections::Stream<T, Tick<L>, Bounded, O, R>;
239    type Backtrace = crate::compile::ir::backtrace::Backtrace;
240
241    fn preferred_tick(&self) -> Option<Tick<L>> {
242        Some(self.collection.location().tick.clone())
243    }
244
245    fn get_location(&self) -> &L {
246        panic!("Atomic location has no accessible inner location")
247    }
248
249    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
250        assert_eq!(
251            self.collection.location().tick.id(),
252            tick.id(),
253            "Mismatched tick for atomic slicing"
254        );
255
256        let out = self.collection.batch_atomic(self.nondet);
257        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
258        out
259    }
260}
261
262impl<'a, T, L: Location<'a> + NoTick> Slicable<'a, L>
263    for Atomic<crate::live_collections::Singleton<T, crate::location::Atomic<L>, Unbounded>>
264{
265    type Slice = crate::live_collections::Singleton<T, Tick<L>, Bounded>;
266    type Backtrace = crate::compile::ir::backtrace::Backtrace;
267
268    fn preferred_tick(&self) -> Option<Tick<L>> {
269        Some(self.collection.location().tick.clone())
270    }
271
272    fn get_location(&self) -> &L {
273        panic!("Atomic location has no accessible inner location")
274    }
275
276    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
277        assert_eq!(
278            self.collection.location().tick.id(),
279            tick.id(),
280            "Mismatched tick for atomic slicing"
281        );
282
283        let out = self.collection.snapshot_atomic(self.nondet);
284        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
285        out
286    }
287}
288
289impl<'a, T, L: Location<'a> + NoTick> Slicable<'a, L>
290    for Atomic<crate::live_collections::Optional<T, crate::location::Atomic<L>, Unbounded>>
291{
292    type Slice = crate::live_collections::Optional<T, Tick<L>, Bounded>;
293    type Backtrace = crate::compile::ir::backtrace::Backtrace;
294
295    fn preferred_tick(&self) -> Option<Tick<L>> {
296        Some(self.collection.location().tick.clone())
297    }
298
299    fn get_location(&self) -> &L {
300        panic!("Atomic location has no accessible inner location")
301    }
302
303    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
304        assert_eq!(
305            self.collection.location().tick.id(),
306            tick.id(),
307            "Mismatched tick for atomic slicing"
308        );
309
310        let out = self.collection.snapshot_atomic(self.nondet);
311        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
312        out
313    }
314}
315
316impl<'a, K, V, L: Location<'a> + NoTick, O: Ordering, R: Retries> Slicable<'a, L>
317    for Atomic<
318        crate::live_collections::KeyedStream<K, V, crate::location::Atomic<L>, Unbounded, O, R>,
319    >
320{
321    type Slice = crate::live_collections::KeyedStream<K, V, Tick<L>, Bounded, O, R>;
322    type Backtrace = crate::compile::ir::backtrace::Backtrace;
323
324    fn preferred_tick(&self) -> Option<Tick<L>> {
325        Some(self.collection.location().tick.clone())
326    }
327
328    fn get_location(&self) -> &L {
329        panic!("Atomic location has no accessible inner location")
330    }
331
332    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
333        assert_eq!(
334            self.collection.location().tick.id(),
335            tick.id(),
336            "Mismatched tick for atomic slicing"
337        );
338
339        let out = self.collection.batch_atomic(self.nondet);
340        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
341        out
342    }
343}
344
345impl<'a, K, V, L: Location<'a> + NoTick> Slicable<'a, L>
346    for Atomic<crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, Unbounded>>
347{
348    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L>, Bounded>;
349    type Backtrace = crate::compile::ir::backtrace::Backtrace;
350
351    fn preferred_tick(&self) -> Option<Tick<L>> {
352        Some(self.collection.location().tick.clone())
353    }
354
355    fn get_location(&self) -> &L {
356        panic!("Atomic location has no accessible inner location")
357    }
358
359    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
360        assert_eq!(
361            self.collection.location().tick.id(),
362            tick.id(),
363            "Mismatched tick for atomic slicing"
364        );
365
366        let out = self.collection.snapshot_atomic(self.nondet);
367        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
368        out
369    }
370}
371
372impl<'a, K, V, L: Location<'a> + NoTick> Slicable<'a, L>
373    for Atomic<
374        crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, BoundedValue>,
375    >
376{
377    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L>, Bounded>;
378    type Backtrace = crate::compile::ir::backtrace::Backtrace;
379
380    fn preferred_tick(&self) -> Option<Tick<L>> {
381        Some(self.collection.location().tick.clone())
382    }
383
384    fn get_location(&self) -> &L {
385        panic!("Atomic location has no accessible inner location")
386    }
387
388    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
389        assert_eq!(
390            self.collection.location().tick.id(),
391            tick.id(),
392            "Mismatched tick for atomic slicing"
393        );
394
395        let out = self.collection.batch_atomic(self.nondet);
396        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
397        out
398    }
399}