Skip to main content

wry_bindgen/
lib.rs

1//! wry-bindgen - Runtime support for wasm-bindgen-style bindings over Wry's WebView
2//!
3//! This crate provides the runtime types and traits needed for the `#[wasm_bindgen]`
4//! attribute macro to generate code that works with Wry's IPC protocol.
5//!
6//! # Architecture
7//!
8//! The crate is organized into several modules:
9//!
10//! - [`BinaryEncode`]/[`BinaryDecode`] - Core encoding/decoding traits for Rust types
11//! - [`JSFunction`] - JSFunction type for calling JavaScript functions
12//! - [`batch`] - Batching helpers for grouping multiple JS operations
13//! - [`wry`] - Event loop and Wry integration
14
15#![no_std]
16
17#[doc(hidden)]
18pub extern crate alloc;
19#[macro_use]
20extern crate std;
21
22pub mod batch;
23mod cast;
24mod clamped;
25pub mod closure;
26pub mod convert;
27mod encode;
28mod erasure;
29mod function;
30mod function_registry;
31mod id_allocator;
32mod intern;
33pub(crate) mod ipc;
34#[macro_use]
35mod wire;
36#[doc(hidden)]
37#[path = "rt.rs"]
38pub mod __rt;
39mod js_error;
40mod js_helpers;
41mod lazy;
42mod object_store;
43mod parent;
44mod runtime;
45pub mod sys;
46mod try_from_js;
47mod type_cache;
48mod value;
49pub mod wry;
50
51pub use intern::*;
52
53// Re-export core types
54pub use crate::__rt::marker::ErasableGeneric;
55pub use cast::JsCast;
56pub use clamped::Clamped;
57pub use closure::{
58    Closure, IntoWasmClosure, IntoWasmClosureRef, IntoWasmClosureRefMut, MaybeUnwindSafe,
59    ScopedClosure, WasmClosure, WasmClosureFnOnce, WasmClosureFnOnceAbort, WryWasmClosure,
60};
61pub use js_error::JsError;
62pub use lazy::JsThreadLocal;
63pub use value::JsValue;
64
65pub use crate::__rt::{Ref, RefMut};
66pub use parent::Parent;
67
68pub use convert::{IntoJsGeneric, JsGeneric};
69pub use encode::{BatchableResult, BinaryDecode, BinaryEncode, EncodeTypeDef};
70pub use function::JSFunction;
71pub use ipc::{DecodeError, DecodedData, EncodedData};
72pub use sys::{JsOption, Null, Promising, Undefined};
73
74// Re-export the macros
75pub use wry_bindgen_macro::link_to;
76pub use wry_bindgen_macro::wasm_bindgen;
77
78/// Macro to register and call a JavaScript function.
79///
80/// This macro encapsulates the common pattern of:
81/// 1. Creating a static JsFunctionSpec
82/// 2. Submitting it to inventory
83/// 3. Creating a LazyJsFunction with the given signature
84/// 4. Calling the function with the provided arguments
85///
86/// # Usage
87/// ```ignore
88/// __wry_call_js_function!("(a, b) => a + b", fn(i32, i32) -> i32, (x, y))
89/// ```
90#[macro_export]
91#[doc(hidden)]
92macro_rules! __wry_call_js_function {
93    ($js_code:expr, $fn_type:ty, ($($args:expr),*)) => {{
94        static __FUNC: $crate::__rt::LazyJsFunction<$fn_type> =
95            $crate::__wry_submit_js_function!($js_code);
96
97        __FUNC.call($($args),*)
98    }};
99}
100
101/// Macro to register and call a JavaScript function.
102///
103/// This macro encapsulates the common pattern of:
104/// 1. Creating a static JsFunctionSpec
105/// 2. Submitting it to inventory
106/// 3. Creating a LazyJsFunction with the given signature
107///
108/// # Usage
109/// ```ignore
110/// __wry_submit_js_function!("(a, b) => a + b")
111/// ```
112#[macro_export]
113#[doc(hidden)]
114macro_rules! __wry_submit_js_function {
115    ($js_code:expr) => {{
116        static __SPEC: $crate::__rt::JsFunctionSpec =
117            $crate::__rt::JsFunctionSpec::new(|| $crate::alloc::format!($js_code));
118
119        $crate::__rt::inventory::submit! {
120            __SPEC
121        }
122
123        __SPEC.resolve_as()
124    }};
125}
126
127/// Extension trait for Option to unwrap or throw a JS error.
128/// This is API-compatible with wasm-bindgen's UnwrapThrowExt.
129pub trait UnwrapThrowExt<T>: Sized {
130    /// Unwrap the value or panic with a message.
131    ///
132    /// Has a default impl (delegating to [`expect_throw`](Self::expect_throw)) to
133    /// match upstream wasm-bindgen, so downstream impls only need `expect_throw`.
134    #[cfg_attr(any(debug_assertions, not(target_family = "wasm")), track_caller)]
135    fn unwrap_throw(self) -> T {
136        if cfg!(all(debug_assertions, target_family = "wasm")) {
137            let loc = core::panic::Location::caller();
138            let msg = alloc::format!(
139                "called `{}::unwrap_throw()` ({}:{}:{})",
140                core::any::type_name::<Self>(),
141                loc.file(),
142                loc.line(),
143                loc.column()
144            );
145            self.expect_throw(&msg)
146        } else {
147            self.expect_throw("called `unwrap_throw()`")
148        }
149    }
150
151    /// Unwrap the value or panic with a custom message.
152    fn expect_throw(self, message: &str) -> T;
153}
154
155impl<T> UnwrapThrowExt<T> for Option<T> {
156    fn unwrap_throw(self) -> T {
157        self.expect("called `Option::unwrap_throw()` on a `None` value")
158    }
159
160    fn expect_throw(self, message: &str) -> T {
161        self.expect(message)
162    }
163}
164
165impl<T, E> UnwrapThrowExt<T> for Result<T, E>
166where
167    E: core::fmt::Debug,
168{
169    fn unwrap_throw(self) -> T {
170        self.expect("called `Result::unwrap_throw()` on an `Err` value")
171    }
172
173    fn expect_throw(self, message: &str) -> T {
174        self.expect(message)
175    }
176}
177
178#[cold]
179#[inline(never)]
180pub fn throw_val(s: JsValue) -> ! {
181    panic!("{s:?}");
182}
183
184/// Throw a JS exception with the given message.
185///
186/// # Panics
187/// This function always panics when running outside of WASM.
188#[cold]
189#[inline(never)]
190pub fn throw_str(s: &str) -> ! {
191    panic!("cannot throw JS exception when running outside of wasm: {s}");
192}
193
194/// Renamed to [`throw_str`].
195#[cold]
196#[inline(never)]
197#[deprecated(note = "renamed to `throw_str`")]
198#[doc(hidden)]
199pub fn throw(s: &str) -> ! {
200    throw_str(s)
201}
202
203/// Returns the number of live externref objects.
204///
205/// # Panics
206/// This function always panics when running outside of WASM.
207pub fn externref_heap_live_count() -> u32 {
208    panic!("cannot introspect wasm memory when running outside of wasm")
209}
210
211/// Returns a handle to this Wasm instance's `WebAssembly.Module`.
212///
213/// # Panics
214/// This function always panics when running outside of WASM.
215pub fn module() -> JsValue {
216    panic!("cannot introspect wasm memory when running outside of wasm")
217}
218
219/// Returns a handle to this Wasm instance's `WebAssembly.Instance`.
220///
221/// # Panics
222/// This function always panics when running outside of WASM.
223pub fn instance() -> JsValue {
224    panic!("cannot introspect wasm memory when running outside of wasm")
225}
226
227/// Returns a handle to this Wasm instance's `WebAssembly.Instance.prototype.exports`.
228///
229/// # Panics
230/// This function always panics when running outside of WASM.
231pub fn exports() -> JsValue {
232    panic!("cannot introspect wasm memory when running outside of wasm")
233}
234
235/// Returns a handle to this Wasm instance's `WebAssembly.Memory`.
236///
237/// # Panics
238/// This function always panics when running outside of WASM.
239pub fn memory() -> JsValue {
240    panic!("cannot introspect wasm memory when running outside of wasm")
241}
242
243/// Returns a handle to this Wasm instance's `WebAssembly.Table` (indirect function table).
244///
245/// # Panics
246/// This function always panics when running outside of WASM.
247pub fn function_table() -> JsValue {
248    panic!("cannot introspect wasm memory when running outside of wasm")
249}
250
251/// Legacy wrapper for imported statics.
252///
253/// This type implements `Deref` to the inner type so it's typically used as if
254/// it were `&T`. Prefer `#[wasm_bindgen(thread_local_v2)]` and [`JsThreadLocal`].
255#[deprecated = "use with `#[wasm_bindgen(thread_local_v2)]` instead"]
256pub struct JsStatic<T: 'static> {
257    #[doc(hidden)]
258    pub __inner: &'static std::thread::LocalKey<T>,
259}
260
261#[allow(deprecated)]
262impl<T: 'static> core::ops::Deref for JsStatic<T> {
263    type Target = T;
264    fn deref(&self) -> &T {
265        unsafe { self.__inner.with(|ptr| &*(ptr as *const T)) }
266    }
267}
268
269/// Prelude module for common imports
270pub mod prelude {
271    pub use crate::Clamped;
272    pub use crate::JsCast;
273    pub use crate::JsError;
274    pub use crate::JsValue;
275    pub use crate::UnwrapThrowExt;
276    pub use crate::WasmClosure;
277    pub use crate::closure::{Closure, ScopedClosure};
278    pub use crate::convert::Upcast;
279    pub use crate::convert::{IntoJsGeneric, JsGeneric, UpcastFrom};
280    pub use crate::wasm_bindgen;
281    pub use crate::{BatchableResult, BinaryDecode, BinaryEncode, EncodeTypeDef};
282    pub use crate::{JSFunction, JsThreadLocal};
283    pub use crate::{JsOption, Null, Promising, Undefined};
284}