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
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use serde;
use serde::de::DeserializeOwned;
pub use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub use wapc_guest::prelude;
pub use wapc_guest::prelude::{console_log, host_call};

#[macro_export]
macro_rules! register_view {
    ($n:ident, $t:ident) => {{
        crate::prelude::register_function(
            &["view-start-", stringify!($n)].join("")[..],
            |b: &[u8]| {
                let params = crate::deserialize(b)?;
                let s = $t::start(params)?;
                serialize(&s)
            },
        );
        crate::prelude::register_function(
            &["view-event-", stringify!($n)].join("")[..],
            |b: &[u8]| {
                let (state, name, payload): (&[u8], &str, &[u8]) = crate::deserialize(b)?;
                let mut s: $t = crate::deserialize(state)?;
                s.event(name, payload)?;
                serialize(&s)
            },
        );
        crate::prelude::register_function(
            &["view-render-", stringify!($n)].join("")[..],
            |b: &[u8]| {
                let s: $t = crate::deserialize(b)?;
                let html = s.render()?;
                Ok(html.into_bytes())
            },
        );
    }};
}
#[macro_export]
macro_rules! register_call {
    ($n:ident, $f:ident) => {{
        crate::prelude::register_function(&["call-", stringify!($n)].join("")[..], |b: &[u8]| {
            run_function(b, $f)
        });
    }};
}
#[macro_export]
macro_rules! assemble_init {
    ($f:block) => {
        #[no_mangle]
        pub extern "C" fn wapc_init() {
            std::panic::set_hook(Box::new(hook));
            $f
        }
    };
}

pub fn hook(info: &std::panic::PanicInfo) {
    let msg = info.to_string();
    wapc_guest::prelude::console_log(&msg[..]);
}

pub type Html = String;
pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Sync + Send>>;

pub trait View: Sync + Send {
    fn start(params: HashMap<String, String>) -> Result<Self>
    where
        Self: Sized;
    fn event(&mut self, msg: &str, body: &[u8]) -> Result<()>;
    fn render(&self) -> Result<Html>;
}

pub fn serialize<T: ?Sized>(val: &T) -> Result<Vec<u8>>
where
    T: Serialize,
{
    match rmp_serde::to_vec(val) {
        Ok(v) => Ok(v),
        Err(v) => Err(Box::new(v)),
    }
}

pub fn deserialize<'a, R: ?Sized, T>(rd: &'a R) -> Result<T>
where
    R: AsRef<[u8]>,
    T: Deserialize<'a>,
{
    match rmp_serde::from_read_ref(rd) {
        Ok(v) => Ok(v),
        Err(v) => Err(Box::new(v)),
    }
}

pub fn run_function<T, R>(
    b: &[u8],
    f: fn(&Option<T>) -> std::result::Result<Box<R>, Box<dyn std::error::Error + Sync + Send>>,
) -> wapc_guest::prelude::CallResult
where
    T: DeserializeOwned,
    R: Serialize + ?Sized,
{
    if b.len() == 0 {
        match rmp_serde::to_vec(&f(&None)?) {
            Ok(v) => Ok(v),
            Err(v) => Err(Box::new(v)),
        }
    } else {
        match rmp_serde::from_read_ref(&b) {
            Ok(input) => match rmp_serde::to_vec(&f(&Some(input))?) {
                Ok(v) => Ok(v),
                Err(v) => Err(Box::new(v)),
            },
            Err(v) => Err(Box::new(v)),
        }
    }
}