1#[fp_macros::document_module]
16mod inner {
17 use {
18 crate::{
19 Apply,
20 brands::{
21 ArcBrand,
22 LazyBrand,
23 RcBrand,
24 },
25 classes::{
26 CloneFn,
27 Deferrable,
28 LiftFn,
29 Monoid,
30 RefFoldable,
31 RefFoldableWithIndex,
32 RefFunctor,
33 RefFunctorWithIndex,
34 RefLift,
35 RefPointed,
36 RefSemiapplicative,
37 RefSemimonad,
38 Semigroup,
39 SendCloneFn,
40 SendDeferrable,
41 SendLiftFn,
42 SendRefFoldable,
43 SendRefFoldableWithIndex,
44 SendRefFunctor,
45 SendRefFunctorWithIndex,
46 SendRefLift,
47 SendRefPointed,
48 SendRefSemiapplicative,
49 SendRefSemimonad,
50 WithIndex,
51 },
52 dispatch::Ref,
53 impl_kind,
54 kinds::*,
55 types::{
56 SendThunk,
57 Thunk,
58 Trampoline,
59 },
60 },
61 fp_macros::*,
62 std::{
63 cell::LazyCell,
64 fmt,
65 hash::{
66 Hash,
67 Hasher,
68 },
69 rc::Rc,
70 sync::{
71 Arc,
72 LazyLock,
73 },
74 },
75 };
76
77 pub use crate::classes::LazyConfig;
78
79 pub struct RcLazyConfig;
83
84 impl LazyConfig for RcLazyConfig {
85 type Lazy<'a, A: 'a> = Rc<LazyCell<A, Box<dyn FnOnce() -> A + 'a>>>;
86 type PointerBrand = RcBrand;
87 type Thunk<'a, A: 'a> = dyn FnOnce() -> A + 'a;
88
89 #[document_signature]
91 #[document_type_parameters("The lifetime of the computation.", "The type of the value.")]
93 #[document_parameters("The initializer thunk.")]
95 #[document_returns("A new lazy cell.")]
97 #[document_examples]
99 fn lazy_new<'a, A: 'a>(f: Box<Self::Thunk<'a, A>>) -> Self::Lazy<'a, A> {
110 Rc::new(LazyCell::new(f))
111 }
112
113 #[document_signature]
115 #[document_type_parameters(
117 "The lifetime of the computation.",
118 "The borrow lifetime.",
119 "The type of the value."
120 )]
121 #[document_parameters("The lazy cell to evaluate.")]
123 #[document_returns("A reference to the value.")]
125 #[document_examples]
127 fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
138 LazyCell::force(lazy)
139 }
140 }
141
142 pub struct ArcLazyConfig;
146
147 impl LazyConfig for ArcLazyConfig {
148 type Lazy<'a, A: 'a> = Arc<LazyLock<A, Box<dyn FnOnce() -> A + Send + 'a>>>;
149 type PointerBrand = ArcBrand;
150 type Thunk<'a, A: 'a> = dyn FnOnce() -> A + Send + 'a;
151
152 #[document_signature]
154 #[document_type_parameters("The lifetime of the computation.", "The type of the value.")]
156 #[document_parameters("The initializer thunk.")]
158 #[document_returns("A new lazy cell.")]
160 #[document_examples]
162 fn lazy_new<'a, A: 'a>(f: Box<Self::Thunk<'a, A>>) -> Self::Lazy<'a, A> {
173 Arc::new(LazyLock::new(f))
174 }
175
176 #[document_signature]
178 #[document_type_parameters(
180 "The lifetime of the computation.",
181 "The borrow lifetime.",
182 "The type of the value."
183 )]
184 #[document_parameters("The lazy cell to evaluate.")]
186 #[document_returns("A reference to the value.")]
188 #[document_examples]
190 fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
201 LazyLock::force(lazy)
202 }
203 }
204
205 #[document_type_parameters(
224 "The lifetime of the computation.",
225 "The type of the computed value.",
226 "The memoization configuration (determines Rc vs Arc)."
227 )]
228 pub struct Lazy<'a, A, Config: LazyConfig = RcLazyConfig>(
230 pub(crate) Config::Lazy<'a, A>,
232 )
233 where
234 A: 'a;
235
236 #[document_type_parameters(
237 "The lifetime of the computation.",
238 "The type of the computed value.",
239 "The memoization configuration (determines Rc vs Arc)."
240 )]
241 #[document_parameters("The instance to clone.")]
242 impl<'a, A, Config: LazyConfig> Clone for Lazy<'a, A, Config>
243 where
244 A: 'a,
245 {
246 #[document_signature]
247 #[document_returns("A new `Lazy` instance that shares the same underlying memoized value.")]
248 #[document_examples]
249 fn clone(&self) -> Self {
266 Self(self.0.clone())
267 }
268 }
269
270 #[document_type_parameters(
271 "The lifetime of the computation.",
272 "The type of the computed value.",
273 "The memoization configuration (determines Rc vs Arc)."
274 )]
275 #[document_parameters("The lazy instance.")]
276 impl<'a, A, Config: LazyConfig> Lazy<'a, A, Config>
277 where
278 A: 'a,
279 {
280 #[document_signature]
282 #[document_returns("A reference to the memoized value.")]
284 #[document_examples]
286 #[inline]
297 pub fn evaluate(&self) -> &A {
298 Config::evaluate(&self.0)
299 }
300 }
301
302 #[document_type_parameters(
303 "The lifetime of the computation.",
304 "The type of the computed value."
305 )]
306 #[document_parameters("The lazy instance.")]
307 impl<'a, A> Lazy<'a, A, RcLazyConfig>
308 where
309 A: 'a,
310 {
311 #[document_signature]
313 #[document_parameters("The closure that produces the value.")]
315 #[document_returns("A new `Lazy` instance.")]
317 #[inline]
319 #[document_examples]
320 pub fn new(f: impl FnOnce() -> A + 'a) -> Self {
331 Lazy(RcLazyConfig::lazy_new(Box::new(f)))
332 }
333
334 #[document_signature]
338 #[document_parameters("The pre-computed value to wrap.")]
340 #[document_returns("A new `Lazy` instance containing the value.")]
342 #[inline]
344 #[document_examples]
345 pub fn pure(a: A) -> Self {
356 Lazy(RcLazyConfig::lazy_new(Box::new(move || a)))
357 }
358
359 #[document_signature]
364 #[document_returns("An owned clone of the memoized value.")]
366 #[document_examples]
368 #[inline]
380 pub fn evaluate_owned(&self) -> A
381 where
382 A: Clone, {
383 self.evaluate().clone()
384 }
385
386 #[document_signature]
392 #[document_type_parameters("The type of the result.")]
393 #[document_parameters("The function to apply to the memoized value.")]
394 #[document_returns("A new `Lazy` instance containing the mapped value.")]
395 #[document_examples]
396 #[inline]
408 pub fn ref_map<B: 'a>(
409 &self,
410 f: impl Fn(&A) -> B + 'a,
411 ) -> Lazy<'a, B, RcLazyConfig> {
412 let this = self.clone();
413 RcLazy::new(move || f(this.evaluate()))
414 }
415 }
416
417 #[document_type_parameters(
418 "The lifetime of the computation.",
419 "The type of the computed value."
420 )]
421 impl<'a, A> From<Thunk<'a, A>> for Lazy<'a, A, RcLazyConfig> {
422 #[document_signature]
423 #[document_parameters("The thunk to convert.")]
424 #[document_returns("A new `Lazy` instance that will evaluate the thunk on first access.")]
425 #[document_examples]
426 fn from(eval: Thunk<'a, A>) -> Self {
437 Self::new(move || eval.evaluate())
438 }
439 }
440
441 #[document_type_parameters(
442 "The lifetime of the computation.",
443 "The type of the computed value."
444 )]
445 impl<'a, A: 'static> From<Trampoline<A>> for Lazy<'a, A, RcLazyConfig> {
446 #[document_signature]
447 #[document_parameters("The trampoline to convert.")]
448 #[document_returns(
449 "A new `Lazy` instance that will evaluate the trampoline on first access."
450 )]
451 #[document_examples]
452 fn from(task: Trampoline<A>) -> Self {
463 Self::new(move || task.evaluate())
464 }
465 }
466
467 #[document_type_parameters(
468 "The lifetime of the computation.",
469 "The type of the computed value."
470 )]
471 impl<'a, A: Send + Sync + 'a> From<Thunk<'a, A>> for Lazy<'a, A, ArcLazyConfig> {
472 #[document_signature]
477 #[document_parameters("The thunk to convert.")]
478 #[document_returns("A new `Lazy` instance containing the eagerly evaluated value.")]
479 #[document_examples]
480 fn from(eval: Thunk<'a, A>) -> Self {
491 Self::pure(eval.evaluate())
492 }
493 }
494
495 #[document_type_parameters(
496 "The lifetime of the computation.",
497 "The type of the computed value."
498 )]
499 impl<'a, A: Send + Sync + 'static> From<Trampoline<A>> for Lazy<'a, A, ArcLazyConfig> {
500 #[document_signature]
505 #[document_parameters("The trampoline to convert.")]
506 #[document_returns("A new `Lazy` instance containing the eagerly evaluated value.")]
507 #[document_examples]
508 fn from(task: Trampoline<A>) -> Self {
519 Self::pure(task.evaluate())
520 }
521 }
522
523 #[document_type_parameters(
524 "The lifetime of the computation.",
525 "The type of the computed value."
526 )]
527 impl<'a, A: Send + Sync + 'a> From<SendThunk<'a, A>> for Lazy<'a, A, ArcLazyConfig> {
528 #[document_signature]
533 #[document_parameters("The send thunk to convert.")]
534 #[document_returns("A new `ArcLazy` wrapping the deferred computation.")]
535 #[document_examples]
536 fn from(thunk: SendThunk<'a, A>) -> Self {
547 Self::new(move || thunk.evaluate())
548 }
549 }
550
551 #[document_type_parameters(
552 "The lifetime of the computation.",
553 "The type of the computed value."
554 )]
555 impl<'a, A: Clone + Send + Sync + 'a> From<Lazy<'a, A, RcLazyConfig>>
556 for Lazy<'a, A, ArcLazyConfig>
557 {
558 #[document_signature]
563 #[document_parameters("The `RcLazy` instance to convert.")]
564 #[document_returns(
565 "A new `ArcLazy` instance containing a clone of the eagerly evaluated value."
566 )]
567 #[document_examples]
568 fn from(source: Lazy<'a, A, RcLazyConfig>) -> Self {
580 Self::pure(source.evaluate().clone())
581 }
582 }
583
584 #[document_type_parameters(
585 "The lifetime of the computation.",
586 "The type of the computed value."
587 )]
588 impl<'a, A: Clone + 'a> From<Lazy<'a, A, ArcLazyConfig>> for Lazy<'a, A, RcLazyConfig> {
589 #[document_signature]
594 #[document_parameters("The `ArcLazy` instance to convert.")]
595 #[document_returns(
596 "A new `RcLazy` instance containing a clone of the eagerly evaluated value."
597 )]
598 #[document_examples]
599 fn from(source: Lazy<'a, A, ArcLazyConfig>) -> Self {
611 Self::pure(source.evaluate().clone())
612 }
613 }
614
615 #[document_type_parameters(
616 "The lifetime of the computation.",
617 "The type of the computed value."
618 )]
619 #[document_parameters("The lazy instance.")]
620 impl<'a, A> Lazy<'a, A, ArcLazyConfig>
621 where
622 A: Send + Sync + 'a,
623 {
624 #[document_signature]
626 #[document_parameters("The closure that produces the value.")]
628 #[document_returns("A new `Lazy` instance.")]
630 #[inline]
632 #[document_examples]
633 pub fn new(f: impl FnOnce() -> A + Send + 'a) -> Self {
644 Lazy(ArcLazyConfig::lazy_new(Box::new(f)))
645 }
646
647 #[document_signature]
652 #[document_parameters("The pre-computed value to wrap.")]
654 #[document_returns("A new `Lazy` instance containing the value.")]
656 #[inline]
658 #[document_examples]
659 pub fn pure(a: A) -> Self {
670 Lazy(ArcLazyConfig::lazy_new(Box::new(move || a)))
671 }
672
673 #[document_signature]
679 #[document_returns("An owned clone of the memoized value.")]
681 #[document_examples]
683 #[inline]
695 pub fn evaluate_owned(&self) -> A
696 where
697 A: Clone, {
698 self.evaluate().clone()
699 }
700 }
701
702 #[document_type_parameters(
703 "The lifetime of the computation.",
704 "The type of the computed value."
705 )]
706 #[document_parameters("The lazy value to map over.")]
707 impl<'a, A: Send + Sync + 'a> Lazy<'a, A, ArcLazyConfig> {
708 #[document_signature]
719 #[document_type_parameters("The type of the result.")]
720 #[document_parameters("The function to apply to the memoized value.")]
721 #[document_returns("A new `ArcLazy` instance containing the mapped value.")]
722 #[document_examples]
723 #[inline]
735 pub fn ref_map<B: Send + Sync + 'a>(
736 &self,
737 f: impl Fn(&A) -> B + Send + 'a,
738 ) -> Lazy<'a, B, ArcLazyConfig> {
739 let this = self.clone();
740 ArcLazy::new(move || f(this.evaluate()))
741 }
742 }
743
744 pub type RcLazy<'a, A> = Lazy<'a, A, RcLazyConfig>;
746
747 pub type ArcLazy<'a, A> = Lazy<'a, A, ArcLazyConfig>;
749
750 impl_kind! {
751 impl<Config: LazyConfig> for LazyBrand<Config> {
752 type Of<'a, A: 'a>: 'a = Lazy<'a, A, Config>;
753 }
754 }
755
756 #[document_type_parameters(
757 "The lifetime of the computation.",
758 "The type of the computed value."
759 )]
760 impl<'a, A> Deferrable<'a> for Lazy<'a, A, RcLazyConfig>
761 where
762 A: Clone + 'a,
763 {
764 #[document_signature]
769 #[document_parameters("The thunk that produces the lazy value.")]
771 #[document_returns("A new `Lazy` value.")]
773 #[document_examples]
775 fn defer(f: impl FnOnce() -> Self + 'a) -> Self
788 where
789 Self: Sized, {
790 RcLazy::new(move || f().evaluate().clone())
791 }
792 }
793
794 #[document_type_parameters(
795 "The lifetime of the computation.",
796 "The type of the computed value."
797 )]
798 impl<'a, A> SendDeferrable<'a> for Lazy<'a, A, ArcLazyConfig>
799 where
800 A: Clone + Send + Sync + 'a,
801 {
802 #[document_signature]
807 #[document_parameters("The thunk that produces the lazy value.")]
809 #[document_returns("A new `ArcLazy` value.")]
811 #[document_examples]
813 fn send_defer(f: impl FnOnce() -> Self + Send + 'a) -> Self
825 where
826 Self: Sized, {
827 ArcLazy::new(move || f().evaluate().clone())
828 }
829 }
830
831 impl RefFunctor for LazyBrand<RcLazyConfig> {
832 #[document_signature]
834 #[document_type_parameters(
836 "The lifetime of the values.",
837 "The type of the value.",
838 "The type of the result."
839 )]
840 #[document_parameters("The function to apply.", "The memoized value.")]
842 #[document_returns("A new memoized value.")]
844 #[document_examples]
846 fn ref_map<'a, A: 'a, B: 'a>(
859 f: impl Fn(&A) -> B + 'a,
860 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
861 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
862 fa.ref_map(f)
863 }
864 }
865
866 impl SendRefFunctor for LazyBrand<ArcLazyConfig> {
867 #[document_signature]
869 #[document_type_parameters(
871 "The lifetime of the values.",
872 "The type of the value.",
873 "The type of the result."
874 )]
875 #[document_parameters("The function to apply.", "The memoized value.")]
877 #[document_returns("A new memoized value.")]
879 #[document_examples]
881 fn send_ref_map<'a, A: Send + Sync + 'a, B: Send + Sync + 'a>(
894 f: impl Fn(&A) -> B + Send + 'a,
895 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
896 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
897 fa.ref_map(f)
898 }
899 }
900
901 impl SendRefPointed for LazyBrand<ArcLazyConfig> {
904 #[document_signature]
906 #[document_type_parameters("The lifetime of the value.", "The type of the value.")]
908 #[document_parameters("A reference to the value to wrap.")]
910 #[document_returns("A new thread-safe memoized value containing a clone of the input.")]
912 #[document_examples]
913 fn send_ref_pure<'a, A: Clone + Send + Sync + 'a>(
926 a: &A
927 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
928 let cloned = a.clone();
929 ArcLazy::new(move || cloned)
930 }
931 }
932
933 impl SendRefLift for LazyBrand<ArcLazyConfig> {
936 #[document_signature]
938 #[document_type_parameters(
940 "The lifetime of the values.",
941 "The type of the first value.",
942 "The type of the second value.",
943 "The type of the result."
944 )]
945 #[document_parameters(
947 "The function to lift.",
948 "The first memoized value.",
949 "The second memoized value."
950 )]
951 #[document_returns("A new thread-safe memoized value containing the result.")]
953 #[document_examples]
954 fn send_ref_lift2<'a, A: Send + Sync + 'a, B: Send + Sync + 'a, C: Send + Sync + 'a>(
968 func: impl Fn(&A, &B) -> C + Send + 'a,
969 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
970 fb: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
971 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) {
972 let fa = fa.clone();
973 let fb = fb.clone();
974 ArcLazy::new(move || func(fa.evaluate(), fb.evaluate()))
975 }
976 }
977
978 impl SendRefSemiapplicative for LazyBrand<ArcLazyConfig> {
981 #[document_signature]
983 #[document_type_parameters(
985 "The lifetime of the values.",
986 "The brand of the thread-safe cloneable function wrapper.",
987 "The type of the input value.",
988 "The type of the output value."
989 )]
990 #[document_parameters("The memoized wrapped by-ref function.", "The memoized value.")]
992 #[document_returns("A new thread-safe memoized value containing the result.")]
994 #[document_examples]
995 fn send_ref_apply<
1011 'a,
1012 FnBrand: 'a + SendCloneFn<Ref>,
1013 A: Send + Sync + 'a,
1014 B: Send + Sync + 'a,
1015 >(
1016 ff: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as SendCloneFn<Ref>>::Of<'a, A, B>>),
1017 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1018 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1019 let ff = ff.clone();
1020 let fa = fa.clone();
1021 ArcLazy::new(move || {
1022 let f = ff.evaluate();
1023 let a = fa.evaluate();
1024 (**f)(a)
1025 })
1026 }
1027 }
1028
1029 impl SendRefSemimonad for LazyBrand<ArcLazyConfig> {
1032 #[document_signature]
1034 #[document_type_parameters(
1036 "The lifetime of the values.",
1037 "The type of the value inside the context.",
1038 "The type of the value in the resulting context."
1039 )]
1040 #[document_parameters(
1042 "The memoized value.",
1043 "A thread-safe function that receives a reference and returns a new memoized value."
1044 )]
1045 #[document_returns("A new thread-safe memoized value produced by the function.")]
1047 #[document_examples]
1048 fn send_ref_bind<'a, A: Send + Sync + 'a, B: Send + Sync + 'a>(
1064 ma: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1065 f: impl Fn(&A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + Send + 'a,
1066 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1067 f(ma.evaluate())
1068 }
1069 }
1070
1071 impl SendRefFoldable for LazyBrand<ArcLazyConfig> {
1074 #[document_signature]
1076 #[document_type_parameters(
1077 "The lifetime of the computation.",
1078 "The brand of the cloneable function to use.",
1079 "The type of the computed value.",
1080 "The monoid type."
1081 )]
1082 #[document_parameters("The mapping function.", "The Lazy to fold.")]
1083 #[document_returns("The monoid value.")]
1084 #[document_examples]
1085 fn send_ref_fold_map<'a, FnBrand, A: Send + Sync + 'a + Clone, M>(
1101 func: impl Fn(&A) -> M + Send + Sync + 'a,
1102 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1103 ) -> M
1104 where
1105 FnBrand: SendLiftFn + 'a,
1106 M: Monoid + Send + Sync + 'a, {
1107 func(fa.evaluate())
1108 }
1109 }
1110
1111 impl SendRefFoldableWithIndex for LazyBrand<ArcLazyConfig> {
1114 #[document_signature]
1116 #[document_type_parameters(
1117 "The lifetime of the computation.",
1118 "The brand of the cloneable function to use.",
1119 "The type of the computed value.",
1120 "The monoid type."
1121 )]
1122 #[document_parameters("The function to apply.", "The Lazy to fold.")]
1123 #[document_returns("The monoid value.")]
1124 #[document_examples]
1125 fn send_ref_fold_map_with_index<
1143 'a,
1144 FnBrand,
1145 A: Send + Sync + 'a + Clone,
1146 R: Monoid + Send + Sync + 'a,
1147 >(
1148 f: impl Fn((), &A) -> R + Send + Sync + 'a,
1149 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1150 ) -> R
1151 where
1152 FnBrand: SendLiftFn + 'a, {
1153 f((), fa.evaluate())
1154 }
1155 }
1156
1157 impl SendRefFunctorWithIndex for LazyBrand<ArcLazyConfig> {
1160 #[document_signature]
1162 #[document_type_parameters(
1163 "The lifetime of the computation.",
1164 "The type of the input value.",
1165 "The type of the output value."
1166 )]
1167 #[document_parameters("The function to apply.", "The Lazy to map over.")]
1168 #[document_returns("A new Lazy containing the mapped value.")]
1169 #[document_examples]
1170 fn send_ref_map_with_index<'a, A: Send + Sync + 'a, B: Send + Sync + 'a>(
1186 f: impl Fn((), &A) -> B + Send + Sync + 'a,
1187 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1188 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1189 Self::send_ref_map(move |a| f((), a), fa)
1190 }
1191 }
1192
1193 impl RefPointed for LazyBrand<RcLazyConfig> {
1196 #[document_signature]
1198 #[document_type_parameters(
1200 "The lifetime of the value.",
1201 "The type of the value. Must be `Clone`."
1202 )]
1203 #[document_parameters("A reference to the value to wrap.")]
1205 #[document_returns("A new memoized value containing a clone of the input.")]
1207 #[document_examples]
1209 fn ref_pure<'a, A: Clone + 'a>(
1222 a: &A
1223 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>) {
1224 let cloned = a.clone();
1225 RcLazy::new(move || cloned)
1226 }
1227 }
1228
1229 impl RefLift for LazyBrand<RcLazyConfig> {
1232 #[document_signature]
1234 #[document_type_parameters(
1236 "The lifetime of the values.",
1237 "The type of the first value.",
1238 "The type of the second value.",
1239 "The type of the result."
1240 )]
1241 #[document_parameters(
1243 "The function to lift.",
1244 "The first memoized value.",
1245 "The second memoized value."
1246 )]
1247 #[document_returns("A new memoized value containing the result.")]
1249 #[document_examples]
1251 fn ref_lift2<'a, A: 'a, B: 'a, C: 'a>(
1265 func: impl Fn(&A, &B) -> C + 'a,
1266 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1267 fb: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>),
1268 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, C>) {
1269 let fa = fa.clone();
1270 let fb = fb.clone();
1271 RcLazy::new(move || func(fa.evaluate(), fb.evaluate()))
1272 }
1273 }
1274
1275 impl RefSemiapplicative for LazyBrand<RcLazyConfig> {
1278 #[document_signature]
1280 #[document_type_parameters(
1282 "The lifetime of the values.",
1283 "The brand of the cloneable function wrapper.",
1284 "The type of the input value.",
1285 "The type of the output value."
1286 )]
1287 #[document_parameters("The memoized wrapped by-ref function.", "The memoized value.")]
1289 #[document_returns("A new memoized value containing the result of applying the function.")]
1291 #[document_examples]
1293 fn ref_apply<'a, FnBrand: 'a + CloneFn<Ref>, A: 'a, B: 'a>(
1307 ff: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, <FnBrand as CloneFn<Ref>>::Of<'a, A, B>>),
1308 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1309 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1310 let ff = ff.clone();
1311 let fa = fa.clone();
1312 RcLazy::new(move || {
1313 let f = ff.evaluate();
1314 let a = fa.evaluate();
1315 (**f)(a)
1316 })
1317 }
1318 }
1319
1320 impl RefSemimonad for LazyBrand<RcLazyConfig> {
1323 #[document_signature]
1325 #[document_type_parameters(
1327 "The lifetime of the values.",
1328 "The type of the value inside the context.",
1329 "The type of the value in the resulting context."
1330 )]
1331 #[document_parameters(
1333 "The memoized value.",
1334 "A function that receives a reference to the value and returns a new memoized value."
1335 )]
1336 #[document_returns("A new memoized value produced by the function.")]
1338 #[document_examples]
1340 fn ref_bind<'a, A: 'a, B: 'a>(
1358 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1359 f: impl Fn(&A) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) + 'a,
1360 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1361 f(fa.evaluate())
1362 }
1363 }
1364
1365 #[document_type_parameters(
1368 "The lifetime of the reference.",
1369 "The type of the computed value.",
1370 "The memoization configuration."
1371 )]
1372 #[document_parameters("The lazy value to display.")]
1373 impl<'a, A: fmt::Display + 'a, Config: LazyConfig> fmt::Display for Lazy<'a, A, Config> {
1374 #[document_signature]
1376 #[document_parameters("The formatter.")]
1378 #[document_returns("The formatting result.")]
1380 #[document_examples]
1382 fn fmt(
1396 &self,
1397 f: &mut fmt::Formatter<'_>,
1398 ) -> fmt::Result {
1399 fmt::Display::fmt(self.evaluate(), f)
1400 }
1401 }
1402
1403 #[document_type_parameters(
1406 "The lifetime of the computation.",
1407 "The type of the computed value."
1408 )]
1409 impl<'a, A: Semigroup + Clone + 'a> Semigroup for Lazy<'a, A, RcLazyConfig> {
1410 #[document_signature]
1414 #[document_parameters("The first lazy value.", "The second lazy value.")]
1416 #[document_returns("A new `RcLazy` containing the combined result.")]
1418 #[document_examples]
1420 fn append(
1433 a: Self,
1434 b: Self,
1435 ) -> Self {
1436 RcLazy::new(move || Semigroup::append(a.evaluate().clone(), b.evaluate().clone()))
1437 }
1438 }
1439
1440 #[document_type_parameters(
1441 "The lifetime of the computation.",
1442 "The type of the computed value."
1443 )]
1444 impl<'a, A: Semigroup + Clone + Send + Sync + 'a> Semigroup for Lazy<'a, A, ArcLazyConfig> {
1445 #[document_signature]
1449 #[document_parameters("The first lazy value.", "The second lazy value.")]
1451 #[document_returns("A new `ArcLazy` containing the combined result.")]
1453 #[document_examples]
1455 fn append(
1468 a: Self,
1469 b: Self,
1470 ) -> Self {
1471 ArcLazy::new(move || Semigroup::append(a.evaluate().clone(), b.evaluate().clone()))
1472 }
1473 }
1474
1475 #[document_type_parameters(
1478 "The lifetime of the computation.",
1479 "The type of the computed value."
1480 )]
1481 impl<'a, A: Monoid + Clone + 'a> Monoid for Lazy<'a, A, RcLazyConfig> {
1482 #[document_signature]
1484 #[document_returns("An `RcLazy` producing the identity value of `A`.")]
1486 #[document_examples]
1488 fn empty() -> Self {
1499 RcLazy::new(|| Monoid::empty())
1500 }
1501 }
1502
1503 #[document_type_parameters(
1504 "The lifetime of the computation.",
1505 "The type of the computed value."
1506 )]
1507 impl<'a, A: Monoid + Clone + Send + Sync + 'a> Monoid for Lazy<'a, A, ArcLazyConfig> {
1508 #[document_signature]
1510 #[document_returns("An `ArcLazy` producing the identity value of `A`.")]
1512 #[document_examples]
1514 fn empty() -> Self {
1525 ArcLazy::new(|| Monoid::empty())
1526 }
1527 }
1528
1529 #[document_type_parameters(
1532 "The lifetime of the reference.",
1533 "The type of the computed value.",
1534 "The memoization configuration."
1535 )]
1536 #[document_parameters("The lazy value to hash.")]
1537 impl<'a, A: Hash + 'a, Config: LazyConfig> Hash for Lazy<'a, A, Config> {
1538 #[document_signature]
1540 #[document_type_parameters("The type of the hasher.")]
1541 #[document_parameters("The hasher state.")]
1543 #[document_examples]
1545 fn hash<H: Hasher>(
1577 &self,
1578 state: &mut H,
1579 ) {
1580 self.evaluate().hash(state)
1581 }
1582 }
1583
1584 #[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1587 impl<Config: LazyConfig> RefFoldable for LazyBrand<Config> {
1588 #[document_signature]
1593 #[document_type_parameters(
1595 "The lifetime of the computation.",
1596 "The brand of the cloneable function to use.",
1597 "The type of the elements in the structure.",
1598 "The type of the monoid."
1599 )]
1600 #[document_parameters("The mapping function.", "The Lazy to fold.")]
1602 #[document_returns("The monoid value.")]
1604 #[document_examples]
1605 fn ref_fold_map<'a, FnBrand, A: 'a + Clone, M>(
1621 func: impl Fn(&A) -> M + 'a,
1622 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1623 ) -> M
1624 where
1625 FnBrand: LiftFn + 'a,
1626 M: Monoid + 'a, {
1627 func(fa.evaluate())
1628 }
1629
1630 #[document_signature]
1634 #[document_type_parameters(
1636 "The lifetime of the computation.",
1637 "The brand of the cloneable function to use.",
1638 "The type of the elements in the structure.",
1639 "The type of the accumulator."
1640 )]
1641 #[document_parameters(
1643 "The function to apply to each element reference and the accumulator.",
1644 "The initial value of the accumulator.",
1645 "The `Lazy` to fold."
1646 )]
1647 #[document_returns("The final accumulator value.")]
1649 #[document_examples]
1650 fn ref_fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
1667 func: impl Fn(&A, B) -> B + 'a,
1668 initial: B,
1669 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1670 ) -> B
1671 where
1672 FnBrand: LiftFn + 'a, {
1673 func(fa.evaluate(), initial)
1674 }
1675
1676 #[document_signature]
1680 #[document_type_parameters(
1682 "The lifetime of the computation.",
1683 "The brand of the cloneable function to use.",
1684 "The type of the elements in the structure.",
1685 "The type of the accumulator."
1686 )]
1687 #[document_parameters(
1689 "The function to apply to the accumulator and each element reference.",
1690 "The initial value of the accumulator.",
1691 "The `Lazy` to fold."
1692 )]
1693 #[document_returns("The final accumulator value.")]
1695 #[document_examples]
1696 fn ref_fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
1713 func: impl Fn(B, &A) -> B + 'a,
1714 initial: B,
1715 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1716 ) -> B
1717 where
1718 FnBrand: LiftFn + 'a, {
1719 func(initial, fa.evaluate())
1720 }
1721 }
1722
1723 #[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1726 impl<Config: LazyConfig> WithIndex for LazyBrand<Config> {
1727 type Index = ();
1728 }
1729
1730 #[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1733 impl<Config: LazyConfig> RefFoldableWithIndex for LazyBrand<Config> {
1734 #[document_signature]
1739 #[document_type_parameters(
1741 "The lifetime of the computation.",
1742 "The brand of the cloneable function to use.",
1743 "The type of the computed value.",
1744 "The monoid type."
1745 )]
1746 #[document_parameters(
1748 "The function to apply to the index and value reference.",
1749 "The Lazy to fold."
1750 )]
1751 #[document_returns("The monoid value.")]
1753 #[document_examples]
1754 fn ref_fold_map_with_index<'a, FnBrand, A: 'a + Clone, R: Monoid + 'a>(
1771 f: impl Fn((), &A) -> R + 'a,
1772 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1773 ) -> R
1774 where
1775 FnBrand: LiftFn + 'a, {
1776 f((), fa.evaluate())
1777 }
1778 }
1779
1780 impl RefFunctorWithIndex for LazyBrand<RcLazyConfig> {
1783 #[document_signature]
1788 #[document_type_parameters(
1790 "The lifetime of the computation.",
1791 "The type of the input value.",
1792 "The type of the output value."
1793 )]
1794 #[document_parameters(
1796 "The function to apply to the index and value reference.",
1797 "The Lazy to map over."
1798 )]
1799 #[document_returns("A new Lazy containing the mapped value.")]
1801 #[document_examples]
1802 fn ref_map_with_index<'a, A: 'a, B: 'a>(
1818 f: impl Fn((), &A) -> B + 'a,
1819 fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1820 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1821 Self::ref_map(move |a| f((), a), fa)
1822 }
1823 }
1824
1825 #[document_type_parameters(
1828 "The lifetime of the computation.",
1829 "The type of the computed value.",
1830 "The memoization configuration."
1831 )]
1832 #[document_parameters("The lazy value to compare.")]
1833 impl<'a, A: PartialEq + 'a, Config: LazyConfig> PartialEq for Lazy<'a, A, Config> {
1834 #[document_signature]
1838 #[document_parameters("The other lazy value to compare with.")]
1839 #[document_returns("`true` if the evaluated values are equal.")]
1840 #[document_examples]
1841 fn eq(
1853 &self,
1854 other: &Self,
1855 ) -> bool {
1856 self.evaluate() == other.evaluate()
1857 }
1858 }
1859
1860 #[document_type_parameters(
1863 "The lifetime of the computation.",
1864 "The type of the computed value.",
1865 "The memoization configuration."
1866 )]
1867 #[document_parameters("The lazy value to compare.")]
1868 impl<'a, A: PartialOrd + 'a, Config: LazyConfig> PartialOrd for Lazy<'a, A, Config> {
1869 #[document_signature]
1873 #[document_parameters("The other lazy value to compare with.")]
1874 #[document_returns(
1875 "The ordering between the evaluated values, or `None` if not comparable."
1876 )]
1877 #[document_examples]
1878 fn partial_cmp(
1890 &self,
1891 other: &Self,
1892 ) -> Option<std::cmp::Ordering> {
1893 self.evaluate().partial_cmp(other.evaluate())
1894 }
1895 }
1896
1897 #[document_type_parameters(
1900 "The lifetime of the computation.",
1901 "The type of the computed value.",
1902 "The memoization configuration."
1903 )]
1904 impl<'a, A: Eq + 'a, Config: LazyConfig> Eq for Lazy<'a, A, Config> {}
1905
1906 #[document_type_parameters(
1909 "The lifetime of the computation.",
1910 "The type of the computed value.",
1911 "The memoization configuration."
1912 )]
1913 #[document_parameters("The lazy value to compare.")]
1914 impl<'a, A: Ord + 'a, Config: LazyConfig> Ord for Lazy<'a, A, Config> {
1915 #[document_signature]
1919 #[document_parameters("The other lazy value to compare with.")]
1920 #[document_returns("The ordering between the evaluated values.")]
1921 #[document_examples]
1922 fn cmp(
1934 &self,
1935 other: &Self,
1936 ) -> std::cmp::Ordering {
1937 self.evaluate().cmp(other.evaluate())
1938 }
1939 }
1940
1941 #[document_type_parameters(
1942 "The lifetime of the computation.",
1943 "The type of the computed value.",
1944 "The memoization configuration."
1945 )]
1946 #[document_parameters("The lazy value to format.")]
1947 impl<'a, A, Config: LazyConfig> fmt::Debug for Lazy<'a, A, Config>
1948 where
1949 A: 'a,
1950 {
1951 #[document_signature]
1953 #[document_parameters("The formatter.")]
1954 #[document_returns("The formatting result.")]
1955 #[document_examples]
1956 fn fmt(
1966 &self,
1967 f: &mut fmt::Formatter<'_>,
1968 ) -> fmt::Result {
1969 f.write_str("Lazy(..)")
1970 }
1971 }
1972
1973 #[document_signature]
1987 #[document_type_parameters(
1989 "The lifetime of the computation.",
1990 "The type of the computed value."
1991 )]
1992 #[document_parameters(
1994 "The function that receives a lazy self-reference and produces the value."
1995 )]
1996 #[document_returns("A new `RcLazy` instance.")]
1998 #[document_examples]
2000 pub fn rc_lazy_fix<'a, A: Clone + 'a>(
2011 f: impl FnOnce(RcLazy<'a, A>) -> A + 'a
2012 ) -> RcLazy<'a, A> {
2013 use std::{
2014 cell::OnceCell,
2015 rc::Weak,
2016 };
2017
2018 #[expect(
2019 clippy::type_complexity,
2020 reason = "Nested smart pointers are inherent to the fix-point construction"
2021 )]
2022 let cell: Rc<OnceCell<Weak<LazyCell<A, Box<dyn FnOnce() -> A + 'a>>>>> = Rc::new(OnceCell::new());
2023 let cell_clone = cell.clone();
2024 let lazy = RcLazy::new(move || {
2025 #[expect(
2029 clippy::expect_used,
2030 reason = "Invariant: cell set immediately after closure creation, Weak upgrade always succeeds"
2031 )]
2032 let weak = cell_clone.get().expect("rc_lazy_fix: cell not initialized");
2033 #[expect(
2034 clippy::expect_used,
2035 reason = "Invariant: cell set immediately after closure creation, Weak upgrade always succeeds"
2036 )]
2037 let self_ref = Lazy(weak.upgrade().expect("rc_lazy_fix: outer lazy was dropped"));
2038 f(self_ref)
2039 });
2040 let _ = cell.set(Rc::downgrade(&lazy.0));
2041 lazy
2042 }
2043
2044 #[document_signature]
2056 #[document_type_parameters(
2058 "The lifetime of the computation.",
2059 "The type of the computed value."
2060 )]
2061 #[document_parameters(
2063 "The function that receives a lazy self-reference and produces the value."
2064 )]
2065 #[document_returns("A new `ArcLazy` instance.")]
2067 #[document_examples]
2069 pub fn arc_lazy_fix<'a, A: Clone + Send + Sync + 'a>(
2080 f: impl FnOnce(ArcLazy<'a, A>) -> A + Send + 'a
2081 ) -> ArcLazy<'a, A> {
2082 use std::sync::{
2083 OnceLock,
2084 Weak,
2085 };
2086
2087 #[expect(
2088 clippy::type_complexity,
2089 reason = "Nested smart pointers are inherent to the fix-point construction"
2090 )]
2091 let cell: Arc<OnceLock<Weak<LazyLock<A, Box<dyn FnOnce() -> A + Send + 'a>>>>> =
2092 Arc::new(OnceLock::new());
2093 let cell_clone = cell.clone();
2094 let lazy = ArcLazy::new(move || {
2095 #[expect(
2099 clippy::expect_used,
2100 reason = "Invariant: cell set immediately after closure creation, Weak upgrade always succeeds"
2101 )]
2102 let weak = cell_clone.get().expect("arc_lazy_fix: cell not initialized");
2103 #[expect(
2104 clippy::expect_used,
2105 reason = "Invariant: cell set immediately after closure creation, Weak upgrade always succeeds"
2106 )]
2107 let self_ref = Lazy(weak.upgrade().expect("arc_lazy_fix: outer lazy was dropped"));
2108 f(self_ref)
2109 });
2110 let _ = cell.set(Arc::downgrade(&lazy.0));
2111 lazy
2112 }
2113}
2114
2115pub use inner::*;
2116
2117#[cfg(test)]
2118#[expect(
2119 clippy::unwrap_used,
2120 clippy::panic,
2121 reason = "Tests use panicking operations for brevity and clarity"
2122)]
2123mod tests {
2124 use {
2125 super::inner::*,
2126 crate::types::{
2127 Thunk,
2128 Trampoline,
2129 },
2130 quickcheck_macros::quickcheck,
2131 std::{
2132 cell::RefCell,
2133 rc::Rc,
2134 sync::Arc,
2135 },
2136 };
2137
2138 #[test]
2142 fn test_memo_caching() {
2143 let counter = Rc::new(RefCell::new(0));
2144 let counter_clone = counter.clone();
2145 let memo = RcLazy::new(move || {
2146 *counter_clone.borrow_mut() += 1;
2147 42
2148 });
2149
2150 assert_eq!(*counter.borrow(), 0);
2151 assert_eq!(*memo.evaluate(), 42);
2152 assert_eq!(*counter.borrow(), 1);
2153 assert_eq!(*memo.evaluate(), 42);
2154 assert_eq!(*counter.borrow(), 1);
2155 }
2156
2157 #[test]
2161 fn test_memo_sharing() {
2162 let counter = Rc::new(RefCell::new(0));
2163 let counter_clone = counter.clone();
2164 let memo = RcLazy::new(move || {
2165 *counter_clone.borrow_mut() += 1;
2166 42
2167 });
2168 let shared = memo.clone();
2169
2170 assert_eq!(*memo.evaluate(), 42);
2171 assert_eq!(*counter.borrow(), 1);
2172 assert_eq!(*shared.evaluate(), 42);
2173 assert_eq!(*counter.borrow(), 1);
2174 }
2175
2176 #[test]
2180 fn test_arc_memo_thread_safety() {
2181 use std::{
2182 sync::atomic::{
2183 AtomicUsize,
2184 Ordering,
2185 },
2186 thread,
2187 };
2188
2189 let counter = Arc::new(AtomicUsize::new(0));
2190 let counter_clone = counter.clone();
2191 let memo = ArcLazy::new(move || {
2192 counter_clone.fetch_add(1, Ordering::SeqCst);
2193 42
2194 });
2195
2196 let mut handles = vec![];
2197 for _ in 0 .. 10 {
2198 let memo_clone = memo.clone();
2199 handles.push(thread::spawn(move || {
2200 assert_eq!(*memo_clone.evaluate(), 42);
2201 }));
2202 }
2203
2204 for handle in handles {
2205 handle.join().unwrap();
2206 }
2207
2208 assert_eq!(counter.load(Ordering::SeqCst), 1);
2209 }
2210
2211 #[test]
2215 fn test_memo_from_eval() {
2216 let eval = Thunk::new(|| 42);
2217 let memo = RcLazy::from(eval);
2218 assert_eq!(*memo.evaluate(), 42);
2219 }
2220
2221 #[test]
2225 fn test_memo_from_task() {
2226 let task = Trampoline::pure(42);
2228 let memo = RcLazy::from(task);
2229 assert_eq!(*memo.evaluate(), 42);
2230 }
2231
2232 #[test]
2236 fn test_rc_lazy_to_arc_lazy() {
2237 let rc = RcLazy::new(|| "hello".to_string());
2238 let arc: ArcLazy<String> = ArcLazy::from(rc);
2239 assert_eq!(*arc.evaluate(), "hello");
2240 }
2241
2242 #[test]
2246 fn test_arc_lazy_to_rc_lazy() {
2247 let arc = ArcLazy::new(|| "world".to_string());
2248 let rc: RcLazy<String> = RcLazy::from(arc);
2249 assert_eq!(*rc.evaluate(), "world");
2250 }
2251
2252 #[test]
2256 fn test_rc_to_arc_eager_evaluation() {
2257 let counter = Rc::new(RefCell::new(0));
2258 let counter_clone = counter.clone();
2259 let rc = RcLazy::new(move || {
2260 *counter_clone.borrow_mut() += 1;
2261 99
2262 });
2263 assert_eq!(*counter.borrow(), 0);
2264
2265 let arc: ArcLazy<i32> = ArcLazy::from(rc);
2266 assert_eq!(*counter.borrow(), 1);
2268 assert_eq!(*arc.evaluate(), 99);
2269 assert_eq!(*counter.borrow(), 1);
2271 }
2272
2273 #[test]
2277 fn test_arc_to_rc_eager_evaluation() {
2278 use std::sync::atomic::{
2279 AtomicUsize,
2280 Ordering,
2281 };
2282
2283 let counter = Arc::new(AtomicUsize::new(0));
2284 let counter_clone = counter.clone();
2285 let arc = ArcLazy::new(move || {
2286 counter_clone.fetch_add(1, Ordering::SeqCst);
2287 77
2288 });
2289 assert_eq!(counter.load(Ordering::SeqCst), 0);
2290
2291 let rc: RcLazy<i32> = RcLazy::from(arc);
2292 assert_eq!(counter.load(Ordering::SeqCst), 1);
2294 assert_eq!(*rc.evaluate(), 77);
2295 assert_eq!(counter.load(Ordering::SeqCst), 1);
2297 }
2298
2299 #[quickcheck]
2301 fn prop_rc_to_arc_preserves_value(x: i32) -> bool {
2302 let rc = RcLazy::new(move || x);
2303 let arc: ArcLazy<i32> = ArcLazy::from(rc);
2304 *arc.evaluate() == x
2305 }
2306
2307 #[quickcheck]
2309 fn prop_arc_to_rc_preserves_value(x: i32) -> bool {
2310 let arc = ArcLazy::new(move || x);
2311 let rc: RcLazy<i32> = RcLazy::from(arc);
2312 *rc.evaluate() == x
2313 }
2314
2315 #[test]
2317 fn test_defer() {
2318 use crate::classes::deferrable::defer;
2319
2320 let memo: RcLazy<i32> = defer(|| RcLazy::new(|| 42));
2321 assert_eq!(*memo.evaluate(), 42);
2322 }
2323
2324 #[test]
2326 fn test_send_defer() {
2327 use crate::classes::send_deferrable::send_defer;
2328
2329 let memo: ArcLazy<i32> = send_defer(|| ArcLazy::new(|| 42));
2330 assert_eq!(*memo.evaluate(), 42);
2331 }
2332
2333 #[test]
2337 fn test_rc_lazy_pure() {
2338 let lazy = RcLazy::pure(42);
2339 assert_eq!(*lazy.evaluate(), 42);
2340
2341 let shared = lazy.clone();
2343 assert_eq!(*shared.evaluate(), 42);
2344 }
2345
2346 #[test]
2350 fn test_arc_lazy_pure() {
2351 let lazy = ArcLazy::pure(42);
2352 assert_eq!(*lazy.evaluate(), 42);
2353
2354 let shared = lazy.clone();
2356 assert_eq!(*shared.evaluate(), 42);
2357 }
2358
2359 #[test]
2363 fn test_arc_lazy_pure_thread_safety() {
2364 use std::thread;
2365
2366 let lazy = ArcLazy::pure(42);
2367
2368 let mut handles = vec![];
2369 for _ in 0 .. 10 {
2370 let lazy_clone = lazy.clone();
2371 handles.push(thread::spawn(move || {
2372 assert_eq!(*lazy_clone.evaluate(), 42);
2373 }));
2374 }
2375
2376 for handle in handles {
2377 handle.join().unwrap();
2378 }
2379 }
2380
2381 #[quickcheck]
2385 fn prop_rc_memo_get_memoization(x: i32) -> bool {
2386 let memo = RcLazy::new(move || x.wrapping_mul(2));
2387 let result1 = *memo.evaluate();
2388 let result2 = *memo.evaluate();
2389 result1 == result2
2390 }
2391
2392 #[quickcheck]
2394 fn prop_arc_memo_get_memoization(x: i32) -> bool {
2395 let memo = ArcLazy::new(move || x.wrapping_mul(2));
2396 let result1 = *memo.evaluate();
2397 let result2 = *memo.evaluate();
2398 result1 == result2
2399 }
2400
2401 #[quickcheck]
2405 fn prop_rc_memo_clone_shares_state(x: i32) -> bool {
2406 let memo1 = RcLazy::new(move || x);
2407 let memo2 = memo1.clone();
2408
2409 let result1 = *memo1.evaluate();
2410 let result2 = *memo2.evaluate();
2411 result1 == result2
2412 }
2413
2414 #[quickcheck]
2416 fn prop_arc_memo_clone_shares_state(x: i32) -> bool {
2417 let memo1 = ArcLazy::new(move || x);
2418 let memo2 = memo1.clone();
2419
2420 let result1 = *memo1.evaluate();
2421 let result2 = *memo2.evaluate();
2422 result1 == result2
2423 }
2424
2425 #[quickcheck]
2427 fn prop_memo_get_original_then_clone(x: String) -> bool {
2428 let value = x.clone();
2429 let memo = RcLazy::new(move || value.clone());
2430 let memo_clone = memo.clone();
2431
2432 let result1 = memo.evaluate().clone();
2433 let result2 = memo_clone.evaluate().clone();
2434
2435 result1 == result2
2436 }
2437
2438 #[quickcheck]
2442 fn prop_memo_deterministic(
2443 x: i32,
2444 y: i32,
2445 ) -> bool {
2446 let memo1 = RcLazy::new(move || x.wrapping_add(y));
2447 let memo2 = RcLazy::new(move || x.wrapping_add(y));
2448
2449 *memo1.evaluate() == *memo2.evaluate()
2450 }
2451
2452 #[test]
2458 fn test_arc_lazy_ref_map() {
2459 let memo = ArcLazy::new(|| 10);
2460 let mapped = memo.ref_map(|x| *x * 2);
2461 assert_eq!(*mapped.evaluate(), 20);
2462 }
2463
2464 #[test]
2468 fn test_arc_lazy_ref_map_thread_safety() {
2469 use std::thread;
2470
2471 let memo = ArcLazy::new(|| 10);
2472 let mapped = memo.ref_map(|x| *x * 3);
2473
2474 let mut handles = vec![];
2475 for _ in 0 .. 5 {
2476 let m = mapped.clone();
2477 handles.push(thread::spawn(move || {
2478 assert_eq!(*m.evaluate(), 30);
2479 }));
2480 }
2481
2482 for handle in handles {
2483 handle.join().unwrap();
2484 }
2485 }
2486
2487 #[test]
2493 fn test_rc_lazy_semigroup() {
2494 use crate::classes::semigroup::append;
2495
2496 let a = RcLazy::pure("Hello".to_string());
2497 let b = RcLazy::pure(" World".to_string());
2498 let c = append(a, b);
2499 assert_eq!(*c.evaluate(), "Hello World");
2500 }
2501
2502 #[test]
2506 fn test_arc_lazy_semigroup() {
2507 use crate::classes::semigroup::append;
2508
2509 let a = ArcLazy::pure("Hello".to_string());
2510 let b = ArcLazy::pure(" World".to_string());
2511 let c = append(a, b);
2512 assert_eq!(*c.evaluate(), "Hello World");
2513 }
2514
2515 #[test]
2517 fn test_rc_lazy_semigroup_associativity() {
2518 use crate::classes::semigroup::append;
2519
2520 let a = RcLazy::pure("a".to_string());
2521 let b = RcLazy::pure("b".to_string());
2522 let c = RcLazy::pure("c".to_string());
2523
2524 let ab_c = append(append(a.clone(), b.clone()), c.clone());
2525 let a_bc = append(a, append(b, c));
2526
2527 assert_eq!(*ab_c.evaluate(), *a_bc.evaluate());
2528 }
2529
2530 #[test]
2536 fn test_rc_lazy_monoid() {
2537 use crate::classes::monoid::empty;
2538
2539 let t: RcLazy<String> = empty();
2540 assert_eq!(*t.evaluate(), "");
2541 }
2542
2543 #[test]
2547 fn test_arc_lazy_monoid() {
2548 use crate::classes::monoid::empty;
2549
2550 let t: ArcLazy<String> = empty();
2551 assert_eq!(*t.evaluate(), "");
2552 }
2553
2554 #[test]
2556 fn test_rc_lazy_monoid_identity() {
2557 use crate::classes::{
2558 monoid::empty,
2559 semigroup::append,
2560 };
2561
2562 let a = RcLazy::pure("hello".to_string());
2563
2564 let left: RcLazy<String> = append(empty(), a.clone());
2566 assert_eq!(*left.evaluate(), *a.evaluate());
2567
2568 let right: RcLazy<String> = append(a.clone(), empty());
2570 assert_eq!(*right.evaluate(), *a.evaluate());
2571 }
2572
2573 #[test]
2577 fn test_rc_lazy_ref_fold_right() {
2578 use crate::functions::*;
2579
2580 let lazy = RcLazy::pure(10);
2581 let result = explicit::fold_right::<
2582 crate::brands::RcFnBrand,
2583 crate::brands::LazyBrand<RcLazyConfig>,
2584 _,
2585 _,
2586 _,
2587 _,
2588 >(|a: &i32, b| *a + b, 5, &lazy);
2589 assert_eq!(result, 15);
2590 }
2591
2592 #[test]
2594 fn test_rc_lazy_ref_fold_left() {
2595 use crate::functions::*;
2596
2597 let lazy = RcLazy::pure(10);
2598 let result = explicit::fold_left::<
2599 crate::brands::RcFnBrand,
2600 crate::brands::LazyBrand<RcLazyConfig>,
2601 _,
2602 _,
2603 _,
2604 _,
2605 >(|b, a: &i32| b + *a, 5, &lazy);
2606 assert_eq!(result, 15);
2607 }
2608
2609 #[test]
2611 fn test_rc_lazy_ref_fold_map() {
2612 use crate::functions::*;
2613
2614 let lazy = RcLazy::pure(10);
2615 let result = explicit::fold_map::<
2616 crate::brands::RcFnBrand,
2617 crate::brands::LazyBrand<RcLazyConfig>,
2618 _,
2619 _,
2620 _,
2621 _,
2622 >(|a: &i32| a.to_string(), &lazy);
2623 assert_eq!(result, "10");
2624 }
2625
2626 #[test]
2632 fn test_rc_lazy_partial_eq() {
2633 let a = RcLazy::pure(42);
2634 let b = RcLazy::pure(42);
2635 let c = RcLazy::pure(99);
2636
2637 assert!(a == b);
2638 assert!(b != c);
2639 }
2640
2641 #[test]
2645 fn test_arc_lazy_partial_eq() {
2646 let a = ArcLazy::pure(42);
2647 let b = ArcLazy::pure(42);
2648 let c = ArcLazy::pure(99);
2649
2650 assert!(a == b);
2651 assert!(b != c);
2652 }
2653
2654 #[test]
2660 fn test_rc_lazy_partial_ord() {
2661 let a = RcLazy::pure(1);
2662 let b = RcLazy::pure(2);
2663 let c = RcLazy::pure(2);
2664
2665 assert!(a < b);
2666 assert!(b > a);
2667 assert!(b >= c);
2668 assert!(c <= b);
2669 }
2670
2671 #[test]
2675 fn test_arc_lazy_partial_ord() {
2676 let a = ArcLazy::pure(1);
2677 let b = ArcLazy::pure(2);
2678
2679 assert!(a < b);
2680 assert!(b > a);
2681 }
2682
2683 #[test]
2688 fn test_rc_lazy_fix_constant() {
2689 let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 42);
2690 assert_eq!(*fixed.evaluate(), 42);
2691 }
2692
2693 #[test]
2698 fn test_rc_lazy_fix_cell_initialized() {
2699 let fixed = rc_lazy_fix(|_self_ref: RcLazy<String>| String::from("initialized"));
2700 assert_eq!(fixed.evaluate().as_str(), "initialized");
2702 }
2703
2704 #[test]
2711 fn test_rc_lazy_fix_self_reference_plumbing() {
2712 let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 7);
2714 assert_eq!(*fixed.evaluate(), 7);
2715 }
2716
2717 #[test]
2721 fn test_rc_lazy_fix_memoization() {
2722 let counter = Rc::new(RefCell::new(0));
2723 let counter_clone = counter.clone();
2724 let fixed = rc_lazy_fix(move |_self_ref: RcLazy<i32>| {
2725 *counter_clone.borrow_mut() += 1;
2726 100
2727 });
2728
2729 assert_eq!(*counter.borrow(), 0);
2730 assert_eq!(*fixed.evaluate(), 100);
2731 assert_eq!(*counter.borrow(), 1);
2732 assert_eq!(*fixed.evaluate(), 100);
2734 assert_eq!(*counter.borrow(), 1);
2735 }
2736
2737 #[test]
2739 fn test_rc_lazy_fix_clone_sharing() {
2740 let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 55);
2741 let cloned = fixed.clone();
2742 assert_eq!(*fixed.evaluate(), 55);
2743 assert_eq!(*cloned.evaluate(), 55);
2744 }
2745
2746 #[test]
2749 fn test_arc_lazy_fix_constant() {
2750 let fixed = arc_lazy_fix(|_self_ref: ArcLazy<i32>| 42);
2751 assert_eq!(*fixed.evaluate(), 42);
2752 }
2753
2754 #[test]
2756 fn test_arc_lazy_fix_cell_initialized() {
2757 let fixed = arc_lazy_fix(|_self_ref: ArcLazy<String>| String::from("initialized"));
2758 assert_eq!(fixed.evaluate().as_str(), "initialized");
2760 }
2761
2762 #[test]
2764 fn test_arc_lazy_fix_self_reference_plumbing() {
2765 let fixed = arc_lazy_fix(|_self_ref: ArcLazy<i32>| 7);
2766 assert_eq!(*fixed.evaluate(), 7);
2767 }
2768
2769 #[test]
2771 fn test_arc_lazy_fix_memoization() {
2772 use std::sync::atomic::{
2773 AtomicUsize,
2774 Ordering,
2775 };
2776
2777 let counter = Arc::new(AtomicUsize::new(0));
2778 let counter_clone = counter.clone();
2779 let fixed = arc_lazy_fix(move |_self_ref: ArcLazy<i32>| {
2780 counter_clone.fetch_add(1, Ordering::SeqCst);
2781 100
2782 });
2783
2784 assert_eq!(counter.load(Ordering::SeqCst), 0);
2785 assert_eq!(*fixed.evaluate(), 100);
2786 assert_eq!(counter.load(Ordering::SeqCst), 1);
2787 assert_eq!(*fixed.evaluate(), 100);
2789 assert_eq!(counter.load(Ordering::SeqCst), 1);
2790 }
2791
2792 #[test]
2796 fn test_arc_lazy_ref_fold_right() {
2797 use crate::{
2798 brands::*,
2799 functions::*,
2800 };
2801
2802 let lazy = ArcLazy::new(|| 10);
2803 let result = explicit::fold_right::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, _, _, _>(
2804 |a: &i32, b| *a + b,
2805 5,
2806 &lazy,
2807 );
2808 assert_eq!(result, 15);
2809 }
2810
2811 #[test]
2813 fn test_arc_lazy_ref_fold_left() {
2814 use crate::{
2815 brands::*,
2816 functions::*,
2817 };
2818
2819 let lazy = ArcLazy::new(|| 10);
2820 let result = explicit::fold_left::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, _, _, _>(
2821 |b, a: &i32| b + *a,
2822 5,
2823 &lazy,
2824 );
2825 assert_eq!(result, 15);
2826 }
2827
2828 #[test]
2830 fn test_arc_lazy_ref_fold_map() {
2831 use crate::{
2832 brands::*,
2833 functions::*,
2834 };
2835
2836 let lazy = ArcLazy::new(|| 10);
2837 let result = explicit::fold_map::<ArcFnBrand, LazyBrand<ArcLazyConfig>, _, _, _, _>(
2838 |a: &i32| a.to_string(),
2839 &lazy,
2840 );
2841 assert_eq!(result, "10");
2842 }
2843
2844 #[quickcheck]
2846 fn prop_arc_lazy_ref_fold_right(x: i32) -> bool {
2847 use crate::{
2848 brands::*,
2849 functions::*,
2850 };
2851
2852 let rc_lazy = RcLazy::new(move || x);
2853 let arc_lazy = ArcLazy::new(move || x);
2854 let rc_result = explicit::fold_right::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _, _, _>(
2855 |a: &i32, b| *a + b,
2856 0,
2857 &rc_lazy,
2858 );
2859 let arc_result = explicit::fold_right::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, _, _, _>(
2860 |a: &i32, b| *a + b,
2861 0,
2862 &arc_lazy,
2863 );
2864 rc_result == arc_result
2865 }
2866
2867 #[quickcheck]
2873 fn prop_arc_lazy_ref_map_identity(x: i32) -> bool {
2874 let lazy = ArcLazy::new(move || x);
2875 let mapped = lazy.clone().ref_map(|a| *a);
2876 *lazy.evaluate() == *mapped.evaluate()
2877 }
2878
2879 #[quickcheck]
2883 fn prop_arc_lazy_ref_map_composition(x: i32) -> bool {
2884 let f = |a: &i32| a.wrapping_mul(2);
2885 let g = |a: &i32| a.wrapping_add(1);
2886
2887 let lazy1 = ArcLazy::new(move || x);
2888 let composed = lazy1.ref_map(|a| g(&f(a)));
2889
2890 let lazy2 = ArcLazy::new(move || x);
2891 let chained = lazy2.ref_map(f).ref_map(g);
2892
2893 *composed.evaluate() == *chained.evaluate()
2894 }
2895
2896 #[quickcheck]
2898 fn prop_arc_lazy_ref_map_memoization(x: i32) -> bool {
2899 let lazy = ArcLazy::new(move || x);
2900 let mapped = lazy.ref_map(|a| a.wrapping_mul(3));
2901 let r1 = *mapped.evaluate();
2902 let r2 = *mapped.evaluate();
2903 r1 == r2
2904 }
2905
2906 #[test]
2910 fn test_rc_lazy_fix_self_reference() {
2911 let lazy = rc_lazy_fix(|self_ref: RcLazy<Vec<i32>>| {
2912 let _ = self_ref; vec![1, 2, 3]
2915 });
2916 assert_eq!(*lazy.evaluate(), vec![1, 2, 3]);
2917 }
2918
2919 #[test]
2921 fn test_rc_lazy_fix_uses_self_ref() {
2922 let counter = Rc::new(RefCell::new(0));
2924 let counter_clone = counter.clone();
2925 let lazy = rc_lazy_fix(move |self_ref: RcLazy<i32>| {
2926 *counter_clone.borrow_mut() += 1;
2927 let _ = self_ref;
2930 42
2931 });
2932 assert_eq!(*lazy.evaluate(), 42);
2933 assert_eq!(*counter.borrow(), 1);
2934 assert_eq!(*lazy.evaluate(), 42);
2936 assert_eq!(*counter.borrow(), 1);
2937 }
2938
2939 #[test]
2941 fn test_arc_lazy_fix_self_reference() {
2942 let lazy = arc_lazy_fix(|self_ref: ArcLazy<Vec<i32>>| {
2943 let _ = self_ref;
2944 vec![1, 2, 3]
2945 });
2946 assert_eq!(*lazy.evaluate(), vec![1, 2, 3]);
2947 }
2948
2949 #[test]
2951 fn test_arc_lazy_fix_uses_self_ref() {
2952 use std::sync::atomic::{
2953 AtomicUsize,
2954 Ordering,
2955 };
2956
2957 let counter = Arc::new(AtomicUsize::new(0));
2958 let counter_clone = counter.clone();
2959 let lazy = arc_lazy_fix(move |self_ref: ArcLazy<i32>| {
2960 counter_clone.fetch_add(1, Ordering::SeqCst);
2961 let _ = self_ref;
2962 42
2963 });
2964 assert_eq!(*lazy.evaluate(), 42);
2965 assert_eq!(counter.load(Ordering::SeqCst), 1);
2966 assert_eq!(*lazy.evaluate(), 42);
2968 assert_eq!(counter.load(Ordering::SeqCst), 1);
2969 }
2970
2971 #[test]
2973 fn test_arc_lazy_fix_thread_safety() {
2974 use std::thread;
2975
2976 let lazy = arc_lazy_fix(|self_ref: ArcLazy<i32>| {
2977 let _ = self_ref;
2978 42
2979 });
2980
2981 let mut handles = vec![];
2982 for _ in 0 .. 10 {
2983 let lazy_clone = lazy.clone();
2984 handles.push(thread::spawn(move || {
2985 assert_eq!(*lazy_clone.evaluate(), 42);
2986 }));
2987 }
2988
2989 for handle in handles {
2990 handle.join().unwrap();
2991 }
2992 }
2993
2994 #[quickcheck]
2996 fn prop_rc_lazy_fix_constant(x: i32) -> bool {
2997 let fixed = rc_lazy_fix(move |_: RcLazy<i32>| x);
2998 *fixed.evaluate() == x
2999 }
3000
3001 #[quickcheck]
3003 fn prop_arc_lazy_fix_constant(x: i32) -> bool {
3004 let fixed = arc_lazy_fix(move |_: ArcLazy<i32>| x);
3005 *fixed.evaluate() == x
3006 }
3007
3008 #[quickcheck]
3014 fn ref_functor_identity(x: i32) -> bool {
3015 let lazy = RcLazy::pure(x);
3016 *lazy.clone().ref_map(|v| *v).evaluate() == *lazy.evaluate()
3017 }
3018
3019 #[quickcheck]
3021 fn ref_functor_composition(x: i32) -> bool {
3022 let f = |a: &i32| a.wrapping_add(1);
3023 let g = |a: &i32| a.wrapping_mul(2);
3024 let lazy = RcLazy::pure(x);
3025 let lhs = *lazy.clone().ref_map(move |v| f(&g(v))).evaluate();
3026 let rhs = *lazy.ref_map(g).ref_map(f).evaluate();
3027 lhs == rhs
3028 }
3029
3030 #[quickcheck]
3034 fn deferrable_transparency(x: i32) -> bool {
3035 let lazy = RcLazy::pure(x);
3036 let deferred: RcLazy<i32> = crate::classes::Deferrable::defer(move || RcLazy::pure(x));
3037 *deferred.evaluate() == *lazy.evaluate()
3038 }
3039
3040 #[quickcheck]
3044 fn rc_lazy_semigroup_associativity(
3045 a: String,
3046 b: String,
3047 c: String,
3048 ) -> bool {
3049 use crate::classes::semigroup::append;
3050
3051 let la = RcLazy::pure(a.clone());
3052 let lb = RcLazy::pure(b.clone());
3053 let lc = RcLazy::pure(c.clone());
3054 let la2 = RcLazy::pure(a);
3055 let lb2 = RcLazy::pure(b);
3056 let lc2 = RcLazy::pure(c);
3057 let lhs = append(append(la, lb), lc).evaluate().clone();
3058 let rhs = append(la2, append(lb2, lc2)).evaluate().clone();
3059 lhs == rhs
3060 }
3061
3062 #[quickcheck]
3064 fn arc_lazy_semigroup_associativity(
3065 a: String,
3066 b: String,
3067 c: String,
3068 ) -> bool {
3069 use crate::classes::semigroup::append;
3070
3071 let la = ArcLazy::pure(a.clone());
3072 let lb = ArcLazy::pure(b.clone());
3073 let lc = ArcLazy::pure(c.clone());
3074 let la2 = ArcLazy::pure(a);
3075 let lb2 = ArcLazy::pure(b);
3076 let lc2 = ArcLazy::pure(c);
3077 let lhs = append(append(la, lb), lc).evaluate().clone();
3078 let rhs = append(la2, append(lb2, lc2)).evaluate().clone();
3079 lhs == rhs
3080 }
3081
3082 #[quickcheck]
3086 fn rc_lazy_monoid_left_identity(x: String) -> bool {
3087 use crate::classes::{
3088 monoid::empty,
3089 semigroup::append,
3090 };
3091
3092 let a = RcLazy::pure(x.clone());
3093 let lhs: RcLazy<String> = append(empty(), a);
3094 *lhs.evaluate() == x
3095 }
3096
3097 #[quickcheck]
3099 fn rc_lazy_monoid_right_identity(x: String) -> bool {
3100 use crate::classes::{
3101 monoid::empty,
3102 semigroup::append,
3103 };
3104
3105 let a = RcLazy::pure(x.clone());
3106 let rhs: RcLazy<String> = append(a, empty());
3107 *rhs.evaluate() == x
3108 }
3109
3110 #[quickcheck]
3112 fn arc_lazy_monoid_left_identity(x: String) -> bool {
3113 use crate::classes::{
3114 monoid::empty,
3115 semigroup::append,
3116 };
3117
3118 let a = ArcLazy::pure(x.clone());
3119 let lhs: ArcLazy<String> = append(empty(), a);
3120 *lhs.evaluate() == x
3121 }
3122
3123 #[quickcheck]
3125 fn arc_lazy_monoid_right_identity(x: String) -> bool {
3126 use crate::classes::{
3127 monoid::empty,
3128 semigroup::append,
3129 };
3130
3131 let a = ArcLazy::pure(x.clone());
3132 let rhs: ArcLazy<String> = append(a, empty());
3133 *rhs.evaluate() == x
3134 }
3135
3136 #[test]
3140 fn test_rc_lazy_config_pointer_brand() {
3141 fn assert_brand_is_rc<C: LazyConfig<PointerBrand = crate::brands::RcBrand>>() {}
3142 assert_brand_is_rc::<RcLazyConfig>();
3143 }
3144
3145 #[test]
3147 fn test_arc_lazy_config_pointer_brand() {
3148 fn assert_brand_is_arc<C: LazyConfig<PointerBrand = crate::brands::ArcBrand>>() {}
3149 assert_brand_is_arc::<ArcLazyConfig>();
3150 }
3151
3152 #[test]
3159 fn test_panic_poisoning() {
3160 use std::panic;
3161
3162 let memo: RcLazy<i32> = RcLazy::new(|| {
3163 panic!("initializer panic");
3164 });
3165
3166 let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
3167 let _ = memo.evaluate();
3168 }));
3169 assert!(result.is_err(), "First evaluate should panic");
3170
3171 let result2 = panic::catch_unwind(panic::AssertUnwindSafe(|| {
3172 let _ = memo.evaluate();
3173 }));
3174 assert!(result2.is_err(), "Second evaluate should also panic (poisoned)");
3175 }
3176
3177 #[test]
3179 fn test_rc_lazy_fix_shared_self_ref() {
3180 let lazy = rc_lazy_fix(|self_ref: RcLazy<i32>| {
3181 let _captured = self_ref.clone();
3183 100
3184 });
3185 assert_eq!(*lazy.evaluate(), 100);
3186 let cloned = lazy.clone();
3188 assert_eq!(*cloned.evaluate(), 100);
3189 }
3190
3191 #[test]
3197 fn test_rc_lazy_fix_knot_tying_ptr_eq() {
3198 let stash: Rc<RefCell<Option<RcLazy<i32>>>> = Rc::new(RefCell::new(None));
3199 let stash_clone = stash.clone();
3200 let lazy = rc_lazy_fix(move |self_ref: RcLazy<i32>| {
3201 *stash_clone.borrow_mut() = Some(self_ref);
3203 42
3204 });
3205 assert_eq!(*lazy.evaluate(), 42);
3207 let self_ref = stash.borrow().clone().unwrap();
3209 assert!(Rc::ptr_eq(&lazy.0, &self_ref.0));
3211 assert_eq!(*self_ref.evaluate(), 42);
3213 }
3214
3215 #[test]
3218 fn test_rc_lazy_fix_knot_tying_shared_cache() {
3219 let counter = Rc::new(RefCell::new(0));
3220 let stash: Rc<RefCell<Option<RcLazy<i32>>>> = Rc::new(RefCell::new(None));
3221 let counter_clone = counter.clone();
3222 let stash_clone = stash.clone();
3223 let lazy = rc_lazy_fix(move |self_ref: RcLazy<i32>| {
3224 *stash_clone.borrow_mut() = Some(self_ref);
3225 *counter_clone.borrow_mut() += 1;
3226 100
3227 });
3228 assert_eq!(*counter.borrow(), 0);
3229 assert_eq!(*lazy.evaluate(), 100);
3231 assert_eq!(*counter.borrow(), 1);
3232 let self_ref = stash.borrow().clone().unwrap();
3234 assert_eq!(*self_ref.evaluate(), 100);
3235 assert_eq!(*counter.borrow(), 1);
3237 }
3238
3239 #[test]
3244 #[should_panic]
3245 fn test_rc_lazy_fix_reentrant_panics() {
3246 let lazy = rc_lazy_fix(|self_ref: RcLazy<i32>| {
3247 *self_ref.evaluate() + 1
3250 });
3251 let _ = lazy.evaluate();
3252 }
3253
3254 #[test]
3257 fn test_arc_lazy_fix_knot_tying_ptr_eq() {
3258 use std::sync::Mutex;
3259
3260 let stash: Arc<Mutex<Option<ArcLazy<i32>>>> = Arc::new(Mutex::new(None));
3261 let stash_clone = stash.clone();
3262 let lazy = arc_lazy_fix(move |self_ref: ArcLazy<i32>| {
3263 *stash_clone.lock().unwrap() = Some(self_ref);
3264 42
3265 });
3266 assert_eq!(*lazy.evaluate(), 42);
3267 let self_ref = stash.lock().unwrap().clone().unwrap();
3268 assert!(Arc::ptr_eq(&lazy.0, &self_ref.0));
3270 assert_eq!(*self_ref.evaluate(), 42);
3272 }
3273
3274 #[test]
3277 fn test_arc_lazy_fix_knot_tying_shared_cache() {
3278 use std::sync::{
3279 Mutex,
3280 atomic::{
3281 AtomicUsize,
3282 Ordering,
3283 },
3284 };
3285
3286 let counter = Arc::new(AtomicUsize::new(0));
3287 let stash: Arc<Mutex<Option<ArcLazy<i32>>>> = Arc::new(Mutex::new(None));
3288 let counter_clone = counter.clone();
3289 let stash_clone = stash.clone();
3290 let lazy = arc_lazy_fix(move |self_ref: ArcLazy<i32>| {
3291 *stash_clone.lock().unwrap() = Some(self_ref);
3292 counter_clone.fetch_add(1, Ordering::SeqCst);
3293 100
3294 });
3295 assert_eq!(counter.load(Ordering::SeqCst), 0);
3296 assert_eq!(*lazy.evaluate(), 100);
3297 assert_eq!(counter.load(Ordering::SeqCst), 1);
3298 let self_ref = stash.lock().unwrap().clone().unwrap();
3300 assert_eq!(*self_ref.evaluate(), 100);
3301 assert_eq!(counter.load(Ordering::SeqCst), 1);
3303 }
3304
3305 #[test]
3309 fn test_arc_lazy_fix_knot_tying_cross_thread() {
3310 use std::{
3311 sync::Mutex,
3312 thread,
3313 };
3314
3315 let stash: Arc<Mutex<Option<ArcLazy<i32>>>> = Arc::new(Mutex::new(None));
3316 let stash_clone = stash.clone();
3317 let lazy = arc_lazy_fix(move |self_ref: ArcLazy<i32>| {
3318 *stash_clone.lock().unwrap() = Some(self_ref);
3319 77
3320 });
3321 assert_eq!(*lazy.evaluate(), 77);
3322 let self_ref = stash.lock().unwrap().clone().unwrap();
3323 let handle = thread::spawn(move || *self_ref.evaluate());
3325 assert_eq!(handle.join().unwrap(), 77);
3326 }
3327
3328 #[test]
3329 fn m_do_ref_lazy_manual() {
3330 use crate::{
3332 brands::LazyBrand,
3333 functions::*,
3334 };
3335
3336 let lazy_a = RcLazy::new(|| 10i32);
3337
3338 let result =
3339 explicit::bind::<LazyBrand<RcLazyConfig>, _, _, _, _>(&lazy_a, move |a: &i32| {
3340 ref_pure::<LazyBrand<RcLazyConfig>, _>(&(*a * 2))
3341 });
3342
3343 assert_eq!(*result.evaluate(), 20);
3344 }
3345
3346 #[test]
3347 fn m_do_ref_lazy_macro() {
3348 use {
3349 crate::{
3350 brands::LazyBrand,
3351 functions::*,
3352 },
3353 fp_macros::m_do,
3354 };
3355
3356 let lazy_a = RcLazy::new(|| 10i32);
3357
3358 let result = m_do!(ref LazyBrand<RcLazyConfig> {
3359 a: &i32 <- lazy_a;
3360 pure(*a * 2)
3361 });
3362
3363 assert_eq!(*result.evaluate(), 20);
3364 }
3365
3366 #[test]
3367 fn m_do_ref_lazy_multi_bind() {
3368 use {
3369 crate::{
3370 brands::LazyBrand,
3371 functions::*,
3372 },
3373 fp_macros::m_do,
3374 };
3375
3376 let lazy_a = RcLazy::new(|| 10i32);
3377 let lazy_b = RcLazy::new(|| 20i32);
3378
3379 let result = m_do!(ref LazyBrand<RcLazyConfig> {
3383 a: &i32 <- lazy_a;
3384 let a_val = *a;
3385 b: &i32 <- lazy_b.clone();
3386 pure(a_val + *b)
3387 });
3388
3389 assert_eq!(*result.evaluate(), 30);
3390 }
3391
3392 #[test]
3393 fn m_do_ref_lazy_untyped() {
3394 use {
3395 crate::{
3396 brands::LazyBrand,
3397 functions::*,
3398 },
3399 fp_macros::m_do,
3400 };
3401
3402 let lazy_a = RcLazy::new(|| 10i32);
3403
3404 let result = m_do!(ref LazyBrand<RcLazyConfig> {
3405 a <- lazy_a;
3406 pure(*a * 3)
3407 });
3408
3409 assert_eq!(*result.evaluate(), 30);
3410 }
3411
3412 #[test]
3413 fn a_do_ref_lazy() {
3414 use {
3415 crate::{
3416 brands::LazyBrand,
3417 functions::*,
3418 },
3419 fp_macros::a_do,
3420 };
3421
3422 let lazy_a = RcLazy::new(|| 10i32);
3423 let lazy_b = RcLazy::new(|| 20i32);
3424
3425 let result = a_do!(ref LazyBrand<RcLazyConfig> {
3428 a: &i32 <- lazy_a;
3429 b: &i32 <- lazy_b;
3430 *a + *b
3431 });
3432
3433 assert_eq!(*result.evaluate(), 30);
3434 }
3435}