spiegel 0.2.0

A Rust library for reflection
Documentation
#![feature(impl_trait_in_bindings, unboxed_closures, fn_traits)]

pub trait Map<A> {
    type Output: Sequence;
    fn apply(self, arg: A) -> Self::Output;
}

pub trait Fold<I, A> {
    fn apply(self, init: I, arg: A) -> I;
}

pub trait Collection<A> {
    fn apply(a: A) -> Self;
}

pub trait Zip<A> {
    type Output: Sequence;
    fn apply(self, a: A) -> Self::Output;
}

pub trait Sequence
where
    Self: Sized,
{
    fn len(&self) -> usize;
    fn is_empty(&self) -> bool {
        self.len() == 0
    }
    fn map<F: Map<Self>>(self, f: F) -> F::Output {
        f.apply(self)
    }
    fn fold<I, F: Fold<I, Self>>(self, init: I, f: F) -> I {
        f.apply(init, self)
    }
    fn collect<C: Collection<Self>>(self) -> C {
        C::apply(self)
    }
    fn zip<Z: Zip<Self>>(self, z: Z) -> Z::Output {
        z.apply(self)
    }
}

pub struct End;
pub struct Seq<A, B>(pub A, pub B);

impl Sequence for End {
    fn len(&self) -> usize {
        0
    }
}

impl<A, B> Sequence for Seq<A, B>
where
    B: Sequence,
{
    fn len(&self) -> usize {
        1 + self.1.len()
    }
}

impl<F> Map<End> for F {
    type Output = End;
    fn apply(self, arg: End) -> Self::Output {
        arg
    }
}

impl<A, B, X, Y> Zip<Seq<X, Y>> for Seq<A, B>
where
    B: Zip<Y>,
{
    type Output = Seq<(X, A), B::Output>;
    fn apply(self, Seq(x, y): Seq<X, Y>) -> Self::Output {
        let Seq(a, b) = self;
        Seq((x, a), b.apply(y))
    }
}

impl Zip<End> for End {
    type Output = End;
    fn apply(self, _arg: End) -> Self::Output {
        End
    }
}

impl<F, A, B> Map<Seq<A, B>> for F
where
    F: FnMut<(A,)>,
    F: Map<B>,
{
    type Output = Seq<<F as FnOnce<(A,)>>::Output, <F as Map<B>>::Output>;
    fn apply(mut self, Seq(a, b): Seq<A, B>) -> Self::Output {
        Seq(self(a), self.apply(b))
    }
}

impl<F, I> Fold<I, End> for F {
    fn apply(self, init: I, _arg: End) -> I {
        init
    }
}

impl<F, I, A, B> Fold<I, Seq<A, B>> for F
where
    F: FnMut<(I, A), Output = I>,
    F: Fold<I, B>,
{
    fn apply(mut self, init: I, Seq(a, b): Seq<A, B>) -> I {
        let next_init = self(init, a);
        self.apply(next_init, b)
    }
}

#[macro_export]
macro_rules! function {
    (@switch) => {()};
    (@switch $($tt:tt)+) => {$($tt)+};
    ($name:ident $(<$($generic: ident $(,)?)*>)? ($($($args:ident)+:$arg_ty: ty),* $(,)?) $(-> $ty:ty)? $(where ($($clauses:tt)*))? $body:block) => {
        #[allow(non_camel_case_types)]
        pub struct $name;

        impl$(<$($generic,)*>)? FnOnce<($($arg_ty,)*)> for $name $(where $($clauses)*)? {
            type Output = function!(@switch $($ty)?);

            extern "rust-call" fn call_once(self, ($($($args)+,)*): ($($arg_ty,)*)) -> Self::Output {
                $body
            }
        }

        impl$(<$($generic,)*>)? FnMut<($($arg_ty,)*)> for $name $(where $($clauses)*)? {
            extern "rust-call" fn call_mut(&mut self, ($($($args)+,)*): ($($arg_ty,)*)) -> Self::Output {
                $body
            }
        }

        impl$(<$($generic,)*>)? Fn<($($arg_ty,)*)> for $name $(where $($clauses)*)? {
            extern "rust-call" fn call(&self, ($($($args)+,)*): ($($arg_ty,)*)) -> Self::Output {
                $body
            }
        }
    };
}

#[macro_export]
macro_rules! closure {
    ([$($capture:ident),* $(,)?] $(<$($generic: ident $(,)?)*>)? ($($($args:ident)+:$arg_ty: ty),* $(,)?) $(-> $ty:ty)? $(where ($($clauses:tt)*))? $body:block) => {{
        pub struct Closure<$($capture,)*>($($capture)*);

        impl<$($capture,)* $($($generic,)*)?> FnOnce<($($arg_ty,)*)> for Closure<$($capture,)*> $(where $($clauses)*)? {
            type Output = function!(@switch $($ty)?);

            extern "rust-call" fn call_once(self, ($($($args)+,)*): ($($arg_ty,)*)) -> Self::Output {
                let Closure($($capture),*) = self;
                $body
            }
        }

        impl<$($capture,)* $($($generic,)*)?> FnMut<($($arg_ty,)*)> for Closure<$($capture,)*> $(where $($clauses)*)? {
            extern "rust-call" fn call_mut(&mut self, ($($($args)+,)*): ($($arg_ty,)*)) -> Self::Output {
                let Closure($(ref $capture),*) = *self;
                $body
            }
        }

        impl<$($capture,)* $($($generic,)*)?> Fn<($($arg_ty,)*)> for Closure<$($capture,)*> $(where $($clauses)*)? {
            extern "rust-call" fn call(&self, ($($($args)+,)*): ($($arg_ty,)*)) -> Self::Output {
                let Closure($(ref $capture),*) = *self;
                $body
            }
        }

        Closure($($capture),*)
    }};
}

#[macro_export]
macro_rules! seq {
    () => {
        End
    };
    ($expr:expr $(,)?) => {
        Seq($expr, End)
    };
    ($expr:expr, $($other:expr),+ $(,)?) => {
        Seq($expr, seq!($($other,)+))
    }
}

#[macro_export]
macro_rules! Seq {
    () => {
        End
    };
    ($expr:ty $(,)?) => {
        Seq<$expr, End>
    };
    ($expr:ty, $($other:ty),+ $(,)?) => {
        Seq<$expr, Seq!($($other),+)>
    }
}

function!(fold_vector<T>(mut init: Vec<T>, val: T) -> Vec<T> {
    init.push(val);
    init
});

impl<T, B> Collection<Seq<T, B>> for Vec<T>
where
    fold_vector: Fold<Vec<T>, Seq<T, B>>,
    B: Sequence,
{
    fn apply(a: Seq<T, B>) -> Self {
        a.fold(Vec::new(), fold_vector)
    }
}

function!(Dbg<T>(a: T) -> T where (T: std::fmt::Debug) {
    println!("{:?}", a);
    a
});

pub fn functor<F, T>(_: &F, _: &T)
where
    F: Map<T>,
{
}

pub trait Struct {
    type Fields: Sequence + Zip<Self::Names>;
    type Names: Sequence + Zip<Self::Fields>;

    fn fields(self) -> Self::Fields;
    fn names() -> Self::Names;
}

pub struct Point {
    pub x: i32,
    pub y: &'static str,
    pub z: i32,
}

impl Struct for Point {
    type Fields = Seq!(i32, &'static str, i32);
    type Names = Seq!(&'static str, &'static str, &'static str);

    fn fields(self) -> Self::Fields {
        seq!(self.x, self.y, self.z)
    }

    fn names() -> Self::Names {
        seq!("x", "y", "z")
    }
}

pub fn dbg<S: Struct>(s: S)
where
    Dbg: Map<<<S as Struct>::Fields as Zip<<S as Struct>::Names>>::Output>,
{
    let names: impl Sequence = S::names();
    let fields: impl Sequence = s.fields();
    names.zip(fields).map(Dbg);
}