std-traits 0.7.0

Traits for types in the standard library.
Documentation
use crate::{
    num::Integer,
    primitive::Primitive,
    ptr::{Pointer, cast_ptr},
    tuple::Tuple,
    util::cast_int,
};

pub trait FunctionPointer: Primitive + Copy + Sized {
    type Args: Tuple;
    type Return;

    fn call(self, args: Self::Args) -> Self::Return;

    fn cast_ptr<T: Sized, P: Pointer<T>>(self) -> P;

    fn cast_int<T: Integer>(self) -> T;
}

impl<R> Primitive for fn() -> R {}
impl<R> FunctionPointer for fn() -> R {
    type Args = ();
    type Return = R;

    fn call(self, _args: Self::Args) -> Self::Return {
        self()
    }

    fn cast_ptr<T: Sized, P: Pointer<T>>(self) -> P {
        cast_ptr!(T, P, self)
    }

    fn cast_int<T: Integer>(self) -> T {
        cast_int!(self => T)
    }
}

#[cfg_attr(docsrs, doc(fake_variadic))]
#[cfg_attr(
    docsrs,
    doc = "This trait is implemented for function pointers with up to 12 arguments."
)]
impl<A1, R> Primitive for fn(A1) -> R {}

#[cfg_attr(docsrs, doc(fake_variadic))]
#[cfg_attr(
    docsrs,
    doc = "This trait is implemented for function pointers with up to 12 arguments."
)]
impl<A1, R> FunctionPointer for fn(A1) -> R {
    type Args = (A1,);
    type Return = R;

    fn call(self, args: Self::Args) -> Self::Return {
        self(args.0)
    }

    fn cast_ptr<T: Sized, P: Pointer<T>>(self) -> P {
        cast_ptr!(T, P, self)
    }

    fn cast_int<T: Integer>(self) -> T {
        cast_int!(self => T)
    }
}

macro_rules! impl_fn {
    ($($args:tt $n:tt),*) => {
        #[cfg_attr(docsrs, doc(hidden))]
        impl<$($args,)* R> Primitive for fn($($args,)*) -> R {}
        #[cfg_attr(docsrs, doc(hidden))]
        impl<$($args,)* R> FunctionPointer for fn($($args,)*) -> R {
            type Args = ($($args,)*);
            type Return = R;

            fn call(self, args: Self::Args) -> Self::Return {
                self($(args.$n),*)
            }

            fn cast_ptr<T: Sized, P: Pointer<T>>(self) -> P {
                cast_ptr!(T, P, self)
            }

            fn cast_int<T: Integer>(self) -> T {
                cast_int!(self => T)
            }
        }
    }
}

/*
for n in range(2, 13):
    print(f"impl_fn!({', '.join(f'A{i + 1} {i}' for i in range(n))});")
*/
impl_fn!(A1 0, A2 1);
impl_fn!(A1 0, A2 1, A3 2);
impl_fn!(A1 0, A2 1, A3 2, A4 3);
impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4);
impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5);
impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6);
impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7);
impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8);
impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8, A10 9);
impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8, A10 9, A11 10);
impl_fn!(A1 0, A2 1, A3 2, A4 3, A5 4, A6 5, A7 6, A8 7, A9 8, A10 9, A11 10, A12 11);

#[cfg(test)]
mod test {
    use super::FunctionPointer;

    fn f0() {}
    fn f1<T>(a: T) -> T {
        a
    }
    fn f2<T1, T2>(a: T1, b: T2) -> (T1, T2) {
        (a, b)
    }
    fn f3<T1, T2, T3>(a: T1, b: T2, c: T3) -> (T1, T2, T3) {
        (a, b, c)
    }

    #[test]
    fn test_call_0_args() {
        (f0 as fn() -> _).call(());
    }

    #[test]
    fn test_call_1_arg() {
        assert_eq!((f1 as fn(usize) -> _).call((1337,)), (1337usize));
    }

    #[test]
    fn test_call_2_args() {
        assert_eq!(
            (f2 as fn(char, [u8; 2]) -> _).call(('x', [2, 3])),
            ('x', [2u8, 3u8])
        );
    }

    #[test]
    fn test_call_3_args() {
        assert_eq!(
            (f3 as fn(usize, &'static str, bool) -> _).call((1, "b", false)),
            (1usize, "b", false)
        );
    }
}