1use super::boundedness::{Bounded, Unbounded};
4use crate::live_collections::boundedness::Boundedness;
5use crate::live_collections::keyed_singleton::BoundedValue;
6use crate::live_collections::stream::{Ordering, Retries};
7use crate::location::{Location, NoTick, Tick};
8use crate::nondet::NonDet;
9
10#[doc(hidden)]
11pub fn __sliced_wrap_invoke<A, B, O: Unslicable>(
12 a: A,
13 b: B,
14 f: impl FnOnce(A, B) -> O,
15) -> O::Unsliced {
16 let o_slice = f(a, b);
17 o_slice.unslice()
18}
19
20#[doc(hidden)]
21#[macro_export]
22macro_rules! __sliced_parse_uses__ {
23 (
25 @uses [$($uses:tt)*]
26 @states [$($states:tt)*]
27 let $name:ident = use $(::$style:ident)?($expr:expr, $nondet:expr); $($rest:tt)*
28 ) => {
29 $crate::__sliced_parse_uses__!(
30 @uses [$($uses)* { $name, ($($style)?), $expr, $nondet }]
31 @states [$($states)*]
32 $($rest)*
33 )
34 };
35
36 (
38 @uses [$($uses:tt)*]
39 @states [$($states:tt)*]
40 let mut $name:ident = use ::$style:ident $(::<$ty:ty>)? ($($args:expr)?); $($rest:tt)*
41 ) => {
42 $crate::__sliced_parse_uses__!(
43 @uses [$($uses)*]
44 @states [$($states)* { $name, $style, (($($ty)?), ($($args)?)) }]
45 $($rest)*
46 )
47 };
48
49 (
51 @uses []
52 @states [$({ $state_name:ident, $state_style:ident, $state_arg:tt })+]
53 $($body:tt)*
54 ) => {
55 {
56 compile_error!("sliced! requires at least one `let name = use(...)` statement to determine the tick")
58 }
59 };
60
61 (
63 @uses [{ $first_name:ident, ($($first_style:ident)?), $first:expr, $nondet_first:expr } $({ $rest_name:ident, ($($rest_style:ident)?), $rest:expr, $nondet_expl:expr })*]
64 @states [$({ $state_name:ident, $state_style:ident, (($($state_ty:ty)?), ($($state_arg:expr)?)) })*]
65 $($body:tt)*
66 ) => {
67 {
68 let _ = $nondet_first;
69 $(let _ = $nondet_expl;)*
70
71 let __styled = (
72 $($crate::live_collections::sliced::style::$first_style)?($first),
73 $($($crate::live_collections::sliced::style::$rest_style)?($rest),)*
74 );
75
76 let __tick = $crate::live_collections::sliced::Slicable::preferred_tick(&__styled).unwrap_or_else(|| $crate::live_collections::sliced::Slicable::get_location(&__styled.0).tick());
77 let __backtraces = {
78 use $crate::compile::ir::backtrace::__macro_get_backtrace;
79 (
80 $crate::macro_support::copy_span::copy_span!($first, {
81 __macro_get_backtrace(1)
82 }),
83 $($crate::macro_support::copy_span::copy_span!($rest, {
84 __macro_get_backtrace(1)
85 }),)*
86 )
87 };
88 let __sliced = $crate::live_collections::sliced::Slicable::slice(__styled, &__tick, __backtraces, $nondet_first);
89 let (
90 $first_name,
91 $($rest_name,)*
92 ) = __sliced;
93
94 let (__handles, __states) = $crate::live_collections::sliced::unzip_cycles((
96 $($crate::live_collections::sliced::style::$state_style$(::<$state_ty, _>)?(& __tick, $($state_arg)?),)*
97 ));
98
99 let (
101 $(mut $state_name,)*
102 ) = __states;
103
104 let __body_result = {
106 $($body)*
107 };
108
109 let __final_states = (
111 $($state_name,)*
112 );
113 $crate::live_collections::sliced::complete_cycles(__handles, __final_states);
114
115 $crate::live_collections::sliced::Unslicable::unslice(__body_result)
117 }
118 };
119}
120
121#[macro_export]
122macro_rules! __sliced__ {
167 ($($tt:tt)*) => {
168 $crate::__sliced_parse_uses__!(
169 @uses []
170 @states []
171 $($tt)*
172 )
173 };
174}
175
176pub use crate::__sliced__ as sliced;
177
178pub fn yield_atomic<T>(t: T) -> style::Atomic<T> {
182 style::Atomic(t)
183}
184
185pub mod style {
187 use super::Slicable;
188 #[cfg(stageleft_runtime)]
189 use crate::forward_handle::{CycleCollection, CycleCollectionWithInitial};
190 use crate::forward_handle::{TickCycle, TickCycleHandle};
191 use crate::live_collections::boundedness::{Bounded, Unbounded};
192 use crate::live_collections::keyed_singleton::BoundedValue;
193 use crate::live_collections::sliced::Unslicable;
194 use crate::live_collections::stream::{Ordering, Retries, Stream};
195 use crate::location::tick::DeferTick;
196 use crate::location::{Location, NoTick, Tick};
197 use crate::nondet::NonDet;
198
199 pub struct Atomic<T>(pub T);
201
202 pub fn atomic<T>(t: T) -> Atomic<T> {
204 Atomic(t)
205 }
206
207 #[cfg(stageleft_runtime)]
215 #[expect(
216 private_bounds,
217 reason = "only Hydro collections can implement CycleCollectionWithInitial"
218 )]
219 pub fn state<
220 'a,
221 S: CycleCollectionWithInitial<'a, TickCycle, Location = Tick<L>>,
222 L: Location<'a> + NoTick,
223 >(
224 tick: &Tick<L>,
225 initial_fn: impl FnOnce(&Tick<L>) -> S,
226 ) -> (TickCycleHandle<'a, S>, S) {
227 let initial = initial_fn(tick);
228 tick.cycle_with_initial(initial)
229 }
230
231 #[cfg(stageleft_runtime)]
236 #[expect(
237 private_bounds,
238 reason = "only Hydro collections can implement CycleCollection"
239 )]
240 pub fn state_null<
241 'a,
242 S: CycleCollection<'a, TickCycle, Location = Tick<L>> + DeferTick,
243 L: Location<'a> + NoTick,
244 >(
245 tick: &Tick<L>,
246 ) -> (TickCycleHandle<'a, S>, S) {
247 tick.cycle::<S>()
248 }
249
250 impl<'a, T, L: Location<'a> + NoTick, O: Ordering, R: Retries> Slicable<'a, L>
251 for Atomic<Stream<T, crate::location::Atomic<L>, Unbounded, O, R>>
252 {
253 type Slice = Stream<T, Tick<L>, Bounded, O, R>;
254 type Backtrace = crate::compile::ir::backtrace::Backtrace;
255
256 fn preferred_tick(&self) -> Option<Tick<L>> {
257 Some(self.0.location().tick.clone())
258 }
259
260 fn get_location(&self) -> &L {
261 panic!("Atomic location has no accessible inner location")
262 }
263
264 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
265 assert_eq!(
266 self.0.location().tick.id(),
267 tick.id(),
268 "Mismatched tick for atomic slicing"
269 );
270
271 let out = self.0.batch_atomic(nondet);
272 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
273 out
274 }
275 }
276
277 impl<'a, T, L: Location<'a> + NoTick, O: Ordering, R: Retries> Unslicable
278 for Atomic<Stream<T, Tick<L>, Bounded, O, R>>
279 {
280 type Unsliced = Stream<T, crate::location::Atomic<L>, Unbounded, O, R>;
281
282 fn unslice(self) -> Self::Unsliced {
283 self.0.all_ticks_atomic()
284 }
285 }
286
287 impl<'a, T, L: Location<'a> + NoTick> Slicable<'a, L>
288 for Atomic<crate::live_collections::Singleton<T, crate::location::Atomic<L>, Unbounded>>
289 {
290 type Slice = crate::live_collections::Singleton<T, Tick<L>, Bounded>;
291 type Backtrace = crate::compile::ir::backtrace::Backtrace;
292
293 fn preferred_tick(&self) -> Option<Tick<L>> {
294 Some(self.0.location().tick.clone())
295 }
296
297 fn get_location(&self) -> &L {
298 panic!("Atomic location has no accessible inner location")
299 }
300
301 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
302 assert_eq!(
303 self.0.location().tick.id(),
304 tick.id(),
305 "Mismatched tick for atomic slicing"
306 );
307
308 let out = self.0.snapshot_atomic(nondet);
309 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
310 out
311 }
312 }
313
314 impl<'a, T, L: Location<'a> + NoTick> Unslicable
315 for Atomic<crate::live_collections::Singleton<T, Tick<L>, Bounded>>
316 {
317 type Unsliced =
318 crate::live_collections::Singleton<T, crate::location::Atomic<L>, Unbounded>;
319
320 fn unslice(self) -> Self::Unsliced {
321 self.0.latest_atomic()
322 }
323 }
324
325 impl<'a, T, L: Location<'a> + NoTick> Slicable<'a, L>
326 for Atomic<crate::live_collections::Optional<T, crate::location::Atomic<L>, Unbounded>>
327 {
328 type Slice = crate::live_collections::Optional<T, Tick<L>, Bounded>;
329 type Backtrace = crate::compile::ir::backtrace::Backtrace;
330
331 fn preferred_tick(&self) -> Option<Tick<L>> {
332 Some(self.0.location().tick.clone())
333 }
334
335 fn get_location(&self) -> &L {
336 panic!("Atomic location has no accessible inner location")
337 }
338
339 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
340 assert_eq!(
341 self.0.location().tick.id(),
342 tick.id(),
343 "Mismatched tick for atomic slicing"
344 );
345
346 let out = self.0.snapshot_atomic(nondet);
347 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
348 out
349 }
350 }
351
352 impl<'a, T, L: Location<'a> + NoTick> Unslicable
353 for Atomic<crate::live_collections::Optional<T, Tick<L>, Bounded>>
354 {
355 type Unsliced = crate::live_collections::Optional<T, crate::location::Atomic<L>, Unbounded>;
356
357 fn unslice(self) -> Self::Unsliced {
358 self.0.latest_atomic()
359 }
360 }
361
362 impl<'a, K, V, L: Location<'a> + NoTick> Slicable<'a, L>
363 for Atomic<
364 crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, Unbounded>,
365 >
366 {
367 type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L>, Bounded>;
368 type Backtrace = crate::compile::ir::backtrace::Backtrace;
369
370 fn preferred_tick(&self) -> Option<Tick<L>> {
371 Some(self.0.location().tick.clone())
372 }
373
374 fn get_location(&self) -> &L {
375 panic!("Atomic location has no accessible inner location")
376 }
377
378 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
379 assert_eq!(
380 self.0.location().tick.id(),
381 tick.id(),
382 "Mismatched tick for atomic slicing"
383 );
384
385 let out = self.0.snapshot_atomic(nondet);
386 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
387 out
388 }
389 }
390
391 impl<'a, K, V, L: Location<'a> + NoTick> Slicable<'a, L>
392 for Atomic<
393 crate::live_collections::KeyedSingleton<K, V, crate::location::Atomic<L>, BoundedValue>,
394 >
395 {
396 type Slice = crate::live_collections::KeyedSingleton<K, V, Tick<L>, Bounded>;
397 type Backtrace = crate::compile::ir::backtrace::Backtrace;
398
399 fn preferred_tick(&self) -> Option<Tick<L>> {
400 Some(self.0.location().tick.clone())
401 }
402
403 fn get_location(&self) -> &L {
404 panic!("Atomic location has no accessible inner location")
405 }
406
407 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
408 assert_eq!(
409 self.0.location().tick.id(),
410 tick.id(),
411 "Mismatched tick for atomic slicing"
412 );
413
414 let out = self.0.batch_atomic(nondet);
415 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
416 out
417 }
418 }
419}
420
421pub trait Slicable<'a, L: Location<'a>> {
423 type Slice;
425
426 type Backtrace;
428
429 fn preferred_tick(&self) -> Option<Tick<L>>;
431
432 fn get_location(&self) -> &L;
434
435 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice;
442}
443
444pub trait Unslicable {
446 type Unsliced;
448
449 fn unslice(self) -> Self::Unsliced;
451}
452
453#[doc(hidden)]
455pub trait UnzipCycles {
456 type Handles;
458 type States;
460
461 fn unzip(self) -> (Self::Handles, Self::States);
463}
464
465#[doc(hidden)]
467pub fn unzip_cycles<T: UnzipCycles>(cycles: T) -> (T::Handles, T::States) {
468 cycles.unzip()
469}
470
471#[doc(hidden)]
473pub trait CompleteCycles<States> {
474 fn complete(self, states: States);
476}
477
478#[doc(hidden)]
480pub fn complete_cycles<H: CompleteCycles<S>, S>(handles: H, states: S) {
481 handles.complete(states);
482}
483
484impl<'a, L: Location<'a>> Slicable<'a, L> for () {
485 type Slice = ();
486 type Backtrace = ();
487
488 fn get_location(&self) -> &L {
489 unreachable!()
490 }
491
492 fn preferred_tick(&self) -> Option<Tick<L>> {
493 None
494 }
495
496 fn slice(self, _tick: &Tick<L>, __backtrace: Self::Backtrace, _nondet: NonDet) -> Self::Slice {}
497}
498
499impl Unslicable for () {
500 type Unsliced = ();
501
502 fn unslice(self) -> Self::Unsliced {}
503}
504
505macro_rules! impl_slicable_for_tuple {
506 ($($T:ident, $T_bt:ident, $idx:tt),+) => {
507 impl<'a, L: Location<'a>, $($T: Slicable<'a, L>),+> Slicable<'a, L> for ($($T,)+) {
508 type Slice = ($($T::Slice,)+);
509 type Backtrace = ($($T::Backtrace,)+);
510
511 fn get_location(&self) -> &L {
512 self.0.get_location()
513 }
514
515 fn preferred_tick(&self) -> Option<Tick<L>> {
516 let mut preferred: Option<Tick<L>> = None;
517 $(
518 if let Some(tick) = self.$idx.preferred_tick() {
519 preferred = Some(match preferred {
520 Some(current) => {
521 if $crate::location::Location::id(¤t) == $crate::location::Location::id(&tick) {
522 current
523 } else {
524 panic!("Mismatched preferred ticks for sliced collections")
525 }
526 },
527 None => tick,
528 });
529 }
530 )+
531 preferred
532 }
533
534 #[expect(non_snake_case, reason = "macro codegen")]
535 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
536 let ($($T,)+) = self;
537 let ($($T_bt,)+) = backtrace;
538 ($($T.slice(tick, $T_bt, nondet),)+)
539 }
540 }
541
542 impl<$($T: Unslicable),+> Unslicable for ($($T,)+) {
543 type Unsliced = ($($T::Unsliced,)+);
544
545 #[expect(non_snake_case, reason = "macro codegen")]
546 fn unslice(self) -> Self::Unsliced {
547 let ($($T,)+) = self;
548 ($($T.unslice(),)+)
549 }
550 }
551 };
552}
553
554#[cfg(stageleft_runtime)]
555impl_slicable_for_tuple!(S1, S1_bt, 0);
556#[cfg(stageleft_runtime)]
557impl_slicable_for_tuple!(S1, S1_bt, 0, S2, S2_bt, 1);
558#[cfg(stageleft_runtime)]
559impl_slicable_for_tuple!(S1, S1_bt, 0, S2, S2_bt, 1, S3, S3_bt, 2);
560#[cfg(stageleft_runtime)]
561impl_slicable_for_tuple!(S1, S1_bt, 0, S2, S2_bt, 1, S3, S3_bt, 2, S4, S4_bt, 3);
562#[cfg(stageleft_runtime)]
563impl_slicable_for_tuple!(
564 S1, S1_bt, 0, S2, S2_bt, 1, S3, S3_bt, 2, S4, S4_bt, 3, S5, S5_bt, 4
565); macro_rules! impl_cycles_for_tuple {
568 ($($H:ident, $S:ident, $idx:tt),*) => {
569 impl<$($H, $S),*> UnzipCycles for ($(($H, $S),)*) {
570 type Handles = ($($H,)*);
571 type States = ($($S,)*);
572
573 #[expect(clippy::allow_attributes, reason = "macro codegen")]
574 #[allow(non_snake_case, reason = "macro codegen")]
575 fn unzip(self) -> (Self::Handles, Self::States) {
576 let ($($H,)*) = self;
577 (
578 ($($H.0,)*),
579 ($($H.1,)*),
580 )
581 }
582 }
583
584 impl<$($H: crate::forward_handle::CompleteCycle<$S>, $S),*> CompleteCycles<($($S,)*)> for ($($H,)*) {
585 #[expect(clippy::allow_attributes, reason = "macro codegen")]
586 #[allow(non_snake_case, reason = "macro codegen")]
587 fn complete(self, states: ($($S,)*)) {
588 let ($($H,)*) = self;
589 let ($($S,)*) = states;
590 $($H.complete_next_tick($S);)*
591 }
592 }
593 };
594}
595
596#[cfg(stageleft_runtime)]
597impl_cycles_for_tuple!();
598#[cfg(stageleft_runtime)]
599impl_cycles_for_tuple!(H1, S1, 0);
600#[cfg(stageleft_runtime)]
601impl_cycles_for_tuple!(H1, S1, 0, H2, S2, 1);
602#[cfg(stageleft_runtime)]
603impl_cycles_for_tuple!(H1, S1, 0, H2, S2, 1, H3, S3, 2);
604#[cfg(stageleft_runtime)]
605impl_cycles_for_tuple!(H1, S1, 0, H2, S2, 1, H3, S3, 2, H4, S4, 3);
606#[cfg(stageleft_runtime)]
607impl_cycles_for_tuple!(H1, S1, 0, H2, S2, 1, H3, S3, 2, H4, S4, 3, H5, S5, 4);
608
609impl<'a, T, L: Location<'a>, B: Boundedness, O: Ordering, R: Retries> Slicable<'a, L>
610 for super::Stream<T, L, B, O, R>
611{
612 type Slice = super::Stream<T, Tick<L>, Bounded, O, R>;
613 type Backtrace = crate::compile::ir::backtrace::Backtrace;
614
615 fn get_location(&self) -> &L {
616 self.location()
617 }
618
619 fn preferred_tick(&self) -> Option<Tick<L>> {
620 None
621 }
622
623 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
624 let out = self.batch(tick, nondet);
625 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
626 out
627 }
628}
629
630impl<'a, T, L: Location<'a>, O: Ordering, R: Retries> Unslicable
631 for super::Stream<T, Tick<L>, Bounded, O, R>
632{
633 type Unsliced = super::Stream<T, L, Unbounded, O, R>;
634
635 fn unslice(self) -> Self::Unsliced {
636 self.all_ticks()
637 }
638}
639
640impl<'a, T, L: Location<'a>, B: Boundedness> Slicable<'a, L> for super::Singleton<T, L, B> {
641 type Slice = super::Singleton<T, Tick<L>, Bounded>;
642 type Backtrace = crate::compile::ir::backtrace::Backtrace;
643
644 fn get_location(&self) -> &L {
645 self.location()
646 }
647
648 fn preferred_tick(&self) -> Option<Tick<L>> {
649 None
650 }
651
652 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
653 let out = self.snapshot(tick, nondet);
654 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
655 out
656 }
657}
658
659impl<'a, T, L: Location<'a>> Unslicable for super::Singleton<T, Tick<L>, Bounded> {
660 type Unsliced = super::Singleton<T, L, Unbounded>;
661
662 fn unslice(self) -> Self::Unsliced {
663 self.latest()
664 }
665}
666
667impl<'a, T, L: Location<'a>> Slicable<'a, L> for super::Optional<T, L, Unbounded> {
668 type Slice = super::Optional<T, Tick<L>, Bounded>;
669 type Backtrace = crate::compile::ir::backtrace::Backtrace;
670
671 fn get_location(&self) -> &L {
672 self.location()
673 }
674
675 fn preferred_tick(&self) -> Option<Tick<L>> {
676 None
677 }
678
679 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
680 let out = self.snapshot(tick, nondet);
681 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
682 out
683 }
684}
685
686impl<'a, T, L: Location<'a>> Unslicable for super::Optional<T, Tick<L>, Bounded> {
687 type Unsliced = super::Optional<T, L, Unbounded>;
688
689 fn unslice(self) -> Self::Unsliced {
690 self.latest()
691 }
692}
693
694impl<'a, K, V, L: Location<'a>, O: Ordering, R: Retries> Slicable<'a, L>
695 for super::KeyedStream<K, V, L, Unbounded, O, R>
696{
697 type Slice = super::KeyedStream<K, V, Tick<L>, Bounded, O, R>;
698 type Backtrace = crate::compile::ir::backtrace::Backtrace;
699
700 fn get_location(&self) -> &L {
701 self.location()
702 }
703
704 fn preferred_tick(&self) -> Option<Tick<L>> {
705 None
706 }
707
708 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
709 let out = self.batch(tick, nondet);
710 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
711 out
712 }
713}
714
715impl<'a, K, V, L: Location<'a>, O: Ordering, R: Retries> Unslicable
716 for super::KeyedStream<K, V, Tick<L>, Bounded, O, R>
717{
718 type Unsliced = super::KeyedStream<K, V, L, Unbounded, O, R>;
719
720 fn unslice(self) -> Self::Unsliced {
721 self.all_ticks()
722 }
723}
724
725impl<'a, K, V, L: Location<'a>> Slicable<'a, L> for super::KeyedSingleton<K, V, L, Unbounded> {
726 type Slice = super::KeyedSingleton<K, V, Tick<L>, Bounded>;
727 type Backtrace = crate::compile::ir::backtrace::Backtrace;
728
729 fn get_location(&self) -> &L {
730 self.location()
731 }
732
733 fn preferred_tick(&self) -> Option<Tick<L>> {
734 None
735 }
736
737 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
738 let out = self.snapshot(tick, nondet);
739 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
740 out
741 }
742}
743
744impl<'a, K, V, L: Location<'a> + NoTick> Slicable<'a, L>
745 for super::KeyedSingleton<K, V, L, BoundedValue>
746{
747 type Slice = super::KeyedSingleton<K, V, Tick<L>, Bounded>;
748 type Backtrace = crate::compile::ir::backtrace::Backtrace;
749
750 fn get_location(&self) -> &L {
751 self.location()
752 }
753
754 fn preferred_tick(&self) -> Option<Tick<L>> {
755 None
756 }
757
758 fn slice(self, tick: &Tick<L>, backtrace: Self::Backtrace, nondet: NonDet) -> Self::Slice {
759 let out = self.batch(tick, nondet);
760 out.ir_node.borrow_mut().op_metadata_mut().backtrace = backtrace;
761 out
762 }
763}
764
765#[cfg(feature = "sim")]
766#[cfg(test)]
767mod tests {
768 use stageleft::q;
769
770 use super::sliced;
771 use crate::location::Location;
772 use crate::nondet::nondet;
773 use crate::prelude::FlowBuilder;
774
775 #[test]
779 fn sim_state_counter() {
780 let flow = FlowBuilder::new();
781 let node = flow.process::<()>();
782
783 let (input_send, input) = node.sim_input::<i32, _, _>();
784
785 let out_recv = sliced! {
786 let batch = use(input, nondet!());
787 let mut counter = use::state(|l| l.singleton(q!(0)));
788
789 let new_count = counter.clone().zip(batch.count())
790 .map(q!(|(old, add)| old + add));
791 counter = new_count.clone();
792 new_count.into_stream()
793 }
794 .sim_output();
795
796 flow.sim().exhaustive(async || {
797 input_send.send(1);
798 assert_eq!(out_recv.next().await.unwrap(), 1);
799
800 input_send.send(1);
801 assert_eq!(out_recv.next().await.unwrap(), 2);
802
803 input_send.send(1);
804 assert_eq!(out_recv.next().await.unwrap(), 3);
805 });
806 }
807
808 #[cfg(feature = "sim")]
810 #[test]
811 fn sim_state_null_optional() {
812 use crate::live_collections::Optional;
813 use crate::live_collections::boundedness::Bounded;
814 use crate::location::{Location, Tick};
815
816 let flow = FlowBuilder::new();
817 let node = flow.process::<()>();
818
819 let (input_send, input) = node.sim_input::<i32, _, _>();
820
821 let out_recv = sliced! {
822 let batch = use(input, nondet!());
823 let mut prev = use::state_null::<Optional<i32, Tick<_>, Bounded>>();
824
825 let output = prev.clone().unwrap_or(prev.location().singleton(q!(-1)));
827 prev = batch.first();
829 output.into_stream()
830 }
831 .sim_output();
832
833 flow.sim().exhaustive(async || {
834 input_send.send(10);
835 assert_eq!(out_recv.next().await.unwrap(), -1);
837
838 input_send.send(20);
839 assert_eq!(out_recv.next().await.unwrap(), 10);
841
842 input_send.send(30);
843 assert_eq!(out_recv.next().await.unwrap(), 20);
845 });
846 }
847}