func 0.1.0

A crate that helps creating colsures from function pointers
Documentation
#[derive(Debug)]
pub struct Func<C, P, R> {
    pub captured: C,
    pub function: fn(&C, P) -> R,
}

#[derive(Debug)]
pub struct FuncMut<C, P, R> {
    pub captured: C,
    pub function: fn(&mut C, P) -> R,
}

#[derive(Debug)]
pub struct FuncOnce<C, P, R> {
    pub captured: C,
    pub function: fn(C, P) -> R,
}

macro_rules! impl_func {
    ($($param_name:ident: $param_type:ident),*) => {
        impl<C $(,$param_type)*, R> Func<C, ($($param_type,)*), R> {
            pub fn call(&self $(,$param_name: $param_type)*) -> R {
                (self.function)(&self.captured, ($($param_name,)*))
            }

            pub fn to_fn(self) -> impl Fn($($param_type),*) -> R {
                let Self{captured, function} = self;
                move |$($param_name: $param_type),*| {
                    function(&captured, ($($param_name,)*))
                }
            }
        }

        impl<C $(,$param_type)*, R> FuncMut<C, ($($param_type,)*), R> {
            pub fn call(&mut self $(,$param_name: $param_type)*) -> R {
                (self.function)(&mut self.captured, ($($param_name,)*))
            }

            pub fn to_fn_mut(self) -> impl FnMut($($param_type),*) -> R {
                let Self{mut captured, function} = self;
                move |$($param_name: $param_type),*| {
                    function(&mut captured, ($($param_name,)*))
                }
            }
        }

        impl<C $(,$param_type)*, R> FuncOnce<C, ($($param_type,)*), R> {
            pub fn call(self $(,$param_name: $param_type)*) -> R {
                (self.function)(self.captured, ($($param_name,)*))
            }

            pub fn to_fn_once(self) -> impl FnOnce($($param_type),*) -> R {
                let Self{captured, function} = self;
                move |$($param_name: $param_type),*| {
                    function(captured, ($($param_name,)*))
                }
            }
        }
    };
}

impl<C: Clone, P, R> Clone for Func<C, P, R> {
    fn clone(&self) -> Self {
        Self {
            captured: self.captured.clone(),
            function: self.function.clone(),
        }
    }
}

impl<C: Clone, P, R> Clone for FuncMut<C, P, R> {
    fn clone(&self) -> Self {
        Self {
            captured: self.captured.clone(),
            function: self.function.clone(),
        }
    }
}

impl<C: Clone, P, R> Clone for FuncOnce<C, P, R> {
    fn clone(&self) -> Self {
        Self {
            captured: self.captured.clone(),
            function: self.function.clone(),
        }
    }
}

impl<C: Copy, P, R> Copy for Func<C, P, R> {}
impl<C: Copy, P, R> Copy for FuncMut<C, P, R> {}
impl<C: Copy, P, R> Copy for FuncOnce<C, P, R> {}

impl<C: PartialEq, P, R> PartialEq for Func<C, P, R> {
    fn eq(&self, other: &Self) -> bool {
        self.captured == other.captured && self.function == other.function
    }
}

impl<C: PartialEq, P, R> PartialEq for FuncMut<C, P, R> {
    fn eq(&self, other: &Self) -> bool {
        self.captured == other.captured && self.function == other.function
    }
}

impl<C: PartialEq, P, R> PartialEq for FuncOnce<C, P, R> {
    fn eq(&self, other: &Self) -> bool {
        self.captured == other.captured && self.function == other.function
    }
}

impl<C: Eq, P, R> Eq for Func<C, P, R> {}
impl<C: Eq, P, R> Eq for FuncMut<C, P, R> {}
impl<C: Eq, P, R> Eq for FuncOnce<C, P, R> {}

#[macro_export]
macro_rules! func {
    ($($body:tt)*) => {
        $crate::func_internal! {
            @internal
            Func
            $($body)*
        }
    };
}

#[macro_export]
macro_rules! func_mut {
    ($($body:tt)*) => {
        $crate::func_internal! {
            @internal
            FuncMut
            $($body)*
        }
    };
}

#[macro_export]
macro_rules! func_once {
    ($($body:tt)*) => {
        $crate::func_internal! {
            @internal
            FuncOnce
            $($body)*
        }
    };
}

#[macro_export]
macro_rules! func_internal {
    (
        @internal
        $type:ident
        $([$($cap_ident:ident $(: $cap_expr:expr)?),*])?
        $(|$($param_ident:ident $(: $param_ty:ty)?),*|)?
        $(-> $r_type:ty)?
        $body:block
    ) => {
        $crate::$type {
            captured: (
                $($($crate::cap_internal!(@internal $cap_ident $(, $cap_expr)?),)*)?
            ),
            function: |
                ($($($cap_ident,)*)?),
                ($($($param_ident,)*)?): (
                    $($($crate::param_internal!(@internal $($param_ty)?),)*)?
                )
            | $(-> $r_type)? { $body },
        }
    };
}

#[macro_export]
macro_rules! cap_internal {
    (@internal $cap_ident:ident) => {
        $cap_ident
    };
    (@internal $cap_ident:ident, $cap_expr:expr) => {
        $cap_expr
    };
}

#[macro_export]
macro_rules! param_internal {
    (@internal) => {
        _
    };
    (@internal $param_ty:ty) => {
        $param_ty
    };
}

impl_func!();
impl_func!(p1: P1);
impl_func!(p1: P1, p2: P2);
impl_func!(p1: P1, p2: P2, p3: P3);
impl_func!(p1: P1, p2: P2, p3: P3, p4: P4);
impl_func!(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5);
impl_func!(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6);
impl_func!(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7);
impl_func!(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8);

mod test {

    #[test]
    fn addition_func_with_type_annotations() {
        let add = func!(|a: i32, b: i32| -> i32 { a + b });
        assert_eq!(add.call(1, 2), 3);
    }

    #[test]
    fn addition_func_without_parameter_type_annotations() {
        let add = func!(|a, b| -> i32 { a + b });
        assert_eq!(add.call(1, 2), 3);
    }

    #[test]
    fn addition_func_without_type_annotations() {
        let add = func!(|a, b| { a + b });
        assert_eq!(add.call(1, 2), 3);
    }

    #[test]
    fn labeled_capturing_addition_func() {
        let coeff = 3;
        let add = func!([c: coeff] |a: i32, b: i32| -> i32 { c * a + c * b });
        assert_eq!(add.call(1, 2), 9);
    }

    #[test]
    fn unlabeled_capturing_addition_func() {
        let c = 3;
        let add = func!([c] |a: i32, b: i32| -> i32 { c * a + c * b });
        assert_eq!(add.call(1, 2), 9);
    }
}