wasm_rs_shared_channel/
lib.rs

1//! # Shared Channel for WebAssembly
2//!
3//! This crate provides a way for WebAssembly threads to receive messages from other threads using
4//! a JavaScript primitive called `SharedArrayBuffer` which allows to share memory and use atomics
5//! between different threads.
6//!
7//! This allows us to deploy Rust code as a worker process communicating with the main thread.
8use js_sys::Uint8Array;
9use thiserror::Error;
10use wasm_bindgen::prelude::*;
11
12pub mod spsc;
13
14/// [`Shareable::from`] indicates that it needs at least `n` bytes to proceed
15#[derive(Debug, Clone, Error)]
16#[error("expects {0} bytes more")]
17pub struct Expects(pub u32);
18
19/// Any type that can be sent through a shared channel must implement this
20pub trait Shareable: Sized {
21    /// A generic error
22    type Error: std::error::Error;
23    /// Converts value into a [`js_sys::Uint8Array`]
24    fn to_bytes(&self) -> Result<Uint8Array, Self::Error>;
25    /// Converts [`js_sys::Uint8Array`] into a value
26    fn from(bytes: &Uint8Array) -> Result<Result<Self, Expects>, Self::Error>;
27}
28
29#[cfg(feature = "serde")]
30impl<T> Shareable for T
31where
32    for<'a> T: serde::Serialize + serde::Deserialize<'a>,
33{
34    #[cfg(not(any(feature = "serde-bincode")))]
35    std::compile_error!("one of these features has to be enabled: serde-bincode");
36
37    #[cfg(feature = "serde-bincode")]
38    type Error = bincode::Error;
39
40    fn to_bytes(&self) -> Result<Uint8Array, Self::Error> {
41        #[cfg(feature = "serde-bincode")]
42        let mut result: Vec<u8> = (bincode::serialized_size(self)? as u32)
43            .to_ne_bytes()
44            .into();
45        #[cfg(feature = "serde-bincode")]
46        let mut encoded: Vec<u8> = bincode::serialize(self)?;
47        result.append(&mut encoded);
48        Ok(Uint8Array::from(&result[..]))
49    }
50    fn from(bytes: &Uint8Array) -> Result<Result<Self, Expects>, Self::Error> {
51        if bytes.byte_length() == 0 {
52            return Ok(Err(Expects(4))); // need length
53        }
54        if bytes.byte_length() >= 4 {
55            let mut data = vec![0; bytes.byte_length() as usize];
56            bytes.copy_to(&mut data);
57            let size = u32::from_ne_bytes([data[0], data[1], data[2], data[3]]);
58            if bytes.byte_length() == 4 {
59                return Ok(Err(Expects(4 + size))); // now we know the full length
60            }
61            #[cfg(feature = "serde-bincode")]
62            return Ok(Ok(bincode::deserialize::<Self>(&data[4..])?));
63        }
64
65        #[cfg(feature = "serde-bincode")]
66        Err(Box::new(bincode::ErrorKind::Custom(
67            "unexpected data".to_string(),
68        )))
69    }
70}