computation_process/
computable.rs1use crate::{Completable, DynComputable, Incomplete};
2use cancel_this::Cancellable;
3use serde::{Deserialize, Serialize};
4
5pub trait Computable<T> {
13 fn try_compute(&mut self) -> Completable<T>;
15
16 fn compute_completable(&mut self) -> Completable<T> {
25 loop {
26 match self.try_compute() {
27 Ok(value) => return Ok(value),
28 Err(Incomplete::Suspended) => continue,
29 Err(e) => return Err(e),
30 }
31 }
32 }
33
34 fn compute(&mut self) -> Cancellable<T> {
42 match self.compute_completable() {
43 Ok(value) => Ok(value),
44 Err(Incomplete::Suspended) => unreachable!(
45 "`compute_completable` never returns `Incomplete::Suspended` by definition."
46 ),
47 Err(Incomplete::Cancelled(c)) => Err(c),
48 Err(Incomplete::Exhausted) => panic!("Called `compute` on an exhausted `Computable`."),
49 }
50 }
51
52 fn dyn_computable(self) -> DynComputable<T>
54 where
55 Self: Sized + 'static,
56 {
57 Box::new(self)
58 }
59}
60
61#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
63pub struct ComputableResult<T, C: Computable<T>> {
64 computable: C,
65 result: Option<T>,
66}
67
68impl<T, C: Computable<T>> From<C> for ComputableResult<T, C> {
69 fn from(value: C) -> Self {
70 ComputableResult {
71 computable: value,
72 result: None,
73 }
74 }
75}
76
77impl<T, C: Computable<T>> ComputableResult<T, C> {
78 pub fn new(computable: C) -> Self {
80 computable.into()
81 }
82
83 pub fn try_compute(&mut self) -> Completable<&T> {
86 if self.result.is_none() {
87 let result = self.computable.try_compute()?;
88 self.result = Some(result);
89 }
90
91 if let Some(result) = self.result.as_ref() {
92 return Ok(result);
93 }
94
95 unreachable!("Both `result` and `computable` cannot be `None`.")
96 }
97
98 pub fn result_ref(&self) -> Option<&T> {
100 self.result.as_ref()
101 }
102
103 pub fn result(self) -> Option<T> {
105 self.result
106 }
107
108 pub fn computable_ref(&self) -> &C {
110 &self.computable
111 }
112
113 pub fn computable(self) -> C {
115 self.computable
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use crate::{ComputableIdentity, Incomplete};
123
124 #[test]
125 fn test_computable_result_from() {
126 let identity: ComputableIdentity<i32> = 42.into();
127 let result: ComputableResult<i32, ComputableIdentity<i32>> = identity.into();
128 assert!(result.result_ref().is_none());
129 }
130
131 #[test]
132 fn test_computable_result_new() {
133 let identity: ComputableIdentity<i32> = 100.into();
134 let mut result = ComputableResult::new(identity);
135 assert!(result.result_ref().is_none());
136
137 let computed = result.try_compute().unwrap();
138 assert_eq!(*computed, 100);
139 assert_eq!(result.result_ref(), Some(&100));
140 }
141
142 #[test]
143 fn test_computable_result_try_compute_multiple_times() {
144 let identity: ComputableIdentity<String> = "test".to_string().into();
145 let mut result = ComputableResult::new(identity);
146
147 let first = result.try_compute().unwrap();
148 assert_eq!(*first, "test");
149 let first_ptr = first as *const String;
150
151 let second = result.try_compute().unwrap();
153 assert_eq!(*second, "test");
154 let second_ptr = second as *const String;
155 assert_eq!(first_ptr, second_ptr);
156 }
157
158 #[test]
159 fn test_computable_result_result() {
160 let identity: ComputableIdentity<i32> = 42.into();
161 let mut result = ComputableResult::new(identity);
162 let _ = result.try_compute().unwrap();
163
164 let value = result.result();
165 assert_eq!(value, Some(42));
166 }
167
168 #[test]
169 fn test_computable_result_result_none() {
170 let identity: ComputableIdentity<i32> = 42.into();
171 let result = ComputableResult::new(identity);
172 let value = result.result();
173 assert_eq!(value, None);
174 }
175
176 #[test]
177 fn test_computable_result_computable_ref() {
178 let identity: ComputableIdentity<i32> = 42.into();
179 let result = ComputableResult::new(identity);
180 let _computable_ref = result.computable_ref();
181 }
182
183 #[test]
184 fn test_computable_result_computable() {
185 let identity: ComputableIdentity<i32> = 42.into();
186 let result = ComputableResult::new(identity);
187 let mut computable = result.computable();
188 let value = computable.try_compute().unwrap();
189 assert_eq!(value, 42);
190 }
191
192 #[test]
193 fn test_dyn_computable() {
194 let identity: ComputableIdentity<i32> = 42.into();
195 let mut dyn_computable = identity.dyn_computable();
196 let result = dyn_computable.try_compute().unwrap();
197 assert_eq!(result, 42);
198 }
199
200 #[test]
201 fn test_compute_method() {
202 let mut identity: ComputableIdentity<i32> = 42.into();
203 let result = identity.compute().unwrap();
204 assert_eq!(result, 42);
205 }
206
207 struct SuspendingComputable {
209 count: u32,
210 target: u32,
211 }
212
213 impl Computable<u32> for SuspendingComputable {
214 fn try_compute(&mut self) -> Completable<u32> {
215 self.count += 1;
216 if self.count < self.target {
217 Err(Incomplete::Suspended)
218 } else {
219 Ok(self.count)
220 }
221 }
222 }
223
224 #[test]
225 fn test_compute_with_suspensions() {
226 let mut computable = SuspendingComputable {
227 count: 0,
228 target: 3,
229 };
230 let result = computable.compute().unwrap();
231 assert_eq!(result, 3);
232 }
233
234 #[test]
235 fn test_try_compute_with_suspensions() {
236 let mut computable = SuspendingComputable {
237 count: 0,
238 target: 3,
239 };
240
241 assert_eq!(computable.try_compute(), Err(Incomplete::Suspended));
243 assert_eq!(computable.try_compute(), Err(Incomplete::Suspended));
245 assert_eq!(computable.try_compute(), Ok(3));
247 }
248}