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.
4
5use crate::{
6	Apply,
7	brands::LazyBrand,
8	classes::{Deferrable, RefFunctor, SendDeferrable},
9	impl_kind,
10	kinds::*,
11	types::{Thunk, Trampoline},
12};
13use fp_macros::{doc_params, doc_type_params, hm_signature};
14use std::{
15	cell::LazyCell,
16	rc::Rc,
17	sync::{Arc, LazyLock},
18};
19
20/// Configuration for memoization strategy.
21///
22/// This trait bundles together the choices for:
23/// - Pointer type ([`Rc`] vs [`Arc`]).
24/// - Lazy cell type ([`LazyCell`] vs [`LazyLock`]).
25///
26/// # Note on Standard Library Usage
27///
28/// This design leverages Rust 1.80's `LazyCell` and `LazyLock` types,
29/// which encapsulate the initialization-once logic.
30pub trait LazyConfig: 'static {
31	/// The lazy cell type for infallible memoization.
32	type Lazy<'a, A: 'a>: Clone;
33
34	/// The lazy cell type for fallible memoization.
35	type TryLazy<'a, A: 'a, E: 'a>: Clone;
36
37	/// The type of the initializer thunk.
38	type Thunk<'a, A: 'a>: ?Sized;
39
40	/// The type of the fallible initializer thunk.
41	type TryThunk<'a, A: 'a, E: 'a>: ?Sized;
42
43	/// Creates a new lazy cell from an initializer.
44	///
45	/// ### Type Signature
46	///
47	#[hm_signature]
48	///
49	/// ### Type Parameters
50	///
51	#[doc_type_params("The lifetime of the computation.", "The type of the value.")]
52	///
53	/// ### Parameters
54	///
55	#[doc_params("The initializer thunk.")]
56	///
57	/// ### Returns
58	///
59	/// A new lazy cell.
60	///
61	/// ### Examples
62	///
63	/// ```
64	/// use fp_library::types::*;
65	///
66	/// let lazy = RcLazyConfig::lazy_new(Box::new(|| 42));
67	/// assert_eq!(*RcLazyConfig::evaluate(&lazy), 42);
68	/// ```
69	fn lazy_new<'a, A: 'a>(f: Box<Self::Thunk<'a, A>>) -> Self::Lazy<'a, A>;
70
71	/// Creates a new fallible lazy cell from an initializer.
72	///
73	/// ### Type Signature
74	///
75	#[hm_signature]
76	///
77	/// ### Type Parameters
78	///
79	#[doc_type_params(
80		"The lifetime of the computation.",
81		"The type of the value.",
82		"The type of the error."
83	)]
84	///
85	/// ### Parameters
86	///
87	#[doc_params("The initializer thunk.")]
88	///
89	/// ### Returns
90	///
91	/// A new fallible lazy cell.
92	///
93	/// ### Examples
94	///
95	/// ```
96	/// use fp_library::types::*;
97	///
98	/// let lazy = RcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
99	/// assert_eq!(RcLazyConfig::try_evaluate(&lazy), Ok(&42));
100	/// ```
101	fn try_lazy_new<'a, A: 'a, E: 'a>(f: Box<Self::TryThunk<'a, A, E>>) -> Self::TryLazy<'a, A, E>;
102
103	/// Forces evaluation and returns a reference.
104	///
105	/// ### Type Signature
106	///
107	#[hm_signature]
108	///
109	/// ### Type Parameters
110	///
111	#[doc_type_params(
112		"The lifetime of the computation.",
113		"The lifetime of the reference.",
114		"The type of the value."
115	)]
116	///
117	/// ### Parameters
118	///
119	#[doc_params("The lazy cell to evaluate.")]
120	///
121	/// ### Returns
122	///
123	/// A reference to the value.
124	///
125	/// ### Examples
126	///
127	/// ```
128	/// use fp_library::types::*;
129	///
130	/// let lazy = RcLazyConfig::lazy_new(Box::new(|| 42));
131	/// assert_eq!(*RcLazyConfig::evaluate(&lazy), 42);
132	/// ```
133	fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A;
134
135	/// Forces evaluation and returns a reference to the result.
136	///
137	/// ### Type Signature
138	///
139	#[hm_signature]
140	///
141	/// ### Type Parameters
142	///
143	#[doc_type_params(
144		"The lifetime of the computation.",
145		"The lifetime of the reference.",
146		"The type of the value.",
147		"The type of the error."
148	)]
149	///
150	/// ### Parameters
151	///
152	#[doc_params("The fallible lazy cell to evaluate.")]
153	///
154	/// ### Returns
155	///
156	/// A result containing a reference to the value or error.
157	///
158	/// ### Examples
159	///
160	/// ```
161	/// use fp_library::types::*;
162	///
163	/// let lazy = RcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
164	/// assert_eq!(RcLazyConfig::try_evaluate(&lazy), Ok(&42));
165	/// ```
166	fn try_evaluate<'a, 'b, A: 'a, E: 'a>(
167		lazy: &'b Self::TryLazy<'a, A, E>
168	) -> Result<&'b A, &'b E>;
169}
170
171/// Single-threaded memoization using [`Rc<LazyCell>`].
172///
173/// Not thread-safe. Use [`ArcLazyConfig`] for multi-threaded contexts.
174pub struct RcLazyConfig;
175
176impl LazyConfig for RcLazyConfig {
177	type Lazy<'a, A: 'a> = Rc<LazyCell<A, Box<dyn FnOnce() -> A + 'a>>>;
178	type TryLazy<'a, A: 'a, E: 'a> =
179		Rc<LazyCell<Result<A, E>, Box<dyn FnOnce() -> Result<A, E> + 'a>>>;
180	type Thunk<'a, A: 'a> = dyn FnOnce() -> A + 'a;
181	type TryThunk<'a, A: 'a, E: 'a> = dyn FnOnce() -> Result<A, E> + 'a;
182
183	/// Creates a new lazy cell from an initializer.
184	///
185	/// ### Type Signature
186	///
187	#[hm_signature]
188	///
189	/// ### Type Parameters
190	///
191	#[doc_type_params("The lifetime of the computation.", "The type of the value.")]
192	///
193	/// ### Parameters
194	///
195	#[doc_params("The initializer thunk.")]
196	///
197	/// ### Returns
198	///
199	/// A new lazy cell.
200	///
201	/// ### Examples
202	///
203	/// ```
204	/// use fp_library::types::*;
205	///
206	/// let lazy = RcLazyConfig::lazy_new(Box::new(|| 42));
207	/// assert_eq!(*RcLazyConfig::evaluate(&lazy), 42);
208	/// ```
209	fn lazy_new<'a, A: 'a>(f: Box<Self::Thunk<'a, A>>) -> Self::Lazy<'a, A> {
210		Rc::new(LazyCell::new(f))
211	}
212
213	/// Creates a new fallible lazy cell from an initializer.
214	///
215	/// ### Type Signature
216	///
217	#[hm_signature]
218	///
219	/// ### Type Parameters
220	///
221	#[doc_type_params(
222		"The lifetime of the computation.",
223		"The type of the value.",
224		"The type of the error."
225	)]
226	///
227	/// ### Parameters
228	///
229	#[doc_params("The initializer thunk.")]
230	///
231	/// ### Returns
232	///
233	/// A new fallible lazy cell.
234	///
235	/// ### Examples
236	///
237	/// ```
238	/// use fp_library::types::*;
239	///
240	/// let lazy = RcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
241	/// assert_eq!(RcLazyConfig::try_evaluate(&lazy), Ok(&42));
242	/// ```
243	fn try_lazy_new<'a, A: 'a, E: 'a>(f: Box<Self::TryThunk<'a, A, E>>) -> Self::TryLazy<'a, A, E> {
244		Rc::new(LazyCell::new(f))
245	}
246
247	/// Forces evaluation and returns a reference.
248	///
249	/// ### Type Signature
250	///
251	#[hm_signature]
252	///
253	/// ### Type Parameters
254	///
255	#[doc_type_params(
256		"The lifetime of the computation.",
257		"The lifetime of the reference.",
258		"The type of the value."
259	)]
260	///
261	/// ### Parameters
262	///
263	#[doc_params("The lazy cell to evaluate.")]
264	///
265	/// ### Returns
266	///
267	/// A reference to the value.
268	///
269	/// ### Examples
270	///
271	/// ```
272	/// use fp_library::types::*;
273	///
274	/// let lazy = RcLazyConfig::lazy_new(Box::new(|| 42));
275	/// assert_eq!(*RcLazyConfig::evaluate(&lazy), 42);
276	/// ```
277	fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
278		LazyCell::force(lazy)
279	}
280
281	/// Forces evaluation and returns a reference to the result.
282	///
283	/// ### Type Signature
284	///
285	#[hm_signature]
286	///
287	/// ### Type Parameters
288	///
289	#[doc_type_params(
290		"The lifetime of the computation.",
291		"The lifetime of the reference.",
292		"The type of the value.",
293		"The type of the error."
294	)]
295	///
296	/// ### Parameters
297	///
298	#[doc_params("The fallible lazy cell to evaluate.")]
299	///
300	/// ### Returns
301	///
302	/// A result containing a reference to the value or error.
303	///
304	/// ### Examples
305	///
306	/// ```
307	/// use fp_library::types::*;
308	///
309	/// let lazy = RcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
310	/// assert_eq!(RcLazyConfig::try_evaluate(&lazy), Ok(&42));
311	/// ```
312	fn try_evaluate<'a, 'b, A: 'a, E: 'a>(
313		lazy: &'b Self::TryLazy<'a, A, E>
314	) -> Result<&'b A, &'b E> {
315		LazyCell::force(lazy).as_ref()
316	}
317}
318
319/// Thread-safe memoization using [`Arc<LazyLock>`].
320///
321/// Requires `A: Send + Sync` for the value type.
322pub struct ArcLazyConfig;
323
324impl LazyConfig for ArcLazyConfig {
325	type Lazy<'a, A: 'a> = Arc<LazyLock<A, Box<dyn FnOnce() -> A + Send + 'a>>>;
326	type TryLazy<'a, A: 'a, E: 'a> =
327		Arc<LazyLock<Result<A, E>, Box<dyn FnOnce() -> Result<A, E> + Send + 'a>>>;
328	type Thunk<'a, A: 'a> = dyn FnOnce() -> A + Send + 'a;
329	type TryThunk<'a, A: 'a, E: 'a> = dyn FnOnce() -> Result<A, E> + Send + 'a;
330
331	/// Creates a new lazy cell from an initializer.
332	///
333	/// ### Type Signature
334	///
335	#[hm_signature]
336	///
337	/// ### Type Parameters
338	///
339	#[doc_type_params("The lifetime of the computation.", "The type of the value.")]
340	///
341	/// ### Parameters
342	///
343	#[doc_params("The initializer thunk.")]
344	///
345	/// ### Returns
346	///
347	/// A new lazy cell.
348	///
349	/// ### Examples
350	///
351	/// ```
352	/// use fp_library::types::*;
353	///
354	/// let lazy = ArcLazyConfig::lazy_new(Box::new(|| 42));
355	/// assert_eq!(*ArcLazyConfig::evaluate(&lazy), 42);
356	/// ```
357	fn lazy_new<'a, A: 'a>(f: Box<Self::Thunk<'a, A>>) -> Self::Lazy<'a, A> {
358		Arc::new(LazyLock::new(f))
359	}
360
361	/// Creates a new fallible lazy cell from an initializer.
362	///
363	/// ### Type Signature
364	///
365	#[hm_signature]
366	///
367	/// ### Type Parameters
368	///
369	#[doc_type_params(
370		"The lifetime of the computation.",
371		"The type of the value.",
372		"The type of the error."
373	)]
374	///
375	/// ### Parameters
376	///
377	#[doc_params("The initializer thunk.")]
378	///
379	/// ### Returns
380	///
381	/// A new fallible lazy cell.
382	///
383	/// ### Examples
384	///
385	/// ```
386	/// use fp_library::types::*;
387	///
388	/// let lazy = ArcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
389	/// assert_eq!(ArcLazyConfig::try_evaluate(&lazy), Ok(&42));
390	/// ```
391	fn try_lazy_new<'a, A: 'a, E: 'a>(f: Box<Self::TryThunk<'a, A, E>>) -> Self::TryLazy<'a, A, E> {
392		Arc::new(LazyLock::new(f))
393	}
394
395	/// Forces evaluation and returns a reference.
396	///
397	/// ### Type Signature
398	///
399	#[hm_signature]
400	///
401	/// ### Type Parameters
402	///
403	#[doc_type_params(
404		"The lifetime of the computation.",
405		"The lifetime of the reference.",
406		"The type of the value."
407	)]
408	///
409	/// ### Parameters
410	///
411	#[doc_params("The lazy cell to evaluate.")]
412	///
413	/// ### Returns
414	///
415	/// A reference to the value.
416	///
417	/// ### Examples
418	///
419	/// ```
420	/// use fp_library::types::*;
421	///
422	/// let lazy = ArcLazyConfig::lazy_new(Box::new(|| 42));
423	/// assert_eq!(*ArcLazyConfig::evaluate(&lazy), 42);
424	/// ```
425	fn evaluate<'a, 'b, A: 'a>(lazy: &'b Self::Lazy<'a, A>) -> &'b A {
426		LazyLock::force(lazy)
427	}
428
429	/// Forces evaluation and returns a reference to the result.
430	///
431	/// ### Type Signature
432	///
433	#[hm_signature]
434	///
435	/// ### Type Parameters
436	///
437	#[doc_type_params(
438		"The lifetime of the computation.",
439		"The lifetime of the reference.",
440		"The type of the value.",
441		"The type of the error."
442	)]
443	///
444	/// ### Parameters
445	///
446	#[doc_params("The fallible lazy cell to evaluate.")]
447	///
448	/// ### Returns
449	///
450	/// A result containing a reference to the value or error.
451	///
452	/// ### Examples
453	///
454	/// ```
455	/// use fp_library::types::*;
456	///
457	/// let lazy = ArcLazyConfig::try_lazy_new(Box::new(|| Ok::<i32, ()>(42)));
458	/// assert_eq!(ArcLazyConfig::try_evaluate(&lazy), Ok(&42));
459	/// ```
460	fn try_evaluate<'a, 'b, A: 'a, E: 'a>(
461		lazy: &'b Self::TryLazy<'a, A, E>
462	) -> Result<&'b A, &'b E> {
463		LazyLock::force(lazy).as_ref()
464	}
465}
466
467/// A lazily-computed, memoized value with shared semantics.
468///
469/// The computation runs at most once; subsequent accesses return the cached value.
470/// Cloning a `Lazy` shares the underlying cache - all clones see the same value.
471///
472/// ### Type Parameters
473///
474/// * `A`: The type of the computed value.
475/// * `Config`: The memoization configuration (determines Rc vs Arc).
476///
477/// ### Fields
478///
479/// * `0`: The internal lazy cell.
480///
481/// ### Examples
482///
483/// ```
484/// use fp_library::types::*;
485///
486/// let memo = Lazy::<_, RcLazyConfig>::new(|| 5);
487/// let shared = memo.clone();
488///
489/// // First force computes and caches:
490/// let value = memo.evaluate();
491///
492/// // Second force returns cached value (shared sees same result):
493/// assert_eq!(shared.evaluate(), value);
494/// ```
495pub struct Lazy<'a, A, Config: LazyConfig = RcLazyConfig>(pub(crate) Config::Lazy<'a, A>)
496where
497	A: 'a;
498
499impl<'a, A, Config: LazyConfig> Clone for Lazy<'a, A, Config>
500where
501	A: 'a,
502{
503	fn clone(&self) -> Self {
504		Self(self.0.clone())
505	}
506}
507
508impl<'a, A, Config: LazyConfig> Lazy<'a, A, Config>
509where
510	A: 'a,
511{
512	/// Gets the memoized value, computing on first access.
513	///
514	/// ### Type Signature
515	///
516	#[hm_signature]
517	///
518	/// ### Returns
519	///
520	/// A reference to the memoized value.
521	///
522	/// ### Examples
523	///
524	/// ```
525	/// use fp_library::types::*;
526	///
527	/// let memo = Lazy::<_, RcLazyConfig>::new(|| 42);
528	/// assert_eq!(*memo.evaluate(), 42);
529	/// ```
530	pub fn evaluate(&self) -> &A {
531		Config::evaluate(&self.0)
532	}
533}
534
535impl<'a, A> Lazy<'a, A, RcLazyConfig>
536where
537	A: 'a,
538{
539	/// Creates a new Lazy that will run `f` on first access.
540	///
541	/// ### Type Signature
542	///
543	#[hm_signature]
544	///
545	/// ### Type Parameters
546	///
547	#[doc_type_params("The type of the initializer closure.")]
548	///
549	/// ### Parameters
550	///
551	#[doc_params("The closure that produces the value.")]
552	///
553	/// ### Returns
554	///
555	/// A new `Lazy` instance.
556	///
557	/// ### Examples
558	///
559	/// ```
560	/// use fp_library::types::*;
561	///
562	/// let memo = Lazy::<_, RcLazyConfig>::new(|| 42);
563	/// assert_eq!(*memo.evaluate(), 42);
564	/// ```
565	pub fn new<F>(f: F) -> Self
566	where
567		F: FnOnce() -> A + 'a,
568	{
569		Lazy(RcLazyConfig::lazy_new(Box::new(f)))
570	}
571
572	/// Creates a `Lazy` from an already-computed value.
573	///
574	/// The value is immediately available without any computation.
575	///
576	/// ### Type Signature
577	///
578	#[hm_signature]
579	///
580	/// ### Parameters
581	///
582	#[doc_params("The pre-computed value to wrap.")]
583	///
584	/// ### Returns
585	///
586	/// A new `Lazy` instance containing the value.
587	///
588	/// ### Examples
589	///
590	/// ```
591	/// use fp_library::types::*;
592	///
593	/// let lazy = Lazy::<_, RcLazyConfig>::pure(42);
594	/// assert_eq!(*lazy.evaluate(), 42);
595	/// ```
596	pub fn pure(a: A) -> Self {
597		Lazy(RcLazyConfig::lazy_new(Box::new(move || a)))
598	}
599}
600
601impl<'a, A> From<Thunk<'a, A>> for Lazy<'a, A, RcLazyConfig> {
602	fn from(eval: Thunk<'a, A>) -> Self {
603		Self::new(move || eval.evaluate())
604	}
605}
606
607impl<'a, A> From<Trampoline<A>> for Lazy<'a, A, RcLazyConfig>
608where
609	A: Send,
610{
611	fn from(task: Trampoline<A>) -> Self {
612		Self::new(move || task.evaluate())
613	}
614}
615
616impl<'a, A> Lazy<'a, A, ArcLazyConfig>
617where
618	A: 'a,
619{
620	/// Creates a new Lazy that will run `f` on first access.
621	///
622	/// ### Type Signature
623	///
624	#[hm_signature]
625	///
626	/// ### Type Parameters
627	///
628	#[doc_type_params("The type of the initializer closure.")]
629	///
630	/// ### Parameters
631	///
632	#[doc_params("The closure that produces the value.")]
633	///
634	/// ### Returns
635	///
636	/// A new `Lazy` instance.
637	///
638	/// ### Examples
639	///
640	/// ```
641	/// use fp_library::types::*;
642	///
643	/// let lazy = Lazy::<_, ArcLazyConfig>::new(|| 42);
644	/// assert_eq!(*lazy.evaluate(), 42);
645	/// ```
646	pub fn new<F>(f: F) -> Self
647	where
648		F: FnOnce() -> A + Send + 'a,
649	{
650		Lazy(ArcLazyConfig::lazy_new(Box::new(f)))
651	}
652
653	/// Creates a `Lazy` from an already-computed value.
654	///
655	/// The value is immediately available without any computation.
656	/// Requires `Send` since `ArcLazy` is thread-safe.
657	///
658	/// ### Type Signature
659	///
660	#[hm_signature]
661	///
662	/// ### Parameters
663	///
664	#[doc_params("The pre-computed value to wrap.")]
665	///
666	/// ### Returns
667	///
668	/// A new `Lazy` instance containing the value.
669	///
670	/// ### Examples
671	///
672	/// ```
673	/// use fp_library::types::*;
674	///
675	/// let lazy = Lazy::<_, ArcLazyConfig>::pure(42);
676	/// assert_eq!(*lazy.evaluate(), 42);
677	/// ```
678	pub fn pure(a: A) -> Self
679	where
680		A: Send,
681	{
682		Lazy(ArcLazyConfig::lazy_new(Box::new(move || a)))
683	}
684}
685
686/// Single-threaded memoization alias.
687pub type RcLazy<'a, A> = Lazy<'a, A, RcLazyConfig>;
688
689/// Thread-safe memoization alias.
690pub type ArcLazy<'a, A> = Lazy<'a, A, ArcLazyConfig>;
691
692impl_kind! {
693	impl<Config: LazyConfig> for LazyBrand<Config> {
694		type Of<'a, A: 'a>: 'a = Lazy<'a, A, Config>;
695	}
696}
697
698impl<'a, A> Deferrable<'a> for Lazy<'a, A, RcLazyConfig>
699where
700	A: Clone + 'a,
701{
702	/// Defers a computation that produces a `Lazy` value.
703	///
704	/// This flattens the nested structure: instead of `Lazy<Lazy<A>>`, we get `Lazy<A>`.
705	/// The inner `Lazy` is computed only when the outer `Lazy` is evaluated.
706	///
707	/// ### Type Signature
708	///
709	#[hm_signature(Deferrable)]
710	///
711	/// ### Type Parameters
712	///
713	#[doc_type_params("The type of the thunk.")]
714	///
715	/// ### Parameters
716	///
717	#[doc_params("The thunk that produces the lazy value.")]
718	///
719	/// ### Returns
720	///
721	/// A new `Lazy` value.
722	///
723	/// ### Examples
724	///
725	/// ```
726	/// use fp_library::{brands::*, classes::*, types::*, functions::*};
727	///
728	/// let lazy = Lazy::<_, RcLazyConfig>::defer(|| RcLazy::pure(42));
729	/// assert_eq!(*lazy.evaluate(), 42);
730	/// ```
731	fn defer<F>(f: F) -> Self
732	where
733		F: FnOnce() -> Self + 'a,
734		Self: Sized,
735	{
736		RcLazy::new(move || f().evaluate().clone())
737	}
738}
739
740impl<'a, A> SendDeferrable<'a> for Lazy<'a, A, ArcLazyConfig>
741where
742	A: Clone + Send + Sync + 'a,
743{
744	/// Defers a computation that produces a thread-safe `Lazy` value.
745	///
746	/// This flattens the nested structure: instead of `ArcLazy<ArcLazy<A>>`, we get `ArcLazy<A>`.
747	/// The inner `Lazy` is computed only when the outer `Lazy` is evaluated.
748	///
749	/// ### Type Signature
750	///
751	#[hm_signature(SendDeferrable)]
752	///
753	/// ### Type Parameters
754	///
755	#[doc_type_params("The type of the thunk.")]
756	///
757	/// ### Parameters
758	///
759	#[doc_params("The thunk that produces the lazy value.")]
760	///
761	/// ### Returns
762	///
763	/// A new `ArcLazy` value.
764	///
765	/// ### Examples
766	///
767	/// ```
768	/// use fp_library::{brands::*, classes::*, types::*};
769	///
770	/// let lazy = ArcLazy::send_defer(|| ArcLazy::pure(42));
771	/// assert_eq!(*lazy.evaluate(), 42);
772	/// ```
773	fn send_defer<F>(f: F) -> Self
774	where
775		F: FnOnce() -> Self + Send + Sync + 'a,
776		Self: Sized,
777	{
778		ArcLazy::new(move || f().evaluate().clone())
779	}
780}
781
782impl RefFunctor for LazyBrand<RcLazyConfig> {
783	/// Maps a function over the memoized value, where the function takes a reference.
784	///
785	/// ### Type Signature
786	///
787	#[hm_signature(RefFunctor)]
788	///
789	/// ### Type Parameters
790	///
791	#[doc_type_params(
792		"The lifetime of the values.",
793		"The type of the value.",
794		"The type of the result.",
795		"The type of the function."
796	)]
797	///
798	/// ### Parameters
799	///
800	#[doc_params("The function to apply.", "The memoized value.")]
801	///
802	/// ### Returns
803	///
804	/// A new memoized value.
805	///
806	/// ### Examples
807	///
808	/// ```
809	/// use fp_library::{brands::*, classes::*, types::*};
810	///
811	/// let memo = Lazy::<_, RcLazyConfig>::new(|| 10);
812	/// let mapped = LazyBrand::<RcLazyConfig>::ref_map(
813	///     |x: &i32| *x * 2,
814	///     memo,
815	/// );
816	/// assert_eq!(*mapped.evaluate(), 20);
817	/// ```
818	fn ref_map<'a, A: 'a, B: 'a, F>(
819		f: F,
820		fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
821	) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>)
822	where
823		F: FnOnce(&A) -> B + 'a,
824	{
825		let fa = fa.clone();
826		let init: Box<dyn FnOnce() -> B + 'a> = Box::new(move || f(fa.evaluate()));
827		Lazy(RcLazyConfig::lazy_new(init))
828	}
829}
830
831#[cfg(test)]
832mod tests {
833	use super::*;
834	use std::cell::RefCell;
835	use std::rc::Rc;
836
837	/// Tests that `Lazy` caches the result of the computation.
838	///
839	/// Verifies that the initializer is called only once.
840	#[test]
841	fn test_memo_caching() {
842		let counter = Rc::new(RefCell::new(0));
843		let counter_clone = counter.clone();
844		let memo = RcLazy::new(move || {
845			*counter_clone.borrow_mut() += 1;
846			42
847		});
848
849		assert_eq!(*counter.borrow(), 0);
850		assert_eq!(*memo.evaluate(), 42);
851		assert_eq!(*counter.borrow(), 1);
852		assert_eq!(*memo.evaluate(), 42);
853		assert_eq!(*counter.borrow(), 1);
854	}
855
856	/// Tests that `Lazy` shares the cache across clones.
857	///
858	/// Verifies that clones see the same value and don't recompute.
859	#[test]
860	fn test_memo_sharing() {
861		let counter = Rc::new(RefCell::new(0));
862		let counter_clone = counter.clone();
863		let memo = RcLazy::new(move || {
864			*counter_clone.borrow_mut() += 1;
865			42
866		});
867		let shared = memo.clone();
868
869		assert_eq!(*memo.evaluate(), 42);
870		assert_eq!(*counter.borrow(), 1);
871		assert_eq!(*shared.evaluate(), 42);
872		assert_eq!(*counter.borrow(), 1);
873	}
874
875	/// Tests thread safety of `ArcLazy`.
876	///
877	/// Verifies that `ArcLazy` can be shared across threads and computes only once.
878	#[test]
879	fn test_arc_memo_thread_safety() {
880		use std::sync::atomic::{AtomicUsize, Ordering};
881		use std::thread;
882
883		let counter = Arc::new(AtomicUsize::new(0));
884		let counter_clone = counter.clone();
885		let memo = ArcLazy::new(move || {
886			counter_clone.fetch_add(1, Ordering::SeqCst);
887			42
888		});
889
890		let mut handles = vec![];
891		for _ in 0..10 {
892			let memo_clone = memo.clone();
893			handles.push(thread::spawn(move || {
894				assert_eq!(*memo_clone.evaluate(), 42);
895			}));
896		}
897
898		for handle in handles {
899			handle.join().unwrap();
900		}
901
902		assert_eq!(counter.load(Ordering::SeqCst), 1);
903	}
904
905	/// Tests creation from `Thunk`.
906	///
907	/// Verifies `From<Thunk>` works correctly.
908	#[test]
909	fn test_memo_from_eval() {
910		let eval = Thunk::new(|| 42);
911		let memo = RcLazy::from(eval);
912		assert_eq!(*memo.evaluate(), 42);
913	}
914
915	/// Tests creation from `Trampoline`.
916	///
917	/// Verifies `From<Trampoline>` works correctly.
918	#[test]
919	fn test_memo_from_task() {
920		// Trampoline requires Send, so we use a Send-compatible value
921		let task = Trampoline::pure(42);
922		let memo = RcLazy::from(task);
923		assert_eq!(*memo.evaluate(), 42);
924	}
925
926	/// Tests Defer implementation.
927	#[test]
928	fn test_defer() {
929		use crate::classes::deferrable::defer;
930
931		let memo: RcLazy<i32> = defer(|| RcLazy::new(|| 42));
932		assert_eq!(*memo.evaluate(), 42);
933	}
934
935	/// Tests SendDefer implementation.
936	#[test]
937	fn test_send_defer() {
938		use crate::classes::send_deferrable::send_defer;
939
940		let memo: ArcLazy<i32> = send_defer(|| ArcLazy::new(|| 42));
941		assert_eq!(*memo.evaluate(), 42);
942	}
943
944	/// Tests `RcLazy::pure`.
945	///
946	/// Verifies that `pure` creates a lazy value from a pre-computed value.
947	#[test]
948	fn test_rc_lazy_pure() {
949		let lazy = RcLazy::pure(42);
950		assert_eq!(*lazy.evaluate(), 42);
951
952		// Verify it's still lazy (shares cache)
953		let shared = lazy.clone();
954		assert_eq!(*shared.evaluate(), 42);
955	}
956
957	/// Tests `ArcLazy::pure`.
958	///
959	/// Verifies that `pure` creates a thread-safe lazy value from a pre-computed value.
960	#[test]
961	fn test_arc_lazy_pure() {
962		let lazy = ArcLazy::pure(42);
963		assert_eq!(*lazy.evaluate(), 42);
964
965		// Verify it's still lazy (shares cache)
966		let shared = lazy.clone();
967		assert_eq!(*shared.evaluate(), 42);
968	}
969
970	/// Tests `ArcLazy::pure` with thread safety.
971	///
972	/// Verifies that `pure` works across threads.
973	#[test]
974	fn test_arc_lazy_pure_thread_safety() {
975		use std::thread;
976
977		let lazy = ArcLazy::pure(42);
978
979		let mut handles = vec![];
980		for _ in 0..10 {
981			let lazy_clone = lazy.clone();
982			handles.push(thread::spawn(move || {
983				assert_eq!(*lazy_clone.evaluate(), 42);
984			}));
985		}
986
987		for handle in handles {
988			handle.join().unwrap();
989		}
990	}
991}