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
6#[cfg(stageleft_runtime)]
7use std::marker::PhantomData;
8
9use super::Slicable;
10#[cfg(stageleft_runtime)]
11use crate::forward_handle::{CycleCollection, CycleCollectionWithInitial};
12use crate::forward_handle::{TickCycle, TickCycleHandle};
13use crate::live_collections::boundedness::{Bounded, Boundedness, Unbounded};
14use crate::live_collections::keyed_singleton::{
15    BoundedValue, KeyedSingletonBound, KeyedSingletonSnapshotBound,
16};
17use crate::live_collections::optional::OptionalBound;
18use crate::live_collections::singleton::SingletonBound;
19use crate::live_collections::stream::{ExactlyOnce, Ordering, Retries, TotalOrder};
20use crate::location::Location;
21use crate::location::tick::{DeferTick, Tick};
22use crate::nondet::{NonDet, nondet};
23
24/// Default style wrapper that stores a collection and its non-determinism guard.
25///
26/// This is used by the `sliced!` macro when no explicit style is specified. This style is
27/// deprecated; use the explicit [`batch`] or [`snapshot`] styles instead.
28pub struct Default<T> {
29    pub(crate) collection: T,
30    pub(crate) nondet: NonDet,
31}
32
33impl<T> Default<T> {
34    /// Creates a new default-styled wrapper.
35    pub fn new(collection: T, nondet: NonDet) -> Self {
36        Self { collection, nondet }
37    }
38}
39
40/// Helper function for unstyled `use` in `sliced!` macro - wraps the collection in Default style.
41#[doc(hidden)]
42#[deprecated(
43    note = "use `use::batch(...)` for stream-like collections or `use::snapshot(...)` for singleton-like collections instead"
44)]
45pub fn default<T>(t: T, nondet: NonDet) -> Default<T> {
46    Default::new(t, nondet)
47}
48
49/// Batch style wrapper that stores a stream-like collection and its non-determinism guard.
50///
51/// This is used by the `sliced!` macro when `use::batch(...)` is specified.
52pub struct Batch<T, H = ()> {
53    pub(crate) collection: T,
54    pub(crate) nondet: NonDet<H>,
55}
56
57impl<T, H> Batch<T, H> {
58    /// Creates a new batch-styled wrapper.
59    pub fn new(collection: T, nondet: NonDet<H>) -> Self {
60        Self { collection, nondet }
61    }
62}
63
64/// Wraps a stream-like live collection (such as a [`Stream`](crate::live_collections::Stream),
65/// [`KeyedStream`](crate::live_collections::KeyedStream), or a
66/// [`KeyedSingleton`](crate::live_collections::KeyedSingleton) with bounded values) to be
67/// sliced into non-deterministic batches of asynchronously arriving elements.
68pub fn batch<T, H>(t: T, nondet: NonDet<H>) -> Batch<T, H> {
69    Batch::new(t, nondet)
70}
71
72/// Snapshot style wrapper that stores a singleton-like collection and its non-determinism guard.
73///
74/// This is used by the `sliced!` macro when `use::snapshot(...)` is specified.
75pub struct Snapshot<T, H = ()> {
76    pub(crate) collection: T,
77    pub(crate) nondet: NonDet<H>,
78}
79
80impl<T, H> Snapshot<T, H> {
81    /// Creates a new snapshot-styled wrapper.
82    pub fn new(collection: T, nondet: NonDet<H>) -> Self {
83        Self { collection, nondet }
84    }
85}
86
87/// Wraps a singleton-like live collection (such as a
88/// [`Singleton`](crate::live_collections::Singleton),
89/// [`Optional`](crate::live_collections::Optional), or a
90/// [`KeyedSingleton`](crate::live_collections::KeyedSingleton) with asynchronously updated
91/// values) to be sliced into non-deterministic snapshots of its continuously changing value.
92pub fn snapshot<T, H>(t: T, nondet: NonDet<H>) -> Snapshot<T, H> {
93    Snapshot::new(t, nondet)
94}
95
96/// Time style wrapper that stores the non-determinism guard for reading the wall clock.
97///
98/// This is used by the `sliced!` macro when `use::time(...)` is specified. It carries no
99/// collection: the slice is the tick's current wall-clock reading
100/// ([`Tick::current_tick_instant`]).
101#[cfg(feature = "tokio")]
102pub struct Time {
103    pub(crate) nondet: NonDet,
104}
105
106#[cfg(feature = "tokio")]
107impl Time {
108    /// Creates a new time-styled wrapper.
109    pub fn new(nondet: NonDet) -> Self {
110        Self { nondet }
111    }
112}
113
114/// Reads the wall clock at each tick of the slice, as a bounded [`Singleton`] of
115/// [`tokio::time::Instant`] (the value depends on when the tick executes, hence the
116/// non-determinism guard). Since it carries no collection, it cannot be the first `use`
117/// of a `sliced!` block (the tick's location comes from a collection).
118///
119/// [`Singleton`]: crate::live_collections::Singleton
120#[cfg(feature = "tokio")]
121pub fn time(nondet: NonDet) -> Time {
122    Time::new(nondet)
123}
124
125/// Atomic style wrapper that stores a collection and its non-determinism guard.
126///
127/// This is used by the `sliced!` macro when `use::atomic(...)` is specified.
128pub struct Atomic<T> {
129    pub(crate) collection: T,
130    pub(crate) nondet: NonDet,
131}
132
133impl<T> Atomic<T> {
134    /// Creates a new atomic-styled wrapper.
135    pub fn new(collection: T, nondet: NonDet) -> Self {
136        Self { collection, nondet }
137    }
138}
139
140/// Wraps a live collection to be treated atomically during slicing.
141pub fn atomic<T>(t: T, nondet: NonDet) -> Atomic<T> {
142    Atomic::new(t, nondet)
143}
144
145/// Creates a stateful cycle with an initial value for use in `sliced!`.
146///
147/// The tick (which is the source of truth for lifetimes) is bound first, returning a
148/// [`StateBuilder`] which accepts the user-provided initializer via [`StateBuilder::build`].
149/// This two-step layout ensures that type errors caused by a bad initializer are attributed
150/// to the initializer argument rather than the tick or the entire macro invocation.
151///
152/// The initial value is computed from a closure that receives the location
153/// for the body of the slice.
154///
155/// The initial value is used on the first iteration, and subsequent iterations receive
156/// the value assigned to the mutable binding at the end of the previous iteration.
157#[cfg(stageleft_runtime)]
158pub fn state<'t, S, L>(tick: &'t Tick<L>) -> StateBuilder<'t, S, L> {
159    StateBuilder {
160        tick,
161        _phantom: PhantomData,
162    }
163}
164
165/// Builder returned by [`state`], which accepts the user-provided initializer.
166#[cfg(stageleft_runtime)]
167pub struct StateBuilder<'t, S, L> {
168    tick: &'t Tick<L>,
169    _phantom: PhantomData<S>,
170}
171
172#[cfg(stageleft_runtime)]
173impl<'t, 'a, S, L: Location<'a>> StateBuilder<'t, S, L> {
174    /// Supplies the initializer closure and creates the stateful cycle.
175    ///
176    /// The initializer takes the tick at the builder's `'t` lifetime (rather than a
177    /// higher-ranked `for<'x>` bound), since the builder already stores the tick reference.
178    /// This way, an initializer that requires a specific tick reference lifetime produces a
179    /// borrow error directly on the tick, instead of a confusing "implementation of `Fn` is
180    /// not general enough" error that blames an unrelated variable.
181    #[expect(
182        private_bounds,
183        reason = "only Hydro collections can implement CycleCollectionWithInitial"
184    )]
185    pub fn build(self, initial_fn: impl FnOnce(&'t Tick<L>) -> S) -> (TickCycleHandle<'a, S>, S)
186    where
187        S: CycleCollectionWithInitial<'a, TickCycle, Location = Tick<L::DropConsistency>>,
188    {
189        let initial = initial_fn(self.tick);
190        initial.location().clone().cycle_with_initial(initial)
191    }
192}
193
194/// Creates a stateful cycle without an initial value for use in `sliced!`.
195///
196/// The tick (which is the source of truth for lifetimes) is bound first, returning a
197/// [`StateNullBuilder`] which creates the cycle via [`StateNullBuilder::build`].
198///
199/// On the first iteration, the state will be null/empty. Subsequent iterations receive
200/// the value assigned to the mutable binding at the end of the previous iteration.
201#[cfg(stageleft_runtime)]
202pub fn state_null<'t, S, L>(tick: &'t Tick<L>) -> StateNullBuilder<'t, S, L> {
203    StateNullBuilder {
204        tick,
205        _phantom: PhantomData,
206    }
207}
208
209/// Builder returned by [`state_null`], which creates the cycle.
210#[cfg(stageleft_runtime)]
211pub struct StateNullBuilder<'t, S, L> {
212    tick: &'t Tick<L>,
213    _phantom: PhantomData<S>,
214}
215
216#[cfg(stageleft_runtime)]
217impl<'t, 'a, S, L: Location<'a>> StateNullBuilder<'t, S, L> {
218    /// Creates the stateful cycle, which starts as null/empty on the first iteration.
219    #[expect(
220        private_bounds,
221        reason = "only Hydro collections can implement CycleCollection"
222    )]
223    pub fn build(self) -> (TickCycleHandle<'a, S>, S)
224    where
225        S: CycleCollection<'a, TickCycle, Location = Tick<L::DropConsistency>> + DeferTick,
226    {
227        self.tick.cycle::<S, _>()
228    }
229}
230
231// ============================================================================
232// Time style Slicable implementation
233// ============================================================================
234
235#[cfg(feature = "tokio")]
236impl<'a, L: Location<'a>> Slicable<'a, L> for Time {
237    type Slice =
238        crate::live_collections::Singleton<tokio::time::Instant, Tick<L::DropConsistency>, Bounded>;
239    type Backtrace = crate::compile::ir::backtrace::Backtrace;
240
241    fn get_location(&self) -> L {
242        unreachable!(
243            "`use::time(...)` carries no collection; it cannot be the first `use` of a `sliced!` block"
244        )
245    }
246    fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace) -> Self::Slice {
247        let out = tick.current_tick_instant(self.nondet);
248        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
249        out
250    }
251}
252
253// ============================================================================
254// Default style Slicable implementations
255//
256// All of these drop consistency because they are performing non-deterministic
257// batching / snapshotting.
258// ============================================================================
259
260impl<'a, T, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
261    Slicable<'a, L::DropConsistency> for Default<crate::live_collections::Stream<T, L, B, O, R>>
262{
263    type Slice = crate::live_collections::Stream<T, Tick<L::DropConsistency>, Bounded, O, R>;
264    type Backtrace = crate::compile::ir::backtrace::Backtrace;
265
266    fn get_location(&self) -> L::DropConsistency {
267        self.collection.location().drop_consistency()
268    }
269    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
270        let _ = self.nondet;
271        let out = self.collection.batch(
272            tick,
273            nondet!(/** justified by the guard stored in this style wrapper */),
274        );
275        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
276        out
277    }
278}
279
280impl<'a, T, L: Location<'a>, B: SingletonBound> Slicable<'a, L::DropConsistency>
281    for Default<crate::live_collections::Singleton<T, L, B>>
282{
283    type Slice = crate::live_collections::Singleton<T, Tick<L::DropConsistency>, Bounded>;
284    type Backtrace = crate::compile::ir::backtrace::Backtrace;
285
286    fn get_location(&self) -> L::DropConsistency {
287        self.collection.location().drop_consistency()
288    }
289    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
290        let _ = self.nondet;
291        let out = self.collection.snapshot(
292            tick,
293            nondet!(/** justified by the guard stored in this style wrapper */),
294        );
295        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
296        out
297    }
298}
299
300impl<'a, T, L: Location<'a>, B: OptionalBound> Slicable<'a, L::DropConsistency>
301    for Default<crate::live_collections::Optional<T, L, B>>
302{
303    type Slice = crate::live_collections::Optional<T, Tick<L::DropConsistency>, Bounded>;
304    type Backtrace = crate::compile::ir::backtrace::Backtrace;
305
306    fn get_location(&self) -> L::DropConsistency {
307        self.collection.location().drop_consistency()
308    }
309    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
310        let out = self.collection.snapshot(tick, 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>, B: Boundedness, O: Ordering, R: Retries>
317    Slicable<'a, L::DropConsistency>
318    for Default<crate::live_collections::KeyedStream<K, V, L, B, O, R>>
319{
320    type Slice =
321        crate::live_collections::KeyedStream<K, V, Tick<L::DropConsistency>, Bounded, O, R>;
322    type Backtrace = crate::compile::ir::backtrace::Backtrace;
323
324    fn get_location(&self) -> L::DropConsistency {
325        self.collection.location().drop_consistency()
326    }
327    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
328        let _ = self.nondet;
329        let out = self.collection.batch(
330            tick,
331            nondet!(/** justified by the guard stored in this style wrapper */),
332        );
333        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
334        out
335    }
336}
337
338impl<'a, K, V, L: Location<'a>, B: KeyedSingletonSnapshotBound<ValueBound = Unbounded>>
339    Slicable<'a, L::DropConsistency>
340    for Default<crate::live_collections::KeyedSingleton<K, V, L, B>>
341{
342    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
343    type Backtrace = crate::compile::ir::backtrace::Backtrace;
344
345    fn get_location(&self) -> L::DropConsistency {
346        self.collection.location().drop_consistency()
347    }
348    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
349        let _ = self.nondet;
350        let out = self.collection.snapshot(
351            tick,
352            nondet!(/** justified by the guard stored in this style wrapper */),
353        );
354        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
355        out
356    }
357}
358
359impl<'a, K, V, L: Location<'a>> Slicable<'a, L::DropConsistency>
360    for Default<crate::live_collections::KeyedSingleton<K, V, L, BoundedValue>>
361{
362    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
363    type Backtrace = crate::compile::ir::backtrace::Backtrace;
364
365    fn get_location(&self) -> L::DropConsistency {
366        self.collection.location().drop_consistency()
367    }
368    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
369        let _ = self.nondet;
370        let out = self.collection.batch(
371            tick,
372            nondet!(/** justified by the guard stored in this style wrapper */),
373        );
374        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
375        out
376    }
377}
378
379// ============================================================================
380// Batch style Slicable implementations (stream-like collections)
381//
382// All of these drop consistency because they are performing non-deterministic
383// batching.
384// ============================================================================
385
386impl<'a, T, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
387    Slicable<'a, L::DropConsistency>
388    for Batch<
389        crate::live_collections::Stream<T, L, B, O, R>,
390        Option<crate::sim_hooks::BatchHook<T, O, R, L::SimHookScope>>,
391    >
392{
393    type Slice = crate::live_collections::Stream<T, Tick<L::DropConsistency>, Bounded, O, R>;
394    type Backtrace = crate::compile::ir::backtrace::Backtrace;
395
396    fn get_location(&self) -> L::DropConsistency {
397        self.collection.location().drop_consistency()
398    }
399    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
400        let out = self.collection.batch(tick, self.nondet);
401        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
402        out
403    }
404}
405
406impl<'a, K, V, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
407    Slicable<'a, L::DropConsistency>
408    for Batch<
409        crate::live_collections::KeyedStream<K, V, L, B, O, R>,
410        Option<crate::sim_hooks::KeyedBatchHook<K, V, O, R, L::SimHookScope>>,
411    >
412{
413    type Slice =
414        crate::live_collections::KeyedStream<K, V, Tick<L::DropConsistency>, Bounded, O, R>;
415    type Backtrace = crate::compile::ir::backtrace::Backtrace;
416
417    fn get_location(&self) -> L::DropConsistency {
418        self.collection.location().drop_consistency()
419    }
420    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
421        let out = self.collection.batch(tick, self.nondet);
422        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
423        out
424    }
425}
426
427impl<'a, K, V, L: Location<'a>, B: KeyedSingletonBound<ValueBound = Bounded>>
428    Slicable<'a, L::DropConsistency>
429    for Batch<
430        crate::live_collections::KeyedSingleton<K, V, L, B>,
431        Option<crate::sim_hooks::KeyedBatchHook<K, V, TotalOrder, ExactlyOnce, L::SimHookScope>>,
432    >
433{
434    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
435    type Backtrace = crate::compile::ir::backtrace::Backtrace;
436
437    fn get_location(&self) -> L::DropConsistency {
438        self.collection.location().drop_consistency()
439    }
440    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
441        let out = self.collection.batch(tick, self.nondet);
442        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
443        out
444    }
445}
446
447// ============================================================================
448// Snapshot style Slicable implementations (singleton-like collections)
449//
450// All of these drop consistency because they are performing non-deterministic
451// snapshotting.
452// ============================================================================
453
454impl<'a, T, L: Location<'a>, B: SingletonBound> Slicable<'a, L::DropConsistency>
455    for Snapshot<
456        crate::live_collections::Singleton<T, L, B>,
457        Option<crate::sim_hooks::SnapshotHook<T, L::SimHookScope>>,
458    >
459{
460    type Slice = crate::live_collections::Singleton<T, Tick<L::DropConsistency>, Bounded>;
461    type Backtrace = crate::compile::ir::backtrace::Backtrace;
462
463    fn get_location(&self) -> L::DropConsistency {
464        self.collection.location().drop_consistency()
465    }
466    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
467        let out = self.collection.snapshot(tick, self.nondet);
468        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
469        out
470    }
471}
472
473impl<'a, T, L: Location<'a>, B: OptionalBound> Slicable<'a, L::DropConsistency>
474    for Snapshot<crate::live_collections::Optional<T, L, B>>
475{
476    type Slice = crate::live_collections::Optional<T, Tick<L::DropConsistency>, Bounded>;
477    type Backtrace = crate::compile::ir::backtrace::Backtrace;
478
479    fn get_location(&self) -> L::DropConsistency {
480        self.collection.location().drop_consistency()
481    }
482    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
483        let out = self.collection.snapshot(tick, self.nondet);
484        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
485        out
486    }
487}
488
489impl<'a, K, V, L: Location<'a>, B: KeyedSingletonSnapshotBound> Slicable<'a, L::DropConsistency>
490    for Snapshot<
491        crate::live_collections::KeyedSingleton<K, V, L, B>,
492        Option<crate::sim_hooks::KeyedSnapshotHook<K, V, L::SimHookScope>>,
493    >
494{
495    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
496    type Backtrace = crate::compile::ir::backtrace::Backtrace;
497
498    fn get_location(&self) -> L::DropConsistency {
499        self.collection.location().drop_consistency()
500    }
501    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
502        let out = self.collection.snapshot(tick, self.nondet);
503        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
504        out
505    }
506}
507
508// ============================================================================
509// Atomic style Slicable implementations
510// ============================================================================
511
512impl<'a, T, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
513    Slicable<'a, L::DropConsistency>
514    for Atomic<crate::live_collections::Stream<T, crate::location::Atomic<L>, B, O, R>>
515{
516    type Slice = crate::live_collections::Stream<T, Tick<L::DropConsistency>, Bounded, O, R>;
517    type Backtrace = crate::compile::ir::backtrace::Backtrace;
518    fn get_location(&self) -> L::DropConsistency {
519        self.collection.location().tick.l.drop_consistency()
520    }
521
522    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
523        let _ = self.nondet;
524        let out = self.collection.batch_atomic(
525            tick,
526            nondet!(/** justified by the guard stored in this style wrapper */),
527        );
528        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
529        out
530    }
531}
532
533impl<'a, T, L: Location<'a>, B: SingletonBound> Slicable<'a, L::DropConsistency>
534    for Atomic<crate::live_collections::Singleton<T, crate::location::Atomic<L>, B>>
535{
536    type Slice = crate::live_collections::Singleton<T, Tick<L::DropConsistency>, Bounded>;
537    type Backtrace = crate::compile::ir::backtrace::Backtrace;
538    fn get_location(&self) -> L::DropConsistency {
539        self.collection.location().tick.l.drop_consistency()
540    }
541
542    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
543        let _ = self.nondet;
544        let out = self.collection.snapshot_atomic(
545            tick,
546            nondet!(/** justified by the guard stored in this style wrapper */),
547        );
548        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
549        out
550    }
551}
552
553impl<'a, T, L: Location<'a>, B: OptionalBound> Slicable<'a, L::DropConsistency>
554    for Atomic<crate::live_collections::Optional<T, crate::location::Atomic<L>, B>>
555{
556    type Slice = crate::live_collections::Optional<T, Tick<L::DropConsistency>, Bounded>;
557    type Backtrace = crate::compile::ir::backtrace::Backtrace;
558    fn get_location(&self) -> L::DropConsistency {
559        self.collection.location().tick.l.drop_consistency()
560    }
561
562    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
563        let out = self.collection.snapshot_atomic(tick, self.nondet);
564        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
565        out
566    }
567}
568
569impl<'a, K, V, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries>
570    Slicable<'a, L::DropConsistency>
571    for Atomic<crate::live_collections::KeyedStream<K, V, crate::location::Atomic<L>, B, O, R>>
572{
573    type Slice =
574        crate::live_collections::KeyedStream<K, V, Tick<L::DropConsistency>, Bounded, O, R>;
575    type Backtrace = crate::compile::ir::backtrace::Backtrace;
576    fn get_location(&self) -> L::DropConsistency {
577        self.collection.location().tick.l.drop_consistency()
578    }
579
580    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
581        let out = self.collection.batch_atomic(tick, self.nondet);
582        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
583        out
584    }
585}
586
587impl<'a, K, V, L: Location<'a>, B: KeyedSingletonSnapshotBound<ValueBound = Unbounded>>
588    Slicable<'a, L::DropConsistency>
589    for Atomic<crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, B>>
590{
591    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
592    type Backtrace = crate::compile::ir::backtrace::Backtrace;
593    fn get_location(&self) -> L::DropConsistency {
594        self.collection.location().tick.l.drop_consistency()
595    }
596
597    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
598        let out = self.collection.snapshot_atomic(tick, self.nondet);
599        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
600        out
601    }
602}
603
604impl<'a, K, V, L: Location<'a>> Slicable<'a, L::DropConsistency>
605    for Atomic<
606        crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, BoundedValue>,
607    >
608{
609    type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L::DropConsistency>, Bounded>;
610    type Backtrace = crate::compile::ir::backtrace::Backtrace;
611    fn get_location(&self) -> L::DropConsistency {
612        self.collection.location().tick.l.drop_consistency()
613    }
614
615    fn slice(self, tick: &Tick<L::DropConsistency>, backtrace: Self::Backtrace) -> Self::Slice {
616        let out = self.collection.batch_atomic(tick, self.nondet);
617        out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
618        out
619    }
620}