#[fp_macros::document_module]
mod inner {
use {
crate::{
Apply,
brands::TryLazyBrand,
classes::{
Deferrable,
LazyConfig,
LiftFn,
Monoid,
RefFoldable,
RefFoldableWithIndex,
RefFunctor,
Semigroup,
SendDeferrable,
SendRefFunctor,
WithIndex,
},
impl_kind,
kinds::*,
types::{
ArcLazyConfig,
Lazy,
RcLazyConfig,
TrySendThunk,
TryThunk,
TryTrampoline,
},
},
fp_macros::*,
std::{
fmt,
hash::{
Hash,
Hasher,
},
},
};
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
pub struct TryLazy<'a, A, E, Config: LazyConfig = RcLazyConfig>(
pub(crate) Lazy<'a, Result<A, E>, Config>,
)
where
A: 'a,
E: 'a;
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
#[document_parameters("The instance to clone.")]
impl<'a, A, E, Config: LazyConfig> Clone for TryLazy<'a, A, E, Config>
where
A: 'a,
E: 'a,
{
#[document_signature]
#[document_returns(
"A new `TryLazy` instance that shares the same underlying memoized result."
)]
#[document_examples]
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
#[document_parameters("The `TryLazy` instance.")]
impl<'a, A, E, Config: LazyConfig> TryLazy<'a, A, E, Config>
where
A: 'a,
E: 'a,
{
#[document_signature]
#[document_returns("A result containing a reference to the value or error.")]
#[document_examples]
#[inline]
pub fn evaluate(&self) -> Result<&A, &E> {
self.0.evaluate().as_ref()
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
#[document_parameters("The try-lazy cell instance.")]
impl<'a, A, E> TryLazy<'a, A, E, RcLazyConfig>
where
A: 'a,
E: 'a,
{
#[document_signature]
#[document_parameters("The closure that produces the result.")]
#[document_returns("A new `TryLazy` instance.")]
#[document_examples]
#[inline]
pub fn new(f: impl FnOnce() -> Result<A, E> + 'a) -> Self {
TryLazy(Lazy::<'a, Result<A, E>, RcLazyConfig>::new(f))
}
#[document_signature]
#[document_parameters("The success value to wrap.")]
#[document_returns("A new `TryLazy` instance that evaluates to `Ok(&a)`.")]
#[document_examples]
#[inline]
pub fn ok(a: A) -> Self {
Self::new(move || Ok(a))
}
#[document_signature]
#[document_parameters("The error value to wrap.")]
#[document_returns("A new `TryLazy` instance that evaluates to `Err(&e)`.")]
#[document_examples]
#[inline]
pub fn err(e: E) -> Self {
Self::new(move || Err(e))
}
#[document_signature]
#[document_returns("An owned `Result` clone of the memoized value.")]
#[document_examples]
#[inline]
pub fn evaluate_owned(&self) -> Result<A, E>
where
A: Clone,
E: Clone, {
self.evaluate().cloned().map_err(|e| e.clone())
}
#[document_signature]
#[document_type_parameters("The type of the mapped success value.")]
#[document_parameters("The function to apply to the success value.")]
#[document_returns("A new `RcTryLazy` that applies `f` to the success value of this cell.")]
#[document_examples]
#[inline]
pub fn map<B: 'a>(
self,
f: impl FnOnce(&A) -> B + 'a,
) -> RcTryLazy<'a, B, E>
where
E: Clone + 'a, {
RcTryLazy::new(move || match self.evaluate() {
Ok(a) => Ok(f(a)),
Err(e) => Err(e.clone()),
})
}
#[document_signature]
#[document_type_parameters("The type of the mapped success value.")]
#[document_parameters("The function to apply to the success value.")]
#[document_returns("A new `RcTryLazy` that applies `f` to the success value of this cell.")]
#[document_examples]
#[inline]
pub fn ref_map<B: 'a>(
&self,
f: impl Fn(&A) -> B + 'a,
) -> RcTryLazy<'a, B, E>
where
E: Clone + 'a, {
let this = self.clone();
RcTryLazy::new(move || match this.evaluate() {
Ok(a) => Ok(f(a)),
Err(e) => Err(e.clone()),
})
}
#[document_signature]
#[document_type_parameters("The type of the mapped error value.")]
#[document_parameters("The function to apply to the error value.")]
#[document_returns("A new `RcTryLazy` that applies `f` to the error value of this cell.")]
#[document_examples]
#[inline]
pub fn map_err<E2: 'a>(
self,
f: impl FnOnce(&E) -> E2 + 'a,
) -> RcTryLazy<'a, A, E2>
where
A: Clone + 'a, {
RcTryLazy::new(move || match self.evaluate() {
Ok(a) => Ok(a.clone()),
Err(e) => Err(f(e)),
})
}
#[document_signature]
#[document_type_parameters(
"The type of the mapped success value.",
"The type of the mapped error value."
)]
#[document_parameters(
"The function to apply to the success value.",
"The function to apply to the error value."
)]
#[document_returns(
"A new `RcTryLazy` that applies `f` to the success value or `g` to the error value of this cell."
)]
#[document_examples]
#[inline]
pub fn bimap<B: 'a, F: 'a>(
self,
f: impl FnOnce(&A) -> B + 'a,
g: impl FnOnce(&E) -> F + 'a,
) -> RcTryLazy<'a, B, F> {
RcTryLazy::new(move || match self.evaluate() {
Ok(a) => Ok(f(a)),
Err(e) => Err(g(e)),
})
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> From<TryThunk<'a, A, E>> for TryLazy<'a, A, E, RcLazyConfig> {
#[document_signature]
#[document_parameters("The fallible thunk to convert.")]
#[document_returns(
"A new `TryLazy` instance that will evaluate the thunk on first access."
)]
#[document_examples]
fn from(eval: TryThunk<'a, A, E>) -> Self {
Self::new(move || eval.evaluate())
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> From<TryTrampoline<A, E>> for TryLazy<'a, A, E, RcLazyConfig> {
#[document_signature]
#[document_parameters("The fallible trampoline to convert.")]
#[document_returns(
"A new `TryLazy` instance that will evaluate the trampoline on first access."
)]
#[document_examples]
fn from(task: TryTrampoline<A, E>) -> Self {
Self::new(move || task.evaluate())
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> From<Lazy<'a, A, RcLazyConfig>> for TryLazy<'a, A, E, RcLazyConfig>
where
A: Clone + 'a,
E: 'a,
{
#[document_signature]
#[document_parameters("The lazy value to convert.")]
#[document_returns("A new `TryLazy` instance that wraps the lazy value.")]
#[document_examples]
fn from(memo: Lazy<'a, A, RcLazyConfig>) -> Self {
Self::new(move || Ok(memo.evaluate().clone()))
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A: 'a, E: 'a> From<Result<A, E>> for TryLazy<'a, A, E, RcLazyConfig> {
#[document_signature]
#[document_parameters("The result to convert.")]
#[document_returns("A new `TryLazy` instance that produces the result.")]
#[document_examples]
fn from(result: Result<A, E>) -> Self {
Self::new(move || result)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> From<TryThunk<'a, A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
where
A: Send + Sync + 'a,
E: Send + Sync + 'a,
{
#[document_signature]
#[document_parameters("The fallible thunk to convert.")]
#[document_returns("A new `TryLazy` instance containing the eagerly evaluated result.")]
#[document_examples]
fn from(eval: TryThunk<'a, A, E>) -> Self {
let result = eval.evaluate();
Self::new(move || result)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> From<TryTrampoline<A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
where
A: Send + Sync + 'static,
E: Send + Sync + 'static,
{
#[document_signature]
#[document_parameters("The fallible trampoline to convert.")]
#[document_returns("A new `TryLazy` instance containing the eagerly evaluated result.")]
#[document_examples]
fn from(task: TryTrampoline<A, E>) -> Self {
let result = task.evaluate();
Self::new(move || result)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> From<Lazy<'a, A, ArcLazyConfig>> for TryLazy<'a, A, E, ArcLazyConfig>
where
A: Clone + Send + Sync + 'a,
E: Send + Sync + 'a,
{
#[document_signature]
#[document_parameters("The thread-safe lazy value to convert.")]
#[document_returns("A new `TryLazy` instance that wraps the lazy value.")]
#[document_examples]
fn from(memo: Lazy<'a, A, ArcLazyConfig>) -> Self {
Self::new(move || Ok(memo.evaluate().clone()))
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> From<Result<A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
where
A: Send + Sync + 'a,
E: Send + Sync + 'a,
{
#[document_signature]
#[document_parameters("The result to convert.")]
#[document_returns("A new `TryLazy` instance that produces the result.")]
#[document_examples]
fn from(result: Result<A, E>) -> Self {
Self::new(move || result)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> From<TrySendThunk<'a, A, E>> for TryLazy<'a, A, E, ArcLazyConfig>
where
A: Send + Sync + 'a,
E: Send + Sync + 'a,
{
#[document_signature]
#[document_parameters("The fallible send thunk to convert.")]
#[document_returns("A thread-safe `ArcTryLazy` that evaluates the thunk on first access.")]
#[document_examples]
fn from(thunk: TrySendThunk<'a, A, E>) -> Self {
thunk.into_arc_try_lazy()
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A: Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a>
From<TryLazy<'a, A, E, RcLazyConfig>> for TryLazy<'a, A, E, ArcLazyConfig>
{
#[document_signature]
#[document_parameters("The `RcTryLazy` instance to convert.")]
#[document_returns(
"A new `ArcTryLazy` instance containing a clone of the eagerly evaluated result."
)]
#[document_examples]
fn from(source: TryLazy<'a, A, E, RcLazyConfig>) -> Self {
let result: Result<A, E> = source.evaluate().cloned().map_err(Clone::clone);
Self::new(move || result)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A: Clone + 'a, E: Clone + 'a> From<TryLazy<'a, A, E, ArcLazyConfig>>
for TryLazy<'a, A, E, RcLazyConfig>
{
#[document_signature]
#[document_parameters("The `ArcTryLazy` instance to convert.")]
#[document_returns(
"A new `RcTryLazy` instance containing a clone of the eagerly evaluated result."
)]
#[document_examples]
fn from(source: TryLazy<'a, A, E, ArcLazyConfig>) -> Self {
let result: Result<A, E> = source.evaluate().cloned().map_err(Clone::clone);
Self::new(move || result)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error value."
)]
impl<'a, A: 'a, E: 'a> TryLazy<'a, A, E, RcLazyConfig> {
#[document_signature]
#[document_parameters(
"The closure that might panic.",
"The function that converts a panic payload into the error type."
)]
#[document_returns(
"A new `TryLazy` instance where panics are converted to `Err(E)` via the handler."
)]
#[document_examples]
pub fn catch_unwind_with(
f: impl FnOnce() -> A + std::panic::UnwindSafe + 'a,
handler: impl FnOnce(Box<dyn std::any::Any + Send>) -> E + 'a,
) -> Self {
Self::new(move || std::panic::catch_unwind(f).map_err(handler))
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value."
)]
impl<'a, A> TryLazy<'a, A, String, RcLazyConfig>
where
A: 'a,
{
#[document_signature]
#[document_parameters("The closure that might panic.")]
#[document_returns("A new `TryLazy` instance where panics are converted to `Err(String)`.")]
#[document_examples]
pub fn catch_unwind(f: impl FnOnce() -> A + std::panic::UnwindSafe + 'a) -> Self {
Self::catch_unwind_with(f, crate::utils::panic_payload_to_string)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
#[document_parameters("The `TryLazy` instance.")]
impl<'a, A, E> TryLazy<'a, A, E, RcLazyConfig>
where
A: Clone + 'a,
E: Clone + 'a,
{
#[document_signature]
#[document_type_parameters("The type of the new success value.")]
#[document_parameters("The fallible function to apply to the success value.")]
#[document_returns("A new `TryLazy` containing the chained result.")]
#[document_examples]
pub fn and_then<B: 'a>(
self,
f: impl FnOnce(&A) -> Result<B, E> + 'a,
) -> TryLazy<'a, B, E, RcLazyConfig> {
let fa = self;
TryLazy::<'a, B, E, RcLazyConfig>::new(move || match fa.evaluate() {
Ok(a) => f(a),
Err(e) => Err(e.clone()),
})
}
#[document_signature]
#[document_parameters("The recovery function to apply to the error value.")]
#[document_returns("A new `TryLazy` containing the recovered result.")]
#[document_examples]
pub fn or_else(
self,
f: impl FnOnce(&E) -> Result<A, E> + 'a,
) -> TryLazy<'a, A, E, RcLazyConfig> {
let fa = self;
TryLazy::<'a, A, E, RcLazyConfig>::new(move || match fa.evaluate() {
Ok(a) => Ok(a.clone()),
Err(e) => f(e),
})
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
#[document_parameters("The try-lazy cell instance.")]
impl<'a, A, E> TryLazy<'a, A, E, ArcLazyConfig>
where
A: Send + Sync + 'a,
E: Send + Sync + 'a,
{
#[document_signature]
#[document_parameters("The closure that produces the result.")]
#[document_returns("A new `TryLazy` instance.")]
#[document_examples]
#[inline]
pub fn new(f: impl FnOnce() -> Result<A, E> + Send + 'a) -> Self {
TryLazy(Lazy::<'a, Result<A, E>, ArcLazyConfig>::new(f))
}
#[document_signature]
#[document_parameters("The success value to wrap.")]
#[document_returns("A new `ArcTryLazy` instance that evaluates to `Ok(&a)`.")]
#[document_examples]
#[inline]
pub fn ok(a: A) -> Self {
Self::new(move || Ok(a))
}
#[document_signature]
#[document_parameters("The error value to wrap.")]
#[document_returns("A new `ArcTryLazy` instance that evaluates to `Err(&e)`.")]
#[document_examples]
#[inline]
pub fn err(e: E) -> Self {
Self::new(move || Err(e))
}
#[document_signature]
#[document_returns("An owned `Result` clone of the memoized value.")]
#[document_examples]
#[inline]
pub fn evaluate_owned(&self) -> Result<A, E>
where
A: Clone,
E: Clone, {
self.evaluate().cloned().map_err(|e| e.clone())
}
#[document_signature]
#[document_type_parameters("The type of the mapped success value.")]
#[document_parameters("The function to apply to the success value.")]
#[document_returns(
"A new `ArcTryLazy` that applies `f` to the success value of this cell."
)]
#[document_examples]
#[inline]
pub fn map<B: Send + Sync + 'a>(
self,
f: impl FnOnce(&A) -> B + Send + 'a,
) -> ArcTryLazy<'a, B, E>
where
E: Clone, {
ArcTryLazy::new(move || match self.evaluate() {
Ok(a) => Ok(f(a)),
Err(e) => Err(e.clone()),
})
}
#[document_signature]
#[document_type_parameters("The type of the mapped success value.")]
#[document_parameters("The function to apply to the success value.")]
#[document_returns(
"A new `ArcTryLazy` that applies `f` to the success value of this cell."
)]
#[document_examples]
#[inline]
pub fn ref_map<B: Send + Sync + 'a>(
&self,
f: impl Fn(&A) -> B + Send + 'a,
) -> ArcTryLazy<'a, B, E>
where
E: Clone, {
let this = self.clone();
ArcTryLazy::new(move || match this.evaluate() {
Ok(a) => Ok(f(a)),
Err(e) => Err(e.clone()),
})
}
#[document_signature]
#[document_type_parameters("The type of the mapped error value.")]
#[document_parameters("The function to apply to the error value.")]
#[document_returns("A new `ArcTryLazy` that applies `f` to the error value of this cell.")]
#[document_examples]
#[inline]
pub fn map_err<E2: Send + Sync + 'a>(
self,
f: impl FnOnce(&E) -> E2 + Send + 'a,
) -> ArcTryLazy<'a, A, E2>
where
A: Clone, {
ArcTryLazy::new(move || match self.evaluate() {
Ok(a) => Ok(a.clone()),
Err(e) => Err(f(e)),
})
}
#[document_signature]
#[document_type_parameters(
"The type of the mapped success value.",
"The type of the mapped error value."
)]
#[document_parameters(
"The function to apply to the success value.",
"The function to apply to the error value."
)]
#[document_returns(
"A new `ArcTryLazy` that applies `f` to the success value or `g` to the error value of this cell."
)]
#[document_examples]
#[inline]
pub fn bimap<B: Send + Sync + 'a, F: Send + Sync + 'a>(
self,
f: impl FnOnce(&A) -> B + Send + 'a,
g: impl FnOnce(&E) -> F + Send + 'a,
) -> ArcTryLazy<'a, B, F> {
ArcTryLazy::new(move || match self.evaluate() {
Ok(a) => Ok(f(a)),
Err(e) => Err(g(e)),
})
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error value."
)]
impl<'a, A: Send + Sync + 'a, E: Send + Sync + 'a> TryLazy<'a, A, E, ArcLazyConfig> {
#[document_signature]
#[document_parameters(
"The closure that might panic.",
"The function that converts a panic payload into the error type."
)]
#[document_returns(
"A new `ArcTryLazy` instance where panics are converted to `Err(E)` via the handler."
)]
#[document_examples]
pub fn catch_unwind_with(
f: impl FnOnce() -> A + std::panic::UnwindSafe + Send + 'a,
handler: impl FnOnce(Box<dyn std::any::Any + Send>) -> E + Send + 'a,
) -> Self {
Self::new(move || std::panic::catch_unwind(f).map_err(handler))
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value."
)]
impl<'a, A> TryLazy<'a, A, String, ArcLazyConfig>
where
A: Send + Sync + 'a,
{
#[document_signature]
#[document_parameters("The closure that might panic.")]
#[document_returns(
"A new `ArcTryLazy` instance where panics are converted to `Err(String)`."
)]
#[document_examples]
pub fn catch_unwind(f: impl FnOnce() -> A + std::panic::UnwindSafe + Send + 'a) -> Self {
Self::catch_unwind_with(f, crate::utils::panic_payload_to_string)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
#[document_parameters("The `TryLazy` instance.")]
impl<'a, A, E> TryLazy<'a, A, E, ArcLazyConfig>
where
A: Clone + Send + Sync + 'a,
E: Clone + Send + Sync + 'a,
{
#[document_signature]
#[document_type_parameters("The type of the new success value.")]
#[document_parameters("The fallible function to apply to the success value.")]
#[document_returns("A new `ArcTryLazy` containing the chained result.")]
#[document_examples]
pub fn and_then<B: Send + Sync + 'a>(
self,
f: impl FnOnce(&A) -> Result<B, E> + Send + 'a,
) -> TryLazy<'a, B, E, ArcLazyConfig> {
let fa = self;
TryLazy::<'a, B, E, ArcLazyConfig>::new(move || match fa.evaluate() {
Ok(a) => f(a),
Err(e) => Err(e.clone()),
})
}
#[document_signature]
#[document_parameters("The recovery function to apply to the error value.")]
#[document_returns("A new `ArcTryLazy` containing the recovered result.")]
#[document_examples]
pub fn or_else(
self,
f: impl FnOnce(&E) -> Result<A, E> + Send + 'a,
) -> TryLazy<'a, A, E, ArcLazyConfig> {
let fa = self;
TryLazy::<'a, A, E, ArcLazyConfig>::new(move || match fa.evaluate() {
Ok(a) => Ok(a.clone()),
Err(e) => f(e),
})
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> Deferrable<'a> for TryLazy<'a, A, E, RcLazyConfig>
where
A: Clone + 'a,
E: Clone + 'a,
{
#[document_signature]
#[document_parameters("The thunk that produces the lazy value.")]
#[document_returns("A new `TryLazy` value.")]
#[document_examples]
fn defer(f: impl FnOnce() -> Self + 'a) -> Self
where
Self: Sized, {
Self::new(move || match f().evaluate() {
Ok(a) => Ok(a.clone()),
Err(e) => Err(e.clone()),
})
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A, E> SendDeferrable<'a> for TryLazy<'a, A, E, ArcLazyConfig>
where
A: Clone + Send + Sync + 'a,
E: Clone + Send + Sync + 'a,
{
#[document_signature]
#[document_parameters("The thunk that produces the lazy value.")]
#[document_returns("A new `ArcTryLazy` value.")]
#[document_examples]
fn send_defer(f: impl FnOnce() -> Self + Send + 'a) -> Self
where
Self: Sized, {
Self::new(move || match f().evaluate() {
Ok(a) => Ok(a.clone()),
Err(e) => Err(e.clone()),
})
}
}
pub type RcTryLazy<'a, A, E> = TryLazy<'a, A, E, RcLazyConfig>;
pub type ArcTryLazy<'a, A, E> = TryLazy<'a, A, E, ArcLazyConfig>;
impl_kind! {
impl<E: 'static, Config: LazyConfig> for TryLazyBrand<E, Config> {
#[document_default]
type Of<'a, A: 'a>: 'a = TryLazy<'a, A, E, Config>;
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The success value type.",
"The type of the error."
)]
impl<'a, A: Semigroup + Clone + 'a, E: Clone + 'a> Semigroup for TryLazy<'a, A, E, RcLazyConfig> {
#[document_signature]
#[document_parameters("The first `TryLazy`.", "The second `TryLazy`.")]
#[document_returns("A new `RcTryLazy` containing the combined result.")]
#[document_examples]
fn append(
a: Self,
b: Self,
) -> Self {
RcTryLazy::new(move || {
let a_val = match a.evaluate() {
Ok(v) => v.clone(),
Err(e) => return Err(e.clone()),
};
let b_val = match b.evaluate() {
Ok(v) => v.clone(),
Err(e) => return Err(e.clone()),
};
Ok(Semigroup::append(a_val, b_val))
})
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The success value type.",
"The type of the error."
)]
impl<'a, A: Semigroup + Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a> Semigroup
for TryLazy<'a, A, E, ArcLazyConfig>
{
#[document_signature]
#[document_parameters("The first `ArcTryLazy`.", "The second `ArcTryLazy`.")]
#[document_returns("A new `ArcTryLazy` containing the combined result.")]
#[document_examples]
fn append(
a: Self,
b: Self,
) -> Self {
ArcTryLazy::new(move || {
let a_val = match a.evaluate() {
Ok(v) => v.clone(),
Err(e) => return Err(e.clone()),
};
let b_val = match b.evaluate() {
Ok(v) => v.clone(),
Err(e) => return Err(e.clone()),
};
Ok(Semigroup::append(a_val, b_val))
})
}
}
#[document_type_parameters("The error type.", "The memoization configuration.")]
impl<E: 'static, Config: LazyConfig> RefFoldable for TryLazyBrand<E, Config> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the computation.",
"The brand of the cloneable function to use.",
"The type of the elements.",
"The monoid type."
)]
#[document_parameters("The mapping function.", "The TryLazy to fold.")]
#[document_returns("The monoid value.")]
#[document_examples]
fn ref_fold_map<'a, FnBrand, A: 'a + Clone, M>(
func: impl Fn(&A) -> M + 'a,
fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> M
where
FnBrand: LiftFn + 'a,
M: Monoid + 'a, {
match fa.evaluate() {
Ok(a) => func(a),
Err(_) => Monoid::empty(),
}
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the computation.",
"The brand of the cloneable function to use.",
"The type of the elements.",
"The type of the accumulator."
)]
#[document_parameters(
"The function to apply to each element reference and the accumulator.",
"The initial value of the accumulator.",
"The TryLazy to fold."
)]
#[document_returns("The final accumulator value.")]
#[document_examples]
fn ref_fold_right<'a, FnBrand, A: 'a + Clone, B: 'a>(
func: impl Fn(&A, B) -> B + 'a,
initial: B,
fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> B
where
FnBrand: LiftFn + 'a, {
match fa.evaluate() {
Ok(a) => func(a, initial),
Err(_) => initial,
}
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the computation.",
"The brand of the cloneable function to use.",
"The type of the elements.",
"The type of the accumulator."
)]
#[document_parameters(
"The function to apply to the accumulator and each element reference.",
"The initial value of the accumulator.",
"The TryLazy to fold."
)]
#[document_returns("The final accumulator value.")]
#[document_examples]
fn ref_fold_left<'a, FnBrand, A: 'a + Clone, B: 'a>(
func: impl Fn(B, &A) -> B + 'a,
initial: B,
fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> B
where
FnBrand: LiftFn + 'a, {
match fa.evaluate() {
Ok(a) => func(initial, a),
Err(_) => initial,
}
}
}
#[document_type_parameters("The error type.", "The memoization configuration.")]
impl<E: 'static, Config: LazyConfig> WithIndex for TryLazyBrand<E, Config> {
type Index = ();
}
#[document_type_parameters("The error type.", "The memoization configuration.")]
impl<E: 'static, Config: LazyConfig> RefFoldableWithIndex for TryLazyBrand<E, Config> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the computation.",
"The brand of the cloneable function to use.",
"The type of the computed value.",
"The monoid type."
)]
#[document_parameters(
"The function to apply to the index and the value reference.",
"The TryLazy to fold."
)]
#[document_returns("The monoid value.")]
#[document_examples]
fn ref_fold_map_with_index<'a, FnBrand, A: 'a + Clone, R: Monoid + 'a>(
f: impl Fn((), &A) -> R + 'a,
fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> R
where
FnBrand: LiftFn + 'a, {
match fa.evaluate() {
Ok(a) => f((), a),
Err(_) => Monoid::empty(),
}
}
}
#[document_type_parameters("The type of the error.")]
impl<E: 'static + Clone> RefFunctor for TryLazyBrand<E, RcLazyConfig> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the success value.",
"The type of the result."
)]
#[document_parameters(
"The function to apply to the success value.",
"The memoized fallible value."
)]
#[document_returns("A new memoized fallible value containing the mapped result.")]
#[document_examples]
fn ref_map<'a, A: 'a, B: 'a>(
f: impl Fn(&A) -> B + 'a,
fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
fa.ref_map(f)
}
}
#[document_type_parameters("The type of the error.")]
impl<E: 'static + Clone + Send + Sync> SendRefFunctor for TryLazyBrand<E, ArcLazyConfig> {
#[document_signature]
#[document_type_parameters(
"The lifetime of the values.",
"The type of the success value.",
"The type of the result."
)]
#[document_parameters(
"The function to apply to the success value.",
"The memoized fallible value."
)]
#[document_returns("A new memoized fallible value containing the mapped result.")]
#[document_examples]
fn send_ref_map<'a, A: Send + Sync + 'a, B: Send + Sync + 'a>(
f: impl Fn(&A) -> B + Send + 'a,
fa: &Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, A>),
) -> Apply!(<Self as Kind!( type Of<'a, T: 'a>: 'a; )>::Of<'a, B>) {
fa.ref_map(f)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A: Monoid + Clone + 'a, E: Clone + 'a> Monoid for TryLazy<'a, A, E, RcLazyConfig> {
#[document_signature]
#[document_returns("An `RcTryLazy` producing the identity value wrapped in `Ok`.")]
#[document_examples]
fn empty() -> Self {
RcTryLazy::new(|| Ok(Monoid::empty()))
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
impl<'a, A: Monoid + Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a> Monoid
for TryLazy<'a, A, E, ArcLazyConfig>
{
#[document_signature]
#[document_returns("An `ArcTryLazy` producing the identity value wrapped in `Ok`.")]
#[document_examples]
fn empty() -> Self {
ArcTryLazy::new(|| Ok(Monoid::empty()))
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
#[document_parameters("The try-lazy value to hash.")]
impl<'a, A: Hash + 'a, E: Hash + 'a, Config: LazyConfig> Hash for TryLazy<'a, A, E, Config> {
#[document_signature]
#[document_type_parameters("The type of the hasher.")]
#[document_parameters("The hasher state.")]
#[document_examples]
fn hash<H: Hasher>(
&self,
state: &mut H,
) {
self.0.evaluate().hash(state)
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
#[document_parameters("The try-lazy value to compare.")]
impl<'a, A: PartialEq + 'a, E: PartialEq + 'a, Config: LazyConfig> PartialEq
for TryLazy<'a, A, E, Config>
{
#[document_signature]
#[document_parameters("The other try-lazy value to compare with.")]
#[document_returns("`true` if the evaluated results are equal.")]
#[document_examples]
fn eq(
&self,
other: &Self,
) -> bool {
self.0.evaluate() == other.0.evaluate()
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
impl<'a, A: Eq + 'a, E: Eq + 'a, Config: LazyConfig> Eq for TryLazy<'a, A, E, Config> {}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
#[document_parameters("The try-lazy value to compare.")]
impl<'a, A: PartialOrd + 'a, E: PartialOrd + 'a, Config: LazyConfig> PartialOrd
for TryLazy<'a, A, E, Config>
{
#[document_signature]
#[document_parameters("The other try-lazy value to compare with.")]
#[document_returns(
"The ordering between the evaluated results, or `None` if not comparable."
)]
#[document_examples]
fn partial_cmp(
&self,
other: &Self,
) -> Option<std::cmp::Ordering> {
self.0.evaluate().partial_cmp(other.0.evaluate())
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
#[document_parameters("The try-lazy value to compare.")]
impl<'a, A: Ord + 'a, E: Ord + 'a, Config: LazyConfig> Ord for TryLazy<'a, A, E, Config> {
#[document_signature]
#[document_parameters("The other try-lazy value to compare with.")]
#[document_returns("The ordering between the evaluated results.")]
#[document_examples]
fn cmp(
&self,
other: &Self,
) -> std::cmp::Ordering {
self.0.evaluate().cmp(other.0.evaluate())
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
#[document_parameters("The try-lazy value to display.")]
impl<'a, A: fmt::Display + 'a, E: fmt::Display + 'a, Config: LazyConfig> fmt::Display
for TryLazy<'a, A, E, Config>
{
#[document_signature]
#[document_parameters("The formatter.")]
#[document_returns("The formatting result.")]
#[document_examples]
fn fmt(
&self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
match self.evaluate() {
Ok(a) => write!(f, "Ok({})", a),
Err(e) => write!(f, "Err({})", e),
}
}
}
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error.",
"The memoization configuration."
)]
#[document_parameters("The try-lazy value to format.")]
impl<'a, A, E, Config: LazyConfig> fmt::Debug for TryLazy<'a, A, E, Config>
where
A: 'a,
E: 'a,
{
#[document_signature]
#[document_parameters("The formatter.")]
#[document_returns("The formatting result.")]
#[document_examples]
fn fmt(
&self,
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
f.write_str("TryLazy(..)")
}
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
#[document_parameters(
"The function that receives a fallible lazy self-reference and produces the result."
)]
#[document_returns("A new `RcTryLazy` instance.")]
#[document_examples]
pub fn rc_try_lazy_fix<'a, A: Clone + 'a, E: Clone + 'a>(
f: impl FnOnce(RcTryLazy<'a, A, E>) -> Result<A, E> + 'a
) -> RcTryLazy<'a, A, E> {
use crate::types::lazy::rc_lazy_fix;
TryLazy(rc_lazy_fix(move |inner| {
let self_ref = TryLazy(inner);
f(self_ref)
}))
}
#[document_signature]
#[document_type_parameters(
"The lifetime of the computation.",
"The type of the computed value.",
"The type of the error."
)]
#[document_parameters(
"The function that receives a fallible lazy self-reference and produces the result."
)]
#[document_returns("A new `ArcTryLazy` instance.")]
#[document_examples]
pub fn arc_try_lazy_fix<'a, A: Clone + Send + Sync + 'a, E: Clone + Send + Sync + 'a>(
f: impl FnOnce(ArcTryLazy<'a, A, E>) -> Result<A, E> + Send + 'a
) -> ArcTryLazy<'a, A, E> {
use crate::types::lazy::arc_lazy_fix;
TryLazy(arc_lazy_fix(move |inner| {
let self_ref = TryLazy(inner);
f(self_ref)
}))
}
}
pub use inner::*;
#[cfg(test)]
#[expect(
clippy::unwrap_used,
clippy::panic,
reason = "Tests use panicking operations for brevity and clarity"
)]
mod tests {
use {
super::*,
crate::{
brands::{
RcFnBrand,
TryLazyBrand,
},
types::{
ArcLazyConfig,
RcLazy,
RcLazyConfig,
TrySendThunk,
TryThunk,
TryTrampoline,
},
},
quickcheck_macros::quickcheck,
std::{
cell::RefCell,
rc::Rc,
sync::Arc,
},
};
#[test]
fn test_try_memo_caching_ok() {
let counter = Rc::new(RefCell::new(0));
let counter_clone = counter.clone();
let memo: RcTryLazy<i32, ()> = RcTryLazy::new(move || {
*counter_clone.borrow_mut() += 1;
Ok(42)
});
assert_eq!(*counter.borrow(), 0);
assert_eq!(memo.evaluate(), Ok(&42));
assert_eq!(*counter.borrow(), 1);
assert_eq!(memo.evaluate(), Ok(&42));
assert_eq!(*counter.borrow(), 1);
}
#[test]
fn test_try_memo_caching_err() {
let counter = Rc::new(RefCell::new(0));
let counter_clone = counter.clone();
let memo: RcTryLazy<i32, i32> = RcTryLazy::new(move || {
*counter_clone.borrow_mut() += 1;
Err(0)
});
assert_eq!(*counter.borrow(), 0);
assert_eq!(memo.evaluate(), Err(&0));
assert_eq!(*counter.borrow(), 1);
assert_eq!(memo.evaluate(), Err(&0));
assert_eq!(*counter.borrow(), 1);
}
#[test]
fn test_try_memo_sharing() {
let counter = Rc::new(RefCell::new(0));
let counter_clone = counter.clone();
let memo: RcTryLazy<i32, ()> = RcTryLazy::new(move || {
*counter_clone.borrow_mut() += 1;
Ok(42)
});
let shared = memo.clone();
assert_eq!(memo.evaluate(), Ok(&42));
assert_eq!(*counter.borrow(), 1);
assert_eq!(shared.evaluate(), Ok(&42));
assert_eq!(*counter.borrow(), 1);
}
#[test]
fn test_catch_unwind() {
let memo = RcTryLazy::catch_unwind(|| {
if true {
panic!("oops")
}
42
});
match memo.evaluate() {
Err(e) => assert_eq!(e, "oops"),
Ok(_) => panic!("Should have failed"),
}
}
#[test]
fn test_try_memo_from_try_eval() {
let eval = TryThunk::new(|| Ok::<i32, ()>(42));
let memo = RcTryLazy::from(eval);
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_try_memo_from_try_task() {
let task = TryTrampoline::<i32, ()>::ok(42);
let memo = RcTryLazy::from(task);
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_try_memo_from_rc_memo() {
let memo = RcLazy::new(|| 42);
let try_memo: crate::types::RcTryLazy<i32, ()> = crate::types::RcTryLazy::from(memo);
assert_eq!(try_memo.evaluate(), Ok(&42));
}
#[test]
fn test_try_memo_from_arc_memo() {
use crate::types::ArcLazy;
let memo = ArcLazy::new(|| 42);
let try_memo: crate::types::ArcTryLazy<i32, ()> = crate::types::ArcTryLazy::from(memo);
assert_eq!(try_memo.evaluate(), Ok(&42));
}
#[test]
fn test_send_defer() {
use crate::classes::send_deferrable::send_defer;
let memo: ArcTryLazy<i32, ()> = send_defer(|| ArcTryLazy::new(|| Ok(42)));
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_rc_try_lazy_ok() {
let memo = RcTryLazy::<i32, ()>::ok(42);
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_rc_try_lazy_err() {
let memo = RcTryLazy::<i32, String>::err("error".to_string());
assert_eq!(memo.evaluate(), Err(&"error".to_string()));
}
#[test]
fn test_arc_try_lazy_ok() {
let memo = ArcTryLazy::<i32, ()>::ok(42);
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_arc_try_lazy_err() {
let memo = ArcTryLazy::<i32, String>::err("error".to_string());
assert_eq!(memo.evaluate(), Err(&"error".to_string()));
}
#[test]
fn test_rc_try_lazy_from_result_ok() {
let memo: RcTryLazy<i32, String> = RcTryLazy::from(Ok(42));
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_rc_try_lazy_from_result_err() {
let memo: RcTryLazy<i32, String> = RcTryLazy::from(Err("error".to_string()));
assert_eq!(memo.evaluate(), Err(&"error".to_string()));
}
#[test]
fn test_arc_try_lazy_from_result_ok() {
let memo: ArcTryLazy<i32, String> = ArcTryLazy::from(Ok(42));
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_arc_try_lazy_from_result_err() {
let memo: ArcTryLazy<i32, String> = ArcTryLazy::from(Err("error".to_string()));
assert_eq!(memo.evaluate(), Err(&"error".to_string()));
}
#[test]
fn test_panic_poisoning() {
use std::panic;
let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| {
panic!("initializer panic");
});
let result = panic::catch_unwind(panic::AssertUnwindSafe(|| {
let _ = memo.evaluate();
}));
assert!(result.is_err(), "First evaluate should panic");
let result2 = panic::catch_unwind(panic::AssertUnwindSafe(|| {
let _ = memo.evaluate();
}));
assert!(result2.is_err(), "Second evaluate should also panic (poisoned)");
}
#[test]
fn test_arc_try_lazy_thread_safety() {
use std::{
sync::atomic::{
AtomicUsize,
Ordering,
},
thread,
};
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = counter.clone();
let memo: ArcTryLazy<i32, String> = ArcTryLazy::new(move || {
counter_clone.fetch_add(1, Ordering::SeqCst);
Ok(42)
});
let mut handles = vec![];
for _ in 0 .. 10 {
let memo_clone = memo.clone();
handles.push(thread::spawn(move || {
assert_eq!(memo_clone.evaluate(), Ok(&42));
}));
}
for handle in handles {
handle.join().unwrap();
}
assert_eq!(counter.load(Ordering::SeqCst), 1);
}
#[quickcheck]
fn memoization_ok(x: i32) -> bool {
let memo: RcTryLazy<i32, i32> = RcTryLazy::new(move || Ok(x));
let first = memo.evaluate();
let second = memo.evaluate();
first == second && first == Ok(&x)
}
#[quickcheck]
fn memoization_err(e: i32) -> bool {
let memo: RcTryLazy<i32, i32> = RcTryLazy::new(move || Err(e));
let first = memo.evaluate();
let second = memo.evaluate();
first == second && first == Err(&e)
}
#[quickcheck]
fn deferrable_transparency(x: i32) -> bool {
use crate::classes::send_deferrable::send_defer;
let memo: ArcTryLazy<i32, i32> = ArcTryLazy::new(move || Ok(x));
let deferred: ArcTryLazy<i32, i32> = send_defer(move || ArcTryLazy::new(move || Ok(x)));
memo.evaluate() == deferred.evaluate()
}
#[test]
fn test_arc_catch_unwind() {
let memo = ArcTryLazy::catch_unwind(|| {
if true {
panic!("oops")
}
42
});
match memo.evaluate() {
Err(e) => assert_eq!(e, "oops"),
Ok(_) => panic!("Should have failed"),
}
}
#[test]
fn test_arc_catch_unwind_success() {
let memo = ArcTryLazy::catch_unwind(|| 42);
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_rc_catch_unwind_with_panic() {
let memo = RcTryLazy::<i32, i32>::catch_unwind_with(
|| {
if true {
panic!("oops")
}
42
},
|_payload| -1,
);
assert_eq!(memo.evaluate(), Err(&-1));
}
#[test]
fn test_rc_catch_unwind_with_success() {
let memo = RcTryLazy::<i32, i32>::catch_unwind_with(|| 42, |_payload| -1);
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_arc_catch_unwind_with_panic() {
let memo = ArcTryLazy::<i32, i32>::catch_unwind_with(
|| {
if true {
panic!("oops")
}
42
},
|_payload| -1,
);
assert_eq!(memo.evaluate(), Err(&-1));
}
#[test]
fn test_arc_catch_unwind_with_success() {
let memo = ArcTryLazy::<i32, i32>::catch_unwind_with(|| 42, |_payload| -1);
assert_eq!(memo.evaluate(), Ok(&42));
}
#[test]
fn test_rc_try_lazy_map_ok() {
let memo = RcTryLazy::<i32, String>::ok(10);
let mapped = memo.map(|a| a * 2);
assert_eq!(mapped.evaluate(), Ok(&20));
}
#[test]
fn test_rc_try_lazy_map_err() {
let memo = RcTryLazy::<i32, String>::err("error".to_string());
let mapped = memo.map(|a| a * 2);
assert_eq!(mapped.evaluate(), Err(&"error".to_string()));
}
#[test]
fn test_rc_try_lazy_map_err_err() {
let memo = RcTryLazy::<i32, String>::err("error".to_string());
let mapped = memo.map_err(|e| format!("wrapped: {}", e));
assert_eq!(mapped.evaluate(), Err(&"wrapped: error".to_string()));
}
#[test]
fn test_rc_try_lazy_map_err_ok() {
let memo = RcTryLazy::<i32, String>::ok(42);
let mapped = memo.map_err(|e| format!("wrapped: {}", e));
assert_eq!(mapped.evaluate(), Ok(&42));
}
#[test]
fn test_rc_try_lazy_bimap_ok() {
let memo = RcTryLazy::<i32, String>::ok(10);
let mapped = memo.bimap(|a| a * 2, |e| e.len());
assert_eq!(mapped.evaluate(), Ok(&20));
}
#[test]
fn test_rc_try_lazy_bimap_err() {
let memo = RcTryLazy::<i32, String>::err("error".to_string());
let mapped = memo.bimap(|a| a * 2, |e| e.len());
assert_eq!(mapped.evaluate(), Err(&5));
}
#[test]
fn test_arc_try_lazy_map_ok() {
let memo = ArcTryLazy::<i32, String>::ok(10);
let mapped = memo.map(|a| a * 2);
assert_eq!(mapped.evaluate(), Ok(&20));
}
#[test]
fn test_arc_try_lazy_map_err() {
let memo = ArcTryLazy::<i32, String>::err("error".to_string());
let mapped = memo.map(|a| a * 2);
assert_eq!(mapped.evaluate(), Err(&"error".to_string()));
}
#[test]
fn test_arc_try_lazy_map_err_err() {
let memo = ArcTryLazy::<i32, String>::err("error".to_string());
let mapped = memo.map_err(|e| format!("wrapped: {}", e));
assert_eq!(mapped.evaluate(), Err(&"wrapped: error".to_string()));
}
#[test]
fn test_arc_try_lazy_map_err_ok() {
let memo = ArcTryLazy::<i32, String>::ok(42);
let mapped = memo.map_err(|e| format!("wrapped: {}", e));
assert_eq!(mapped.evaluate(), Ok(&42));
}
#[test]
fn test_arc_try_lazy_bimap_ok() {
let memo = ArcTryLazy::<i32, String>::ok(10);
let mapped = memo.bimap(|a| a * 2, |e| e.len());
assert_eq!(mapped.evaluate(), Ok(&20));
}
#[test]
fn test_arc_try_lazy_bimap_err() {
let memo = ArcTryLazy::<i32, String>::err("error".to_string());
let mapped = memo.bimap(|a| a * 2, |e| e.len());
assert_eq!(mapped.evaluate(), Err(&5));
}
#[test]
fn test_ref_functor_rc_try_lazy_ok() {
use crate::{
brands::TryLazyBrand,
classes::RefFunctor,
};
let memo = RcTryLazy::<i32, String>::ok(10);
let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x * 3, &memo);
assert_eq!(mapped.evaluate(), Ok(&30));
}
#[test]
fn test_ref_functor_rc_try_lazy_err() {
use crate::{
brands::TryLazyBrand,
classes::RefFunctor,
};
let memo = RcTryLazy::<i32, String>::err("fail".to_string());
let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x * 3, &memo);
assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
}
#[test]
fn test_ref_functor_rc_try_lazy_identity() {
use crate::{
brands::TryLazyBrand,
classes::RefFunctor,
};
let memo = RcTryLazy::<i32, String>::ok(42);
let mapped = TryLazyBrand::<String, RcLazyConfig>::ref_map(|x: &i32| *x, &memo.clone());
assert_eq!(mapped.evaluate(), Ok(&42));
}
#[test]
fn test_send_ref_functor_arc_try_lazy_ok() {
use crate::{
brands::TryLazyBrand,
classes::SendRefFunctor,
};
let memo = ArcTryLazy::<i32, String>::ok(10);
let mapped = TryLazyBrand::<String, ArcLazyConfig>::send_ref_map(|x: &i32| *x * 3, &memo);
assert_eq!(mapped.evaluate(), Ok(&30));
}
#[test]
fn test_send_ref_functor_arc_try_lazy_err() {
use crate::{
brands::TryLazyBrand,
classes::SendRefFunctor,
};
let memo = ArcTryLazy::<i32, String>::err("fail".to_string());
let mapped = TryLazyBrand::<String, ArcLazyConfig>::send_ref_map(|x: &i32| *x * 3, &memo);
assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
}
#[test]
fn test_rc_try_lazy_ref_map_ok() {
let memo = RcTryLazy::<i32, String>::ok(10);
let mapped = memo.ref_map(|x| *x * 2);
assert_eq!(mapped.evaluate(), Ok(&20));
}
#[test]
fn test_rc_try_lazy_ref_map_err() {
let memo = RcTryLazy::<i32, String>::err("fail".to_string());
let mapped = memo.ref_map(|x| *x * 2);
assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
}
#[test]
fn test_rc_try_lazy_ref_map_identity() {
let memo = RcTryLazy::<i32, String>::ok(42);
let mapped = memo.ref_map(|x| *x);
assert_eq!(mapped.evaluate(), Ok(&42));
}
#[test]
fn test_arc_try_lazy_ref_map_ok() {
let memo = ArcTryLazy::<i32, String>::ok(10);
let mapped = memo.ref_map(|x| *x * 2);
assert_eq!(mapped.evaluate(), Ok(&20));
}
#[test]
fn test_arc_try_lazy_ref_map_err() {
let memo = ArcTryLazy::<i32, String>::err("fail".to_string());
let mapped = memo.ref_map(|x| *x * 2);
assert_eq!(mapped.evaluate(), Err(&"fail".to_string()));
}
#[test]
fn test_arc_try_lazy_ref_map_identity() {
let memo = ArcTryLazy::<i32, String>::ok(42);
let mapped = memo.ref_map(|x| *x);
assert_eq!(mapped.evaluate(), Ok(&42));
}
#[test]
fn test_semigroup_rc_try_lazy_both_ok() {
use crate::functions::append;
let a = RcTryLazy::<String, String>::ok("Hello".to_string());
let b = RcTryLazy::<String, String>::ok(" World".to_string());
let c = append(a, b);
assert_eq!(c.evaluate(), Ok(&"Hello World".to_string()));
}
#[test]
fn test_semigroup_rc_try_lazy_first_err() {
use crate::functions::append;
let a = RcTryLazy::<String, String>::err("err1".to_string());
let b = RcTryLazy::<String, String>::ok("ok".to_string());
let c = append(a, b);
assert_eq!(c.evaluate(), Err(&"err1".to_string()));
}
#[test]
fn test_semigroup_rc_try_lazy_second_err() {
use crate::functions::append;
let a = RcTryLazy::<String, String>::ok("ok".to_string());
let b = RcTryLazy::<String, String>::err("err2".to_string());
let c = append(a, b);
assert_eq!(c.evaluate(), Err(&"err2".to_string()));
}
#[test]
fn test_semigroup_arc_try_lazy_both_ok() {
use crate::functions::append;
let a = ArcTryLazy::<String, String>::ok("Hello".to_string());
let b = ArcTryLazy::<String, String>::ok(" World".to_string());
let c = append(a, b);
assert_eq!(c.evaluate(), Ok(&"Hello World".to_string()));
}
#[test]
fn test_semigroup_arc_try_lazy_first_err() {
use crate::functions::append;
let a = ArcTryLazy::<String, String>::err("err1".to_string());
let b = ArcTryLazy::<String, String>::ok("ok".to_string());
let c = append(a, b);
assert_eq!(c.evaluate(), Err(&"err1".to_string()));
}
#[test]
fn test_monoid_rc_try_lazy_empty() {
use crate::functions::empty;
let t: RcTryLazy<String, ()> = empty();
assert_eq!(t.evaluate(), Ok(&String::new()));
}
#[test]
fn test_monoid_arc_try_lazy_empty() {
use crate::functions::empty;
let t: ArcTryLazy<String, ()> = empty();
assert_eq!(t.evaluate(), Ok(&String::new()));
}
#[test]
fn test_monoid_rc_try_lazy_left_identity() {
use crate::functions::{
append,
empty,
};
let a = RcTryLazy::<String, ()>::ok("hello".to_string());
let result = append(empty::<RcTryLazy<String, ()>>(), a);
assert_eq!(result.evaluate(), Ok(&"hello".to_string()));
}
#[test]
fn test_monoid_rc_try_lazy_right_identity() {
use crate::functions::{
append,
empty,
};
let a = RcTryLazy::<String, ()>::ok("hello".to_string());
let result = append(a, empty::<RcTryLazy<String, ()>>());
assert_eq!(result.evaluate(), Ok(&"hello".to_string()));
}
#[test]
fn test_foldable_rc_try_lazy_fold_right_ok() {
use crate::{
brands::*,
functions::*,
};
let lazy = RcTryLazy::<i32, String>::ok(10);
let result = explicit::fold_right::<
crate::brands::RcFnBrand,
TryLazyBrand<String, RcLazyConfig>,
_,
_,
_,
_,
>(|a: &i32, b| *a + b, 5, &lazy);
assert_eq!(result, 15);
}
#[test]
fn test_foldable_rc_try_lazy_fold_right_err() {
use crate::{
brands::*,
functions::*,
};
let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
let result = explicit::fold_right::<
crate::brands::RcFnBrand,
TryLazyBrand<String, RcLazyConfig>,
_,
_,
_,
_,
>(|a: &i32, b| *a + b, 5, &lazy);
assert_eq!(result, 5);
}
#[test]
fn test_foldable_rc_try_lazy_fold_left_ok() {
use crate::{
brands::*,
functions::*,
};
let lazy = RcTryLazy::<i32, String>::ok(10);
let result = explicit::fold_left::<
crate::brands::RcFnBrand,
TryLazyBrand<String, RcLazyConfig>,
_,
_,
_,
_,
>(|b, a: &i32| b + *a, 5, &lazy);
assert_eq!(result, 15);
}
#[test]
fn test_foldable_rc_try_lazy_fold_left_err() {
use crate::{
brands::*,
functions::*,
};
let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
let result = explicit::fold_left::<
crate::brands::RcFnBrand,
TryLazyBrand<String, RcLazyConfig>,
_,
_,
_,
_,
>(|b, a: &i32| b + *a, 5, &lazy);
assert_eq!(result, 5);
}
#[test]
fn test_foldable_rc_try_lazy_fold_map_ok() {
use crate::{
brands::*,
functions::*,
};
let lazy = RcTryLazy::<i32, String>::ok(10);
let result = explicit::fold_map::<RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _, _, _>(
|a: &i32| a.to_string(),
&lazy,
);
assert_eq!(result, "10");
}
#[test]
fn test_foldable_rc_try_lazy_fold_map_err() {
use crate::{
brands::*,
functions::*,
};
let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
let result = explicit::fold_map::<RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _, _, _>(
|a: &i32| a.to_string(),
&lazy,
);
assert_eq!(result, "");
}
#[test]
fn test_foldable_arc_try_lazy_fold_right_ok() {
use crate::{
brands::*,
functions::*,
};
let lazy = ArcTryLazy::<i32, String>::ok(10);
let result = explicit::fold_right::<
crate::brands::ArcFnBrand,
TryLazyBrand<String, ArcLazyConfig>,
_,
_,
_,
_,
>(|a: &i32, b| *a + b, 5, &lazy);
assert_eq!(result, 15);
}
#[test]
fn test_foldable_arc_try_lazy_fold_right_err() {
use crate::{
brands::*,
functions::*,
};
let lazy = ArcTryLazy::<i32, String>::err("fail".to_string());
let result = explicit::fold_right::<
crate::brands::ArcFnBrand,
TryLazyBrand<String, ArcLazyConfig>,
_,
_,
_,
_,
>(|a: &i32, b| *a + b, 5, &lazy);
assert_eq!(result, 5);
}
#[test]
fn test_rc_try_lazy_ref_fold_map_with_index_ok() {
use crate::classes::ref_foldable_with_index::RefFoldableWithIndex;
let lazy = RcTryLazy::<i32, ()>::ok(42);
let result =
<TryLazyBrand<(), RcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
RcFnBrand,
_,
_,
>(|_, x: &i32| x.to_string(), &lazy);
assert_eq!(result, "42");
}
#[test]
fn test_rc_try_lazy_ref_fold_map_with_index_err() {
use crate::classes::ref_foldable_with_index::RefFoldableWithIndex;
let lazy = RcTryLazy::<i32, String>::err("fail".to_string());
let result =
<TryLazyBrand<String, RcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
RcFnBrand,
_,
_,
>(|_, x: &i32| x.to_string(), &lazy);
assert_eq!(result, "");
}
#[test]
fn test_arc_try_lazy_ref_fold_map_with_index_ok() {
use crate::classes::ref_foldable_with_index::RefFoldableWithIndex;
let lazy = ArcTryLazy::<i32, ()>::ok(10);
let result =
<TryLazyBrand<(), ArcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
RcFnBrand,
_,
_,
>(|_, x: &i32| x.to_string(), &lazy);
assert_eq!(result, "10");
}
#[test]
fn test_arc_try_lazy_ref_fold_map_with_index_err() {
use crate::classes::ref_foldable_with_index::RefFoldableWithIndex;
let lazy = ArcTryLazy::<i32, String>::err("fail".to_string());
let result =
<TryLazyBrand<String, ArcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
RcFnBrand,
_,
_,
>(|_, x: &i32| x.to_string(), &lazy);
assert_eq!(result, "");
}
#[test]
fn test_rc_try_lazy_foldable_with_index_compatibility() {
use crate::{
brands::*,
classes::ref_foldable_with_index::RefFoldableWithIndex,
functions::*,
};
let lazy1 = RcTryLazy::<i32, ()>::ok(7);
let lazy2 = RcTryLazy::<i32, ()>::ok(7);
let fold_result = explicit::fold_map::<RcFnBrand, TryLazyBrand<(), RcLazyConfig>, _, _, _, _>(
|a: &i32| a.to_string(),
&lazy1,
);
let fold_with_index_result =
<TryLazyBrand<(), RcLazyConfig> as RefFoldableWithIndex>::ref_fold_map_with_index::<
RcFnBrand,
_,
_,
>(|_, a| a.to_string(), &lazy2);
assert_eq!(fold_result, fold_with_index_result);
}
#[test]
fn test_semigroup_append_first_err_short_circuits() {
use {
crate::classes::Semigroup,
std::cell::Cell,
};
let counter = Rc::new(Cell::new(0u32));
let counter_clone = counter.clone();
let a: RcTryLazy<String, String> = RcTryLazy::new(|| Err("first failed".into()));
let b: RcTryLazy<String, String> = RcTryLazy::new(move || {
counter_clone.set(counter_clone.get() + 1);
Ok("second".into())
});
let result = Semigroup::append(a, b);
assert_eq!(result.evaluate(), Err(&"first failed".to_string()));
assert_eq!(counter.get(), 0, "second operand should not be evaluated");
}
#[test]
fn test_semigroup_append_second_err() {
use crate::classes::Semigroup;
let a: RcTryLazy<String, String> = RcTryLazy::new(|| Ok("hello".into()));
let b: RcTryLazy<String, String> = RcTryLazy::new(|| Err("second failed".into()));
let result = Semigroup::append(a, b);
assert_eq!(result.evaluate(), Err(&"second failed".to_string()));
}
#[test]
fn test_semigroup_append_both_ok() {
use crate::classes::Semigroup;
let a: RcTryLazy<String, ()> = RcTryLazy::new(|| Ok("Hello".into()));
let b: RcTryLazy<String, ()> = RcTryLazy::new(|| Ok(" World".into()));
let result = Semigroup::append(a, b);
assert_eq!(result.evaluate(), Ok(&"Hello World".to_string()));
}
#[test]
fn test_map_ok() {
let memo = RcTryLazy::new(|| Ok::<i32, ()>(21));
let mapped = memo.map(|x| x * 2);
assert_eq!(mapped.evaluate(), Ok(&42));
}
#[test]
fn test_map_err() {
let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
let mapped = memo.map(|x| x * 2);
assert_eq!(mapped.evaluate(), Err(&"oops".to_string()));
}
#[test]
fn test_map_err_on_err() {
let memo: RcTryLazy<i32, i32> = RcTryLazy::new(|| Err(21));
let mapped = memo.map_err(|e| e * 2);
assert_eq!(mapped.evaluate(), Err(&42));
}
#[test]
fn test_map_err_on_ok() {
let memo: RcTryLazy<i32, i32> = RcTryLazy::new(|| Ok(42));
let mapped = memo.map_err(|e| e * 2);
assert_eq!(mapped.evaluate(), Ok(&42));
}
#[test]
fn test_and_then_ok() {
let memo = RcTryLazy::new(|| Ok::<i32, String>(21));
let chained = memo.and_then(|x| Ok(x * 2));
assert_eq!(chained.evaluate(), Ok(&42));
}
#[test]
fn test_and_then_chained_err() {
let memo = RcTryLazy::new(|| Ok::<i32, String>(21));
let chained = memo.and_then(|_: &i32| Err::<i32, String>("chained failure".into()));
assert_eq!(chained.evaluate(), Err(&"chained failure".to_string()));
}
#[test]
fn test_and_then_initial_err() {
let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("initial".into()));
let chained = memo.and_then(|x| Ok(x * 2));
assert_eq!(chained.evaluate(), Err(&"initial".to_string()));
}
#[test]
fn test_or_else_recovers() {
let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
let recovered = memo.or_else(|_| Ok(42));
assert_eq!(recovered.evaluate(), Ok(&42));
}
#[test]
fn test_or_else_noop_on_ok() {
let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Ok(42));
let recovered = memo.or_else(|_| Ok(99));
assert_eq!(recovered.evaluate(), Ok(&42));
}
#[test]
fn test_or_else_recovery_fails() {
let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("first".into()));
let recovered = memo.or_else(|_| Err("second".into()));
assert_eq!(recovered.evaluate(), Err(&"second".to_string()));
}
#[test]
fn test_foldable_ok() {
use crate::{
brands::*,
functions::*,
};
let memo: RcTryLazy<i32, ()> = RcTryLazy::new(|| Ok(10));
let result = explicit::fold_right::<RcFnBrand, TryLazyBrand<(), RcLazyConfig>, _, _, _, _>(
|a: &i32, b| *a + b,
5,
&memo,
);
assert_eq!(result, 15);
}
#[test]
fn test_foldable_err() {
use crate::{
brands::*,
functions::*,
};
let memo: RcTryLazy<i32, String> = RcTryLazy::new(|| Err("oops".into()));
let result =
explicit::fold_right::<RcFnBrand, TryLazyBrand<String, RcLazyConfig>, _, _, _, _>(
|a: &i32, b| *a + b,
5,
&memo,
);
assert_eq!(result, 5);
}
#[test]
fn test_from_try_send_thunk_ok() {
let counter = Arc::new(std::sync::atomic::AtomicUsize::new(0));
let counter_clone = counter.clone();
let thunk: TrySendThunk<i32, ()> = TrySendThunk::new(move || {
counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
Ok(42)
});
assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 0);
let lazy: ArcTryLazy<i32, ()> = ArcTryLazy::from(thunk);
assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 0);
assert_eq!(lazy.evaluate(), Ok(&42));
assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
assert_eq!(lazy.evaluate(), Ok(&42));
assert_eq!(counter.load(std::sync::atomic::Ordering::SeqCst), 1);
}
#[test]
fn test_from_try_send_thunk_err() {
let thunk: TrySendThunk<i32, String> = TrySendThunk::new(move || Err("fail".to_string()));
let lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(thunk);
assert_eq!(lazy.evaluate(), Err(&"fail".to_string()));
}
#[test]
fn test_try_send_thunk_into_arc_try_lazy() {
let thunk: TrySendThunk<i32, ()> = TrySendThunk::ok(42);
let lazy: ArcTryLazy<i32, ()> = thunk.into();
assert_eq!(lazy.evaluate(), Ok(&42));
}
#[test]
fn test_try_lazy_partial_eq_ok() {
let a = RcTryLazy::<i32, ()>::ok(42);
let b = RcTryLazy::<i32, ()>::ok(42);
assert_eq!(a, b);
}
#[test]
fn test_try_lazy_partial_eq_ok_neq() {
let a = RcTryLazy::<i32, ()>::ok(1);
let b = RcTryLazy::<i32, ()>::ok(2);
assert_ne!(a, b);
}
#[test]
fn test_try_lazy_partial_eq_err() {
let a = RcTryLazy::<i32, String>::err("fail".to_string());
let b = RcTryLazy::<i32, String>::err("fail".to_string());
assert_eq!(a, b);
}
#[test]
fn test_try_lazy_partial_eq_ok_vs_err() {
let a = RcTryLazy::<i32, i32>::ok(1);
let b = RcTryLazy::<i32, i32>::err(1);
assert_ne!(a, b);
}
#[test]
fn test_try_lazy_partial_eq_arc() {
let a = ArcTryLazy::<i32, ()>::ok(42);
let b = ArcTryLazy::<i32, ()>::ok(42);
assert_eq!(a, b);
}
#[test]
fn test_try_lazy_hash_eq() {
use std::{
collections::hash_map::DefaultHasher,
hash::{
Hash,
Hasher,
},
};
let a = RcTryLazy::<i32, ()>::ok(42);
let b = RcTryLazy::<i32, ()>::ok(42);
let mut h1 = DefaultHasher::new();
a.hash(&mut h1);
let mut h2 = DefaultHasher::new();
b.hash(&mut h2);
assert_eq!(h1.finish(), h2.finish());
}
#[test]
fn test_try_lazy_hash_matches_result() {
use std::{
collections::hash_map::DefaultHasher,
hash::{
Hash,
Hasher,
},
};
let lazy = RcTryLazy::<i32, ()>::ok(42);
let mut h1 = DefaultHasher::new();
lazy.hash(&mut h1);
let result: Result<i32, ()> = Ok(42);
let mut h2 = DefaultHasher::new();
result.hash(&mut h2);
assert_eq!(h1.finish(), h2.finish());
}
#[test]
fn test_try_lazy_partial_ord_ok() {
let a = RcTryLazy::<i32, ()>::ok(1);
let b = RcTryLazy::<i32, ()>::ok(2);
assert!(a < b);
assert!(b > a);
}
#[test]
fn test_try_lazy_partial_ord_eq() {
let a = RcTryLazy::<i32, ()>::ok(42);
let b = RcTryLazy::<i32, ()>::ok(42);
assert!(a <= b);
assert!(a >= b);
}
#[test]
fn test_try_lazy_ord_ok() {
use std::cmp::Ordering;
let a = RcTryLazy::<i32, ()>::ok(1);
let b = RcTryLazy::<i32, ()>::ok(2);
assert_eq!(a.cmp(&b), Ordering::Less);
assert_eq!(b.cmp(&a), Ordering::Greater);
}
#[test]
fn test_try_lazy_ord_eq() {
use std::cmp::Ordering;
let a = RcTryLazy::<i32, ()>::ok(42);
let b = RcTryLazy::<i32, ()>::ok(42);
assert_eq!(a.cmp(&b), Ordering::Equal);
}
#[test]
fn test_try_lazy_ord_arc() {
use std::cmp::Ordering;
let a = ArcTryLazy::<i32, ()>::ok(1);
let b = ArcTryLazy::<i32, ()>::ok(2);
assert_eq!(a.cmp(&b), Ordering::Less);
}
#[test]
fn test_try_lazy_eq_trait() {
fn assert_eq_impl<T: Eq>(_: &T) {}
let a = RcTryLazy::<i32, ()>::ok(42);
assert_eq_impl(&a);
}
#[test]
fn test_try_lazy_display_ok_rc() {
let lazy = RcTryLazy::<i32, String>::ok(42);
assert_eq!(format!("{}", lazy), "Ok(42)");
}
#[test]
fn test_try_lazy_display_err_rc() {
let lazy = RcTryLazy::<i32, String>::err("oops".to_string());
assert_eq!(format!("{}", lazy), "Err(oops)");
}
#[test]
fn test_try_lazy_display_ok_arc() {
let lazy = ArcTryLazy::<i32, String>::ok(42);
assert_eq!(format!("{}", lazy), "Ok(42)");
}
#[test]
fn test_try_lazy_display_err_arc() {
let lazy = ArcTryLazy::<i32, String>::err("oops".to_string());
assert_eq!(format!("{}", lazy), "Err(oops)");
}
#[test]
fn test_try_lazy_rc_to_arc_ok() {
let rc_lazy = RcTryLazy::<i32, String>::ok(42);
let arc_lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(rc_lazy);
assert_eq!(arc_lazy.evaluate(), Ok(&42));
}
#[test]
fn test_try_lazy_rc_to_arc_err() {
let rc_lazy = RcTryLazy::<i32, String>::err("fail".to_string());
let arc_lazy: ArcTryLazy<i32, String> = ArcTryLazy::from(rc_lazy);
assert_eq!(arc_lazy.evaluate(), Err(&"fail".to_string()));
}
#[test]
fn test_try_lazy_arc_to_rc_ok() {
let arc_lazy = ArcTryLazy::<i32, String>::ok(42);
let rc_lazy: RcTryLazy<i32, String> = RcTryLazy::from(arc_lazy);
assert_eq!(rc_lazy.evaluate(), Ok(&42));
}
#[test]
fn test_try_lazy_arc_to_rc_err() {
let arc_lazy = ArcTryLazy::<i32, String>::err("fail".to_string());
let rc_lazy: RcTryLazy<i32, String> = RcTryLazy::from(arc_lazy);
assert_eq!(rc_lazy.evaluate(), Err(&"fail".to_string()));
}
#[test]
fn test_rc_try_lazy_fix_ok_constant() {
let fixed = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, ()>| Ok(42));
assert_eq!(fixed.evaluate(), Ok(&42));
}
#[test]
fn test_rc_try_lazy_fix_err_constant() {
let fixed = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, String>| Err("fail".to_string()));
assert_eq!(fixed.evaluate(), Err(&"fail".to_string()));
}
#[test]
fn test_rc_try_lazy_fix_memoization() {
let counter = Rc::new(RefCell::new(0));
let counter_clone = counter.clone();
let fixed = rc_try_lazy_fix(move |_self_ref: RcTryLazy<i32, ()>| {
*counter_clone.borrow_mut() += 1;
Ok(100)
});
assert_eq!(*counter.borrow(), 0);
assert_eq!(fixed.evaluate(), Ok(&100));
assert_eq!(*counter.borrow(), 1);
assert_eq!(fixed.evaluate(), Ok(&100));
assert_eq!(*counter.borrow(), 1);
}
#[test]
fn test_rc_try_lazy_fix_self_reference() {
let fixed = rc_try_lazy_fix(|self_ref: RcTryLazy<Vec<i32>, ()>| {
let _ = self_ref;
Ok(vec![1, 2, 3])
});
assert_eq!(fixed.evaluate(), Ok(&vec![1, 2, 3]));
}
#[test]
fn test_rc_try_lazy_fix_clone_sharing() {
let fixed = rc_try_lazy_fix(|_self_ref: RcTryLazy<i32, ()>| Ok(55));
let cloned = fixed.clone();
assert_eq!(fixed.evaluate(), Ok(&55));
assert_eq!(cloned.evaluate(), Ok(&55));
}
#[test]
fn test_rc_try_lazy_fix_uses_self_ref() {
let counter = Rc::new(RefCell::new(0));
let counter_clone = counter.clone();
let lazy = rc_try_lazy_fix(move |self_ref: RcTryLazy<i32, ()>| {
*counter_clone.borrow_mut() += 1;
let _ = self_ref;
Ok(42)
});
assert_eq!(lazy.evaluate(), Ok(&42));
assert_eq!(*counter.borrow(), 1);
assert_eq!(lazy.evaluate(), Ok(&42));
assert_eq!(*counter.borrow(), 1);
}
#[test]
fn test_arc_try_lazy_fix_ok_constant() {
let fixed = arc_try_lazy_fix(|_self_ref: ArcTryLazy<i32, ()>| Ok(42));
assert_eq!(fixed.evaluate(), Ok(&42));
}
#[test]
fn test_arc_try_lazy_fix_err_constant() {
let fixed = arc_try_lazy_fix(|_self_ref: ArcTryLazy<i32, String>| Err("fail".to_string()));
assert_eq!(fixed.evaluate(), Err(&"fail".to_string()));
}
#[test]
fn test_arc_try_lazy_fix_memoization() {
use std::sync::atomic::{
AtomicUsize,
Ordering,
};
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = counter.clone();
let fixed = arc_try_lazy_fix(move |_self_ref: ArcTryLazy<i32, ()>| {
counter_clone.fetch_add(1, Ordering::SeqCst);
Ok(100)
});
assert_eq!(counter.load(Ordering::SeqCst), 0);
assert_eq!(fixed.evaluate(), Ok(&100));
assert_eq!(counter.load(Ordering::SeqCst), 1);
assert_eq!(fixed.evaluate(), Ok(&100));
assert_eq!(counter.load(Ordering::SeqCst), 1);
}
#[test]
fn test_arc_try_lazy_fix_self_reference() {
let fixed = arc_try_lazy_fix(|self_ref: ArcTryLazy<Vec<i32>, ()>| {
let _ = self_ref;
Ok(vec![1, 2, 3])
});
assert_eq!(fixed.evaluate(), Ok(&vec![1, 2, 3]));
}
#[test]
fn test_arc_try_lazy_fix_uses_self_ref() {
use std::sync::atomic::{
AtomicUsize,
Ordering,
};
let counter = Arc::new(AtomicUsize::new(0));
let counter_clone = counter.clone();
let lazy = arc_try_lazy_fix(move |self_ref: ArcTryLazy<i32, ()>| {
counter_clone.fetch_add(1, Ordering::SeqCst);
let _ = self_ref;
Ok(42)
});
assert_eq!(lazy.evaluate(), Ok(&42));
assert_eq!(counter.load(Ordering::SeqCst), 1);
assert_eq!(lazy.evaluate(), Ok(&42));
assert_eq!(counter.load(Ordering::SeqCst), 1);
}
#[test]
fn test_arc_try_lazy_fix_thread_safety() {
use std::thread;
let lazy = arc_try_lazy_fix(|self_ref: ArcTryLazy<i32, ()>| {
let _ = self_ref;
Ok(42)
});
let mut handles = vec![];
for _ in 0 .. 10 {
let lazy_clone = lazy.clone();
handles.push(thread::spawn(move || {
assert_eq!(lazy_clone.evaluate(), Ok(&42));
}));
}
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn test_rc_try_lazy_fix_knot_tying_ptr_eq() {
let stash: Rc<RefCell<Option<RcTryLazy<i32, ()>>>> = Rc::new(RefCell::new(None));
let stash_clone = stash.clone();
let lazy = rc_try_lazy_fix(move |self_ref: RcTryLazy<i32, ()>| {
*stash_clone.borrow_mut() = Some(self_ref);
Ok(42)
});
assert_eq!(lazy.evaluate(), Ok(&42));
let self_ref = stash.borrow().clone().unwrap();
assert!(Rc::ptr_eq(&lazy.0.0, &self_ref.0.0));
assert_eq!(self_ref.evaluate(), Ok(&42));
}
#[test]
fn test_rc_try_lazy_fix_knot_tying_shared_cache() {
let counter = Rc::new(RefCell::new(0));
let stash: Rc<RefCell<Option<RcTryLazy<i32, ()>>>> = Rc::new(RefCell::new(None));
let counter_clone = counter.clone();
let stash_clone = stash.clone();
let lazy = rc_try_lazy_fix(move |self_ref: RcTryLazy<i32, ()>| {
*stash_clone.borrow_mut() = Some(self_ref);
*counter_clone.borrow_mut() += 1;
Ok(100)
});
assert_eq!(*counter.borrow(), 0);
assert_eq!(lazy.evaluate(), Ok(&100));
assert_eq!(*counter.borrow(), 1);
let self_ref = stash.borrow().clone().unwrap();
assert_eq!(self_ref.evaluate(), Ok(&100));
assert_eq!(*counter.borrow(), 1);
}
#[test]
fn test_rc_try_lazy_fix_knot_tying_err_shared() {
let stash: Rc<RefCell<Option<RcTryLazy<i32, String>>>> = Rc::new(RefCell::new(None));
let stash_clone = stash.clone();
let lazy = rc_try_lazy_fix(move |self_ref: RcTryLazy<i32, String>| {
*stash_clone.borrow_mut() = Some(self_ref);
Err("fail".to_string())
});
assert_eq!(lazy.evaluate(), Err(&"fail".to_string()));
let self_ref = stash.borrow().clone().unwrap();
assert_eq!(self_ref.evaluate(), Err(&"fail".to_string()));
assert!(Rc::ptr_eq(&lazy.0.0, &self_ref.0.0));
}
#[test]
#[should_panic]
fn test_rc_try_lazy_fix_reentrant_panics() {
let lazy = rc_try_lazy_fix(|self_ref: RcTryLazy<i32, ()>| {
Ok(*self_ref.evaluate().unwrap() + 1)
});
let _ = lazy.evaluate();
}
#[test]
fn test_arc_try_lazy_fix_knot_tying_ptr_eq() {
use std::sync::Mutex;
let stash: Arc<Mutex<Option<ArcTryLazy<i32, ()>>>> = Arc::new(Mutex::new(None));
let stash_clone = stash.clone();
let lazy = arc_try_lazy_fix(move |self_ref: ArcTryLazy<i32, ()>| {
*stash_clone.lock().unwrap() = Some(self_ref);
Ok(42)
});
assert_eq!(lazy.evaluate(), Ok(&42));
let self_ref = stash.lock().unwrap().clone().unwrap();
assert!(Arc::ptr_eq(&lazy.0.0, &self_ref.0.0));
assert_eq!(self_ref.evaluate(), Ok(&42));
}
#[test]
fn test_arc_try_lazy_fix_knot_tying_shared_cache() {
use std::sync::{
Mutex,
atomic::{
AtomicUsize,
Ordering,
},
};
let counter = Arc::new(AtomicUsize::new(0));
let stash: Arc<Mutex<Option<ArcTryLazy<i32, ()>>>> = Arc::new(Mutex::new(None));
let counter_clone = counter.clone();
let stash_clone = stash.clone();
let lazy = arc_try_lazy_fix(move |self_ref: ArcTryLazy<i32, ()>| {
*stash_clone.lock().unwrap() = Some(self_ref);
counter_clone.fetch_add(1, Ordering::SeqCst);
Ok(100)
});
assert_eq!(counter.load(Ordering::SeqCst), 0);
assert_eq!(lazy.evaluate(), Ok(&100));
assert_eq!(counter.load(Ordering::SeqCst), 1);
let self_ref = stash.lock().unwrap().clone().unwrap();
assert_eq!(self_ref.evaluate(), Ok(&100));
assert_eq!(counter.load(Ordering::SeqCst), 1);
}
#[test]
fn test_arc_try_lazy_fix_knot_tying_cross_thread() {
use std::{
sync::Mutex,
thread,
};
let stash: Arc<Mutex<Option<ArcTryLazy<i32, ()>>>> = Arc::new(Mutex::new(None));
let stash_clone = stash.clone();
let lazy = arc_try_lazy_fix(move |self_ref: ArcTryLazy<i32, ()>| {
*stash_clone.lock().unwrap() = Some(self_ref);
Ok(77)
});
assert_eq!(lazy.evaluate(), Ok(&77));
let self_ref = stash.lock().unwrap().clone().unwrap();
let handle = thread::spawn(move || self_ref.evaluate_owned());
assert_eq!(handle.join().unwrap(), Ok(77));
}
}