mika 0.0.0

A framework for building wasm front-end web application in Rust
#[macro_export]
macro_rules! handler {
    ($state:ident . $($idents:ident).+ (_)) => {{
        let cloned_state = $state.clone();
        move |arg| cloned_state.$($idents).+(arg)
    }};
    ($state:ident . $($idents:ident).+ (_, $($tt:tt)+)) => {{
        let cloned_state = $state.clone();
        move |arg| cloned_state.$($idents).+(arg, $($tt)+)
    }};
    ($state:ident . $($idents:ident).+ ($($tt:tt)*)) => {{
        let cloned_state = $state.clone();
        move |_| cloned_state.$($idents).+($($tt)*)
    }};
}

#[macro_export]
macro_rules! update {
    ($state:ident, $first:ident$(::$idents:ident)*) => {{
        let cloned_state = $state.clone();
        move |_| cloned_state.update($first$(::$idents)*)
    }};
    ($state:ident, $first:ident$(::$idents:ident)*(_)) => {{
        let cloned_state = $state.clone();
        move |arg| cloned_state.update($first$(::$idents)*(arg))
    }};
    ($state:ident, $first:ident$(::$idents:ident)*(_, $($tt:tt)+)) => {{
        let cloned_state = $state.clone();
        move |arg| cloned_state.update($first$(::$idents)*(arg, $($tt)+))
    }};
    ($state:ident, $first:ident$(::$idents:ident)*($($tt:tt)+)) => {{
        let cloned_state = $state.clone();
        move |_| cloned_state.update($first$(::$idents)*($($tt)+))
    }};
}

#[macro_export]
macro_rules! create_app_handle {
    ($TypeName:ident) => {
        #[wasm_bindgen]
        pub struct AppHandle {
            _app: App<$TypeName>,
        }

        #[wasm_bindgen]
        impl AppHandle {
            #[wasm_bindgen(constructor)]
            pub fn new() -> Self {
                Self {
                    _app: App::start_in_body($TypeName::new())
                }
            }
        }
    };
}

#[cfg(test)]
mod test {
    enum Msg {
        N42,
        Double(i32),
        Add(i32,i32),
        Sum(i32,i32,i32),
    }
    #[derive(Clone)]
    struct Test;
    impl Test {
        fn n42(&self) -> i32 {
            42
        }
        fn double(&self, me: i32)  -> i32 {
            me * 2
        }
        fn add(&self, a: i32, b: i32)  -> i32 {
            a + b
        }
        fn sum(&self, a: i32, b: i32, c: i32) -> i32 {
            a + b + c
        }
        fn update(&self, m: Msg) -> i32 {
            match m {
                Msg::N42 => 42,
                Msg::Double(value) => value*2,
                Msg::Add(v1, v2) => v1 + v2,
                Msg::Sum(v1,v2,v3) => v1 + v2 + v3,
            }
        }
    }

    #[test]
    fn handler_no_arg() {
        assert_eq!(42, handler!(Test.n42())(()));
    }

    #[test]
    fn handler_with_arg() {
        assert_eq!(84, handler!(Test.double(42))(()));
        assert_eq!(84, handler!(Test.add(42,42))(()));
        assert_eq!(85, handler!(Test.sum(42,42,1))(()));
    }

    #[test]
    fn handler_optional_arg_only() {
        assert_eq!(84, handler!(Test.double(_))(42));
    }

    #[test]
    fn handler_optional_arg_and_other() {
        assert_eq!(84, handler!(Test.add(_,42))(42));
        assert_eq!(85, handler!(Test.sum(_,42,1))(42));
    }

    #[test]
    fn update() {
        assert_eq!(42, update!(Test, Msg::N42)(()));
        assert_eq!(84, update!(Test, Msg::Double(42))(()));
        assert_eq!(84, update!(Test, Msg::Add(42,42))(()));
        assert_eq!(80, update!(Test, Msg::Sum(42,42,-4))(()));
    }

    #[test]
    fn update_with_optional_arg() {
        assert_eq!(84, update!(Test, Msg::Double(_))(42));
        assert_eq!(84, update!(Test, Msg::Add(_,42))(42));
        assert_eq!(80, update!(Test, Msg::Sum(_,42,42))(-4));
    }
}