Skip to main content

wry_bindgen/encode/
values.rs

1//! JsValue, Closure, and reference encoding implementations.
2
3use alloc::string::String;
4use alloc::vec::Vec;
5use core::marker::PhantomData;
6
7use crate::Closure;
8use crate::batch::{Runtime, with_runtime};
9use crate::ipc::{DecodeError, DecodedData, EncodedData};
10use crate::value::JsValue;
11
12use super::{BatchableResult, BinaryDecode, BinaryEncode, EncodeTypeDef, TypeTag};
13
14impl EncodeTypeDef for JsValue {
15    fn encode_type_def(buf: &mut Vec<u8>) {
16        buf.push(TypeTag::HeapRef as u8);
17    }
18}
19
20impl BinaryEncode for JsValue {
21    fn encode(self, encoder: &mut EncodedData) {
22        encoder.push_u64(self.id());
23    }
24}
25
26impl BinaryDecode for JsValue {
27    fn decode(_decoder: &mut DecodedData) -> Result<Self, DecodeError> {
28        // JS always sends heap references without inline IDs: Rust allocates them
29        // into the current inbound batch and ships the IDs back in the next
30        // outbound message's install-batch list.
31        let id = with_runtime(|runtime| runtime.get_next_inbound_js_heap_id());
32        Ok(JsValue::from_id(id))
33    }
34}
35
36impl BatchableResult for JsValue {
37    fn try_placeholder(batch: &mut Runtime) -> Option<Self> {
38        // Use get_next_placeholder_id() to track reserved slots for JS
39        Some(JsValue::from_id(batch.get_next_placeholder_id()))
40    }
41}
42
43impl<F: ?Sized> BatchableResult for Closure<F> {
44    fn try_placeholder(batch: &mut Runtime) -> Option<Self> {
45        Some(Closure {
46            _phantom: PhantomData,
47            callback: crate::closure::CallbackOwnership::None,
48            value: JsValue::try_placeholder(batch)?,
49        })
50    }
51}
52
53/// Implement BatchableResult for value types that always need a flush to get the result.
54macro_rules! impl_value_type {
55    ($($ty:ty),*) => {
56        $(impl BatchableResult for $ty {})*
57    };
58}
59
60impl_value_type!(
61    bool, char, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, isize, usize, f32, f64, String
62);
63
64/// Marker trait for types that can be cheaply cloned for encoding.
65macro_rules! ref_encode_via_clone {
66    ($($ty:ty),* $(,)?) => {
67        $(
68            impl BinaryEncode for &$ty {
69                fn encode(self, encoder: &mut EncodedData) {
70                    self.clone().encode(encoder);
71                }
72            }
73        )*
74    };
75}
76
77ref_encode_via_clone!(
78    bool, char, u8, u16, u32, u64, i8, i16, i32, i64, f32, f64, usize, isize, String,
79);
80
81macro_rules! slice_encode_via_copy {
82    ($($ty:ty),* $(,)?) => {
83        $(
84            impl BinaryEncode for &[$ty] {
85                fn encode(self, encoder: &mut EncodedData) {
86                    encoder.push_u32(self.len() as u32);
87                    for val in self {
88                        (*val).encode(encoder);
89                    }
90                }
91            }
92
93            impl BinaryEncode for &mut [$ty] {
94                fn encode(self, encoder: &mut EncodedData) {
95                    encoder.push_u32(self.len() as u32);
96                    for val in self {
97                        (*val).encode(encoder);
98                    }
99                }
100            }
101        )*
102    };
103}
104
105slice_encode_via_copy!(
106    bool, char, u8, u16, u32, u64, i8, i16, i32, i64, f32, f64, usize, isize
107);
108
109impl<T: crate::convert::JsGeneric> BinaryEncode for &T {
110    fn encode(self, encoder: &mut EncodedData) {
111        encoder.push_u64(self.as_ref().id());
112    }
113}