1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use std::marker::{Tuple, PhantomData};

use tupleops::{TuplePrepend, Prepend, TupleConcat, ConcatTuples};

use crate::Curried;

/// A trait for things which may be curried.
/// 
/// C is the rightmost argument being applied in the curry.
/// 
/// X is the rest of the arguments left over after currying.
/// 
/// This trait is automatically implemented for anything implementing [FnOnce](FnOnce) which takes one or more argument.
/// 
/// ```rust
/// use currying::*;
/// 
/// let f = |x, y, z| x + y + z;
/// let (x, y, z) = (1, 2, 3);
/// 
/// let fz = f.rcurry(z);
/// 
/// assert_eq!(fz(x, y), f(x, y, z));
/// 
/// let fyz = fz.rcurry(y);
/// 
/// assert_eq!(fyz(x), f(x, y, z));
/// 
/// let fxyz = fyz.rcurry(x);
/// 
/// assert_eq!(fxyz(), f(x, y, z));
/// ```
#[const_trait]
pub trait RCurry<C, X>
{
    type Output;

    fn rcurry(self, arg: C) -> Self::Output;
}

impl<C, X, F> const RCurry<C, X> for F
where
    (C,): Tuple,
    X: Tuple,
    ((), X): TupleConcat<(), X>,
    ConcatTuples<(), X>: Tuple,
    (ConcatTuples<(), X>, (C,)): TupleConcat<ConcatTuples<(), X>, (C,)>,
    ConcatTuples<ConcatTuples<(), X>, (C,)>: Tuple,
    F: FnOnce<ConcatTuples<ConcatTuples<(), X>, (C,)>>
{
    type Output = Curried<(), X, (C,), F>;

    fn rcurry(self, arg: C) -> Self::Output
    {
        Curried {
            args_left: (),
            args_right: (arg,),
            func: self,
            phantom: PhantomData
        }
    }
}