1use std::future::Future;
2use std::panic::AssertUnwindSafe;
3
4use crate::worker_sys::Context as JsContext;
5use crate::Result;
6
7use serde::de::DeserializeOwned;
8use wasm_bindgen::JsValue;
9use wasm_bindgen_futures::future_to_promise;
10
11#[derive(Debug)]
13pub struct Context {
14 inner: JsContext,
15}
16
17unsafe impl Send for Context {}
18unsafe impl Sync for Context {}
19
20impl Context {
21 pub fn new(inner: JsContext) -> Self {
23 Self { inner }
24 }
25
26 pub fn wait_until<F>(&self, future: F)
36 where
37 F: Future<Output = ()> + 'static,
38 {
39 self.inner
40 .wait_until(&future_to_promise(AssertUnwindSafe(async {
41 future.await;
42 Ok(JsValue::UNDEFINED)
43 })))
44 .unwrap()
45 }
46
47 pub fn pass_through_on_exception(&self) {
51 self.inner.pass_through_on_exception().unwrap()
52 }
53
54 pub fn props<T: DeserializeOwned>(&self) -> Result<T> {
83 Ok(serde_wasm_bindgen::from_value(self.inner.props())?)
84 }
85}
86
87impl AsRef<JsContext> for Context {
88 fn as_ref(&self) -> &JsContext {
89 &self.inner
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use serde::Deserialize;
97 use wasm_bindgen::JsCast;
98 use wasm_bindgen_test::*;
99
100 #[derive(Debug, Deserialize, PartialEq)]
101 struct TestProps {
102 #[serde(rename = "clientId")]
103 client_id: String,
104 permissions: Vec<String>,
105 }
106
107 #[wasm_bindgen_test]
108 fn test_props_deserialization() {
109 let obj = js_sys::Object::new();
111
112 let props = js_sys::Object::new();
114 js_sys::Reflect::set(&props, &"clientId".into(), &"frontend-worker".into()).unwrap();
115
116 let permissions = js_sys::Array::new();
117 permissions.push(&"read".into());
118 permissions.push(&"write".into());
119 js_sys::Reflect::set(&props, &"permissions".into(), &permissions.into()).unwrap();
120
121 js_sys::Reflect::set(&obj, &"props".into(), &props.into()).unwrap();
122
123 let js_context: JsContext = obj.unchecked_into();
125 let context = Context::new(js_context);
126
127 let result: Result<TestProps> = context.props();
129 assert!(result.is_ok());
130
131 let props = result.unwrap();
132 assert_eq!(props.client_id, "frontend-worker");
133 assert_eq!(props.permissions, vec!["read", "write"]);
134 }
135
136 #[wasm_bindgen_test]
137 fn test_props_empty_object() {
138 let obj = js_sys::Object::new();
140 let props = js_sys::Object::new();
141 js_sys::Reflect::set(&obj, &"props".into(), &props.into()).unwrap();
142
143 let js_context: JsContext = obj.unchecked_into();
144 let context = Context::new(js_context);
145
146 #[derive(Debug, Deserialize, PartialEq)]
147 struct EmptyProps {}
148
149 let result: Result<EmptyProps> = context.props();
150 assert!(result.is_ok());
151 }
152}