use crate::funcmap::{T1, T2};
use functor_derive::Functor;
use std::marker::PhantomData;
#[test]
fn attributes_on_type_params_are_supported() {
#[derive(Functor, Debug, PartialEq)]
struct Test<#[cfg(test)] S, #[cfg(test)] T>(S, T);
let src = Test(T1, T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, T1));
}
#[test]
fn attributes_on_lifetime_params_are_supported() {
#[derive(Functor, Debug, PartialEq)]
struct Test<#[cfg(test)] 'a, T>(T, PhantomData<&'a ()>);
let src = Test(T1, PhantomData);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, PhantomData));
}
#[test]
fn attributes_on_const_params_are_supported() {
#[derive(Functor, Debug, PartialEq)]
struct Test<T, #[cfg(test)] const N: usize>(T);
let src = Test::<_, 42>(T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2));
}
#[test]
fn defaults_on_type_params_are_supported() {
#[derive(Functor, Debug, PartialEq)]
struct Test<S = T1, T = T1>(S, T);
let src = Test(T1, T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, T1));
}
#[test]
fn defaults_on_const_params_are_supported() {
#[derive(Functor, Debug, PartialEq)]
struct Test<T, const N: usize = 0>(T);
let src = Test::<_>(T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2));
}
#[test]
fn impl_is_restricted_to_trait_bounds_on_generics_of_original_type() {
trait TestTrait {}
impl TestTrait for T1 {}
impl TestTrait for T2 {}
#[derive(Functor, Debug, PartialEq)]
struct Test<S: TestTrait, T: TestTrait>(S, T);
let src = Test(T1, T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, T1));
}
#[test]
fn impl_is_restricted_to_self_dependent_trait_bounds_on_generics_of_original_type() {
trait TestTrait<T> {
type Assoc;
}
impl<S> TestTrait<S> for T1 {
type Assoc = S;
}
impl<S> TestTrait<S> for T2 {
type Assoc = S;
}
#[derive(Functor, Debug, PartialEq)]
struct Test<S: TestTrait<S, Assoc = S>, T: TestTrait<T, Assoc = T>>(S, T);
let src = Test(T1, T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, T1));
}
#[test]
fn impl_is_restricted_to_cross_dependent_trait_bounds_on_generics_of_original_type() {
trait TestTrait<T> {
type Assoc;
}
impl<S> TestTrait<S> for T1 {
type Assoc = S;
}
impl<S> TestTrait<S> for T2 {
type Assoc = S;
}
#[derive(Functor, Debug, PartialEq)]
struct Test<S: TestTrait<T, Assoc = T>, T: TestTrait<S, Assoc = S>>(S, T);
let src = Test(T1, T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, T1));
}
#[test]
fn impl_is_restricted_to_maybe_sized_bound_on_unmapped_generic_of_original_type() {
trait TestTrait<T: ?Sized> {}
type Unsized = [()];
impl TestTrait<T1> for Unsized {}
impl TestTrait<T2> for Unsized {}
#[derive(Functor, Debug, PartialEq)]
struct Test<S: ?Sized, T: ?Sized + TestTrait<S>>(PhantomData<S>, PhantomData<T>);
let src = Test::<T1, Unsized>(PhantomData, PhantomData);
let dst = src.fmap(|_: T1| T2);
assert_eq!(dst, Test(PhantomData, PhantomData));
}
#[test]
fn impl_is_restricted_to_lifetime_bounds_on_generics_of_original_type() {
#[derive(Functor, Debug, PartialEq)]
struct Test<'a, T: 'a>(T, PhantomData<&'a ()>);
let src = Test(T1, PhantomData);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, PhantomData));
}
#[test]
fn impl_is_restricted_to_trait_bounds_in_where_clause_on_original_type() {
trait TestTrait {}
impl TestTrait for T1 {}
impl TestTrait for T2 {}
#[derive(Functor, Debug, PartialEq)]
struct Test<S, T>(S, T)
where
S: TestTrait,
T: TestTrait;
let src = Test(T1, T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, T1));
}
#[test]
fn impl_is_restricted_to_self_dependent_trait_bounds_in_where_clause_on_original_type() {
trait TestTrait<T> {
type Assoc;
}
impl<S> TestTrait<S> for T1 {
type Assoc = S;
}
impl<S> TestTrait<S> for T2 {
type Assoc = S;
}
#[derive(Functor, Debug, PartialEq)]
struct Test<S, T>(S, T)
where
S: TestTrait<S, Assoc = S>,
T: TestTrait<T, Assoc = T>;
let src = Test(T1, T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, T1));
}
#[test]
fn impl_is_restricted_to_cross_dependent_trait_bounds_in_where_clause_on_original_type() {
trait TestTrait<T> {
type Assoc;
}
impl<S> TestTrait<S> for T1 {
type Assoc = S;
}
impl<S> TestTrait<S> for T2 {
type Assoc = S;
}
#[derive(Functor, Debug, PartialEq)]
struct Test<S, T>(S, T)
where
S: TestTrait<T, Assoc = T>,
T: TestTrait<S, Assoc = S>;
let src = Test(T1, T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, T1));
}
#[test]
fn impl_is_restricted_to_trait_bounds_with_bound_lifetimes_in_where_clause_on_original_type() {
trait TestTrait<'a> {}
impl<'a> TestTrait<'a> for T1 {}
impl<'a> TestTrait<'a> for T2 {}
#[derive(Functor, Debug, PartialEq)]
struct Test<S, T>(S, T)
where
for<'a> T: TestTrait<'a>;
let src = Test(T1, T1);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, T1));
}
#[test]
fn impl_is_restricted_to_lifetime_bounds_in_where_clause_of_original_type() {
#[derive(Functor, Debug, PartialEq)]
struct Test<'a, T>(T, PhantomData<&'a ()>)
where
T: 'a;
let src = Test(T1, PhantomData);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, PhantomData));
}
#[test]
fn const_args_with_braces_are_supported() {
#[derive(Debug, PartialEq)]
struct Inner<const N: usize>;
#[derive(Functor, Debug, PartialEq)]
struct Test<T>(T, Inner<{ 41 + 1 }>);
let src = Test(T1, Inner);
let dst = src.fmap(|_| T2);
assert_eq!(dst, Test(T2, Inner));
}