Skip to content

Instantly share code, notes, and snippets.

@Hywan
Last active October 11, 2019 13:17
Show Gist options
  • Select an option

  • Save Hywan/ce725569fd3534adee5f6f8d90f67a36 to your computer and use it in GitHub Desktop.

Select an option

Save Hywan/ce725569fd3534adee5f6f8d90f67a36 to your computer and use it in GitHub Desktop.

Revisions

  1. Hywan revised this gist Oct 11, 2019. 1 changed file with 105 additions and 6 deletions.
    111 changes: 105 additions & 6 deletions lib.rs
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    use std::fmt::Debug;
    use std::{convert::TryFrom, fmt::Debug};

    pub trait WitValue
    where
    @@ -19,16 +19,20 @@ pub trait WitCall<Func, Inputs> {

    macro_rules! do_it {
    ( $($x:ident),* ) => {
    // Implement `Function` for `Func`
    impl< Func $( , $x )* > Function<Func, ( $( $x ),* )> for Func
    where
    Func: Fn( $( $x ),* ),
    $( $x: WitValue ),*
    {
    fn to_callable(&self) -> &Func {
    println!("size of me {}", ::std::mem::size_of::<Self>());
    println!("size of usize {}", ::std::mem::size_of::<usize>());
    self
    }
    }

    // Implement `WitCall` for tuples.
    impl< Func $( , $x )* > WitCall<Func, ( $( $x ),* )> for ( $( $x ),* )
    where
    Func: Fn( $( $x ),* ),
    @@ -42,12 +46,13 @@ macro_rules! do_it {
    }
    }

    // Implement `call` on `dyn Function`.
    impl<Func $( , $x )*> dyn Function<Func, ( $( $x ),* )>
    where
    Func: Fn( $( $x ),* ),
    $( $x: WitValue ),*
    {
    #[allow(non_snake_case)]
    #[allow(dead_code, non_snake_case)]
    fn call(&self $( , $x: $x )*) {
    ( $( $x ),* ).call(self);
    }
    @@ -71,7 +76,7 @@ do_it!(A, B, C, D, E, F, G, H, I, J, K, L);

    #[cfg(test)]
    #[test]
    fn main() {
    fn test_functions() {
    // arity 0

    ().call(&|| {
    @@ -85,23 +90,117 @@ fn main() {

    // arity 1

    (42i32).call(&|a: i32| {
    (42).call(&|a: i32| {
    println!("{:?}", a);
    });

    let f1: &dyn Function<_, _> = &|a: i32| {
    println!("~~~> {:?}", a);
    };
    f1.call(42i32);
    f1.call(42);

    // arity 2

    (1i32, 2i32).call(&|a: i32, b: i32| {
    (1, 2).call(&|a: i32, b: i32| {
    println!("{:?}, {:?}", a, b);
    });

    let f2: &dyn Function<_, _> = &|a: i32, b: i32| {
    println!("~~~> {:?}, {:?}", a, b);
    };
    f2.call(1, 2);
    }

    pub enum Ty {
    I32,
    I64,
    F32,
    F64,
    }

    #[derive(Debug)]
    pub enum Value {
    I32(i32),
    I64(i64),
    F32(f32),
    F64(f64),
    }

    macro_rules! impl_value {
    ($native_type:ty, $value_variant:ident) => {
    impl TryFrom<&Value> for $native_type {
    type Error = &'static str;

    fn try_from(w: &Value) -> Result<Self, Self::Error> {
    match w {
    Value::$value_variant(n) => Ok(n.clone()),
    _ => Err("Invalid cast."),
    }
    }
    }
    };
    }

    impl_value!(i32, I32);
    impl_value!(i64, I64);
    impl_value!(f32, F32);
    impl_value!(f64, F64);

    #[allow(unused)]
    macro_rules! any_to_value {
    ($variable:ident, $expected_ty:expr) => {{
    use std::convert::TryInto;

    let value: Value = {
    let var_ref: &dyn Any = &$variable;

    match $expected_ty {
    Ty::I32 => var_ref
    .downcast_ref::<i32>()
    .and_then(|v| Some(Value::I32(*v))),
    Ty::I64 => var_ref
    .downcast_ref::<i64>()
    .and_then(|v| Some(Value::I64(*v))),
    Ty::F32 => var_ref
    .downcast_ref::<f32>()
    .and_then(|v| Some(Value::F32(*v))),
    Ty::F64 => var_ref
    .downcast_ref::<f64>()
    .and_then(|v| Some(Value::F64(*v))),
    }
    }
    .expect(&format!(
    "Failed to downcast the value of `{}`.",
    stringify!($variable)
    ));

    (&value).try_into().expect("Failed to cast.")
    }};
    }

    #[cfg(test)]
    #[test]
    fn test_dynamically_typed_functions() {
    use std::any::Any;

    // more fun with dynamically typed inputs

    fn f<A, B>() -> impl Fn(A, B)
    where
    A: Any + WitValue,
    B: Any + WitValue,
    {
    let a_expected_type = Ty::I32;
    let b_expected_type = Ty::I32;

    move |a: A, b: B| {
    let a: i32 = any_to_value!(a, a_expected_type);
    let b: i32 = any_to_value!(b, b_expected_type);

    println!("~~~> {:?} + {:?} = {:?}", a, b, a + b);
    }
    }

    let f2: &dyn Function<_, _> = &f();
    f2.call(1i32, 2i32);
    }
  2. Hywan revised this gist Oct 11, 2019. 1 changed file with 35 additions and 23 deletions.
    58 changes: 35 additions & 23 deletions lib.rs
    Original file line number Diff line number Diff line change
    @@ -2,12 +2,12 @@ use std::fmt::Debug;

    pub trait WitValue
    where
    Self: Debug,
    Self: Sized + Debug + Copy,
    {
    }

    impl WitValue for i32 {}
    impl WitValue for u32 {}
    impl WitValue for f32 {}

    pub trait Function<Func, Inputs> {
    fn to_callable(&self) -> &Func;
    @@ -19,20 +19,20 @@ pub trait WitCall<Func, Inputs> {

    macro_rules! do_it {
    ( $($x:ident),* ) => {
    impl< Func $( ,$x )* > Function<Func, ( $( $x ),* )> for Func
    impl< Func $( , $x )* > Function<Func, ( $( $x ),* )> for Func
    where
    Func: Fn( $( $x ),* )
    $( ,$x: WitValue )*
    Func: Fn( $( $x ),* ),
    $( $x: WitValue ),*
    {
    fn to_callable(&self) -> &Func {
    self
    }
    }

    impl< Func $( ,$x )* > WitCall<Func, ( $( $x ),* )> for ( $( $x ),* )
    impl< Func $( , $x )* > WitCall<Func, ( $( $x ),* )> for ( $( $x ),* )
    where
    Func: Fn( $( $x ),* )
    $( ,$x: WitValue )*
    Func: Fn( $( $x ),* ),
    $( $x: WitValue ),*
    {
    #[allow(non_snake_case, unused_parens)]
    fn call(self, function: &dyn Function<Func, ( $( $x ),* )>) {
    @@ -41,6 +41,17 @@ macro_rules! do_it {
    function( $( $x ),* )
    }
    }

    impl<Func $( , $x )*> dyn Function<Func, ( $( $x ),* )>
    where
    Func: Fn( $( $x ),* ),
    $( $x: WitValue ),*
    {
    #[allow(non_snake_case)]
    fn call(&self $( , $x: $x )*) {
    ( $( $x ),* ).call(self);
    }
    }
    }
    }

    @@ -56,40 +67,41 @@ do_it!(A, B, C, D, E, F, G, H);
    do_it!(A, B, C, D, E, F, G, H, I);
    do_it!(A, B, C, D, E, F, G, H, I, J);
    do_it!(A, B, C, D, E, F, G, H, I, J, K);

    pub fn call<InputTypes, InputValues, Func>(
    inputs: InputValues,
    function: &dyn Function<Func, InputTypes>,
    ) where
    InputValues: WitCall<Func, InputTypes>,
    {
    inputs.call(function);
    }
    do_it!(A, B, C, D, E, F, G, H, I, J, K, L);

    #[cfg(test)]
    #[test]
    fn main() {
    // arity 0

    ().call(&|| {
    println!("()");
    });

    call((), &|| {
    let f0: &dyn Function<_, _> = &|| {
    println!("~~~> ()");
    });
    };
    f0.call();

    // arity 1

    (42i32).call(&|a: i32| {
    println!("{:?}", a);
    });

    call(42i32, &|a: i32| {
    let f1: &dyn Function<_, _> = &|a: i32| {
    println!("~~~> {:?}", a);
    });
    };
    f1.call(42i32);

    // arity 2

    (1i32, 2i32).call(&|a: i32, b: i32| {
    println!("{:?}, {:?}", a, b);
    });

    call((1i32, 2i32), &|a: i32, b: i32| {
    let f2: &dyn Function<_, _> = &|a: i32, b: i32| {
    println!("~~~> {:?}, {:?}", a, b);
    });
    };
    f2.call(1i32, 2i32);
    }
  3. Hywan created this gist Oct 7, 2019.
    95 changes: 95 additions & 0 deletions lib.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,95 @@
    use std::fmt::Debug;

    pub trait WitValue
    where
    Self: Debug,
    {
    }

    impl WitValue for i32 {}
    impl WitValue for u32 {}

    pub trait Function<Func, Inputs> {
    fn to_callable(&self) -> &Func;
    }

    pub trait WitCall<Func, Inputs> {
    fn call(self, function: &dyn Function<Func, Inputs>);
    }

    macro_rules! do_it {
    ( $($x:ident),* ) => {
    impl< Func $( ,$x )* > Function<Func, ( $( $x ),* )> for Func
    where
    Func: Fn( $( $x ),* )
    $( ,$x: WitValue )*
    {
    fn to_callable(&self) -> &Func {
    self
    }
    }

    impl< Func $( ,$x )* > WitCall<Func, ( $( $x ),* )> for ( $( $x ),* )
    where
    Func: Fn( $( $x ),* )
    $( ,$x: WitValue )*
    {
    #[allow(non_snake_case, unused_parens)]
    fn call(self, function: &dyn Function<Func, ( $( $x ),* )>) {
    let function: &dyn Fn( $( $x ),* ) = function.to_callable();
    let ( $( $x ),* ) = self;
    function( $( $x ),* )
    }
    }
    }
    }

    do_it!();
    do_it!(A);
    do_it!(A, B);
    do_it!(A, B, C);
    do_it!(A, B, C, D);
    do_it!(A, B, C, D, E);
    do_it!(A, B, C, D, E, F);
    do_it!(A, B, C, D, E, F, G);
    do_it!(A, B, C, D, E, F, G, H);
    do_it!(A, B, C, D, E, F, G, H, I);
    do_it!(A, B, C, D, E, F, G, H, I, J);
    do_it!(A, B, C, D, E, F, G, H, I, J, K);

    pub fn call<InputTypes, InputValues, Func>(
    inputs: InputValues,
    function: &dyn Function<Func, InputTypes>,
    ) where
    InputValues: WitCall<Func, InputTypes>,
    {
    inputs.call(function);
    }

    #[cfg(test)]
    #[test]
    fn main() {
    ().call(&|| {
    println!("()");
    });

    call((), &|| {
    println!("~~~> ()");
    });

    (42i32).call(&|a: i32| {
    println!("{:?}", a);
    });

    call(42i32, &|a: i32| {
    println!("~~~> {:?}", a);
    });

    (1i32, 2i32).call(&|a: i32, b: i32| {
    println!("{:?}, {:?}", a, b);
    });

    call((1i32, 2i32), &|a: i32, b: i32| {
    println!("~~~> {:?}, {:?}", a, b);
    });
    }