1use std::future::Future;
2
3use crux_core::{Command, Request, capability::Operation, command::RequestBuilder};
4use facet::Facet;
5use serde::{Deserialize, Serialize};
6
7#[derive(Facet, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
9#[repr(C)]
10pub enum DelayOperation {
11 GetRandom(usize, usize),
12 Delay(usize),
13}
14#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
18pub enum DelayOutput {
19 Random(usize),
20 TimeUp,
21}
22impl Operation for DelayOperation {
26 type Output = DelayOutput;
27}
28#[must_use]
33pub fn milliseconds<Effect, Event>(
34 millis: usize,
35) -> RequestBuilder<Effect, Event, impl Future<Output = DelayOutput>>
36where
37 Effect: Send + From<Request<DelayOperation>> + 'static,
38 Event: Send + 'static,
39{
40 Command::request_from_shell(DelayOperation::Delay(millis))
41}
42
43#[must_use]
50pub fn random<Effect, Event>(
51 min: usize,
52 max: usize,
53) -> RequestBuilder<Effect, Event, impl Future<Output = DelayOutput>>
54where
55 Effect: Send + From<Request<DelayOperation>> + 'static,
56 Event: Send + 'static,
57{
58 assert!(min <= max, "min must be less than or equal to max");
59
60 Command::request_from_shell(DelayOperation::GetRandom(min, max)).then_request(|response| {
61 let DelayOutput::Random(millis) = response else {
62 panic!("Expected a random number")
63 };
64
65 Command::request_from_shell(DelayOperation::Delay(millis))
66 })
67}
68#[cfg(test)]
72mod tests {
73 use crux_core::macros::effect;
74
75 use super::*;
76
77 #[effect]
78 pub enum Effect {
79 Delay(DelayOperation),
80 }
81
82 enum Event {
83 Delay(DelayOutput),
84 }
85
86 #[test]
87 fn test_delay() {
88 let delay = 100;
89
90 let mut cmd = milliseconds(delay).then_send(Event::Delay);
91
92 cmd.expect_no_events();
93 let effect = cmd.expect_one_effect();
94 let Effect::Delay(mut request) = effect;
95
96 assert_eq!(request.operation, DelayOperation::Delay(delay));
97
98 request.resolve(DelayOutput::TimeUp).unwrap();
99
100 let event = cmd.events().next().unwrap();
101 let Event::Delay(output) = event;
102 assert_eq!(output, DelayOutput::TimeUp);
103
104 assert!(cmd.is_done());
105 }
106
107 #[test]
108 fn test_random() {
109 let min = 100;
110 let max = 200;
111
112 let mut cmd = random(min, max).then_send(Event::Delay);
113
114 cmd.expect_no_events();
115 let effect = cmd.expect_one_effect();
116 let Effect::Delay(mut request) = effect;
117
118 assert_eq!(request.operation, DelayOperation::GetRandom(min, max));
119 request.resolve(DelayOutput::Random(150)).unwrap();
120
121 cmd.expect_no_events();
122 let effect = cmd.expect_one_effect();
123 let Effect::Delay(mut request) = effect;
124
125 assert_eq!(request.operation, DelayOperation::Delay(150));
126
127 request.resolve(DelayOutput::TimeUp).unwrap();
128
129 let event = cmd.events().next().unwrap();
130 let Event::Delay(output) = event;
131 assert_eq!(output, DelayOutput::TimeUp);
132
133 assert!(cmd.is_done());
134 }
135}
136