#![expect(clippy::unimplemented, reason = "Tests use panicking operations for brevity and clarity")]
#[expect(unused, reason = "Feasibility test helpers used only within module")]
#[cfg(test)]
mod tests {
trait Kind {
type Of<A>;
}
struct VecBrand;
impl Kind for VecBrand {
type Of<A> = Vec<A>;
}
struct OptionBrand;
impl Kind for OptionBrand {
type Of<A> = Option<A>;
}
struct Val;
struct Ref;
trait VecFunctorDispatch<A, B, FA, Marker> {
fn dispatch(
self,
fa: FA,
) -> Vec<B>;
}
impl<A, B, F> VecFunctorDispatch<A, B, Vec<A>, Val> for F
where
F: Fn(A) -> B,
{
fn dispatch(
self,
fa: Vec<A>,
) -> Vec<B> {
fa.into_iter().map(self).collect()
}
}
impl<'b, A, B, F> VecFunctorDispatch<A, B, &'b Vec<A>, Ref> for F
where
F: Fn(&A) -> B,
{
fn dispatch(
self,
fa: &'b Vec<A>,
) -> Vec<B> {
fa.iter().map(self).collect()
}
}
impl<A, B, F> VecFunctorDispatch<A, B, Vec<A>, Ref> for F
where
F: Fn(&A) -> B,
{
fn dispatch(
self,
fa: Vec<A>,
) -> Vec<B> {
fa.iter().map(self).collect()
}
}
fn vec_map<A, B, FA, Marker>(
f: impl VecFunctorDispatch<A, B, FA, Marker>,
fa: FA,
) -> Vec<B> {
f.dispatch(fa)
}
#[test]
fn val_owned() {
let v = vec![1, 2, 3];
let result = vec_map(|x: i32| x.to_string(), v);
assert_eq!(result, vec!["1", "2", "3"]);
}
#[test]
fn ref_owned() {
let v = vec![1, 2, 3];
let result = vec_map(|x: &i32| x.to_string(), v);
assert_eq!(result, vec!["1", "2", "3"]);
}
#[test]
fn ref_borrowed() {
let v = vec![1, 2, 3];
let result = vec_map(|x: &i32| x.to_string(), &v);
assert_eq!(result, vec!["1", "2", "3"]);
assert_eq!(v, vec![1, 2, 3]);
}
#[test]
fn ref_borrowed_reuse() {
let v = vec![1, 2, 3];
let a = vec_map(|x: &i32| x.to_string(), &v);
let b = vec_map(|x: &i32| x * 2, &v);
assert_eq!(a, vec!["1", "2", "3"]);
assert_eq!(b, vec![2, 4, 6]);
assert_eq!(v, vec![1, 2, 3]);
}
trait OptionFunctorDispatch<A, B, FA, Marker> {
fn dispatch(
self,
fa: FA,
) -> Option<B>;
}
impl<A, B, F> OptionFunctorDispatch<A, B, Option<A>, Val> for F
where
F: Fn(A) -> B,
{
fn dispatch(
self,
fa: Option<A>,
) -> Option<B> {
fa.map(self)
}
}
impl<'b, A, B, F> OptionFunctorDispatch<A, B, &'b Option<A>, Ref> for F
where
F: Fn(&A) -> B,
{
fn dispatch(
self,
fa: &'b Option<A>,
) -> Option<B> {
fa.as_ref().map(self)
}
}
impl<A, B, F> OptionFunctorDispatch<A, B, Option<A>, Ref> for F
where
F: Fn(&A) -> B,
{
fn dispatch(
self,
fa: Option<A>,
) -> Option<B> {
fa.as_ref().map(self)
}
}
fn option_map<A, B, FA, Marker>(
f: impl OptionFunctorDispatch<A, B, FA, Marker>,
fa: FA,
) -> Option<B> {
f.dispatch(fa)
}
#[test]
fn option_val_owned() {
let result = option_map(|x: i32| x.to_string(), Some(42));
assert_eq!(result, Some("42".to_string()));
}
#[test]
fn option_ref_owned() {
let result = option_map(|x: &i32| x.to_string(), Some(42));
assert_eq!(result, Some("42".to_string()));
}
#[test]
fn option_ref_borrowed() {
let v = Some(42);
let result = option_map(|x: &i32| x.to_string(), &v);
assert_eq!(result, Some("42".to_string()));
assert_eq!(v, Some(42));
}
trait VecBindDispatch<A, B, FA, Marker> {
fn dispatch(
self,
fa: FA,
) -> Vec<B>;
}
impl<A, B, F> VecBindDispatch<A, B, Vec<A>, Val> for F
where
F: Fn(A) -> Vec<B>,
{
fn dispatch(
self,
fa: Vec<A>,
) -> Vec<B> {
fa.into_iter().flat_map(self).collect()
}
}
impl<'b, A, B, F> VecBindDispatch<A, B, &'b Vec<A>, Ref> for F
where
F: Fn(&A) -> Vec<B>,
{
fn dispatch(
self,
fa: &'b Vec<A>,
) -> Vec<B> {
fa.iter().flat_map(self).collect()
}
}
impl<A, B, F> VecBindDispatch<A, B, Vec<A>, Ref> for F
where
F: Fn(&A) -> Vec<B>,
{
fn dispatch(
self,
fa: Vec<A>,
) -> Vec<B> {
fa.iter().flat_map(self).collect()
}
}
fn vec_bind<A, B, FA, Marker>(
fa: FA,
f: impl VecBindDispatch<A, B, FA, Marker>,
) -> Vec<B> {
f.dispatch(fa)
}
#[test]
fn bind_val_owned() {
let result = vec_bind(vec![1, 2, 3], |x: i32| vec![x, x * 10]);
assert_eq!(result, vec![1, 10, 2, 20, 3, 30]);
}
#[test]
fn bind_ref_owned() {
let result = vec_bind(vec![1, 2, 3], |x: &i32| vec![*x, *x * 10]);
assert_eq!(result, vec![1, 10, 2, 20, 3, 30]);
}
#[test]
fn bind_ref_borrowed() {
let v = vec![1, 2, 3];
let result = vec_bind(&v, |x: &i32| vec![*x, *x * 10]);
assert_eq!(result, vec![1, 10, 2, 20, 3, 30]);
assert_eq!(v, vec![1, 2, 3]);
}
trait VecLift2Dispatch<A, B, C, FA, FB, Marker> {
fn dispatch(
self,
fa: FA,
fb: FB,
) -> Vec<C>;
}
impl<A, B, C, F> VecLift2Dispatch<A, B, C, Vec<A>, Vec<B>, Val> for F
where
F: Fn(A, B) -> C,
A: Clone,
B: Clone,
{
fn dispatch(
self,
fa: Vec<A>,
fb: Vec<B>,
) -> Vec<C> {
fa.into_iter()
.flat_map(|a| fb.iter().map(move |b| (a.clone(), b.clone())))
.map(|(a, b)| (self)(a, b))
.collect()
}
}
impl<'b1, 'b2, A, B, C, F> VecLift2Dispatch<A, B, C, &'b1 Vec<A>, &'b2 Vec<B>, Ref> for F
where
F: Fn(&A, &B) -> C + Clone,
{
fn dispatch(
self,
fa: &'b1 Vec<A>,
fb: &'b2 Vec<B>,
) -> Vec<C> {
fa.iter()
.flat_map(|a| {
let f = self.clone();
fb.iter().map(move |b| f(a, b))
})
.collect()
}
}
fn vec_lift2<A, B, C, FA, FB, Marker>(
f: impl VecLift2Dispatch<A, B, C, FA, FB, Marker>,
fa: FA,
fb: FB,
) -> Vec<C> {
f.dispatch(fa, fb)
}
#[test]
fn lift2_val_owned() {
let result = vec_lift2(|x: i32, y: i32| x + y, vec![1, 2], vec![10, 20]);
assert_eq!(result, vec![11, 21, 12, 22]);
}
#[test]
fn lift2_ref_borrowed() {
let a = vec![1, 2];
let b = vec![10, 20];
let result = vec_lift2(|x: &i32, y: &i32| x + y, &a, &b);
assert_eq!(result, vec![11, 21, 12, 22]);
assert_eq!(a, vec![1, 2]);
assert_eq!(b, vec![10, 20]);
}
fn make_vec() -> Vec<i32> {
vec![1, 2, 3]
}
#[test]
fn dispatch_temporary_borrow() {
let result = vec_map(|x: &i32| x * 2, &make_vec());
assert_eq!(result, vec![2, 4, 6]);
}
#[test]
fn dispatch_nested_bind_borrowed() {
let v = vec![1, 2];
let result = vec_bind(&vec_bind(&v, |x: &i32| vec![*x, *x * 10]), |y: &i32| vec![*y + 100]);
assert_eq!(result, vec![101, 110, 102, 120]);
assert_eq!(v, vec![1, 2]);
}
#[test]
fn dispatch_mixed_modes() {
let v = vec![1, 2, 3];
let strings = vec_map(|x: &i32| x.to_string(), &v);
let doubled = vec_map(|x: i32| x * 2, v);
assert_eq!(strings, vec!["1", "2", "3"]);
assert_eq!(doubled, vec![2, 4, 6]);
}
#[test]
fn dispatch_inference_typed_val() {
let v = vec![1, 2, 3];
let result: Vec<String> = vec_map(|x: i32| x.to_string(), v);
assert_eq!(result, vec!["1", "2", "3"]);
}
#[test]
fn dispatch_inference_ref_borrow() {
let v = vec![1, 2, 3];
let result: Vec<String> = vec_map(|x: &i32| x.to_string(), &v);
assert_eq!(result, vec!["1", "2", "3"]);
}
#[test]
fn dispatch_ref_closure_owned_container() {
let result = vec_map(|x: &i32| x.to_string(), vec![1, 2, 3]);
assert_eq!(result, vec!["1", "2", "3"]);
}
#[test]
fn dispatch_no_ambiguity_ref_owned() {
let result: Vec<String> = vec_map(|x: &i32| x.to_string(), vec![42]);
assert_eq!(result, vec!["42"]);
}
#[test]
fn dispatch_no_ambiguity_ref_borrowed() {
let v = vec![42];
let result: Vec<String> = vec_map(|x: &i32| x.to_string(), &v);
assert_eq!(result, vec!["42"]);
assert_eq!(v, vec![42]);
}
trait GatKind {
type Of<A>;
}
struct GatVec;
impl GatKind for GatVec {
type Of<A> = Vec<A>;
}
struct GatOption;
impl GatKind for GatOption {
type Of<A> = Option<A>;
}
trait GatFunctorDispatch<'a, Brand: GatKind, A, B, FA, Marker> {
fn dispatch(
self,
fa: FA,
) -> Brand::Of<B>;
}
impl<'a, Brand: GatKind, A, B, F>
GatFunctorDispatch<'a, Brand, A, B, <Brand as GatKind>::Of<A>, Val> for F
where
F: Fn(A) -> B,
{
fn dispatch(
self,
_fa: <Brand as GatKind>::Of<A>,
) -> Brand::Of<B> {
unimplemented!("generic val - use concrete tests")
}
}
impl<'a, 'b, Brand: GatKind, A, B, F>
GatFunctorDispatch<'a, Brand, A, B, &'b <Brand as GatKind>::Of<A>, Ref> for F
where
F: Fn(&A) -> B,
{
fn dispatch(
self,
_fa: &'b <Brand as GatKind>::Of<A>,
) -> Brand::Of<B> {
unimplemented!("generic ref - use concrete tests")
}
}
fn gat_map<'a, Brand: GatKind, A, B, FA, Marker>(
f: impl GatFunctorDispatch<'a, Brand, A, B, FA, Marker>,
fa: FA,
) -> Brand::Of<B> {
f.dispatch(fa)
}
trait TwoImplVecDispatch<A, B, FA, Marker> {
fn dispatch(
self,
fa: FA,
) -> Vec<B>;
}
impl<A, B, F> TwoImplVecDispatch<A, B, Vec<A>, Val> for F
where
F: Fn(A) -> B,
{
fn dispatch(
self,
fa: Vec<A>,
) -> Vec<B> {
fa.into_iter().map(self).collect()
}
}
impl<'b, A, B, F> TwoImplVecDispatch<A, B, &'b Vec<A>, Ref> for F
where
F: Fn(&A) -> B,
{
fn dispatch(
self,
fa: &'b Vec<A>,
) -> Vec<B> {
fa.iter().map(self).collect()
}
}
fn two_impl_map<A, B, FA, Marker>(
f: impl TwoImplVecDispatch<A, B, FA, Marker>,
fa: FA,
) -> Vec<B> {
f.dispatch(fa)
}
#[test]
fn two_impl_val_owned() {
let result = two_impl_map(|x: i32| x.to_string(), vec![1, 2, 3]);
assert_eq!(result, vec!["1", "2", "3"]);
}
#[test]
fn two_impl_ref_borrowed() {
let v = vec![1, 2, 3];
let result = two_impl_map(|x: &i32| x.to_string(), &v);
assert_eq!(result, vec!["1", "2", "3"]);
assert_eq!(v, vec![1, 2, 3]);
}
#[test]
fn two_impl_ref_borrowed_reuse() {
let v = vec![1, 2, 3];
let a = two_impl_map(|x: &i32| x.to_string(), &v);
let b = two_impl_map(|x: &i32| x * 2, &v);
assert_eq!(a, vec!["1", "2", "3"]);
assert_eq!(b, vec![2, 4, 6]);
}
#[test]
fn two_impl_ref_temporary() {
let result = two_impl_map(|x: &i32| x * 2, &vec![1, 2, 3]);
assert_eq!(result, vec![2, 4, 6]);
}
#[test]
fn two_impl_nested_bind() {
trait TwoImplVecBind<A, B, FA, Marker> {
fn dispatch(
self,
fa: FA,
) -> Vec<B>;
}
impl<A, B, F> TwoImplVecBind<A, B, Vec<A>, Val> for F
where
F: Fn(A) -> Vec<B>,
{
fn dispatch(
self,
fa: Vec<A>,
) -> Vec<B> {
fa.into_iter().flat_map(self).collect()
}
}
impl<'b, A, B, F> TwoImplVecBind<A, B, &'b Vec<A>, Ref> for F
where
F: Fn(&A) -> Vec<B>,
{
fn dispatch(
self,
fa: &'b Vec<A>,
) -> Vec<B> {
fa.iter().flat_map(self).collect()
}
}
fn two_bind<A, B, FA, Marker>(
fa: FA,
f: impl TwoImplVecBind<A, B, FA, Marker>,
) -> Vec<B> {
f.dispatch(fa)
}
let v = vec![1, 2];
let result = two_bind(&two_bind(&v, |x: &i32| vec![*x, *x * 10]), |y: &i32| vec![*y + 100]);
assert_eq!(result, vec![101, 110, 102, 120]);
assert_eq!(v, vec![1, 2]);
}
#[test]
fn two_impl_mixed_modes() {
let v = vec![1, 2, 3];
let strings = two_impl_map(|x: &i32| x.to_string(), &v);
let doubled = two_impl_map(|x: i32| x * 2, v);
assert_eq!(strings, vec!["1", "2", "3"]);
assert_eq!(doubled, vec![2, 4, 6]);
}
trait GatVecFunctorDispatch<'a, A, B, FA, Marker> {
fn dispatch(
self,
fa: FA,
) -> <GatVec as GatKind>::Of<B>;
}
impl<'a, A, B, F> GatVecFunctorDispatch<'a, A, B, <GatVec as GatKind>::Of<A>, Val> for F
where
F: Fn(A) -> B,
{
fn dispatch(
self,
fa: <GatVec as GatKind>::Of<A>,
) -> Vec<B> {
fa.into_iter().map(self).collect()
}
}
impl<'a, 'b, A, B, F> GatVecFunctorDispatch<'a, A, B, &'b <GatVec as GatKind>::Of<A>, Ref> for F
where
F: Fn(&A) -> B,
{
fn dispatch(
self,
fa: &'b <GatVec as GatKind>::Of<A>,
) -> Vec<B> {
fa.iter().map(self).collect()
}
}
fn gat_vec_map<'a, A, B, FA, Marker>(
f: impl GatVecFunctorDispatch<'a, A, B, FA, Marker>,
fa: FA,
) -> Vec<B> {
f.dispatch(fa)
}
#[test]
fn gat_projection_val() {
let result = gat_vec_map(|x: i32| x.to_string(), vec![1, 2, 3]);
assert_eq!(result, vec!["1", "2", "3"]);
}
#[test]
fn gat_projection_ref_borrowed() {
let v = vec![1, 2, 3];
let result = gat_vec_map(|x: &i32| x.to_string(), &v);
assert_eq!(result, vec!["1", "2", "3"]);
assert_eq!(v, vec![1, 2, 3]);
}
}