1#[fp_macros::document_module]
17mod inner {
18 use {
19 crate::{
20 classes::Deferrable,
21 types::{
22 Lazy,
23 LazyConfig,
24 Trampoline,
25 TryLazy,
26 },
27 },
28 fp_macros::*,
29 };
30
31 #[document_type_parameters("The type of the success value.", "The type of the error value.")]
35 pub struct TryTrampoline<A: 'static, E: 'static>(
37 Trampoline<Result<A, E>>,
39 );
40
41 #[document_type_parameters("The type of the success value.", "The type of the error value.")]
42 #[document_parameters("The fallible trampoline computation.")]
43 impl<A: 'static + Send, E: 'static + Send> TryTrampoline<A, E> {
44 #[document_signature]
46 #[document_parameters("The success value.")]
48 #[document_returns("A `TryTrampoline` representing success.")]
50 #[document_examples]
52 pub fn ok(a: A) -> Self {
60 TryTrampoline(Trampoline::pure(Ok(a)))
61 }
62
63 #[document_signature]
65 #[document_parameters("The error value.")]
67 #[document_returns("A `TryTrampoline` representing failure.")]
69 #[document_examples]
71 pub fn err(e: E) -> Self {
79 TryTrampoline(Trampoline::pure(Err(e)))
80 }
81
82 #[document_signature]
84 #[document_parameters("The closure to execute.")]
86 #[document_returns("A `TryTrampoline` that executes `f` when run.")]
88 #[document_examples]
90 pub fn new(f: impl FnOnce() -> Result<A, E> + 'static) -> Self {
98 TryTrampoline(Trampoline::new(f))
99 }
100
101 #[document_signature]
105 #[document_parameters("A thunk that returns the next step.")]
107 #[document_returns("A `TryTrampoline` that executes `f` to get the next step.")]
109 #[document_examples]
133 pub fn defer(f: impl FnOnce() -> TryTrampoline<A, E> + 'static) -> Self {
141 TryTrampoline(Trampoline::defer(move || f().0))
142 }
143
144 #[document_signature]
146 #[document_type_parameters("The type of the new success value.")]
148 #[document_parameters("The function to apply to the success value.")]
150 #[document_returns("A new `TryTrampoline` with the transformed success value.")]
152 #[document_examples]
154 pub fn map<B: 'static + Send>(
162 self,
163 func: impl FnOnce(A) -> B + 'static,
164 ) -> TryTrampoline<B, E> {
165 TryTrampoline(self.0.map(|result| result.map(func)))
166 }
167
168 #[document_signature]
170 #[document_type_parameters("The type of the new error value.")]
172 #[document_parameters("The function to apply to the error value.")]
174 #[document_returns("A new `TryTrampoline` with the transformed error value.")]
176 #[document_examples]
178 pub fn map_err<E2: 'static + Send>(
187 self,
188 func: impl FnOnce(E) -> E2 + 'static,
189 ) -> TryTrampoline<A, E2> {
190 TryTrampoline(self.0.map(|result| result.map_err(func)))
191 }
192
193 #[document_signature]
195 #[document_type_parameters("The type of the new success value.")]
197 #[document_parameters("The function to apply to the success value.")]
199 #[document_returns("A new `TryTrampoline` that chains `f` after this task.")]
201 #[document_examples]
203 pub fn bind<B: 'static + Send>(
211 self,
212 f: impl FnOnce(A) -> TryTrampoline<B, E> + 'static,
213 ) -> TryTrampoline<B, E> {
214 TryTrampoline(self.0.bind(|result| match result {
215 Ok(a) => f(a).0,
216 Err(e) => Trampoline::pure(Err(e)),
217 }))
218 }
219
220 #[document_signature]
222 #[document_parameters("The function to apply to the error value.")]
224 #[document_returns("A new `TryTrampoline` that attempts to recover from failure.")]
226 #[document_examples]
228 pub fn catch(
237 self,
238 f: impl FnOnce(E) -> TryTrampoline<A, E> + 'static,
239 ) -> Self {
240 TryTrampoline(self.0.bind(|result| match result {
241 Ok(a) => Trampoline::pure(Ok(a)),
242 Err(e) => f(e).0,
243 }))
244 }
245
246 #[document_signature]
248 #[document_returns("The result of the computation.")]
250 #[document_examples]
252 pub fn evaluate(self) -> Result<A, E> {
260 self.0.evaluate()
261 }
262 }
263
264 #[document_type_parameters("The type of the success value.", "The type of the error value.")]
265 impl<A, E> From<Trampoline<A>> for TryTrampoline<A, E>
266 where
267 A: Send + 'static,
268 E: Send + 'static,
269 {
270 #[document_signature]
271 #[document_parameters("The trampoline computation to convert.")]
272 #[document_returns("A new `TryTrampoline` instance that wraps the trampoline.")]
273 #[document_examples]
274 fn from(task: Trampoline<A>) -> Self {
282 TryTrampoline(task.map(Ok))
283 }
284 }
285
286 #[document_type_parameters(
287 "The type of the success value.",
288 "The type of the error value.",
289 "The memoization configuration."
290 )]
291 impl<A, E, Config> From<Lazy<'static, A, Config>> for TryTrampoline<A, E>
292 where
293 A: Clone + Send + 'static,
294 E: Send + 'static,
295 Config: LazyConfig,
296 {
297 #[document_signature]
298 #[document_parameters("The lazy value to convert.")]
299 #[document_returns("A new `TryTrampoline` instance that wraps the lazy value.")]
300 #[document_examples]
301 fn from(memo: Lazy<'static, A, Config>) -> Self {
309 TryTrampoline(Trampoline::pure(Ok(memo.evaluate().clone())))
310 }
311 }
312
313 #[document_type_parameters(
314 "The type of the success value.",
315 "The type of the error value.",
316 "The memoization configuration."
317 )]
318 impl<A, E, Config> From<TryLazy<'static, A, E, Config>> for TryTrampoline<A, E>
319 where
320 A: Clone + Send + 'static,
321 E: Clone + Send + 'static,
322 Config: LazyConfig,
323 {
324 #[document_signature]
325 #[document_parameters("The fallible lazy value to convert.")]
326 #[document_returns("A new `TryTrampoline` instance that wraps the fallible lazy value.")]
327 #[document_examples]
328 fn from(memo: TryLazy<'static, A, E, Config>) -> Self {
336 TryTrampoline(Trampoline::pure(memo.evaluate().cloned().map_err(Clone::clone)))
337 }
338 }
339
340 #[document_type_parameters("The type of the success value.", "The type of the error value.")]
341 impl<A, E> Deferrable<'static> for TryTrampoline<A, E>
342 where
343 A: 'static + Send,
344 E: 'static + Send,
345 {
346 #[document_signature]
348 #[document_parameters("A thunk that produces the value.")]
350 #[document_returns("The deferred value.")]
352 #[document_examples]
354 fn defer(f: impl FnOnce() -> Self + 'static) -> Self
367 where
368 Self: Sized, {
369 TryTrampoline(Trampoline::defer(move || f().0))
370 }
371 }
372}
373pub use inner::*;
374
375#[cfg(test)]
376mod tests {
377 use {
378 super::*,
379 crate::types::Trampoline,
380 };
381
382 #[test]
386 fn test_try_task_ok() {
387 let task: TryTrampoline<i32, String> = TryTrampoline::ok(42);
388 assert_eq!(task.evaluate(), Ok(42));
389 }
390
391 #[test]
395 fn test_try_task_err() {
396 let task: TryTrampoline<i32, String> = TryTrampoline::err("error".to_string());
397 assert_eq!(task.evaluate(), Err("error".to_string()));
398 }
399
400 #[test]
404 fn test_try_task_map() {
405 let task: TryTrampoline<i32, String> = TryTrampoline::ok(10).map(|x| x * 2);
406 assert_eq!(task.evaluate(), Ok(20));
407 }
408
409 #[test]
413 fn test_try_task_map_err() {
414 let task: TryTrampoline<i32, String> =
415 TryTrampoline::err("error".to_string()).map_err(|e| e.to_uppercase());
416 assert_eq!(task.evaluate(), Err("ERROR".to_string()));
417 }
418
419 #[test]
423 fn test_try_task_bind() {
424 let task: TryTrampoline<i32, String> =
425 TryTrampoline::ok(10).bind(|x| TryTrampoline::ok(x * 2));
426 assert_eq!(task.evaluate(), Ok(20));
427 }
428
429 #[test]
433 fn test_try_task_or_else() {
434 let task: TryTrampoline<i32, String> =
435 TryTrampoline::err("error".to_string()).catch(|_| TryTrampoline::ok(42));
436 assert_eq!(task.evaluate(), Ok(42));
437 }
438
439 #[test]
443 fn test_try_task_new() {
444 let task: TryTrampoline<i32, String> = TryTrampoline::new(|| Ok(42));
445 assert_eq!(task.evaluate(), Ok(42));
446 }
447
448 #[test]
450 fn test_try_task_from_task() {
451 let task = Trampoline::pure(42);
452 let try_task: TryTrampoline<i32, String> = TryTrampoline::from(task);
453 assert_eq!(try_task.evaluate(), Ok(42));
454 }
455
456 #[test]
458 fn test_try_task_from_memo() {
459 use crate::types::ArcLazy;
460 let memo = ArcLazy::new(|| 42);
461 let try_task: TryTrampoline<i32, String> = TryTrampoline::from(memo);
462 assert_eq!(try_task.evaluate(), Ok(42));
463 }
464
465 #[test]
467 fn test_try_task_from_try_memo() {
468 use crate::types::ArcTryLazy;
469 let memo = ArcTryLazy::new(|| Ok(42));
470 let try_task: TryTrampoline<i32, String> = TryTrampoline::from(memo);
471 assert_eq!(try_task.evaluate(), Ok(42));
472 }
473}