1#[fp_macros::document_module]
42mod inner {
43 use {
44 crate::{
45 Apply,
46 brands::TryLazyBrand,
47 classes::{
48 Deferrable,
49 LazyConfig,
50 LiftFn,
51 Monoid,
52 RefFoldable,
53 RefFoldableWithIndex,
54 RefFunctor,
55 Semigroup,
56 SendDeferrable,
57 SendRefFunctor,
58 WithIndex,
59 },
60 impl_kind,
61 kinds::*,
62 types::{
63 ArcLazyConfig,
64 Lazy,
65 RcLazyConfig,
66 TrySendThunk,
67 TryThunk,
68 TryTrampoline,
69 },
70 },
71 fp_macros::*,
72 std::{
73 fmt,
74 hash::{
75 Hash,
76 Hasher,
77 },
78 },
79 };
80
81 #[document_type_parameters(
101 "The lifetime of the computation.",
102 "The type of the computed value.",
103 "The type of the error.",
104 "The memoization configuration."
105 )]
106 pub struct TryLazy<'a, A, E, Config: LazyConfig = RcLazyConfig>(
112 pub(crate) Lazy<'a, Result<A, E>, Config>,
114 )
115 where
116 A: 'a,
117 E: 'a;
118
119 #[document_type_parameters(
122 "The lifetime of the computation.",
123 "The type of the computed value.",
124 "The type of the error.",
125 "The memoization configuration."
126 )]
127 #[document_parameters("The instance to clone.")]
128 impl<'a, A, E, Config: LazyConfig> Clone for TryLazy<'a, A, E, Config>
129 where
130 A: 'a,
131 E: 'a,
132 {
133 #[document_signature]
134 #[document_returns(
135 "A new `TryLazy` instance that shares the same underlying memoized result."
136 )]
137 #[document_examples]
138 fn clone(&self) -> Self {
146 Self(self.0.clone())
147 }
148 }
149
150 #[document_type_parameters(
153 "The lifetime of the computation.",
154 "The type of the computed value.",
155 "The type of the error.",
156 "The memoization configuration."
157 )]
158 #[document_parameters("The `TryLazy` instance.")]
159 impl<'a, A, E, Config: LazyConfig> TryLazy<'a, A, E, Config>
160 where
161 A: 'a,
162 E: 'a,
163 {
164 #[document_signature]
174 #[document_returns("A result containing a reference to the value or error.")]
176 #[document_examples]
178 #[inline]
186 pub fn evaluate(&self) -> Result<&A, &E> {
187 self.0.evaluate().as_ref()
188 }
189 }
190
191 #[document_type_parameters(
194 "The lifetime of the computation.",
195 "The type of the computed value.",
196 "The type of the error."
197 )]
198 #[document_parameters("The try-lazy cell instance.")]
199 impl<'a, A, E> TryLazy<'a, A, E, RcLazyConfig>
200 where
201 A: 'a,
202 E: 'a,
203 {
204 #[document_signature]
206 #[document_parameters("The closure that produces the result.")]
208 #[document_returns("A new `TryLazy` instance.")]
210 #[document_examples]
212 #[inline]
220 pub fn new(f: impl FnOnce() -> Result<A, E> + 'a) -> Self {
221 TryLazy(Lazy::<'a, Result<A, E>, RcLazyConfig>::new(f))
222 }
223
224 #[document_signature]
226 #[document_parameters("The success value to wrap.")]
228 #[document_returns("A new `TryLazy` instance that evaluates to `Ok(&a)`.")]
230 #[document_examples]
232 #[inline]
240 pub fn ok(a: A) -> Self {
241 Self::new(move || Ok(a))
242 }
243
244 #[document_signature]
246 #[document_parameters("The error value to wrap.")]
248 #[document_returns("A new `TryLazy` instance that evaluates to `Err(&e)`.")]
250 #[document_examples]
252 #[inline]
260 pub fn err(e: E) -> Self {
261 Self::new(move || Err(e))
262 }
263
264 #[document_signature]
269 #[document_returns("An owned `Result` clone of the memoized value.")]
271 #[document_examples]
273 #[inline]
282 pub fn evaluate_owned(&self) -> Result<A, E>
283 where
284 A: Clone,
285 E: Clone, {
286 self.evaluate().cloned().map_err(|e| e.clone())
287 }
288
289 #[document_signature]
300 #[document_type_parameters("The type of the mapped success value.")]
302 #[document_parameters("The function to apply to the success value.")]
304 #[document_returns("A new `RcTryLazy` that applies `f` to the success value of this cell.")]
306 #[document_examples]
308 #[inline]
317 pub fn map<B: 'a>(
318 self,
319 f: impl FnOnce(&A) -> B + 'a,
320 ) -> RcTryLazy<'a, B, E>
321 where
322 E: Clone + 'a, {
323 RcTryLazy::new(move || match self.evaluate() {
324 Ok(a) => Ok(f(a)),
325 Err(e) => Err(e.clone()),
326 })
327 }
328
329 #[document_signature]
345 #[document_type_parameters("The type of the mapped success value.")]
346 #[document_parameters("The function to apply to the success value.")]
347 #[document_returns("A new `RcTryLazy` that applies `f` to the success value of this cell.")]
348 #[document_examples]
349 #[inline]
358 pub fn ref_map<B: 'a>(
359 &self,
360 f: impl Fn(&A) -> B + 'a,
361 ) -> RcTryLazy<'a, B, E>
362 where
363 E: Clone + 'a, {
364 let this = self.clone();
365 RcTryLazy::new(move || match this.evaluate() {
366 Ok(a) => Ok(f(a)),
367 Err(e) => Err(e.clone()),
368 })
369 }
370
371 #[document_signature]
382 #[document_type_parameters("The type of the mapped error value.")]
384 #[document_parameters("The function to apply to the error value.")]
386 #[document_returns("A new `RcTryLazy` that applies `f` to the error value of this cell.")]
388 #[document_examples]
390 #[inline]
399 pub fn map_err<E2: 'a>(
400 self,
401 f: impl FnOnce(&E) -> E2 + 'a,
402 ) -> RcTryLazy<'a, A, E2>
403 where
404 A: Clone + 'a, {
405 RcTryLazy::new(move || match self.evaluate() {
406 Ok(a) => Ok(a.clone()),
407 Err(e) => Err(f(e)),
408 })
409 }
410
411 #[document_signature]
419 #[document_type_parameters(
421 "The type of the mapped success value.",
422 "The type of the mapped error value."
423 )]
424 #[document_parameters(
426 "The function to apply to the success value.",
427 "The function to apply to the error value."
428 )]
429 #[document_returns(
431 "A new `RcTryLazy` that applies `f` to the success value or `g` to the error value of this cell."
432 )]
433 #[document_examples]
435 #[inline]
448 pub fn bimap<B: 'a, F: 'a>(
449 self,
450 f: impl FnOnce(&A) -> B + 'a,
451 g: impl FnOnce(&E) -> F + 'a,
452 ) -> RcTryLazy<'a, B, F> {
453 RcTryLazy::new(move || match self.evaluate() {
454 Ok(a) => Ok(f(a)),
455 Err(e) => Err(g(e)),
456 })
457 }
458 }
459
460 #[document_type_parameters(
463 "The lifetime of the computation.",
464 "The type of the computed value.",
465 "The type of the error."
466 )]
467 impl<'a, A, E> From<TryThunk<'a, A, E>> for TryLazy<'a, A, E, RcLazyConfig> {
468 #[document_signature]
469 #[document_parameters("The fallible thunk to convert.")]
470 #[document_returns(
471 "A new `TryLazy` instance that will evaluate the thunk on first access."
472 )]
473 #[document_examples]
474 fn from(eval: TryThunk<'a, A, E>) -> Self {
482 Self::new(move || eval.evaluate())
483 }
484 }
485
486 #[document_type_parameters(
487 "The lifetime of the computation.",
488 "The type of the computed value.",
489 "The type of the error."
490 )]
491 impl<'a, A, E> From<TryTrampoline<A, E>> for TryLazy<'a, A, E, RcLazyConfig> {
492 #[document_signature]
493 #[document_parameters("The fallible trampoline to convert.")]
494 #[document_returns(
495 "A new `TryLazy` instance that will evaluate the trampoline on first access."
496 )]
497 #[document_examples]
498 fn from(task: TryTrampoline<A, E>) -> Self {
506 Self::new(move || task.evaluate())
507 }
508 }
509
510 #[document_type_parameters(
511 "The lifetime of the computation.",
512 "The type of the computed value.",
513 "The type of the error."
514 )]
515 impl<'a, A, E> From<Lazy<'a, A, RcLazyConfig>> for TryLazy<'a, A, E, RcLazyConfig>
516 where
517 A: Clone + 'a,
518 E: 'a,
519 {
520 #[document_signature]
521 #[document_parameters("The lazy value to convert.")]
522 #[document_returns("A new `TryLazy` instance that wraps the lazy value.")]
523 #[document_examples]
524 fn from(memo: Lazy<'a, A, RcLazyConfig>) -> Self {
532 Self::new(move || Ok(memo.evaluate().clone()))
533 }
534 }
535
536 #[document_type_parameters(
537 "The lifetime of the computation.",
538 "The type of the computed value.",
539 "The type of the error."
540 )]
541 impl<'a, A: 'a, E: 'a> From<Result<A, E>> for TryLazy<'a, A, E, RcLazyConfig> {
542 #[document_signature]
543 #[document_parameters("The result to convert.")]
544 #[document_returns("A new `TryLazy` instance that produces the result.")]
545 #[document_examples]
546 fn from(result: Result<A, E>) -> Self {
556 Self::new(move || result)
557 }
558 }
559
560 #[document_type_parameters(
563 "The lifetime of the computation.",
564 "The type of the computed value.",
565 "The type of the error."
566 )]
567 impl<'a, A, E> From<TryThunk<'a, A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
568 where
569 A: Send + Sync + 'a,
570 E: Send + Sync + 'a,
571 {
572 #[document_signature]
577 #[document_parameters("The fallible thunk to convert.")]
578 #[document_returns("A new `TryLazy` instance containing the eagerly evaluated result.")]
579 #[document_examples]
580 fn from(eval: TryThunk<'a, A, E>) -> Self {
588 let result = eval.evaluate();
589 Self::new(move || result)
590 }
591 }
592
593 #[document_type_parameters(
594 "The lifetime of the computation.",
595 "The type of the computed value.",
596 "The type of the error."
597 )]
598 impl<'a, A, E> From<TryTrampoline<A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
599 where
600 A: Send + Sync + 'static,
601 E: Send + Sync + 'static,
602 {
603 #[document_signature]
608 #[document_parameters("The fallible trampoline to convert.")]
609 #[document_returns("A new `TryLazy` instance containing the eagerly evaluated result.")]
610 #[document_examples]
611 fn from(task: TryTrampoline<A, E>) -> Self {
619 let result = task.evaluate();
620 Self::new(move || result)
621 }
622 }
623
624 #[document_type_parameters(
625 "The lifetime of the computation.",
626 "The type of the computed value.",
627 "The type of the error."
628 )]
629 impl<'a, A, E> From<Lazy<'a, A, ArcLazyConfig>> for TryLazy<'a, A, E, ArcLazyConfig>
630 where
631 A: Clone + Send + Sync + 'a,
632 E: Send + Sync + 'a,
633 {
634 #[document_signature]
635 #[document_parameters("The thread-safe lazy value to convert.")]
636 #[document_returns("A new `TryLazy` instance that wraps the lazy value.")]
637 #[document_examples]
638 fn from(memo: Lazy<'a, A, ArcLazyConfig>) -> Self {
646 Self::new(move || Ok(memo.evaluate().clone()))
647 }
648 }
649
650 #[document_type_parameters(
651 "The lifetime of the computation.",
652 "The type of the computed value.",
653 "The type of the error."
654 )]
655 impl<'a, A, E> From<Result<A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
656 where
657 A: Send + Sync + 'a,
658 E: Send + Sync + 'a,
659 {
660 #[document_signature]
661 #[document_parameters("The result to convert.")]
662 #[document_returns("A new `TryLazy` instance that produces the result.")]
663 #[document_examples]
664 fn from(result: Result<A, E>) -> Self {
674 Self::new(move || result)
675 }
676 }
677
678 #[document_type_parameters(
679 "The lifetime of the computation.",
680 "The type of the computed value.",
681 "The type of the error."
682 )]
683 impl<'a, A, E> From<TrySendThunk<'a, A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
684 where
685 A: Send + Sync + 'a,
686 E: Send + Sync + 'a,
687 {
688 #[document_signature]
694 #[document_parameters("The fallible send thunk to convert.")]
695 #[document_returns("A thread-safe `ArcTryLazy` that evaluates the thunk on first access.")]
696 #[document_examples]
697 fn from(thunk: TrySendThunk<'a, A, E>) -> Self {
705 thunk.into_arc_try_lazy()
706 }
707 }
708
709 #[document_type_parameters(
712 "The lifetime of the computation.",
713 "The type of the computed value.",
714 "The type of the error."
715 )]
716 impl<'a, A: Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a>
717 From<TryLazy<'a, A, E, RcLazyConfig>> for TryLazy<'a, A, E, ArcLazyConfig>
718 {
719 #[document_signature]
725 #[document_parameters("The `RcTryLazy` instance to convert.")]
726 #[document_returns(
727 "A new `ArcTryLazy` instance containing a clone of the eagerly evaluated result."
728 )]
729 #[document_examples]
730 fn from(source: TryLazy<'a, A, E, RcLazyConfig>) -> Self {
743 let result: Result<A, E> = source.evaluate().cloned().map_err(Clone::clone);
744 Self::new(move || result)
745 }
746 }
747
748 #[document_type_parameters(
749 "The lifetime of the computation.",
750 "The type of the computed value.",
751 "The type of the error."
752 )]
753 impl<'a, A: Clone + 'a, E: Clone + 'a> From<TryLazy<'a, A, E, ArcLazyConfig>>
754 for TryLazy<'a, A, E, RcLazyConfig>
755 {
756 #[document_signature]
762 #[document_parameters("The `ArcTryLazy` instance to convert.")]
763 #[document_returns(
764 "A new `RcTryLazy` instance containing a clone of the eagerly evaluated result."
765 )]
766 #[document_examples]
767 fn from(source: TryLazy<'a, A, E, ArcLazyConfig>) -> Self {
780 let result: Result<A, E> = source.evaluate().cloned().map_err(Clone::clone);
781 Self::new(move || result)
782 }
783 }
784
785 #[document_type_parameters(
788 "The lifetime of the computation.",
789 "The type of the computed value.",
790 "The type of the error value."
791 )]
792 impl<'a, A: 'a, E: 'a> TryLazy<'a, A, E, RcLazyConfig> {
793 #[document_signature]
800 #[document_parameters(
802 "The closure that might panic.",
803 "The function that converts a panic payload into the error type."
804 )]
805 #[document_returns(
807 "A new `TryLazy` instance where panics are converted to `Err(E)` via the handler."
808 )]
809 #[document_examples]
811 pub fn catch_unwind_with(
827 f: impl FnOnce() -> A + std::panic::UnwindSafe + 'a,
828 handler: impl FnOnce(Box<dyn std::any::Any + Send>) -> E + 'a,
829 ) -> Self {
830 Self::new(move || std::panic::catch_unwind(f).map_err(handler))
831 }
832 }
833
834 #[document_type_parameters(
835 "The lifetime of the computation.",
836 "The type of the computed value."
837 )]
838 impl<'a, A> TryLazy<'a, A, String, RcLazyConfig>
839 where
840 A: 'a,
841 {
842 #[document_signature]
847 #[document_parameters("The closure that might panic.")]
849 #[document_returns("A new `TryLazy` instance where panics are converted to `Err(String)`.")]
851 #[document_examples]
853 pub fn catch_unwind(f: impl FnOnce() -> A + std::panic::UnwindSafe + 'a) -> Self {
866 Self::catch_unwind_with(f, crate::utils::panic_payload_to_string)
867 }
868 }
869
870 #[document_type_parameters(
873 "The lifetime of the computation.",
874 "The type of the computed value.",
875 "The type of the error."
876 )]
877 #[document_parameters("The `TryLazy` instance.")]
878 impl<'a, A, E> TryLazy<'a, A, E, RcLazyConfig>
879 where
880 A: Clone + 'a,
881 E: Clone + 'a,
882 {
883 #[document_signature]
893 #[document_type_parameters("The type of the new success value.")]
895 #[document_parameters("The fallible function to apply to the success value.")]
897 #[document_returns("A new `TryLazy` containing the chained result.")]
899 #[document_examples]
901 pub fn and_then<B: 'a>(
910 self,
911 f: impl FnOnce(&A) -> Result<B, E> + 'a,
912 ) -> TryLazy<'a, B, E, RcLazyConfig> {
913 let fa = self;
914 TryLazy::<'a, B, E, RcLazyConfig>::new(move || match fa.evaluate() {
915 Ok(a) => f(a),
916 Err(e) => Err(e.clone()),
917 })
918 }
919
920 #[document_signature]
926 #[document_parameters("The recovery function to apply to the error value.")]
928 #[document_returns("A new `TryLazy` containing the recovered result.")]
930 #[document_examples]
932 pub fn or_else(
941 self,
942 f: impl FnOnce(&E) -> Result<A, E> + 'a,
943 ) -> TryLazy<'a, A, E, RcLazyConfig> {
944 let fa = self;
945 TryLazy::<'a, A, E, RcLazyConfig>::new(move || match fa.evaluate() {
946 Ok(a) => Ok(a.clone()),
947 Err(e) => f(e),
948 })
949 }
950 }
951
952 #[document_type_parameters(
955 "The lifetime of the computation.",
956 "The type of the computed value.",
957 "The type of the error."
958 )]
959 #[document_parameters("The try-lazy cell instance.")]
960 impl<'a, A, E> TryLazy<'a, A, E, ArcLazyConfig>
961 where
962 A: Send + Sync + 'a,
963 E: Send + Sync + 'a,
964 {
965 #[document_signature]
967 #[document_parameters("The closure that produces the result.")]
969 #[document_returns("A new `TryLazy` instance.")]
971 #[document_examples]
973 #[inline]
981 pub fn new(f: impl FnOnce() -> Result<A, E> + Send + 'a) -> Self {
982 TryLazy(Lazy::<'a, Result<A, E>, ArcLazyConfig>::new(f))
983 }
984
985 #[document_signature]
987 #[document_parameters("The success value to wrap.")]
989 #[document_returns("A new `ArcTryLazy` instance that evaluates to `Ok(&a)`.")]
991 #[document_examples]
993 #[inline]
1001 pub fn ok(a: A) -> Self {
1002 Self::new(move || Ok(a))
1003 }
1004
1005 #[document_signature]
1007 #[document_parameters("The error value to wrap.")]
1009 #[document_returns("A new `ArcTryLazy` instance that evaluates to `Err(&e)`.")]
1011 #[document_examples]
1013 #[inline]
1021 pub fn err(e: E) -> Self {
1022 Self::new(move || Err(e))
1023 }
1024
1025 #[document_signature]
1031 #[document_returns("An owned `Result` clone of the memoized value.")]
1033 #[document_examples]
1035 #[inline]
1044 pub fn evaluate_owned(&self) -> Result<A, E>
1045 where
1046 A: Clone,
1047 E: Clone, {
1048 self.evaluate().cloned().map_err(|e| e.clone())
1049 }
1050
1051 #[document_signature]
1057 #[document_type_parameters("The type of the mapped success value.")]
1059 #[document_parameters("The function to apply to the success value.")]
1061 #[document_returns(
1063 "A new `ArcTryLazy` that applies `f` to the success value of this cell."
1064 )]
1065 #[document_examples]
1067 #[inline]
1076 pub fn map<B: Send + Sync + 'a>(
1077 self,
1078 f: impl FnOnce(&A) -> B + Send + 'a,
1079 ) -> ArcTryLazy<'a, B, E>
1080 where
1081 E: Clone, {
1082 ArcTryLazy::new(move || match self.evaluate() {
1083 Ok(a) => Ok(f(a)),
1084 Err(e) => Err(e.clone()),
1085 })
1086 }
1087
1088 #[document_signature]
1109 #[document_type_parameters("The type of the mapped success value.")]
1110 #[document_parameters("The function to apply to the success value.")]
1111 #[document_returns(
1112 "A new `ArcTryLazy` that applies `f` to the success value of this cell."
1113 )]
1114 #[document_examples]
1115 #[inline]
1124 pub fn ref_map<B: Send + Sync + 'a>(
1125 &self,
1126 f: impl Fn(&A) -> B + Send + 'a,
1127 ) -> ArcTryLazy<'a, B, E>
1128 where
1129 E: Clone, {
1130 let this = self.clone();
1131 ArcTryLazy::new(move || match this.evaluate() {
1132 Ok(a) => Ok(f(a)),
1133 Err(e) => Err(e.clone()),
1134 })
1135 }
1136
1137 #[document_signature]
1143 #[document_type_parameters("The type of the mapped error value.")]
1145 #[document_parameters("The function to apply to the error value.")]
1147 #[document_returns("A new `ArcTryLazy` that applies `f` to the error value of this cell.")]
1149 #[document_examples]
1151 #[inline]
1160 pub fn map_err<E2: Send + Sync + 'a>(
1161 self,
1162 f: impl FnOnce(&E) -> E2 + Send + 'a,
1163 ) -> ArcTryLazy<'a, A, E2>
1164 where
1165 A: Clone, {
1166 ArcTryLazy::new(move || match self.evaluate() {
1167 Ok(a) => Ok(a.clone()),
1168 Err(e) => Err(f(e)),
1169 })
1170 }
1171
1172 #[document_signature]
1181 #[document_type_parameters(
1183 "The type of the mapped success value.",
1184 "The type of the mapped error value."
1185 )]
1186 #[document_parameters(
1188 "The function to apply to the success value.",
1189 "The function to apply to the error value."
1190 )]
1191 #[document_returns(
1193 "A new `ArcTryLazy` that applies `f` to the success value or `g` to the error value of this cell."
1194 )]
1195 #[document_examples]
1197 #[inline]
1210 pub fn bimap<B: Send + Sync + 'a, F: Send + Sync + 'a>(
1211 self,
1212 f: impl FnOnce(&A) -> B + Send + 'a,
1213 g: impl FnOnce(&E) -> F + Send + 'a,
1214 ) -> ArcTryLazy<'a, B, F> {
1215 ArcTryLazy::new(move || match self.evaluate() {
1216 Ok(a) => Ok(f(a)),
1217 Err(e) => Err(g(e)),
1218 })
1219 }
1220 }
1221
1222 #[document_type_parameters(
1225 "The lifetime of the computation.",
1226 "The type of the computed value.",
1227 "The type of the error value."
1228 )]
1229 impl<'a, A: Send + Sync + 'a, E: Send + Sync + 'a> TryLazy<'a, A, E, ArcLazyConfig> {
1230 #[document_signature]
1237 #[document_parameters(
1239 "The closure that might panic.",
1240 "The function that converts a panic payload into the error type."
1241 )]
1242 #[document_returns(
1244 "A new `ArcTryLazy` instance where panics are converted to `Err(E)` via the handler."
1245 )]
1246 #[document_examples]
1248 pub fn catch_unwind_with(
1264 f: impl FnOnce() -> A + std::panic::UnwindSafe + Send + 'a,
1265 handler: impl FnOnce(Box<dyn std::any::Any + Send>) -> E + Send + 'a,
1266 ) -> Self {
1267 Self::new(move || std::panic::catch_unwind(f).map_err(handler))
1268 }
1269 }
1270
1271 #[document_type_parameters(
1272 "The lifetime of the computation.",
1273 "The type of the computed value."
1274 )]
1275 impl<'a, A> TryLazy<'a, A, String, ArcLazyConfig>
1276 where
1277 A: Send + Sync + 'a,
1278 {
1279 #[document_signature]
1288 #[document_parameters("The closure that might panic.")]
1290 #[document_returns(
1292 "A new `ArcTryLazy` instance where panics are converted to `Err(String)`."
1293 )]
1294 #[document_examples]
1296 pub fn catch_unwind(f: impl FnOnce() -> A + std::panic::UnwindSafe + Send + 'a) -> Self {
1309 Self::catch_unwind_with(f, crate::utils::panic_payload_to_string)
1310 }
1311 }
1312
1313 #[document_type_parameters(
1316 "The lifetime of the computation.",
1317 "The type of the computed value.",
1318 "The type of the error."
1319 )]
1320 #[document_parameters("The `TryLazy` instance.")]
1321 impl<'a, A, E> TryLazy<'a, A, E, ArcLazyConfig>
1322 where
1323 A: Clone + Send + Sync + 'a,
1324 E: Clone + Send + Sync + 'a,
1325 {
1326 #[document_signature]
1336 #[document_type_parameters("The type of the new success value.")]
1338 #[document_parameters("The fallible function to apply to the success value.")]
1340 #[document_returns("A new `ArcTryLazy` containing the chained result.")]
1342 #[document_examples]
1344 pub fn and_then<B: Send + Sync + 'a>(
1353 self,
1354 f: impl FnOnce(&A) -> Result<B, E> + Send + 'a,
1355 ) -> TryLazy<'a, B, E, ArcLazyConfig> {
1356 let fa = self;
1357 TryLazy::<'a, B, E, ArcLazyConfig>::new(move || match fa.evaluate() {
1358 Ok(a) => f(a),
1359 Err(e) => Err(e.clone()),
1360 })
1361 }
1362
1363 #[document_signature]
1369 #[document_parameters("The recovery function to apply to the error value.")]
1371 #[document_returns("A new `ArcTryLazy` containing the recovered result.")]
1373 #[document_examples]
1375 pub fn or_else(
1384 self,
1385 f: impl FnOnce(&E) -> Result<A, E> + Send + 'a,
1386 ) -> TryLazy<'a, A, E, ArcLazyConfig> {
1387 let fa = self;
1388 TryLazy::<'a, A, E, ArcLazyConfig>::new(move || match fa.evaluate() {
1389 Ok(a) => Ok(a.clone()),
1390 Err(e) => f(e),
1391 })
1392 }
1393 }
1394
1395 #[document_type_parameters(
1398 "The lifetime of the computation.",
1399 "The type of the computed value.",
1400 "The type of the error."
1401 )]
1402 impl<'a, A, E> Deferrable<'a> for TryLazy<'a, A, E, RcLazyConfig>
1403 where
1404 A: Clone + 'a,
1405 E: Clone + 'a,
1406 {
1407 #[document_signature]
1412 #[document_parameters("The thunk that produces the lazy value.")]
1414 #[document_returns("A new `TryLazy` value.")]
1416 #[document_examples]
1418 fn defer(f: impl FnOnce() -> Self + 'a) -> Self
1431 where
1432 Self: Sized, {
1433 Self::new(move || match f().evaluate() {
1434 Ok(a) => Ok(a.clone()),
1435 Err(e) => Err(e.clone()),
1436 })
1437 }
1438 }
1439
1440 #[document_type_parameters(
1441 "The lifetime of the computation.",
1442 "The type of the computed value.",
1443 "The type of the error."
1444 )]
1445 impl<'a, A, E> SendDeferrable<'a> for TryLazy<'a, A, E, ArcLazyConfig>
1446 where
1447 A: Clone + Send + Sync + 'a,
1448 E: Clone + Send + Sync + 'a,
1449 {
1450 #[document_signature]
1455 #[document_parameters("The thunk that produces the lazy value.")]
1457 #[document_returns("A new `ArcTryLazy` value.")]
1459 #[document_examples]
1461 fn send_defer(f: impl FnOnce() -> Self + Send + 'a) -> Self
1473 where
1474 Self: Sized, {
1475 Self::new(move || match f().evaluate() {
1476 Ok(a) => Ok(a.clone()),
1477 Err(e) => Err(e.clone()),
1478 })
1479 }
1480 }
1481
1482 pub type RcTryLazy<'a, A, E> = TryLazy<'a, A, E, RcLazyConfig>;
1486
1487 pub type ArcTryLazy<'a, A, E> = TryLazy<'a, A, E, ArcLazyConfig>;
1489
1490 impl_kind! {
1493 impl<E: 'static, Config: LazyConfig> for TryLazyBrand<E, Config> {
1494 #[document_default]
1495 type Of<'a, A: 'a>: 'a = TryLazy<'a, A, E, Config>;
1496 }
1497 }
1498
1499 #[document_type_parameters(
1502 "The lifetime of the computation.",
1503 "The success value type.",
1504 "The type of the error."
1505 )]
1506 impl<'a, A: Semigroup + Clone + 'a, E: Clone + 'a> Semigroup for TryLazy<'a, A, E, RcLazyConfig> {
1507 #[document_signature]
1512 #[document_parameters("The first `TryLazy`.", "The second `TryLazy`.")]
1514 #[document_returns("A new `RcTryLazy` containing the combined result.")]
1516 #[document_examples]
1518 fn append(
1532 a: Self,
1533 b: Self,
1534 ) -> Self {
1535 RcTryLazy::new(move || {
1536 let a_val = match a.evaluate() {
1537 Ok(v) => v.clone(),
1538 Err(e) => return Err(e.clone()),
1539 };
1540 let b_val = match b.evaluate() {
1541 Ok(v) => v.clone(),
1542 Err(e) => return Err(e.clone()),
1543 };
1544 Ok(Semigroup::append(a_val, b_val))
1545 })
1546 }
1547 }
1548
1549 #[document_type_parameters(
1550 "The lifetime of the computation.",
1551 "The success value type.",
1552 "The type of the error."
1553 )]
1554 impl<'a, A: Semigroup + Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a> Semigroup
1555 for TryLazy<'a, A, E, ArcLazyConfig>
1556 {
1557 #[document_signature]
1562 #[document_parameters("The first `ArcTryLazy`.", "The second `ArcTryLazy`.")]
1564 #[document_returns("A new `ArcTryLazy` containing the combined result.")]
1566 #[document_examples]
1568 fn append(
1582 a: Self,
1583 b: Self,
1584 ) -> Self {
1585 ArcTryLazy::new(move || {
1586 let a_val = match a.evaluate() {
1587 Ok(v) => v.clone(),
1588 Err(e) => return Err(e.clone()),
1589 };
1590 let b_val = match b.evaluate() {
1591 Ok(v) => v.clone(),
1592 Err(e) => return Err(e.clone()),
1593 };
1594 Ok(Semigroup::append(a_val, b_val))
1595 })
1596 }
1597 }
1598
1599 #[document_type_parameters("The error type.", "The memoization configuration.")]
1602 impl<E: 'static, Config: LazyConfig> RefFoldable for TryLazyBrand<E, Config> {
1603 #[document_signature]
1608 #[document_type_parameters(
1609 "The lifetime of the computation.",
1610 "The brand of the cloneable function to use.",
1611 "The type of the elements.",
1612 "The monoid type."
1613 )]
1614 #[document_parameters("The mapping function.", "The TryLazy to fold.")]
1615 #[document_returns("The monoid value.")]
1616 #[document_examples]
1617 fn ref_fold_map<'a, FnBrand, A: 'a + Clone, M>(
1633 func: impl Fn(&A) -> M + 'a,
1634 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1635 ) -> M
1636 where
1637 FnBrand: LiftFn + 'a,
1638 M: Monoid + 'a, {
1639 match fa.evaluate() {
1640 Ok(a) => func(a),
1641 Err(_) => Monoid::empty(),
1642 }
1643 }
1644
1645 #[document_signature]
1647 #[document_type_parameters(
1648 "The lifetime of the computation.",
1649 "The brand of the cloneable function to use.",
1650 "The type of the elements.",
1651 "The type of the accumulator."
1652 )]
1653 #[document_parameters(
1654 "The function to apply to each element reference and the accumulator.",
1655 "The initial value of the accumulator.",
1656 "The TryLazy to fold."
1657 )]
1658 #[document_returns("The final accumulator value.")]
1659 #[document_examples]
1660 fn ref_fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
1677 func: impl Fn(&A, B) -> B + 'a,
1678 initial: B,
1679 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1680 ) -> B
1681 where
1682 FnBrand: LiftFn + 'a, {
1683 match fa.evaluate() {
1684 Ok(a) => func(a, initial),
1685 Err(_) => initial,
1686 }
1687 }
1688
1689 #[document_signature]
1691 #[document_type_parameters(
1692 "The lifetime of the computation.",
1693 "The brand of the cloneable function to use.",
1694 "The type of the elements.",
1695 "The type of the accumulator."
1696 )]
1697 #[document_parameters(
1698 "The function to apply to the accumulator and each element reference.",
1699 "The initial value of the accumulator.",
1700 "The TryLazy to fold."
1701 )]
1702 #[document_returns("The final accumulator value.")]
1703 #[document_examples]
1704 fn ref_fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
1721 func: impl Fn(B, &A) -> B + 'a,
1722 initial: B,
1723 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1724 ) -> B
1725 where
1726 FnBrand: LiftFn + 'a, {
1727 match fa.evaluate() {
1728 Ok(a) => func(initial, a),
1729 Err(_) => initial,
1730 }
1731 }
1732 }
1733
1734 #[document_type_parameters("The error type.", "The memoization configuration.")]
1737 impl<E: 'static, Config: LazyConfig> WithIndex for TryLazyBrand<E, Config> {
1738 type Index = ();
1739 }
1740
1741 #[document_type_parameters("The error type.", "The memoization configuration.")]
1744 impl<E: 'static, Config: LazyConfig> RefFoldableWithIndex for TryLazyBrand<E, Config> {
1745 #[document_signature]
1747 #[document_type_parameters(
1748 "The lifetime of the computation.",
1749 "The brand of the cloneable function to use.",
1750 "The type of the computed value.",
1751 "The monoid type."
1752 )]
1753 #[document_parameters(
1754 "The function to apply to the index and the value reference.",
1755 "The TryLazy to fold."
1756 )]
1757 #[document_returns("The monoid value.")]
1758 #[document_examples]
1759 fn ref_fold_map_with_index<'a, FnBrand, A: 'a + Clone, R: Monoid + 'a>(
1776 f: impl Fn((), &A) -> R + 'a,
1777 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1778 ) -> R
1779 where
1780 FnBrand: LiftFn + 'a, {
1781 match fa.evaluate() {
1782 Ok(a) => f((), a),
1783 Err(_) => Monoid::empty(),
1784 }
1785 }
1786 }
1787
1788 #[document_type_parameters("The type of the error.")]
1791 impl<E: 'static + Clone> RefFunctor for TryLazyBrand<E, RcLazyConfig> {
1792 #[document_signature]
1797 #[document_type_parameters(
1799 "The lifetime of the values.",
1800 "The type of the success value.",
1801 "The type of the result."
1802 )]
1803 #[document_parameters(
1805 "The function to apply to the success value.",
1806 "The memoized fallible value."
1807 )]
1808 #[document_returns("A new memoized fallible value containing the mapped result.")]
1810 #[document_examples]
1812 fn ref_map<'a, A: 'a, B: 'a>(
1825 f: impl Fn(&A) -> B + 'a,
1826 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1827 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1828 fa.ref_map(f)
1829 }
1830 }
1831
1832 #[document_type_parameters("The type of the error.")]
1835 impl<E: 'static + Clone + Send + Sync> SendRefFunctor for TryLazyBrand<E, ArcLazyConfig> {
1836 #[document_signature]
1841 #[document_type_parameters(
1843 "The lifetime of the values.",
1844 "The type of the success value.",
1845 "The type of the result."
1846 )]
1847 #[document_parameters(
1849 "The function to apply to the success value.",
1850 "The memoized fallible value."
1851 )]
1852 #[document_returns("A new memoized fallible value containing the mapped result.")]
1854 #[document_examples]
1856 fn send_ref_map<'a, A: Send + Sync + 'a, B: Send + Sync + 'a>(
1869 f: impl Fn(&A) -> B + Send + 'a,
1870 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1871 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1872 fa.ref_map(f)
1873 }
1874 }
1875
1876 #[document_type_parameters(
1879 "The lifetime of the computation.",
1880 "The type of the computed value.",
1881 "The type of the error."
1882 )]
1883 impl<'a, A: Monoid + Clone + 'a, E: Clone + 'a> Monoid for TryLazy<'a, A, E, RcLazyConfig> {
1884 #[document_signature]
1886 #[document_returns("An `RcTryLazy` producing the identity value wrapped in `Ok`.")]
1888 #[document_examples]
1890 fn empty() -> Self {
1901 RcTryLazy::new(|| Ok(Monoid::empty()))
1902 }
1903 }
1904
1905 #[document_type_parameters(
1906 "The lifetime of the computation.",
1907 "The type of the computed value.",
1908 "The type of the error."
1909 )]
1910 impl<'a, A: Monoid + Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a> Monoid
1911 for TryLazy<'a, A, E, ArcLazyConfig>
1912 {
1913 #[document_signature]
1915 #[document_returns("An `ArcTryLazy` producing the identity value wrapped in `Ok`.")]
1917 #[document_examples]
1919 fn empty() -> Self {
1930 ArcTryLazy::new(|| Ok(Monoid::empty()))
1931 }
1932 }
1933
1934 #[document_type_parameters(
1937 "The lifetime of the computation.",
1938 "The type of the computed value.",
1939 "The type of the error.",
1940 "The memoization configuration."
1941 )]
1942 #[document_parameters("The try-lazy value to hash.")]
1943 impl<'a, A: Hash + 'a, E: Hash + 'a, Config: LazyConfig> Hash for TryLazy<'a, A, E, Config> {
1944 #[document_signature]
1946 #[document_type_parameters("The type of the hasher.")]
1947 #[document_parameters("The hasher state.")]
1949 #[document_examples]
1951 fn hash<H: Hasher>(
1983 &self,
1984 state: &mut H,
1985 ) {
1986 self.0.evaluate().hash(state)
1987 }
1988 }
1989
1990 #[document_type_parameters(
1993 "The lifetime of the computation.",
1994 "The type of the computed value.",
1995 "The type of the error.",
1996 "The memoization configuration."
1997 )]
1998 #[document_parameters("The try-lazy value to compare.")]
1999 impl<'a, A: PartialEq + 'a, E: PartialEq + 'a, Config: LazyConfig> PartialEq
2000 for TryLazy<'a, A, E, Config>
2001 {
2002 #[document_signature]
2006 #[document_parameters("The other try-lazy value to compare with.")]
2007 #[document_returns("`true` if the evaluated results are equal.")]
2008 #[document_examples]
2009 fn eq(
2018 &self,
2019 other: &Self,
2020 ) -> bool {
2021 self.0.evaluate() == other.0.evaluate()
2022 }
2023 }
2024
2025 #[document_type_parameters(
2028 "The lifetime of the computation.",
2029 "The type of the computed value.",
2030 "The type of the error.",
2031 "The memoization configuration."
2032 )]
2033 impl<'a, A: Eq + 'a, E: Eq + 'a, Config: LazyConfig> Eq for TryLazy<'a, A, E, Config> {}
2034
2035 #[document_type_parameters(
2038 "The lifetime of the computation.",
2039 "The type of the computed value.",
2040 "The type of the error.",
2041 "The memoization configuration."
2042 )]
2043 #[document_parameters("The try-lazy value to compare.")]
2044 impl<'a, A: PartialOrd + 'a, E: PartialOrd + 'a, Config: LazyConfig> PartialOrd
2045 for TryLazy<'a, A, E, Config>
2046 {
2047 #[document_signature]
2051 #[document_parameters("The other try-lazy value to compare with.")]
2052 #[document_returns(
2053 "The ordering between the evaluated results, or `None` if not comparable."
2054 )]
2055 #[document_examples]
2056 fn partial_cmp(
2065 &self,
2066 other: &Self,
2067 ) -> Option<std::cmp::Ordering> {
2068 self.0.evaluate().partial_cmp(other.0.evaluate())
2069 }
2070 }
2071
2072 #[document_type_parameters(
2075 "The lifetime of the computation.",
2076 "The type of the computed value.",
2077 "The type of the error.",
2078 "The memoization configuration."
2079 )]
2080 #[document_parameters("The try-lazy value to compare.")]
2081 impl<'a, A: Ord + 'a, E: Ord + 'a, Config: LazyConfig> Ord for TryLazy<'a, A, E, Config> {
2082 #[document_signature]
2086 #[document_parameters("The other try-lazy value to compare with.")]
2087 #[document_returns("The ordering between the evaluated results.")]
2088 #[document_examples]
2089 fn cmp(
2098 &self,
2099 other: &Self,
2100 ) -> std::cmp::Ordering {
2101 self.0.evaluate().cmp(other.0.evaluate())
2102 }
2103 }
2104
2105 #[document_type_parameters(
2108 "The lifetime of the computation.",
2109 "The type of the computed value.",
2110 "The type of the error.",
2111 "The memoization configuration."
2112 )]
2113 #[document_parameters("The try-lazy value to display.")]
2114 impl<'a, A: fmt::Display + 'a, E: fmt::Display + 'a, Config: LazyConfig> fmt::Display
2115 for TryLazy<'a, A, E, Config>
2116 {
2117 #[document_signature]
2119 #[document_parameters("The formatter.")]
2121 #[document_returns("The formatting result.")]
2123 #[document_examples]
2125 fn fmt(
2142 &self,
2143 f: &mut fmt::Formatter<'_>,
2144 ) -> fmt::Result {
2145 match self.evaluate() {
2146 Ok(a) => write!(f, "Ok({})", a),
2147 Err(e) => write!(f, "Err({})", e),
2148 }
2149 }
2150 }
2151
2152 #[document_type_parameters(
2155 "The lifetime of the computation.",
2156 "The type of the computed value.",
2157 "The type of the error.",
2158 "The memoization configuration."
2159 )]
2160 #[document_parameters("The try-lazy value to format.")]
2161 impl<'a, A, E, Config: LazyConfig> fmt::Debug for TryLazy<'a, A, E, Config>
2162 where
2163 A: 'a,
2164 E: 'a,
2165 {
2166 #[document_signature]
2168 #[document_parameters("The formatter.")]
2169 #[document_returns("The formatting result.")]
2170 #[document_examples]
2171 fn fmt(
2178 &self,
2179 f: &mut fmt::Formatter<'_>,
2180 ) -> fmt::Result {
2181 f.write_str("TryLazy(..)")
2182 }
2183 }
2184
2185 #[document_signature]
2199 #[document_type_parameters(
2201 "The lifetime of the computation.",
2202 "The type of the computed value.",
2203 "The type of the error."
2204 )]
2205 #[document_parameters(
2207 "The function that receives a fallible lazy self-reference and produces the result."
2208 )]
2209 #[document_returns("A new `RcTryLazy` instance.")]
2211 #[document_examples]
2213 pub fn rc_try_lazy_fix<'a, A: Clone + 'a, E: Clone + 'a>(
2224 f: impl FnOnce(RcTryLazy<'a, A, E>) -> Result<A, E> + 'a
2225 ) -> RcTryLazy<'a, A, E> {
2226 use crate::types::lazy::rc_lazy_fix;
2227
2228 TryLazy(rc_lazy_fix(move |inner| {
2229 let self_ref = TryLazy(inner);
2230 f(self_ref)
2231 }))
2232 }
2233
2234 #[document_signature]
2246 #[document_type_parameters(
2248 "The lifetime of the computation.",
2249 "The type of the computed value.",
2250 "The type of the error."
2251 )]
2252 #[document_parameters(
2254 "The function that receives a fallible lazy self-reference and produces the result."
2255 )]
2256 #[document_returns("A new `ArcTryLazy` instance.")]
2258 #[document_examples]
2260 pub fn arc_try_lazy_fix<'a, A: Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a>(
2271 f: impl FnOnce(ArcTryLazy<'a, A, E>) -> Result<A, E> + Send + 'a
2272 ) -> ArcTryLazy<'a, A, E> {
2273 use crate::types::lazy::arc_lazy_fix;
2274
2275 TryLazy(arc_lazy_fix(move |inner| {
2276 let self_ref = TryLazy(inner);
2277 f(self_ref)
2278 }))
2279 }
2280}
2281pub use inner::*;
2282
2283#[cfg(test)]
2284#[expect(
2285 clippy::unwrap_used,
2286 clippy::panic,
2287 reason = "Tests use panicking operations for brevity and clarity"
2288)]
2289mod tests {
2290 use {
2291 super::*,
2292 crate::{
2293 brands::{
2294 RcFnBrand,
2295 TryLazyBrand,
2296 },
2297 types::{
2298 ArcLazyConfig,
2299 RcLazy,
2300 RcLazyConfig,
2301 TrySendThunk,
2302 TryThunk,
2303 TryTrampoline,
2304 },
2305 },
2306 quickcheck_macros::quickcheck,
2307 std::{
2308 cell::RefCell,
2309 rc::Rc,
2310 sync::Arc,
2311 },
2312 };
2313
2314 #[test]
2318 fn test_try_memo_caching_ok() {
2319 let counter = Rc::new(RefCell::new(0));
2320 let counter_clone = counter.clone();
2321 let memo: RcTryLazy<i32, ()> = RcTryLazy::new(move || {
2322 *counter_clone.borrow_mut() += 1;
2323 Ok(42)
2324 });
2325
2326 assert_eq!(*counter.borrow(), 0);
2327 assert_eq!(memo.evaluate(), Ok(&42));
2328 assert_eq!(*counter.borrow(), 1);
2329 assert_eq!(memo.evaluate(), Ok(&42));
2330 assert_eq!(*counter.borrow(), 1);
2331 }
2332
2333 #[test]
2337 fn test_try_memo_caching_err() {
2338 let counter = Rc::new(RefCell::new(0));
2339 let counter_clone = counter.clone();
2340 let memo: RcTryLazy<i32, i32> = RcTryLazy::new(move || {
2341 *counter_clone.borrow_mut() += 1;
2342 Err(0)
2343 });
2344
2345 assert_eq!(*counter.borrow(), 0);
2346 assert_eq!(memo.evaluate(), Err(&0));
2347 assert_eq!(*counter.borrow(), 1);
2348 assert_eq!(memo.evaluate(), Err(&0));
2349 assert_eq!(*counter.borrow(), 1);
2350 }
2351
2352 #[test]
2356 fn test_try_memo_sharing() {
2357 let counter = Rc::new(RefCell::new(0));
2358 let counter_clone = counter.clone();
2359 let memo: RcTryLazy<i32, ()> = RcTryLazy::new(move || {
2360 *counter_clone.borrow_mut() += 1;
2361 Ok(42)
2362 });
2363 let shared = memo.clone();
2364
2365 assert_eq!(memo.evaluate(), Ok(&42));
2366 assert_eq!(*counter.borrow(), 1);
2367 assert_eq!(shared.evaluate(), Ok(&42));
2368 assert_eq!(*counter.borrow(), 1);
2369 }
2370
2371 #[test]
2375 fn test_catch_unwind() {
2376 let memo = RcTryLazy::catch_unwind(|| {
2377 if true {
2378 panic!("oops")
2379 }
2380 42
2381 });
2382
2383 match memo.evaluate() {
2384 Err(e) => assert_eq!(e, "oops"),
2385 Ok(_) => panic!("Should have failed"),
2386 }
2387 }
2388
2389 #[test]
2391 fn test_try_memo_from_try_eval() {
2392 let eval = TryThunk::new(|| Ok::<i32, ()>(42));
2393 let memo = RcTryLazy::from(eval);
2394 assert_eq!(memo.evaluate(), Ok(&42));
2395 }
2396
2397 #[test]
2399 fn test_try_memo_from_try_task() {
2400 let task = TryTrampoline::<i32, ()>::ok(42);
2401 let memo = RcTryLazy::from(task);
2402 assert_eq!(memo.evaluate(), Ok(&42));
2403 }
2404
2405 #[test]
2407 fn test_try_memo_from_rc_memo() {
2408 let memo = RcLazy::new(|| 42);
2409 let try_memo: crate::types::RcTryLazy<i32, ()> = crate::types::RcTryLazy::from(memo);
2410 assert_eq!(try_memo.evaluate(), Ok(&42));
2411 }
2412
2413 #[test]
2415 fn test_try_memo_from_arc_memo() {
2416 use crate::types::ArcLazy;
2417 let memo = ArcLazy::new(|| 42);
2418 let try_memo: crate::types::ArcTryLazy<i32, ()> = crate::types::ArcTryLazy::from(memo);
2419 assert_eq!(try_memo.evaluate(), Ok(&42));
2420 }
2421
2422 #[test]
2424 fn test_send_defer() {
2425 use crate::classes::send_deferrable::send_defer;
2426
2427 let memo: ArcTryLazy<i32, ()> = send_defer(|| ArcTryLazy::new(|| Ok(42)));
2428 assert_eq!(memo.evaluate(), Ok(&42));
2429 }
2430
2431 #[test]
2433 fn test_rc_try_lazy_ok() {
2434 let memo = RcTryLazy::<i32, ()>::ok(42);
2435 assert_eq!(memo.evaluate(), Ok(&42));
2436 }
2437
2438 #[test]
2440 fn test_rc_try_lazy_err() {
2441 let memo = RcTryLazy::<i32, String>::err("error".to_string());
2442 assert_eq!(memo.evaluate(), Err(&"error".to_string()));
2443 }
2444
2445 #[test]
2447 fn test_arc_try_lazy_ok() {
2448 let memo = ArcTryLazy::<i32, ()>::ok(42);
2449 assert_eq!(memo.evaluate(), Ok(&42));
2450 }
2451
2452 #[test]
2454 fn test_arc_try_lazy_err() {
2455 let memo = ArcTryLazy::<i32, String>::err("error".to_string());
2456 assert_eq!(memo.evaluate(), Err(&"error".to_string()));
2457 }
2458
2459 #[test]
2461 fn test_rc_try_lazy_from_result_ok() {
2462 let memo: RcTryLazy<i32, String> = RcTryLazy::from(Ok(42));
2463 assert_eq!(memo.evaluate(), Ok(&42));
2464 }
2465
2466 #[test]
2468 fn test_rc_try_lazy_from_result_err() {
2469 let memo: RcTryLazy<i32, String> = RcTryLazy::from(Err("error".to_string()));
2470 assert_eq!(memo.evaluate(), Err(&"error".to_string()));
2471 }
2472
2473 #[test]
2475 fn test_arc_try_lazy_from_result_ok() {
2476 let memo: ArcTryLazy<i32, String> = ArcTryLazy::from(Ok(42));
2477 assert_eq!(memo.evaluate(), Ok(&42));
2478 }
2479
2480 #[test]
2482 fn test_arc_try_lazy_from_result_err() {
2483 let memo: ArcTryLazy<i32, String> = ArcTryLazy::from(Err("error".to_string()));
2484 assert_eq!(memo.evaluate(), Err(&"error".to_string()));
2485 }
2486
2487 #[test]
2492 fn test_panic_poisoning() {
2493 use std::panic;
2494
2495 let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| {
2496 panic!("initializer panic");
2497 });
2498
2499 let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
2500 let _ = memo.evaluate();
2501 }));
2502 assert!(result.is_err(), "First evaluate should panic");
2503
2504 let result2 = panic::catch_unwind(panic::AssertUnwindSafe(|| {
2505 let _ = memo.evaluate();
2506 }));
2507 assert!(result2.is_err(), "Second evaluate should also panic (poisoned)");
2508 }
2509
2510 #[test]
2515 fn test_arc_try_lazy_thread_safety() {
2516 use std::{
2517 sync::atomic::{
2518 AtomicUsize,
2519 Ordering,
2520 },
2521 thread,
2522 };
2523
2524 let counter = Arc::new(AtomicUsize::new(0));
2525 let counter_clone = counter.clone();
2526 let memo: ArcTryLazy<i32, String> = ArcTryLazy::new(move || {
2527 counter_clone.fetch_add(1, Ordering::SeqCst);
2528 Ok(42)
2529 });
2530
2531 let mut handles = vec![];
2532 for _ in 0 .. 10 {
2533 let memo_clone = memo.clone();
2534 handles.push(thread::spawn(move || {
2535 assert_eq!(memo_clone.evaluate(), Ok(&42));
2536 }));
2537 }
2538
2539 for handle in handles {
2540 handle.join().unwrap();
2541 }
2542
2543 assert_eq!(counter.load(Ordering::SeqCst), 1);
2544 }
2545
2546 #[quickcheck]
2548 fn memoization_ok(x: i32) -> bool {
2549 let memo: RcTryLazy<i32, i32> = RcTryLazy::new(move || Ok(x));
2550 let first = memo.evaluate();
2551 let second = memo.evaluate();
2552 first == second && first == Ok(&x)
2553 }
2554
2555 #[quickcheck]
2557 fn memoization_err(e: i32) -> bool {
2558 let memo: RcTryLazy<i32, i32> = RcTryLazy::new(move || Err(e));
2559 let first = memo.evaluate();
2560 let second = memo.evaluate();
2561 first == second && first == Err(&e)
2562 }
2563
2564 #[quickcheck]
2566 fn deferrable_transparency(x: i32) -> bool {
2567 use crate::classes::send_deferrable::send_defer;
2568
2569 let memo: ArcTryLazy<i32, i32> = ArcTryLazy::new(move || Ok(x));
2570 let deferred: ArcTryLazy<i32, i32> = send_defer(move || ArcTryLazy::new(move || Ok(x)));
2571 memo.evaluate() == deferred.evaluate()
2572 }
2573
2574 #[test]
2578 fn test_arc_catch_unwind() {
2579 let memo = ArcTryLazy::catch_unwind(|| {
2580 if true {
2581 panic!("oops")
2582 }
2583 42
2584 });
2585
2586 match memo.evaluate() {
2587 Err(e) => assert_eq!(e, "oops"),
2588 Ok(_) => panic!("Should have failed"),
2589 }
2590 }
2591
2592 #[test]
2596 fn test_arc_catch_unwind_success() {
2597 let memo = ArcTryLazy::catch_unwind(|| 42);
2598 assert_eq!(memo.evaluate(), Ok(&42));
2599 }
2600
2601 #[test]
2605 fn test_rc_catch_unwind_with_panic() {
2606 let memo = RcTryLazy::<i32, i32>::catch_unwind_with(
2607 || {
2608 if true {
2609 panic!("oops")
2610 }
2611 42
2612 },
2613 |_payload| -1,
2614 );
2615 assert_eq!(memo.evaluate(), Err(&-1));
2616 }
2617
2618 #[test]
2622 fn test_rc_catch_unwind_with_success() {
2623 let memo = RcTryLazy::<i32, i32>::catch_unwind_with(|| 42, |_payload| -1);
2624 assert_eq!(memo.evaluate(), Ok(&42));
2625 }
2626
2627 #[test]
2631 fn test_arc_catch_unwind_with_panic() {
2632 let memo = ArcTryLazy::<i32, i32>::catch_unwind_with(
2633 || {
2634 if true {
2635 panic!("oops")
2636 }
2637 42
2638 },
2639 |_payload| -1,
2640 );
2641 assert_eq!(memo.evaluate(), Err(&-1));
2642 }
2643
2644 #[test]
2648 fn test_arc_catch_unwind_with_success() {
2649 let memo = ArcTryLazy::<i32, i32>::catch_unwind_with(|| 42, |_payload| -1);
2650 assert_eq!(memo.evaluate(), Ok(&42));
2651 }
2652
2653 #[test]
2657 fn test_rc_try_lazy_map_ok() {
2658 let memo = RcTryLazy::<i32, String>::ok(10);
2659 let mapped = memo.map(|a| a * 2);
2660 assert_eq!(mapped.evaluate(), Ok(&20));
2661 }
2662
2663 #[test]
2667 fn test_rc_try_lazy_map_err() {
2668 let memo = RcTryLazy::<i32, String>::err("error".to_string());
2669 let mapped = memo.map(|a| a * 2);
2670 assert_eq!(mapped.evaluate(), Err(&"error".to_string()));
2671 }
2672
2673 #[test]
2677 fn test_rc_try_lazy_map_err_err() {
2678 let memo = RcTryLazy::<i32, String>::err("error".to_string());
2679 let mapped = memo.map_err(|e| format!("wrapped: {}", e));
2680 assert_eq!(mapped.evaluate(), Err(&"wrapped: error".to_string()));
2681 }
2682
2683 #[test]
2687 fn test_rc_try_lazy_map_err_ok() {
2688 let memo = RcTryLazy::<i32, String>::ok(42);
2689 let mapped = memo.map_err(|e| format!("wrapped: {}", e));
2690 assert_eq!(mapped.evaluate(), Ok(&42));
2691 }
2692
2693 #[test]
2697 fn test_rc_try_lazy_bimap_ok() {
2698 let memo = RcTryLazy::<i32, String>::ok(10);
2699 let mapped = memo.bimap(|a| a * 2, |e| e.len());
2700 assert_eq!(mapped.evaluate(), Ok(&20));
2701 }
2702
2703 #[test]
2707 fn test_rc_try_lazy_bimap_err() {
2708 let memo = RcTryLazy::<i32, String>::err("error".to_string());
2709 let mapped = memo.bimap(|a| a * 2, |e| e.len());
2710 assert_eq!(mapped.evaluate(), Err(&5));
2711 }
2712
2713 #[test]
2717 fn test_arc_try_lazy_map_ok() {
2718 let memo = ArcTryLazy::<i32, String>::ok(10);
2719 let mapped = memo.map(|a| a * 2);
2720 assert_eq!(mapped.evaluate(), Ok(&20));
2721 }
2722
2723 #[test]
2727 fn test_arc_try_lazy_map_err() {
2728 let memo = ArcTryLazy::<i32, String>::err("error".to_string());
2729 let mapped = memo.map(|a| a * 2);
2730 assert_eq!(mapped.evaluate(), Err(&"error".to_string()));
2731 }
2732
2733 #[test]
2737 fn test_arc_try_lazy_map_err_err() {
2738 let memo = ArcTryLazy::<i32, String>::err("error".to_string());
2739 let mapped = memo.map_err(|e| format!("wrapped: {}", e));
2740 assert_eq!(mapped.evaluate(), Err(&"wrapped: error".to_string()));
2741 }
2742
2743 #[test]
2747 fn test_arc_try_lazy_map_err_ok() {
2748 let memo = ArcTryLazy::<i32, String>::ok(42);
2749 let mapped = memo.map_err(|e| format!("wrapped: {}", e));
2750 assert_eq!(mapped.evaluate(), Ok(&42));
2751 }
2752
2753 #[test]
2757 fn test_arc_try_lazy_bimap_ok() {
2758 let memo = ArcTryLazy::<i32, String>::ok(10);
2759 let mapped = memo.bimap(|a| a * 2, |e| e.len());
2760 assert_eq!(mapped.evaluate(), Ok(&20));
2761 }
2762
2763 #[test]
2767 fn test_arc_try_lazy_bimap_err() {
2768 let memo = ArcTryLazy::<i32, String>::err("error".to_string());
2769 let mapped = memo.bimap(|a| a * 2, |e| e.len());
2770 assert_eq!(mapped.evaluate(), Err(&5));
2771 }
2772
2773 #[test]
2777 fn test_ref_functor_rc_try_lazy_ok() {
2778 use crate::{
2779 brands::TryLazyBrand,
2780 classes::RefFunctor,
2781 };
2782 let memo = RcTryLazy::<i32, String>::ok(10);
2783 let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x * 3, &memo);
2784 assert_eq!(mapped.evaluate(), Ok(&30));
2785 }
2786
2787 #[test]
2789 fn test_ref_functor_rc_try_lazy_err() {
2790 use crate::{
2791 brands::TryLazyBrand,
2792 classes::RefFunctor,
2793 };
2794 let memo = RcTryLazy::<i32, String>::err("fail".to_string());
2795 let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x * 3, &memo);
2796 assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
2797 }
2798
2799 #[test]
2801 fn test_ref_functor_rc_try_lazy_identity() {
2802 use crate::{
2803 brands::TryLazyBrand,
2804 classes::RefFunctor,
2805 };
2806 let memo = RcTryLazy::<i32, String>::ok(42);
2807 let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x, &memo.clone());
2808 assert_eq!(mapped.evaluate(), Ok(&42));
2809 }
2810
2811 #[test]
2815 fn test_send_ref_functor_arc_try_lazy_ok() {
2816 use crate::{
2817 brands::TryLazyBrand,
2818 classes::SendRefFunctor,
2819 };
2820 let memo = ArcTryLazy::<i32, String>::ok(10);
2821 let mapped = TryLazyBrand::<String, ArcLazyConfig>::send_ref_map(|x: &i32| *x * 3, &memo);
2822 assert_eq!(mapped.evaluate(), Ok(&30));
2823 }
2824
2825 #[test]
2827 fn test_send_ref_functor_arc_try_lazy_err() {
2828 use crate::{
2829 brands::TryLazyBrand,
2830 classes::SendRefFunctor,
2831 };
2832 let memo = ArcTryLazy::<i32, String>::err("fail".to_string());
2833 let mapped = TryLazyBrand::<String, ArcLazyConfig>::send_ref_map(|x: &i32| *x * 3, &memo);
2834 assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
2835 }
2836
2837 #[test]
2841 fn test_rc_try_lazy_ref_map_ok() {
2842 let memo = RcTryLazy::<i32, String>::ok(10);
2843 let mapped = memo.ref_map(|x| *x * 2);
2844 assert_eq!(mapped.evaluate(), Ok(&20));
2845 }
2846
2847 #[test]
2849 fn test_rc_try_lazy_ref_map_err() {
2850 let memo = RcTryLazy::<i32, String>::err("fail".to_string());
2851 let mapped = memo.ref_map(|x| *x * 2);
2852 assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
2853 }
2854
2855 #[test]
2857 fn test_rc_try_lazy_ref_map_identity() {
2858 let memo = RcTryLazy::<i32, String>::ok(42);
2859 let mapped = memo.ref_map(|x| *x);
2860 assert_eq!(mapped.evaluate(), Ok(&42));
2861 }
2862
2863 #[test]
2865 fn test_arc_try_lazy_ref_map_ok() {
2866 let memo = ArcTryLazy::<i32, String>::ok(10);
2867 let mapped = memo.ref_map(|x| *x * 2);
2868 assert_eq!(mapped.evaluate(), Ok(&20));
2869 }
2870
2871 #[test]
2873 fn test_arc_try_lazy_ref_map_err() {
2874 let memo = ArcTryLazy::<i32, String>::err("fail".to_string());
2875 let mapped = memo.ref_map(|x| *x * 2);
2876 assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
2877 }
2878
2879 #[test]
2881 fn test_arc_try_lazy_ref_map_identity() {
2882 let memo = ArcTryLazy::<i32, String>::ok(42);
2883 let mapped = memo.ref_map(|x| *x);
2884 assert_eq!(mapped.evaluate(), Ok(&42));
2885 }
2886
2887 #[test]
2891 fn test_semigroup_rc_try_lazy_both_ok() {
2892 use crate::functions::append;
2893 let a = RcTryLazy::<String, String>::ok("Hello".to_string());
2894 let b = RcTryLazy::<String, String>::ok(" World".to_string());
2895 let c = append(a, b);
2896 assert_eq!(c.evaluate(), Ok(&"Hello World".to_string()));
2897 }
2898
2899 #[test]
2901 fn test_semigroup_rc_try_lazy_first_err() {
2902 use crate::functions::append;
2903 let a = RcTryLazy::<String, String>::err("err1".to_string());
2904 let b = RcTryLazy::<String, String>::ok("ok".to_string());
2905 let c = append(a, b);
2906 assert_eq!(c.evaluate(), Err(&"err1".to_string()));
2907 }
2908
2909 #[test]
2911 fn test_semigroup_rc_try_lazy_second_err() {
2912 use crate::functions::append;
2913 let a = RcTryLazy::<String, String>::ok("ok".to_string());
2914 let b = RcTryLazy::<String, String>::err("err2".to_string());
2915 let c = append(a, b);
2916 assert_eq!(c.evaluate(), Err(&"err2".to_string()));
2917 }
2918
2919 #[test]
2921 fn test_semigroup_arc_try_lazy_both_ok() {
2922 use crate::functions::append;
2923 let a = ArcTryLazy::<String, String>::ok("Hello".to_string());
2924 let b = ArcTryLazy::<String, String>::ok(" World".to_string());
2925 let c = append(a, b);
2926 assert_eq!(c.evaluate(), Ok(&"Hello World".to_string()));
2927 }
2928
2929 #[test]
2931 fn test_semigroup_arc_try_lazy_first_err() {
2932 use crate::functions::append;
2933 let a = ArcTryLazy::<String, String>::err("err1".to_string());
2934 let b = ArcTryLazy::<String, String>::ok("ok".to_string());
2935 let c = append(a, b);
2936 assert_eq!(c.evaluate(), Err(&"err1".to_string()));
2937 }
2938
2939 #[test]
2943 fn test_monoid_rc_try_lazy_empty() {
2944 use crate::functions::empty;
2945 let t: RcTryLazy<String, ()> = empty();
2946 assert_eq!(t.evaluate(), Ok(&String::new()));
2947 }
2948
2949 #[test]
2951 fn test_monoid_arc_try_lazy_empty() {
2952 use crate::functions::empty;
2953 let t: ArcTryLazy<String, ()> = empty();
2954 assert_eq!(t.evaluate(), Ok(&String::new()));
2955 }
2956
2957 #[test]
2959 fn test_monoid_rc_try_lazy_left_identity() {
2960 use crate::functions::{
2961 append,
2962 empty,
2963 };
2964 let a = RcTryLazy::<String, ()>::ok("hello".to_string());
2965 let result = append(empty::<RcTryLazy<String, ()>>(), a);
2966 assert_eq!(result.evaluate(), Ok(&"hello".to_string()));
2967 }
2968
2969 #[test]
2971 fn test_monoid_rc_try_lazy_right_identity() {
2972 use crate::functions::{
2973 append,
2974 empty,
2975 };
2976 let a = RcTryLazy::<String, ()>::ok("hello".to_string());
2977 let result = append(a, empty::<RcTryLazy<String, ()>>());
2978 assert_eq!(result.evaluate(), Ok(&"hello".to_string()));
2979 }
2980
2981 #[test]
2985 fn test_foldable_rc_try_lazy_fold_right_ok() {
2986 use crate::{
2987 brands::*,
2988 functions::*,
2989 };
2990
2991 let lazy = RcTryLazy::<i32, String>::ok(10);
2992 let result = explicit::fold_right::<
2993 crate::brands::RcFnBrand,
2994 TryLazyBrand<String, RcLazyConfig>,
2995 _,
2996 _,
2997 _,
2998 _,
2999 >(|a: &i32, b| *a + b, 5, &lazy);
3000 assert_eq!(result, 15);
3001 }
3002
3003 #[test]
3005 fn test_foldable_rc_try_lazy_fold_right_err() {
3006 use crate::{
3007 brands::*,
3008 functions::*,
3009 };
3010
3011 let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3012 let result = explicit::fold_right::<
3013 crate::brands::RcFnBrand,
3014 TryLazyBrand<String, RcLazyConfig>,
3015 _,
3016 _,
3017 _,
3018 _,
3019 >(|a: &i32, b| *a + b, 5, &lazy);
3020 assert_eq!(result, 5);
3021 }
3022
3023 #[test]
3025 fn test_foldable_rc_try_lazy_fold_left_ok() {
3026 use crate::{
3027 brands::*,
3028 functions::*,
3029 };
3030
3031 let lazy = RcTryLazy::<i32, String>::ok(10);
3032 let result = explicit::fold_left::<
3033 crate::brands::RcFnBrand,
3034 TryLazyBrand<String, RcLazyConfig>,
3035 _,
3036 _,
3037 _,
3038 _,
3039 >(|b, a: &i32| b + *a, 5, &lazy);
3040 assert_eq!(result, 15);
3041 }
3042
3043 #[test]
3045 fn test_foldable_rc_try_lazy_fold_left_err() {
3046 use crate::{
3047 brands::*,
3048 functions::*,
3049 };
3050
3051 let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3052 let result = explicit::fold_left::<
3053 crate::brands::RcFnBrand,
3054 TryLazyBrand<String, RcLazyConfig>,
3055 _,
3056 _,
3057 _,
3058 _,
3059 >(|b, a: &i32| b + *a, 5, &lazy);
3060 assert_eq!(result, 5);
3061 }
3062
3063 #[test]
3065 fn test_foldable_rc_try_lazy_fold_map_ok() {
3066 use crate::{
3067 brands::*,
3068 functions::*,
3069 };
3070
3071 let lazy = RcTryLazy::<i32, String>::ok(10);
3072 let result = explicit::fold_map::<RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _, _, _>(
3073 |a: &i32| a.to_string(),
3074 &lazy,
3075 );
3076 assert_eq!(result, "10");
3077 }
3078
3079 #[test]
3081 fn test_foldable_rc_try_lazy_fold_map_err() {
3082 use crate::{
3083 brands::*,
3084 functions::*,
3085 };
3086
3087 let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3088 let result = explicit::fold_map::<RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _, _, _>(
3089 |a: &i32| a.to_string(),
3090 &lazy,
3091 );
3092 assert_eq!(result, "");
3093 }
3094
3095 #[test]
3097 fn test_foldable_arc_try_lazy_fold_right_ok() {
3098 use crate::{
3099 brands::*,
3100 functions::*,
3101 };
3102
3103 let lazy = ArcTryLazy::<i32, String>::ok(10);
3104 let result = explicit::fold_right::<
3105 crate::brands::ArcFnBrand,
3106 TryLazyBrand<String, ArcLazyConfig>,
3107 _,
3108 _,
3109 _,
3110 _,
3111 >(|a: &i32, b| *a + b, 5, &lazy);
3112 assert_eq!(result, 15);
3113 }
3114
3115 #[test]
3117 fn test_foldable_arc_try_lazy_fold_right_err() {
3118 use crate::{
3119 brands::*,
3120 functions::*,
3121 };
3122
3123 let lazy = ArcTryLazy::<i32, String>::err("fail".to_string());
3124 let result = explicit::fold_right::<
3125 crate::brands::ArcFnBrand,
3126 TryLazyBrand<String, ArcLazyConfig>,
3127 _,
3128 _,
3129 _,
3130 _,
3131 >(|a: &i32, b| *a + b, 5, &lazy);
3132 assert_eq!(result, 5);
3133 }
3134
3135 #[test]
3141 fn test_rc_try_lazy_ref_fold_map_with_index_ok() {
3142 use crate::classes::ref_foldable_with_index::RefFoldableWithIndex;
3143
3144 let lazy = RcTryLazy::<i32, ()>::ok(42);
3145 let result =
3146 <TryLazyBrand<(), RcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
3147 RcFnBrand,
3148 _,
3149 _,
3150 >(|_, x: &i32| x.to_string(), &lazy);
3151 assert_eq!(result, "42");
3152 }
3153
3154 #[test]
3158 fn test_rc_try_lazy_ref_fold_map_with_index_err() {
3159 use crate::classes::ref_foldable_with_index::RefFoldableWithIndex;
3160
3161 let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3162 let result =
3163 <TryLazyBrand<String, RcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
3164 RcFnBrand,
3165 _,
3166 _,
3167 >(|_, x: &i32| x.to_string(), &lazy);
3168 assert_eq!(result, "");
3169 }
3170
3171 #[test]
3175 fn test_arc_try_lazy_ref_fold_map_with_index_ok() {
3176 use crate::classes::ref_foldable_with_index::RefFoldableWithIndex;
3177
3178 let lazy = ArcTryLazy::<i32, ()>::ok(10);
3179 let result =
3180 <TryLazyBrand<(), ArcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
3181 RcFnBrand,
3182 _,
3183 _,
3184 >(|_, x: &i32| x.to_string(), &lazy);
3185 assert_eq!(result, "10");
3186 }
3187
3188 #[test]
3192 fn test_arc_try_lazy_ref_fold_map_with_index_err() {
3193 use crate::classes::ref_foldable_with_index::RefFoldableWithIndex;
3194
3195 let lazy = ArcTryLazy::<i32, String>::err("fail".to_string());
3196 let result =
3197 <TryLazyBrand<String, ArcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
3198 RcFnBrand,
3199 _,
3200 _,
3201 >(|_, x: &i32| x.to_string(), &lazy);
3202 assert_eq!(result, "");
3203 }
3204
3205 #[test]
3209 fn test_rc_try_lazy_foldable_with_index_compatibility() {
3210 use crate::{
3211 brands::*,
3212 classes::ref_foldable_with_index::RefFoldableWithIndex,
3213 functions::*,
3214 };
3215
3216 let lazy1 = RcTryLazy::<i32, ()>::ok(7);
3217 let lazy2 = RcTryLazy::<i32, ()>::ok(7);
3218
3219 let fold_result = explicit::fold_map::<RcFnBrand, TryLazyBrand<(), RcLazyConfig>, _, _, _, _>(
3220 |a: &i32| a.to_string(),
3221 &lazy1,
3222 );
3223 let fold_with_index_result =
3224 <TryLazyBrand<(), RcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
3225 RcFnBrand,
3226 _,
3227 _,
3228 >(|_, a| a.to_string(), &lazy2);
3229 assert_eq!(fold_result, fold_with_index_result);
3230 }
3231
3232 #[test]
3236 fn test_semigroup_append_first_err_short_circuits() {
3237 use {
3238 crate::classes::Semigroup,
3239 std::cell::Cell,
3240 };
3241
3242 let counter = Rc::new(Cell::new(0u32));
3243 let counter_clone = counter.clone();
3244
3245 let a: RcTryLazy<String, String> = RcTryLazy::new(|| Err("first failed".into()));
3246 let b: RcTryLazy<String, String> = RcTryLazy::new(move || {
3247 counter_clone.set(counter_clone.get() + 1);
3248 Ok("second".into())
3249 });
3250
3251 let result = Semigroup::append(a, b);
3252 assert_eq!(result.evaluate(), Err(&"first failed".to_string()));
3253 assert_eq!(counter.get(), 0, "second operand should not be evaluated");
3254 }
3255
3256 #[test]
3260 fn test_semigroup_append_second_err() {
3261 use crate::classes::Semigroup;
3262
3263 let a: RcTryLazy<String, String> = RcTryLazy::new(|| Ok("hello".into()));
3264 let b: RcTryLazy<String, String> = RcTryLazy::new(|| Err("second failed".into()));
3265
3266 let result = Semigroup::append(a, b);
3267 assert_eq!(result.evaluate(), Err(&"second failed".to_string()));
3268 }
3269
3270 #[test]
3272 fn test_semigroup_append_both_ok() {
3273 use crate::classes::Semigroup;
3274
3275 let a: RcTryLazy<String, ()> = RcTryLazy::new(|| Ok("Hello".into()));
3276 let b: RcTryLazy<String, ()> = RcTryLazy::new(|| Ok(" World".into()));
3277
3278 let result = Semigroup::append(a, b);
3279 assert_eq!(result.evaluate(), Ok(&"Hello World".to_string()));
3280 }
3281
3282 #[test]
3284 fn test_map_ok() {
3285 let memo = RcTryLazy::new(|| Ok::<i32, ()>(21));
3286 let mapped = memo.map(|x| x * 2);
3287 assert_eq!(mapped.evaluate(), Ok(&42));
3288 }
3289
3290 #[test]
3292 fn test_map_err() {
3293 let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
3294 let mapped = memo.map(|x| x * 2);
3295 assert_eq!(mapped.evaluate(), Err(&"oops".to_string()));
3296 }
3297
3298 #[test]
3300 fn test_map_err_on_err() {
3301 let memo: RcTryLazy<i32, i32> = RcTryLazy::new(|| Err(21));
3302 let mapped = memo.map_err(|e| e * 2);
3303 assert_eq!(mapped.evaluate(), Err(&42));
3304 }
3305
3306 #[test]
3308 fn test_map_err_on_ok() {
3309 let memo: RcTryLazy<i32, i32> = RcTryLazy::new(|| Ok(42));
3310 let mapped = memo.map_err(|e| e * 2);
3311 assert_eq!(mapped.evaluate(), Ok(&42));
3312 }
3313
3314 #[test]
3316 fn test_and_then_ok() {
3317 let memo = RcTryLazy::new(|| Ok::<i32, String>(21));
3318 let chained = memo.and_then(|x| Ok(x * 2));
3319 assert_eq!(chained.evaluate(), Ok(&42));
3320 }
3321
3322 #[test]
3324 fn test_and_then_chained_err() {
3325 let memo = RcTryLazy::new(|| Ok::<i32, String>(21));
3326 let chained = memo.and_then(|_: &i32| Err::<i32, String>("chained failure".into()));
3327 assert_eq!(chained.evaluate(), Err(&"chained failure".to_string()));
3328 }
3329
3330 #[test]
3332 fn test_and_then_initial_err() {
3333 let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("initial".into()));
3334 let chained = memo.and_then(|x| Ok(x * 2));
3335 assert_eq!(chained.evaluate(), Err(&"initial".to_string()));
3336 }
3337
3338 #[test]
3340 fn test_or_else_recovers() {
3341 let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
3342 let recovered = memo.or_else(|_| Ok(42));
3343 assert_eq!(recovered.evaluate(), Ok(&42));
3344 }
3345
3346 #[test]
3348 fn test_or_else_noop_on_ok() {
3349 let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Ok(42));
3350 let recovered = memo.or_else(|_| Ok(99));
3351 assert_eq!(recovered.evaluate(), Ok(&42));
3352 }
3353
3354 #[test]
3356 fn test_or_else_recovery_fails() {
3357 let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("first".into()));
3358 let recovered = memo.or_else(|_| Err("second".into()));
3359 assert_eq!(recovered.evaluate(), Err(&"second".to_string()));
3360 }
3361
3362 #[test]
3364 fn test_foldable_ok() {
3365 use crate::{
3366 brands::*,
3367 functions::*,
3368 };
3369
3370 let memo: RcTryLazy<i32, ()> = RcTryLazy::new(|| Ok(10));
3371 let result = explicit::fold_right::<RcFnBrand, TryLazyBrand<(), RcLazyConfig>, _, _, _, _>(
3372 |a: &i32, b| *a + b,
3373 5,
3374 &memo,
3375 );
3376 assert_eq!(result, 15);
3377 }
3378
3379 #[test]
3381 fn test_foldable_err() {
3382 use crate::{
3383 brands::*,
3384 functions::*,
3385 };
3386
3387 let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
3388 let result =
3389 explicit::fold_right::<RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _, _, _>(
3390 |a: &i32, b| *a + b,
3391 5,
3392 &memo,
3393 );
3394 assert_eq!(result, 5);
3395 }
3396
3397 #[test]
3399 fn test_from_try_send_thunk_ok() {
3400 let counter = Arc::new(std::sync::atomic::AtomicUsize::new(0));
3401 let counter_clone = counter.clone();
3402 let thunk: TrySendThunk<i32, ()> = TrySendThunk::new(move || {
3403 counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
3404 Ok(42)
3405 });
3406
3407 assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 0);
3409
3410 let lazy: ArcTryLazy<i32, ()> = ArcTryLazy::from(thunk);
3411 assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 0);
3412
3413 assert_eq!(lazy.evaluate(), Ok(&42));
3415 assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
3416
3417 assert_eq!(lazy.evaluate(), Ok(&42));
3419 assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
3420 }
3421
3422 #[test]
3424 fn test_from_try_send_thunk_err() {
3425 let thunk: TrySendThunk<i32, String> = TrySendThunk::new(move || Err("fail".to_string()));
3426 let lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(thunk);
3427 assert_eq!(lazy.evaluate(), Err(&"fail".to_string()));
3428 }
3429
3430 #[test]
3432 fn test_try_send_thunk_into_arc_try_lazy() {
3433 let thunk: TrySendThunk<i32, ()> = TrySendThunk::ok(42);
3434 let lazy: ArcTryLazy<i32, ()> = thunk.into();
3435 assert_eq!(lazy.evaluate(), Ok(&42));
3436 }
3437
3438 #[test]
3442 fn test_try_lazy_partial_eq_ok() {
3443 let a = RcTryLazy::<i32, ()>::ok(42);
3444 let b = RcTryLazy::<i32, ()>::ok(42);
3445 assert_eq!(a, b);
3446 }
3447
3448 #[test]
3450 fn test_try_lazy_partial_eq_ok_neq() {
3451 let a = RcTryLazy::<i32, ()>::ok(1);
3452 let b = RcTryLazy::<i32, ()>::ok(2);
3453 assert_ne!(a, b);
3454 }
3455
3456 #[test]
3458 fn test_try_lazy_partial_eq_err() {
3459 let a = RcTryLazy::<i32, String>::err("fail".to_string());
3460 let b = RcTryLazy::<i32, String>::err("fail".to_string());
3461 assert_eq!(a, b);
3462 }
3463
3464 #[test]
3466 fn test_try_lazy_partial_eq_ok_vs_err() {
3467 let a = RcTryLazy::<i32, i32>::ok(1);
3468 let b = RcTryLazy::<i32, i32>::err(1);
3469 assert_ne!(a, b);
3470 }
3471
3472 #[test]
3474 fn test_try_lazy_partial_eq_arc() {
3475 let a = ArcTryLazy::<i32, ()>::ok(42);
3476 let b = ArcTryLazy::<i32, ()>::ok(42);
3477 assert_eq!(a, b);
3478 }
3479
3480 #[test]
3484 fn test_try_lazy_hash_eq() {
3485 use std::{
3486 collections::hash_map::DefaultHasher,
3487 hash::{
3488 Hash,
3489 Hasher,
3490 },
3491 };
3492
3493 let a = RcTryLazy::<i32, ()>::ok(42);
3494 let b = RcTryLazy::<i32, ()>::ok(42);
3495
3496 let mut h1 = DefaultHasher::new();
3497 a.hash(&mut h1);
3498 let mut h2 = DefaultHasher::new();
3499 b.hash(&mut h2);
3500
3501 assert_eq!(h1.finish(), h2.finish());
3502 }
3503
3504 #[test]
3506 fn test_try_lazy_hash_matches_result() {
3507 use std::{
3508 collections::hash_map::DefaultHasher,
3509 hash::{
3510 Hash,
3511 Hasher,
3512 },
3513 };
3514
3515 let lazy = RcTryLazy::<i32, ()>::ok(42);
3516 let mut h1 = DefaultHasher::new();
3517 lazy.hash(&mut h1);
3518
3519 let result: Result<i32, ()> = Ok(42);
3520 let mut h2 = DefaultHasher::new();
3521 result.hash(&mut h2);
3522
3523 assert_eq!(h1.finish(), h2.finish());
3524 }
3525
3526 #[test]
3530 fn test_try_lazy_partial_ord_ok() {
3531 let a = RcTryLazy::<i32, ()>::ok(1);
3532 let b = RcTryLazy::<i32, ()>::ok(2);
3533 assert!(a < b);
3534 assert!(b > a);
3535 }
3536
3537 #[test]
3539 fn test_try_lazy_partial_ord_eq() {
3540 let a = RcTryLazy::<i32, ()>::ok(42);
3541 let b = RcTryLazy::<i32, ()>::ok(42);
3542 assert!(a <= b);
3543 assert!(a >= b);
3544 }
3545
3546 #[test]
3550 fn test_try_lazy_ord_ok() {
3551 use std::cmp::Ordering;
3552
3553 let a = RcTryLazy::<i32, ()>::ok(1);
3554 let b = RcTryLazy::<i32, ()>::ok(2);
3555 assert_eq!(a.cmp(&b), Ordering::Less);
3556 assert_eq!(b.cmp(&a), Ordering::Greater);
3557 }
3558
3559 #[test]
3561 fn test_try_lazy_ord_eq() {
3562 use std::cmp::Ordering;
3563
3564 let a = RcTryLazy::<i32, ()>::ok(42);
3565 let b = RcTryLazy::<i32, ()>::ok(42);
3566 assert_eq!(a.cmp(&b), Ordering::Equal);
3567 }
3568
3569 #[test]
3571 fn test_try_lazy_ord_arc() {
3572 use std::cmp::Ordering;
3573
3574 let a = ArcTryLazy::<i32, ()>::ok(1);
3575 let b = ArcTryLazy::<i32, ()>::ok(2);
3576 assert_eq!(a.cmp(&b), Ordering::Less);
3577 }
3578
3579 #[test]
3581 fn test_try_lazy_eq_trait() {
3582 fn assert_eq_impl<T: Eq>(_: &T) {}
3583 let a = RcTryLazy::<i32, ()>::ok(42);
3584 assert_eq_impl(&a);
3585 }
3586
3587 #[test]
3591 fn test_try_lazy_display_ok_rc() {
3592 let lazy = RcTryLazy::<i32, String>::ok(42);
3593 assert_eq!(format!("{}", lazy), "Ok(42)");
3594 }
3595
3596 #[test]
3598 fn test_try_lazy_display_err_rc() {
3599 let lazy = RcTryLazy::<i32, String>::err("oops".to_string());
3600 assert_eq!(format!("{}", lazy), "Err(oops)");
3601 }
3602
3603 #[test]
3605 fn test_try_lazy_display_ok_arc() {
3606 let lazy = ArcTryLazy::<i32, String>::ok(42);
3607 assert_eq!(format!("{}", lazy), "Ok(42)");
3608 }
3609
3610 #[test]
3612 fn test_try_lazy_display_err_arc() {
3613 let lazy = ArcTryLazy::<i32, String>::err("oops".to_string());
3614 assert_eq!(format!("{}", lazy), "Err(oops)");
3615 }
3616
3617 #[test]
3621 fn test_try_lazy_rc_to_arc_ok() {
3622 let rc_lazy = RcTryLazy::<i32, String>::ok(42);
3623 let arc_lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(rc_lazy);
3624 assert_eq!(arc_lazy.evaluate(), Ok(&42));
3625 }
3626
3627 #[test]
3629 fn test_try_lazy_rc_to_arc_err() {
3630 let rc_lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3631 let arc_lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(rc_lazy);
3632 assert_eq!(arc_lazy.evaluate(), Err(&"fail".to_string()));
3633 }
3634
3635 #[test]
3637 fn test_try_lazy_arc_to_rc_ok() {
3638 let arc_lazy = ArcTryLazy::<i32, String>::ok(42);
3639 let rc_lazy: RcTryLazy<i32, String> = RcTryLazy::from(arc_lazy);
3640 assert_eq!(rc_lazy.evaluate(), Ok(&42));
3641 }
3642
3643 #[test]
3645 fn test_try_lazy_arc_to_rc_err() {
3646 let arc_lazy = ArcTryLazy::<i32, String>::err("fail".to_string());
3647 let rc_lazy: RcTryLazy<i32, String> = RcTryLazy::from(arc_lazy);
3648 assert_eq!(rc_lazy.evaluate(), Err(&"fail".to_string()));
3649 }
3650
3651 #[test]
3656 fn test_rc_try_lazy_fix_ok_constant() {
3657 let fixed = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, ()>| Ok(42));
3658 assert_eq!(fixed.evaluate(), Ok(&42));
3659 }
3660
3661 #[test]
3664 fn test_rc_try_lazy_fix_err_constant() {
3665 let fixed = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, String>| Err("fail".to_string()));
3666 assert_eq!(fixed.evaluate(), Err(&"fail".to_string()));
3667 }
3668
3669 #[test]
3671 fn test_rc_try_lazy_fix_memoization() {
3672 let counter = Rc::new(RefCell::new(0));
3673 let counter_clone = counter.clone();
3674 let fixed = rc_try_lazy_fix(move |_self_ref: RcTryLazy<i32, ()>| {
3675 *counter_clone.borrow_mut() += 1;
3676 Ok(100)
3677 });
3678
3679 assert_eq!(*counter.borrow(), 0);
3680 assert_eq!(fixed.evaluate(), Ok(&100));
3681 assert_eq!(*counter.borrow(), 1);
3682 assert_eq!(fixed.evaluate(), Ok(&100));
3684 assert_eq!(*counter.borrow(), 1);
3685 }
3686
3687 #[test]
3689 fn test_rc_try_lazy_fix_self_reference() {
3690 let fixed = rc_try_lazy_fix(|self_ref: RcTryLazy<Vec<i32>, ()>| {
3691 let _ = self_ref;
3693 Ok(vec![1, 2, 3])
3694 });
3695 assert_eq!(fixed.evaluate(), Ok(&vec![1, 2, 3]));
3696 }
3697
3698 #[test]
3700 fn test_rc_try_lazy_fix_clone_sharing() {
3701 let fixed = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, ()>| Ok(55));
3702 let cloned = fixed.clone();
3703 assert_eq!(fixed.evaluate(), Ok(&55));
3704 assert_eq!(cloned.evaluate(), Ok(&55));
3705 }
3706
3707 #[test]
3709 fn test_rc_try_lazy_fix_uses_self_ref() {
3710 let counter = Rc::new(RefCell::new(0));
3711 let counter_clone = counter.clone();
3712 let lazy = rc_try_lazy_fix(move |self_ref: RcTryLazy<i32, ()>| {
3713 *counter_clone.borrow_mut() += 1;
3714 let _ = self_ref;
3715 Ok(42)
3716 });
3717 assert_eq!(lazy.evaluate(), Ok(&42));
3718 assert_eq!(*counter.borrow(), 1);
3719 assert_eq!(lazy.evaluate(), Ok(&42));
3721 assert_eq!(*counter.borrow(), 1);
3722 }
3723
3724 #[test]
3727 fn test_arc_try_lazy_fix_ok_constant() {
3728 let fixed = arc_try_lazy_fix(|_self_ref: ArcTryLazy<i32, ()>| Ok(42));
3729 assert_eq!(fixed.evaluate(), Ok(&42));
3730 }
3731
3732 #[test]
3735 fn test_arc_try_lazy_fix_err_constant() {
3736 let fixed = arc_try_lazy_fix(|_self_ref: ArcTryLazy<i32, String>| Err("fail".to_string()));
3737 assert_eq!(fixed.evaluate(), Err(&"fail".to_string()));
3738 }
3739
3740 #[test]
3742 fn test_arc_try_lazy_fix_memoization() {
3743 use std::sync::atomic::{
3744 AtomicUsize,
3745 Ordering,
3746 };
3747
3748 let counter = Arc::new(AtomicUsize::new(0));
3749 let counter_clone = counter.clone();
3750 let fixed = arc_try_lazy_fix(move |_self_ref: ArcTryLazy<i32, ()>| {
3751 counter_clone.fetch_add(1, Ordering::SeqCst);
3752 Ok(100)
3753 });
3754
3755 assert_eq!(counter.load(Ordering::SeqCst), 0);
3756 assert_eq!(fixed.evaluate(), Ok(&100));
3757 assert_eq!(counter.load(Ordering::SeqCst), 1);
3758 assert_eq!(fixed.evaluate(), Ok(&100));
3760 assert_eq!(counter.load(Ordering::SeqCst), 1);
3761 }
3762
3763 #[test]
3765 fn test_arc_try_lazy_fix_self_reference() {
3766 let fixed = arc_try_lazy_fix(|self_ref: ArcTryLazy<Vec<i32>, ()>| {
3767 let _ = self_ref;
3768 Ok(vec![1, 2, 3])
3769 });
3770 assert_eq!(fixed.evaluate(), Ok(&vec![1, 2, 3]));
3771 }
3772
3773 #[test]
3775 fn test_arc_try_lazy_fix_uses_self_ref() {
3776 use std::sync::atomic::{
3777 AtomicUsize,
3778 Ordering,
3779 };
3780
3781 let counter = Arc::new(AtomicUsize::new(0));
3782 let counter_clone = counter.clone();
3783 let lazy = arc_try_lazy_fix(move |self_ref: ArcTryLazy<i32, ()>| {
3784 counter_clone.fetch_add(1, Ordering::SeqCst);
3785 let _ = self_ref;
3786 Ok(42)
3787 });
3788 assert_eq!(lazy.evaluate(), Ok(&42));
3789 assert_eq!(counter.load(Ordering::SeqCst), 1);
3790 assert_eq!(lazy.evaluate(), Ok(&42));
3792 assert_eq!(counter.load(Ordering::SeqCst), 1);
3793 }
3794
3795 #[test]
3797 fn test_arc_try_lazy_fix_thread_safety() {
3798 use std::thread;
3799
3800 let lazy = arc_try_lazy_fix(|self_ref: ArcTryLazy<i32, ()>| {
3801 let _ = self_ref;
3802 Ok(42)
3803 });
3804
3805 let mut handles = vec![];
3806 for _ in 0 .. 10 {
3807 let lazy_clone = lazy.clone();
3808 handles.push(thread::spawn(move || {
3809 assert_eq!(lazy_clone.evaluate(), Ok(&42));
3810 }));
3811 }
3812
3813 for handle in handles {
3814 handle.join().unwrap();
3815 }
3816 }
3817
3818 #[test]
3824 fn test_rc_try_lazy_fix_knot_tying_ptr_eq() {
3825 let stash: Rc<RefCell<Option<RcTryLazy<i32, ()>>>> = Rc::new(RefCell::new(None));
3826 let stash_clone = stash.clone();
3827 let lazy = rc_try_lazy_fix(move |self_ref: RcTryLazy<i32, ()>| {
3828 *stash_clone.borrow_mut() = Some(self_ref);
3829 Ok(42)
3830 });
3831 assert_eq!(lazy.evaluate(), Ok(&42));
3832 let self_ref = stash.borrow().clone().unwrap();
3833 assert!(Rc::ptr_eq(&lazy.0.0, &self_ref.0.0));
3835 assert_eq!(self_ref.evaluate(), Ok(&42));
3837 }
3838
3839 #[test]
3842 fn test_rc_try_lazy_fix_knot_tying_shared_cache() {
3843 let counter = Rc::new(RefCell::new(0));
3844 let stash: Rc<RefCell<Option<RcTryLazy<i32, ()>>>> = Rc::new(RefCell::new(None));
3845 let counter_clone = counter.clone();
3846 let stash_clone = stash.clone();
3847 let lazy = rc_try_lazy_fix(move |self_ref: RcTryLazy<i32, ()>| {
3848 *stash_clone.borrow_mut() = Some(self_ref);
3849 *counter_clone.borrow_mut() += 1;
3850 Ok(100)
3851 });
3852 assert_eq!(*counter.borrow(), 0);
3853 assert_eq!(lazy.evaluate(), Ok(&100));
3854 assert_eq!(*counter.borrow(), 1);
3855 let self_ref = stash.borrow().clone().unwrap();
3857 assert_eq!(self_ref.evaluate(), Ok(&100));
3858 assert_eq!(*counter.borrow(), 1);
3860 }
3861
3862 #[test]
3865 fn test_rc_try_lazy_fix_knot_tying_err_shared() {
3866 let stash: Rc<RefCell<Option<RcTryLazy<i32, String>>>> = Rc::new(RefCell::new(None));
3867 let stash_clone = stash.clone();
3868 let lazy = rc_try_lazy_fix(move |self_ref: RcTryLazy<i32, String>| {
3869 *stash_clone.borrow_mut() = Some(self_ref);
3870 Err("fail".to_string())
3871 });
3872 assert_eq!(lazy.evaluate(), Err(&"fail".to_string()));
3873 let self_ref = stash.borrow().clone().unwrap();
3874 assert_eq!(self_ref.evaluate(), Err(&"fail".to_string()));
3876 assert!(Rc::ptr_eq(&lazy.0.0, &self_ref.0.0));
3878 }
3879
3880 #[test]
3885 #[should_panic]
3886 fn test_rc_try_lazy_fix_reentrant_panics() {
3887 let lazy = rc_try_lazy_fix(|self_ref: RcTryLazy<i32, ()>| {
3888 Ok(*self_ref.evaluate().unwrap() + 1)
3891 });
3892 let _ = lazy.evaluate();
3893 }
3894
3895 #[test]
3898 fn test_arc_try_lazy_fix_knot_tying_ptr_eq() {
3899 use std::sync::Mutex;
3900
3901 let stash: Arc<Mutex<Option<ArcTryLazy<i32, ()>>>> = Arc::new(Mutex::new(None));
3902 let stash_clone = stash.clone();
3903 let lazy = arc_try_lazy_fix(move |self_ref: ArcTryLazy<i32, ()>| {
3904 *stash_clone.lock().unwrap() = Some(self_ref);
3905 Ok(42)
3906 });
3907 assert_eq!(lazy.evaluate(), Ok(&42));
3908 let self_ref = stash.lock().unwrap().clone().unwrap();
3909 assert!(Arc::ptr_eq(&lazy.0.0, &self_ref.0.0));
3910 assert_eq!(self_ref.evaluate(), Ok(&42));
3911 }
3912
3913 #[test]
3916 fn test_arc_try_lazy_fix_knot_tying_shared_cache() {
3917 use std::sync::{
3918 Mutex,
3919 atomic::{
3920 AtomicUsize,
3921 Ordering,
3922 },
3923 };
3924
3925 let counter = Arc::new(AtomicUsize::new(0));
3926 let stash: Arc<Mutex<Option<ArcTryLazy<i32, ()>>>> = Arc::new(Mutex::new(None));
3927 let counter_clone = counter.clone();
3928 let stash_clone = stash.clone();
3929 let lazy = arc_try_lazy_fix(move |self_ref: ArcTryLazy<i32, ()>| {
3930 *stash_clone.lock().unwrap() = Some(self_ref);
3931 counter_clone.fetch_add(1, Ordering::SeqCst);
3932 Ok(100)
3933 });
3934 assert_eq!(counter.load(Ordering::SeqCst), 0);
3935 assert_eq!(lazy.evaluate(), Ok(&100));
3936 assert_eq!(counter.load(Ordering::SeqCst), 1);
3937 let self_ref = stash.lock().unwrap().clone().unwrap();
3938 assert_eq!(self_ref.evaluate(), Ok(&100));
3939 assert_eq!(counter.load(Ordering::SeqCst), 1);
3940 }
3941
3942 #[test]
3946 fn test_arc_try_lazy_fix_knot_tying_cross_thread() {
3947 use std::{
3948 sync::Mutex,
3949 thread,
3950 };
3951
3952 let stash: Arc<Mutex<Option<ArcTryLazy<i32, ()>>>> = Arc::new(Mutex::new(None));
3953 let stash_clone = stash.clone();
3954 let lazy = arc_try_lazy_fix(move |self_ref: ArcTryLazy<i32, ()>| {
3955 *stash_clone.lock().unwrap() = Some(self_ref);
3956 Ok(77)
3957 });
3958 assert_eq!(lazy.evaluate(), Ok(&77));
3959 let self_ref = stash.lock().unwrap().clone().unwrap();
3960 let handle = thread::spawn(move || self_ref.evaluate_owned());
3961 assert_eq!(handle.join().unwrap(), Ok(77));
3962 }
3963}