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 #[document_fields("The internal `Trampoline` wrapping a `Result`.")]
37 pub struct TryTrampoline<A: 'static, E: 'static>(Trampoline<Result<A, E>>);
39
40 #[document_type_parameters("The type of the success value.", "The type of the error value.")]
41 #[document_parameters("The fallible trampoline computation.")]
42 impl<A: 'static + Send, E: 'static + Send> TryTrampoline<A, E> {
43 #[document_signature]
45 #[document_parameters("The success value.")]
47 #[document_returns("A `TryTrampoline` representing success.")]
49 #[document_examples]
51 pub fn ok(a: A) -> Self {
59 TryTrampoline(Trampoline::pure(Ok(a)))
60 }
61
62 #[document_signature]
64 #[document_parameters("The error value.")]
66 #[document_returns("A `TryTrampoline` representing failure.")]
68 #[document_examples]
70 pub fn err(e: E) -> Self {
78 TryTrampoline(Trampoline::pure(Err(e)))
79 }
80
81 #[document_signature]
83 #[document_parameters("The closure to execute.")]
85 #[document_returns("A `TryTrampoline` that executes `f` when run.")]
87 #[document_examples]
89 pub fn new(f: impl FnOnce() -> Result<A, E> + 'static) -> Self {
97 TryTrampoline(Trampoline::new(f))
98 }
99
100 #[document_signature]
104 #[document_parameters("A thunk that returns the next step.")]
106 #[document_returns("A `TryTrampoline` that executes `f` to get the next step.")]
108 #[document_examples]
132 pub fn defer(f: impl FnOnce() -> TryTrampoline<A, E> + 'static) -> Self {
140 TryTrampoline(Trampoline::defer(move || f().0))
141 }
142
143 #[document_signature]
145 #[document_type_parameters("The type of the new success value.")]
147 #[document_parameters("The function to apply to the success value.")]
149 #[document_returns("A new `TryTrampoline` with the transformed success value.")]
151 #[document_examples]
153 pub fn map<B: 'static + Send>(
161 self,
162 func: impl FnOnce(A) -> B + 'static,
163 ) -> TryTrampoline<B, E> {
164 TryTrampoline(self.0.map(|result| result.map(func)))
165 }
166
167 #[document_signature]
169 #[document_type_parameters("The type of the new error value.")]
171 #[document_parameters("The function to apply to the error value.")]
173 #[document_returns("A new `TryTrampoline` with the transformed error value.")]
175 #[document_examples]
177 pub fn map_err<E2: 'static + Send>(
186 self,
187 func: impl FnOnce(E) -> E2 + 'static,
188 ) -> TryTrampoline<A, E2> {
189 TryTrampoline(self.0.map(|result| result.map_err(func)))
190 }
191
192 #[document_signature]
194 #[document_type_parameters("The type of the new success value.")]
196 #[document_parameters("The function to apply to the success value.")]
198 #[document_returns("A new `TryTrampoline` that chains `f` after this task.")]
200 #[document_examples]
202 pub fn bind<B: 'static + Send>(
210 self,
211 f: impl FnOnce(A) -> TryTrampoline<B, E> + 'static,
212 ) -> TryTrampoline<B, E> {
213 TryTrampoline(self.0.bind(|result| match result {
214 Ok(a) => f(a).0,
215 Err(e) => Trampoline::pure(Err(e)),
216 }))
217 }
218
219 #[document_signature]
221 #[document_parameters("The function to apply to the error value.")]
223 #[document_returns("A new `TryTrampoline` that attempts to recover from failure.")]
225 #[document_examples]
227 pub fn catch(
236 self,
237 f: impl FnOnce(E) -> TryTrampoline<A, E> + 'static,
238 ) -> Self {
239 TryTrampoline(self.0.bind(|result| match result {
240 Ok(a) => Trampoline::pure(Ok(a)),
241 Err(e) => f(e).0,
242 }))
243 }
244
245 #[document_signature]
247 #[document_returns("The result of the computation.")]
249 #[document_examples]
251 pub fn evaluate(self) -> Result<A, E> {
259 self.0.evaluate()
260 }
261 }
262
263 #[document_type_parameters("The type of the success value.", "The type of the error value.")]
264 impl<A, E> From<Trampoline<A>> for TryTrampoline<A, E>
265 where
266 A: Send + 'static,
267 E: Send + 'static,
268 {
269 #[document_signature]
270 #[document_parameters("The trampoline computation to convert.")]
271 #[document_returns("A new `TryTrampoline` instance that wraps the trampoline.")]
272 #[document_examples]
273 fn from(task: Trampoline<A>) -> Self {
281 TryTrampoline(task.map(Ok))
282 }
283 }
284
285 #[document_type_parameters(
286 "The type of the success value.",
287 "The type of the error value.",
288 "The memoization configuration."
289 )]
290 impl<A, E, Config> From<Lazy<'static, A, Config>> for TryTrampoline<A, E>
291 where
292 A: Clone + Send + 'static,
293 E: Send + 'static,
294 Config: LazyConfig,
295 {
296 #[document_signature]
297 #[document_parameters("The lazy value to convert.")]
298 #[document_returns("A new `TryTrampoline` instance that wraps the lazy value.")]
299 #[document_examples]
300 fn from(memo: Lazy<'static, A, Config>) -> Self {
308 TryTrampoline(Trampoline::pure(Ok(memo.evaluate().clone())))
309 }
310 }
311
312 #[document_type_parameters(
313 "The type of the success value.",
314 "The type of the error value.",
315 "The memoization configuration."
316 )]
317 impl<A, E, Config> From<TryLazy<'static, A, E, Config>> for TryTrampoline<A, E>
318 where
319 A: Clone + Send + 'static,
320 E: Clone + Send + 'static,
321 Config: LazyConfig,
322 {
323 #[document_signature]
324 #[document_parameters("The fallible lazy value to convert.")]
325 #[document_returns("A new `TryTrampoline` instance that wraps the fallible lazy value.")]
326 #[document_examples]
327 fn from(memo: TryLazy<'static, A, E, Config>) -> Self {
335 TryTrampoline(Trampoline::pure(memo.evaluate().cloned().map_err(Clone::clone)))
336 }
337 }
338
339 #[document_type_parameters("The type of the success value.", "The type of the error value.")]
340 impl<A, E> Deferrable<'static> for TryTrampoline<A, E>
341 where
342 A: 'static + Send,
343 E: 'static + Send,
344 {
345 #[document_signature]
347 #[document_parameters("A thunk that produces the value.")]
349 #[document_returns("The deferred value.")]
351 #[document_examples]
353 fn defer(f: impl FnOnce() -> Self + 'static) -> Self
366 where
367 Self: Sized, {
368 TryTrampoline(Trampoline::defer(move || f().0))
369 }
370 }
371}
372pub use inner::*;
373
374#[cfg(test)]
375mod tests {
376 use {
377 super::*,
378 crate::types::Trampoline,
379 };
380
381 #[test]
385 fn test_try_task_ok() {
386 let task: TryTrampoline<i32, String> = TryTrampoline::ok(42);
387 assert_eq!(task.evaluate(), Ok(42));
388 }
389
390 #[test]
394 fn test_try_task_err() {
395 let task: TryTrampoline<i32, String> = TryTrampoline::err("error".to_string());
396 assert_eq!(task.evaluate(), Err("error".to_string()));
397 }
398
399 #[test]
403 fn test_try_task_map() {
404 let task: TryTrampoline<i32, String> = TryTrampoline::ok(10).map(|x| x * 2);
405 assert_eq!(task.evaluate(), Ok(20));
406 }
407
408 #[test]
412 fn test_try_task_map_err() {
413 let task: TryTrampoline<i32, String> =
414 TryTrampoline::err("error".to_string()).map_err(|e| e.to_uppercase());
415 assert_eq!(task.evaluate(), Err("ERROR".to_string()));
416 }
417
418 #[test]
422 fn test_try_task_bind() {
423 let task: TryTrampoline<i32, String> =
424 TryTrampoline::ok(10).bind(|x| TryTrampoline::ok(x * 2));
425 assert_eq!(task.evaluate(), Ok(20));
426 }
427
428 #[test]
432 fn test_try_task_or_else() {
433 let task: TryTrampoline<i32, String> =
434 TryTrampoline::err("error".to_string()).catch(|_| TryTrampoline::ok(42));
435 assert_eq!(task.evaluate(), Ok(42));
436 }
437
438 #[test]
442 fn test_try_task_new() {
443 let task: TryTrampoline<i32, String> = TryTrampoline::new(|| Ok(42));
444 assert_eq!(task.evaluate(), Ok(42));
445 }
446
447 #[test]
449 fn test_try_task_from_task() {
450 let task = Trampoline::pure(42);
451 let try_task: TryTrampoline<i32, String> = TryTrampoline::from(task);
452 assert_eq!(try_task.evaluate(), Ok(42));
453 }
454
455 #[test]
457 fn test_try_task_from_memo() {
458 use crate::types::ArcLazy;
459 let memo = ArcLazy::new(|| 42);
460 let try_task: TryTrampoline<i32, String> = TryTrampoline::from(memo);
461 assert_eq!(try_task.evaluate(), Ok(42));
462 }
463
464 #[test]
466 fn test_try_task_from_try_memo() {
467 use crate::types::ArcTryLazy;
468 let memo = ArcTryLazy::new(|| Ok(42));
469 let try_task: TryTrampoline<i32, String> = TryTrampoline::from(memo);
470 assert_eq!(try_task.evaluate(), Ok(42));
471 }
472}