Skip to main content

fp_library/types/
lazy.rs

1//! Memoized lazy evaluation with shared cache semantics.
2//!
3//! Computes a value at most once on first access and caches the result. All clones share the same cache. Available in both single-threaded [`RcLazy`] and thread-safe [`ArcLazy`] variants. The corresponding brands are [`RcLazyBrand`](crate::brands::RcLazyBrand) and [`ArcLazyBrand`](crate::brands::ArcLazyBrand).
4//!
5//! ## Why `Lazy` does not implement `Functor`
6//!
7//! [`Lazy::evaluate`] returns `&A` (a reference to the cached value), not an owned `A`.
8//! The standard [`Functor`](crate::classes::Functor) trait requires `A -> B`, which would
9//! need either cloning or consuming the cached value. Instead, `Lazy` implements
10//! [`RefFunctor`](crate::classes::RefFunctor) (and [`SendRefFunctor`](crate::classes::SendRefFunctor)
11//! for `ArcLazy`), whose `ref_map` takes `&A -> B`. Use [`map`](crate::functions::map) with a
12//! closure that takes `&A` to map over lazy values, or [`send_ref_map`](crate::functions::send_ref_map)
13//! for thread-safe mapping.
14
15#[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	/// Single-threaded memoization using [`Rc<LazyCell>`].
80	///
81	/// Not thread-safe. Use [`ArcLazyConfig`] for multi-threaded contexts.
82	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		/// Creates a new lazy cell from an initializer.
90		#[document_signature]
91		///
92		#[document_type_parameters("The lifetime of the computation.", "The type of the value.")]
93		///
94		#[document_parameters("The initializer thunk.")]
95		///
96		#[document_returns("A new lazy cell.")]
97		///
98		#[document_examples]
99		///
100		/// ```
101		/// use fp_library::{
102		/// 	classes::*,
103		/// 	types::*,
104		/// };
105		///
106		/// let lazy = RcLazyConfig::lazy_new(Box::new(|| 42));
107		/// assert_eq!(*RcLazyConfig::evaluate(&lazy), 42);
108		/// ```
109		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		/// Forces evaluation and returns a reference.
114		#[document_signature]
115		///
116		#[document_type_parameters(
117			"The lifetime of the computation.",
118			"The borrow lifetime.",
119			"The type of the value."
120		)]
121		///
122		#[document_parameters("The lazy cell to evaluate.")]
123		///
124		#[document_returns("A reference to the value.")]
125		///
126		#[document_examples]
127		///
128		/// ```
129		/// use fp_library::{
130		/// 	classes::*,
131		/// 	types::*,
132		/// };
133		///
134		/// let lazy = RcLazyConfig::lazy_new(Box::new(|| 42));
135		/// assert_eq!(*RcLazyConfig::evaluate(&lazy), 42);
136		/// ```
137		fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
138			LazyCell::force(lazy)
139		}
140	}
141
142	/// Thread-safe memoization using [`Arc<LazyLock>`].
143	///
144	/// Requires `A: Send + Sync` for the value type.
145	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		/// Creates a new lazy cell from an initializer.
153		#[document_signature]
154		///
155		#[document_type_parameters("The lifetime of the computation.", "The type of the value.")]
156		///
157		#[document_parameters("The initializer thunk.")]
158		///
159		#[document_returns("A new lazy cell.")]
160		///
161		#[document_examples]
162		///
163		/// ```
164		/// use fp_library::{
165		/// 	classes::*,
166		/// 	types::*,
167		/// };
168		///
169		/// let lazy = ArcLazyConfig::lazy_new(Box::new(|| 42));
170		/// assert_eq!(*ArcLazyConfig::evaluate(&lazy), 42);
171		/// ```
172		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		/// Forces evaluation and returns a reference.
177		#[document_signature]
178		///
179		#[document_type_parameters(
180			"The lifetime of the computation.",
181			"The borrow lifetime.",
182			"The type of the value."
183		)]
184		///
185		#[document_parameters("The lazy cell to evaluate.")]
186		///
187		#[document_returns("A reference to the value.")]
188		///
189		#[document_examples]
190		///
191		/// ```
192		/// use fp_library::{
193		/// 	classes::*,
194		/// 	types::*,
195		/// };
196		///
197		/// let lazy = ArcLazyConfig::lazy_new(Box::new(|| 42));
198		/// assert_eq!(*ArcLazyConfig::evaluate(&lazy), 42);
199		/// ```
200		fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
201			LazyLock::force(lazy)
202		}
203	}
204
205	/// A lazily-computed, memoized value with shared semantics.
206	///
207	/// The computation runs at most once; subsequent accesses return the cached value.
208	/// Cloning a `Lazy` shares the underlying cache, so all clones see the same value.
209	///
210	/// ### Panics
211	///
212	/// If the initializer closure panics, the underlying [`LazyCell`](std::cell::LazyCell)
213	/// (for [`RcLazyConfig`]) or [`LazyLock`](std::sync::LazyLock) (for [`ArcLazyConfig`])
214	/// is poisoned. Any subsequent call to [`evaluate`](Lazy::evaluate) on the same instance
215	/// or any of its clones will panic again. For panic-safe memoization, use
216	/// [`TryLazy`](crate::types::TryLazy) with a closure that catches panics via
217	/// [`std::panic::catch_unwind`].
218	///
219	/// ### Higher-Kinded Type Representation
220	///
221	/// The higher-kinded representation of this type constructor is [`LazyBrand<Config>`](crate::brands::LazyBrand),
222	/// which is parameterized by the memoization configuration and is polymorphic over the computed value type.
223	#[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	///
229	pub struct Lazy<'a, A, Config: LazyConfig = RcLazyConfig>(
230		/// The internal lazy cell.
231		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		///
250		/// ```
251		/// use fp_library::{
252		/// 	classes::*,
253		/// 	types::*,
254		/// };
255		///
256		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 5);
257		/// let shared = memo.clone();
258		///
259		/// // First force computes and caches:
260		/// let value = memo.evaluate();
261		///
262		/// // Second force returns cached value (shared sees same result):
263		/// assert_eq!(shared.evaluate(), value);
264		/// ```
265		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		/// Gets the memoized value, computing on first access.
281		#[document_signature]
282		///
283		#[document_returns("A reference to the memoized value.")]
284		///
285		#[document_examples]
286		///
287		/// ```
288		/// use fp_library::{
289		/// 	classes::*,
290		/// 	types::*,
291		/// };
292		///
293		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 42);
294		/// assert_eq!(*memo.evaluate(), 42);
295		/// ```
296		#[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		/// Creates a new Lazy that will run `f` on first access.
312		#[document_signature]
313		///
314		#[document_parameters("The closure that produces the value.")]
315		///
316		#[document_returns("A new `Lazy` instance.")]
317		///
318		#[inline]
319		#[document_examples]
320		///
321		/// ```
322		/// use fp_library::{
323		/// 	classes::*,
324		/// 	types::*,
325		/// };
326		///
327		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 42);
328		/// assert_eq!(*memo.evaluate(), 42);
329		/// ```
330		pub fn new(f: impl FnOnce() -> A + 'a) -> Self {
331			Lazy(RcLazyConfig::lazy_new(Box::new(f)))
332		}
333
334		/// Creates a `Lazy` from an already-computed value.
335		///
336		/// The value is immediately available without any computation.
337		#[document_signature]
338		///
339		#[document_parameters("The pre-computed value to wrap.")]
340		///
341		#[document_returns("A new `Lazy` instance containing the value.")]
342		///
343		#[inline]
344		#[document_examples]
345		///
346		/// ```
347		/// use fp_library::{
348		/// 	classes::*,
349		/// 	types::*,
350		/// };
351		///
352		/// let lazy = Lazy::<_, RcLazyConfig>::pure(42);
353		/// assert_eq!(*lazy.evaluate(), 42);
354		/// ```
355		pub fn pure(a: A) -> Self {
356			Lazy(RcLazyConfig::lazy_new(Box::new(move || a)))
357		}
358
359		/// Returns a clone of the memoized value, computing on first access.
360		///
361		/// This is a convenience wrapper around [`evaluate`](Lazy::evaluate) for cases
362		/// where an owned value is needed rather than a reference.
363		#[document_signature]
364		///
365		#[document_returns("An owned clone of the memoized value.")]
366		///
367		#[document_examples]
368		///
369		/// ```
370		/// use fp_library::{
371		/// 	classes::*,
372		/// 	types::*,
373		/// };
374		///
375		/// let memo = RcLazy::new(|| vec![1, 2, 3]);
376		/// let owned: Vec<i32> = memo.evaluate_owned();
377		/// assert_eq!(owned, vec![1, 2, 3]);
378		/// ```
379		#[inline]
380		pub fn evaluate_owned(&self) -> A
381		where
382			A: Clone, {
383			self.evaluate().clone()
384		}
385
386		/// Maps a function over the memoized value by reference.
387		///
388		/// This is the inherent method form of [`RefFunctor::ref_map`](crate::classes::ref_functor::RefFunctor::ref_map).
389		/// The mapping function receives a reference to the cached value and returns a new value,
390		/// which is itself lazily memoized.
391		#[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		///
397		/// ```
398		/// use fp_library::{
399		/// 	classes::*,
400		/// 	types::*,
401		/// };
402		///
403		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 10);
404		/// let mapped = memo.ref_map(|x| *x * 2);
405		/// assert_eq!(*mapped.evaluate(), 20);
406		/// ```
407		#[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		///
427		/// ```
428		/// use fp_library::{
429		/// 	classes::*,
430		/// 	types::*,
431		/// };
432		/// let thunk = Thunk::new(|| 42);
433		/// let lazy: RcLazy<i32> = Lazy::from(thunk);
434		/// assert_eq!(*lazy.evaluate(), 42);
435		/// ```
436		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		///
453		/// ```
454		/// use fp_library::{
455		/// 	classes::*,
456		/// 	types::*,
457		/// };
458		/// let task = Trampoline::pure(42);
459		/// let lazy: RcLazy<i32> = Lazy::from(task);
460		/// assert_eq!(*lazy.evaluate(), 42);
461		/// ```
462		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		/// Converts a [`Thunk`] into an [`ArcLazy`] by eagerly evaluating the thunk.
473		///
474		/// Thunk is `!Send`, so the value must be computed immediately to cross
475		/// into the thread-safe `ArcLazy` world.
476		#[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		///
481		/// ```
482		/// use fp_library::{
483		/// 	classes::*,
484		/// 	types::*,
485		/// };
486		/// let thunk = Thunk::new(|| 42);
487		/// let lazy: ArcLazy<i32> = ArcLazy::from(thunk);
488		/// assert_eq!(*lazy.evaluate(), 42);
489		/// ```
490		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		/// Converts a [`Trampoline`] into an [`ArcLazy`] by eagerly evaluating the trampoline.
501		///
502		/// Trampoline is `!Send`, so the value must be computed immediately to cross
503		/// into the thread-safe `ArcLazy` world.
504		#[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		///
509		/// ```
510		/// use fp_library::{
511		/// 	classes::*,
512		/// 	types::*,
513		/// };
514		/// let task = Trampoline::pure(42);
515		/// let lazy: ArcLazy<i32> = ArcLazy::from(task);
516		/// assert_eq!(*lazy.evaluate(), 42);
517		/// ```
518		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		/// Converts a [`SendThunk`] into an [`ArcLazy`] without eager evaluation.
529		///
530		/// Because `SendThunk` already satisfies `Send`, the inner closure can be
531		/// passed directly into `ArcLazy`, deferring computation until first access.
532		#[document_signature]
533		#[document_parameters("The send thunk to convert.")]
534		#[document_returns("A new `ArcLazy` wrapping the deferred computation.")]
535		#[document_examples]
536		///
537		/// ```
538		/// use fp_library::{
539		/// 	classes::*,
540		/// 	types::*,
541		/// };
542		/// let thunk = SendThunk::new(|| 42);
543		/// let lazy: ArcLazy<i32> = ArcLazy::from(thunk);
544		/// assert_eq!(*lazy.evaluate(), 42);
545		/// ```
546		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		/// Converts an [`RcLazy`] into an [`ArcLazy`] by eagerly evaluating and cloning the value.
559		///
560		/// `RcLazy` is `!Send`, so the value must be computed immediately and cloned
561		/// into the thread-safe `ArcLazy` world.
562		#[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		///
569		/// ```
570		/// use fp_library::{
571		/// 	classes::*,
572		/// 	types::*,
573		/// };
574		///
575		/// let rc_lazy = RcLazy::new(|| 42);
576		/// let arc_lazy: ArcLazy<i32> = ArcLazy::from(rc_lazy);
577		/// assert_eq!(*arc_lazy.evaluate(), 42);
578		/// ```
579		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		/// Converts an [`ArcLazy`] into an [`RcLazy`] by eagerly evaluating and cloning the value.
590		///
591		/// The value is computed immediately and cloned into a new single-threaded
592		/// `RcLazy` instance.
593		#[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		///
600		/// ```
601		/// use fp_library::{
602		/// 	classes::*,
603		/// 	types::*,
604		/// };
605		///
606		/// let arc_lazy = ArcLazy::new(|| 42);
607		/// let rc_lazy: RcLazy<i32> = RcLazy::from(arc_lazy);
608		/// assert_eq!(*rc_lazy.evaluate(), 42);
609		/// ```
610		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		/// Creates a new Lazy that will run `f` on first access.
625		#[document_signature]
626		///
627		#[document_parameters("The closure that produces the value.")]
628		///
629		#[document_returns("A new `Lazy` instance.")]
630		///
631		#[inline]
632		#[document_examples]
633		///
634		/// ```
635		/// use fp_library::{
636		/// 	classes::*,
637		/// 	types::*,
638		/// };
639		///
640		/// let lazy = Lazy::<_, ArcLazyConfig>::new(|| 42);
641		/// assert_eq!(*lazy.evaluate(), 42);
642		/// ```
643		pub fn new(f: impl FnOnce() -> A + Send + 'a) -> Self {
644			Lazy(ArcLazyConfig::lazy_new(Box::new(f)))
645		}
646
647		/// Creates a `Lazy` from an already-computed value.
648		///
649		/// The value is immediately available without any computation.
650		/// Requires `Send + Sync` since `ArcLazy` is thread-safe.
651		#[document_signature]
652		///
653		#[document_parameters("The pre-computed value to wrap.")]
654		///
655		#[document_returns("A new `Lazy` instance containing the value.")]
656		///
657		#[inline]
658		#[document_examples]
659		///
660		/// ```
661		/// use fp_library::{
662		/// 	classes::*,
663		/// 	types::*,
664		/// };
665		///
666		/// let lazy = Lazy::<_, ArcLazyConfig>::pure(42);
667		/// assert_eq!(*lazy.evaluate(), 42);
668		/// ```
669		pub fn pure(a: A) -> Self {
670			Lazy(ArcLazyConfig::lazy_new(Box::new(move || a)))
671		}
672
673		/// Returns a clone of the memoized value, computing on first access.
674		///
675		/// This is a convenience wrapper around [`evaluate`](Lazy::evaluate) for cases
676		/// where an owned value is needed rather than a reference. Requires `Send + Sync`
677		/// since `ArcLazy` is thread-safe.
678		#[document_signature]
679		///
680		#[document_returns("An owned clone of the memoized value.")]
681		///
682		#[document_examples]
683		///
684		/// ```
685		/// use fp_library::{
686		/// 	classes::*,
687		/// 	types::*,
688		/// };
689		///
690		/// let memo = ArcLazy::new(|| vec![1, 2, 3]);
691		/// let owned: Vec<i32> = memo.evaluate_owned();
692		/// assert_eq!(owned, vec![1, 2, 3]);
693		/// ```
694		#[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		/// Maps a function over the memoized value by reference.
709		///
710		/// This is the `ArcLazy` counterpart of [`RcLazy::ref_map`](Lazy::ref_map).
711		/// The mapping function receives a reference to the cached value and returns a new value,
712		/// which is itself lazily memoized.
713		///
714		/// Note: A blanket `RefFunctor` trait impl is not provided for `LazyBrand<ArcLazyConfig>`
715		/// because the `RefFunctor` trait does not require `Send` on the mapping function, but
716		/// `ArcLazy::new` requires `Send`. This inherent method adds the necessary `Send` bounds
717		/// explicitly.
718		#[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		///
724		/// ```
725		/// use fp_library::{
726		/// 	classes::*,
727		/// 	types::*,
728		/// };
729		///
730		/// let memo = ArcLazy::new(|| 10);
731		/// let mapped = memo.ref_map(|x| *x * 2);
732		/// assert_eq!(*mapped.evaluate(), 20);
733		/// ```
734		#[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	/// Single-threaded memoization alias.
745	pub type RcLazy<'a, A> = Lazy<'a, A, RcLazyConfig>;
746
747	/// Thread-safe memoization alias.
748	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		/// Defers a computation that produces a `Lazy` value.
765		///
766		/// This flattens the nested structure: instead of `Lazy<Lazy<A>>`, we get `Lazy<A>`.
767		/// The inner `Lazy` is computed only when the outer `Lazy` is evaluated.
768		#[document_signature]
769		///
770		#[document_parameters("The thunk that produces the lazy value.")]
771		///
772		#[document_returns("A new `Lazy` value.")]
773		///
774		#[document_examples]
775		///
776		/// ```
777		/// use fp_library::{
778		/// 	brands::*,
779		/// 	classes::*,
780		/// 	functions::*,
781		/// 	types::*,
782		/// };
783		///
784		/// let lazy = Lazy::<_, RcLazyConfig>::defer(|| RcLazy::pure(42));
785		/// assert_eq!(*lazy.evaluate(), 42);
786		/// ```
787		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		/// Defers a computation that produces a thread-safe `Lazy` value using a thread-safe thunk.
803		///
804		/// This flattens the nested structure: instead of `ArcLazy<ArcLazy<A>>`, we get `ArcLazy<A>`.
805		/// The inner `Lazy` is computed only when the outer `Lazy` is evaluated.
806		#[document_signature]
807		///
808		#[document_parameters("The thunk that produces the lazy value.")]
809		///
810		#[document_returns("A new `ArcLazy` value.")]
811		///
812		#[document_examples]
813		///
814		/// ```
815		/// use fp_library::{
816		/// 	brands::*,
817		/// 	classes::*,
818		/// 	types::*,
819		/// };
820		///
821		/// let lazy = ArcLazy::send_defer(|| ArcLazy::pure(42));
822		/// assert_eq!(*lazy.evaluate(), 42);
823		/// ```
824		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		/// Maps a function over the memoized value, where the function takes a reference.
833		#[document_signature]
834		///
835		#[document_type_parameters(
836			"The lifetime of the values.",
837			"The type of the value.",
838			"The type of the result."
839		)]
840		///
841		#[document_parameters("The function to apply.", "The memoized value.")]
842		///
843		#[document_returns("A new memoized value.")]
844		///
845		#[document_examples]
846		///
847		/// ```
848		/// use fp_library::{
849		/// 	brands::*,
850		/// 	classes::*,
851		/// 	types::*,
852		/// };
853		///
854		/// let memo = Lazy::<_, RcLazyConfig>::new(|| 10);
855		/// let mapped = LazyBrand::<RcLazyConfig>::ref_map(|x: &i32| *x * 2, &memo);
856		/// assert_eq!(*mapped.evaluate(), 20);
857		/// ```
858		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		/// Maps a thread-safe function over the memoized value, where the function takes a reference.
868		#[document_signature]
869		///
870		#[document_type_parameters(
871			"The lifetime of the values.",
872			"The type of the value.",
873			"The type of the result."
874		)]
875		///
876		#[document_parameters("The function to apply.", "The memoized value.")]
877		///
878		#[document_returns("A new memoized value.")]
879		///
880		#[document_examples]
881		///
882		/// ```
883		/// use fp_library::{
884		/// 	brands::*,
885		/// 	classes::*,
886		/// 	types::*,
887		/// };
888		///
889		/// let memo = ArcLazy::new(|| 10);
890		/// let mapped = LazyBrand::<ArcLazyConfig>::send_ref_map(|x: &i32| *x * 2, &memo);
891		/// assert_eq!(*mapped.evaluate(), 20);
892		/// ```
893		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	// -- SendRefPointed --
902
903	impl SendRefPointed for LazyBrand<ArcLazyConfig> {
904		/// Wraps a cloned value in a new thread-safe memoized context.
905		#[document_signature]
906		///
907		#[document_type_parameters("The lifetime of the value.", "The type of the value.")]
908		///
909		#[document_parameters("A reference to the value to wrap.")]
910		///
911		#[document_returns("A new thread-safe memoized value containing a clone of the input.")]
912		#[document_examples]
913		///
914		/// ```
915		/// use fp_library::{
916		/// 	brands::*,
917		/// 	classes::*,
918		/// 	types::*,
919		/// };
920		///
921		/// let value = 42;
922		/// let lazy = LazyBrand::<ArcLazyConfig>::send_ref_pure(&value);
923		/// assert_eq!(*lazy.evaluate(), 42);
924		/// ```
925		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	// -- SendRefLift --
934
935	impl SendRefLift for LazyBrand<ArcLazyConfig> {
936		/// Lifts a thread-safe binary function over two memoized values using references.
937		#[document_signature]
938		///
939		#[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		///
946		#[document_parameters(
947			"The function to lift.",
948			"The first memoized value.",
949			"The second memoized value."
950		)]
951		///
952		#[document_returns("A new thread-safe memoized value containing the result.")]
953		#[document_examples]
954		///
955		/// ```
956		/// use fp_library::{
957		/// 	brands::*,
958		/// 	classes::*,
959		/// 	types::*,
960		/// };
961		///
962		/// let x = ArcLazy::new(|| 3);
963		/// let y = ArcLazy::new(|| 4);
964		/// let z = LazyBrand::<ArcLazyConfig>::send_ref_lift2(|a: &i32, b: &i32| *a + *b, &x, &y);
965		/// assert_eq!(*z.evaluate(), 7);
966		/// ```
967		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	// -- SendRefSemiapplicative --
979
980	impl SendRefSemiapplicative for LazyBrand<ArcLazyConfig> {
981		/// Applies a wrapped thread-safe by-ref function to a memoized value.
982		#[document_signature]
983		///
984		#[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		///
991		#[document_parameters("The memoized wrapped by-ref function.", "The memoized value.")]
992		///
993		#[document_returns("A new thread-safe memoized value containing the result.")]
994		#[document_examples]
995		///
996		/// ```
997		/// use fp_library::{
998		/// 	brands::*,
999		/// 	classes::*,
1000		/// 	types::*,
1001		/// };
1002		///
1003		/// let f = ArcLazy::new(|| {
1004		/// 	std::sync::Arc::new(|x: &i32| *x * 2) as std::sync::Arc<dyn Fn(&i32) -> i32 + Send + Sync>
1005		/// });
1006		/// let x = ArcLazy::new(|| 5);
1007		/// let result = LazyBrand::<ArcLazyConfig>::send_ref_apply::<ArcFnBrand, _, _>(&f, &x);
1008		/// assert_eq!(*result.evaluate(), 10);
1009		/// ```
1010		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	// -- SendRefSemimonad --
1030
1031	impl SendRefSemimonad for LazyBrand<ArcLazyConfig> {
1032		/// Sequences a thread-safe computation using a reference to the memoized value.
1033		#[document_signature]
1034		///
1035		#[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		///
1041		#[document_parameters(
1042			"The memoized value.",
1043			"A thread-safe function that receives a reference and returns a new memoized value."
1044		)]
1045		///
1046		#[document_returns("A new thread-safe memoized value produced by the function.")]
1047		#[document_examples]
1048		///
1049		/// ```
1050		/// use fp_library::{
1051		/// 	brands::*,
1052		/// 	classes::*,
1053		/// 	types::*,
1054		/// };
1055		///
1056		/// let lazy = ArcLazy::new(|| 5);
1057		/// let result = LazyBrand::<ArcLazyConfig>::send_ref_bind(&lazy, |x: &i32| {
1058		/// 	let v = *x * 2;
1059		/// 	ArcLazy::new(move || v)
1060		/// });
1061		/// assert_eq!(*result.evaluate(), 10);
1062		/// ```
1063		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	// --- SendRefFoldable ---
1072
1073	impl SendRefFoldable for LazyBrand<ArcLazyConfig> {
1074		/// Maps the value to a monoid by reference (thread-safe).
1075		#[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		///
1086		/// ```
1087		/// use fp_library::{
1088		/// 	brands::*,
1089		/// 	classes::send_ref_foldable::*,
1090		/// 	types::*,
1091		/// };
1092		///
1093		/// let lazy = ArcLazy::new(|| 5);
1094		/// let result = send_ref_fold_map::<ArcFnBrand, LazyBrand<ArcLazyConfig>, _, _>(
1095		/// 	|a: &i32| a.to_string(),
1096		/// 	&lazy,
1097		/// );
1098		/// assert_eq!(result, "5");
1099		/// ```
1100		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	// --- SendRefFoldableWithIndex ---
1112
1113	impl SendRefFoldableWithIndex for LazyBrand<ArcLazyConfig> {
1114		/// Maps the value to a monoid by reference with the unit index (thread-safe).
1115		#[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		///
1126		/// ```
1127		/// use fp_library::{
1128		/// 	brands::*,
1129		/// 	classes::send_ref_foldable_with_index::SendRefFoldableWithIndex,
1130		/// 	types::*,
1131		/// };
1132		///
1133		/// let lazy = ArcLazy::new(|| 42);
1134		/// let result =
1135		/// 	<LazyBrand<ArcLazyConfig> as SendRefFoldableWithIndex>::send_ref_fold_map_with_index::<
1136		/// 		ArcFnBrand,
1137		/// 		_,
1138		/// 		_,
1139		/// 	>(|_, x: &i32| x.to_string(), &lazy);
1140		/// assert_eq!(result, "42");
1141		/// ```
1142		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	// --- SendRefFunctorWithIndex ---
1158
1159	impl SendRefFunctorWithIndex for LazyBrand<ArcLazyConfig> {
1160		/// Maps a function over the `ArcLazy` by reference with the unit index (thread-safe).
1161		#[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		///
1171		/// ```
1172		/// use fp_library::{
1173		/// 	brands::*,
1174		/// 	classes::send_ref_functor_with_index::SendRefFunctorWithIndex,
1175		/// 	types::*,
1176		/// };
1177		///
1178		/// let lazy = ArcLazy::new(|| 42);
1179		/// let mapped = <LazyBrand<ArcLazyConfig> as SendRefFunctorWithIndex>::send_ref_map_with_index(
1180		/// 	|_, x: &i32| x.to_string(),
1181		/// 	&lazy,
1182		/// );
1183		/// assert_eq!(*mapped.evaluate(), "42");
1184		/// ```
1185		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	// -- RefPointed --
1194
1195	impl RefPointed for LazyBrand<RcLazyConfig> {
1196		/// Wraps a cloned value in a new memoized context.
1197		#[document_signature]
1198		///
1199		#[document_type_parameters(
1200			"The lifetime of the value.",
1201			"The type of the value. Must be `Clone`."
1202		)]
1203		///
1204		#[document_parameters("A reference to the value to wrap.")]
1205		///
1206		#[document_returns("A new memoized value containing a clone of the input.")]
1207		///
1208		#[document_examples]
1209		///
1210		/// ```
1211		/// use fp_library::{
1212		/// 	brands::*,
1213		/// 	classes::*,
1214		/// 	types::*,
1215		/// };
1216		///
1217		/// let value = 42;
1218		/// let lazy = LazyBrand::<RcLazyConfig>::ref_pure(&value);
1219		/// assert_eq!(*lazy.evaluate(), 42);
1220		/// ```
1221		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	// -- RefLift --
1230
1231	impl RefLift for LazyBrand<RcLazyConfig> {
1232		/// Lifts a binary function over two memoized values using references.
1233		#[document_signature]
1234		///
1235		#[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		///
1242		#[document_parameters(
1243			"The function to lift.",
1244			"The first memoized value.",
1245			"The second memoized value."
1246		)]
1247		///
1248		#[document_returns("A new memoized value containing the result.")]
1249		///
1250		#[document_examples]
1251		///
1252		/// ```
1253		/// use fp_library::{
1254		/// 	brands::*,
1255		/// 	classes::*,
1256		/// 	types::*,
1257		/// };
1258		///
1259		/// let x = RcLazy::pure(3);
1260		/// let y = RcLazy::pure(4);
1261		/// let z = LazyBrand::<RcLazyConfig>::ref_lift2(|a: &i32, b: &i32| *a + *b, &x, &y);
1262		/// assert_eq!(*z.evaluate(), 7);
1263		/// ```
1264		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	// -- RefSemiapplicative --
1276
1277	impl RefSemiapplicative for LazyBrand<RcLazyConfig> {
1278		/// Applies a wrapped by-ref function within a memoized context to a memoized value.
1279		#[document_signature]
1280		///
1281		#[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		///
1288		#[document_parameters("The memoized wrapped by-ref function.", "The memoized value.")]
1289		///
1290		#[document_returns("A new memoized value containing the result of applying the function.")]
1291		///
1292		#[document_examples]
1293		///
1294		/// ```
1295		/// use fp_library::{
1296		/// 	brands::*,
1297		/// 	classes::*,
1298		/// 	types::*,
1299		/// };
1300		///
1301		/// let f = RcLazy::pure(std::rc::Rc::new(|x: &i32| *x * 2) as std::rc::Rc<dyn Fn(&i32) -> i32>);
1302		/// let x = RcLazy::pure(5);
1303		/// let result = LazyBrand::<RcLazyConfig>::ref_apply::<RcFnBrand, _, _>(&f, &x);
1304		/// assert_eq!(*result.evaluate(), 10);
1305		/// ```
1306		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	// -- RefSemimonad --
1321
1322	impl RefSemimonad for LazyBrand<RcLazyConfig> {
1323		/// Sequences a computation using a reference to the memoized value.
1324		#[document_signature]
1325		///
1326		#[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		///
1332		#[document_parameters(
1333			"The memoized value.",
1334			"A function that receives a reference to the value and returns a new memoized value."
1335		)]
1336		///
1337		#[document_returns("A new memoized value produced by the function.")]
1338		///
1339		#[document_examples]
1340		///
1341		/// ```
1342		/// use fp_library::{
1343		/// 	brands::*,
1344		/// 	classes::*,
1345		/// 	types::*,
1346		/// };
1347		///
1348		/// let lazy = RcLazy::pure(5);
1349		/// let result = LazyBrand::<RcLazyConfig>::ref_bind(&lazy, |x: &i32| {
1350		/// 	Lazy::<_, RcLazyConfig>::new({
1351		/// 		let v = *x;
1352		/// 		move || v * 2
1353		/// 	})
1354		/// });
1355		/// assert_eq!(*result.evaluate(), 10);
1356		/// ```
1357		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	// --- Display ---
1366
1367	#[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		/// Forces evaluation and displays the value.
1375		#[document_signature]
1376		///
1377		#[document_parameters("The formatter.")]
1378		///
1379		#[document_returns("The formatting result.")]
1380		///
1381		#[document_examples]
1382		///
1383		/// ```
1384		/// use fp_library::{
1385		/// 	classes::*,
1386		/// 	types::*,
1387		/// };
1388		///
1389		/// let lazy = RcLazy::new(|| 42);
1390		/// assert_eq!(format!("{}", lazy), "42");
1391		///
1392		/// let lazy = ArcLazy::new(|| 42);
1393		/// assert_eq!(format!("{}", lazy), "42");
1394		/// ```
1395		fn fmt(
1396			&self,
1397			f: &mut fmt::Formatter<'_>,
1398		) -> fmt::Result {
1399			fmt::Display::fmt(self.evaluate(), f)
1400		}
1401	}
1402
1403	// --- Semigroup ---
1404
1405	#[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		/// Combines two `RcLazy` values by combining their results using the inner type's `Semigroup`.
1411		///
1412		/// Both sides are forced on evaluation.
1413		#[document_signature]
1414		///
1415		#[document_parameters("The first lazy value.", "The second lazy value.")]
1416		///
1417		#[document_returns("A new `RcLazy` containing the combined result.")]
1418		///
1419		#[document_examples]
1420		///
1421		/// ```
1422		/// use fp_library::{
1423		/// 	functions::*,
1424		/// 	types::*,
1425		/// };
1426		///
1427		/// let a = RcLazy::pure("Hello".to_string());
1428		/// let b = RcLazy::pure(" World".to_string());
1429		/// let c = append(a, b);
1430		/// assert_eq!(*c.evaluate(), "Hello World");
1431		/// ```
1432		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		/// Combines two `ArcLazy` values by combining their results using the inner type's `Semigroup`.
1446		///
1447		/// Both sides are forced on evaluation.
1448		#[document_signature]
1449		///
1450		#[document_parameters("The first lazy value.", "The second lazy value.")]
1451		///
1452		#[document_returns("A new `ArcLazy` containing the combined result.")]
1453		///
1454		#[document_examples]
1455		///
1456		/// ```
1457		/// use fp_library::{
1458		/// 	functions::*,
1459		/// 	types::*,
1460		/// };
1461		///
1462		/// let a = ArcLazy::pure("Hello".to_string());
1463		/// let b = ArcLazy::pure(" World".to_string());
1464		/// let c = append(a, b);
1465		/// assert_eq!(*c.evaluate(), "Hello World");
1466		/// ```
1467		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	// --- Monoid ---
1476
1477	#[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		/// Returns the identity `RcLazy`.
1483		#[document_signature]
1484		///
1485		#[document_returns("An `RcLazy` producing the identity value of `A`.")]
1486		///
1487		#[document_examples]
1488		///
1489		/// ```
1490		/// use fp_library::{
1491		/// 	functions::*,
1492		/// 	types::*,
1493		/// };
1494		///
1495		/// let t: RcLazy<String> = empty();
1496		/// assert_eq!(*t.evaluate(), "");
1497		/// ```
1498		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		/// Returns the identity `ArcLazy`.
1509		#[document_signature]
1510		///
1511		#[document_returns("An `ArcLazy` producing the identity value of `A`.")]
1512		///
1513		#[document_examples]
1514		///
1515		/// ```
1516		/// use fp_library::{
1517		/// 	functions::*,
1518		/// 	types::*,
1519		/// };
1520		///
1521		/// let t: ArcLazy<String> = empty();
1522		/// assert_eq!(*t.evaluate(), "");
1523		/// ```
1524		fn empty() -> Self {
1525			ArcLazy::new(|| Monoid::empty())
1526		}
1527	}
1528
1529	// --- Hash ---
1530
1531	#[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		/// Forces evaluation and hashes the value.
1539		#[document_signature]
1540		#[document_type_parameters("The type of the hasher.")]
1541		///
1542		#[document_parameters("The hasher state.")]
1543		///
1544		#[document_examples]
1545		///
1546		/// ```
1547		/// use {
1548		/// 	fp_library::types::*,
1549		/// 	std::{
1550		/// 		collections::hash_map::DefaultHasher,
1551		/// 		hash::{
1552		/// 			Hash,
1553		/// 			Hasher,
1554		/// 		},
1555		/// 	},
1556		/// };
1557		///
1558		/// let lazy = RcLazy::new(|| 42);
1559		/// let mut hasher = DefaultHasher::new();
1560		/// lazy.hash(&mut hasher);
1561		/// let h1 = hasher.finish();
1562		///
1563		/// let mut hasher = DefaultHasher::new();
1564		/// 42i32.hash(&mut hasher);
1565		/// let h2 = hasher.finish();
1566		///
1567		/// assert_eq!(h1, h2);
1568		///
1569		/// let lazy = ArcLazy::new(|| 42);
1570		/// let mut hasher = DefaultHasher::new();
1571		/// lazy.hash(&mut hasher);
1572		/// let h3 = hasher.finish();
1573		///
1574		/// assert_eq!(h1, h3);
1575		/// ```
1576		fn hash<H: Hasher>(
1577			&self,
1578			state: &mut H,
1579		) {
1580			self.evaluate().hash(state)
1581		}
1582	}
1583
1584	// --- RefFoldable ---
1585
1586	#[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1587	impl<Config: LazyConfig> RefFoldable for LazyBrand<Config> {
1588		/// Maps the value to a monoid by reference and returns it.
1589		///
1590		/// Forces evaluation and maps the single contained value by reference.
1591		/// No cloning is required since the closure receives `&A` directly.
1592		#[document_signature]
1593		///
1594		#[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		///
1601		#[document_parameters("The mapping function.", "The Lazy to fold.")]
1602		///
1603		#[document_returns("The monoid value.")]
1604		#[document_examples]
1605		///
1606		/// ```
1607		/// use fp_library::{
1608		/// 	brands::*,
1609		/// 	functions::*,
1610		/// 	types::*,
1611		/// };
1612		///
1613		/// let lazy = RcLazy::new(|| 10);
1614		/// let result = explicit::fold_map::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _, _, _>(
1615		/// 	|a: &i32| a.to_string(),
1616		/// 	&lazy,
1617		/// );
1618		/// assert_eq!(result, "10");
1619		/// ```
1620		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		/// Folds the `Lazy` from the right by reference.
1631		///
1632		/// Forces evaluation and folds the single contained value by reference.
1633		#[document_signature]
1634		///
1635		#[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		///
1642		#[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		///
1648		#[document_returns("The final accumulator value.")]
1649		#[document_examples]
1650		///
1651		/// ```
1652		/// use fp_library::{
1653		/// 	brands::*,
1654		/// 	functions::*,
1655		/// 	types::*,
1656		/// };
1657		///
1658		/// let lazy = RcLazy::new(|| 10);
1659		/// let result = explicit::fold_right::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _, _, _>(
1660		/// 	|a: &i32, b| *a + b,
1661		/// 	5,
1662		/// 	&lazy,
1663		/// );
1664		/// assert_eq!(result, 15);
1665		/// ```
1666		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		/// Folds the `Lazy` from the left by reference.
1677		///
1678		/// Forces evaluation and folds the single contained value by reference.
1679		#[document_signature]
1680		///
1681		#[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		///
1688		#[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		///
1694		#[document_returns("The final accumulator value.")]
1695		#[document_examples]
1696		///
1697		/// ```
1698		/// use fp_library::{
1699		/// 	brands::*,
1700		/// 	functions::*,
1701		/// 	types::*,
1702		/// };
1703		///
1704		/// let lazy = RcLazy::new(|| 10);
1705		/// let result = explicit::fold_left::<RcFnBrand, LazyBrand<RcLazyConfig>, _, _, _, _>(
1706		/// 	|b, a: &i32| b + *a,
1707		/// 	5,
1708		/// 	&lazy,
1709		/// );
1710		/// assert_eq!(result, 15);
1711		/// ```
1712		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	// --- WithIndex ---
1724
1725	#[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1726	impl<Config: LazyConfig> WithIndex for LazyBrand<Config> {
1727		type Index = ();
1728	}
1729
1730	// --- RefFoldableWithIndex ---
1731
1732	#[document_type_parameters("The memoization configuration (determines Rc vs Arc).")]
1733	impl<Config: LazyConfig> RefFoldableWithIndex for LazyBrand<Config> {
1734		/// Maps the value to a monoid by reference with the unit index.
1735		///
1736		/// Forces evaluation and maps the single contained value by reference,
1737		/// providing `()` as the index.
1738		#[document_signature]
1739		///
1740		#[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		///
1747		#[document_parameters(
1748			"The function to apply to the index and value reference.",
1749			"The Lazy to fold."
1750		)]
1751		///
1752		#[document_returns("The monoid value.")]
1753		#[document_examples]
1754		///
1755		/// ```
1756		/// use fp_library::{
1757		/// 	brands::*,
1758		/// 	classes::ref_foldable_with_index::RefFoldableWithIndex,
1759		/// 	types::*,
1760		/// };
1761		///
1762		/// let lazy = RcLazy::new(|| 42);
1763		/// let result = <LazyBrand<RcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
1764		/// 	RcFnBrand,
1765		/// 	_,
1766		/// 	_,
1767		/// >(|_, x: &i32| x.to_string(), &lazy);
1768		/// assert_eq!(result, "42");
1769		/// ```
1770		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	// --- RefFunctorWithIndex ---
1781
1782	impl RefFunctorWithIndex for LazyBrand<RcLazyConfig> {
1783		/// Maps a function over the `Lazy` by reference with the unit index.
1784		///
1785		/// Forces evaluation and maps the single contained value by reference,
1786		/// providing `()` as the index. Returns a new `Lazy` wrapping the result.
1787		#[document_signature]
1788		///
1789		#[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		///
1795		#[document_parameters(
1796			"The function to apply to the index and value reference.",
1797			"The Lazy to map over."
1798		)]
1799		///
1800		#[document_returns("A new Lazy containing the mapped value.")]
1801		#[document_examples]
1802		///
1803		/// ```
1804		/// use fp_library::{
1805		/// 	brands::*,
1806		/// 	classes::ref_functor_with_index::RefFunctorWithIndex,
1807		/// 	types::*,
1808		/// };
1809		///
1810		/// let lazy = RcLazy::new(|| 42);
1811		/// let mapped = <LazyBrand<RcLazyConfig> as RefFunctorWithIndex>::ref_map_with_index(
1812		/// 	|_, x: &i32| x.to_string(),
1813		/// 	&lazy,
1814		/// );
1815		/// assert_eq!(*mapped.evaluate(), "42");
1816		/// ```
1817		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	// --- PartialEq ---
1826
1827	#[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		/// Compares two `Lazy` values for equality by forcing evaluation of both sides.
1835		///
1836		/// Note: This will trigger computation if either value has not yet been evaluated.
1837		#[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		///
1842		/// ```
1843		/// use fp_library::{
1844		/// 	classes::*,
1845		/// 	types::*,
1846		/// };
1847		///
1848		/// let a = RcLazy::pure(42);
1849		/// let b = RcLazy::pure(42);
1850		/// assert!(a == b);
1851		/// ```
1852		fn eq(
1853			&self,
1854			other: &Self,
1855		) -> bool {
1856			self.evaluate() == other.evaluate()
1857		}
1858	}
1859
1860	// --- PartialOrd ---
1861
1862	#[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		/// Compares two `Lazy` values for ordering by forcing evaluation of both sides.
1870		///
1871		/// Note: This will trigger computation if either value has not yet been evaluated.
1872		#[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		///
1879		/// ```
1880		/// use fp_library::{
1881		/// 	classes::*,
1882		/// 	types::*,
1883		/// };
1884		///
1885		/// let a = RcLazy::pure(1);
1886		/// let b = RcLazy::pure(2);
1887		/// assert!(a < b);
1888		/// ```
1889		fn partial_cmp(
1890			&self,
1891			other: &Self,
1892		) -> Option<std::cmp::Ordering> {
1893			self.evaluate().partial_cmp(other.evaluate())
1894		}
1895	}
1896
1897	// --- Eq ---
1898
1899	#[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	// --- Ord ---
1907
1908	#[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		/// Compares two `Lazy` values for ordering by forcing evaluation of both sides.
1916		///
1917		/// Note: This will trigger computation if either value has not yet been evaluated.
1918		#[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		///
1923		/// ```
1924		/// use fp_library::{
1925		/// 	classes::*,
1926		/// 	types::*,
1927		/// };
1928		///
1929		/// let a = RcLazy::pure(1);
1930		/// let b = RcLazy::pure(2);
1931		/// assert_eq!(a.cmp(&b), std::cmp::Ordering::Less);
1932		/// ```
1933		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		/// Formats the lazy value without evaluating it.
1952		#[document_signature]
1953		#[document_parameters("The formatter.")]
1954		#[document_returns("The formatting result.")]
1955		#[document_examples]
1956		///
1957		/// ```
1958		/// use fp_library::{
1959		/// 	classes::*,
1960		/// 	types::*,
1961		/// };
1962		/// let lazy = Lazy::<_, RcLazyConfig>::pure(42);
1963		/// assert_eq!(format!("{:?}", lazy), "Lazy(..)");
1964		/// ```
1965		fn fmt(
1966			&self,
1967			f: &mut fmt::Formatter<'_>,
1968		) -> fmt::Result {
1969			f.write_str("Lazy(..)")
1970		}
1971	}
1972
1973	// --- Fix combinators ---
1974
1975	/// Computes a fixed point for `RcLazy`.
1976	///
1977	/// Constructs a self-referential `RcLazy` where the initializer receives a clone
1978	/// of the resulting lazy cell. This enables recursive definitions where the value
1979	/// depends on the lazy cell itself.
1980	///
1981	/// # Caveats
1982	///
1983	/// **Panic on reentrant evaluation:** Forcing the self-reference inside `f` before
1984	/// the outer cell has completed initialization causes a panic, because `LazyCell`
1985	/// detects the reentrant access.
1986	#[document_signature]
1987	///
1988	#[document_type_parameters(
1989		"The lifetime of the computation.",
1990		"The type of the computed value."
1991	)]
1992	///
1993	#[document_parameters(
1994		"The function that receives a lazy self-reference and produces the value."
1995	)]
1996	///
1997	#[document_returns("A new `RcLazy` instance.")]
1998	///
1999	#[document_examples]
2000	///
2001	/// ```
2002	/// use fp_library::types::{
2003	/// 	lazy::rc_lazy_fix,
2004	/// 	*,
2005	/// };
2006	///
2007	/// let lazy = rc_lazy_fix(|_self_ref: RcLazy<i32>| 42);
2008	/// assert_eq!(*lazy.evaluate(), 42);
2009	/// ```
2010	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			// INVARIANT: cell is always set on the line after this closure is
2026			// created, and the outer RcLazy is still alive (we are inside its
2027			// evaluation), so the Weak upgrade always succeeds.
2028			#[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	/// Computes a fixed point for `ArcLazy`.
2045	///
2046	/// Constructs a self-referential `ArcLazy` where the initializer receives a clone
2047	/// of the resulting lazy cell. This enables recursive definitions where the value
2048	/// depends on the lazy cell itself.
2049	///
2050	/// # Caveats
2051	///
2052	/// **Deadlock on reentrant evaluation:** Forcing the self-reference inside `f` before
2053	/// the outer cell has completed initialization causes a deadlock, because `LazyLock`
2054	/// blocks on the lock that the current thread already holds.
2055	#[document_signature]
2056	///
2057	#[document_type_parameters(
2058		"The lifetime of the computation.",
2059		"The type of the computed value."
2060	)]
2061	///
2062	#[document_parameters(
2063		"The function that receives a lazy self-reference and produces the value."
2064	)]
2065	///
2066	#[document_returns("A new `ArcLazy` instance.")]
2067	///
2068	#[document_examples]
2069	///
2070	/// ```
2071	/// use fp_library::types::{
2072	/// 	lazy::arc_lazy_fix,
2073	/// 	*,
2074	/// };
2075	///
2076	/// let lazy = arc_lazy_fix(|_self_ref: ArcLazy<i32>| 42);
2077	/// assert_eq!(*lazy.evaluate(), 42);
2078	/// ```
2079	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			// INVARIANT: cell is always set on the line after this closure is
2096			// created, and the outer ArcLazy is still alive (we are inside its
2097			// evaluation), so the Weak upgrade always succeeds.
2098			#[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	/// Tests that `Lazy` caches the result of the computation.
2139	///
2140	/// Verifies that the initializer is called only once.
2141	#[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	/// Tests that `Lazy` shares the cache across clones.
2158	///
2159	/// Verifies that clones see the same value and don't recompute.
2160	#[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	/// Tests thread safety of `ArcLazy`.
2177	///
2178	/// Verifies that `ArcLazy` can be shared across threads and computes only once.
2179	#[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	/// Tests creation from `Thunk`.
2212	///
2213	/// Verifies `From<Thunk>` works correctly.
2214	#[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	/// Tests creation from `Trampoline`.
2222	///
2223	/// Verifies `From<Trampoline>` works correctly.
2224	#[test]
2225	fn test_memo_from_task() {
2226		// Trampoline requires 'static due to type erasure via Box<dyn Any>
2227		let task = Trampoline::pure(42);
2228		let memo = RcLazy::from(task);
2229		assert_eq!(*memo.evaluate(), 42);
2230	}
2231
2232	/// Tests conversion from `RcLazy` to `ArcLazy`.
2233	///
2234	/// Verifies `From<RcLazy>` for `ArcLazy` works correctly.
2235	#[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	/// Tests conversion from `ArcLazy` to `RcLazy`.
2243	///
2244	/// Verifies `From<ArcLazy>` for `RcLazy` works correctly.
2245	#[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	/// Tests that `RcLazy` to `ArcLazy` conversion eagerly evaluates.
2253	///
2254	/// Verifies that the source is evaluated during conversion, not deferred.
2255	#[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		// Conversion should have forced evaluation.
2267		assert_eq!(*counter.borrow(), 1);
2268		assert_eq!(*arc.evaluate(), 99);
2269		// No additional evaluation.
2270		assert_eq!(*counter.borrow(), 1);
2271	}
2272
2273	/// Tests that `ArcLazy` to `RcLazy` conversion eagerly evaluates.
2274	///
2275	/// Verifies that the source is evaluated during conversion, not deferred.
2276	#[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		// Conversion should have forced evaluation.
2293		assert_eq!(counter.load(Ordering::SeqCst), 1);
2294		assert_eq!(*rc.evaluate(), 77);
2295		// No additional evaluation.
2296		assert_eq!(counter.load(Ordering::SeqCst), 1);
2297	}
2298
2299	/// Property: RcLazy to ArcLazy round-trip preserves values.
2300	#[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	/// Property: ArcLazy to RcLazy round-trip preserves values.
2308	#[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	/// Tests Defer implementation.
2316	#[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	/// Tests SendDefer implementation.
2325	#[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	/// Tests `RcLazy::pure`.
2334	///
2335	/// Verifies that `pure` creates a lazy value from a pre-computed value.
2336	#[test]
2337	fn test_rc_lazy_pure() {
2338		let lazy = RcLazy::pure(42);
2339		assert_eq!(*lazy.evaluate(), 42);
2340
2341		// Verify it's still lazy (shares cache)
2342		let shared = lazy.clone();
2343		assert_eq!(*shared.evaluate(), 42);
2344	}
2345
2346	/// Tests `ArcLazy::pure`.
2347	///
2348	/// Verifies that `pure` creates a thread-safe lazy value from a pre-computed value.
2349	#[test]
2350	fn test_arc_lazy_pure() {
2351		let lazy = ArcLazy::pure(42);
2352		assert_eq!(*lazy.evaluate(), 42);
2353
2354		// Verify it's still lazy (shares cache)
2355		let shared = lazy.clone();
2356		assert_eq!(*shared.evaluate(), 42);
2357	}
2358
2359	/// Tests `ArcLazy::pure` with thread safety.
2360	///
2361	/// Verifies that `pure` works across threads.
2362	#[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	// Memoization Properties
2382
2383	/// Property: getting a memoized value twice returns the same result (Rc).
2384	#[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	/// Property: getting a memoized value twice returns the same result (Arc).
2393	#[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	// Clone Equivalence Properties
2402
2403	/// Property: cloning an RcLazy shares state.
2404	#[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	/// Property: cloning an ArcLazy shares state.
2415	#[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	/// Property: getting original then clone gives same result.
2426	#[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	// Determinism Properties
2439
2440	/// Property: lazy computation is deterministic.
2441	#[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	// --- Tests for ArcLazy::ref_map ---
2453
2454	/// Tests `ArcLazy::ref_map`.
2455	///
2456	/// Verifies that `ref_map` applies a function to the memoized value by reference.
2457	#[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	/// Tests `ArcLazy::ref_map` thread safety.
2465	///
2466	/// Verifies that the mapped value can be shared across threads.
2467	#[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	// --- Tests for Semigroup ---
2488
2489	/// Tests the `Semigroup` implementation for `RcLazy`.
2490	///
2491	/// Verifies that `append` correctly combines two lazy values.
2492	#[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	/// Tests the `Semigroup` implementation for `ArcLazy`.
2503	///
2504	/// Verifies that `append` correctly combines two thread-safe lazy values.
2505	#[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	/// Tests `Semigroup` associativity for `RcLazy`.
2516	#[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	// --- Tests for Monoid ---
2531
2532	/// Tests the `Monoid` implementation for `RcLazy`.
2533	///
2534	/// Verifies that `empty` returns the identity element.
2535	#[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	/// Tests the `Monoid` implementation for `ArcLazy`.
2544	///
2545	/// Verifies that `empty` returns the identity element.
2546	#[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	/// Tests `Monoid` identity laws for `RcLazy`.
2555	#[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		// Left identity: append(empty(), a) == a
2565		let left: RcLazy<String> = append(empty(), a.clone());
2566		assert_eq!(*left.evaluate(), *a.evaluate());
2567
2568		// Right identity: append(a, empty()) == a
2569		let right: RcLazy<String> = append(a.clone(), empty());
2570		assert_eq!(*right.evaluate(), *a.evaluate());
2571	}
2572
2573	// --- Tests for RefFoldable ---
2574
2575	/// Tests `fold_right` for `RcLazy`.
2576	#[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	/// Tests `fold_left` for `RcLazy`.
2593	#[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	/// Tests `fold_map` for `RcLazy`.
2610	#[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	// --- Tests for PartialEq ---
2627
2628	/// Tests `PartialEq` for `RcLazy`.
2629	///
2630	/// Verifies that equality comparison forces evaluation.
2631	#[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	/// Tests `PartialEq` for `ArcLazy`.
2642	///
2643	/// Verifies that equality comparison forces evaluation.
2644	#[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	// --- Tests for PartialOrd ---
2655
2656	/// Tests `PartialOrd` for `RcLazy`.
2657	///
2658	/// Verifies that ordering comparison forces evaluation.
2659	#[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	/// Tests `PartialOrd` for `ArcLazy`.
2672	///
2673	/// Verifies that ordering comparison forces evaluation.
2674	#[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	// fix combinator tests
2684
2685	/// Tests that `rc_lazy_fix` produces the correct value when
2686	/// the function ignores the self-reference.
2687	#[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	/// Tests that `rc_lazy_fix` sets up the `OnceCell` before evaluation.
2694	///
2695	/// The closure inside the resulting `RcLazy` reads from the cell, so the
2696	/// cell must be populated by the time evaluation happens.
2697	#[test]
2698	fn test_rc_lazy_fix_cell_initialized() {
2699		let fixed = rc_lazy_fix(|_self_ref: RcLazy<String>| String::from("initialized"));
2700		// If the cell were not initialized, this would panic.
2701		assert_eq!(fixed.evaluate().as_str(), "initialized");
2702	}
2703
2704	/// Tests that `rc_lazy_fix` correctly threads the self-reference.
2705	///
2706	/// The function `f` receives a lazy self-reference. When `f` does not
2707	/// force it (avoiding infinite recursion), we can verify the plumbing
2708	/// by having `f` return a value derived from a closure that captures
2709	/// (but does not evaluate) the self-reference.
2710	#[test]
2711	fn test_rc_lazy_fix_self_reference_plumbing() {
2712		// f returns a value without forcing the self-reference.
2713		let fixed = rc_lazy_fix(|_self_ref: RcLazy<i32>| 7);
2714		assert_eq!(*fixed.evaluate(), 7);
2715	}
2716
2717	/// Tests that `rc_lazy_fix` memoizes the result.
2718	///
2719	/// Multiple evaluations should return the same cached value.
2720	#[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		// Second evaluation should use cached value.
2733		assert_eq!(*fixed.evaluate(), 100);
2734		assert_eq!(*counter.borrow(), 1);
2735	}
2736
2737	/// Tests that `rc_lazy_fix` works with cloned results sharing the cache.
2738	#[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	/// Tests that `arc_lazy_fix` produces the correct value when
2747	/// the function ignores the self-reference.
2748	#[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	/// Tests that `arc_lazy_fix` sets up the `OnceLock` before evaluation.
2755	#[test]
2756	fn test_arc_lazy_fix_cell_initialized() {
2757		let fixed = arc_lazy_fix(|_self_ref: ArcLazy<String>| String::from("initialized"));
2758		// If the lock were not initialized, this would panic.
2759		assert_eq!(fixed.evaluate().as_str(), "initialized");
2760	}
2761
2762	/// Tests that `arc_lazy_fix` correctly threads the self-reference.
2763	#[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	/// Tests that `arc_lazy_fix` memoizes the result.
2770	#[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		// Second evaluation should use cached value.
2788		assert_eq!(*fixed.evaluate(), 100);
2789		assert_eq!(counter.load(Ordering::SeqCst), 1);
2790	}
2791
2792	// --- ArcLazy RefFoldable tests ---
2793
2794	/// Tests `fold_right` on `ArcLazy`.
2795	#[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	/// Tests `fold_left` on `ArcLazy`.
2812	#[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	/// Tests `fold_map` on `ArcLazy`.
2829	#[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	/// Property: ArcLazy fold_right is consistent with RcLazy fold_right.
2845	#[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	// --- SendRefFunctor (ArcLazy ref_map) law tests ---
2868
2869	/// Property: ArcLazy ref_map identity law.
2870	///
2871	/// ref_map(|x| x.clone(), fa) should produce the same value as fa.
2872	#[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	/// Property: ArcLazy ref_map composition law.
2880	///
2881	/// ref_map(g . f, fa) == ref_map(g, ref_map(f, fa)).
2882	#[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	/// Property: ArcLazy ref_map preserves memoization.
2897	#[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	// --- rc_lazy_fix / arc_lazy_fix tests ---
2907
2908	/// Tests `rc_lazy_fix` with a self-referential computation.
2909	#[test]
2910	fn test_rc_lazy_fix_self_reference() {
2911		let lazy = rc_lazy_fix(|self_ref: RcLazy<Vec<i32>>| {
2912			// The self-reference can be evaluated to get the same value.
2913			let _ = self_ref; // The self-ref is available but evaluating it here would recurse.
2914			vec![1, 2, 3]
2915		});
2916		assert_eq!(*lazy.evaluate(), vec![1, 2, 3]);
2917	}
2918
2919	/// Tests `rc_lazy_fix` where `f` uses the self-reference after initial evaluation.
2920	#[test]
2921	fn test_rc_lazy_fix_uses_self_ref() {
2922		// Create a lazy value that, when evaluated, stores its own length.
2923		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			// We cannot evaluate self_ref during construction (would deadlock),
2928			// but we can capture it for later use in a derived value.
2929			let _ = self_ref;
2930			42
2931		});
2932		assert_eq!(*lazy.evaluate(), 42);
2933		assert_eq!(*counter.borrow(), 1);
2934		// Verify memoization: second evaluate does not re-run.
2935		assert_eq!(*lazy.evaluate(), 42);
2936		assert_eq!(*counter.borrow(), 1);
2937	}
2938
2939	/// Tests `arc_lazy_fix` with a self-referential computation.
2940	#[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	/// Tests `arc_lazy_fix` where `f` uses the self-reference after initial evaluation.
2950	#[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		// Verify memoization: second evaluate does not re-run.
2967		assert_eq!(*lazy.evaluate(), 42);
2968		assert_eq!(counter.load(Ordering::SeqCst), 1);
2969	}
2970
2971	/// Tests `arc_lazy_fix` is thread-safe.
2972	#[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	/// Property: `rc_lazy_fix` with a constant function produces that constant.
2995	#[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	/// Property: `arc_lazy_fix` with a constant function produces that constant.
3002	#[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 Law Tests
3009
3010	// RefFunctor Laws
3011
3012	/// RefFunctor identity: `ref_map(|v| v.clone(), fa)` evaluates to the same value as `fa`.
3013	#[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	/// RefFunctor composition: `ref_map(|v| f(&g(v)), fa) == ref_map(f, ref_map(g, fa))`.
3020	#[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	// Deferrable Laws
3031
3032	/// Deferrable transparency: `defer(|| pure(x))` evaluates to the same value as `pure(x)`.
3033	#[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	// Semigroup Laws
3041
3042	/// Semigroup associativity for `RcLazy`: `append(append(a, b), c) == append(a, append(b, c))`.
3043	#[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	/// Semigroup associativity for `ArcLazy`: `append(append(a, b), c) == append(a, append(b, c))`.
3063	#[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	// Monoid Laws
3083
3084	/// Monoid left identity for `RcLazy`: `append(empty(), a) == a`.
3085	#[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	/// Monoid right identity for `RcLazy`: `append(a, empty()) == a`.
3098	#[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	/// Monoid left identity for `ArcLazy`: `append(empty(), a) == a`.
3111	#[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	/// Monoid right identity for `ArcLazy`: `append(a, empty()) == a`.
3124	#[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	// --- Tests for LazyConfig::PointerBrand ---
3137
3138	/// Tests that `RcLazyConfig::PointerBrand` is `RcBrand`.
3139	#[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	/// Tests that `ArcLazyConfig::PointerBrand` is `ArcBrand`.
3146	#[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	// SC-2: Panic poisoning test for Lazy
3153
3154	/// Tests that a panicking initializer poisons the RcLazy.
3155	///
3156	/// Verifies that subsequent evaluate calls also panic after
3157	/// the initializer panics.
3158	#[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	/// Tests `rc_lazy_fix` where the self-reference is shared with a derived lazy.
3178	#[test]
3179	fn test_rc_lazy_fix_shared_self_ref() {
3180		let lazy = rc_lazy_fix(|self_ref: RcLazy<i32>| {
3181			// Store the self-ref for later verification that it shares the same cache.
3182			let _captured = self_ref.clone();
3183			100
3184		});
3185		assert_eq!(*lazy.evaluate(), 100);
3186		// Clone should share the same cache.
3187		let cloned = lazy.clone();
3188		assert_eq!(*cloned.evaluate(), 100);
3189	}
3190
3191	// -- Knot-tying tests: self-reference is actually used after initialization --
3192
3193	/// Tests that `rc_lazy_fix` ties the knot: the self-reference captured
3194	/// inside the closure points to the same `Rc` cell as the returned lazy.
3195	/// After evaluation, querying the self-reference yields the cached value.
3196	#[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			// Store the self-reference externally so we can inspect it later.
3202			*stash_clone.borrow_mut() = Some(self_ref);
3203			42
3204		});
3205		// Force evaluation.
3206		assert_eq!(*lazy.evaluate(), 42);
3207		// Retrieve the stashed self-reference.
3208		let self_ref = stash.borrow().clone().unwrap();
3209		// The self-reference must point to the same underlying Rc cell.
3210		assert!(Rc::ptr_eq(&lazy.0, &self_ref.0));
3211		// Evaluating the self-reference yields the same cached value.
3212		assert_eq!(*self_ref.evaluate(), 42);
3213	}
3214
3215	/// Tests that `rc_lazy_fix` knot-tying produces a shared cache: the
3216	/// initializer runs exactly once even when accessed through the self-reference.
3217	#[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		// Force evaluation through the outer lazy.
3230		assert_eq!(*lazy.evaluate(), 100);
3231		assert_eq!(*counter.borrow(), 1);
3232		// Force evaluation through the stashed self-reference.
3233		let self_ref = stash.borrow().clone().unwrap();
3234		assert_eq!(*self_ref.evaluate(), 100);
3235		// Counter must still be 1: the initializer was not re-run.
3236		assert_eq!(*counter.borrow(), 1);
3237	}
3238
3239	/// Tests that `rc_lazy_fix` panics on reentrant evaluation.
3240	///
3241	/// Forcing the self-reference inside the initializer triggers a
3242	/// `LazyCell` reentrant-init panic.
3243	#[test]
3244	#[should_panic]
3245	fn test_rc_lazy_fix_reentrant_panics() {
3246		let lazy = rc_lazy_fix(|self_ref: RcLazy<i32>| {
3247			// Forcing the self-reference during initialization is reentrant
3248			// and must panic.
3249			*self_ref.evaluate() + 1
3250		});
3251		let _ = lazy.evaluate();
3252	}
3253
3254	/// Tests that `arc_lazy_fix` ties the knot: the self-reference captured
3255	/// inside the closure points to the same `Arc` cell as the returned lazy.
3256	#[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		// The self-reference must point to the same underlying Arc cell.
3269		assert!(Arc::ptr_eq(&lazy.0, &self_ref.0));
3270		// Evaluating the self-reference yields the same cached value.
3271		assert_eq!(*self_ref.evaluate(), 42);
3272	}
3273
3274	/// Tests that `arc_lazy_fix` knot-tying produces a shared cache: the
3275	/// initializer runs exactly once even when accessed through the self-reference.
3276	#[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		// Access through the stashed self-reference.
3299		let self_ref = stash.lock().unwrap().clone().unwrap();
3300		assert_eq!(*self_ref.evaluate(), 100);
3301		// Counter must still be 1: the initializer was not re-run.
3302		assert_eq!(counter.load(Ordering::SeqCst), 1);
3303	}
3304
3305	/// Tests that `arc_lazy_fix` knot-tying works across threads: the
3306	/// self-reference can be evaluated from a different thread and still
3307	/// returns the cached value.
3308	#[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		// Evaluate the self-reference from a spawned thread.
3324		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		// Manual expansion of what m_do!(ref ...) should generate
3331		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		// Multi-bind in ref mode: each bind receives &A, but inner closures
3380		// can't capture references from outer binds (lifetime issue). Use
3381		// let bindings to clone the referenced value for use in later binds.
3382		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		// a_do uses lift2, which doesn't have the FnOnce issue since
3426		// applicative binds are independent (no nesting).
3427		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}