Skip to main content

fp_library/types/
try_lazy.rs

1//! Memoized lazy evaluation for fallible computations.
2//!
3//! Computes a [`Result`] at most once and caches either the success value or error. All clones
4//! share the same cache. Available in both single-threaded [`RcTryLazy`] and thread-safe
5//! [`ArcTryLazy`] variants.
6//!
7//! # `Foldable` and error discarding
8//!
9//! The [`Foldable`](crate::classes::Foldable) implementation for
10//! [`TryLazyBrand<E, Config>`](crate::brands::TryLazyBrand) treats `TryLazy` as a container of
11//! zero or one success values. If the computation produces an `Err`, the fold sees an empty
12//! container and returns the initial accumulator unchanged. The error value is silently discarded.
13//! Use [`evaluate`](TryLazy::evaluate) directly if you need to inspect or handle errors.
14//!
15//! # Choosing between `TryLazy`, `Lazy<Result<A, E>>`, and `Result<Lazy, E>`
16//!
17//! - **[`TryLazy<A, E>`](TryLazy)**: Use when the computation itself may fail, and you want
18//!   memoization of the entire outcome (success or error). The result is computed at most once;
19//!   subsequent accesses return the cached `Ok` or `Err`.
20//! - **`Lazy<Result<A, E>>`**: Equivalent in caching behavior, but does not participate in the
21//!   `TryLazy` combinator API (`map_err`, `and_then`, `or_else`). Prefer `TryLazy` for
22//!   ergonomics when working with fallible computations.
23//! - **`Result<Lazy<A>, E>`**: The error is known eagerly (before any lazy computation). Use
24//!   this when failure is detected up front and only the success path involves deferred work.
25//!
26//! # `TryLazy::map` vs `Lazy::ref_map` naming
27//!
28//! [`Lazy::ref_map`](crate::types::Lazy::ref_map) is named `ref_map` because it receives a
29//! `&A` reference (the memoized value is borrowed, not moved). [`TryLazy::map`](TryLazy::map)
30//! follows the same convention internally (the closure receives `&A` from the cached result), but
31//! uses the name `map` to mirror [`Result::map`] and the other fallible-type combinators
32//! (`map_err`, `and_then`, `or_else`). The mapping closure must clone or derive a new `B` from
33//! the reference.
34
35#[fp_macros::document_module]
36mod inner {
37	use {
38		crate::{
39			Apply,
40			brands::TryLazyBrand,
41			classes::{
42				CloneableFn,
43				Deferrable,
44				Foldable,
45				FoldableWithIndex,
46				Monoid,
47				RefFunctor,
48				Semigroup,
49				SendDeferrable,
50				SendRefFunctor,
51				TryLazyConfig,
52				WithIndex,
53			},
54			impl_kind,
55			kinds::*,
56			types::{
57				ArcLazyConfig,
58				Lazy,
59				RcLazyConfig,
60				TrySendThunk,
61				TryThunk,
62				TryTrampoline,
63			},
64		},
65		fp_macros::*,
66		std::{
67			fmt,
68			hash::{
69				Hash,
70				Hasher,
71			},
72		},
73	};
74
75	/// A lazily-computed, memoized value that may fail.
76	///
77	/// The computation runs at most once. If it succeeds, the value is cached.
78	/// If it fails, the error is cached. Subsequent accesses return the cached result.
79	///
80	/// ### When to Use
81	///
82	/// Use `TryLazy` for memoized fallible computation. The `Result` is cached on first
83	/// evaluation, and subsequent accesses return the cached outcome without re-running
84	/// the closure. For non-memoized fallible deferred computation, use
85	/// [`TryThunk`](crate::types::TryThunk). For stack-safe fallible recursion, use
86	/// [`TryTrampoline`](crate::types::TryTrampoline).
87	///
88	/// ### Cache Chain Behavior
89	///
90	/// Chaining [`map`](TryLazy::map) or [`map_err`](TryLazy::map_err) calls creates a
91	/// linked list of `Rc`/`Arc`-referenced cells. Each mapped `TryLazy` holds a reference
92	/// to its predecessor, keeping predecessor values alive in memory. This is the same
93	/// behavior as [`Lazy::ref_map`](crate::types::Lazy::ref_map).
94	#[document_type_parameters(
95		"The lifetime of the computation.",
96		"The type of the computed value.",
97		"The type of the error.",
98		"The memoization configuration."
99	)]
100	///
101	/// ### Higher-Kinded Type Representation
102	///
103	/// The higher-kinded representation of this type constructor is [`TryLazyBrand<E, Config>`](crate::brands::TryLazyBrand),
104	/// which is parameterized by both the error type and the [`TryLazyConfig`], and is polymorphic over the success value type.
105	pub struct TryLazy<'a, A, E, Config: TryLazyConfig = RcLazyConfig>(
106		/// The internal lazy cell.
107		pub(crate) Config::TryLazy<'a, A, E>,
108	)
109	where
110		A: 'a,
111		E: 'a;
112
113	#[document_type_parameters(
114		"The lifetime of the computation.",
115		"The type of the computed value.",
116		"The type of the error.",
117		"The memoization configuration."
118	)]
119	#[document_parameters("The instance to clone.")]
120	impl<'a, A, E, Config: TryLazyConfig> Clone for TryLazy<'a, A, E, Config>
121	where
122		A: 'a,
123		E: 'a,
124	{
125		#[document_signature]
126		#[document_returns(
127			"A new `TryLazy` instance that shares the same underlying memoized result."
128		)]
129		#[document_examples]
130		///
131		/// ```
132		/// use fp_library::types::*;
133		/// let memo = TryLazy::<_, _, RcLazyConfig>::new(|| Ok::<i32, ()>(42));
134		/// let cloned = memo.clone();
135		/// assert_eq!(cloned.evaluate(), Ok(&42));
136		/// ```
137		fn clone(&self) -> Self {
138			Self(self.0.clone())
139		}
140	}
141
142	#[document_type_parameters(
143		"The lifetime of the computation.",
144		"The type of the computed value.",
145		"The type of the error.",
146		"The memoization configuration."
147	)]
148	#[document_parameters("The `TryLazy` instance.")]
149	impl<'a, A, E, Config: TryLazyConfig> TryLazy<'a, A, E, Config>
150	where
151		A: 'a,
152		E: 'a,
153	{
154		/// Gets the memoized result, computing on first access.
155		///
156		/// ### Panics
157		///
158		/// If the initializer closure panics, the underlying [`LazyCell`](std::cell::LazyCell)
159		/// (for [`RcLazyConfig`]) or [`LazyLock`](std::sync::LazyLock) (for [`ArcLazyConfig`])
160		/// is poisoned. Any subsequent call to `evaluate` on the same instance or any of its
161		/// clones will panic again. For panic-safe memoization, wrap the closure body with
162		/// [`std::panic::catch_unwind`] and store the result as an `Err` variant.
163		#[document_signature]
164		///
165		#[document_returns("A result containing a reference to the value or error.")]
166		///
167		#[document_examples]
168		///
169		/// ```
170		/// use fp_library::types::*;
171		///
172		/// let memo = TryLazy::<_, _, RcLazyConfig>::new(|| Ok::<i32, ()>(42));
173		/// assert_eq!(memo.evaluate(), Ok(&42));
174		/// ```
175		#[inline]
176		pub fn evaluate(&self) -> Result<&A, &E> {
177			Config::try_evaluate(&self.0)
178		}
179	}
180
181	#[document_type_parameters(
182		"The lifetime of the computation.",
183		"The type of the computed value.",
184		"The type of the error."
185	)]
186	#[document_parameters("The try-lazy cell instance.")]
187	impl<'a, A, E> TryLazy<'a, A, E, RcLazyConfig>
188	where
189		A: 'a,
190		E: 'a,
191	{
192		/// Creates a new `TryLazy` that will run `f` on first access.
193		#[document_signature]
194		///
195		#[document_parameters("The closure that produces the result.")]
196		///
197		#[document_returns("A new `TryLazy` instance.")]
198		///
199		#[document_examples]
200		///
201		/// ```
202		/// use fp_library::types::*;
203		///
204		/// let memo = TryLazy::<_, _, RcLazyConfig>::new(|| Ok::<i32, ()>(42));
205		/// assert_eq!(memo.evaluate(), Ok(&42));
206		/// ```
207		#[inline]
208		pub fn new(f: impl FnOnce() -> Result<A, E> + 'a) -> Self {
209			TryLazy(RcLazyConfig::try_lazy_new(Box::new(f)))
210		}
211
212		/// Creates a `TryLazy` containing an already-computed success value.
213		#[document_signature]
214		///
215		#[document_parameters("The success value to wrap.")]
216		///
217		#[document_returns("A new `TryLazy` instance that evaluates to `Ok(&a)`.")]
218		///
219		#[document_examples]
220		///
221		/// ```
222		/// use fp_library::types::*;
223		///
224		/// let memo = RcTryLazy::<i32, ()>::ok(42);
225		/// assert_eq!(memo.evaluate(), Ok(&42));
226		/// ```
227		#[inline]
228		pub fn ok(a: A) -> Self {
229			Self::new(move || Ok(a))
230		}
231
232		/// Creates a `TryLazy` containing an already-computed error value.
233		#[document_signature]
234		///
235		#[document_parameters("The error value to wrap.")]
236		///
237		#[document_returns("A new `TryLazy` instance that evaluates to `Err(&e)`.")]
238		///
239		#[document_examples]
240		///
241		/// ```
242		/// use fp_library::types::*;
243		///
244		/// let memo = RcTryLazy::<i32, String>::err("error".to_string());
245		/// assert_eq!(memo.evaluate(), Err(&"error".to_string()));
246		/// ```
247		#[inline]
248		pub fn err(e: E) -> Self {
249			Self::new(move || Err(e))
250		}
251
252		/// Returns a clone of the memoized result, computing on first access.
253		///
254		/// This is a convenience wrapper around [`evaluate`](TryLazy::evaluate) for cases
255		/// where an owned `Result` is needed rather than a `Result` of references.
256		#[document_signature]
257		///
258		#[document_returns("An owned `Result` clone of the memoized value.")]
259		///
260		#[document_examples]
261		///
262		/// ```
263		/// use fp_library::types::*;
264		///
265		/// let memo = RcTryLazy::<i32, String>::ok(42);
266		/// let owned: Result<i32, String> = memo.evaluate_owned();
267		/// assert_eq!(owned, Ok(42));
268		/// ```
269		#[inline]
270		pub fn evaluate_owned(&self) -> Result<A, E>
271		where
272			A: Clone,
273			E: Clone, {
274			self.evaluate().cloned().map_err(|e| e.clone())
275		}
276
277		/// Transforms the success value by creating a new `TryLazy` cell.
278		///
279		/// The original cell is evaluated on first access of the new cell. The mapping
280		/// function receives a reference to the cached success value.
281		///
282		/// ### Why `E: Clone`?
283		///
284		/// The inner cell holds `Result<A, E>`. Mapping the success side requires cloning
285		/// the error out of the `&E` reference when the result is `Err`, because the new
286		/// cell must own its own cached `Result<B, E>`.
287		#[document_signature]
288		///
289		#[document_type_parameters("The type of the mapped success value.")]
290		///
291		#[document_parameters("The function to apply to the success value.")]
292		///
293		#[document_returns("A new `RcTryLazy` that applies `f` to the success value of this cell.")]
294		///
295		#[document_examples]
296		///
297		/// ```
298		/// use fp_library::types::*;
299		///
300		/// let memo = RcTryLazy::<i32, String>::ok(10);
301		/// let mapped = memo.map(|a| a * 2);
302		/// assert_eq!(mapped.evaluate(), Ok(&20));
303		/// ```
304		#[inline]
305		pub fn map<B: 'a>(
306			self,
307			f: impl FnOnce(&A) -> B + 'a,
308		) -> RcTryLazy<'a, B, E>
309		where
310			E: Clone + 'a, {
311			RcTryLazy::new(move || match self.evaluate() {
312				Ok(a) => Ok(f(a)),
313				Err(e) => Err(e.clone()),
314			})
315		}
316
317		/// Maps a function over the memoized success value by reference.
318		///
319		/// This is the inherent method form of [`RefFunctor::ref_map`](crate::classes::ref_functor::RefFunctor::ref_map)
320		/// for `RcTryLazy`. Evaluates the lazy cell and, if `Ok`, applies `f` to the referenced
321		/// success value. If `Err`, clones the error into the new cell.
322		///
323		/// This is functionally identical to [`map`](TryLazy::map) but exists so that
324		/// the `RefFunctor` trait implementation can delegate to an inherent method,
325		/// matching the pattern used by [`RcLazy::ref_map`](crate::types::lazy::Lazy::ref_map).
326		///
327		/// ### Why `E: Clone`?
328		///
329		/// The inner cell holds `Result<A, E>`. Mapping the success side requires cloning
330		/// the error out of the `&E` reference when the result is `Err`, because the new
331		/// cell must own its own cached `Result<B, E>`.
332		#[document_signature]
333		#[document_type_parameters("The type of the mapped success value.")]
334		#[document_parameters("The function to apply to the success value.")]
335		#[document_returns("A new `RcTryLazy` that applies `f` to the success value of this cell.")]
336		#[document_examples]
337		///
338		/// ```
339		/// use fp_library::types::*;
340		///
341		/// let memo = RcTryLazy::<i32, String>::ok(10);
342		/// let mapped = memo.ref_map(|x| *x * 2);
343		/// assert_eq!(mapped.evaluate(), Ok(&20));
344		/// ```
345		#[inline]
346		pub fn ref_map<B: 'a>(
347			self,
348			f: impl FnOnce(&A) -> B + 'a,
349		) -> RcTryLazy<'a, B, E>
350		where
351			E: Clone + 'a, {
352			RcTryLazy::new(move || match self.evaluate() {
353				Ok(a) => Ok(f(a)),
354				Err(e) => Err(e.clone()),
355			})
356		}
357
358		/// Transforms the error value by creating a new `TryLazy` cell.
359		///
360		/// The original cell is evaluated on first access of the new cell. The mapping
361		/// function receives a reference to the cached error value.
362		///
363		/// ### Why `A: Clone`?
364		///
365		/// The inner cell holds `Result<A, E>`. Mapping the error side requires cloning
366		/// the success value out of the `&A` reference when the result is `Ok`, because the
367		/// new cell must own its own cached `Result<A, E2>`.
368		#[document_signature]
369		///
370		#[document_type_parameters("The type of the mapped error value.")]
371		///
372		#[document_parameters("The function to apply to the error value.")]
373		///
374		#[document_returns("A new `RcTryLazy` that applies `f` to the error value of this cell.")]
375		///
376		#[document_examples]
377		///
378		/// ```
379		/// use fp_library::types::*;
380		///
381		/// let memo = RcTryLazy::<i32, String>::err("error".to_string());
382		/// let mapped = memo.map_err(|e| format!("wrapped: {}", e));
383		/// assert_eq!(mapped.evaluate(), Err(&"wrapped: error".to_string()));
384		/// ```
385		#[inline]
386		pub fn map_err<E2: 'a>(
387			self,
388			f: impl FnOnce(&E) -> E2 + 'a,
389		) -> RcTryLazy<'a, A, E2>
390		where
391			A: Clone + 'a, {
392			RcTryLazy::new(move || match self.evaluate() {
393				Ok(a) => Ok(a.clone()),
394				Err(e) => Err(f(e)),
395			})
396		}
397
398		/// Transforms both the success and error values by creating a new `TryLazy` cell.
399		///
400		/// The original cell is evaluated on first access of the new cell. The success
401		/// mapping function `f` receives a reference to the cached success value, and the
402		/// error mapping function `g` receives a reference to the cached error value.
403		/// Unlike `map` (which requires `E: Clone`) or `map_err` (which requires `A: Clone`),
404		/// `bimap` needs neither because each branch is fully transformed.
405		#[document_signature]
406		///
407		#[document_type_parameters(
408			"The type of the mapped success value.",
409			"The type of the mapped error value."
410		)]
411		///
412		#[document_parameters(
413			"The function to apply to the success value.",
414			"The function to apply to the error value."
415		)]
416		///
417		#[document_returns(
418			"A new `RcTryLazy` that applies `f` to the success value or `g` to the error value of this cell."
419		)]
420		///
421		#[document_examples]
422		///
423		/// ```
424		/// use fp_library::types::*;
425		///
426		/// let ok_memo = RcTryLazy::<i32, String>::ok(10);
427		/// let mapped = ok_memo.bimap(|a| a * 2, |e| e.len());
428		/// assert_eq!(mapped.evaluate(), Ok(&20));
429		///
430		/// let err_memo = RcTryLazy::<i32, String>::err("error".to_string());
431		/// let mapped = err_memo.bimap(|a| a * 2, |e| e.len());
432		/// assert_eq!(mapped.evaluate(), Err(&5));
433		/// ```
434		#[inline]
435		pub fn bimap<B: 'a, F: 'a>(
436			self,
437			f: impl FnOnce(&A) -> B + 'a,
438			g: impl FnOnce(&E) -> F + 'a,
439		) -> RcTryLazy<'a, B, F> {
440			RcTryLazy::new(move || match self.evaluate() {
441				Ok(a) => Ok(f(a)),
442				Err(e) => Err(g(e)),
443			})
444		}
445	}
446
447	#[document_type_parameters(
448		"The lifetime of the computation.",
449		"The type of the computed value.",
450		"The type of the error."
451	)]
452	impl<'a, A, E> From<TryThunk<'a, A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
453	where
454		A: Send + Sync + 'a,
455		E: Send + Sync + 'a,
456	{
457		/// Converts a [`TryThunk`] into an [`ArcTryLazy`] by eagerly evaluating the thunk.
458		///
459		/// `TryThunk` is `!Send`, so the result must be computed immediately to cross
460		/// into the thread-safe `ArcTryLazy` world.
461		#[document_signature]
462		#[document_parameters("The fallible thunk to convert.")]
463		#[document_returns("A new `TryLazy` instance containing the eagerly evaluated result.")]
464		#[document_examples]
465		///
466		/// ```
467		/// use fp_library::types::*;
468		/// let thunk = TryThunk::new(|| Ok::<i32, ()>(42));
469		/// let memo: ArcTryLazy<i32, ()> = ArcTryLazy::from(thunk);
470		/// assert_eq!(memo.evaluate(), Ok(&42));
471		/// ```
472		fn from(eval: TryThunk<'a, A, E>) -> Self {
473			let result = eval.evaluate();
474			Self::new(move || result)
475		}
476	}
477
478	#[document_type_parameters(
479		"The lifetime of the computation.",
480		"The type of the computed value.",
481		"The type of the error."
482	)]
483	impl<'a, A, E> From<TryTrampoline<A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
484	where
485		A: Send + Sync + 'static,
486		E: Send + Sync + 'static,
487	{
488		/// Converts a [`TryTrampoline`] into an [`ArcTryLazy`] by eagerly evaluating the trampoline.
489		///
490		/// `TryTrampoline` is `!Send`, so the result must be computed immediately to cross
491		/// into the thread-safe `ArcTryLazy` world.
492		#[document_signature]
493		#[document_parameters("The fallible trampoline to convert.")]
494		#[document_returns("A new `TryLazy` instance containing the eagerly evaluated result.")]
495		#[document_examples]
496		///
497		/// ```
498		/// use fp_library::types::*;
499		/// let task = TryTrampoline::<_, ()>::ok(42);
500		/// let memo: ArcTryLazy<i32, ()> = ArcTryLazy::from(task);
501		/// assert_eq!(memo.evaluate(), Ok(&42));
502		/// ```
503		fn from(task: TryTrampoline<A, E>) -> Self {
504			let result = task.evaluate();
505			Self::new(move || result)
506		}
507	}
508
509	#[document_type_parameters(
510		"The lifetime of the computation.",
511		"The type of the computed value.",
512		"The type of the error."
513	)]
514	impl<'a, A, E> From<TryThunk<'a, A, E>> for TryLazy<'a, A, E, RcLazyConfig> {
515		#[document_signature]
516		#[document_parameters("The fallible thunk to convert.")]
517		#[document_returns(
518			"A new `TryLazy` instance that will evaluate the thunk on first access."
519		)]
520		#[document_examples]
521		///
522		/// ```
523		/// use fp_library::types::*;
524		/// let thunk = TryThunk::new(|| Ok::<i32, ()>(42));
525		/// let memo: RcTryLazy<i32, ()> = TryLazy::from(thunk);
526		/// assert_eq!(memo.evaluate(), Ok(&42));
527		/// ```
528		fn from(eval: TryThunk<'a, A, E>) -> Self {
529			Self::new(move || eval.evaluate())
530		}
531	}
532
533	#[document_type_parameters(
534		"The lifetime of the computation.",
535		"The type of the computed value.",
536		"The type of the error."
537	)]
538	impl<'a, A, E> From<TryTrampoline<A, E>> for TryLazy<'a, A, E, RcLazyConfig> {
539		#[document_signature]
540		#[document_parameters("The fallible trampoline to convert.")]
541		#[document_returns(
542			"A new `TryLazy` instance that will evaluate the trampoline on first access."
543		)]
544		#[document_examples]
545		///
546		/// ```
547		/// use fp_library::types::*;
548		/// let task = TryTrampoline::<_, ()>::ok(42);
549		/// let memo: RcTryLazy<i32, ()> = TryLazy::from(task);
550		/// assert_eq!(memo.evaluate(), Ok(&42));
551		/// ```
552		fn from(task: TryTrampoline<A, E>) -> Self {
553			Self::new(move || task.evaluate())
554		}
555	}
556
557	#[document_type_parameters(
558		"The lifetime of the computation.",
559		"The type of the computed value.",
560		"The type of the error."
561	)]
562	impl<'a, A, E> From<Lazy<'a, A, ArcLazyConfig>> for TryLazy<'a, A, E, ArcLazyConfig>
563	where
564		A: Clone + Send + Sync + 'a,
565		E: Send + Sync + 'a,
566	{
567		#[document_signature]
568		#[document_parameters("The thread-safe lazy value to convert.")]
569		#[document_returns("A new `TryLazy` instance that wraps the lazy value.")]
570		#[document_examples]
571		///
572		/// ```
573		/// use fp_library::types::*;
574		/// let lazy = Lazy::<_, ArcLazyConfig>::pure(42);
575		/// let memo: TryLazy<_, (), _> = TryLazy::from(lazy);
576		/// assert_eq!(memo.evaluate(), Ok(&42));
577		/// ```
578		fn from(memo: Lazy<'a, A, ArcLazyConfig>) -> Self {
579			Self::new(move || Ok(memo.evaluate().clone()))
580		}
581	}
582
583	#[document_type_parameters(
584		"The lifetime of the computation.",
585		"The type of the computed value.",
586		"The type of the error."
587	)]
588	impl<'a, A, E> From<Lazy<'a, A, RcLazyConfig>> for TryLazy<'a, A, E, RcLazyConfig>
589	where
590		A: Clone + 'a,
591		E: 'a,
592	{
593		#[document_signature]
594		#[document_parameters("The lazy value to convert.")]
595		#[document_returns("A new `TryLazy` instance that wraps the lazy value.")]
596		#[document_examples]
597		///
598		/// ```
599		/// use fp_library::types::*;
600		/// let lazy = Lazy::<_, RcLazyConfig>::pure(42);
601		/// let memo: TryLazy<_, (), _> = TryLazy::from(lazy);
602		/// assert_eq!(memo.evaluate(), Ok(&42));
603		/// ```
604		fn from(memo: Lazy<'a, A, RcLazyConfig>) -> Self {
605			Self::new(move || Ok(memo.evaluate().clone()))
606		}
607	}
608
609	#[document_type_parameters(
610		"The lifetime of the computation.",
611		"The type of the computed value.",
612		"The type of the error."
613	)]
614	impl<'a, A: 'a, E: 'a> From<Result<A, E>> for TryLazy<'a, A, E, RcLazyConfig> {
615		#[document_signature]
616		#[document_parameters("The result to convert.")]
617		#[document_returns("A new `TryLazy` instance that produces the result.")]
618		#[document_examples]
619		///
620		/// ```
621		/// use fp_library::types::*;
622		/// let ok_memo: RcTryLazy<i32, String> = RcTryLazy::from(Ok(42));
623		/// assert_eq!(ok_memo.evaluate(), Ok(&42));
624		///
625		/// let err_memo: RcTryLazy<i32, String> = RcTryLazy::from(Err("error".to_string()));
626		/// assert_eq!(err_memo.evaluate(), Err(&"error".to_string()));
627		/// ```
628		fn from(result: Result<A, E>) -> Self {
629			Self::new(move || result)
630		}
631	}
632
633	#[document_type_parameters(
634		"The lifetime of the computation.",
635		"The type of the computed value.",
636		"The type of the error."
637	)]
638	impl<'a, A, E> From<Result<A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
639	where
640		A: 'a,
641		E: 'a,
642		Result<A, E>: Send,
643	{
644		#[document_signature]
645		#[document_parameters("The result to convert.")]
646		#[document_returns("A new `TryLazy` instance that produces the result.")]
647		#[document_examples]
648		///
649		/// ```
650		/// use fp_library::types::*;
651		/// let ok_memo: ArcTryLazy<i32, String> = ArcTryLazy::from(Ok(42));
652		/// assert_eq!(ok_memo.evaluate(), Ok(&42));
653		///
654		/// let err_memo: ArcTryLazy<i32, String> = ArcTryLazy::from(Err("error".to_string()));
655		/// assert_eq!(err_memo.evaluate(), Err(&"error".to_string()));
656		/// ```
657		fn from(result: Result<A, E>) -> Self {
658			Self::new(move || result)
659		}
660	}
661
662	#[document_type_parameters(
663		"The lifetime of the computation.",
664		"The type of the computed value.",
665		"The type of the error."
666	)]
667	impl<'a, A, E> From<TrySendThunk<'a, A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
668	where
669		A: Send + Sync + 'a,
670		E: Send + Sync + 'a,
671	{
672		/// Converts a [`TrySendThunk`] into an [`ArcTryLazy`] without eager evaluation.
673		///
674		/// Unlike conversions from `TryThunk` or `TryTrampoline`, this conversion does
675		/// **not** evaluate the thunk eagerly. The inner `Send` closure is passed directly
676		/// into `ArcTryLazy::new`, so evaluation is deferred until first access.
677		#[document_signature]
678		#[document_parameters("The fallible send thunk to convert.")]
679		#[document_returns("A thread-safe `ArcTryLazy` that evaluates the thunk on first access.")]
680		#[document_examples]
681		///
682		/// ```
683		/// use fp_library::types::*;
684		/// let thunk: TrySendThunk<i32, ()> = TrySendThunk::ok(42);
685		/// let lazy: ArcTryLazy<i32, ()> = ArcTryLazy::from(thunk);
686		/// assert_eq!(lazy.evaluate(), Ok(&42));
687		/// ```
688		fn from(thunk: TrySendThunk<'a, A, E>) -> Self {
689			thunk.into_arc_try_lazy()
690		}
691	}
692
693	#[document_type_parameters(
694		"The lifetime of the computation.",
695		"The type of the computed value.",
696		"The type of the error."
697	)]
698	impl<'a, A: Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a>
699		From<TryLazy<'a, A, E, RcLazyConfig>> for TryLazy<'a, A, E, ArcLazyConfig>
700	{
701		/// Converts an [`RcTryLazy`] into an [`ArcTryLazy`] by eagerly evaluating and cloning the
702		/// result.
703		///
704		/// `RcTryLazy` is `!Send`, so the result must be computed immediately and cloned
705		/// into the thread-safe `ArcTryLazy` world.
706		#[document_signature]
707		#[document_parameters("The `RcTryLazy` instance to convert.")]
708		#[document_returns(
709			"A new `ArcTryLazy` instance containing a clone of the eagerly evaluated result."
710		)]
711		#[document_examples]
712		///
713		/// ```
714		/// use fp_library::types::*;
715		///
716		/// let rc_lazy = RcTryLazy::<i32, String>::ok(42);
717		/// let arc_lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(rc_lazy);
718		/// assert_eq!(arc_lazy.evaluate(), Ok(&42));
719		///
720		/// let rc_err = RcTryLazy::<i32, String>::err("oops".to_string());
721		/// let arc_err: ArcTryLazy<i32, String> = ArcTryLazy::from(rc_err);
722		/// assert_eq!(arc_err.evaluate(), Err(&"oops".to_string()));
723		/// ```
724		fn from(source: TryLazy<'a, A, E, RcLazyConfig>) -> Self {
725			let result: Result<A, E> = source.evaluate().cloned().map_err(Clone::clone);
726			Self::new(move || result)
727		}
728	}
729
730	#[document_type_parameters(
731		"The lifetime of the computation.",
732		"The type of the computed value.",
733		"The type of the error."
734	)]
735	impl<'a, A: Clone + 'a, E: Clone + 'a> From<TryLazy<'a, A, E, ArcLazyConfig>>
736		for TryLazy<'a, A, E, RcLazyConfig>
737	{
738		/// Converts an [`ArcTryLazy`] into an [`RcTryLazy`] by eagerly evaluating and cloning the
739		/// result.
740		///
741		/// The result is computed immediately and cloned into a new single-threaded
742		/// `RcTryLazy` instance.
743		#[document_signature]
744		#[document_parameters("The `ArcTryLazy` instance to convert.")]
745		#[document_returns(
746			"A new `RcTryLazy` instance containing a clone of the eagerly evaluated result."
747		)]
748		#[document_examples]
749		///
750		/// ```
751		/// use fp_library::types::*;
752		///
753		/// let arc_lazy = ArcTryLazy::<i32, String>::ok(42);
754		/// let rc_lazy: RcTryLazy<i32, String> = RcTryLazy::from(arc_lazy);
755		/// assert_eq!(rc_lazy.evaluate(), Ok(&42));
756		///
757		/// let arc_err = ArcTryLazy::<i32, String>::err("oops".to_string());
758		/// let rc_err: RcTryLazy<i32, String> = RcTryLazy::from(arc_err);
759		/// assert_eq!(rc_err.evaluate(), Err(&"oops".to_string()));
760		/// ```
761		fn from(source: TryLazy<'a, A, E, ArcLazyConfig>) -> Self {
762			let result: Result<A, E> = source.evaluate().cloned().map_err(Clone::clone);
763			Self::new(move || result)
764		}
765	}
766
767	#[document_type_parameters(
768		"The lifetime of the computation.",
769		"The type of the computed value.",
770		"The type of the error value."
771	)]
772	impl<'a, A: 'a, E: 'a> TryLazy<'a, A, E, RcLazyConfig> {
773		/// Creates a `TryLazy` that catches unwinds (panics), converting the
774		/// panic payload using a custom conversion function.
775		///
776		/// The closure `f` is executed when the lazy cell is first evaluated.
777		/// If `f` panics, the panic payload is passed to `handler` to produce
778		/// the error value. If `f` returns normally, the value is wrapped in `Ok`.
779		#[document_signature]
780		///
781		#[document_parameters(
782			"The closure that might panic.",
783			"The function that converts a panic payload into the error type."
784		)]
785		///
786		#[document_returns(
787			"A new `TryLazy` instance where panics are converted to `Err(E)` via the handler."
788		)]
789		///
790		#[document_examples]
791		///
792		/// ```
793		/// use fp_library::types::*;
794		///
795		/// let memo = RcTryLazy::<i32, i32>::catch_unwind_with(
796		/// 	|| {
797		/// 		if true {
798		/// 			panic!("oops")
799		/// 		}
800		/// 		42
801		/// 	},
802		/// 	|_payload| -1,
803		/// );
804		/// assert_eq!(memo.evaluate(), Err(&-1));
805		/// ```
806		pub fn catch_unwind_with(
807			f: impl FnOnce() -> A + std::panic::UnwindSafe + 'a,
808			handler: impl FnOnce(Box<dyn std::any::Any + Send>) -> E + 'a,
809		) -> Self {
810			Self::new(move || std::panic::catch_unwind(f).map_err(handler))
811		}
812	}
813
814	#[document_type_parameters(
815		"The lifetime of the computation.",
816		"The type of the computed value."
817	)]
818	impl<'a, A> TryLazy<'a, A, String, RcLazyConfig>
819	where
820		A: 'a,
821	{
822		/// Creates a `TryLazy` that catches unwinds (panics).
823		///
824		/// This is a convenience wrapper around [`catch_unwind_with`](TryLazy::catch_unwind_with)
825		/// that uses the default panic payload to string conversion.
826		#[document_signature]
827		///
828		#[document_parameters("The closure that might panic.")]
829		///
830		#[document_returns("A new `TryLazy` instance where panics are converted to `Err(String)`.")]
831		///
832		#[document_examples]
833		///
834		/// ```
835		/// use fp_library::types::*;
836		///
837		/// let memo = TryLazy::<_, String, RcLazyConfig>::catch_unwind(|| {
838		/// 	if true {
839		/// 		panic!("oops")
840		/// 	}
841		/// 	42
842		/// });
843		/// assert_eq!(memo.evaluate(), Err(&"oops".to_string()));
844		/// ```
845		pub fn catch_unwind(f: impl FnOnce() -> A + std::panic::UnwindSafe + 'a) -> Self {
846			Self::catch_unwind_with(f, crate::utils::panic_payload_to_string)
847		}
848	}
849
850	#[document_type_parameters(
851		"The lifetime of the computation.",
852		"The type of the computed value.",
853		"The type of the error."
854	)]
855	#[document_parameters("The `TryLazy` instance.")]
856	impl<'a, A, E> TryLazy<'a, A, E, RcLazyConfig>
857	where
858		A: Clone + 'a,
859		E: Clone + 'a,
860	{
861		/// Chains a fallible operation on the success value.
862		///
863		/// If this `TryLazy` succeeds, applies `f` to the cached `&A` and returns a new
864		/// `TryLazy` that evaluates the result of `f`. If this `TryLazy` fails, the
865		/// error is cloned into the new `TryLazy`.
866		///
867		/// Note: unlike the typical Rust `and_then` signature where the callback takes
868		/// an owned `A`, this callback receives `&A` (a shared reference to the memoized
869		/// value) because `TryLazy` caches its result behind a shared pointer.
870		#[document_signature]
871		///
872		#[document_type_parameters("The type of the new success value.")]
873		///
874		#[document_parameters("The fallible function to apply to the success value.")]
875		///
876		#[document_returns("A new `TryLazy` containing the chained result.")]
877		///
878		#[document_examples]
879		///
880		/// ```
881		/// use fp_library::types::*;
882		///
883		/// let memo = RcTryLazy::new(|| Ok::<i32, String>(21));
884		/// let chained = memo.and_then(|x| if *x > 0 { Ok(x * 2) } else { Err("negative".into()) });
885		/// assert_eq!(chained.evaluate(), Ok(&42));
886		/// ```
887		pub fn and_then<B: 'a>(
888			self,
889			f: impl FnOnce(&A) -> Result<B, E> + 'a,
890		) -> TryLazy<'a, B, E, RcLazyConfig> {
891			let fa = self;
892			TryLazy::<'a, B, E, RcLazyConfig>::new(move || match fa.evaluate() {
893				Ok(a) => f(a),
894				Err(e) => Err(e.clone()),
895			})
896		}
897
898		/// Provides a fallback on the error value.
899		///
900		/// If this `TryLazy` fails, applies `f` to the cached `&E` and returns a new
901		/// `TryLazy` that evaluates the result of `f`. If this `TryLazy` succeeds, the
902		/// success value is cloned into the new `TryLazy`.
903		#[document_signature]
904		///
905		#[document_parameters("The recovery function to apply to the error value.")]
906		///
907		#[document_returns("A new `TryLazy` containing the recovered result.")]
908		///
909		#[document_examples]
910		///
911		/// ```
912		/// use fp_library::types::*;
913		///
914		/// let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
915		/// let recovered = memo.or_else(|_| Ok(42));
916		/// assert_eq!(recovered.evaluate(), Ok(&42));
917		/// ```
918		pub fn or_else(
919			self,
920			f: impl FnOnce(&E) -> Result<A, E> + 'a,
921		) -> TryLazy<'a, A, E, RcLazyConfig> {
922			let fa = self;
923			TryLazy::<'a, A, E, RcLazyConfig>::new(move || match fa.evaluate() {
924				Ok(a) => Ok(a.clone()),
925				Err(e) => f(e),
926			})
927		}
928	}
929
930	#[document_type_parameters(
931		"The lifetime of the computation.",
932		"The type of the computed value.",
933		"The type of the error."
934	)]
935	#[document_parameters("The `TryLazy` instance.")]
936	impl<'a, A, E> TryLazy<'a, A, E, ArcLazyConfig>
937	where
938		A: Clone + Send + Sync + 'a,
939		E: Clone + Send + Sync + 'a,
940	{
941		/// Chains a fallible operation on the success value (thread-safe variant).
942		///
943		/// If this `ArcTryLazy` succeeds, applies `f` to the cached `&A` and returns a
944		/// new `ArcTryLazy` that evaluates the result of `f`. If this `ArcTryLazy`
945		/// fails, the error is cloned into the new `ArcTryLazy`.
946		///
947		/// Note: unlike the typical Rust `and_then` signature where the callback takes
948		/// an owned `A`, this callback receives `&A` (a shared reference to the memoized
949		/// value) because `ArcTryLazy` caches its result behind a shared pointer.
950		#[document_signature]
951		///
952		#[document_type_parameters("The type of the new success value.")]
953		///
954		#[document_parameters("The fallible function to apply to the success value.")]
955		///
956		#[document_returns("A new `ArcTryLazy` containing the chained result.")]
957		///
958		#[document_examples]
959		///
960		/// ```
961		/// use fp_library::types::*;
962		///
963		/// let memo = ArcTryLazy::new(|| Ok::<i32, String>(21));
964		/// let chained = memo.and_then(|x| if *x > 0 { Ok(x * 2) } else { Err("negative".into()) });
965		/// assert_eq!(chained.evaluate(), Ok(&42));
966		/// ```
967		pub fn and_then<B: Send + Sync + 'a>(
968			self,
969			f: impl FnOnce(&A) -> Result<B, E> + Send + 'a,
970		) -> TryLazy<'a, B, E, ArcLazyConfig> {
971			let fa = self;
972			TryLazy::<'a, B, E, ArcLazyConfig>::new(move || match fa.evaluate() {
973				Ok(a) => f(a),
974				Err(e) => Err(e.clone()),
975			})
976		}
977
978		/// Provides a fallback on the error value (thread-safe variant).
979		///
980		/// If this `ArcTryLazy` fails, applies `f` to the cached `&E` and returns a
981		/// new `ArcTryLazy` that evaluates the result of `f`. If this `ArcTryLazy`
982		/// succeeds, the success value is cloned into the new `ArcTryLazy`.
983		#[document_signature]
984		///
985		#[document_parameters("The recovery function to apply to the error value.")]
986		///
987		#[document_returns("A new `ArcTryLazy` containing the recovered result.")]
988		///
989		#[document_examples]
990		///
991		/// ```
992		/// use fp_library::types::*;
993		///
994		/// let memo: ArcTryLazy<i32, String> = ArcTryLazy::new(|| Err("oops".into()));
995		/// let recovered = memo.or_else(|_| Ok(42));
996		/// assert_eq!(recovered.evaluate(), Ok(&42));
997		/// ```
998		pub fn or_else(
999			self,
1000			f: impl FnOnce(&E) -> Result<A, E> + Send + 'a,
1001		) -> TryLazy<'a, A, E, ArcLazyConfig> {
1002			let fa = self;
1003			TryLazy::<'a, A, E, ArcLazyConfig>::new(move || match fa.evaluate() {
1004				Ok(a) => Ok(a.clone()),
1005				Err(e) => f(e),
1006			})
1007		}
1008	}
1009
1010	#[document_type_parameters(
1011		"The lifetime of the computation.",
1012		"The type of the computed value.",
1013		"The type of the error."
1014	)]
1015	#[document_parameters("The try-lazy cell instance.")]
1016	impl<'a, A, E> TryLazy<'a, A, E, ArcLazyConfig>
1017	where
1018		A: 'a,
1019		E: 'a,
1020	{
1021		/// Creates a new `TryLazy` that will run `f` on first access.
1022		#[document_signature]
1023		///
1024		#[document_parameters("The closure that produces the result.")]
1025		///
1026		#[document_returns("A new `TryLazy` instance.")]
1027		///
1028		#[document_examples]
1029		///
1030		/// ```
1031		/// use fp_library::types::*;
1032		///
1033		/// let memo = TryLazy::<_, _, ArcLazyConfig>::new(|| Ok::<i32, ()>(42));
1034		/// assert_eq!(memo.evaluate(), Ok(&42));
1035		/// ```
1036		#[inline]
1037		pub fn new(f: impl FnOnce() -> Result<A, E> + Send + 'a) -> Self {
1038			TryLazy(ArcLazyConfig::try_lazy_new(Box::new(f)))
1039		}
1040
1041		/// Creates a thread-safe `TryLazy` containing an already-computed success value.
1042		#[document_signature]
1043		///
1044		#[document_parameters("The success value to wrap.")]
1045		///
1046		#[document_returns("A new `ArcTryLazy` instance that evaluates to `Ok(&a)`.")]
1047		///
1048		#[document_examples]
1049		///
1050		/// ```
1051		/// use fp_library::types::*;
1052		///
1053		/// let memo = ArcTryLazy::<i32, ()>::ok(42);
1054		/// assert_eq!(memo.evaluate(), Ok(&42));
1055		/// ```
1056		#[inline]
1057		pub fn ok(a: A) -> Self
1058		where
1059			A: Send,
1060			E: Send, {
1061			Self::new(move || Ok(a))
1062		}
1063
1064		/// Creates a thread-safe `TryLazy` containing an already-computed error value.
1065		#[document_signature]
1066		///
1067		#[document_parameters("The error value to wrap.")]
1068		///
1069		#[document_returns("A new `ArcTryLazy` instance that evaluates to `Err(&e)`.")]
1070		///
1071		#[document_examples]
1072		///
1073		/// ```
1074		/// use fp_library::types::*;
1075		///
1076		/// let memo = ArcTryLazy::<i32, String>::err("error".to_string());
1077		/// assert_eq!(memo.evaluate(), Err(&"error".to_string()));
1078		/// ```
1079		#[inline]
1080		pub fn err(e: E) -> Self
1081		where
1082			A: Send,
1083			E: Send, {
1084			Self::new(move || Err(e))
1085		}
1086
1087		/// Returns a clone of the memoized result, computing on first access.
1088		///
1089		/// This is a convenience wrapper around [`evaluate`](TryLazy::evaluate) for cases
1090		/// where an owned `Result` is needed rather than a `Result` of references.
1091		/// Requires `Send + Sync` since `ArcTryLazy` is thread-safe.
1092		#[document_signature]
1093		///
1094		#[document_returns("An owned `Result` clone of the memoized value.")]
1095		///
1096		#[document_examples]
1097		///
1098		/// ```
1099		/// use fp_library::types::*;
1100		///
1101		/// let memo = ArcTryLazy::<i32, String>::ok(42);
1102		/// let owned: Result<i32, String> = memo.evaluate_owned();
1103		/// assert_eq!(owned, Ok(42));
1104		/// ```
1105		#[inline]
1106		pub fn evaluate_owned(&self) -> Result<A, E>
1107		where
1108			A: Clone + Send + Sync,
1109			E: Clone + Send + Sync, {
1110			self.evaluate().cloned().map_err(|e| e.clone())
1111		}
1112
1113		/// Transforms the success value by creating a new thread-safe `TryLazy` cell.
1114		///
1115		/// The original cell is evaluated on first access of the new cell. The mapping
1116		/// function receives a reference to the cached success value. The error type must
1117		/// be `Clone` because the new cell owns its own cached result.
1118		#[document_signature]
1119		///
1120		#[document_type_parameters("The type of the mapped success value.")]
1121		///
1122		#[document_parameters("The function to apply to the success value.")]
1123		///
1124		#[document_returns(
1125			"A new `ArcTryLazy` that applies `f` to the success value of this cell."
1126		)]
1127		///
1128		#[document_examples]
1129		///
1130		/// ```
1131		/// use fp_library::types::*;
1132		///
1133		/// let memo = ArcTryLazy::<i32, String>::ok(10);
1134		/// let mapped = memo.map(|a| a * 2);
1135		/// assert_eq!(mapped.evaluate(), Ok(&20));
1136		/// ```
1137		#[inline]
1138		pub fn map<B: 'a>(
1139			self,
1140			f: impl FnOnce(&A) -> B + Send + 'a,
1141		) -> ArcTryLazy<'a, B, E>
1142		where
1143			A: Send + Sync,
1144			E: Clone + Send + Sync, {
1145			ArcTryLazy::new(move || match self.evaluate() {
1146				Ok(a) => Ok(f(a)),
1147				Err(e) => Err(e.clone()),
1148			})
1149		}
1150
1151		/// Maps a function over the memoized success value by reference.
1152		///
1153		/// This is the `ArcTryLazy` counterpart of [`RcTryLazy::ref_map`](TryLazy::ref_map).
1154		/// Evaluates the lazy cell and, if `Ok`, applies `f` to the referenced success value.
1155		/// If `Err`, clones the error into the new cell.
1156		///
1157		/// This is functionally identical to [`map`](TryLazy::map) but exists so that
1158		/// the `SendRefFunctor` trait implementation can delegate to an inherent method,
1159		/// matching the pattern used by [`ArcLazy::ref_map`](crate::types::lazy::Lazy::ref_map).
1160		///
1161		/// Note: A blanket `RefFunctor` trait impl is not provided for `TryLazyBrand<E, ArcLazyConfig>`
1162		/// because the `RefFunctor` trait does not require `Send` on the mapping function, but
1163		/// `ArcTryLazy::new` requires `Send`. This inherent method adds the necessary `Send` bounds
1164		/// explicitly.
1165		///
1166		/// ### Why `E: Clone`?
1167		///
1168		/// The inner cell holds `Result<A, E>`. Mapping the success side requires cloning
1169		/// the error out of the `&E` reference when the result is `Err`, because the new
1170		/// cell must own its own cached `Result<B, E>`.
1171		#[document_signature]
1172		#[document_type_parameters("The type of the mapped success value.")]
1173		#[document_parameters("The function to apply to the success value.")]
1174		#[document_returns(
1175			"A new `ArcTryLazy` that applies `f` to the success value of this cell."
1176		)]
1177		#[document_examples]
1178		///
1179		/// ```
1180		/// use fp_library::types::*;
1181		///
1182		/// let memo = ArcTryLazy::<i32, String>::ok(10);
1183		/// let mapped = memo.ref_map(|x| *x * 2);
1184		/// assert_eq!(mapped.evaluate(), Ok(&20));
1185		/// ```
1186		#[inline]
1187		pub fn ref_map<B: 'a>(
1188			self,
1189			f: impl FnOnce(&A) -> B + Send + 'a,
1190		) -> ArcTryLazy<'a, B, E>
1191		where
1192			A: Send + Sync,
1193			E: Clone + Send + Sync, {
1194			ArcTryLazy::new(move || match self.evaluate() {
1195				Ok(a) => Ok(f(a)),
1196				Err(e) => Err(e.clone()),
1197			})
1198		}
1199
1200		/// Transforms the error value by creating a new thread-safe `TryLazy` cell.
1201		///
1202		/// The original cell is evaluated on first access of the new cell. The mapping
1203		/// function receives a reference to the cached error value. The success type must
1204		/// be `Clone` because the new cell owns its own cached result.
1205		#[document_signature]
1206		///
1207		#[document_type_parameters("The type of the mapped error value.")]
1208		///
1209		#[document_parameters("The function to apply to the error value.")]
1210		///
1211		#[document_returns("A new `ArcTryLazy` that applies `f` to the error value of this cell.")]
1212		///
1213		#[document_examples]
1214		///
1215		/// ```
1216		/// use fp_library::types::*;
1217		///
1218		/// let memo = ArcTryLazy::<i32, String>::err("error".to_string());
1219		/// let mapped = memo.map_err(|e| format!("wrapped: {}", e));
1220		/// assert_eq!(mapped.evaluate(), Err(&"wrapped: error".to_string()));
1221		/// ```
1222		#[inline]
1223		pub fn map_err<E2: 'a>(
1224			self,
1225			f: impl FnOnce(&E) -> E2 + Send + 'a,
1226		) -> ArcTryLazy<'a, A, E2>
1227		where
1228			A: Clone + Send + Sync,
1229			E: Send + Sync, {
1230			ArcTryLazy::new(move || match self.evaluate() {
1231				Ok(a) => Ok(a.clone()),
1232				Err(e) => Err(f(e)),
1233			})
1234		}
1235
1236		/// Transforms both the success and error values by creating a new thread-safe
1237		/// `TryLazy` cell.
1238		///
1239		/// The original cell is evaluated on first access of the new cell. The success
1240		/// mapping function `f` receives a reference to the cached success value, and the
1241		/// error mapping function `g` receives a reference to the cached error value.
1242		/// Unlike `map` (which requires `E: Clone`) or `map_err` (which requires `A: Clone`),
1243		/// `bimap` needs neither because each branch is fully transformed.
1244		#[document_signature]
1245		///
1246		#[document_type_parameters(
1247			"The type of the mapped success value.",
1248			"The type of the mapped error value."
1249		)]
1250		///
1251		#[document_parameters(
1252			"The function to apply to the success value.",
1253			"The function to apply to the error value."
1254		)]
1255		///
1256		#[document_returns(
1257			"A new `ArcTryLazy` that applies `f` to the success value or `g` to the error value of this cell."
1258		)]
1259		///
1260		#[document_examples]
1261		///
1262		/// ```
1263		/// use fp_library::types::*;
1264		///
1265		/// let ok_memo = ArcTryLazy::<i32, String>::ok(10);
1266		/// let mapped = ok_memo.bimap(|a| a * 2, |e| e.len());
1267		/// assert_eq!(mapped.evaluate(), Ok(&20));
1268		///
1269		/// let err_memo = ArcTryLazy::<i32, String>::err("error".to_string());
1270		/// let mapped = err_memo.bimap(|a| a * 2, |e| e.len());
1271		/// assert_eq!(mapped.evaluate(), Err(&5));
1272		/// ```
1273		#[inline]
1274		pub fn bimap<B: 'a, F: 'a>(
1275			self,
1276			f: impl FnOnce(&A) -> B + Send + 'a,
1277			g: impl FnOnce(&E) -> F + Send + 'a,
1278		) -> ArcTryLazy<'a, B, F>
1279		where
1280			A: Send + Sync,
1281			E: Send + Sync, {
1282			ArcTryLazy::new(move || match self.evaluate() {
1283				Ok(a) => Ok(f(a)),
1284				Err(e) => Err(g(e)),
1285			})
1286		}
1287	}
1288
1289	#[document_type_parameters(
1290		"The lifetime of the computation.",
1291		"The type of the computed value.",
1292		"The type of the error value."
1293	)]
1294	impl<'a, A: 'a, E: 'a> TryLazy<'a, A, E, ArcLazyConfig> {
1295		/// Creates a thread-safe `TryLazy` that catches unwinds (panics),
1296		/// converting the panic payload using a custom conversion function.
1297		///
1298		/// The closure `f` is executed when the lazy cell is first evaluated.
1299		/// If `f` panics, the panic payload is passed to `handler` to produce
1300		/// the error value. If `f` returns normally, the value is wrapped in `Ok`.
1301		#[document_signature]
1302		///
1303		#[document_parameters(
1304			"The closure that might panic.",
1305			"The function that converts a panic payload into the error type."
1306		)]
1307		///
1308		#[document_returns(
1309			"A new `ArcTryLazy` instance where panics are converted to `Err(E)` via the handler."
1310		)]
1311		///
1312		#[document_examples]
1313		///
1314		/// ```
1315		/// use fp_library::types::*;
1316		///
1317		/// let memo = ArcTryLazy::<i32, i32>::catch_unwind_with(
1318		/// 	|| {
1319		/// 		if true {
1320		/// 			panic!("oops")
1321		/// 		}
1322		/// 		42
1323		/// 	},
1324		/// 	|_payload| -1,
1325		/// );
1326		/// assert_eq!(memo.evaluate(), Err(&-1));
1327		/// ```
1328		pub fn catch_unwind_with(
1329			f: impl FnOnce() -> A + std::panic::UnwindSafe + Send + 'a,
1330			handler: impl FnOnce(Box<dyn std::any::Any + Send>) -> E + Send + 'a,
1331		) -> Self {
1332			Self::new(move || std::panic::catch_unwind(f).map_err(handler))
1333		}
1334	}
1335
1336	#[document_type_parameters(
1337		"The lifetime of the computation.",
1338		"The type of the computed value."
1339	)]
1340	impl<'a, A> TryLazy<'a, A, String, ArcLazyConfig>
1341	where
1342		A: 'a,
1343	{
1344		/// Creates a thread-safe `TryLazy` that catches unwinds (panics).
1345		///
1346		/// The closure is executed when the lazy cell is first evaluated. If the
1347		/// closure panics, the panic payload is converted to a `String` error and
1348		/// cached. If the closure returns normally, the value is cached as `Ok`.
1349		///
1350		/// This is a convenience wrapper around [`catch_unwind_with`](TryLazy::catch_unwind_with)
1351		/// that uses the default panic payload to string conversion.
1352		#[document_signature]
1353		///
1354		#[document_parameters("The closure that might panic.")]
1355		///
1356		#[document_returns(
1357			"A new `ArcTryLazy` instance where panics are converted to `Err(String)`."
1358		)]
1359		///
1360		#[document_examples]
1361		///
1362		/// ```
1363		/// use fp_library::types::*;
1364		///
1365		/// let memo = TryLazy::<_, String, ArcLazyConfig>::catch_unwind(|| {
1366		/// 	if true {
1367		/// 		panic!("oops")
1368		/// 	}
1369		/// 	42
1370		/// });
1371		/// assert_eq!(memo.evaluate(), Err(&"oops".to_string()));
1372		/// ```
1373		pub fn catch_unwind(f: impl FnOnce() -> A + std::panic::UnwindSafe + Send + 'a) -> Self {
1374			Self::catch_unwind_with(f, crate::utils::panic_payload_to_string)
1375		}
1376	}
1377
1378	#[document_type_parameters(
1379		"The lifetime of the computation.",
1380		"The type of the computed value.",
1381		"The type of the error."
1382	)]
1383	impl<'a, A, E> Deferrable<'a> for TryLazy<'a, A, E, RcLazyConfig>
1384	where
1385		A: Clone + 'a,
1386		E: Clone + 'a,
1387	{
1388		/// Defers a computation that produces a `TryLazy` value.
1389		///
1390		/// This flattens the nested structure: instead of `TryLazy<TryLazy<A, E>, E>`, we get `TryLazy<A, E>`.
1391		/// The inner `TryLazy` is computed only when the outer `TryLazy` is evaluated.
1392		#[document_signature]
1393		///
1394		#[document_parameters("The thunk that produces the lazy value.")]
1395		///
1396		#[document_returns("A new `TryLazy` value.")]
1397		///
1398		#[document_examples]
1399		///
1400		/// ```
1401		/// use fp_library::{
1402		/// 	brands::*,
1403		/// 	classes::*,
1404		/// 	functions::*,
1405		/// 	types::*,
1406		/// };
1407		///
1408		/// let lazy = TryLazy::<_, (), RcLazyConfig>::defer(|| RcTryLazy::new(|| Ok(42)));
1409		/// assert_eq!(lazy.evaluate(), Ok(&42));
1410		/// ```
1411		fn defer(f: impl FnOnce() -> Self + 'a) -> Self
1412		where
1413			Self: Sized, {
1414			Self::new(move || match f().evaluate() {
1415				Ok(a) => Ok(a.clone()),
1416				Err(e) => Err(e.clone()),
1417			})
1418		}
1419	}
1420
1421	impl_kind! {
1422		impl<E: 'static, Config: TryLazyConfig> for TryLazyBrand<E, Config> {
1423			#[document_default]
1424			type Of<'a, A: 'a>: 'a = TryLazy<'a, A, E, Config>;
1425		}
1426	}
1427
1428	#[document_type_parameters(
1429		"The lifetime of the computation.",
1430		"The success value type.",
1431		"The type of the error."
1432	)]
1433	impl<'a, A: Semigroup + Clone + 'a, E: Clone + 'a> Semigroup for TryLazy<'a, A, E, RcLazyConfig> {
1434		/// Combines two `RcTryLazy` values by combining their success values.
1435		///
1436		/// Evaluates `a` first. If `a` is `Err`, returns the error immediately without
1437		/// evaluating `b`. If both succeed, combines the values using `Semigroup::append`.
1438		#[document_signature]
1439		///
1440		#[document_parameters("The first `TryLazy`.", "The second `TryLazy`.")]
1441		///
1442		#[document_returns("A new `RcTryLazy` containing the combined result.")]
1443		///
1444		#[document_examples]
1445		///
1446		/// ```
1447		/// use fp_library::{
1448		/// 	classes::*,
1449		/// 	functions::*,
1450		/// 	types::*,
1451		/// };
1452		///
1453		/// let a: RcTryLazy<String, ()> = RcTryLazy::new(|| Ok("Hello".to_string()));
1454		/// let b: RcTryLazy<String, ()> = RcTryLazy::new(|| Ok(" World".to_string()));
1455		/// let c = append::<_>(a, b);
1456		/// assert_eq!(c.evaluate(), Ok(&"Hello World".to_string()));
1457		/// ```
1458		fn append(
1459			a: Self,
1460			b: Self,
1461		) -> Self {
1462			RcTryLazy::new(move || {
1463				let a_val = match a.evaluate() {
1464					Ok(v) => v.clone(),
1465					Err(e) => return Err(e.clone()),
1466				};
1467				let b_val = match b.evaluate() {
1468					Ok(v) => v.clone(),
1469					Err(e) => return Err(e.clone()),
1470				};
1471				Ok(Semigroup::append(a_val, b_val))
1472			})
1473		}
1474	}
1475
1476	#[document_type_parameters(
1477		"The lifetime of the computation.",
1478		"The success value type.",
1479		"The type of the error."
1480	)]
1481	impl<'a, A: Semigroup + Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a> Semigroup
1482		for TryLazy<'a, A, E, ArcLazyConfig>
1483	{
1484		/// Combines two `ArcTryLazy` values by combining their success values.
1485		///
1486		/// Evaluates `a` first. If `a` is `Err`, returns the error immediately without
1487		/// evaluating `b`. If both succeed, combines the values using `Semigroup::append`.
1488		#[document_signature]
1489		///
1490		#[document_parameters("The first `ArcTryLazy`.", "The second `ArcTryLazy`.")]
1491		///
1492		#[document_returns("A new `ArcTryLazy` containing the combined result.")]
1493		///
1494		#[document_examples]
1495		///
1496		/// ```
1497		/// use fp_library::{
1498		/// 	classes::*,
1499		/// 	functions::*,
1500		/// 	types::*,
1501		/// };
1502		///
1503		/// let a: ArcTryLazy<String, ()> = ArcTryLazy::new(|| Ok("Hello".to_string()));
1504		/// let b: ArcTryLazy<String, ()> = ArcTryLazy::new(|| Ok(" World".to_string()));
1505		/// let c = append::<_>(a, b);
1506		/// assert_eq!(c.evaluate(), Ok(&"Hello World".to_string()));
1507		/// ```
1508		fn append(
1509			a: Self,
1510			b: Self,
1511		) -> Self {
1512			ArcTryLazy::new(move || {
1513				let a_val = match a.evaluate() {
1514					Ok(v) => v.clone(),
1515					Err(e) => return Err(e.clone()),
1516				};
1517				let b_val = match b.evaluate() {
1518					Ok(v) => v.clone(),
1519					Err(e) => return Err(e.clone()),
1520				};
1521				Ok(Semigroup::append(a_val, b_val))
1522			})
1523		}
1524	}
1525
1526	#[document_type_parameters("The error type.", "The memoization configuration.")]
1527	impl<E: 'static, Config: TryLazyConfig> Foldable for TryLazyBrand<E, Config> {
1528		/// Folds the `TryLazy` from the right.
1529		///
1530		/// If the computation succeeded, applies `func` to the success value and the
1531		/// initial accumulator. If it failed, returns the initial accumulator unchanged
1532		/// (the error is discarded).
1533		#[document_signature]
1534		///
1535		#[document_type_parameters(
1536			"The lifetime of the computation.",
1537			"The brand of the cloneable function to use.",
1538			"The type of the elements in the structure.",
1539			"The type of the accumulator."
1540		)]
1541		///
1542		#[document_parameters(
1543			"The function to apply to each element and the accumulator.",
1544			"The initial value of the accumulator.",
1545			"The `TryLazy` to fold."
1546		)]
1547		///
1548		#[document_returns("The final accumulator value.")]
1549		#[document_examples]
1550		///
1551		/// ```
1552		/// use fp_library::{
1553		/// 	brands::*,
1554		/// 	functions::*,
1555		/// 	types::*,
1556		/// };
1557		///
1558		/// let memo: RcTryLazy<i32, ()> = RcTryLazy::new(|| Ok(10));
1559		/// let result =
1560		/// 	fold_right::<RcFnBrand, TryLazyBrand<(), RcLazyConfig>, _, _>(|a, b| a + b, 5, memo);
1561		/// assert_eq!(result, 15);
1562		/// ```
1563		fn fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
1564			func: impl Fn(A, B) -> B + 'a,
1565			initial: B,
1566			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1567		) -> B
1568		where
1569			FnBrand: CloneableFn + 'a, {
1570			match fa.evaluate() {
1571				Ok(a) => func(a.clone(), initial),
1572				Err(_) => initial,
1573			}
1574		}
1575
1576		/// Folds the `TryLazy` from the left.
1577		///
1578		/// If the computation succeeded, applies `func` to the initial accumulator and
1579		/// the success value. If it failed, returns the initial accumulator unchanged
1580		/// (the error is discarded).
1581		#[document_signature]
1582		///
1583		#[document_type_parameters(
1584			"The lifetime of the computation.",
1585			"The brand of the cloneable function to use.",
1586			"The type of the elements in the structure.",
1587			"The type of the accumulator."
1588		)]
1589		///
1590		#[document_parameters(
1591			"The function to apply to the accumulator and each element.",
1592			"The initial value of the accumulator.",
1593			"The `TryLazy` to fold."
1594		)]
1595		///
1596		#[document_returns("The final accumulator value.")]
1597		#[document_examples]
1598		///
1599		/// ```
1600		/// use fp_library::{
1601		/// 	brands::*,
1602		/// 	functions::*,
1603		/// 	types::*,
1604		/// };
1605		///
1606		/// let memo: RcTryLazy<i32, ()> = RcTryLazy::new(|| Ok(10));
1607		/// let result =
1608		/// 	fold_left::<RcFnBrand, TryLazyBrand<(), RcLazyConfig>, _, _>(|b, a| b + a, 5, memo);
1609		/// assert_eq!(result, 15);
1610		/// ```
1611		fn fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
1612			func: impl Fn(B, A) -> B + 'a,
1613			initial: B,
1614			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1615		) -> B
1616		where
1617			FnBrand: CloneableFn + 'a, {
1618			match fa.evaluate() {
1619				Ok(a) => func(initial, a.clone()),
1620				Err(_) => initial,
1621			}
1622		}
1623
1624		/// Maps the success value to a monoid and returns it.
1625		///
1626		/// Forces evaluation and, if the computation succeeded, maps the value.
1627		/// If the computation failed, returns the monoid identity element.
1628		#[document_signature]
1629		///
1630		#[document_type_parameters(
1631			"The lifetime of the computation.",
1632			"The brand of the cloneable function to use.",
1633			"The type of the elements in the structure.",
1634			"The type of the monoid."
1635		)]
1636		///
1637		#[document_parameters("The mapping function.", "The TryLazy to fold.")]
1638		///
1639		#[document_returns("The monoid value.")]
1640		#[document_examples]
1641		///
1642		/// ```
1643		/// use fp_library::{
1644		/// 	brands::*,
1645		/// 	functions::*,
1646		/// 	types::*,
1647		/// };
1648		///
1649		/// let memo: RcTryLazy<i32, ()> = RcTryLazy::new(|| Ok(10));
1650		/// let result = fold_map::<RcFnBrand, TryLazyBrand<(), RcLazyConfig>, _, String>(
1651		/// 	|a: i32| a.to_string(),
1652		/// 	memo,
1653		/// );
1654		/// assert_eq!(result, "10");
1655		/// ```
1656		fn fold_map<'a, FnBrand, A: 'a + Clone, R: Monoid>(
1657			func: impl Fn(A) -> R + 'a,
1658			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1659		) -> R
1660		where
1661			FnBrand: CloneableFn + 'a, {
1662			match fa.evaluate() {
1663				Ok(a) => func(a.clone()),
1664				Err(_) => Monoid::empty(),
1665			}
1666		}
1667	}
1668
1669	// --- WithIndex ---
1670
1671	#[document_type_parameters("The error type.", "The memoization configuration.")]
1672	impl<E: 'static, Config: TryLazyConfig> WithIndex for TryLazyBrand<E, Config> {
1673		type Index = ();
1674	}
1675
1676	// --- FoldableWithIndex ---
1677
1678	#[document_type_parameters("The error type.", "The memoization configuration.")]
1679	impl<E: 'static, Config: TryLazyConfig> FoldableWithIndex for TryLazyBrand<E, Config> {
1680		/// Folds the `TryLazy` using a monoid, providing the index `()`.
1681		///
1682		/// Forces evaluation and, if the computation succeeded, maps the value with
1683		/// the unit index. If the computation failed, returns the monoid identity
1684		/// element.
1685		#[document_signature]
1686		///
1687		#[document_type_parameters(
1688			"The lifetime of the computation.",
1689			"The type of the computed value.",
1690			"The monoid type."
1691		)]
1692		///
1693		#[document_parameters(
1694			"The function to apply to the index and the value.",
1695			"The `TryLazy` to fold."
1696		)]
1697		///
1698		#[document_returns("The monoid value.")]
1699		#[document_examples]
1700		///
1701		/// ```
1702		/// use fp_library::{
1703		/// 	brands::*,
1704		/// 	classes::foldable_with_index::FoldableWithIndex,
1705		/// 	types::*,
1706		/// };
1707		///
1708		/// let lazy: RcTryLazy<i32, ()> = RcTryLazy::new(|| Ok(10));
1709		/// let result = <TryLazyBrand<(), RcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
1710		/// 	|_, x: i32| x.to_string(),
1711		/// 	lazy,
1712		/// );
1713		/// assert_eq!(result, "10");
1714		/// ```
1715		fn fold_map_with_index<'a, A: 'a + Clone, R: Monoid>(
1716			f: impl Fn((), A) -> R + 'a,
1717			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1718		) -> R {
1719			match fa.evaluate() {
1720				Ok(a) => f((), a.clone()),
1721				Err(_) => Monoid::empty(),
1722			}
1723		}
1724	}
1725
1726	#[document_type_parameters(
1727		"The lifetime of the computation.",
1728		"The type of the computed value.",
1729		"The type of the error."
1730	)]
1731	impl<'a, A, E> Deferrable<'a> for TryLazy<'a, A, E, ArcLazyConfig>
1732	where
1733		A: Clone + Send + Sync + 'a,
1734		E: Clone + Send + Sync + 'a,
1735	{
1736		/// Defers a computation that produces a thread-safe `TryLazy` value.
1737		///
1738		/// The thunk `f` is called eagerly to obtain the inner `ArcTryLazy`, which
1739		/// is then returned directly. The inner `ArcTryLazy` retains its own lazy
1740		/// semantics, so the underlying computation is still deferred. This eager
1741		/// call to `f` is necessary because `Deferrable::defer` does not require
1742		/// `Send` on the thunk, while `ArcTryLazy::new` does.
1743		#[document_signature]
1744		///
1745		#[document_parameters("The thunk that produces the lazy value.")]
1746		///
1747		#[document_returns("A new `ArcTryLazy` value.")]
1748		///
1749		#[document_examples]
1750		///
1751		/// ```
1752		/// use fp_library::{
1753		/// 	brands::*,
1754		/// 	classes::*,
1755		/// 	functions::*,
1756		/// 	types::*,
1757		/// };
1758		///
1759		/// let lazy: ArcTryLazy<i32, ()> = defer(|| ArcTryLazy::new(|| Ok(42)));
1760		/// assert_eq!(lazy.evaluate(), Ok(&42));
1761		/// ```
1762		fn defer(f: impl FnOnce() -> Self + 'a) -> Self
1763		where
1764			Self: Sized, {
1765			f()
1766		}
1767	}
1768
1769	#[document_type_parameters(
1770		"The lifetime of the computation.",
1771		"The type of the computed value.",
1772		"The type of the error."
1773	)]
1774	impl<'a, A, E> SendDeferrable<'a> for TryLazy<'a, A, E, ArcLazyConfig>
1775	where
1776		A: Clone + Send + Sync + 'a,
1777		E: Clone + Send + Sync + 'a,
1778	{
1779		/// Defers a computation that produces a thread-safe `TryLazy` value using a thread-safe thunk.
1780		///
1781		/// This flattens the nested structure: instead of `ArcTryLazy<ArcTryLazy<A, E>, E>`, we get `ArcTryLazy<A, E>`.
1782		/// The inner `TryLazy` is computed only when the outer `TryLazy` is evaluated.
1783		#[document_signature]
1784		///
1785		#[document_parameters("The thunk that produces the lazy value.")]
1786		///
1787		#[document_returns("A new `ArcTryLazy` value.")]
1788		///
1789		#[document_examples]
1790		///
1791		/// ```
1792		/// use fp_library::{
1793		/// 	brands::*,
1794		/// 	classes::*,
1795		/// 	types::*,
1796		/// };
1797		///
1798		/// let lazy: ArcTryLazy<i32, ()> = ArcTryLazy::send_defer(|| ArcTryLazy::new(|| Ok(42)));
1799		/// assert_eq!(lazy.evaluate(), Ok(&42));
1800		/// ```
1801		fn send_defer(f: impl FnOnce() -> Self + Send + 'a) -> Self
1802		where
1803			Self: Sized, {
1804			Self::new(move || match f().evaluate() {
1805				Ok(a) => Ok(a.clone()),
1806				Err(e) => Err(e.clone()),
1807			})
1808		}
1809	}
1810
1811	/// Single-threaded fallible memoization alias.
1812	pub type RcTryLazy<'a, A, E> = TryLazy<'a, A, E, RcLazyConfig>;
1813
1814	/// Thread-safe fallible memoization alias.
1815	pub type ArcTryLazy<'a, A, E> = TryLazy<'a, A, E, ArcLazyConfig>;
1816
1817	// --- RefFunctor ---
1818
1819	#[document_type_parameters("The type of the error.")]
1820	impl<E: 'static + Clone> RefFunctor for TryLazyBrand<E, RcLazyConfig> {
1821		/// Maps a function over the success value of the memoized result, where the function takes a reference.
1822		///
1823		/// Evaluates the `TryLazy` and, if `Ok`, applies `f` to the referenced success value.
1824		/// If `Err`, clones the error into the new cell.
1825		#[document_signature]
1826		///
1827		#[document_type_parameters(
1828			"The lifetime of the values.",
1829			"The type of the success value.",
1830			"The type of the result."
1831		)]
1832		///
1833		#[document_parameters(
1834			"The function to apply to the success value.",
1835			"The memoized fallible value."
1836		)]
1837		///
1838		#[document_returns("A new memoized fallible value containing the mapped result.")]
1839		///
1840		#[document_examples]
1841		///
1842		/// ```
1843		/// use fp_library::{
1844		/// 	brands::*,
1845		/// 	classes::*,
1846		/// 	types::*,
1847		/// };
1848		///
1849		/// let memo = RcTryLazy::<i32, String>::ok(10);
1850		/// let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x * 2, memo);
1851		/// assert_eq!(mapped.evaluate(), Ok(&20));
1852		/// ```
1853		fn ref_map<'a, A: 'a, B: 'a>(
1854			f: impl FnOnce(&A) -> B + 'a,
1855			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1856		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1857			fa.ref_map(f)
1858		}
1859	}
1860
1861	// --- SendRefFunctor ---
1862
1863	#[document_type_parameters("The type of the error.")]
1864	impl<E: 'static + Clone + Send + Sync> SendRefFunctor for TryLazyBrand<E, ArcLazyConfig> {
1865		/// Maps a thread-safe function over the success value of the memoized result, where the function takes a reference.
1866		///
1867		/// Evaluates the `TryLazy` and, if `Ok`, applies `f` to the referenced success value.
1868		/// If `Err`, clones the error into the new cell.
1869		#[document_signature]
1870		///
1871		#[document_type_parameters(
1872			"The lifetime of the values.",
1873			"The type of the success value.",
1874			"The type of the result."
1875		)]
1876		///
1877		#[document_parameters(
1878			"The function to apply to the success value.",
1879			"The memoized fallible value."
1880		)]
1881		///
1882		#[document_returns("A new memoized fallible value containing the mapped result.")]
1883		///
1884		#[document_examples]
1885		///
1886		/// ```
1887		/// use fp_library::{
1888		/// 	brands::*,
1889		/// 	classes::*,
1890		/// 	types::*,
1891		/// };
1892		///
1893		/// let memo = ArcTryLazy::<i32, String>::ok(10);
1894		/// let mapped = TryLazyBrand::<String, ArcLazyConfig>::send_ref_map(|x: &i32| *x * 2, memo);
1895		/// assert_eq!(mapped.evaluate(), Ok(&20));
1896		/// ```
1897		fn send_ref_map<'a, A: Send + Sync + 'a, B: Send + Sync + 'a>(
1898			f: impl FnOnce(&A) -> B + Send + 'a,
1899			fa: Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
1900		) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
1901			fa.ref_map(f)
1902		}
1903	}
1904
1905	// --- Monoid ---
1906
1907	#[document_type_parameters(
1908		"The lifetime of the computation.",
1909		"The type of the computed value.",
1910		"The type of the error."
1911	)]
1912	impl<'a, A: Monoid + Clone + 'a, E: Clone + 'a> Monoid for TryLazy<'a, A, E, RcLazyConfig> {
1913		/// Returns the identity `RcTryLazy`, which evaluates to `Ok(A::empty())`.
1914		#[document_signature]
1915		///
1916		#[document_returns("An `RcTryLazy` producing the identity value wrapped in `Ok`.")]
1917		///
1918		#[document_examples]
1919		///
1920		/// ```
1921		/// use fp_library::{
1922		/// 	functions::*,
1923		/// 	types::*,
1924		/// };
1925		///
1926		/// let t: RcTryLazy<String, ()> = empty();
1927		/// assert_eq!(t.evaluate(), Ok(&String::new()));
1928		/// ```
1929		fn empty() -> Self {
1930			RcTryLazy::new(|| Ok(Monoid::empty()))
1931		}
1932	}
1933
1934	#[document_type_parameters(
1935		"The lifetime of the computation.",
1936		"The type of the computed value.",
1937		"The type of the error."
1938	)]
1939	impl<'a, A: Monoid + Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a> Monoid
1940		for TryLazy<'a, A, E, ArcLazyConfig>
1941	{
1942		/// Returns the identity `ArcTryLazy`, which evaluates to `Ok(A::empty())`.
1943		#[document_signature]
1944		///
1945		#[document_returns("An `ArcTryLazy` producing the identity value wrapped in `Ok`.")]
1946		///
1947		#[document_examples]
1948		///
1949		/// ```
1950		/// use fp_library::{
1951		/// 	functions::*,
1952		/// 	types::*,
1953		/// };
1954		///
1955		/// let t: ArcTryLazy<String, ()> = empty();
1956		/// assert_eq!(t.evaluate(), Ok(&String::new()));
1957		/// ```
1958		fn empty() -> Self {
1959			ArcTryLazy::new(|| Ok(Monoid::empty()))
1960		}
1961	}
1962
1963	// --- Hash ---
1964
1965	#[document_type_parameters(
1966		"The lifetime of the computation.",
1967		"The type of the computed value.",
1968		"The type of the error.",
1969		"The memoization configuration."
1970	)]
1971	#[document_parameters("The try-lazy value to hash.")]
1972	impl<'a, A: Hash + 'a, E: Hash + 'a, Config: TryLazyConfig> Hash for TryLazy<'a, A, E, Config> {
1973		/// Forces evaluation and hashes the result.
1974		#[document_signature]
1975		#[document_type_parameters("The type of the hasher.")]
1976		///
1977		#[document_parameters("The hasher state.")]
1978		///
1979		#[document_examples]
1980		///
1981		/// ```
1982		/// use {
1983		/// 	fp_library::types::*,
1984		/// 	std::{
1985		/// 		collections::hash_map::DefaultHasher,
1986		/// 		hash::{
1987		/// 			Hash,
1988		/// 			Hasher,
1989		/// 		},
1990		/// 	},
1991		/// };
1992		///
1993		/// let lazy = RcTryLazy::<i32, ()>::new(|| Ok(42));
1994		/// let mut hasher = DefaultHasher::new();
1995		/// lazy.hash(&mut hasher);
1996		/// let h1 = hasher.finish();
1997		///
1998		/// let mut hasher = DefaultHasher::new();
1999		/// Ok::<i32, ()>(42).hash(&mut hasher);
2000		/// let h2 = hasher.finish();
2001		///
2002		/// assert_eq!(h1, h2);
2003		///
2004		/// let lazy = ArcTryLazy::<i32, ()>::new(|| Ok(42));
2005		/// let mut hasher = DefaultHasher::new();
2006		/// lazy.hash(&mut hasher);
2007		/// let h3 = hasher.finish();
2008		///
2009		/// assert_eq!(h1, h3);
2010		/// ```
2011		fn hash<H: Hasher>(
2012			&self,
2013			state: &mut H,
2014		) {
2015			self.evaluate().hash(state)
2016		}
2017	}
2018
2019	// --- PartialEq ---
2020
2021	#[document_type_parameters(
2022		"The lifetime of the computation.",
2023		"The type of the computed value.",
2024		"The type of the error.",
2025		"The memoization configuration."
2026	)]
2027	#[document_parameters("The try-lazy value to compare.")]
2028	impl<'a, A: PartialEq + 'a, E: PartialEq + 'a, Config: TryLazyConfig> PartialEq
2029		for TryLazy<'a, A, E, Config>
2030	{
2031		/// Compares two `TryLazy` values for equality by forcing evaluation of both sides.
2032		///
2033		/// Note: This will trigger computation if either value has not yet been evaluated.
2034		#[document_signature]
2035		#[document_parameters("The other try-lazy value to compare with.")]
2036		#[document_returns("`true` if the evaluated results are equal.")]
2037		#[document_examples]
2038		///
2039		/// ```
2040		/// use fp_library::types::*;
2041		///
2042		/// let a = RcTryLazy::<i32, ()>::new(|| Ok(42));
2043		/// let b = RcTryLazy::<i32, ()>::new(|| Ok(42));
2044		/// assert!(a == b);
2045		/// ```
2046		fn eq(
2047			&self,
2048			other: &Self,
2049		) -> bool {
2050			self.evaluate() == other.evaluate()
2051		}
2052	}
2053
2054	// --- PartialOrd ---
2055
2056	#[document_type_parameters(
2057		"The lifetime of the computation.",
2058		"The type of the computed value.",
2059		"The type of the error.",
2060		"The memoization configuration."
2061	)]
2062	#[document_parameters("The try-lazy value to compare.")]
2063	impl<'a, A: PartialOrd + 'a, E: PartialOrd + 'a, Config: TryLazyConfig> PartialOrd
2064		for TryLazy<'a, A, E, Config>
2065	{
2066		/// Compares two `TryLazy` values for ordering by forcing evaluation of both sides.
2067		///
2068		/// Note: This will trigger computation if either value has not yet been evaluated.
2069		#[document_signature]
2070		#[document_parameters("The other try-lazy value to compare with.")]
2071		#[document_returns(
2072			"The ordering between the evaluated results, or `None` if not comparable."
2073		)]
2074		#[document_examples]
2075		///
2076		/// ```
2077		/// use fp_library::types::*;
2078		///
2079		/// let a = RcTryLazy::<i32, ()>::new(|| Ok(1));
2080		/// let b = RcTryLazy::<i32, ()>::new(|| Ok(2));
2081		/// assert!(a < b);
2082		/// ```
2083		fn partial_cmp(
2084			&self,
2085			other: &Self,
2086		) -> Option<std::cmp::Ordering> {
2087			self.evaluate().partial_cmp(&other.evaluate())
2088		}
2089	}
2090
2091	// --- Eq ---
2092
2093	#[document_type_parameters(
2094		"The lifetime of the computation.",
2095		"The type of the computed value.",
2096		"The type of the error.",
2097		"The memoization configuration."
2098	)]
2099	impl<'a, A: Eq + 'a, E: Eq + 'a, Config: TryLazyConfig> Eq for TryLazy<'a, A, E, Config> {}
2100
2101	// --- Ord ---
2102
2103	#[document_type_parameters(
2104		"The lifetime of the computation.",
2105		"The type of the computed value.",
2106		"The type of the error.",
2107		"The memoization configuration."
2108	)]
2109	#[document_parameters("The try-lazy value to compare.")]
2110	impl<'a, A: Ord + 'a, E: Ord + 'a, Config: TryLazyConfig> Ord for TryLazy<'a, A, E, Config> {
2111		/// Compares two `TryLazy` values for ordering by forcing evaluation of both sides.
2112		///
2113		/// Note: This will trigger computation if either value has not yet been evaluated.
2114		#[document_signature]
2115		#[document_parameters("The other try-lazy value to compare with.")]
2116		#[document_returns("The ordering between the evaluated results.")]
2117		#[document_examples]
2118		///
2119		/// ```
2120		/// use fp_library::types::*;
2121		///
2122		/// let a = RcTryLazy::<i32, ()>::new(|| Ok(1));
2123		/// let b = RcTryLazy::<i32, ()>::new(|| Ok(2));
2124		/// assert_eq!(a.cmp(&b), std::cmp::Ordering::Less);
2125		/// ```
2126		fn cmp(
2127			&self,
2128			other: &Self,
2129		) -> std::cmp::Ordering {
2130			self.evaluate().cmp(&other.evaluate())
2131		}
2132	}
2133
2134	// --- Display ---
2135
2136	#[document_type_parameters(
2137		"The lifetime of the computation.",
2138		"The type of the computed value.",
2139		"The type of the error.",
2140		"The memoization configuration."
2141	)]
2142	#[document_parameters("The try-lazy value to display.")]
2143	impl<'a, A: fmt::Display + 'a, E: fmt::Display + 'a, Config: TryLazyConfig> fmt::Display
2144		for TryLazy<'a, A, E, Config>
2145	{
2146		/// Forces evaluation and displays `Ok(value)` or `Err(error)`.
2147		#[document_signature]
2148		///
2149		#[document_parameters("The formatter.")]
2150		///
2151		#[document_returns("The formatting result.")]
2152		///
2153		#[document_examples]
2154		///
2155		/// ```
2156		/// use fp_library::types::*;
2157		///
2158		/// let ok_lazy = RcTryLazy::<i32, String>::ok(42);
2159		/// assert_eq!(format!("{}", ok_lazy), "Ok(42)");
2160		///
2161		/// let err_lazy = RcTryLazy::<i32, String>::err("oops".to_string());
2162		/// assert_eq!(format!("{}", err_lazy), "Err(oops)");
2163		///
2164		/// let ok_arc = ArcTryLazy::<i32, String>::ok(42);
2165		/// assert_eq!(format!("{}", ok_arc), "Ok(42)");
2166		///
2167		/// let err_arc = ArcTryLazy::<i32, String>::err("oops".to_string());
2168		/// assert_eq!(format!("{}", err_arc), "Err(oops)");
2169		/// ```
2170		fn fmt(
2171			&self,
2172			f: &mut fmt::Formatter<'_>,
2173		) -> fmt::Result {
2174			match self.evaluate() {
2175				Ok(a) => write!(f, "Ok({})", a),
2176				Err(e) => write!(f, "Err({})", e),
2177			}
2178		}
2179	}
2180
2181	// --- Debug ---
2182
2183	#[document_type_parameters(
2184		"The lifetime of the computation.",
2185		"The type of the computed value.",
2186		"The type of the error.",
2187		"The memoization configuration."
2188	)]
2189	#[document_parameters("The try-lazy value to format.")]
2190	impl<'a, A, E, Config: TryLazyConfig> fmt::Debug for TryLazy<'a, A, E, Config>
2191	where
2192		A: 'a,
2193		E: 'a,
2194	{
2195		/// Formats the try-lazy value without evaluating it.
2196		#[document_signature]
2197		#[document_parameters("The formatter.")]
2198		#[document_returns("The formatting result.")]
2199		#[document_examples]
2200		///
2201		/// ```
2202		/// use fp_library::types::*;
2203		/// let memo = TryLazy::<_, _, RcLazyConfig>::new(|| Ok::<i32, ()>(42));
2204		/// assert_eq!(format!("{:?}", memo), "TryLazy(..)");
2205		/// ```
2206		fn fmt(
2207			&self,
2208			f: &mut fmt::Formatter<'_>,
2209		) -> fmt::Result {
2210			f.write_str("TryLazy(..)")
2211		}
2212	}
2213
2214	// --- Fix combinators ---
2215
2216	/// Computes a fixed point for `RcTryLazy`.
2217	///
2218	/// Constructs a self-referential `RcTryLazy` where the initializer receives a clone
2219	/// of the resulting fallible lazy cell. This enables recursive definitions where the
2220	/// result depends on the lazy cell itself.
2221	///
2222	/// # Caveats
2223	///
2224	/// **Panic on reentrant evaluation:** Forcing the self-reference inside `f` before
2225	/// the outer cell has completed initialization causes a panic, because `LazyCell`
2226	/// detects the reentrant access.
2227	#[document_signature]
2228	///
2229	#[document_type_parameters(
2230		"The lifetime of the computation.",
2231		"The type of the computed value.",
2232		"The type of the error."
2233	)]
2234	///
2235	#[document_parameters(
2236		"The function that receives a fallible lazy self-reference and produces the result."
2237	)]
2238	///
2239	#[document_returns("A new `RcTryLazy` instance.")]
2240	///
2241	#[document_examples]
2242	///
2243	/// ```
2244	/// use fp_library::types::{
2245	/// 	try_lazy::rc_try_lazy_fix,
2246	/// 	*,
2247	/// };
2248	///
2249	/// let lazy = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, ()>| Ok(42));
2250	/// assert_eq!(lazy.evaluate(), Ok(&42));
2251	/// ```
2252	pub fn rc_try_lazy_fix<'a, A: Clone + 'a, E: Clone + 'a>(
2253		f: impl FnOnce(RcTryLazy<'a, A, E>) -> Result<A, E> + 'a
2254	) -> RcTryLazy<'a, A, E> {
2255		use std::{
2256			cell::OnceCell,
2257			rc::{
2258				Rc,
2259				Weak,
2260			},
2261		};
2262
2263		#[allow(clippy::type_complexity)]
2264		let cell: Rc<
2265			OnceCell<
2266				Weak<std::cell::LazyCell<Result<A, E>, Box<dyn FnOnce() -> Result<A, E> + 'a>>>,
2267			>,
2268		> = Rc::new(OnceCell::new());
2269		let cell_clone = cell.clone();
2270		let lazy = RcTryLazy::new(move || {
2271			// INVARIANT: cell is always set on the line after this closure is
2272			// created, and the outer RcTryLazy is still alive (we are inside its
2273			// evaluation), so the Weak upgrade always succeeds.
2274			#[allow(clippy::expect_used)]
2275			let weak = cell_clone.get().expect("rc_try_lazy_fix: cell not initialized");
2276			#[allow(clippy::expect_used)]
2277			let self_ref = TryLazy(weak.upgrade().expect("rc_try_lazy_fix: outer lazy was dropped"));
2278			f(self_ref)
2279		});
2280		let _ = cell.set(Rc::downgrade(&lazy.0));
2281		lazy
2282	}
2283
2284	/// Computes a fixed point for `ArcTryLazy`.
2285	///
2286	/// Constructs a self-referential `ArcTryLazy` where the initializer receives a clone
2287	/// of the resulting fallible lazy cell. This enables recursive definitions where the
2288	/// result depends on the lazy cell itself.
2289	///
2290	/// # Caveats
2291	///
2292	/// **Deadlock on reentrant evaluation:** Forcing the self-reference inside `f` before
2293	/// the outer cell has completed initialization causes a deadlock, because `LazyLock`
2294	/// blocks on the lock that the current thread already holds.
2295	#[document_signature]
2296	///
2297	#[document_type_parameters(
2298		"The lifetime of the computation.",
2299		"The type of the computed value.",
2300		"The type of the error."
2301	)]
2302	///
2303	#[document_parameters(
2304		"The function that receives a fallible lazy self-reference and produces the result."
2305	)]
2306	///
2307	#[document_returns("A new `ArcTryLazy` instance.")]
2308	///
2309	#[document_examples]
2310	///
2311	/// ```
2312	/// use fp_library::types::{
2313	/// 	try_lazy::arc_try_lazy_fix,
2314	/// 	*,
2315	/// };
2316	///
2317	/// let lazy = arc_try_lazy_fix(|_self_ref: ArcTryLazy<i32, ()>| Ok(42));
2318	/// assert_eq!(lazy.evaluate(), Ok(&42));
2319	/// ```
2320	pub fn arc_try_lazy_fix<'a, A: Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a>(
2321		f: impl FnOnce(ArcTryLazy<'a, A, E>) -> Result<A, E> + Send + 'a
2322	) -> ArcTryLazy<'a, A, E> {
2323		use std::sync::{
2324			Arc,
2325			OnceLock,
2326			Weak,
2327		};
2328
2329		#[allow(clippy::type_complexity)]
2330		let cell: Arc<
2331			OnceLock<
2332				Weak<
2333					std::sync::LazyLock<
2334						Result<A, E>,
2335						Box<dyn FnOnce() -> Result<A, E> + Send + 'a>,
2336					>,
2337				>,
2338			>,
2339		> = Arc::new(OnceLock::new());
2340		let cell_clone = cell.clone();
2341		let lazy = ArcTryLazy::new(move || {
2342			// INVARIANT: cell is always set on the line after this closure is
2343			// created, and the outer ArcTryLazy is still alive (we are inside its
2344			// evaluation), so the Weak upgrade always succeeds.
2345			#[allow(clippy::expect_used)]
2346			let weak = cell_clone.get().expect("arc_try_lazy_fix: cell not initialized");
2347			#[allow(clippy::expect_used)]
2348			let self_ref = TryLazy(weak.upgrade().expect("arc_try_lazy_fix: outer lazy was dropped"));
2349			f(self_ref)
2350		});
2351		let _ = cell.set(Arc::downgrade(&lazy.0));
2352		lazy
2353	}
2354}
2355pub use inner::*;
2356
2357#[cfg(test)]
2358mod tests {
2359	use {
2360		super::*,
2361		crate::{
2362			brands::TryLazyBrand,
2363			types::{
2364				ArcLazyConfig,
2365				RcLazy,
2366				RcLazyConfig,
2367				TrySendThunk,
2368				TryThunk,
2369				TryTrampoline,
2370			},
2371		},
2372		quickcheck_macros::quickcheck,
2373		std::{
2374			cell::RefCell,
2375			rc::Rc,
2376			sync::Arc,
2377		},
2378	};
2379
2380	/// Tests that `TryLazy` caches successful results.
2381	///
2382	/// Verifies that the initializer is called only once for success.
2383	#[test]
2384	fn test_try_memo_caching_ok() {
2385		let counter = Rc::new(RefCell::new(0));
2386		let counter_clone = counter.clone();
2387		let memo: RcTryLazy<i32, ()> = RcTryLazy::new(move || {
2388			*counter_clone.borrow_mut() += 1;
2389			Ok(42)
2390		});
2391
2392		assert_eq!(*counter.borrow(), 0);
2393		assert_eq!(memo.evaluate(), Ok(&42));
2394		assert_eq!(*counter.borrow(), 1);
2395		assert_eq!(memo.evaluate(), Ok(&42));
2396		assert_eq!(*counter.borrow(), 1);
2397	}
2398
2399	/// Tests that `TryLazy` caches error results.
2400	///
2401	/// Verifies that the initializer is called only once for error.
2402	#[test]
2403	fn test_try_memo_caching_err() {
2404		let counter = Rc::new(RefCell::new(0));
2405		let counter_clone = counter.clone();
2406		let memo: RcTryLazy<i32, i32> = RcTryLazy::new(move || {
2407			*counter_clone.borrow_mut() += 1;
2408			Err(0)
2409		});
2410
2411		assert_eq!(*counter.borrow(), 0);
2412		assert_eq!(memo.evaluate(), Err(&0));
2413		assert_eq!(*counter.borrow(), 1);
2414		assert_eq!(memo.evaluate(), Err(&0));
2415		assert_eq!(*counter.borrow(), 1);
2416	}
2417
2418	/// Tests that `TryLazy` shares the cache across clones.
2419	///
2420	/// Verifies that clones see the same result.
2421	#[test]
2422	fn test_try_memo_sharing() {
2423		let counter = Rc::new(RefCell::new(0));
2424		let counter_clone = counter.clone();
2425		let memo: RcTryLazy<i32, ()> = RcTryLazy::new(move || {
2426			*counter_clone.borrow_mut() += 1;
2427			Ok(42)
2428		});
2429		let shared = memo.clone();
2430
2431		assert_eq!(memo.evaluate(), Ok(&42));
2432		assert_eq!(*counter.borrow(), 1);
2433		assert_eq!(shared.evaluate(), Ok(&42));
2434		assert_eq!(*counter.borrow(), 1);
2435	}
2436
2437	/// Tests `catch_unwind`.
2438	///
2439	/// Verifies that panics are caught and converted to errors.
2440	#[test]
2441	fn test_catch_unwind() {
2442		let memo = RcTryLazy::catch_unwind(|| {
2443			if true {
2444				panic!("oops")
2445			}
2446			42
2447		});
2448
2449		match memo.evaluate() {
2450			Err(e) => assert_eq!(e, "oops"),
2451			Ok(_) => panic!("Should have failed"),
2452		}
2453	}
2454
2455	/// Tests creation from `TryThunk`.
2456	#[test]
2457	fn test_try_memo_from_try_eval() {
2458		let eval = TryThunk::new(|| Ok::<i32, ()>(42));
2459		let memo = RcTryLazy::from(eval);
2460		assert_eq!(memo.evaluate(), Ok(&42));
2461	}
2462
2463	/// Tests creation from `TryTrampoline`.
2464	#[test]
2465	fn test_try_memo_from_try_task() {
2466		let task = TryTrampoline::<i32, ()>::ok(42);
2467		let memo = RcTryLazy::from(task);
2468		assert_eq!(memo.evaluate(), Ok(&42));
2469	}
2470
2471	/// Tests conversion to TryLazy.
2472	#[test]
2473	fn test_try_memo_from_rc_memo() {
2474		let memo = RcLazy::new(|| 42);
2475		let try_memo: crate::types::RcTryLazy<i32, ()> = crate::types::RcTryLazy::from(memo);
2476		assert_eq!(try_memo.evaluate(), Ok(&42));
2477	}
2478
2479	/// Tests conversion to ArcTryLazy.
2480	#[test]
2481	fn test_try_memo_from_arc_memo() {
2482		use crate::types::ArcLazy;
2483		let memo = ArcLazy::new(|| 42);
2484		let try_memo: crate::types::ArcTryLazy<i32, ()> = crate::types::ArcTryLazy::from(memo);
2485		assert_eq!(try_memo.evaluate(), Ok(&42));
2486	}
2487
2488	/// Tests SendDefer implementation.
2489	#[test]
2490	fn test_send_defer() {
2491		use crate::classes::send_deferrable::send_defer;
2492
2493		let memo: ArcTryLazy<i32, ()> = send_defer(|| ArcTryLazy::new(|| Ok(42)));
2494		assert_eq!(memo.evaluate(), Ok(&42));
2495	}
2496
2497	/// Tests `RcTryLazy::ok` convenience constructor.
2498	#[test]
2499	fn test_rc_try_lazy_ok() {
2500		let memo = RcTryLazy::<i32, ()>::ok(42);
2501		assert_eq!(memo.evaluate(), Ok(&42));
2502	}
2503
2504	/// Tests `RcTryLazy::err` convenience constructor.
2505	#[test]
2506	fn test_rc_try_lazy_err() {
2507		let memo = RcTryLazy::<i32, String>::err("error".to_string());
2508		assert_eq!(memo.evaluate(), Err(&"error".to_string()));
2509	}
2510
2511	/// Tests `ArcTryLazy::ok` convenience constructor.
2512	#[test]
2513	fn test_arc_try_lazy_ok() {
2514		let memo = ArcTryLazy::<i32, ()>::ok(42);
2515		assert_eq!(memo.evaluate(), Ok(&42));
2516	}
2517
2518	/// Tests `ArcTryLazy::err` convenience constructor.
2519	#[test]
2520	fn test_arc_try_lazy_err() {
2521		let memo = ArcTryLazy::<i32, String>::err("error".to_string());
2522		assert_eq!(memo.evaluate(), Err(&"error".to_string()));
2523	}
2524
2525	/// Tests `From<Result>` for `RcTryLazy` with `Ok`.
2526	#[test]
2527	fn test_rc_try_lazy_from_result_ok() {
2528		let memo: RcTryLazy<i32, String> = RcTryLazy::from(Ok(42));
2529		assert_eq!(memo.evaluate(), Ok(&42));
2530	}
2531
2532	/// Tests `From<Result>` for `RcTryLazy` with `Err`.
2533	#[test]
2534	fn test_rc_try_lazy_from_result_err() {
2535		let memo: RcTryLazy<i32, String> = RcTryLazy::from(Err("error".to_string()));
2536		assert_eq!(memo.evaluate(), Err(&"error".to_string()));
2537	}
2538
2539	/// Tests `From<Result>` for `ArcTryLazy` with `Ok`.
2540	#[test]
2541	fn test_arc_try_lazy_from_result_ok() {
2542		let memo: ArcTryLazy<i32, String> = ArcTryLazy::from(Ok(42));
2543		assert_eq!(memo.evaluate(), Ok(&42));
2544	}
2545
2546	/// Tests `From<Result>` for `ArcTryLazy` with `Err`.
2547	#[test]
2548	fn test_arc_try_lazy_from_result_err() {
2549		let memo: ArcTryLazy<i32, String> = ArcTryLazy::from(Err("error".to_string()));
2550		assert_eq!(memo.evaluate(), Err(&"error".to_string()));
2551	}
2552
2553	// SC-2: Panic poisoning test for TryLazy
2554
2555	/// Tests that a panicking initializer poisons the RcTryLazy.
2556	///
2557	/// Verifies that subsequent evaluate calls also panic after
2558	/// the initializer panics.
2559	#[test]
2560	fn test_panic_poisoning() {
2561		use std::panic;
2562
2563		let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| {
2564			panic!("initializer panic");
2565		});
2566
2567		let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
2568			let _ = memo.evaluate();
2569		}));
2570		assert!(result.is_err(), "First evaluate should panic");
2571
2572		let result2 = panic::catch_unwind(panic::AssertUnwindSafe(|| {
2573			let _ = memo.evaluate();
2574		}));
2575		assert!(result2.is_err(), "Second evaluate should also panic (poisoned)");
2576	}
2577
2578	// SC-2: Thread safety test for ArcTryLazy
2579
2580	/// Tests that ArcTryLazy is thread-safe.
2581	///
2582	/// Spawns 10 threads sharing an ArcTryLazy and verifies the
2583	/// computation runs exactly once.
2584	#[test]
2585	fn test_arc_try_lazy_thread_safety() {
2586		use std::{
2587			sync::atomic::{
2588				AtomicUsize,
2589				Ordering,
2590			},
2591			thread,
2592		};
2593
2594		let counter = Arc::new(AtomicUsize::new(0));
2595		let counter_clone = counter.clone();
2596		let memo: ArcTryLazy<i32, String> = ArcTryLazy::new(move || {
2597			counter_clone.fetch_add(1, Ordering::SeqCst);
2598			Ok(42)
2599		});
2600
2601		let mut handles = vec![];
2602		for _ in 0 .. 10 {
2603			let memo_clone = memo.clone();
2604			handles.push(thread::spawn(move || {
2605				assert_eq!(memo_clone.evaluate(), Ok(&42));
2606			}));
2607		}
2608
2609		for handle in handles {
2610			handle.join().unwrap();
2611		}
2612
2613		assert_eq!(counter.load(Ordering::SeqCst), 1);
2614	}
2615
2616	// QuickCheck Law Tests
2617
2618	/// Memoization: evaluating twice returns the same value.
2619	#[quickcheck]
2620	fn memoization_ok(x: i32) -> bool {
2621		let memo: RcTryLazy<i32, i32> = RcTryLazy::new(move || Ok(x));
2622		let first = memo.evaluate();
2623		let second = memo.evaluate();
2624		first == second && first == Ok(&x)
2625	}
2626
2627	/// Error memoization: error values are cached correctly.
2628	#[quickcheck]
2629	fn memoization_err(e: i32) -> bool {
2630		let memo: RcTryLazy<i32, i32> = RcTryLazy::new(move || Err(e));
2631		let first = memo.evaluate();
2632		let second = memo.evaluate();
2633		first == second && first == Err(&e)
2634	}
2635
2636	/// Deferrable transparency: `send_defer(|| x).evaluate() == x.evaluate()`.
2637	#[quickcheck]
2638	fn deferrable_transparency(x: i32) -> bool {
2639		use crate::classes::send_deferrable::send_defer;
2640
2641		let memo: ArcTryLazy<i32, i32> = ArcTryLazy::new(move || Ok(x));
2642		let deferred: ArcTryLazy<i32, i32> = send_defer(move || ArcTryLazy::new(move || Ok(x)));
2643		memo.evaluate() == deferred.evaluate()
2644	}
2645
2646	/// Tests `ArcTryLazy::catch_unwind` with a panicking closure.
2647	///
2648	/// Verifies that panics are caught and converted to errors.
2649	#[test]
2650	fn test_arc_catch_unwind() {
2651		let memo = ArcTryLazy::catch_unwind(|| {
2652			if true {
2653				panic!("oops")
2654			}
2655			42
2656		});
2657
2658		match memo.evaluate() {
2659			Err(e) => assert_eq!(e, "oops"),
2660			Ok(_) => panic!("Should have failed"),
2661		}
2662	}
2663
2664	/// Tests `ArcTryLazy::catch_unwind` with a non-panicking closure.
2665	///
2666	/// Verifies that a successful closure wraps the value in `Ok`.
2667	#[test]
2668	fn test_arc_catch_unwind_success() {
2669		let memo = ArcTryLazy::catch_unwind(|| 42);
2670		assert_eq!(memo.evaluate(), Ok(&42));
2671	}
2672
2673	/// Tests `RcTryLazy::catch_unwind_with` with a panicking closure.
2674	///
2675	/// Verifies that the custom handler converts the panic payload.
2676	#[test]
2677	fn test_rc_catch_unwind_with_panic() {
2678		let memo = RcTryLazy::<i32, i32>::catch_unwind_with(
2679			|| {
2680				if true {
2681					panic!("oops")
2682				}
2683				42
2684			},
2685			|_payload| -1,
2686		);
2687		assert_eq!(memo.evaluate(), Err(&-1));
2688	}
2689
2690	/// Tests `RcTryLazy::catch_unwind_with` with a non-panicking closure.
2691	///
2692	/// Verifies that a successful closure wraps the value in `Ok`.
2693	#[test]
2694	fn test_rc_catch_unwind_with_success() {
2695		let memo = RcTryLazy::<i32, i32>::catch_unwind_with(|| 42, |_payload| -1);
2696		assert_eq!(memo.evaluate(), Ok(&42));
2697	}
2698
2699	/// Tests `ArcTryLazy::catch_unwind_with` with a panicking closure.
2700	///
2701	/// Verifies that the custom handler converts the panic payload.
2702	#[test]
2703	fn test_arc_catch_unwind_with_panic() {
2704		let memo = ArcTryLazy::<i32, i32>::catch_unwind_with(
2705			|| {
2706				if true {
2707					panic!("oops")
2708				}
2709				42
2710			},
2711			|_payload| -1,
2712		);
2713		assert_eq!(memo.evaluate(), Err(&-1));
2714	}
2715
2716	/// Tests `ArcTryLazy::catch_unwind_with` with a non-panicking closure.
2717	///
2718	/// Verifies that a successful closure wraps the value in `Ok`.
2719	#[test]
2720	fn test_arc_catch_unwind_with_success() {
2721		let memo = ArcTryLazy::<i32, i32>::catch_unwind_with(|| 42, |_payload| -1);
2722		assert_eq!(memo.evaluate(), Ok(&42));
2723	}
2724
2725	/// Tests `RcTryLazy::map` with a successful value.
2726	///
2727	/// Verifies that `map` transforms the cached success value.
2728	#[test]
2729	fn test_rc_try_lazy_map_ok() {
2730		let memo = RcTryLazy::<i32, String>::ok(10);
2731		let mapped = memo.map(|a| a * 2);
2732		assert_eq!(mapped.evaluate(), Ok(&20));
2733	}
2734
2735	/// Tests `RcTryLazy::map` with an error value.
2736	///
2737	/// Verifies that `map` propagates the error without calling the function.
2738	#[test]
2739	fn test_rc_try_lazy_map_err() {
2740		let memo = RcTryLazy::<i32, String>::err("error".to_string());
2741		let mapped = memo.map(|a| a * 2);
2742		assert_eq!(mapped.evaluate(), Err(&"error".to_string()));
2743	}
2744
2745	/// Tests `RcTryLazy::map_err` with an error value.
2746	///
2747	/// Verifies that `map_err` transforms the cached error value.
2748	#[test]
2749	fn test_rc_try_lazy_map_err_err() {
2750		let memo = RcTryLazy::<i32, String>::err("error".to_string());
2751		let mapped = memo.map_err(|e| format!("wrapped: {}", e));
2752		assert_eq!(mapped.evaluate(), Err(&"wrapped: error".to_string()));
2753	}
2754
2755	/// Tests `RcTryLazy::map_err` with a successful value.
2756	///
2757	/// Verifies that `map_err` propagates the success without calling the function.
2758	#[test]
2759	fn test_rc_try_lazy_map_err_ok() {
2760		let memo = RcTryLazy::<i32, String>::ok(42);
2761		let mapped = memo.map_err(|e| format!("wrapped: {}", e));
2762		assert_eq!(mapped.evaluate(), Ok(&42));
2763	}
2764
2765	/// Tests `RcTryLazy::bimap` with a successful value.
2766	///
2767	/// Verifies that `bimap` transforms the success value via `f`.
2768	#[test]
2769	fn test_rc_try_lazy_bimap_ok() {
2770		let memo = RcTryLazy::<i32, String>::ok(10);
2771		let mapped = memo.bimap(|a| a * 2, |e| e.len());
2772		assert_eq!(mapped.evaluate(), Ok(&20));
2773	}
2774
2775	/// Tests `RcTryLazy::bimap` with an error value.
2776	///
2777	/// Verifies that `bimap` transforms the error value via `g`.
2778	#[test]
2779	fn test_rc_try_lazy_bimap_err() {
2780		let memo = RcTryLazy::<i32, String>::err("error".to_string());
2781		let mapped = memo.bimap(|a| a * 2, |e| e.len());
2782		assert_eq!(mapped.evaluate(), Err(&5));
2783	}
2784
2785	/// Tests `ArcTryLazy::map` with a successful value.
2786	///
2787	/// Verifies that `map` transforms the cached success value.
2788	#[test]
2789	fn test_arc_try_lazy_map_ok() {
2790		let memo = ArcTryLazy::<i32, String>::ok(10);
2791		let mapped = memo.map(|a| a * 2);
2792		assert_eq!(mapped.evaluate(), Ok(&20));
2793	}
2794
2795	/// Tests `ArcTryLazy::map` with an error value.
2796	///
2797	/// Verifies that `map` propagates the error without calling the function.
2798	#[test]
2799	fn test_arc_try_lazy_map_err() {
2800		let memo = ArcTryLazy::<i32, String>::err("error".to_string());
2801		let mapped = memo.map(|a| a * 2);
2802		assert_eq!(mapped.evaluate(), Err(&"error".to_string()));
2803	}
2804
2805	/// Tests `ArcTryLazy::map_err` with an error value.
2806	///
2807	/// Verifies that `map_err` transforms the cached error value.
2808	#[test]
2809	fn test_arc_try_lazy_map_err_err() {
2810		let memo = ArcTryLazy::<i32, String>::err("error".to_string());
2811		let mapped = memo.map_err(|e| format!("wrapped: {}", e));
2812		assert_eq!(mapped.evaluate(), Err(&"wrapped: error".to_string()));
2813	}
2814
2815	/// Tests `ArcTryLazy::map_err` with a successful value.
2816	///
2817	/// Verifies that `map_err` propagates the success without calling the function.
2818	#[test]
2819	fn test_arc_try_lazy_map_err_ok() {
2820		let memo = ArcTryLazy::<i32, String>::ok(42);
2821		let mapped = memo.map_err(|e| format!("wrapped: {}", e));
2822		assert_eq!(mapped.evaluate(), Ok(&42));
2823	}
2824
2825	/// Tests `ArcTryLazy::bimap` with a successful value.
2826	///
2827	/// Verifies that `bimap` transforms the success value via `f`.
2828	#[test]
2829	fn test_arc_try_lazy_bimap_ok() {
2830		let memo = ArcTryLazy::<i32, String>::ok(10);
2831		let mapped = memo.bimap(|a| a * 2, |e| e.len());
2832		assert_eq!(mapped.evaluate(), Ok(&20));
2833	}
2834
2835	/// Tests `ArcTryLazy::bimap` with an error value.
2836	///
2837	/// Verifies that `bimap` transforms the error value via `g`.
2838	#[test]
2839	fn test_arc_try_lazy_bimap_err() {
2840		let memo = ArcTryLazy::<i32, String>::err("error".to_string());
2841		let mapped = memo.bimap(|a| a * 2, |e| e.len());
2842		assert_eq!(mapped.evaluate(), Err(&5));
2843	}
2844
2845	// --- RefFunctor tests ---
2846
2847	/// Tests `RefFunctor::ref_map` on `RcTryLazy` with a successful value.
2848	#[test]
2849	fn test_ref_functor_rc_try_lazy_ok() {
2850		use crate::{
2851			brands::TryLazyBrand,
2852			classes::RefFunctor,
2853		};
2854		let memo = RcTryLazy::<i32, String>::ok(10);
2855		let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x * 3, memo);
2856		assert_eq!(mapped.evaluate(), Ok(&30));
2857	}
2858
2859	/// Tests `RefFunctor::ref_map` on `RcTryLazy` with an error value.
2860	#[test]
2861	fn test_ref_functor_rc_try_lazy_err() {
2862		use crate::{
2863			brands::TryLazyBrand,
2864			classes::RefFunctor,
2865		};
2866		let memo = RcTryLazy::<i32, String>::err("fail".to_string());
2867		let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x * 3, memo);
2868		assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
2869	}
2870
2871	/// Tests `RefFunctor` identity law for `RcTryLazy`.
2872	#[test]
2873	fn test_ref_functor_rc_try_lazy_identity() {
2874		use crate::{
2875			brands::TryLazyBrand,
2876			classes::RefFunctor,
2877		};
2878		let memo = RcTryLazy::<i32, String>::ok(42);
2879		let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x, memo.clone());
2880		assert_eq!(mapped.evaluate(), Ok(&42));
2881	}
2882
2883	// --- SendRefFunctor tests ---
2884
2885	/// Tests `SendRefFunctor::send_ref_map` on `ArcTryLazy` with a successful value.
2886	#[test]
2887	fn test_send_ref_functor_arc_try_lazy_ok() {
2888		use crate::{
2889			brands::TryLazyBrand,
2890			classes::SendRefFunctor,
2891		};
2892		let memo = ArcTryLazy::<i32, String>::ok(10);
2893		let mapped = TryLazyBrand::<String, ArcLazyConfig>::send_ref_map(|x: &i32| *x * 3, memo);
2894		assert_eq!(mapped.evaluate(), Ok(&30));
2895	}
2896
2897	/// Tests `SendRefFunctor::send_ref_map` on `ArcTryLazy` with an error value.
2898	#[test]
2899	fn test_send_ref_functor_arc_try_lazy_err() {
2900		use crate::{
2901			brands::TryLazyBrand,
2902			classes::SendRefFunctor,
2903		};
2904		let memo = ArcTryLazy::<i32, String>::err("fail".to_string());
2905		let mapped = TryLazyBrand::<String, ArcLazyConfig>::send_ref_map(|x: &i32| *x * 3, memo);
2906		assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
2907	}
2908
2909	// --- Inherent ref_map tests ---
2910
2911	/// Tests `RcTryLazy::ref_map` with a successful value.
2912	#[test]
2913	fn test_rc_try_lazy_ref_map_ok() {
2914		let memo = RcTryLazy::<i32, String>::ok(10);
2915		let mapped = memo.ref_map(|x| *x * 2);
2916		assert_eq!(mapped.evaluate(), Ok(&20));
2917	}
2918
2919	/// Tests `RcTryLazy::ref_map` with an error value.
2920	#[test]
2921	fn test_rc_try_lazy_ref_map_err() {
2922		let memo = RcTryLazy::<i32, String>::err("fail".to_string());
2923		let mapped = memo.ref_map(|x| *x * 2);
2924		assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
2925	}
2926
2927	/// Tests `RcTryLazy::ref_map` identity law.
2928	#[test]
2929	fn test_rc_try_lazy_ref_map_identity() {
2930		let memo = RcTryLazy::<i32, String>::ok(42);
2931		let mapped = memo.ref_map(|x| *x);
2932		assert_eq!(mapped.evaluate(), Ok(&42));
2933	}
2934
2935	/// Tests `ArcTryLazy::ref_map` with a successful value.
2936	#[test]
2937	fn test_arc_try_lazy_ref_map_ok() {
2938		let memo = ArcTryLazy::<i32, String>::ok(10);
2939		let mapped = memo.ref_map(|x| *x * 2);
2940		assert_eq!(mapped.evaluate(), Ok(&20));
2941	}
2942
2943	/// Tests `ArcTryLazy::ref_map` with an error value.
2944	#[test]
2945	fn test_arc_try_lazy_ref_map_err() {
2946		let memo = ArcTryLazy::<i32, String>::err("fail".to_string());
2947		let mapped = memo.ref_map(|x| *x * 2);
2948		assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
2949	}
2950
2951	/// Tests `ArcTryLazy::ref_map` identity law.
2952	#[test]
2953	fn test_arc_try_lazy_ref_map_identity() {
2954		let memo = ArcTryLazy::<i32, String>::ok(42);
2955		let mapped = memo.ref_map(|x| *x);
2956		assert_eq!(mapped.evaluate(), Ok(&42));
2957	}
2958
2959	// --- Semigroup tests ---
2960
2961	/// Tests `Semigroup::append` for `RcTryLazy` when both are `Ok`.
2962	#[test]
2963	fn test_semigroup_rc_try_lazy_both_ok() {
2964		use crate::functions::append;
2965		let a = RcTryLazy::<String, String>::ok("Hello".to_string());
2966		let b = RcTryLazy::<String, String>::ok(" World".to_string());
2967		let c = append(a, b);
2968		assert_eq!(c.evaluate(), Ok(&"Hello World".to_string()));
2969	}
2970
2971	/// Tests `Semigroup::append` for `RcTryLazy` when the first is `Err`.
2972	#[test]
2973	fn test_semigroup_rc_try_lazy_first_err() {
2974		use crate::functions::append;
2975		let a = RcTryLazy::<String, String>::err("err1".to_string());
2976		let b = RcTryLazy::<String, String>::ok("ok".to_string());
2977		let c = append(a, b);
2978		assert_eq!(c.evaluate(), Err(&"err1".to_string()));
2979	}
2980
2981	/// Tests `Semigroup::append` for `RcTryLazy` when the second is `Err`.
2982	#[test]
2983	fn test_semigroup_rc_try_lazy_second_err() {
2984		use crate::functions::append;
2985		let a = RcTryLazy::<String, String>::ok("ok".to_string());
2986		let b = RcTryLazy::<String, String>::err("err2".to_string());
2987		let c = append(a, b);
2988		assert_eq!(c.evaluate(), Err(&"err2".to_string()));
2989	}
2990
2991	/// Tests `Semigroup::append` for `ArcTryLazy` when both are `Ok`.
2992	#[test]
2993	fn test_semigroup_arc_try_lazy_both_ok() {
2994		use crate::functions::append;
2995		let a = ArcTryLazy::<String, String>::ok("Hello".to_string());
2996		let b = ArcTryLazy::<String, String>::ok(" World".to_string());
2997		let c = append(a, b);
2998		assert_eq!(c.evaluate(), Ok(&"Hello World".to_string()));
2999	}
3000
3001	/// Tests `Semigroup::append` for `ArcTryLazy` when the first is `Err`.
3002	#[test]
3003	fn test_semigroup_arc_try_lazy_first_err() {
3004		use crate::functions::append;
3005		let a = ArcTryLazy::<String, String>::err("err1".to_string());
3006		let b = ArcTryLazy::<String, String>::ok("ok".to_string());
3007		let c = append(a, b);
3008		assert_eq!(c.evaluate(), Err(&"err1".to_string()));
3009	}
3010
3011	// --- Monoid tests ---
3012
3013	/// Tests `Monoid::empty` for `RcTryLazy`.
3014	#[test]
3015	fn test_monoid_rc_try_lazy_empty() {
3016		use crate::functions::empty;
3017		let t: RcTryLazy<String, ()> = empty();
3018		assert_eq!(t.evaluate(), Ok(&String::new()));
3019	}
3020
3021	/// Tests `Monoid::empty` for `ArcTryLazy`.
3022	#[test]
3023	fn test_monoid_arc_try_lazy_empty() {
3024		use crate::functions::empty;
3025		let t: ArcTryLazy<String, ()> = empty();
3026		assert_eq!(t.evaluate(), Ok(&String::new()));
3027	}
3028
3029	/// Tests monoid left identity for `RcTryLazy`.
3030	#[test]
3031	fn test_monoid_rc_try_lazy_left_identity() {
3032		use crate::functions::{
3033			append,
3034			empty,
3035		};
3036		let a = RcTryLazy::<String, ()>::ok("hello".to_string());
3037		let result = append(empty::<RcTryLazy<String, ()>>(), a);
3038		assert_eq!(result.evaluate(), Ok(&"hello".to_string()));
3039	}
3040
3041	/// Tests monoid right identity for `RcTryLazy`.
3042	#[test]
3043	fn test_monoid_rc_try_lazy_right_identity() {
3044		use crate::functions::{
3045			append,
3046			empty,
3047		};
3048		let a = RcTryLazy::<String, ()>::ok("hello".to_string());
3049		let result = append(a, empty::<RcTryLazy<String, ()>>());
3050		assert_eq!(result.evaluate(), Ok(&"hello".to_string()));
3051	}
3052
3053	// --- Foldable tests ---
3054
3055	/// Tests `Foldable::fold_right` for `RcTryLazy` with `Ok`.
3056	#[test]
3057	fn test_foldable_rc_try_lazy_fold_right_ok() {
3058		use crate::functions::fold_right;
3059		let lazy = RcTryLazy::<i32, String>::ok(10);
3060		let result = fold_right::<crate::brands::RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _>(
3061			|a, b| a + b,
3062			5,
3063			lazy,
3064		);
3065		assert_eq!(result, 15);
3066	}
3067
3068	/// Tests `Foldable::fold_right` for `RcTryLazy` with `Err`.
3069	#[test]
3070	fn test_foldable_rc_try_lazy_fold_right_err() {
3071		use crate::functions::fold_right;
3072		let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3073		let result = fold_right::<crate::brands::RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _>(
3074			|a, b| a + b,
3075			5,
3076			lazy,
3077		);
3078		assert_eq!(result, 5);
3079	}
3080
3081	/// Tests `Foldable::fold_left` for `RcTryLazy` with `Ok`.
3082	#[test]
3083	fn test_foldable_rc_try_lazy_fold_left_ok() {
3084		use crate::functions::fold_left;
3085		let lazy = RcTryLazy::<i32, String>::ok(10);
3086		let result = fold_left::<crate::brands::RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _>(
3087			|b, a| b + a,
3088			5,
3089			lazy,
3090		);
3091		assert_eq!(result, 15);
3092	}
3093
3094	/// Tests `Foldable::fold_left` for `RcTryLazy` with `Err`.
3095	#[test]
3096	fn test_foldable_rc_try_lazy_fold_left_err() {
3097		use crate::functions::fold_left;
3098		let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3099		let result = fold_left::<crate::brands::RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _>(
3100			|b, a| b + a,
3101			5,
3102			lazy,
3103		);
3104		assert_eq!(result, 5);
3105	}
3106
3107	/// Tests `Foldable::fold_map` for `RcTryLazy` with `Ok`.
3108	#[test]
3109	fn test_foldable_rc_try_lazy_fold_map_ok() {
3110		use crate::functions::fold_map;
3111		let lazy = RcTryLazy::<i32, String>::ok(10);
3112		let result = fold_map::<crate::brands::RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _>(
3113			|a: i32| a.to_string(),
3114			lazy,
3115		);
3116		assert_eq!(result, "10");
3117	}
3118
3119	/// Tests `Foldable::fold_map` for `RcTryLazy` with `Err`.
3120	#[test]
3121	fn test_foldable_rc_try_lazy_fold_map_err() {
3122		use crate::functions::fold_map;
3123		let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3124		let result = fold_map::<crate::brands::RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _>(
3125			|a: i32| a.to_string(),
3126			lazy,
3127		);
3128		assert_eq!(result, "");
3129	}
3130
3131	/// Tests `Foldable::fold_right` for `ArcTryLazy` with `Ok`.
3132	#[test]
3133	fn test_foldable_arc_try_lazy_fold_right_ok() {
3134		use crate::functions::fold_right;
3135		let lazy = ArcTryLazy::<i32, String>::ok(10);
3136		let result = fold_right::<
3137			crate::brands::ArcFnBrand,
3138			TryLazyBrand<String, ArcLazyConfig>,
3139			_,
3140			_,
3141		>(|a, b| a + b, 5, lazy);
3142		assert_eq!(result, 15);
3143	}
3144
3145	/// Tests `Foldable::fold_right` for `ArcTryLazy` with `Err`.
3146	#[test]
3147	fn test_foldable_arc_try_lazy_fold_right_err() {
3148		use crate::functions::fold_right;
3149		let lazy = ArcTryLazy::<i32, String>::err("fail".to_string());
3150		let result = fold_right::<
3151			crate::brands::ArcFnBrand,
3152			TryLazyBrand<String, ArcLazyConfig>,
3153			_,
3154			_,
3155		>(|a, b| a + b, 5, lazy);
3156		assert_eq!(result, 5);
3157	}
3158
3159	// --- FoldableWithIndex tests ---
3160
3161	/// Tests `fold_map_with_index` for `RcTryLazy` with `Ok`.
3162	///
3163	/// Verifies that the index is `()` and the value is folded correctly.
3164	#[test]
3165	fn test_rc_try_lazy_fold_map_with_index_ok() {
3166		use crate::classes::foldable_with_index::FoldableWithIndex;
3167
3168		let lazy = RcTryLazy::<i32, ()>::ok(42);
3169		let result = <TryLazyBrand<(), RcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
3170			|_, x: i32| x.to_string(),
3171			lazy,
3172		);
3173		assert_eq!(result, "42");
3174	}
3175
3176	/// Tests `fold_map_with_index` for `RcTryLazy` with `Err`.
3177	///
3178	/// Verifies that the monoid identity is returned when the computation fails.
3179	#[test]
3180	fn test_rc_try_lazy_fold_map_with_index_err() {
3181		use crate::classes::foldable_with_index::FoldableWithIndex;
3182
3183		let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3184		let result = <TryLazyBrand<String, RcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
3185			|_, x: i32| x.to_string(),
3186			lazy,
3187		);
3188		assert_eq!(result, "");
3189	}
3190
3191	/// Tests `fold_map_with_index` for `ArcTryLazy` with `Ok`.
3192	///
3193	/// Verifies that the index is `()` and the value is folded correctly.
3194	#[test]
3195	fn test_arc_try_lazy_fold_map_with_index_ok() {
3196		use crate::classes::foldable_with_index::FoldableWithIndex;
3197
3198		let lazy = ArcTryLazy::<i32, ()>::ok(10);
3199		let result = <TryLazyBrand<(), ArcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
3200			|_, x: i32| x.to_string(),
3201			lazy,
3202		);
3203		assert_eq!(result, "10");
3204	}
3205
3206	/// Tests `fold_map_with_index` for `ArcTryLazy` with `Err`.
3207	///
3208	/// Verifies that the monoid identity is returned when the computation fails.
3209	#[test]
3210	fn test_arc_try_lazy_fold_map_with_index_err() {
3211		use crate::classes::foldable_with_index::FoldableWithIndex;
3212
3213		let lazy = ArcTryLazy::<i32, String>::err("fail".to_string());
3214		let result =
3215			<TryLazyBrand<String, ArcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
3216				|_, x: i32| x.to_string(),
3217				lazy,
3218			);
3219		assert_eq!(result, "");
3220	}
3221
3222	/// Tests compatibility of `FoldableWithIndex` with `Foldable`.
3223	///
3224	/// Verifies that `fold_map(f, fa) == fold_map_with_index(|_, a| f(a), fa)`.
3225	#[test]
3226	fn test_rc_try_lazy_foldable_with_index_compatibility() {
3227		use crate::{
3228			classes::foldable_with_index::FoldableWithIndex,
3229			functions::*,
3230		};
3231
3232		let lazy1 = RcTryLazy::<i32, ()>::ok(7);
3233		let lazy2 = RcTryLazy::<i32, ()>::ok(7);
3234		let f = |a: i32| a.to_string();
3235
3236		let fold_result =
3237			fold_map::<crate::brands::RcFnBrand, TryLazyBrand<(), RcLazyConfig>, _, String>(
3238				f, lazy1,
3239			);
3240		let fold_with_index_result =
3241			<TryLazyBrand<(), RcLazyConfig> as FoldableWithIndex>::fold_map_with_index(
3242				|_, a| f(a),
3243				lazy2,
3244			);
3245		assert_eq!(fold_result, fold_with_index_result);
3246	}
3247
3248	/// Tests `Semigroup::append` where the first operand is `Err`.
3249	///
3250	/// Verifies that the second operand is not evaluated (short-circuit behavior).
3251	#[test]
3252	fn test_semigroup_append_first_err_short_circuits() {
3253		use {
3254			crate::classes::Semigroup,
3255			std::cell::Cell,
3256		};
3257
3258		let counter = Rc::new(Cell::new(0u32));
3259		let counter_clone = counter.clone();
3260
3261		let a: RcTryLazy<String, String> = RcTryLazy::new(|| Err("first failed".into()));
3262		let b: RcTryLazy<String, String> = RcTryLazy::new(move || {
3263			counter_clone.set(counter_clone.get() + 1);
3264			Ok("second".into())
3265		});
3266
3267		let result = Semigroup::append(a, b);
3268		assert_eq!(result.evaluate(), Err(&"first failed".to_string()));
3269		assert_eq!(counter.get(), 0, "second operand should not be evaluated");
3270	}
3271
3272	/// Tests `Semigroup::append` where the second operand fails but the first succeeds.
3273	///
3274	/// Verifies that the error from the second operand is propagated.
3275	#[test]
3276	fn test_semigroup_append_second_err() {
3277		use crate::classes::Semigroup;
3278
3279		let a: RcTryLazy<String, String> = RcTryLazy::new(|| Ok("hello".into()));
3280		let b: RcTryLazy<String, String> = RcTryLazy::new(|| Err("second failed".into()));
3281
3282		let result = Semigroup::append(a, b);
3283		assert_eq!(result.evaluate(), Err(&"second failed".to_string()));
3284	}
3285
3286	/// Tests `Semigroup::append` where both operands succeed.
3287	#[test]
3288	fn test_semigroup_append_both_ok() {
3289		use crate::classes::Semigroup;
3290
3291		let a: RcTryLazy<String, ()> = RcTryLazy::new(|| Ok("Hello".into()));
3292		let b: RcTryLazy<String, ()> = RcTryLazy::new(|| Ok(" World".into()));
3293
3294		let result = Semigroup::append(a, b);
3295		assert_eq!(result.evaluate(), Ok(&"Hello World".to_string()));
3296	}
3297
3298	/// Tests `map` on a successful `TryLazy`.
3299	#[test]
3300	fn test_map_ok() {
3301		let memo = RcTryLazy::new(|| Ok::<i32, ()>(21));
3302		let mapped = memo.map(|x| x * 2);
3303		assert_eq!(mapped.evaluate(), Ok(&42));
3304	}
3305
3306	/// Tests `map` on a failed `TryLazy`.
3307	#[test]
3308	fn test_map_err() {
3309		let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
3310		let mapped = memo.map(|x| x * 2);
3311		assert_eq!(mapped.evaluate(), Err(&"oops".to_string()));
3312	}
3313
3314	/// Tests `map_err` on a failed `TryLazy`.
3315	#[test]
3316	fn test_map_err_on_err() {
3317		let memo: RcTryLazy<i32, i32> = RcTryLazy::new(|| Err(21));
3318		let mapped = memo.map_err(|e| e * 2);
3319		assert_eq!(mapped.evaluate(), Err(&42));
3320	}
3321
3322	/// Tests `map_err` on a successful `TryLazy`.
3323	#[test]
3324	fn test_map_err_on_ok() {
3325		let memo: RcTryLazy<i32, i32> = RcTryLazy::new(|| Ok(42));
3326		let mapped = memo.map_err(|e| e * 2);
3327		assert_eq!(mapped.evaluate(), Ok(&42));
3328	}
3329
3330	/// Tests `and_then` on a successful `TryLazy`.
3331	#[test]
3332	fn test_and_then_ok() {
3333		let memo = RcTryLazy::new(|| Ok::<i32, String>(21));
3334		let chained = memo.and_then(|x| Ok(x * 2));
3335		assert_eq!(chained.evaluate(), Ok(&42));
3336	}
3337
3338	/// Tests `and_then` where the chained operation fails.
3339	#[test]
3340	fn test_and_then_chained_err() {
3341		let memo = RcTryLazy::new(|| Ok::<i32, String>(21));
3342		let chained = memo.and_then(|_: &i32| Err::<i32, String>("chained failure".into()));
3343		assert_eq!(chained.evaluate(), Err(&"chained failure".to_string()));
3344	}
3345
3346	/// Tests `and_then` on a failed `TryLazy`.
3347	#[test]
3348	fn test_and_then_initial_err() {
3349		let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("initial".into()));
3350		let chained = memo.and_then(|x| Ok(x * 2));
3351		assert_eq!(chained.evaluate(), Err(&"initial".to_string()));
3352	}
3353
3354	/// Tests `or_else` on a failed `TryLazy`.
3355	#[test]
3356	fn test_or_else_recovers() {
3357		let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
3358		let recovered = memo.or_else(|_| Ok(42));
3359		assert_eq!(recovered.evaluate(), Ok(&42));
3360	}
3361
3362	/// Tests `or_else` on a successful `TryLazy`.
3363	#[test]
3364	fn test_or_else_noop_on_ok() {
3365		let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Ok(42));
3366		let recovered = memo.or_else(|_| Ok(99));
3367		assert_eq!(recovered.evaluate(), Ok(&42));
3368	}
3369
3370	/// Tests `or_else` where recovery itself fails.
3371	#[test]
3372	fn test_or_else_recovery_fails() {
3373		let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("first".into()));
3374		let recovered = memo.or_else(|_| Err("second".into()));
3375		assert_eq!(recovered.evaluate(), Err(&"second".to_string()));
3376	}
3377
3378	/// Tests `Foldable` fold_right on a successful `TryLazy`.
3379	#[test]
3380	fn test_foldable_ok() {
3381		use crate::{
3382			brands::*,
3383			functions::*,
3384		};
3385
3386		let memo: RcTryLazy<i32, ()> = RcTryLazy::new(|| Ok(10));
3387		let result =
3388			fold_right::<RcFnBrand, TryLazyBrand<(), RcLazyConfig>, _, _>(|a, b| a + b, 5, memo);
3389		assert_eq!(result, 15);
3390	}
3391
3392	/// Tests `Foldable` fold_right on a failed `TryLazy`.
3393	#[test]
3394	fn test_foldable_err() {
3395		use crate::{
3396			brands::*,
3397			functions::*,
3398		};
3399
3400		let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
3401		let result = fold_right::<RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _>(
3402			|a, b| a + b,
3403			5,
3404			memo,
3405		);
3406		assert_eq!(result, 5);
3407	}
3408
3409	/// Tests `From<TrySendThunk> for ArcTryLazy` with a successful thunk.
3410	#[test]
3411	fn test_from_try_send_thunk_ok() {
3412		let counter = Arc::new(std::sync::atomic::AtomicUsize::new(0));
3413		let counter_clone = counter.clone();
3414		let thunk: TrySendThunk<i32, ()> = TrySendThunk::new(move || {
3415			counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
3416			Ok(42)
3417		});
3418
3419		// Conversion should not evaluate eagerly.
3420		assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 0);
3421
3422		let lazy: ArcTryLazy<i32, ()> = ArcTryLazy::from(thunk);
3423		assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 0);
3424
3425		// First access triggers evaluation.
3426		assert_eq!(lazy.evaluate(), Ok(&42));
3427		assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
3428
3429		// Second access uses cached result.
3430		assert_eq!(lazy.evaluate(), Ok(&42));
3431		assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
3432	}
3433
3434	/// Tests `From<TrySendThunk> for ArcTryLazy` with a failing thunk.
3435	#[test]
3436	fn test_from_try_send_thunk_err() {
3437		let thunk: TrySendThunk<i32, String> = TrySendThunk::new(move || Err("fail".to_string()));
3438		let lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(thunk);
3439		assert_eq!(lazy.evaluate(), Err(&"fail".to_string()));
3440	}
3441
3442	/// Tests that `Into<ArcTryLazy>` works for `TrySendThunk`.
3443	#[test]
3444	fn test_try_send_thunk_into_arc_try_lazy() {
3445		let thunk: TrySendThunk<i32, ()> = TrySendThunk::ok(42);
3446		let lazy: ArcTryLazy<i32, ()> = thunk.into();
3447		assert_eq!(lazy.evaluate(), Ok(&42));
3448	}
3449
3450	// --- PartialEq tests ---
3451
3452	/// Tests `PartialEq` for equal `Ok` values.
3453	#[test]
3454	fn test_try_lazy_partial_eq_ok() {
3455		let a = RcTryLazy::<i32, ()>::ok(42);
3456		let b = RcTryLazy::<i32, ()>::ok(42);
3457		assert_eq!(a, b);
3458	}
3459
3460	/// Tests `PartialEq` for unequal `Ok` values.
3461	#[test]
3462	fn test_try_lazy_partial_eq_ok_neq() {
3463		let a = RcTryLazy::<i32, ()>::ok(1);
3464		let b = RcTryLazy::<i32, ()>::ok(2);
3465		assert_ne!(a, b);
3466	}
3467
3468	/// Tests `PartialEq` for equal `Err` values.
3469	#[test]
3470	fn test_try_lazy_partial_eq_err() {
3471		let a = RcTryLazy::<i32, String>::err("fail".to_string());
3472		let b = RcTryLazy::<i32, String>::err("fail".to_string());
3473		assert_eq!(a, b);
3474	}
3475
3476	/// Tests `PartialEq` for `Ok` vs `Err`.
3477	#[test]
3478	fn test_try_lazy_partial_eq_ok_vs_err() {
3479		let a = RcTryLazy::<i32, i32>::ok(1);
3480		let b = RcTryLazy::<i32, i32>::err(1);
3481		assert_ne!(a, b);
3482	}
3483
3484	/// Tests `PartialEq` for `ArcTryLazy`.
3485	#[test]
3486	fn test_try_lazy_partial_eq_arc() {
3487		let a = ArcTryLazy::<i32, ()>::ok(42);
3488		let b = ArcTryLazy::<i32, ()>::ok(42);
3489		assert_eq!(a, b);
3490	}
3491
3492	// --- Hash tests ---
3493
3494	/// Tests that equal `TryLazy` values produce equal hashes.
3495	#[test]
3496	fn test_try_lazy_hash_eq() {
3497		use std::{
3498			collections::hash_map::DefaultHasher,
3499			hash::{
3500				Hash,
3501				Hasher,
3502			},
3503		};
3504
3505		let a = RcTryLazy::<i32, ()>::ok(42);
3506		let b = RcTryLazy::<i32, ()>::ok(42);
3507
3508		let mut h1 = DefaultHasher::new();
3509		a.hash(&mut h1);
3510		let mut h2 = DefaultHasher::new();
3511		b.hash(&mut h2);
3512
3513		assert_eq!(h1.finish(), h2.finish());
3514	}
3515
3516	/// Tests that `TryLazy` hash matches the underlying `Result` hash.
3517	#[test]
3518	fn test_try_lazy_hash_matches_result() {
3519		use std::{
3520			collections::hash_map::DefaultHasher,
3521			hash::{
3522				Hash,
3523				Hasher,
3524			},
3525		};
3526
3527		let lazy = RcTryLazy::<i32, ()>::ok(42);
3528		let mut h1 = DefaultHasher::new();
3529		lazy.hash(&mut h1);
3530
3531		let result: Result<&i32, &()> = Ok(&42);
3532		let mut h2 = DefaultHasher::new();
3533		result.hash(&mut h2);
3534
3535		assert_eq!(h1.finish(), h2.finish());
3536	}
3537
3538	// --- PartialOrd tests ---
3539
3540	/// Tests `PartialOrd` for `Ok` values.
3541	#[test]
3542	fn test_try_lazy_partial_ord_ok() {
3543		let a = RcTryLazy::<i32, ()>::ok(1);
3544		let b = RcTryLazy::<i32, ()>::ok(2);
3545		assert!(a < b);
3546		assert!(b > a);
3547	}
3548
3549	/// Tests `PartialOrd` for equal values.
3550	#[test]
3551	fn test_try_lazy_partial_ord_eq() {
3552		let a = RcTryLazy::<i32, ()>::ok(42);
3553		let b = RcTryLazy::<i32, ()>::ok(42);
3554		assert!(a <= b);
3555		assert!(a >= b);
3556	}
3557
3558	// --- Ord tests ---
3559
3560	/// Tests `Ord` for `Ok` values.
3561	#[test]
3562	fn test_try_lazy_ord_ok() {
3563		use std::cmp::Ordering;
3564
3565		let a = RcTryLazy::<i32, ()>::ok(1);
3566		let b = RcTryLazy::<i32, ()>::ok(2);
3567		assert_eq!(a.cmp(&b), Ordering::Less);
3568		assert_eq!(b.cmp(&a), Ordering::Greater);
3569	}
3570
3571	/// Tests `Ord` for equal values.
3572	#[test]
3573	fn test_try_lazy_ord_eq() {
3574		use std::cmp::Ordering;
3575
3576		let a = RcTryLazy::<i32, ()>::ok(42);
3577		let b = RcTryLazy::<i32, ()>::ok(42);
3578		assert_eq!(a.cmp(&b), Ordering::Equal);
3579	}
3580
3581	/// Tests `Ord` for `ArcTryLazy`.
3582	#[test]
3583	fn test_try_lazy_ord_arc() {
3584		use std::cmp::Ordering;
3585
3586		let a = ArcTryLazy::<i32, ()>::ok(1);
3587		let b = ArcTryLazy::<i32, ()>::ok(2);
3588		assert_eq!(a.cmp(&b), Ordering::Less);
3589	}
3590
3591	/// Tests `Eq` is implemented (compile-time check via trait bound).
3592	#[test]
3593	fn test_try_lazy_eq_trait() {
3594		fn assert_eq_impl<T: Eq>(_: &T) {}
3595		let a = RcTryLazy::<i32, ()>::ok(42);
3596		assert_eq_impl(&a);
3597	}
3598
3599	// --- Display tests ---
3600
3601	/// Tests `Display` for `RcTryLazy` with `Ok` value.
3602	#[test]
3603	fn test_try_lazy_display_ok_rc() {
3604		let lazy = RcTryLazy::<i32, String>::ok(42);
3605		assert_eq!(format!("{}", lazy), "Ok(42)");
3606	}
3607
3608	/// Tests `Display` for `RcTryLazy` with `Err` value.
3609	#[test]
3610	fn test_try_lazy_display_err_rc() {
3611		let lazy = RcTryLazy::<i32, String>::err("oops".to_string());
3612		assert_eq!(format!("{}", lazy), "Err(oops)");
3613	}
3614
3615	/// Tests `Display` for `ArcTryLazy` with `Ok` value.
3616	#[test]
3617	fn test_try_lazy_display_ok_arc() {
3618		let lazy = ArcTryLazy::<i32, String>::ok(42);
3619		assert_eq!(format!("{}", lazy), "Ok(42)");
3620	}
3621
3622	/// Tests `Display` for `ArcTryLazy` with `Err` value.
3623	#[test]
3624	fn test_try_lazy_display_err_arc() {
3625		let lazy = ArcTryLazy::<i32, String>::err("oops".to_string());
3626		assert_eq!(format!("{}", lazy), "Err(oops)");
3627	}
3628
3629	// --- Cross-config conversion tests ---
3630
3631	/// Tests converting `RcTryLazy` to `ArcTryLazy` with `Ok` value.
3632	#[test]
3633	fn test_try_lazy_rc_to_arc_ok() {
3634		let rc_lazy = RcTryLazy::<i32, String>::ok(42);
3635		let arc_lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(rc_lazy);
3636		assert_eq!(arc_lazy.evaluate(), Ok(&42));
3637	}
3638
3639	/// Tests converting `RcTryLazy` to `ArcTryLazy` with `Err` value.
3640	#[test]
3641	fn test_try_lazy_rc_to_arc_err() {
3642		let rc_lazy = RcTryLazy::<i32, String>::err("fail".to_string());
3643		let arc_lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(rc_lazy);
3644		assert_eq!(arc_lazy.evaluate(), Err(&"fail".to_string()));
3645	}
3646
3647	/// Tests converting `ArcTryLazy` to `RcTryLazy` with `Ok` value.
3648	#[test]
3649	fn test_try_lazy_arc_to_rc_ok() {
3650		let arc_lazy = ArcTryLazy::<i32, String>::ok(42);
3651		let rc_lazy: RcTryLazy<i32, String> = RcTryLazy::from(arc_lazy);
3652		assert_eq!(rc_lazy.evaluate(), Ok(&42));
3653	}
3654
3655	/// Tests converting `ArcTryLazy` to `RcTryLazy` with `Err` value.
3656	#[test]
3657	fn test_try_lazy_arc_to_rc_err() {
3658		let arc_lazy = ArcTryLazy::<i32, String>::err("fail".to_string());
3659		let rc_lazy: RcTryLazy<i32, String> = RcTryLazy::from(arc_lazy);
3660		assert_eq!(rc_lazy.evaluate(), Err(&"fail".to_string()));
3661	}
3662
3663	// --- rc_try_lazy_fix / arc_try_lazy_fix tests ---
3664
3665	/// Tests that `rc_try_lazy_fix` produces the correct `Ok` value when
3666	/// the function ignores the self-reference.
3667	#[test]
3668	fn test_rc_try_lazy_fix_ok_constant() {
3669		let fixed = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, ()>| Ok(42));
3670		assert_eq!(fixed.evaluate(), Ok(&42));
3671	}
3672
3673	/// Tests that `rc_try_lazy_fix` produces the correct `Err` value when
3674	/// the function ignores the self-reference.
3675	#[test]
3676	fn test_rc_try_lazy_fix_err_constant() {
3677		let fixed = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, String>| Err("fail".to_string()));
3678		assert_eq!(fixed.evaluate(), Err(&"fail".to_string()));
3679	}
3680
3681	/// Tests that `rc_try_lazy_fix` memoizes the result.
3682	#[test]
3683	fn test_rc_try_lazy_fix_memoization() {
3684		let counter = Rc::new(RefCell::new(0));
3685		let counter_clone = counter.clone();
3686		let fixed = rc_try_lazy_fix(move |_self_ref: RcTryLazy<i32, ()>| {
3687			*counter_clone.borrow_mut() += 1;
3688			Ok(100)
3689		});
3690
3691		assert_eq!(*counter.borrow(), 0);
3692		assert_eq!(fixed.evaluate(), Ok(&100));
3693		assert_eq!(*counter.borrow(), 1);
3694		// Second evaluation should use cached value.
3695		assert_eq!(fixed.evaluate(), Ok(&100));
3696		assert_eq!(*counter.borrow(), 1);
3697	}
3698
3699	/// Tests that `rc_try_lazy_fix` correctly threads the self-reference.
3700	#[test]
3701	fn test_rc_try_lazy_fix_self_reference() {
3702		let fixed = rc_try_lazy_fix(|self_ref: RcTryLazy<Vec<i32>, ()>| {
3703			// The self-reference is available but evaluating it here would recurse.
3704			let _ = self_ref;
3705			Ok(vec![1, 2, 3])
3706		});
3707		assert_eq!(fixed.evaluate(), Ok(&vec![1, 2, 3]));
3708	}
3709
3710	/// Tests that `rc_try_lazy_fix` works with cloned results sharing the cache.
3711	#[test]
3712	fn test_rc_try_lazy_fix_clone_sharing() {
3713		let fixed = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, ()>| Ok(55));
3714		let cloned = fixed.clone();
3715		assert_eq!(fixed.evaluate(), Ok(&55));
3716		assert_eq!(cloned.evaluate(), Ok(&55));
3717	}
3718
3719	/// Tests that `rc_try_lazy_fix` uses the self-reference after initial evaluation.
3720	#[test]
3721	fn test_rc_try_lazy_fix_uses_self_ref() {
3722		let counter = Rc::new(RefCell::new(0));
3723		let counter_clone = counter.clone();
3724		let lazy = rc_try_lazy_fix(move |self_ref: RcTryLazy<i32, ()>| {
3725			*counter_clone.borrow_mut() += 1;
3726			let _ = self_ref;
3727			Ok(42)
3728		});
3729		assert_eq!(lazy.evaluate(), Ok(&42));
3730		assert_eq!(*counter.borrow(), 1);
3731		// Verify memoization: second evaluate does not re-run.
3732		assert_eq!(lazy.evaluate(), Ok(&42));
3733		assert_eq!(*counter.borrow(), 1);
3734	}
3735
3736	/// Tests that `arc_try_lazy_fix` produces the correct `Ok` value when
3737	/// the function ignores the self-reference.
3738	#[test]
3739	fn test_arc_try_lazy_fix_ok_constant() {
3740		let fixed = arc_try_lazy_fix(|_self_ref: ArcTryLazy<i32, ()>| Ok(42));
3741		assert_eq!(fixed.evaluate(), Ok(&42));
3742	}
3743
3744	/// Tests that `arc_try_lazy_fix` produces the correct `Err` value when
3745	/// the function ignores the self-reference.
3746	#[test]
3747	fn test_arc_try_lazy_fix_err_constant() {
3748		let fixed = arc_try_lazy_fix(|_self_ref: ArcTryLazy<i32, String>| Err("fail".to_string()));
3749		assert_eq!(fixed.evaluate(), Err(&"fail".to_string()));
3750	}
3751
3752	/// Tests that `arc_try_lazy_fix` memoizes the result.
3753	#[test]
3754	fn test_arc_try_lazy_fix_memoization() {
3755		use std::sync::atomic::{
3756			AtomicUsize,
3757			Ordering,
3758		};
3759
3760		let counter = Arc::new(AtomicUsize::new(0));
3761		let counter_clone = counter.clone();
3762		let fixed = arc_try_lazy_fix(move |_self_ref: ArcTryLazy<i32, ()>| {
3763			counter_clone.fetch_add(1, Ordering::SeqCst);
3764			Ok(100)
3765		});
3766
3767		assert_eq!(counter.load(Ordering::SeqCst), 0);
3768		assert_eq!(fixed.evaluate(), Ok(&100));
3769		assert_eq!(counter.load(Ordering::SeqCst), 1);
3770		// Second evaluation should use cached value.
3771		assert_eq!(fixed.evaluate(), Ok(&100));
3772		assert_eq!(counter.load(Ordering::SeqCst), 1);
3773	}
3774
3775	/// Tests that `arc_try_lazy_fix` correctly threads the self-reference.
3776	#[test]
3777	fn test_arc_try_lazy_fix_self_reference() {
3778		let fixed = arc_try_lazy_fix(|self_ref: ArcTryLazy<Vec<i32>, ()>| {
3779			let _ = self_ref;
3780			Ok(vec![1, 2, 3])
3781		});
3782		assert_eq!(fixed.evaluate(), Ok(&vec![1, 2, 3]));
3783	}
3784
3785	/// Tests that `arc_try_lazy_fix` uses the self-reference after initial evaluation.
3786	#[test]
3787	fn test_arc_try_lazy_fix_uses_self_ref() {
3788		use std::sync::atomic::{
3789			AtomicUsize,
3790			Ordering,
3791		};
3792
3793		let counter = Arc::new(AtomicUsize::new(0));
3794		let counter_clone = counter.clone();
3795		let lazy = arc_try_lazy_fix(move |self_ref: ArcTryLazy<i32, ()>| {
3796			counter_clone.fetch_add(1, Ordering::SeqCst);
3797			let _ = self_ref;
3798			Ok(42)
3799		});
3800		assert_eq!(lazy.evaluate(), Ok(&42));
3801		assert_eq!(counter.load(Ordering::SeqCst), 1);
3802		// Verify memoization: second evaluate does not re-run.
3803		assert_eq!(lazy.evaluate(), Ok(&42));
3804		assert_eq!(counter.load(Ordering::SeqCst), 1);
3805	}
3806
3807	/// Tests that `arc_try_lazy_fix` is thread-safe.
3808	#[test]
3809	fn test_arc_try_lazy_fix_thread_safety() {
3810		use std::thread;
3811
3812		let lazy = arc_try_lazy_fix(|self_ref: ArcTryLazy<i32, ()>| {
3813			let _ = self_ref;
3814			Ok(42)
3815		});
3816
3817		let mut handles = vec![];
3818		for _ in 0 .. 10 {
3819			let lazy_clone = lazy.clone();
3820			handles.push(thread::spawn(move || {
3821				assert_eq!(lazy_clone.evaluate(), Ok(&42));
3822			}));
3823		}
3824
3825		for handle in handles {
3826			handle.join().unwrap();
3827		}
3828	}
3829}