1#[fp_macros::document_module]
15mod inner {
16 use {
17 crate::{
18 Apply,
19 brands::{
20 ArcBrand,
21 LazyBrand,
22 RcBrand,
23 },
24 classes::{
25 CloneableFn,
26 Deferrable,
27 Foldable,
28 FoldableWithIndex,
29 Monoid,
30 RefFunctor,
31 Semigroup,
32 SendDeferrable,
33 SendRefFunctor,
34 WithIndex,
35 },
36 impl_kind,
37 kinds::*,
38 types::{
39 SendThunk,
40 Thunk,
41 Trampoline,
42 },
43 },
44 fp_macros::*,
45 std::{
46 cell::LazyCell,
47 fmt,
48 hash::{
49 Hash,
50 Hasher,
51 },
52 rc::Rc,
53 sync::{
54 Arc,
55 LazyLock,
56 },
57 },
58 };
59
60 pub use crate::classes::{
61 LazyConfig,
62 TryLazyConfig,
63 };
64
65 pub struct RcLazyConfig;
69
70 impl LazyConfig for RcLazyConfig {
71 type Lazy<'a, A: 'a> = Rc<LazyCell<A, Box<dyn FnOnce() -> A + 'a>>>;
72 type PointerBrand = RcBrand;
73 type Thunk<'a, A: 'a> = dyn FnOnce() -> A + 'a;
74
75 #[document_signature]
77 #[document_type_parameters("The lifetime of the computation.", "The type of the value.")]
79 #[document_parameters("The initializer thunk.")]
81 #[document_returns("A new lazy cell.")]
83 #[document_examples]
85 fn lazy_new<'a, A: 'a>(f: Box<Self::Thunk<'a, A>>) -> Self::Lazy<'a, A> {
96 Rc::new(LazyCell::new(f))
97 }
98
99 #[document_signature]
101 #[document_type_parameters(
103 "The lifetime of the computation.",
104 "The borrow lifetime.",
105 "The type of the value."
106 )]
107 #[document_parameters("The lazy cell to evaluate.")]
109 #[document_returns("A reference to the value.")]
111 #[document_examples]
113 fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
124 LazyCell::force(lazy)
125 }
126 }
127
128 impl TryLazyConfig for RcLazyConfig {
129 type TryLazy<'a, A: 'a, E: 'a> =
130 Rc<LazyCell<Result<A, E>, Box<dyn FnOnce() -> Result<A, E> + 'a>>>;
131 type TryThunk<'a, A: 'a, E: 'a> = dyn FnOnce() -> Result<A, E> + 'a;
132
133 #[document_signature]
135 #[document_type_parameters(
137 "The lifetime of the computation.",
138 "The type of the value.",
139 "The type of the error."
140 )]
141 #[document_parameters("The initializer thunk.")]
143 #[document_returns("A new fallible lazy cell.")]
145 #[document_examples]
147 fn try_lazy_new<'a, A: 'a, E: 'a>(
158 f: Box<Self::TryThunk<'a, A, E>>
159 ) -> Self::TryLazy<'a, A, E> {
160 Rc::new(LazyCell::new(f))
161 }
162
163 #[document_signature]
165 #[document_type_parameters(
167 "The lifetime of the computation.",
168 "The borrow lifetime.",
169 "The type of the value.",
170 "The type of the error."
171 )]
172 #[document_parameters("The fallible lazy cell to evaluate.")]
174 #[document_returns("A result containing a reference to the value or error.")]
176 #[document_examples]
178 fn try_evaluate<'a, 'b, A: 'a, E: 'a>(
189 lazy: &'b Self::TryLazy<'a, A, E>
190 ) -> Result<&'b A, &'b E> {
191 LazyCell::force(lazy).as_ref()
192 }
193 }
194
195 pub struct ArcLazyConfig;
199
200 impl LazyConfig for ArcLazyConfig {
201 type Lazy<'a, A: 'a> = Arc<LazyLock<A, Box<dyn FnOnce() -> A + Send + 'a>>>;
202 type PointerBrand = ArcBrand;
203 type Thunk<'a, A: 'a> = dyn FnOnce() -> A + Send + 'a;
204
205 #[document_signature]
207 #[document_type_parameters("The lifetime of the computation.", "The type of the value.")]
209 #[document_parameters("The initializer thunk.")]
211 #[document_returns("A new lazy cell.")]
213 #[document_examples]
215 fn lazy_new<'a, A: 'a>(f: Box<Self::Thunk<'a, A>>) -> Self::Lazy<'a, A> {
226 Arc::new(LazyLock::new(f))
227 }
228
229 #[document_signature]
231 #[document_type_parameters(
233 "The lifetime of the computation.",
234 "The borrow lifetime.",
235 "The type of the value."
236 )]
237 #[document_parameters("The lazy cell to evaluate.")]
239 #[document_returns("A reference to the value.")]
241 #[document_examples]
243 fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
254 LazyLock::force(lazy)
255 }
256 }
257
258 impl TryLazyConfig for ArcLazyConfig {
259 type TryLazy<'a, A: 'a, E: 'a> =
260 Arc<LazyLock<Result<A, E>, Box<dyn FnOnce() -> Result<A, E> + Send + 'a>>>;
261 type TryThunk<'a, A: 'a, E: 'a> = dyn FnOnce() -> Result<A, E> + Send + 'a;
262
263 #[document_signature]
265 #[document_type_parameters(
267 "The lifetime of the computation.",
268 "The type of the value.",
269 "The type of the error."
270 )]
271 #[document_parameters("The initializer thunk.")]
273 #[document_returns("A new fallible lazy cell.")]
275 #[document_examples]
277 fn try_lazy_new<'a, A: 'a, E: 'a>(
288 f: Box<Self::TryThunk<'a, A, E>>
289 ) -> Self::TryLazy<'a, A, E> {
290 Arc::new(LazyLock::new(f))
291 }
292
293 #[document_signature]
295 #[document_type_parameters(
297 "The lifetime of the computation.",
298 "The borrow lifetime.",
299 "The type of the value.",
300 "The type of the error."
301 )]
302 #[document_parameters("The fallible lazy cell to evaluate.")]
304 #[document_returns("A result containing a reference to the value or error.")]
306 #[document_examples]
308 fn try_evaluate<'a, 'b, A: 'a, E: 'a>(
319 lazy: &'b Self::TryLazy<'a, A, E>
320 ) -> Result<&'b A, &'b E> {
321 LazyLock::force(lazy).as_ref()
322 }
323 }
324
325 #[document_type_parameters(
344 "The lifetime of the computation.",
345 "The type of the computed value.",
346 "The memoization configuration (determines Rc vs Arc)."
347 )]
348 pub struct Lazy<'a, A, Config: LazyConfig = RcLazyConfig>(
350 pub(crate) Config::Lazy<'a, A>,
352 )
353 where
354 A: 'a;
355
356 #[document_type_parameters(
357 "The lifetime of the computation.",
358 "The type of the computed value.",
359 "The memoization configuration (determines Rc vs Arc)."
360 )]
361 #[document_parameters("The instance to clone.")]
362 impl<'a, A, Config: LazyConfig> Clone for Lazy<'a, A, Config>
363 where
364 A: 'a,
365 {
366 #[document_signature]
367 #[document_returns("A new `Lazy` instance that shares the same underlying memoized value.")]
368 #[document_examples]
369 fn clone(&self) -> Self {
386 Self(self.0.clone())
387 }
388 }
389
390 #[document_type_parameters(
391 "The lifetime of the computation.",
392 "The type of the computed value.",
393 "The memoization configuration (determines Rc vs Arc)."
394 )]
395 #[document_parameters("The lazy instance.")]
396 impl<'a, A, Config: LazyConfig> Lazy<'a, A, Config>
397 where
398 A: 'a,
399 {
400 #[document_signature]
402 #[document_returns("A reference to the memoized value.")]
404 #[document_examples]
406 #[inline]
417 pub fn evaluate(&self) -> &A {
418 Config::evaluate(&self.0)
419 }
420 }
421
422 #[document_type_parameters(
423 "The lifetime of the computation.",
424 "The type of the computed value."
425 )]
426 #[document_parameters("The lazy instance.")]
427 impl<'a, A> Lazy<'a, A, RcLazyConfig>
428 where
429 A: 'a,
430 {
431 #[document_signature]
433 #[document_parameters("The closure that produces the value.")]
435 #[document_returns("A new `Lazy` instance.")]
437 #[inline]
439 #[document_examples]
440 pub fn new(f: impl FnOnce() -> A + 'a) -> Self {
451 Lazy(RcLazyConfig::lazy_new(Box::new(f)))
452 }
453
454 #[document_signature]
458 #[document_parameters("The pre-computed value to wrap.")]
460 #[document_returns("A new `Lazy` instance containing the value.")]
462 #[inline]
464 #[document_examples]
465 pub fn pure(a: A) -> Self {
476 Lazy(RcLazyConfig::lazy_new(Box::new(move || a)))
477 }
478
479 #[document_signature]
484 #[document_returns("An owned clone of the memoized value.")]
486 #[document_examples]
488 #[inline]
500 pub fn evaluate_owned(&self) -> A
501 where
502 A: Clone, {
503 self.evaluate().clone()
504 }
505
506 #[document_signature]
512 #[document_type_parameters("The type of the result.")]
513 #[document_parameters("The function to apply to the memoized value.")]
514 #[document_returns("A new `Lazy` instance containing the mapped value.")]
515 #[document_examples]
516 #[inline]
528 pub fn ref_map<B: 'a>(
529 self,
530 f: impl FnOnce(&A) -> B + 'a,
531 ) -> Lazy<'a, B, RcLazyConfig> {
532 RcLazy::new(move || f(self.evaluate()))
533 }
534 }
535
536 #[document_type_parameters(
537 "The lifetime of the computation.",
538 "The type of the computed value."
539 )]
540 impl<'a, A> From<Thunk<'a, A>> for Lazy<'a, A, RcLazyConfig> {
541 #[document_signature]
542 #[document_parameters("The thunk to convert.")]
543 #[document_returns("A new `Lazy` instance that will evaluate the thunk on first access.")]
544 #[document_examples]
545 fn from(eval: Thunk<'a, A>) -> Self {
556 Self::new(move || eval.evaluate())
557 }
558 }
559
560 #[document_type_parameters(
561 "The lifetime of the computation.",
562 "The type of the computed value."
563 )]
564 impl<'a, A: 'static> From<Trampoline<A>> for Lazy<'a, A, RcLazyConfig> {
565 #[document_signature]
566 #[document_parameters("The trampoline to convert.")]
567 #[document_returns(
568 "A new `Lazy` instance that will evaluate the trampoline on first access."
569 )]
570 #[document_examples]
571 fn from(task: Trampoline<A>) -> Self {
582 Self::new(move || task.evaluate())
583 }
584 }
585
586 #[document_type_parameters(
587 "The lifetime of the computation.",
588 "The type of the computed value."
589 )]
590 impl<'a, A: Send + Sync + 'a> From<Thunk<'a, A>> for Lazy<'a, A, ArcLazyConfig> {
591 #[document_signature]
596 #[document_parameters("The thunk to convert.")]
597 #[document_returns("A new `Lazy` instance containing the eagerly evaluated value.")]
598 #[document_examples]
599 fn from(eval: Thunk<'a, A>) -> Self {
610 Self::pure(eval.evaluate())
611 }
612 }
613
614 #[document_type_parameters(
615 "The lifetime of the computation.",
616 "The type of the computed value."
617 )]
618 impl<'a, A: Send + Sync + 'static> From<Trampoline<A>> for Lazy<'a, A, ArcLazyConfig> {
619 #[document_signature]
624 #[document_parameters("The trampoline to convert.")]
625 #[document_returns("A new `Lazy` instance containing the eagerly evaluated value.")]
626 #[document_examples]
627 fn from(task: Trampoline<A>) -> Self {
638 Self::pure(task.evaluate())
639 }
640 }
641
642 #[document_type_parameters(
643 "The lifetime of the computation.",
644 "The type of the computed value."
645 )]
646 impl<'a, A: 'a> From<SendThunk<'a, A>> for Lazy<'a, A, ArcLazyConfig> {
647 #[document_signature]
652 #[document_parameters("The send thunk to convert.")]
653 #[document_returns("A new `ArcLazy` wrapping the deferred computation.")]
654 #[document_examples]
655 fn from(thunk: SendThunk<'a, A>) -> Self {
666 Self::new(move || thunk.evaluate())
667 }
668 }
669
670 #[document_type_parameters(
671 "The lifetime of the computation.",
672 "The type of the computed value."
673 )]
674 impl<'a, A: Clone + Send + Sync + 'a> From<Lazy<'a, A, RcLazyConfig>>
675 for Lazy<'a, A, ArcLazyConfig>
676 {
677 #[document_signature]
682 #[document_parameters("The `RcLazy` instance to convert.")]
683 #[document_returns(
684 "A new `ArcLazy` instance containing a clone of the eagerly evaluated value."
685 )]
686 #[document_examples]
687 fn from(source: Lazy<'a, A, RcLazyConfig>) -> Self {
699 Self::pure(source.evaluate().clone())
700 }
701 }
702
703 #[document_type_parameters(
704 "The lifetime of the computation.",
705 "The type of the computed value."
706 )]
707 impl<'a, A: Clone + 'a> From<Lazy<'a, A, ArcLazyConfig>> for Lazy<'a, A, RcLazyConfig> {
708 #[document_signature]
713 #[document_parameters("The `ArcLazy` instance to convert.")]
714 #[document_returns(
715 "A new `RcLazy` instance containing a clone of the eagerly evaluated value."
716 )]
717 #[document_examples]
718 fn from(source: Lazy<'a, A, ArcLazyConfig>) -> Self {
730 Self::pure(source.evaluate().clone())
731 }
732 }
733
734 #[document_type_parameters(
735 "The lifetime of the computation.",
736 "The type of the computed value."
737 )]
738 #[document_parameters("The lazy instance.")]
739 impl<'a, A> Lazy<'a, A, ArcLazyConfig>
740 where
741 A: 'a,
742 {
743 #[document_signature]
745 #[document_parameters("The closure that produces the value.")]
747 #[document_returns("A new `Lazy` instance.")]
749 #[inline]
751 #[document_examples]
752 pub fn new(f: impl FnOnce() -> A + Send + 'a) -> Self {
763 Lazy(ArcLazyConfig::lazy_new(Box::new(f)))
764 }
765
766 #[document_signature]
771 #[document_parameters("The pre-computed value to wrap.")]
773 #[document_returns("A new `Lazy` instance containing the value.")]
775 #[inline]
777 #[document_examples]
778 pub fn pure(a: A) -> Self
789 where
790 A: Send + Sync, {
791 Lazy(ArcLazyConfig::lazy_new(Box::new(move || a)))
792 }
793
794 #[document_signature]
800 #[document_returns("An owned clone of the memoized value.")]
802 #[document_examples]
804 #[inline]
816 pub fn evaluate_owned(&self) -> A
817 where
818 A: Clone + Send + Sync, {
819 self.evaluate().clone()
820 }
821 }
822
823 #[document_type_parameters(
824 "The lifetime of the computation.",
825 "The type of the computed value."
826 )]
827 #[document_parameters("The lazy value to map over.")]
828 impl<'a, A: 'a> Lazy<'a, A, ArcLazyConfig> {
829 #[document_signature]
840 #[document_type_parameters("The type of the result.")]
841 #[document_parameters("The function to apply to the memoized value.")]
842 #[document_returns("A new `ArcLazy` instance containing the mapped value.")]
843 #[document_examples]
844 #[inline]
856 pub fn ref_map<B: 'a>(
857 self,
858 f: impl FnOnce(&A) -> B + Send + 'a,
859 ) -> Lazy<'a, B, ArcLazyConfig>
860 where
861 A: Send + Sync, {
862 ArcLazy::new(move || f(self.evaluate()))
863 }
864 }
865
866 pub type RcLazy<'a, A> = Lazy<'a, A, RcLazyConfig>;
868
869 pub type ArcLazy<'a, A> = Lazy<'a, A, ArcLazyConfig>;
871
872 impl_kind! {
873 impl<Config: LazyConfig> for LazyBrand<Config> {
874 type Of<'a, A: 'a>: 'a = Lazy<'a, A, Config>;
875 }
876 }
877
878 #[document_type_parameters(
879 "The lifetime of the computation.",
880 "The type of the computed value."
881 )]
882 impl<'a, A> Deferrable<'a> for Lazy<'a, A, RcLazyConfig>
883 where
884 A: Clone + 'a,
885 {
886 #[document_signature]
891 #[document_parameters("The thunk that produces the lazy value.")]
893 #[document_returns("A new `Lazy` value.")]
895 #[document_examples]
897 fn defer(f: impl FnOnce() -> Self + 'a) -> Self
910 where
911 Self: Sized, {
912 RcLazy::new(move || f().evaluate().clone())
913 }
914 }
915
916 #[document_type_parameters("The lifetime of the reference.", "The type of the computed value.")]
917 impl<'a, A> Deferrable<'a> for Lazy<'a, A, ArcLazyConfig>
918 where
919 A: Send + Sync + 'a,
920 {
921 #[document_signature]
929 #[document_parameters("The thunk that produces the lazy value.")]
931 #[document_returns("A new `ArcLazy` value.")]
933 #[document_examples]
935 fn defer(f: impl FnOnce() -> Self + 'a) -> Self
948 where
949 Self: Sized, {
950 f()
951 }
952 }
953
954 #[document_type_parameters(
955 "The lifetime of the computation.",
956 "The type of the computed value."
957 )]
958 impl<'a, A> SendDeferrable<'a> for Lazy<'a, A, ArcLazyConfig>
959 where
960 A: Clone + Send + Sync + 'a,
961 {
962 #[document_signature]
967 #[document_parameters("The thunk that produces the lazy value.")]
969 #[document_returns("A new `ArcLazy` value.")]
971 #[document_examples]
973 fn send_defer(f: impl FnOnce() -> Self + Send + 'a) -> Self
985 where
986 Self: Sized, {
987 ArcLazy::new(move || f().evaluate().clone())
988 }
989 }
990
991 impl RefFunctor for LazyBrand<RcLazyConfig> {
992 #[document_signature]
994 #[document_type_parameters(
996 "The lifetime of the values.",
997 "The type of the value.",
998 "The type of the result."
999 )]
1000 #[document_parameters("The function to apply.", "The memoized value.")]
1002 #[document_returns("A new memoized value.")]
1004 #[document_examples]
1006 fn ref_map<'a, A: 'a, B: 'a>(
1019 f: impl FnOnce(&A) -> B + 'a,
1020 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1021 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1022 fa.ref_map(f)
1023 }
1024 }
1025
1026 impl SendRefFunctor for LazyBrand<ArcLazyConfig> {
1027 #[document_signature]
1029 #[document_type_parameters(
1031 "The lifetime of the values.",
1032 "The type of the value.",
1033 "The type of the result."
1034 )]
1035 #[document_parameters("The function to apply.", "The memoized value.")]
1037 #[document_returns("A new memoized value.")]
1039 #[document_examples]
1041 fn send_ref_map<'a, A: Send + Sync + 'a, B: Send + Sync + 'a>(
1054 f: impl FnOnce(&A) -> B + Send + 'a,
1055 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1056 ) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1057 fa.ref_map(f)
1058 }
1059 }
1060
1061 #[document_type_parameters(
1064 "The lifetime of the reference.",
1065 "The type of the computed value.",
1066 "The memoization configuration."
1067 )]
1068 #[document_parameters("The lazy value to display.")]
1069 impl<'a, A: fmt::Display + 'a, Config: LazyConfig> fmt::Display for Lazy<'a, A, Config> {
1070 #[document_signature]
1072 #[document_parameters("The formatter.")]
1074 #[document_returns("The formatting result.")]
1076 #[document_examples]
1078 fn fmt(
1092 &self,
1093 f: &mut fmt::Formatter<'_>,
1094 ) -> fmt::Result {
1095 fmt::Display::fmt(self.evaluate(), f)
1096 }
1097 }
1098
1099 #[document_type_parameters(
1102 "The lifetime of the computation.",
1103 "The type of the computed value."
1104 )]
1105 impl<'a, A: Semigroup + Clone + 'a> Semigroup for Lazy<'a, A, RcLazyConfig> {
1106 #[document_signature]
1110 #[document_parameters("The first lazy value.", "The second lazy value.")]
1112 #[document_returns("A new `RcLazy` containing the combined result.")]
1114 #[document_examples]
1116 fn append(
1129 a: Self,
1130 b: Self,
1131 ) -> Self {
1132 RcLazy::new(move || Semigroup::append(a.evaluate().clone(), b.evaluate().clone()))
1133 }
1134 }
1135
1136 #[document_type_parameters(
1137 "The lifetime of the computation.",
1138 "The type of the computed value."
1139 )]
1140 impl<'a, A: Semigroup + Clone + Send + Sync + 'a> Semigroup for Lazy<'a, A, ArcLazyConfig> {
1141 #[document_signature]
1145 #[document_parameters("The first lazy value.", "The second lazy value.")]
1147 #[document_returns("A new `ArcLazy` containing the combined result.")]
1149 #[document_examples]
1151 fn append(
1164 a: Self,
1165 b: Self,
1166 ) -> Self {
1167 ArcLazy::new(move || Semigroup::append(a.evaluate().clone(), b.evaluate().clone()))
1168 }
1169 }
1170
1171 #[document_type_parameters(
1174 "The lifetime of the computation.",
1175 "The type of the computed value."
1176 )]
1177 impl<'a, A: Monoid + Clone + 'a> Monoid for Lazy<'a, A, RcLazyConfig> {
1178 #[document_signature]
1180 #[document_returns("An `RcLazy` producing the identity value of `A`.")]
1182 #[document_examples]
1184 fn empty() -> Self {
1195 RcLazy::new(|| Monoid::empty())
1196 }
1197 }
1198
1199 #[document_type_parameters(
1200 "The lifetime of the computation.",
1201 "The type of the computed value."
1202 )]
1203 impl<'a, A: Monoid + Clone + Send + Sync + 'a> Monoid for Lazy<'a, A, ArcLazyConfig> {
1204 #[document_signature]
1206 #[document_returns("An `ArcLazy` producing the identity value of `A`.")]
1208 #[document_examples]
1210 fn empty() -> Self {
1221 ArcLazy::new(|| Monoid::empty())
1222 }
1223 }
1224
1225 #[document_type_parameters(
1228 "The lifetime of the reference.",
1229 "The type of the computed value.",
1230 "The memoization configuration."
1231 )]
1232 #[document_parameters("The lazy value to hash.")]
1233 impl<'a, A: Hash + 'a, Config: LazyConfig> Hash for Lazy<'a, A, Config> {
1234 #[document_signature]
1236 #[document_type_parameters("The type of the hasher.")]
1237 #[document_parameters("The hasher state.")]
1239 #[document_examples]
1241 fn hash<H: Hasher>(
1273 &self,
1274 state: &mut H,
1275 ) {
1276 self.evaluate().hash(state)
1277 }
1278 }
1279
1280 #[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1283 impl<Config: LazyConfig> Foldable for LazyBrand<Config> {
1284 #[document_signature]
1288 #[document_type_parameters(
1290 "The lifetime of the computation.",
1291 "The brand of the cloneable function to use.",
1292 "The type of the elements in the structure.",
1293 "The type of the accumulator."
1294 )]
1295 #[document_parameters(
1297 "The function to apply to each element and the accumulator.",
1298 "The initial value of the accumulator.",
1299 "The `Lazy` to fold."
1300 )]
1301 #[document_returns("The final accumulator value.")]
1303 #[document_examples]
1304 fn fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
1317 func: impl Fn(A, B) -> B + 'a,
1318 initial: B,
1319 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1320 ) -> B
1321 where
1322 FnBrand: CloneableFn + 'a, {
1323 func(fa.evaluate().clone(), initial)
1324 }
1325
1326 #[document_signature]
1330 #[document_type_parameters(
1332 "The lifetime of the computation.",
1333 "The brand of the cloneable function to use.",
1334 "The type of the elements in the structure.",
1335 "The type of the accumulator."
1336 )]
1337 #[document_parameters(
1339 "The function to apply to the accumulator and each element.",
1340 "The initial value of the accumulator.",
1341 "The `Lazy` to fold."
1342 )]
1343 #[document_returns("The final accumulator value.")]
1345 #[document_examples]
1346 fn fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
1359 func: impl Fn(B, A) -> B + 'a,
1360 initial: B,
1361 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1362 ) -> B
1363 where
1364 FnBrand: CloneableFn + 'a, {
1365 func(initial, fa.evaluate().clone())
1366 }
1367
1368 #[document_signature]
1372 #[document_type_parameters(
1374 "The lifetime of the computation.",
1375 "The brand of the cloneable function to use.",
1376 "The type of the elements in the structure.",
1377 "The type of the monoid."
1378 )]
1379 #[document_parameters("The mapping function.", "The Lazy to fold.")]
1381 #[document_returns("The monoid value.")]
1383 #[document_examples]
1384 fn fold_map<'a, FnBrand, A: 'a + Clone, R: Monoid>(
1398 func: impl Fn(A) -> R + 'a,
1399 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1400 ) -> R
1401 where
1402 FnBrand: CloneableFn + 'a, {
1403 func(fa.evaluate().clone())
1404 }
1405 }
1406
1407 #[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1410 impl<Config: LazyConfig> WithIndex for LazyBrand<Config> {
1411 type Index = ();
1412 }
1413
1414 #[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1417 impl<Config: LazyConfig> FoldableWithIndex for LazyBrand<Config> {
1418 #[document_signature]
1422 #[document_type_parameters(
1424 "The lifetime of the computation.",
1425 "The type of the computed value.",
1426 "The monoid type."
1427 )]
1428 #[document_parameters(
1430 "The function to apply to the index and the value.",
1431 "The `Lazy` to fold."
1432 )]
1433 #[document_returns("The monoid value.")]
1435 #[document_examples]
1436 fn fold_map_with_index<'a, A: 'a + Clone, R: Monoid>(
1452 f: impl Fn((), A) -> R + 'a,
1453 fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1454 ) -> R {
1455 f((), fa.evaluate().clone())
1456 }
1457 }
1458
1459 #[document_type_parameters(
1462 "The lifetime of the computation.",
1463 "The type of the computed value.",
1464 "The memoization configuration."
1465 )]
1466 #[document_parameters("The lazy value to compare.")]
1467 impl<'a, A: PartialEq + 'a, Config: LazyConfig> PartialEq for Lazy<'a, A, Config> {
1468 #[document_signature]
1472 #[document_parameters("The other lazy value to compare with.")]
1473 #[document_returns("`true` if the evaluated values are equal.")]
1474 #[document_examples]
1475 fn eq(
1487 &self,
1488 other: &Self,
1489 ) -> bool {
1490 self.evaluate() == other.evaluate()
1491 }
1492 }
1493
1494 #[document_type_parameters(
1497 "The lifetime of the computation.",
1498 "The type of the computed value.",
1499 "The memoization configuration."
1500 )]
1501 #[document_parameters("The lazy value to compare.")]
1502 impl<'a, A: PartialOrd + 'a, Config: LazyConfig> PartialOrd for Lazy<'a, A, Config> {
1503 #[document_signature]
1507 #[document_parameters("The other lazy value to compare with.")]
1508 #[document_returns(
1509 "The ordering between the evaluated values, or `None` if not comparable."
1510 )]
1511 #[document_examples]
1512 fn partial_cmp(
1524 &self,
1525 other: &Self,
1526 ) -> Option<std::cmp::Ordering> {
1527 self.evaluate().partial_cmp(other.evaluate())
1528 }
1529 }
1530
1531 #[document_type_parameters(
1534 "The lifetime of the computation.",
1535 "The type of the computed value.",
1536 "The memoization configuration."
1537 )]
1538 impl<'a, A: Eq + 'a, Config: LazyConfig> Eq for Lazy<'a, A, Config> {}
1539
1540 #[document_type_parameters(
1543 "The lifetime of the computation.",
1544 "The type of the computed value.",
1545 "The memoization configuration."
1546 )]
1547 #[document_parameters("The lazy value to compare.")]
1548 impl<'a, A: Ord + 'a, Config: LazyConfig> Ord for Lazy<'a, A, Config> {
1549 #[document_signature]
1553 #[document_parameters("The other lazy value to compare with.")]
1554 #[document_returns("The ordering between the evaluated values.")]
1555 #[document_examples]
1556 fn cmp(
1568 &self,
1569 other: &Self,
1570 ) -> std::cmp::Ordering {
1571 self.evaluate().cmp(other.evaluate())
1572 }
1573 }
1574
1575 #[document_type_parameters(
1576 "The lifetime of the computation.",
1577 "The type of the computed value.",
1578 "The memoization configuration."
1579 )]
1580 #[document_parameters("The lazy value to format.")]
1581 impl<'a, A, Config: LazyConfig> fmt::Debug for Lazy<'a, A, Config>
1582 where
1583 A: 'a,
1584 {
1585 #[document_signature]
1587 #[document_parameters("The formatter.")]
1588 #[document_returns("The formatting result.")]
1589 #[document_examples]
1590 fn fmt(
1600 &self,
1601 f: &mut fmt::Formatter<'_>,
1602 ) -> fmt::Result {
1603 f.write_str("Lazy(..)")
1604 }
1605 }
1606
1607 #[document_signature]
1621 #[document_type_parameters(
1623 "The lifetime of the computation.",
1624 "The type of the computed value."
1625 )]
1626 #[document_parameters(
1628 "The function that receives a lazy self-reference and produces the value."
1629 )]
1630 #[document_returns("A new `RcLazy` instance.")]
1632 #[document_examples]
1634 pub fn rc_lazy_fix<'a, A: Clone + 'a>(
1645 f: impl FnOnce(RcLazy<'a, A>) -> A + 'a
1646 ) -> RcLazy<'a, A> {
1647 use std::{
1648 cell::OnceCell,
1649 rc::Weak,
1650 };
1651
1652 #[allow(clippy::type_complexity)]
1653 let cell: Rc<OnceCell<Weak<LazyCell<A, Box<dyn FnOnce() -> A + 'a>>>>> = Rc::new(OnceCell::new());
1654 let cell_clone = cell.clone();
1655 let lazy = RcLazy::new(move || {
1656 #[allow(clippy::expect_used)]
1660 let weak = cell_clone.get().expect("rc_lazy_fix: cell not initialized");
1661 #[allow(clippy::expect_used)]
1662 let self_ref = Lazy(weak.upgrade().expect("rc_lazy_fix: outer lazy was dropped"));
1663 f(self_ref)
1664 });
1665 let _ = cell.set(Rc::downgrade(&lazy.0));
1666 lazy
1667 }
1668
1669 #[document_signature]
1681 #[document_type_parameters(
1683 "The lifetime of the computation.",
1684 "The type of the computed value."
1685 )]
1686 #[document_parameters(
1688 "The function that receives a lazy self-reference and produces the value."
1689 )]
1690 #[document_returns("A new `ArcLazy` instance.")]
1692 #[document_examples]
1694 pub fn arc_lazy_fix<'a, A: Clone + Send + Sync + 'a>(
1705 f: impl FnOnce(ArcLazy<'a, A>) -> A + Send + 'a
1706 ) -> ArcLazy<'a, A> {
1707 use std::sync::{
1708 OnceLock,
1709 Weak,
1710 };
1711
1712 #[allow(clippy::type_complexity)]
1713 let cell: Arc<OnceLock<Weak<LazyLock<A, Box<dyn FnOnce() -> A + Send + 'a>>>>> =
1714 Arc::new(OnceLock::new());
1715 let cell_clone = cell.clone();
1716 let lazy = ArcLazy::new(move || {
1717 #[allow(clippy::expect_used)]
1721 let weak = cell_clone.get().expect("arc_lazy_fix: cell not initialized");
1722 #[allow(clippy::expect_used)]
1723 let self_ref = Lazy(weak.upgrade().expect("arc_lazy_fix: outer lazy was dropped"));
1724 f(self_ref)
1725 });
1726 let _ = cell.set(Arc::downgrade(&lazy.0));
1727 lazy
1728 }
1729}
1730
1731pub use inner::*;
1732
1733#[cfg(test)]
1734mod tests {
1735 use {
1736 super::inner::*,
1737 crate::types::{
1738 Thunk,
1739 Trampoline,
1740 },
1741 quickcheck_macros::quickcheck,
1742 std::{
1743 cell::RefCell,
1744 rc::Rc,
1745 sync::Arc,
1746 },
1747 };
1748
1749 #[test]
1753 fn test_memo_caching() {
1754 let counter = Rc::new(RefCell::new(0));
1755 let counter_clone = counter.clone();
1756 let memo = RcLazy::new(move || {
1757 *counter_clone.borrow_mut() += 1;
1758 42
1759 });
1760
1761 assert_eq!(*counter.borrow(), 0);
1762 assert_eq!(*memo.evaluate(), 42);
1763 assert_eq!(*counter.borrow(), 1);
1764 assert_eq!(*memo.evaluate(), 42);
1765 assert_eq!(*counter.borrow(), 1);
1766 }
1767
1768 #[test]
1772 fn test_memo_sharing() {
1773 let counter = Rc::new(RefCell::new(0));
1774 let counter_clone = counter.clone();
1775 let memo = RcLazy::new(move || {
1776 *counter_clone.borrow_mut() += 1;
1777 42
1778 });
1779 let shared = memo.clone();
1780
1781 assert_eq!(*memo.evaluate(), 42);
1782 assert_eq!(*counter.borrow(), 1);
1783 assert_eq!(*shared.evaluate(), 42);
1784 assert_eq!(*counter.borrow(), 1);
1785 }
1786
1787 #[test]
1791 fn test_arc_memo_thread_safety() {
1792 use std::{
1793 sync::atomic::{
1794 AtomicUsize,
1795 Ordering,
1796 },
1797 thread,
1798 };
1799
1800 let counter = Arc::new(AtomicUsize::new(0));
1801 let counter_clone = counter.clone();
1802 let memo = ArcLazy::new(move || {
1803 counter_clone.fetch_add(1, Ordering::SeqCst);
1804 42
1805 });
1806
1807 let mut handles = vec![];
1808 for _ in 0 .. 10 {
1809 let memo_clone = memo.clone();
1810 handles.push(thread::spawn(move || {
1811 assert_eq!(*memo_clone.evaluate(), 42);
1812 }));
1813 }
1814
1815 for handle in handles {
1816 handle.join().unwrap();
1817 }
1818
1819 assert_eq!(counter.load(Ordering::SeqCst), 1);
1820 }
1821
1822 #[test]
1826 fn test_memo_from_eval() {
1827 let eval = Thunk::new(|| 42);
1828 let memo = RcLazy::from(eval);
1829 assert_eq!(*memo.evaluate(), 42);
1830 }
1831
1832 #[test]
1836 fn test_memo_from_task() {
1837 let task = Trampoline::pure(42);
1839 let memo = RcLazy::from(task);
1840 assert_eq!(*memo.evaluate(), 42);
1841 }
1842
1843 #[test]
1847 fn test_rc_lazy_to_arc_lazy() {
1848 let rc = RcLazy::new(|| "hello".to_string());
1849 let arc: ArcLazy<String> = ArcLazy::from(rc);
1850 assert_eq!(*arc.evaluate(), "hello");
1851 }
1852
1853 #[test]
1857 fn test_arc_lazy_to_rc_lazy() {
1858 let arc = ArcLazy::new(|| "world".to_string());
1859 let rc: RcLazy<String> = RcLazy::from(arc);
1860 assert_eq!(*rc.evaluate(), "world");
1861 }
1862
1863 #[test]
1867 fn test_rc_to_arc_eager_evaluation() {
1868 let counter = Rc::new(RefCell::new(0));
1869 let counter_clone = counter.clone();
1870 let rc = RcLazy::new(move || {
1871 *counter_clone.borrow_mut() += 1;
1872 99
1873 });
1874 assert_eq!(*counter.borrow(), 0);
1875
1876 let arc: ArcLazy<i32> = ArcLazy::from(rc);
1877 assert_eq!(*counter.borrow(), 1);
1879 assert_eq!(*arc.evaluate(), 99);
1880 assert_eq!(*counter.borrow(), 1);
1882 }
1883
1884 #[test]
1888 fn test_arc_to_rc_eager_evaluation() {
1889 use std::sync::atomic::{
1890 AtomicUsize,
1891 Ordering,
1892 };
1893
1894 let counter = Arc::new(AtomicUsize::new(0));
1895 let counter_clone = counter.clone();
1896 let arc = ArcLazy::new(move || {
1897 counter_clone.fetch_add(1, Ordering::SeqCst);
1898 77
1899 });
1900 assert_eq!(counter.load(Ordering::SeqCst), 0);
1901
1902 let rc: RcLazy<i32> = RcLazy::from(arc);
1903 assert_eq!(counter.load(Ordering::SeqCst), 1);
1905 assert_eq!(*rc.evaluate(), 77);
1906 assert_eq!(counter.load(Ordering::SeqCst), 1);
1908 }
1909
1910 #[quickcheck]
1912 fn prop_rc_to_arc_preserves_value(x: i32) -> bool {
1913 let rc = RcLazy::new(move || x);
1914 let arc: ArcLazy<i32> = ArcLazy::from(rc);
1915 *arc.evaluate() == x
1916 }
1917
1918 #[quickcheck]
1920 fn prop_arc_to_rc_preserves_value(x: i32) -> bool {
1921 let arc = ArcLazy::new(move || x);
1922 let rc: RcLazy<i32> = RcLazy::from(arc);
1923 *rc.evaluate() == x
1924 }
1925
1926 #[test]
1928 fn test_defer() {
1929 use crate::classes::deferrable::defer;
1930
1931 let memo: RcLazy<i32> = defer(|| RcLazy::new(|| 42));
1932 assert_eq!(*memo.evaluate(), 42);
1933 }
1934
1935 #[test]
1937 fn test_send_defer() {
1938 use crate::classes::send_deferrable::send_defer;
1939
1940 let memo: ArcLazy<i32> = send_defer(|| ArcLazy::new(|| 42));
1941 assert_eq!(*memo.evaluate(), 42);
1942 }
1943
1944 #[test]
1948 fn test_rc_lazy_pure() {
1949 let lazy = RcLazy::pure(42);
1950 assert_eq!(*lazy.evaluate(), 42);
1951
1952 let shared = lazy.clone();
1954 assert_eq!(*shared.evaluate(), 42);
1955 }
1956
1957 #[test]
1961 fn test_arc_lazy_pure() {
1962 let lazy = ArcLazy::pure(42);
1963 assert_eq!(*lazy.evaluate(), 42);
1964
1965 let shared = lazy.clone();
1967 assert_eq!(*shared.evaluate(), 42);
1968 }
1969
1970 #[test]
1974 fn test_arc_lazy_pure_thread_safety() {
1975 use std::thread;
1976
1977 let lazy = ArcLazy::pure(42);
1978
1979 let mut handles = vec![];
1980 for _ in 0 .. 10 {
1981 let lazy_clone = lazy.clone();
1982 handles.push(thread::spawn(move || {
1983 assert_eq!(*lazy_clone.evaluate(), 42);
1984 }));
1985 }
1986
1987 for handle in handles {
1988 handle.join().unwrap();
1989 }
1990 }
1991
1992 #[quickcheck]
1996 fn prop_rc_memo_get_memoization(x: i32) -> bool {
1997 let memo = RcLazy::new(move || x.wrapping_mul(2));
1998 let result1 = *memo.evaluate();
1999 let result2 = *memo.evaluate();
2000 result1 == result2
2001 }
2002
2003 #[quickcheck]
2005 fn prop_arc_memo_get_memoization(x: i32) -> bool {
2006 let memo = ArcLazy::new(move || x.wrapping_mul(2));
2007 let result1 = *memo.evaluate();
2008 let result2 = *memo.evaluate();
2009 result1 == result2
2010 }
2011
2012 #[quickcheck]
2016 fn prop_rc_memo_clone_shares_state(x: i32) -> bool {
2017 let memo1 = RcLazy::new(move || x);
2018 let memo2 = memo1.clone();
2019
2020 let result1 = *memo1.evaluate();
2021 let result2 = *memo2.evaluate();
2022 result1 == result2
2023 }
2024
2025 #[quickcheck]
2027 fn prop_arc_memo_clone_shares_state(x: i32) -> bool {
2028 let memo1 = ArcLazy::new(move || x);
2029 let memo2 = memo1.clone();
2030
2031 let result1 = *memo1.evaluate();
2032 let result2 = *memo2.evaluate();
2033 result1 == result2
2034 }
2035
2036 #[quickcheck]
2038 fn prop_memo_get_original_then_clone(x: String) -> bool {
2039 let value = x.clone();
2040 let memo = RcLazy::new(move || value.clone());
2041 let memo_clone = memo.clone();
2042
2043 let result1 = memo.evaluate().clone();
2044 let result2 = memo_clone.evaluate().clone();
2045
2046 result1 == result2
2047 }
2048
2049 #[quickcheck]
2053 fn prop_memo_deterministic(
2054 x: i32,
2055 y: i32,
2056 ) -> bool {
2057 let memo1 = RcLazy::new(move || x.wrapping_add(y));
2058 let memo2 = RcLazy::new(move || x.wrapping_add(y));
2059
2060 *memo1.evaluate() == *memo2.evaluate()
2061 }
2062
2063 #[test]
2069 fn test_arc_lazy_ref_map() {
2070 let memo = ArcLazy::new(|| 10);
2071 let mapped = memo.ref_map(|x| *x * 2);
2072 assert_eq!(*mapped.evaluate(), 20);
2073 }
2074
2075 #[test]
2079 fn test_arc_lazy_ref_map_thread_safety() {
2080 use std::thread;
2081
2082 let memo = ArcLazy::new(|| 10);
2083 let mapped = memo.ref_map(|x| *x * 3);
2084
2085 let mut handles = vec![];
2086 for _ in 0 .. 5 {
2087 let m = mapped.clone();
2088 handles.push(thread::spawn(move || {
2089 assert_eq!(*m.evaluate(), 30);
2090 }));
2091 }
2092
2093 for handle in handles {
2094 handle.join().unwrap();
2095 }
2096 }
2097
2098 #[test]
2104 fn test_rc_lazy_semigroup() {
2105 use crate::classes::semigroup::append;
2106
2107 let a = RcLazy::pure("Hello".to_string());
2108 let b = RcLazy::pure(" World".to_string());
2109 let c = append(a, b);
2110 assert_eq!(*c.evaluate(), "Hello World");
2111 }
2112
2113 #[test]
2117 fn test_arc_lazy_semigroup() {
2118 use crate::classes::semigroup::append;
2119
2120 let a = ArcLazy::pure("Hello".to_string());
2121 let b = ArcLazy::pure(" World".to_string());
2122 let c = append(a, b);
2123 assert_eq!(*c.evaluate(), "Hello World");
2124 }
2125
2126 #[test]
2128 fn test_rc_lazy_semigroup_associativity() {
2129 use crate::classes::semigroup::append;
2130
2131 let a = RcLazy::pure("a".to_string());
2132 let b = RcLazy::pure("b".to_string());
2133 let c = RcLazy::pure("c".to_string());
2134
2135 let ab_c = append(append(a.clone(), b.clone()), c.clone());
2136 let a_bc = append(a, append(b, c));
2137
2138 assert_eq!(*ab_c.evaluate(), *a_bc.evaluate());
2139 }
2140
2141 #[test]
2147 fn test_rc_lazy_monoid() {
2148 use crate::classes::monoid::empty;
2149
2150 let t: RcLazy<String> = empty();
2151 assert_eq!(*t.evaluate(), "");
2152 }
2153
2154 #[test]
2158 fn test_arc_lazy_monoid() {
2159 use crate::classes::monoid::empty;
2160
2161 let t: ArcLazy<String> = empty();
2162 assert_eq!(*t.evaluate(), "");
2163 }
2164
2165 #[test]
2167 fn test_rc_lazy_monoid_identity() {
2168 use crate::classes::{
2169 monoid::empty,
2170 semigroup::append,
2171 };
2172
2173 let a = RcLazy::pure("hello".to_string());
2174
2175 let left: RcLazy<String> = append(empty(), a.clone());
2177 assert_eq!(*left.evaluate(), *a.evaluate());
2178
2179 let right: RcLazy<String> = append(a.clone(), empty());
2181 assert_eq!(*right.evaluate(), *a.evaluate());
2182 }
2183
2184 #[test]
2188 fn test_rc_lazy_fold_right() {
2189 use crate::functions::*;
2190
2191 let lazy = RcLazy::pure(10);
2192 let result = fold_right::<
2193 crate::brands::RcFnBrand,
2194 crate::brands::LazyBrand<RcLazyConfig>,
2195 _,
2196 _,
2197 >(|a, b| a + b, 5, lazy);
2198 assert_eq!(result, 15);
2199 }
2200
2201 #[test]
2203 fn test_rc_lazy_fold_left() {
2204 use crate::functions::*;
2205
2206 let lazy = RcLazy::pure(10);
2207 let result = fold_left::<
2208 crate::brands::RcFnBrand,
2209 crate::brands::LazyBrand<RcLazyConfig>,
2210 _,
2211 _,
2212 >(|b, a| b + a, 5, lazy);
2213 assert_eq!(result, 15);
2214 }
2215
2216 #[test]
2218 fn test_rc_lazy_fold_map() {
2219 use crate::functions::*;
2220
2221 let lazy = RcLazy::pure(10);
2222 let result =
2223 fold_map::<crate::brands::RcFnBrand, crate::brands::LazyBrand<RcLazyConfig>, _, _>(
2224 |a: i32| a.to_string(),
2225 lazy,
2226 );
2227 assert_eq!(result, "10");
2228 }
2229
2230 #[test]
2236 fn test_rc_lazy_partial_eq() {
2237 let a = RcLazy::pure(42);
2238 let b = RcLazy::pure(42);
2239 let c = RcLazy::pure(99);
2240
2241 assert!(a == b);
2242 assert!(b != c);
2243 }
2244
2245 #[test]
2249 fn test_arc_lazy_partial_eq() {
2250 let a = ArcLazy::pure(42);
2251 let b = ArcLazy::pure(42);
2252 let c = ArcLazy::pure(99);
2253
2254 assert!(a == b);
2255 assert!(b != c);
2256 }
2257
2258 #[test]
2264 fn test_rc_lazy_partial_ord() {
2265 let a = RcLazy::pure(1);
2266 let b = RcLazy::pure(2);
2267 let c = RcLazy::pure(2);
2268
2269 assert!(a < b);
2270 assert!(b > a);
2271 assert!(b >= c);
2272 assert!(c <= b);
2273 }
2274
2275 #[test]
2279 fn test_arc_lazy_partial_ord() {
2280 let a = ArcLazy::pure(1);
2281 let b = ArcLazy::pure(2);
2282
2283 assert!(a < b);
2284 assert!(b > a);
2285 }
2286
2287 #[test]
2292 fn test_rc_lazy_fix_constant() {
2293 let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 42);
2294 assert_eq!(*fixed.evaluate(), 42);
2295 }
2296
2297 #[test]
2302 fn test_rc_lazy_fix_cell_initialized() {
2303 let fixed = rc_lazy_fix(|_self_ref: RcLazy<String>| String::from("initialized"));
2304 assert_eq!(fixed.evaluate().as_str(), "initialized");
2306 }
2307
2308 #[test]
2315 fn test_rc_lazy_fix_self_reference_plumbing() {
2316 let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 7);
2318 assert_eq!(*fixed.evaluate(), 7);
2319 }
2320
2321 #[test]
2325 fn test_rc_lazy_fix_memoization() {
2326 let counter = Rc::new(RefCell::new(0));
2327 let counter_clone = counter.clone();
2328 let fixed = rc_lazy_fix(move |_self_ref: RcLazy<i32>| {
2329 *counter_clone.borrow_mut() += 1;
2330 100
2331 });
2332
2333 assert_eq!(*counter.borrow(), 0);
2334 assert_eq!(*fixed.evaluate(), 100);
2335 assert_eq!(*counter.borrow(), 1);
2336 assert_eq!(*fixed.evaluate(), 100);
2338 assert_eq!(*counter.borrow(), 1);
2339 }
2340
2341 #[test]
2343 fn test_rc_lazy_fix_clone_sharing() {
2344 let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 55);
2345 let cloned = fixed.clone();
2346 assert_eq!(*fixed.evaluate(), 55);
2347 assert_eq!(*cloned.evaluate(), 55);
2348 }
2349
2350 #[test]
2353 fn test_arc_lazy_fix_constant() {
2354 let fixed = arc_lazy_fix(|_self_ref: ArcLazy<i32>| 42);
2355 assert_eq!(*fixed.evaluate(), 42);
2356 }
2357
2358 #[test]
2360 fn test_arc_lazy_fix_cell_initialized() {
2361 let fixed = arc_lazy_fix(|_self_ref: ArcLazy<String>| String::from("initialized"));
2362 assert_eq!(fixed.evaluate().as_str(), "initialized");
2364 }
2365
2366 #[test]
2368 fn test_arc_lazy_fix_self_reference_plumbing() {
2369 let fixed = arc_lazy_fix(|_self_ref: ArcLazy<i32>| 7);
2370 assert_eq!(*fixed.evaluate(), 7);
2371 }
2372
2373 #[test]
2375 fn test_arc_lazy_fix_memoization() {
2376 use std::sync::atomic::{
2377 AtomicUsize,
2378 Ordering,
2379 };
2380
2381 let counter = Arc::new(AtomicUsize::new(0));
2382 let counter_clone = counter.clone();
2383 let fixed = arc_lazy_fix(move |_self_ref: ArcLazy<i32>| {
2384 counter_clone.fetch_add(1, Ordering::SeqCst);
2385 100
2386 });
2387
2388 assert_eq!(counter.load(Ordering::SeqCst), 0);
2389 assert_eq!(*fixed.evaluate(), 100);
2390 assert_eq!(counter.load(Ordering::SeqCst), 1);
2391 assert_eq!(*fixed.evaluate(), 100);
2393 assert_eq!(counter.load(Ordering::SeqCst), 1);
2394 }
2395
2396 #[test]
2400 fn test_arc_lazy_fold_right() {
2401 use crate::{
2402 brands::*,
2403 functions::*,
2404 };
2405
2406 let lazy = ArcLazy::new(|| 10);
2407 let result = fold_right::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, _>(|a, b| a + b, 5, lazy);
2408 assert_eq!(result, 15);
2409 }
2410
2411 #[test]
2413 fn test_arc_lazy_fold_left() {
2414 use crate::{
2415 brands::*,
2416 functions::*,
2417 };
2418
2419 let lazy = ArcLazy::new(|| 10);
2420 let result = fold_left::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, _>(|b, a| b + a, 5, lazy);
2421 assert_eq!(result, 15);
2422 }
2423
2424 #[test]
2426 fn test_arc_lazy_fold_map() {
2427 use crate::{
2428 brands::*,
2429 functions::*,
2430 };
2431
2432 let lazy = ArcLazy::new(|| 10);
2433 let result = fold_map::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, String>(
2434 |a: i32| a.to_string(),
2435 lazy,
2436 );
2437 assert_eq!(result, "10");
2438 }
2439
2440 #[quickcheck]
2442 fn prop_arc_lazy_fold_right(x: i32) -> bool {
2443 use crate::{
2444 brands::*,
2445 functions::*,
2446 };
2447
2448 let rc_lazy = RcLazy::new(move || x);
2449 let arc_lazy = ArcLazy::new(move || x);
2450 let rc_result =
2451 fold_right::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _>(|a, b| a + b, 0, rc_lazy);
2452 let arc_result =
2453 fold_right::<RcFnBrand, LazyBrand<ArcLazyConfig>, _, _>(|a, b| a + b, 0, arc_lazy);
2454 rc_result == arc_result
2455 }
2456
2457 #[test]
2463 fn test_rc_lazy_fold_map_with_index() {
2464 use crate::{
2465 brands::*,
2466 classes::foldable_with_index::FoldableWithIndex,
2467 };
2468
2469 let lazy = RcLazy::new(|| 42);
2470 let result = <LazyBrand<RcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
2471 |_, x: i32| x.to_string(),
2472 lazy,
2473 );
2474 assert_eq!(result, "42");
2475 }
2476
2477 #[test]
2481 fn test_arc_lazy_fold_map_with_index() {
2482 use crate::{
2483 brands::*,
2484 classes::foldable_with_index::FoldableWithIndex,
2485 };
2486
2487 let lazy = ArcLazy::new(|| 10);
2488 let result = <LazyBrand<ArcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
2489 |_, x: i32| x.to_string(),
2490 lazy,
2491 );
2492 assert_eq!(result, "10");
2493 }
2494
2495 #[test]
2499 fn test_rc_lazy_foldable_with_index_compatibility() {
2500 use crate::{
2501 brands::*,
2502 classes::foldable_with_index::FoldableWithIndex,
2503 functions::*,
2504 };
2505
2506 let lazy1 = RcLazy::new(|| 7);
2507 let lazy2 = RcLazy::new(|| 7);
2508 let f = |a: i32| a.to_string();
2509
2510 let fold_result = fold_map::<RcFnBrand, LazyBrand<RcLazyConfig>, _, String>(f, lazy1);
2511 let fold_with_index_result =
2512 <LazyBrand<RcLazyConfig> as FoldableWithIndex>::fold_map_with_index(|_, a| f(a), lazy2);
2513 assert_eq!(fold_result, fold_with_index_result);
2514 }
2515
2516 #[quickcheck]
2522 fn prop_arc_lazy_ref_map_identity(x: i32) -> bool {
2523 let lazy = ArcLazy::new(move || x);
2524 let mapped = lazy.clone().ref_map(|a| *a);
2525 *lazy.evaluate() == *mapped.evaluate()
2526 }
2527
2528 #[quickcheck]
2532 fn prop_arc_lazy_ref_map_composition(x: i32) -> bool {
2533 let f = |a: &i32| a.wrapping_mul(2);
2534 let g = |a: &i32| a.wrapping_add(1);
2535
2536 let lazy1 = ArcLazy::new(move || x);
2537 let composed = lazy1.ref_map(|a| g(&f(a)));
2538
2539 let lazy2 = ArcLazy::new(move || x);
2540 let chained = lazy2.ref_map(f).ref_map(g);
2541
2542 *composed.evaluate() == *chained.evaluate()
2543 }
2544
2545 #[quickcheck]
2547 fn prop_arc_lazy_ref_map_memoization(x: i32) -> bool {
2548 let lazy = ArcLazy::new(move || x);
2549 let mapped = lazy.ref_map(|a| a.wrapping_mul(3));
2550 let r1 = *mapped.evaluate();
2551 let r2 = *mapped.evaluate();
2552 r1 == r2
2553 }
2554
2555 #[test]
2559 fn test_rc_lazy_fix_self_reference() {
2560 let lazy = rc_lazy_fix(|self_ref: RcLazy<Vec<i32>>| {
2561 let _ = self_ref; vec![1, 2, 3]
2564 });
2565 assert_eq!(*lazy.evaluate(), vec![1, 2, 3]);
2566 }
2567
2568 #[test]
2570 fn test_rc_lazy_fix_uses_self_ref() {
2571 let counter = Rc::new(RefCell::new(0));
2573 let counter_clone = counter.clone();
2574 let lazy = rc_lazy_fix(move |self_ref: RcLazy<i32>| {
2575 *counter_clone.borrow_mut() += 1;
2576 let _ = self_ref;
2579 42
2580 });
2581 assert_eq!(*lazy.evaluate(), 42);
2582 assert_eq!(*counter.borrow(), 1);
2583 assert_eq!(*lazy.evaluate(), 42);
2585 assert_eq!(*counter.borrow(), 1);
2586 }
2587
2588 #[test]
2590 fn test_arc_lazy_fix_self_reference() {
2591 let lazy = arc_lazy_fix(|self_ref: ArcLazy<Vec<i32>>| {
2592 let _ = self_ref;
2593 vec![1, 2, 3]
2594 });
2595 assert_eq!(*lazy.evaluate(), vec![1, 2, 3]);
2596 }
2597
2598 #[test]
2600 fn test_arc_lazy_fix_uses_self_ref() {
2601 use std::sync::atomic::{
2602 AtomicUsize,
2603 Ordering,
2604 };
2605
2606 let counter = Arc::new(AtomicUsize::new(0));
2607 let counter_clone = counter.clone();
2608 let lazy = arc_lazy_fix(move |self_ref: ArcLazy<i32>| {
2609 counter_clone.fetch_add(1, Ordering::SeqCst);
2610 let _ = self_ref;
2611 42
2612 });
2613 assert_eq!(*lazy.evaluate(), 42);
2614 assert_eq!(counter.load(Ordering::SeqCst), 1);
2615 assert_eq!(*lazy.evaluate(), 42);
2617 assert_eq!(counter.load(Ordering::SeqCst), 1);
2618 }
2619
2620 #[test]
2622 fn test_arc_lazy_fix_thread_safety() {
2623 use std::thread;
2624
2625 let lazy = arc_lazy_fix(|self_ref: ArcLazy<i32>| {
2626 let _ = self_ref;
2627 42
2628 });
2629
2630 let mut handles = vec![];
2631 for _ in 0 .. 10 {
2632 let lazy_clone = lazy.clone();
2633 handles.push(thread::spawn(move || {
2634 assert_eq!(*lazy_clone.evaluate(), 42);
2635 }));
2636 }
2637
2638 for handle in handles {
2639 handle.join().unwrap();
2640 }
2641 }
2642
2643 #[quickcheck]
2645 fn prop_rc_lazy_fix_constant(x: i32) -> bool {
2646 let fixed = rc_lazy_fix(move |_: RcLazy<i32>| x);
2647 *fixed.evaluate() == x
2648 }
2649
2650 #[quickcheck]
2652 fn prop_arc_lazy_fix_constant(x: i32) -> bool {
2653 let fixed = arc_lazy_fix(move |_: ArcLazy<i32>| x);
2654 *fixed.evaluate() == x
2655 }
2656
2657 #[quickcheck]
2663 fn ref_functor_identity(x: i32) -> bool {
2664 let lazy = RcLazy::pure(x);
2665 *lazy.clone().ref_map(|v| *v).evaluate() == *lazy.evaluate()
2666 }
2667
2668 #[quickcheck]
2670 fn ref_functor_composition(x: i32) -> bool {
2671 let f = |a: &i32| a.wrapping_add(1);
2672 let g = |a: &i32| a.wrapping_mul(2);
2673 let lazy = RcLazy::pure(x);
2674 let lhs = *lazy.clone().ref_map(move |v| f(&g(v))).evaluate();
2675 let rhs = *lazy.ref_map(g).ref_map(f).evaluate();
2676 lhs == rhs
2677 }
2678
2679 #[quickcheck]
2683 fn deferrable_transparency(x: i32) -> bool {
2684 let lazy = RcLazy::pure(x);
2685 let deferred: RcLazy<i32> = crate::classes::Deferrable::defer(move || RcLazy::pure(x));
2686 *deferred.evaluate() == *lazy.evaluate()
2687 }
2688
2689 #[quickcheck]
2693 fn rc_lazy_semigroup_associativity(
2694 a: String,
2695 b: String,
2696 c: String,
2697 ) -> bool {
2698 use crate::classes::semigroup::append;
2699
2700 let la = RcLazy::pure(a.clone());
2701 let lb = RcLazy::pure(b.clone());
2702 let lc = RcLazy::pure(c.clone());
2703 let la2 = RcLazy::pure(a);
2704 let lb2 = RcLazy::pure(b);
2705 let lc2 = RcLazy::pure(c);
2706 let lhs = append(append(la, lb), lc).evaluate().clone();
2707 let rhs = append(la2, append(lb2, lc2)).evaluate().clone();
2708 lhs == rhs
2709 }
2710
2711 #[quickcheck]
2713 fn arc_lazy_semigroup_associativity(
2714 a: String,
2715 b: String,
2716 c: String,
2717 ) -> bool {
2718 use crate::classes::semigroup::append;
2719
2720 let la = ArcLazy::pure(a.clone());
2721 let lb = ArcLazy::pure(b.clone());
2722 let lc = ArcLazy::pure(c.clone());
2723 let la2 = ArcLazy::pure(a);
2724 let lb2 = ArcLazy::pure(b);
2725 let lc2 = ArcLazy::pure(c);
2726 let lhs = append(append(la, lb), lc).evaluate().clone();
2727 let rhs = append(la2, append(lb2, lc2)).evaluate().clone();
2728 lhs == rhs
2729 }
2730
2731 #[quickcheck]
2735 fn rc_lazy_monoid_left_identity(x: String) -> bool {
2736 use crate::classes::{
2737 monoid::empty,
2738 semigroup::append,
2739 };
2740
2741 let a = RcLazy::pure(x.clone());
2742 let lhs: RcLazy<String> = append(empty(), a);
2743 *lhs.evaluate() == x
2744 }
2745
2746 #[quickcheck]
2748 fn rc_lazy_monoid_right_identity(x: String) -> bool {
2749 use crate::classes::{
2750 monoid::empty,
2751 semigroup::append,
2752 };
2753
2754 let a = RcLazy::pure(x.clone());
2755 let rhs: RcLazy<String> = append(a, empty());
2756 *rhs.evaluate() == x
2757 }
2758
2759 #[quickcheck]
2761 fn arc_lazy_monoid_left_identity(x: String) -> bool {
2762 use crate::classes::{
2763 monoid::empty,
2764 semigroup::append,
2765 };
2766
2767 let a = ArcLazy::pure(x.clone());
2768 let lhs: ArcLazy<String> = append(empty(), a);
2769 *lhs.evaluate() == x
2770 }
2771
2772 #[quickcheck]
2774 fn arc_lazy_monoid_right_identity(x: String) -> bool {
2775 use crate::classes::{
2776 monoid::empty,
2777 semigroup::append,
2778 };
2779
2780 let a = ArcLazy::pure(x.clone());
2781 let rhs: ArcLazy<String> = append(a, empty());
2782 *rhs.evaluate() == x
2783 }
2784
2785 #[test]
2789 fn test_rc_lazy_config_pointer_brand() {
2790 fn assert_brand_is_rc<C: LazyConfig<PointerBrand = crate::brands::RcBrand>>() {}
2791 assert_brand_is_rc::<RcLazyConfig>();
2792 }
2793
2794 #[test]
2796 fn test_arc_lazy_config_pointer_brand() {
2797 fn assert_brand_is_arc<C: LazyConfig<PointerBrand = crate::brands::ArcBrand>>() {}
2798 assert_brand_is_arc::<ArcLazyConfig>();
2799 }
2800
2801 #[test]
2808 fn test_panic_poisoning() {
2809 use std::panic;
2810
2811 let memo: RcLazy<i32> = RcLazy::new(|| {
2812 panic!("initializer panic");
2813 });
2814
2815 let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
2816 let _ = memo.evaluate();
2817 }));
2818 assert!(result.is_err(), "First evaluate should panic");
2819
2820 let result2 = panic::catch_unwind(panic::AssertUnwindSafe(|| {
2821 let _ = memo.evaluate();
2822 }));
2823 assert!(result2.is_err(), "Second evaluate should also panic (poisoned)");
2824 }
2825
2826 #[test]
2828 fn test_rc_lazy_fix_shared_self_ref() {
2829 let lazy = rc_lazy_fix(|self_ref: RcLazy<i32>| {
2830 let _captured = self_ref.clone();
2832 100
2833 });
2834 assert_eq!(*lazy.evaluate(), 100);
2835 let cloned = lazy.clone();
2837 assert_eq!(*cloned.evaluate(), 100);
2838 }
2839}