web_thread/
post.rs

1use super::{JsValue, js_sys};
2
3/// Objects that can be sent via `postMessage`.  A type that is `Post`
4/// supports being serialized into a JavaScript object that can be
5/// sent using `postMessage`, and also getting an array of subobjects
6/// that must be
7/// [transferred](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects).
8pub trait Post: AsJs {
9    /// Get a list of the objects that must be
10    /// transferred when calling `postMessage`.
11    ///
12    /// The default implementation returns an empty array.
13    fn transferables(&self) -> js_sys::Array {
14        js_sys::Array::new()
15    }
16}
17
18/// Convenience trait for something that can have messages posted to
19/// it, including
20/// [transferables](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects).
21pub trait PostExt {
22    /// Send a value, transferring subobjects as necessary.
23    ///
24    /// This function consumes `message`, as in general it may leave
25    /// the object in an incoherent state.
26    ///
27    /// # Errors
28    ///
29    /// If the message could not be sent.
30    fn post(&self, message: impl Post) -> Result<(), JsValue>;
31}
32
33impl PostExt for web_sys::MessagePort {
34    fn post(&self, message: impl Post) -> Result<(), JsValue> {
35        // While not syntactically consumed, the use of `postMessage`
36        // here may leave `Context` in an invalid state (setting
37        // transferred JavaScript values to `undefined`).
38        #![allow(clippy::needless_pass_by_value)]
39
40        self.post_message_with_transferable(&message.to_js()?, &message.transferables())
41    }
42}
43
44impl PostExt for web_sys::Worker {
45    fn post(&self, message: impl Post) -> Result<(), JsValue> {
46        // While not syntactically consumed, the use of `postMessage`
47        // here may leave `Context` in an invalid state (setting
48        // transferred JavaScript values to `undefined`).
49        #![allow(clippy::needless_pass_by_value)]
50
51        self.post_message_with_transfer(&message.to_js()?, &message.transferables())
52    }
53}
54
55/// A serializable (JS-friendly) representation of a message plus its
56/// transferables.
57#[derive(serde::Serialize)]
58pub struct Postable {
59    #[serde(with = "serde_wasm_bindgen::preserve")]
60    message: JsValue,
61    #[serde(with = "serde_wasm_bindgen::preserve")]
62    transfer: js_sys::Array,
63}
64
65impl Postable {
66    pub fn new(message: impl Post) -> Result<Self, JsValue> {
67        // While not syntactically consumed, the use of `postMessage`
68        // may leave `Context` in an invalid state (setting
69        // transferred JavaScript values to `undefined`).
70        #![allow(clippy::needless_pass_by_value)]
71
72        Ok(Self {
73            message: message.to_js()?,
74            transfer: message.transferables(),
75        })
76    }
77}
78
79/// An object-safe version of `std::convert::Into`.
80pub trait AsJs {
81    fn to_js(&self) -> Result<JsValue, JsValue>;
82    fn from_js(js_value: JsValue) -> Result<Self, JsValue>
83    where
84        Self: Sized;
85}
86
87impl<T: serde::Serialize + serde::de::DeserializeOwned> AsJs for T {
88    fn to_js(&self) -> Result<JsValue, JsValue> {
89        Ok(serde_wasm_bindgen::to_value(self)?)
90    }
91
92    fn from_js(value: JsValue) -> Result<Self, JsValue>
93    where
94        Self: Sized,
95    {
96        Ok(serde_wasm_bindgen::from_value(value)?)
97    }
98}
99
100impl Post for () {}
101impl Post for u8 {}
102impl Post for u16 {}
103impl Post for u32 {}
104impl Post for u64 {}
105impl Post for u128 {}
106impl Post for i8 {}
107impl Post for i16 {}
108impl Post for i32 {}
109impl Post for i64 {}
110impl Post for i128 {}
111impl Post for String {}
112
113impl<T: Post, E: Post> Post for Result<T, E>
114where
115    Result<T, E>: AsJs,
116{
117    fn transferables(&self) -> js_sys::Array {
118        match self {
119            Ok(x) => x.transferables(),
120            Err(e) => e.transferables(),
121        }
122    }
123}