1use crate::generatable::Generatable;
2use crate::{Collector, Computable, DynAlgorithm, DynGenAlgorithm};
3use cancel_this::Cancellable;
4
5pub trait Stateful<CONTEXT, STATE> {
8 fn configure<I1: Into<CONTEXT>, I2: Into<STATE>>(context: I1, initial_state: I2) -> Self
11 where
12 Self: Sized + 'static,
13 {
14 Self::from_parts(context.into(), initial_state.into())
15 }
16
17 fn from_parts(context: CONTEXT, state: STATE) -> Self
19 where
20 Self: Sized + 'static;
21
22 fn into_parts(self) -> (CONTEXT, STATE);
24
25 fn context(&self) -> &CONTEXT;
27
28 fn state(&self) -> &STATE;
30
31 fn state_mut(&mut self) -> &mut STATE;
37}
38
39pub trait Algorithm<CONTEXT, STATE, OUTPUT>: Computable<OUTPUT> + Stateful<CONTEXT, STATE> {
41 fn run<I1: Into<CONTEXT>, I2: Into<STATE>>(
43 context: I1,
44 initial_state: I2,
45 ) -> Cancellable<OUTPUT>
46 where
47 Self: Sized + 'static,
48 {
49 Self::from_parts(context.into(), initial_state.into()).compute()
50 }
51
52 fn dyn_algorithm(self) -> DynAlgorithm<CONTEXT, STATE, OUTPUT>
54 where
55 Self: Sized + 'static,
56 {
57 Box::new(self)
58 }
59}
60
61pub trait GenAlgorithm<CONTEXT, STATE, OUTPUT>:
63 Generatable<OUTPUT> + Stateful<CONTEXT, STATE>
64{
65 fn computation<COLLECTION: Default + Extend<OUTPUT> + 'static>(
68 self,
69 ) -> impl Computable<COLLECTION>
70 where
71 Self: Sized + 'static,
72 {
73 Collector::<OUTPUT, COLLECTION, Self>::new(self)
74 }
75
76 fn dyn_algorithm(self) -> DynGenAlgorithm<CONTEXT, STATE, OUTPUT>
78 where
79 Self: Sized + 'static,
80 {
81 Box::new(self)
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use crate::{Computation, ComputationStep, Generator, GeneratorStep, Incomplete};
89
90 struct TestComputationStep;
91
92 impl ComputationStep<i32, u32, String> for TestComputationStep {
93 fn step(context: &i32, state: &mut u32) -> crate::Completable<String> {
94 *state += 1;
95 if *state < 2 {
96 Err(Incomplete::Suspended)
97 } else {
98 Ok(format!("done-{}", context))
99 }
100 }
101 }
102
103 #[test]
104 fn test_stateful_from_parts() {
105 let stateful = Computation::<i32, u32, String, TestComputationStep>::from_parts(42, 0);
106 assert_eq!(*stateful.context(), 42);
107 assert_eq!(*stateful.state(), 0);
108 }
109
110 #[test]
111 fn test_stateful_configure() {
112 let stateful = Computation::<i32, u32, String, TestComputationStep>::configure(100, 5u32);
113 assert_eq!(*stateful.context(), 100);
114 assert_eq!(*stateful.state(), 5);
115 }
116
117 #[test]
118 fn test_stateful_into_parts() {
119 let stateful = Computation::<i32, u32, String, TestComputationStep>::from_parts(50, 10);
120 let (context, state) = stateful.into_parts();
121 assert_eq!(context, 50);
122 assert_eq!(state, 10);
123 }
124
125 #[test]
126 fn test_stateful_context() {
127 let stateful = Computation::<i32, u32, String, TestComputationStep>::from_parts(200, 0);
128 assert_eq!(*stateful.context(), 200);
129 }
130
131 #[test]
132 fn test_stateful_state() {
133 let stateful = Computation::<i32, u32, String, TestComputationStep>::from_parts(0, 42);
134 assert_eq!(*stateful.state(), 42);
135 }
136
137 #[test]
138 fn test_stateful_state_mut() {
139 let mut stateful = Computation::<i32, u32, String, TestComputationStep>::from_parts(0, 0);
140 *stateful.state_mut() = 100;
141 assert_eq!(*stateful.state(), 100);
142 }
143
144 #[test]
145 fn test_algorithm_run() {
146 let result = Computation::<i32, u32, String, TestComputationStep>::run(42, 0u32).unwrap();
147 assert_eq!(result, "done-42");
148 }
149
150 #[test]
151 fn test_algorithm_dyn_algorithm() {
152 let algorithm = Computation::<i32, u32, String, TestComputationStep>::from_parts(100, 0);
153 let mut dyn_algorithm = algorithm.dyn_algorithm();
154 let result = dyn_algorithm.compute().unwrap();
155 assert_eq!(result, "done-100");
156 }
157
158 struct TestGeneratorStep;
159
160 impl GeneratorStep<i32, u32, String> for TestGeneratorStep {
161 fn step(context: &i32, state: &mut u32) -> crate::Completable<Option<String>> {
162 *state += 1;
163 if *state <= 2 {
164 Ok(Some(format!("{}-{}", context, state)))
165 } else {
166 Ok(None)
167 }
168 }
169 }
170
171 #[test]
172 fn test_gen_algorithm_computation() {
173 let generator = Generator::<i32, u32, String, TestGeneratorStep>::from_parts(42, 0);
174 let mut computation = generator.computation::<Vec<String>>();
175 let result = computation.compute().unwrap();
176 assert_eq!(result, vec!["42-1", "42-2"]);
177 }
178
179 #[test]
180 fn test_gen_algorithm_computation_hashset() {
181 let generator = Generator::<i32, u32, String, TestGeneratorStep>::from_parts(42, 0);
182 let mut computation = generator.computation::<std::collections::HashSet<String>>();
183 let result = computation.compute().unwrap();
184 assert_eq!(result.len(), 2);
185 assert!(result.contains("42-1"));
186 assert!(result.contains("42-2"));
187 }
188
189 #[test]
190 fn test_gen_algorithm_dyn_algorithm() {
191 let generator = Generator::<i32, u32, String, TestGeneratorStep>::from_parts(100, 0);
192 let mut dyn_algorithm = generator.dyn_algorithm();
193 let item = dyn_algorithm.try_next().unwrap().unwrap();
194 assert_eq!(item, "100-1");
195 }
196
197 #[test]
198 fn test_stateful_configure_with_conversions() {
199 let stateful =
201 Computation::<i32, u32, String, TestComputationStep>::configure(42i16, 10u16);
202 assert_eq!(*stateful.context(), 42i32);
203 assert_eq!(*stateful.state(), 10u32);
204 }
205}