1use std::marker::PhantomData;
8
9use crate::simulation;
10use crate::simulation::Specs;
11use crate::simulation::Run;
12use crate::simulation::Point;
13use crate::simulation::event::Event;
14use crate::simulation::process::*;
15use crate::simulation::observable::disposable::*;
16use crate::simulation::composite::*;
17
18use dvcompute_utils::grc::Grc;
19
20#[cfg(feature="dist_mode")]
21use crate::simulation::comm::context::LogicalProcessContext;
22
23pub mod ops;
25
26#[inline]
28pub fn return_simulation<T>(val: T) -> Return<T> {
29 Return { val: val }
30}
31
32#[inline]
34pub fn delay_simulation<F, M>(f: F) -> Delay<F, M>
35 where F: FnOnce() -> M,
36 M: Simulation
37{
38 Delay { f: f, _phantom: PhantomData }
39}
40
41#[inline]
43pub fn cons_simulation<F, T>(f: F) -> Cons<F, T>
44 where F: FnOnce(&Run) -> simulation::Result<T>
45{
46 Cons { f: f, _phantom: PhantomData }
47}
48
49#[inline]
51pub fn simulation_sequence<I, M>(comps: I) -> Sequence<I::IntoIter, M>
52 where I: IntoIterator<Item = M>,
53 M: Simulation
54{
55 Sequence { comps: comps.into_iter(), _phantom: PhantomData }
56}
57
58#[inline]
60pub fn simulation_sequence_<I, M>(comps: I) -> Sequence_<I::IntoIter, M>
61 where I: IntoIterator<Item = M>,
62 M: Simulation
63{
64 Sequence_ { comps: comps.into_iter(), _phantom: PhantomData }
65}
66
67pub trait Simulation {
69
70 type Item;
72
73 #[doc(hidden)]
75 fn call_simulation(self, r: &Run) -> simulation::Result<Self::Item>;
76
77 #[inline]
79 fn into_event(self) -> SimulationIntoEvent<Self>
80 where Self: Sized
81 {
82 SimulationIntoEvent { comp: self }
83 }
84
85 #[inline]
87 fn into_process(self) -> SimulationIntoProcess<Self>
88 where Self: Sized
89 {
90 SimulationIntoProcess { comp: self }
91 }
92
93 #[inline]
95 fn into_composite(self) -> SimulationIntoComposite<Self>
96 where Self: Sized
97 {
98 SimulationIntoComposite { comp: self }
99 }
100
101 #[inline]
103 fn and_then<U, F>(self, f: F) -> AndThen<Self, U, F>
104 where Self: Sized,
105 U: Simulation,
106 F: FnOnce(Self::Item) -> U,
107 {
108 AndThen { comp: self, f: f, _phantom: PhantomData }
109 }
110
111 #[inline]
113 fn map<B, F>(self, f: F) -> Map<Self, B, F>
114 where Self: Sized,
115 F: FnOnce(Self::Item) -> B,
116 {
117 Map { comp: self, f: f, _phantom: PhantomData }
118 }
119
120 #[inline]
122 fn zip<U>(self, other: U) -> Zip<Self, U>
123 where Self: Sized,
124 U: Simulation
125 {
126 Zip { comp: self, other: other }
127 }
128
129 #[inline]
131 fn ap<U, B>(self, other: U) -> Ap<Self, U, B>
132 where Self: Sized,
133 Self::Item: FnOnce(U::Item) -> B,
134 U: Simulation
135 {
136 Ap { comp: self, other: other, _phantom: PhantomData }
137 }
138
139 #[inline]
141 fn finally<U>(self, finalization: U) -> Finally<Self, U>
142 where Self: Sized,
143 U: Simulation<Item = ()>
144 {
145 Finally { comp: self, finalization: finalization }
146 }
147
148 #[cfg(feature="dist_mode")]
150 #[inline]
151 fn run(self, specs: Specs, ctx: &LogicalProcessContext) -> simulation::Result<Self::Item>
152 where Self: Sized
153 {
154 let run = Run::new(specs, ctx);
155 self.call_simulation(&run)
156 }
157
158 #[cfg(any(feature="branch_mode", feature="branch_wasm_mode"))]
160 #[inline]
161 fn run(self, specs: Specs) -> simulation::Result<Self::Item>
162 where Self: Sized
163 {
164 let run = Run::new(specs);
165 self.call_simulation(&run)
166 }
167
168 #[cfg(feature="dist_mode")]
170 #[inline]
171 fn run_by_index(self, specs: Specs, ctx: &LogicalProcessContext, run_index: usize, run_count: usize) -> simulation::Result<Self::Item>
172 where Self: Sized
173 {
174 let run = Run::by_index(specs, ctx, run_index, run_count);
175 self.call_simulation(&run)
176 }
177
178 #[cfg(any(feature="branch_mode", feature="branch_wasm_mode"))]
180 #[inline]
181 fn run_by_index(self, specs: Specs, run_index: usize, run_count: usize) -> simulation::Result<Self::Item>
182 where Self: Sized
183 {
184 let run = Run::by_index(specs, run_index, run_count);
185 self.call_simulation(&run)
186 }
187
188 #[inline]
190 fn into_boxed(self) -> SimulationBox<Self::Item>
191 where Self: Sized + Clone + 'static
192 {
193 SimulationBox::new(move |r: &Run| { self.call_simulation(r) })
194 }
195}
196
197pub trait IntoSimulation {
199
200 type Simulation: Simulation<Item = Self::Item>;
202
203 type Item;
205
206 fn into_simulation(self) -> Self::Simulation;
208}
209
210impl<M: Simulation> IntoSimulation for M {
211
212 type Simulation = M;
213
214 type Item = M::Item;
215
216 #[inline]
217 fn into_simulation(self) -> Self::Simulation {
218 self
219 }
220}
221
222#[must_use = "computations are lazy and do nothing unless to be run"]
224pub struct SimulationBox<T> {
225 f: Box<dyn SimulationFnBoxClone<T>>
226}
227
228impl<T> SimulationBox<T> {
229
230 #[doc(hidden)]
232 #[inline]
233 fn new<F>(f: F) -> Self
234 where F: FnOnce(&Run) -> simulation::Result<T> + Clone + 'static
235 {
236 SimulationBox {
237 f: Box::new(f)
238 }
239 }
240
241 #[doc(hidden)]
243 #[inline]
244 pub fn call_box(self, arg: (&Run,)) -> simulation::Result<T> {
245 let SimulationBox { f } = self;
246 f.call_box(arg)
247 }
248}
249
250impl<T> Clone for SimulationBox<T> {
251
252 fn clone(&self) -> Self {
253 SimulationBox {
254 f: self.f.call_clone()
255 }
256 }
257}
258
259impl<T> Simulation for SimulationBox<T> {
260
261 type Item = T;
262
263 #[inline]
264 fn call_simulation(self, r: &Run) -> simulation::Result<Self::Item> {
265 self.call_box((r,))
266 }
267
268 #[inline]
269 fn into_boxed(self) -> SimulationBox<Self::Item>
270 where Self: Sized + Clone + 'static
271 {
272 self
273 }
274}
275
276trait SimulationFnBox<T> {
278
279 fn call_box(self: Box<Self>, args: (&Run,)) -> simulation::Result<T>;
281}
282
283impl<T, F> SimulationFnBox<T> for F
284 where F: for<'a> FnOnce(&'a Run) -> simulation::Result<T>
285{
286 fn call_box(self: Box<Self>, args: (&Run,)) -> simulation::Result<T> {
287 let this: Self = *self;
288 this(args.0)
289 }
290}
291
292trait SimulationFnBoxClone<T>: SimulationFnBox<T> {
294
295 fn call_clone(&self) -> Box<dyn SimulationFnBoxClone<T>>;
297}
298
299impl<T, F> SimulationFnBoxClone<T> for F
300 where F: for<'a> FnOnce(&'a Run) -> simulation::Result<T> + Clone + 'static
301{
302 fn call_clone(&self) -> Box<dyn SimulationFnBoxClone<T>> {
303 Box::new(self.clone())
304 }
305}
306
307#[must_use = "computations are lazy and do nothing unless to be run"]
309#[derive(Clone)]
310pub struct Return<T> {
311
312 val: T
314}
315
316impl<T> Simulation for Return<T> {
317
318 type Item = T;
319
320 #[doc(hidden)]
321 #[inline]
322 fn call_simulation(self, _: &Run) -> simulation::Result<T> {
323 let Return { val } = self;
324 Result::Ok(val)
325 }
326}
327
328#[must_use = "computations are lazy and do nothing unless to be run"]
330#[derive(Clone)]
331pub struct Delay<F, M> {
332
333 f: F,
335
336 _phantom: PhantomData<M>
338}
339
340impl<F, M> Simulation for Delay<F, M>
341 where F: FnOnce() -> M,
342 M: Simulation
343{
344 type Item = M::Item;
345
346 #[doc(hidden)]
347 #[inline]
348 fn call_simulation(self, r: &Run) -> simulation::Result<M::Item> {
349 let Delay { f, _phantom } = self;
350 f().call_simulation(r)
351 }
352}
353
354#[must_use = "computations are lazy and do nothing unless to be run"]
356#[derive(Clone)]
357pub struct Cons<F, T> {
358
359 f: F,
361
362 _phantom: PhantomData<T>
364}
365
366impl<F, T> Simulation for Cons<F, T>
367 where F: FnOnce(&Run) -> simulation::Result<T>
368{
369 type Item = T;
370
371 #[doc(hidden)]
372 #[inline]
373 fn call_simulation(self, r: &Run) -> simulation::Result<T> {
374 let Cons { f, _phantom } = self;
375 f(r)
376 }
377}
378
379#[must_use = "computations are lazy and do nothing unless to be run"]
381#[derive(Clone)]
382pub struct SimulationIntoEvent<M> {
383
384 comp: M
386}
387
388impl<M> Event for SimulationIntoEvent<M>
389 where M: Simulation
390{
391 type Item = M::Item;
392
393 #[doc(hidden)]
394 #[inline]
395 fn call_event(self, p: &Point) -> simulation::Result<M::Item> {
396 let SimulationIntoEvent { comp } = self;
397 comp.call_simulation(p.run)
398 }
399}
400
401#[must_use = "computations are lazy and do nothing unless to be run"]
403#[derive(Clone)]
404pub struct SimulationIntoComposite<M> {
405
406 comp: M
408}
409
410impl<M> Composite for SimulationIntoComposite<M>
411 where M: Simulation
412{
413 type Item = M::Item;
414
415 #[doc(hidden)]
416 #[inline]
417 fn call_composite(self, disposable: DisposableBox, p: &Point) -> simulation::Result<(M::Item, DisposableBox)> {
418 let SimulationIntoComposite { comp } = self;
419 let a = comp.call_simulation(p.run)?;
420 Result::Ok((a, disposable))
421 }
422}
423
424#[must_use = "computations are lazy and do nothing unless to be run"]
426#[derive(Clone)]
427pub struct AndThen<M, U, F> {
428
429 comp: M,
431
432 f: F,
434
435 _phantom: PhantomData<U>
437}
438
439impl<M, U, F> Simulation for AndThen<M, U, F>
440 where M: Simulation,
441 U: Simulation,
442 F: FnOnce(M::Item) -> U
443{
444 type Item = U::Item;
445
446 #[doc(hidden)]
447 #[inline]
448 fn call_simulation(self, r: &Run) -> simulation::Result<U::Item> {
449 let AndThen { comp, f, _phantom } = self;
450 match comp.call_simulation(r) {
451 Result::Ok(a) => {
452 let m = f(a);
453 m.call_simulation(r)
454 },
455 Result::Err(e) => {
456 Result::Err(e)
457 }
458 }
459 }
460}
461
462#[must_use = "computations are lazy and do nothing unless to be run"]
464#[derive(Clone)]
465pub struct Map<M, B, F> {
466
467 comp: M,
469
470 f: F,
472
473 _phantom: PhantomData<B>
475}
476
477impl<M, B, F> Simulation for Map<M, B, F>
478 where M: Simulation,
479 F: FnOnce(M::Item) -> B
480{
481 type Item = B;
482
483 #[doc(hidden)]
484 #[inline]
485 fn call_simulation(self, r: &Run) -> simulation::Result<B> {
486 let Map { comp, f, _phantom } = self;
487 match comp.call_simulation(r) {
488 Result::Ok(a) => Result::Ok(f(a)),
489 Result::Err(e) => Result::Err(e)
490 }
491 }
492}
493
494#[must_use = "computations are lazy and do nothing unless to be run"]
496#[derive(Clone)]
497pub struct Zip<M, U> {
498
499 comp: M,
501
502 other: U,
504}
505
506impl<M, U> Simulation for Zip<M, U>
507 where M: Simulation,
508 U: Simulation
509{
510 type Item = (M::Item, U::Item);
511
512 #[doc(hidden)]
513 #[inline]
514 fn call_simulation(self, r: &Run) -> simulation::Result<(M::Item, U::Item)> {
515 let Zip { comp, other } = self;
516 comp.and_then(move |a| {
517 other.map(move |b| (a, b))
518 }).call_simulation(r)
519 }
520}
521
522#[must_use = "computations are lazy and do nothing unless to be run"]
524#[derive(Clone)]
525pub struct Ap<M, U, B> {
526
527 comp: M,
529
530 other: U,
532
533 _phantom: PhantomData<B>
535}
536
537impl<M, U, B> Simulation for Ap<M, U, B>
538 where M: Simulation,
539 U: Simulation,
540 M::Item: FnOnce(U::Item) -> B
541{
542 type Item = B;
543
544 #[doc(hidden)]
545 #[inline]
546 fn call_simulation(self, r: &Run) -> simulation::Result<B> {
547 let Ap { comp, other, _phantom } = self;
548 comp.and_then(move |f| {
549 other.map(move |a| { f(a) })
550 }).call_simulation(r)
551 }
552}
553
554#[must_use = "computations are lazy and do nothing unless to be run"]
556#[derive(Clone)]
557pub struct Finally<M, U> {
558
559 comp: M,
561
562 finalization: U
564}
565
566impl<M, U> Simulation for Finally<M, U>
567 where M: Simulation,
568 U: Simulation<Item = ()>
569{
570 type Item = M::Item;
571
572 #[doc(hidden)]
573 #[inline]
574 fn call_simulation(self, r: &Run) -> simulation::Result<Self::Item> {
575 let Finally { comp, finalization } = self;
576 let x = comp.call_simulation(r);
577 match finalization.call_simulation(r) {
578 Result::Ok(_) => x,
579 Result::Err(e0) => {
580 match x {
581 Result::Ok(_) => Result::Err(e0),
582 Result::Err(e) => Result::Err(e.merge(&e0))
583 }
584 }
585 }
586 }
587}
588
589#[must_use = "computations are lazy and do nothing unless to be run"]
591#[derive(Clone)]
592pub struct SimulationIntoProcess<M> {
593
594 comp: M
596}
597
598impl<M> Process for SimulationIntoProcess<M>
599 where M: Simulation
600{
601 type Item = M::Item;
602
603 #[doc(hidden)]
604 #[inline]
605 fn call_process<C>(self, cont: C, pid: Grc<ProcessId>, p: &Point) -> simulation::Result<()>
606 where C: FnOnce(simulation::Result<Self::Item>, Grc<ProcessId>, &Point) -> simulation::Result<()> + Clone + 'static
607 {
608 if is_process_cancelled(&pid, p) {
609 revoke_process(cont, pid, p)
610 } else {
611 let SimulationIntoProcess { comp } = self;
612 let t = comp.call_simulation(p.run);
613 cont(t, pid, p)
614 }
615 }
616
617 #[doc(hidden)]
618 #[inline]
619 fn call_process_boxed(self, cont: ProcessBoxCont<Self::Item>, pid: Grc<ProcessId>, p: &Point) -> simulation::Result<()> {
620 if is_process_cancelled(&pid, p) {
621 revoke_process_boxed(cont, pid, p)
622 } else {
623 let SimulationIntoProcess { comp } = self;
624 let t = comp.call_simulation(p.run);
625 cont.call_box((t, pid, p))
626 }
627 }
628}
629
630#[must_use = "computations are lazy and do nothing unless to be run"]
632#[derive(Clone)]
633pub struct Sequence<I, M> {
634
635 comps: I,
637
638 _phantom: PhantomData<M>
640}
641
642impl<I, M> Simulation for Sequence<I, M>
643 where I: Iterator<Item = M>,
644 M: Simulation
645{
646 type Item = Vec<M::Item>;
647
648 #[doc(hidden)]
649 fn call_simulation(self, r: &Run) -> simulation::Result<Self::Item> {
650 let Sequence { comps, _phantom } = self;
651 let mut v = {
652 match comps.size_hint() {
653 (_, Some(n)) => Vec::with_capacity(n),
654 (_, None) => Vec::new()
655 }
656 };
657 for m in comps {
658 match m.call_simulation(r) {
659 Result::Ok(a) => {
660 v.push(a)
661 },
662 Result::Err(e) => {
663 return Result::Err(e)
664 }
665 }
666 }
667 Result::Ok(v)
668 }
669}
670
671#[must_use = "computations are lazy and do nothing unless to be run"]
673#[derive(Clone)]
674pub struct Sequence_<I, M> {
675
676 comps: I,
678
679 _phantom: PhantomData<M>
681}
682
683impl<I, M> Simulation for Sequence_<I, M>
684 where I: Iterator<Item = M>,
685 M: Simulation
686{
687 type Item = ();
688
689 #[doc(hidden)]
690 fn call_simulation(self, r: &Run) -> simulation::Result<Self::Item> {
691 let Sequence_ { comps, _phantom } = self;
692 for m in comps {
693 match m.call_simulation(r) {
694 Result::Ok(_) => (),
695 Result::Err(e) => return Result::Err(e)
696 }
697 }
698 Result::Ok(())
699 }
700}