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
use stateroom::MessageFromProcess;
pub use stateroom::{ClientId, MessageRecipient, StateroomContext, StateroomService};
pub use stateroom::{MessagePayload, MessageToProcess};
pub use stateroom_wasm_macro::stateroom_wasm;

type Callback = unsafe extern "C" fn(*const u8, u32);

pub struct WrappedStateroomService<S: StateroomService> {
    state: S,
    context: WasmStateroomContext,
}

impl<S: StateroomService> WrappedStateroomService<S> {
    pub fn new(state: S, callback: Callback) -> Self {
        Self {
            state,
            context: WasmStateroomContext { callback },
        }
    }

    pub fn recv(&mut self, message_ptr: *const u8, message_len: u32) {
        let message = unsafe { std::slice::from_raw_parts(message_ptr, message_len as usize) };
        let message: MessageToProcess = bincode::deserialize(message).unwrap();

        match message {
            MessageToProcess::Init => {
                self.state.init(&self.context);
            }
            MessageToProcess::Connect { client } => {
                self.state.connect(client.into(), &self.context);
            }
            MessageToProcess::Disconnect { client } => {
                self.state.disconnect(client.into(), &self.context);
            }
            MessageToProcess::Message { sender, message } => {
                self.state.message(sender, message, &self.context);
            }
            MessageToProcess::Timer => {
                self.state.timer(&self.context);
            }
        }
    }
}

struct WasmStateroomContext {
    callback: Callback,
}

impl WasmStateroomContext {
    pub fn send(&self, message: &MessageFromProcess) {
        let message = bincode::serialize(message).unwrap();
        unsafe {
            (self.callback)(message.as_ptr(), message.len() as u32);
        }
    }
}

impl StateroomContext for WasmStateroomContext {
    fn send_message(
        &self,
        recipient: impl Into<MessageRecipient>,
        message: impl Into<MessagePayload>,
    ) {
        let message: MessagePayload = message.into();
        let recipient: MessageRecipient = recipient.into();

        self.send(&MessageFromProcess::Message { recipient, message });
    }

    fn set_timer(&self, ms_delay: u32) {
        self.send(&MessageFromProcess::SetTimer { ms_delay });
    }
}