spiegel 0.1.0

comptime reflection library for rust using heterogenous lists
Documentation
#![feature(unboxed_closures, tuple_trait, fn_traits)]

use std::{marker::Tuple, ops::Add};

pub trait Function<T> {
    type Output;
    fn apply(&mut self, value: T) -> Self::Output;
}

pub trait Map<T> {
    type Output;
    fn map(&mut self, value: T) -> Self::Output;
}

pub trait Fold<A, T> {
    fn fold(&mut self, value: T, accumulator: A) -> A;
}

#[derive(Debug, PartialEq, Hash, Clone, Copy)]
pub struct Single<T>(pub T);

#[derive(Debug, PartialEq, Hash, Clone, Copy)]
pub struct Sequence<T, R>(pub T, pub R);

impl<F, A, T> Fold<A, Single<T>> for F
where
    F: Function<(A, T), Output = A>,
{
    fn fold(&mut self, value: Single<T>, accumulator: A) -> A {
        self.apply((accumulator, value.0))
    }
}

impl<F, A, T, R> Fold<A, Sequence<T, R>> for F
where
    F: Function<(A, T), Output = A>,
    F: Fold<A, R>,
{
    fn fold(&mut self, value: Sequence<T, R>, accumulator: A) -> A {
        let first = self.apply((accumulator, value.0));
        self.fold(value.1, first)
    }
}

impl<F, T> Map<Single<T>> for F
where
    F: Function<(T,)>,
{
    type Output = Single<F::Output>;

    fn map(&mut self, value: Single<T>) -> Self::Output {
        Single(self.apply((value.0,)))
    }
}

impl<F, T, R> Map<Sequence<T, R>> for F
where
    F: Function<(T,)>,
    F: Map<R>,
{
    type Output = Sequence<<F as Function<(T,)>>::Output, <F as Map<R>>::Output>;

    fn map(&mut self, value: Sequence<T, R>) -> Self::Output {
        Sequence(self.apply((value.0,)), self.map(value.1))
    }
}

impl<F, T> Function<T> for F
where
    F: FnMut<T>,
    T: Tuple,
{
    type Output = <F as FnOnce<T>>::Output;

    fn apply(&mut self, value: T) -> Self::Output {
        self.call_mut(value)
    }
}

#[macro_export]
macro_rules! list {
    ($x:expr) => {
        Single($x)
    };
    ($x:expr, $y:expr $(,$($tt:tt)*)?) => {
        Sequence($x, list!($y $(,$($tt)*)?))
    };
}

#[macro_export]
macro_rules! List {
    ($x:ty) => {
        Single<$x>
    };
    ($x:ty, $y:ty $(,$($tt:tt)*)?) => {
        Sequence<$x, List!($y $(,$($tt)*)?)>
    };
}

/// TODO: exchange arg:ident to tt muncher for patterns
#[macro_export]
macro_rules! function {
    (
        $name:ident
        $([ $($capture:ident : $cty:ty $(,)?)* ])?
        $(< $($parameter:ident $(,)?)* >)?
        (&mut $self:ident, $($arg:ident: $aty:ty$(,)?)*)
        -> $ret:ty
        $(where ($($tt:tt)*) )?
        $block:block
    ) => {

        pub struct $name<'a> {
            $(
                $($capture: &'a mut $cty,)*
            )?
            __phantom: std::marker::PhantomData<fn(&'a ())>,
        }

        impl<'a, $($($parameter,)*)?> Function<($($aty,)*)> for $name<'a> $(where $($tt)*)? {
            type Output = $ret;

            fn apply(&mut $self, ($($arg,)*): ($($aty,)*)) -> Self::Output {
                $block
            }
        }

        #[allow(clippy::new_without_default)]
        impl<'a> $name<'a> {
            pub fn new($($($capture: &'a mut $cty,)*)?) -> Self {
                Self {
                    $($($capture,)*)?
                    __phantom: std::marker::PhantomData,
                }
            }
        }

    };
    (
        $([ $($capture:ident : $cty:ty $(,)?)* ])?
        $(< $($parameter:ident $(,)?)* >)?
        (&mut $self:ident, $($arg:ident: $aty:ty$(,)?)*)
        -> $ret:ty
        $(where ($($tt:tt)*) )?
        $block:block
    ) => {
        {
            pub struct Func<'a> {
                $(
                    $($capture: &'a mut $cty,)*
                )?
                __phantom: std::marker::PhantomData<fn(&'a ())>,
            }

            impl<'a, $($($parameter,)*)?> Function<($($aty,)*)> for Func<'a> $(where $($tt)*)? {
                type Output = $ret;

                fn apply(&mut $self, ($($arg,)*): ($($aty,)*)) -> Self::Output {
                    $block
                }
            }

            Func {
                $($($capture: &mut $capture,)*)?
                __phantom: std::marker::PhantomData,
            }
        }
    };
}

pub trait Construct<T> {
    fn construct(value: T) -> Self;
}

pub trait List: Sized {
    fn map<F: Map<Self>>(self, f: &mut F) -> F::Output {
        f.map(self)
    }
    fn fold<A, F: Fold<A, Self>>(self, accumulator: A, mut f: F) -> A {
        f.fold(self, accumulator)
    }
    fn construct<T: Construct<Self>>(self) -> T {
        T::construct(self)
    }
}

impl<T> List for Single<T> {}

impl<T, R> List for Sequence<T, R> {}

pub trait Struct: Construct<Self::Fields> {
    type Fields: List;
    type FieldsAndNames: List;

    type FieldsRef<'a>: List
    where
        Self: 'a;
    type FieldsAndNamesRef<'a>: List
    where
        Self: 'a;

    type FieldsMut<'a>: List
    where
        Self: 'a;
    type FieldsAndNamesMut<'a>: List
    where
        Self: 'a;

    fn fields(self) -> Self::Fields;
    fn fields_and_names(self) -> Self::FieldsAndNames;

    fn fields_ref(&self) -> Self::FieldsRef<'_>;
    fn fields_and_names_ref(&self) -> Self::FieldsAndNamesRef<'_>;

    fn fields_mut(&mut self) -> Self::FieldsMut<'_>;
    fn fields_and_names_mut(&mut self) -> Self::FieldsAndNamesMut<'_>;
}

#[derive(Debug, Clone, PartialEq)]
pub struct Point {
    x: i32,
    y: i32,
}

impl Struct for Point {
    type Fields = List![i32, i32];
    type FieldsAndNames = List![(&'static str, i32), (&'static str, i32)];

    type FieldsRef<'a> = List![&'a i32, &'a i32];
    type FieldsAndNamesRef<'a> = List![(&'static str, &'a i32), (&'static str, &'a i32)];

    type FieldsMut<'a> = List![&'a mut i32, &'a mut i32];
    type FieldsAndNamesMut<'a> = List![(&'static str, &'a mut i32), (&'static str, &'a mut i32)];

    fn fields(self) -> Self::Fields {
        list![self.x, self.y]
    }

    fn fields_and_names(self) -> Self::FieldsAndNames {
        list![("x", self.x), ("y", self.y)]
    }

    fn fields_ref(&self) -> Self::FieldsRef<'_> {
        list![&self.x, &self.y]
    }

    fn fields_and_names_ref(&self) -> Self::FieldsAndNamesRef<'_> {
        list![("x", &self.x), ("y", &self.y)]
    }

    fn fields_mut(&mut self) -> Self::FieldsMut<'_> {
        list![&mut self.x, &mut self.y]
    }

    fn fields_and_names_mut(&mut self) -> Self::FieldsAndNamesMut<'_> {
        list![("x", &mut self.x), ("y", &mut self.y)]
    }
}

impl Construct<List![i32, i32]> for Point {
    fn construct(value: List![i32, i32]) -> Self {
        let Sequence(x, Single(y)) = value;
        Self { x, y }
    }
}

function!(
    Dup<T>(&mut self, v: T) -> T where (T: Add<Output = T> + Copy) {
        v + v
    }
);