#![allow(unused_imports, reason = "Kind is used inside Apply! macro expansion")]
#![expect(
clippy::type_complexity,
reason = "Complex Apply! projections are inherent to HKT dispatch POCs"
)]
use {
fp_library::{
Apply,
Kind,
brands::{
ArcFnBrand,
OptionBrand,
RcFnBrand,
ResultErrAppliedBrand,
VecBrand,
},
classes::{
CloneFn,
RefSemiapplicative,
Semiapplicative,
},
dispatch::{
ClosureMode,
Ref,
Val,
},
functions::lift_fn_new,
kinds::{
InferableBrand_cdc7cd43dac7585f,
Kind_cdc7cd43dac7585f,
},
},
std::rc::Rc,
};
trait FnBrandSlotModed<FnBrand, A, B, Mode = Val> {}
impl<'a, A: 'a, B: 'a> FnBrandSlotModed<RcFnBrand, A, B, Val> for Rc<dyn 'a + Fn(A) -> B> {}
impl<'a, A: 'a, B: 'a> FnBrandSlotModed<ArcFnBrand, A, B, Val>
for std::sync::Arc<dyn 'a + Fn(A) -> B + Send + Sync>
{
}
impl<'a, A: 'a, B: 'a> FnBrandSlotModed<RcFnBrand, A, B, Ref> for Rc<dyn 'a + Fn(&A) -> B> {}
impl<'a, A: 'a, B: 'a> FnBrandSlotModed<ArcFnBrand, A, B, Ref>
for std::sync::Arc<dyn 'a + Fn(&A) -> B + Send + Sync>
{
}
trait FnBrandSlotBroad<FnBrand> {}
impl<T: ?Sized> FnBrandSlotBroad<RcFnBrand> for Rc<T> {}
impl<T: ?Sized> FnBrandSlotBroad<ArcFnBrand> for std::sync::Arc<T> {}
mod approach_a {
use super::*;
pub trait ApplyDispatch<
'a,
FnBrand,
Brand: Kind_cdc7cd43dac7585f,
A: 'a,
B: 'a,
W: 'a,
FA,
Marker,
> {
fn dispatch(
self,
fa: FA,
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>);
}
impl<'a, FnBrand, Brand, A, B, W>
ApplyDispatch<
'a,
FnBrand,
Brand,
A,
B,
W,
Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
Val,
> for Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>)
where
FnBrand: CloneFn + 'a,
Brand: Semiapplicative,
A: Clone + 'a,
B: 'a,
W: Clone + 'a,
Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>): Into<
Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, <FnBrand as CloneFn>::Of<'a, A, B>>),
>,
{
fn dispatch(
self,
fa: Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>) {
Brand::apply::<FnBrand, A, B>(self.into(), fa)
}
}
impl<'a, 'b, FnBrand, Brand, A, B, W>
ApplyDispatch<
'a,
FnBrand,
Brand,
A,
B,
W,
&'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
Ref,
> for &'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>)
where
'a: 'b,
FnBrand: CloneFn<Ref> + 'a,
Brand: RefSemiapplicative,
A: 'a,
B: 'a,
W: 'a,
&'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>): Into<
&'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, <FnBrand as CloneFn<Ref>>::Of<'a, A, B>>),
>,
{
fn dispatch(
self,
fa: &'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>) {
Brand::ref_apply::<FnBrand, A, B>(self.into(), fa)
}
}
pub fn apply<'a, FnBrand, Brand, A, B, W, FF, FA>(
ff: FF,
fa: FA,
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>)
where
Brand: Kind_cdc7cd43dac7585f,
FnBrand: CloneFn + CloneFn<Ref> + 'a,
A: 'a,
B: 'a,
W: 'a + FnBrandSlotBroad<FnBrand>,
FA: InferableBrand_cdc7cd43dac7585f<'a, Brand, A>,
FF: InferableBrand_cdc7cd43dac7585f<'a, Brand, W>
+ ApplyDispatch<
'a,
FnBrand,
Brand,
A,
B,
W,
FA,
<FA as InferableBrand_cdc7cd43dac7585f<'a, Brand, A>>::Marker,
>, {
ff.dispatch(fa)
}
}
mod approach_b {
use super::*;
pub trait ApplyDispatch<
'a,
FnBrand,
Brand: Kind_cdc7cd43dac7585f,
A: 'a,
B: 'a,
W: 'a,
FA,
Marker,
> {
fn dispatch(
self,
fa: FA,
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>);
}
impl<'a, FnBrand, Brand, A, B, W>
ApplyDispatch<
'a,
FnBrand,
Brand,
A,
B,
W,
Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
Val,
> for Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>)
where
FnBrand: CloneFn + 'a,
Brand: Semiapplicative,
A: Clone + 'a,
B: 'a,
W: Clone + 'a,
Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>): Into<
Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, <FnBrand as CloneFn>::Of<'a, A, B>>),
>,
{
fn dispatch(
self,
fa: Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>) {
Brand::apply::<FnBrand, A, B>(self.into(), fa)
}
}
impl<'a, 'b, FnBrand, Brand, A, B, W>
ApplyDispatch<
'a,
FnBrand,
Brand,
A,
B,
W,
&'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
Ref,
> for &'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>)
where
'a: 'b,
FnBrand: CloneFn<Ref> + 'a,
Brand: RefSemiapplicative,
A: 'a,
B: 'a,
W: 'a,
&'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>): Into<
&'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, <FnBrand as CloneFn<Ref>>::Of<'a, A, B>>),
>,
{
fn dispatch(
self,
fa: &'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>) {
Brand::ref_apply::<FnBrand, A, B>(self.into(), fa)
}
}
pub fn apply<'a, FnBrand, Brand, A, B, W, FF, FA>(
ff: FF,
fa: FA,
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>)
where
Brand: Kind_cdc7cd43dac7585f,
A: 'a,
B: 'a,
W: 'a,
FA: InferableBrand_cdc7cd43dac7585f<'a, Brand, A>,
<FA as InferableBrand_cdc7cd43dac7585f<'a, Brand, A>>::Marker: ClosureMode,
FnBrand: CloneFn<<FA as InferableBrand_cdc7cd43dac7585f<'a, Brand, A>>::Marker> + 'a,
W: FnBrandSlotModed<
FnBrand,
A,
B,
<FA as InferableBrand_cdc7cd43dac7585f<'a, Brand, A>>::Marker,
>,
FF: InferableBrand_cdc7cd43dac7585f<'a, Brand, W>
+ ApplyDispatch<
'a,
FnBrand,
Brand,
A,
B,
W,
FA,
<FA as InferableBrand_cdc7cd43dac7585f<'a, Brand, A>>::Marker,
>, {
ff.dispatch(fa)
}
}
mod approach_c {
use super::*;
pub trait ApplyDispatch<
'a,
FnBrand,
Brand: Kind_cdc7cd43dac7585f,
A: 'a,
B: 'a,
W: 'a,
FA,
Marker,
> {
fn dispatch(
self,
fa: FA,
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>);
}
impl<'a, FnBrand, Brand, A, B, W>
ApplyDispatch<
'a,
FnBrand,
Brand,
A,
B,
W,
Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
Val,
> for Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>)
where
FnBrand: CloneFn + 'a,
Brand: Semiapplicative,
A: Clone + 'a,
B: 'a,
W: Clone + 'a,
Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>): Into<
Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, <FnBrand as CloneFn>::Of<'a, A, B>>),
>,
{
fn dispatch(
self,
fa: Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>) {
Brand::apply::<FnBrand, A, B>(self.into(), fa)
}
}
impl<'a, 'b, FnBrand, Brand, A, B, W>
ApplyDispatch<
'a,
FnBrand,
Brand,
A,
B,
W,
&'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
Ref,
> for &'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>)
where
'a: 'b,
FnBrand: CloneFn<Ref> + 'a,
Brand: RefSemiapplicative,
A: 'a,
B: 'a,
W: 'a,
&'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, W>): Into<
&'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, <FnBrand as CloneFn<Ref>>::Of<'a, A, B>>),
>,
{
fn dispatch(
self,
fa: &'b Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, A>),
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>) {
Brand::ref_apply::<FnBrand, A, B>(self.into(), fa)
}
}
pub fn apply<'a, FnBrand, Brand, A, B, W, FF, FA>(
ff: FF,
fa: FA,
) -> Apply!(<Brand as Kind!(type Of<'a, T: 'a>: 'a;)>::Of<'a, B>)
where
Brand: Kind_cdc7cd43dac7585f,
FnBrand: 'a,
A: 'a,
B: 'a,
W: 'a + FnBrandSlotBroad<FnBrand>,
FA: InferableBrand_cdc7cd43dac7585f<'a, Brand, A>,
FF: InferableBrand_cdc7cd43dac7585f<'a, Brand, W>
+ ApplyDispatch<
'a,
FnBrand,
Brand,
A,
B,
W,
FA,
<FA as InferableBrand_cdc7cd43dac7585f<'a, Brand, A>>::Marker,
>, {
ff.dispatch(fa)
}
}
#[test]
fn approach_a_val_option() {
let f = Some(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
let x = Some(5i32);
let result: Option<i32> = approach_a::apply(f, x);
assert_eq!(result, Some(10));
}
#[test]
fn approach_a_val_option_none() {
let f = Some(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
let x: Option<i32> = None;
let result: Option<i32> = approach_a::apply(f, x);
assert_eq!(result, None);
}
#[test]
fn approach_a_ref_option() {
let f: Option<Rc<dyn Fn(&i32) -> i32>> = Some(Rc::new(|x: &i32| *x * 2));
let x = Some(5i32);
let result: Option<i32> = approach_a::apply(&f, &x);
assert_eq!(result, Some(10));
}
#[test]
fn approach_a_val_result_crosscheck() {
let f: Result<_, String> = Ok(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x + 1));
let x: Result<i32, String> = Ok(5);
let result =
fp_library::functions::explicit::apply::<RcFnBrand, ResultErrAppliedBrand<String>, _, _>(
f, x,
);
assert_eq!(result, Ok(6));
}
#[test]
fn approach_a_ref_result_crosscheck() {
let f: Result<Rc<dyn Fn(&i32) -> i32>, String> = Ok(Rc::new(|x: &i32| *x + 1));
let x: Result<i32, String> = Ok(5);
let result =
fp_library::functions::ref_apply::<RcFnBrand, ResultErrAppliedBrand<String>, _, _>(&f, &x);
assert_eq!(result, Ok(6));
}
#[test]
fn approach_b_val_option() {
let f = Some(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
let x = Some(5i32);
let result: Option<i32> = approach_b::apply(f, x);
assert_eq!(result, Some(10));
}
#[test]
fn approach_b_val_option_none() {
let f = Some(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
let x: Option<i32> = None;
let result: Option<i32> = approach_b::apply(f, x);
assert_eq!(result, None);
}
#[test]
fn approach_b_ref_option() {
let f: Option<Rc<dyn Fn(&i32) -> i32>> = Some(Rc::new(|x: &i32| *x * 2));
let x = Some(5i32);
let result: Option<i32> = approach_b::apply(&f, &x);
assert_eq!(result, Some(10));
}
#[test]
fn approach_b_val_result_crosscheck() {
let f: Result<_, String> = Ok(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x + 1));
let x: Result<i32, String> = Ok(5);
let result =
fp_library::functions::explicit::apply::<RcFnBrand, ResultErrAppliedBrand<String>, _, _>(
f, x,
);
assert_eq!(result, Ok(6));
}
#[test]
fn approach_b_ref_result_crosscheck() {
let f: Result<Rc<dyn Fn(&i32) -> i32>, String> = Ok(Rc::new(|x: &i32| *x + 1));
let x: Result<i32, String> = Ok(5);
let result =
fp_library::functions::ref_apply::<RcFnBrand, ResultErrAppliedBrand<String>, _, _>(&f, &x);
assert_eq!(result, Ok(6));
}
#[test]
fn approach_c_val_option() {
let f = Some(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
let x = Some(5i32);
let result: Option<i32> = approach_c::apply(f, x);
assert_eq!(result, Some(10));
}
#[test]
fn approach_c_val_option_none() {
let f = Some(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x * 2));
let x: Option<i32> = None;
let result: Option<i32> = approach_c::apply(f, x);
assert_eq!(result, None);
}
#[test]
fn approach_c_ref_option() {
let f: Option<Rc<dyn Fn(&i32) -> i32>> = Some(Rc::new(|x: &i32| *x * 2));
let x = Some(5i32);
let result: Option<i32> = approach_c::apply(&f, &x);
assert_eq!(result, Some(10));
}
#[test]
fn approach_c_val_result_crosscheck() {
let f: Result<_, String> = Ok(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x + 1));
let x: Result<i32, String> = Ok(5);
let result =
fp_library::functions::explicit::apply::<RcFnBrand, ResultErrAppliedBrand<String>, _, _>(
f, x,
);
assert_eq!(result, Ok(6));
}
#[test]
fn approach_c_ref_result_crosscheck() {
let f: Result<Rc<dyn Fn(&i32) -> i32>, String> = Ok(Rc::new(|x: &i32| *x + 1));
let x: Result<i32, String> = Ok(5);
let result =
fp_library::functions::ref_apply::<RcFnBrand, ResultErrAppliedBrand<String>, _, _>(&f, &x);
assert_eq!(result, Ok(6));
}
#[test]
fn approach_b_val_option_type_change() {
let f = Some(lift_fn_new::<RcFnBrand, _, _>(|x: i32| x.to_string()));
let x = Some(42i32);
let result: Option<String> = approach_b::apply(f, x);
assert_eq!(result, Some("42".to_string()));
}
#[test]
fn approach_b_ref_option_type_change() {
let f: Option<Rc<dyn Fn(&i32) -> String>> = Some(Rc::new(|x: &i32| x.to_string()));
let x = Some(42i32);
let result: Option<String> = approach_b::apply(&f, &x);
assert_eq!(result, Some("42".to_string()));
}
#[test]
fn approach_b_val_vec() {
let f = vec![
lift_fn_new::<RcFnBrand, _, _>(|x: i32| x * 10),
lift_fn_new::<RcFnBrand, _, _>(|x: i32| x + 100),
];
let x = vec![1, 2];
let result: Vec<i32> = approach_b::apply(f, x);
assert_eq!(result, vec![10, 20, 101, 102]);
}
#[test]
fn approach_b_ref_vec() {
let f: Vec<Rc<dyn Fn(&i32) -> i32>> =
vec![Rc::new(|x: &i32| *x * 10), Rc::new(|x: &i32| *x + 100)];
let x = vec![1, 2];
let result: Vec<i32> = approach_b::apply(&f, &x);
assert_eq!(result, vec![10, 20, 101, 102]);
}
#[test]
fn approach_b_val_option_ff_none() {
let f: Option<_> = None::<std::rc::Rc<dyn Fn(i32) -> i32>>;
let x = Some(5i32);
let result: Option<i32> = approach_b::apply(f, x);
assert_eq!(result, None);
}