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