wry_bindgen/
encode.rs

1//! Core encoding and decoding traits for the binary protocol.
2//!
3//! This module provides traits for serializing and deserializing Rust types
4//! to/from the binary IPC protocol.
5
6use alloc::boxed::Box;
7use alloc::string::{String, ToString};
8use alloc::vec::Vec;
9use core::marker::PhantomData;
10
11use crate::Closure;
12use crate::WasmClosureFnOnce;
13use crate::batch::{Runtime, with_runtime};
14use crate::convert::RefFromBinaryDecode;
15use crate::ipc::{DecodeError, DecodedData, EncodedData};
16use crate::object_store::ObjectHandle;
17use crate::value::JsValue;
18
19/// Trait for encoding Rust values into the binary protocol.
20/// Each type specifies how to serialize itself.
21pub trait BinaryEncode<P = ()> {
22    fn encode(self, encoder: &mut EncodedData);
23}
24
25/// Trait for decoding values from the binary protocol.
26/// Each type specifies how to deserialize itself.
27pub trait BinaryDecode: Sized {
28    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError>;
29}
30
31/// Trait for converting a closure into a Closure wrapper.
32/// This trait is used instead of `From` to allow blanket implementations
33/// for all closure types without conflicting with other `From` impls.
34/// Output is a generic parameter (not associated type) to allow implementing
35/// the trait multiple times for the same type with different outputs.
36pub trait IntoClosure<M, Output> {
37    fn into_closure(self) -> Output;
38}
39
40/// Trait for return types that can be used in batched JS calls.
41/// Determines how the type behaves during batching.
42pub trait BatchableResult: BinaryDecode {
43    /// Returns Some(placeholder) for opaque types that can be batched,
44    /// None for types that require flushing to get the actual value.
45    ///
46    /// For opaque types (JsValue, Closure), this reserves a heap ID and returns a placeholder.
47    /// For trivial types like (), this returns the known value.
48    /// For value types (primitives, String, Vec, etc.), returns None to trigger a flush.
49    ///
50    /// Default implementation returns None (requires flush).
51    fn try_placeholder(_: &mut Runtime) -> Option<Self> {
52        None
53    }
54}
55
56/// Marker for cached type definition (type already sent, just reference by ID)
57/// Format: [TYPE_CACHED] [type_id: u32]
58pub(crate) const TYPE_CACHED: u8 = 0xFF;
59
60/// Marker for full type definition (first time sending this type signature)
61/// Format: [TYPE_FULL] [type_id: u32] [param_count: u8] [param TypeDefs...] [return TypeDef]
62pub(crate) const TYPE_FULL: u8 = 0xFE;
63
64/// Type tags for the binary type definition protocol.
65/// Used to encode type information that JavaScript can parse to create TypeClass instances.
66#[repr(u8)]
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum TypeTag {
69    // Primitive types
70    Null = 0,
71    Bool = 1,
72    U8 = 2,
73    U16 = 3,
74    U32 = 4,
75    U64 = 5,
76    U128 = 6,
77    I8 = 7,
78    I16 = 8,
79    I32 = 9,
80    I64 = 10,
81    I128 = 11,
82    F32 = 12,
83    F64 = 13,
84    Usize = 14,
85    Isize = 15,
86    String = 16,
87    HeapRef = 17,
88    // Compound types
89    /// Callback type: followed by param_count (u8), param TypeDefs..., return TypeDef
90    Callback = 18,
91    /// Option type: followed by inner TypeDef. Encodes as u8 flag (0=None, 1=Some) + value if Some
92    Option = 19,
93    /// Result type: followed by ok TypeDef and err TypeDef. Encodes as u8 flag (0=Err, 1=Ok) + value
94    Result = 20,
95    /// Array type: followed by element TypeDef. Encodes as u32 length + elements
96    Array = 21,
97    /// Borrowed reference: uses the borrow stack (indices 1-127) instead of the heap.
98    /// Automatically cleaned up after each operation completes.
99    BorrowedRef = 22,
100    /// Clamped u8 array type: represents Uint8ClampedArray in JS.
101    /// Element type is always u8. Encodes as u32 length + u8 elements.
102    U8Clamped = 23,
103    /// String enum type: encodes as u32 index, but type def includes variant strings.
104    /// Format: [StringEnum tag] [variant_count: u8] [for each: string_len: u32, string_bytes...]
105    /// Values encode as u32 discriminant. JS decodes using the lookup array.
106    StringEnum = 24,
107}
108
109/// Trait for types that can encode their type definition into the binary protocol.
110/// This is used to send type information to JavaScript for callback arguments.
111pub trait EncodeTypeDef {
112    /// Encode this type's definition into the buffer.
113    /// For primitives, this is just the TypeTag byte.
114    /// For callbacks, this includes param count, param types, and return type.
115    fn encode_type_def(buf: &mut Vec<u8>);
116}
117
118// Unit type implementations
119
120impl BatchableResult for () {
121    fn try_placeholder(_: &mut Runtime) -> Option<Self> {
122        Some(())
123    }
124}
125
126impl EncodeTypeDef for () {
127    fn encode_type_def(buf: &mut Vec<u8>) {
128        buf.push(TypeTag::Null as u8);
129    }
130}
131
132impl BinaryEncode for () {
133    fn encode(self, _encoder: &mut EncodedData) {
134        // Unit type encodes as nothing
135    }
136}
137
138impl BinaryDecode for () {
139    fn decode(_decoder: &mut DecodedData) -> Result<Self, DecodeError> {
140        Ok(())
141    }
142}
143
144impl EncodeTypeDef for bool {
145    fn encode_type_def(buf: &mut Vec<u8>) {
146        buf.push(TypeTag::Bool as u8);
147    }
148}
149
150impl BinaryEncode for bool {
151    fn encode(self, encoder: &mut EncodedData) {
152        encoder.push_u8(if self { 1 } else { 0 });
153    }
154}
155
156impl BinaryDecode for bool {
157    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
158        Ok(decoder.take_u8()? != 0)
159    }
160}
161
162impl EncodeTypeDef for u8 {
163    fn encode_type_def(buf: &mut Vec<u8>) {
164        buf.push(TypeTag::U8 as u8);
165    }
166}
167
168impl BinaryEncode for u8 {
169    fn encode(self, encoder: &mut EncodedData) {
170        encoder.push_u8(self);
171    }
172}
173
174impl BinaryDecode for u8 {
175    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
176        decoder.take_u8()
177    }
178}
179
180impl EncodeTypeDef for u16 {
181    fn encode_type_def(buf: &mut Vec<u8>) {
182        buf.push(TypeTag::U16 as u8);
183    }
184}
185
186impl BinaryEncode for u16 {
187    fn encode(self, encoder: &mut EncodedData) {
188        encoder.push_u16(self);
189    }
190}
191
192impl BinaryDecode for u16 {
193    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
194        decoder.take_u16()
195    }
196}
197
198impl EncodeTypeDef for u32 {
199    fn encode_type_def(buf: &mut Vec<u8>) {
200        buf.push(TypeTag::U32 as u8);
201    }
202}
203
204impl BinaryEncode for u32 {
205    fn encode(self, encoder: &mut EncodedData) {
206        encoder.push_u32(self);
207    }
208}
209
210impl BinaryDecode for u32 {
211    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
212        decoder.take_u32()
213    }
214}
215
216impl EncodeTypeDef for u64 {
217    fn encode_type_def(buf: &mut Vec<u8>) {
218        buf.push(TypeTag::U64 as u8);
219    }
220}
221
222impl BinaryEncode for u64 {
223    fn encode(self, encoder: &mut EncodedData) {
224        encoder.push_u64(self);
225    }
226}
227
228impl BinaryDecode for u64 {
229    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
230        decoder.take_u64()
231    }
232}
233
234impl EncodeTypeDef for u128 {
235    fn encode_type_def(buf: &mut Vec<u8>) {
236        buf.push(TypeTag::U128 as u8);
237    }
238}
239
240impl BinaryEncode for u128 {
241    fn encode(self, encoder: &mut EncodedData) {
242        encoder.push_u128(self);
243    }
244}
245
246impl BinaryDecode for u128 {
247    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
248        decoder.take_u128()
249    }
250}
251
252impl EncodeTypeDef for i8 {
253    fn encode_type_def(buf: &mut Vec<u8>) {
254        buf.push(TypeTag::I8 as u8);
255    }
256}
257
258impl BinaryEncode for i8 {
259    fn encode(self, encoder: &mut EncodedData) {
260        encoder.push_u8(self as u8);
261    }
262}
263
264impl BinaryDecode for i8 {
265    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
266        Ok(decoder.take_u8()? as i8)
267    }
268}
269
270impl EncodeTypeDef for i16 {
271    fn encode_type_def(buf: &mut Vec<u8>) {
272        buf.push(TypeTag::I16 as u8);
273    }
274}
275
276impl BinaryEncode for i16 {
277    fn encode(self, encoder: &mut EncodedData) {
278        encoder.push_u16(self as u16);
279    }
280}
281
282impl BinaryDecode for i16 {
283    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
284        Ok(decoder.take_u16()? as i16)
285    }
286}
287
288impl EncodeTypeDef for i32 {
289    fn encode_type_def(buf: &mut Vec<u8>) {
290        buf.push(TypeTag::I32 as u8);
291    }
292}
293
294impl BinaryEncode for i32 {
295    fn encode(self, encoder: &mut EncodedData) {
296        encoder.push_u32(self as u32);
297    }
298}
299
300impl BinaryDecode for i32 {
301    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
302        Ok(decoder.take_u32()? as i32)
303    }
304}
305
306impl EncodeTypeDef for i64 {
307    fn encode_type_def(buf: &mut Vec<u8>) {
308        buf.push(TypeTag::I64 as u8);
309    }
310}
311
312impl BinaryEncode for i64 {
313    fn encode(self, encoder: &mut EncodedData) {
314        encoder.push_u64(self as u64);
315    }
316}
317
318impl BinaryDecode for i64 {
319    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
320        Ok(decoder.take_u64()? as i64)
321    }
322}
323
324impl EncodeTypeDef for i128 {
325    fn encode_type_def(buf: &mut Vec<u8>) {
326        buf.push(TypeTag::I128 as u8);
327    }
328}
329
330impl BinaryEncode for i128 {
331    fn encode(self, encoder: &mut EncodedData) {
332        encoder.push_u128(self as u128);
333    }
334}
335
336impl BinaryDecode for i128 {
337    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
338        Ok(decoder.take_u128()? as i128)
339    }
340}
341
342impl EncodeTypeDef for f32 {
343    fn encode_type_def(buf: &mut Vec<u8>) {
344        buf.push(TypeTag::F32 as u8);
345    }
346}
347
348impl BinaryEncode for f32 {
349    fn encode(self, encoder: &mut EncodedData) {
350        encoder.push_u32(self.to_bits());
351    }
352}
353
354impl BinaryDecode for f32 {
355    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
356        Ok(f32::from_bits(decoder.take_u32()?))
357    }
358}
359
360impl EncodeTypeDef for f64 {
361    fn encode_type_def(buf: &mut Vec<u8>) {
362        buf.push(TypeTag::F64 as u8);
363    }
364}
365
366impl BinaryEncode for f64 {
367    fn encode(self, encoder: &mut EncodedData) {
368        encoder.push_u64(self.to_bits());
369    }
370}
371
372impl BinaryDecode for f64 {
373    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
374        Ok(f64::from_bits(decoder.take_u64()?))
375    }
376}
377
378// usize implementations (uses u64 for portability)
379
380impl EncodeTypeDef for usize {
381    fn encode_type_def(buf: &mut Vec<u8>) {
382        buf.push(TypeTag::Usize as u8);
383    }
384}
385
386impl BinaryEncode for usize {
387    fn encode(self, encoder: &mut EncodedData) {
388        encoder.push_u64(self as u64);
389    }
390}
391
392impl BinaryDecode for usize {
393    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
394        Ok(decoder.take_u64()? as usize)
395    }
396}
397
398// isize implementations (uses i64 for portability)
399
400impl EncodeTypeDef for isize {
401    fn encode_type_def(buf: &mut Vec<u8>) {
402        buf.push(TypeTag::Isize as u8);
403    }
404}
405
406impl BinaryEncode for isize {
407    fn encode(self, encoder: &mut EncodedData) {
408        encoder.push_u64(self as u64);
409    }
410}
411
412impl BinaryDecode for isize {
413    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
414        Ok(decoder.take_u64()? as isize)
415    }
416}
417
418// String/str implementations
419
420impl EncodeTypeDef for str {
421    fn encode_type_def(buf: &mut Vec<u8>) {
422        buf.push(TypeTag::String as u8);
423    }
424}
425
426// Explicit impl for &str since str is not Sized and blanket impl doesn't apply
427impl EncodeTypeDef for &str {
428    fn encode_type_def(buf: &mut Vec<u8>) {
429        <str as EncodeTypeDef>::encode_type_def(buf);
430    }
431}
432
433// Blanket impl for &T references
434impl<T: EncodeTypeDef> EncodeTypeDef for &T {
435    fn encode_type_def(buf: &mut Vec<u8>) {
436        T::encode_type_def(buf);
437    }
438}
439
440impl BinaryEncode for &str {
441    fn encode(self, encoder: &mut EncodedData) {
442        encoder.push_str(self);
443    }
444}
445
446impl EncodeTypeDef for String {
447    fn encode_type_def(buf: &mut Vec<u8>) {
448        buf.push(TypeTag::String as u8);
449    }
450}
451
452impl BinaryEncode for String {
453    fn encode(self, encoder: &mut EncodedData) {
454        encoder.push_str(&self);
455    }
456}
457
458impl BinaryDecode for String {
459    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
460        Ok(decoder.take_str()?.to_string())
461    }
462}
463
464impl<T: EncodeTypeDef> EncodeTypeDef for Option<T> {
465    fn encode_type_def(buf: &mut Vec<u8>) {
466        // Option encodes as: [Option tag] [inner type]
467        // Actual values encode as: [u8 flag (0=None, 1=Some)] [value if Some]
468        buf.push(TypeTag::Option as u8);
469        T::encode_type_def(buf);
470    }
471}
472
473impl<T: BinaryDecode> BinaryDecode for Option<T> {
474    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
475        let has_value = decoder.take_u8()? != 0;
476        if has_value {
477            Ok(Some(T::decode(decoder)?))
478        } else {
479            Ok(None)
480        }
481    }
482}
483
484// Encoding for Option<T> where T is encodable
485impl<T: BinaryEncode<P>, P> BinaryEncode<P> for Option<T> {
486    fn encode(self, encoder: &mut EncodedData) {
487        match self {
488            Some(val) => {
489                encoder.push_u8(1);
490                val.encode(encoder);
491            }
492            None => {
493                encoder.push_u8(0);
494            }
495        }
496    }
497}
498
499impl<T: BinaryDecode> BatchableResult for Option<T> {}
500
501impl<T: EncodeTypeDef, E: EncodeTypeDef> EncodeTypeDef for Result<T, E> {
502    fn encode_type_def(buf: &mut Vec<u8>) {
503        // Result encodes as: [Result tag] [ok type] [err type]
504        buf.push(TypeTag::Result as u8);
505        T::encode_type_def(buf);
506        E::encode_type_def(buf);
507    }
508}
509
510impl<T: BinaryDecode, E: BinaryDecode> BinaryDecode for Result<T, E> {
511    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
512        let is_ok = decoder.take_u8()? != 0;
513        if is_ok {
514            Ok(Ok(T::decode(decoder)?))
515        } else {
516            Ok(Err(E::decode(decoder)?))
517        }
518    }
519}
520
521impl<T: BinaryDecode, E: BinaryDecode> BatchableResult for Result<T, E> {}
522
523impl EncodeTypeDef for JsValue {
524    fn encode_type_def(buf: &mut Vec<u8>) {
525        buf.push(TypeTag::HeapRef as u8);
526    }
527}
528
529impl BinaryEncode for JsValue {
530    fn encode(self, encoder: &mut EncodedData) {
531        encoder.push_u64(self.id());
532    }
533}
534
535impl BinaryDecode for JsValue {
536    fn decode(_: &mut DecodedData) -> Result<Self, DecodeError> {
537        // JS value is always in sync with the dom. We should never need to decode it.
538        // Use get_next_heap_id() (NOT get_next_placeholder_id()) because decode() is
539        // called for callback parameters from JS, not for return value placeholders.
540        with_runtime(|runtime| Ok(JsValue::from_id(runtime.get_next_heap_id())))
541    }
542}
543
544impl BatchableResult for JsValue {
545    fn try_placeholder(batch: &mut Runtime) -> Option<Self> {
546        // Use get_next_placeholder_id() to track reserved slots for JS
547        Some(JsValue::from_id(batch.get_next_placeholder_id()))
548    }
549}
550
551impl<F: ?Sized> BatchableResult for Closure<F> {
552    fn try_placeholder(batch: &mut Runtime) -> Option<Self> {
553        Some(Closure {
554            _phantom: PhantomData,
555            value: JsValue::try_placeholder(batch)?,
556        })
557    }
558}
559
560/// Implement BatchableResult for value types that always need a flush to get the result.
561macro_rules! impl_value_type {
562    ($($ty:ty),*) => {
563        $(impl BatchableResult for $ty {})*
564    };
565}
566
567impl_value_type!(
568    bool, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, isize, usize, f32, f64, String
569);
570
571/// Marker trait for types that can be cheaply cloned for encoding.
572pub trait CloneForEncode: Clone {}
573
574impl CloneForEncode for bool {}
575impl CloneForEncode for u8 {}
576impl CloneForEncode for u16 {}
577impl CloneForEncode for u32 {}
578impl CloneForEncode for u64 {}
579impl CloneForEncode for i8 {}
580impl CloneForEncode for i16 {}
581impl CloneForEncode for i32 {}
582impl CloneForEncode for i64 {}
583impl CloneForEncode for f32 {}
584impl CloneForEncode for f64 {}
585impl CloneForEncode for usize {}
586impl CloneForEncode for isize {}
587impl CloneForEncode for String {}
588
589// Blanket implementation for references to types that implement CloneForEncode
590// Note: We only implement for P=() to avoid conflicts with RustCallbackMarker impls
591impl<T: BinaryEncode + CloneForEncode> BinaryEncode for &T {
592    fn encode(self, encoder: &mut EncodedData) {
593        self.clone().encode(encoder);
594    }
595}
596
597// When encoding JsValue references, encode the underlying ID
598impl BinaryEncode for &JsValue {
599    fn encode(self, encoder: &mut EncodedData) {
600        encoder.push_u64(self.id());
601    }
602}
603
604/// Wrapper type that encodes a callback registration key with Callback type info.
605/// This tells JS to create a RustFunction wrapper when decoding the value.
606/// The type parameter F should be `dyn FnMut(...) -> R` to capture the callback signature.
607pub struct CallbackKey<F: ?Sized>(ObjectHandle, PhantomData<F>);
608
609impl<F: ?Sized> CallbackKey<F> {
610    /// Create a new CallbackKey from an ObjectHandle.
611    pub(crate) fn new(handle: ObjectHandle) -> Self {
612        CallbackKey(handle, PhantomData)
613    }
614}
615
616impl<F: ?Sized> BinaryEncode for CallbackKey<F> {
617    fn encode(self, encoder: &mut EncodedData) {
618        self.0.encode(encoder);
619    }
620}
621
622// Blanket impl: All Closures encode as HeapRef since they're JS heap references
623impl<T: ?Sized> EncodeTypeDef for crate::Closure<T> {
624    fn encode_type_def(buf: &mut Vec<u8>) {
625        JsValue::encode_type_def(buf);
626    }
627}
628
629/// Helper macro to decode callback arguments and execute a body.
630///
631/// Usage: decode_args!(decoder; [type1, type2, ...] => body)
632/// The body can use the type names as variables containing the decoded arguments.
633macro_rules! decode_args {
634    // Main entry: decode each arg and call body
635    ($decoder:expr; [$first:ident, $($ty:ident,)*] => $body:expr) => {{
636        #[allow(non_snake_case)]
637        let $first = <$first as BinaryDecode>::decode($decoder).unwrap();
638        decode_args!($decoder; [$($ty,)*] => $body);
639    }};
640    // Nothing to decode, just execute body
641    ($decoder:expr; [] => $body:expr) => {{
642        $body
643    }};
644}
645
646macro_rules! impl_fnmut_stub {
647    ($($arg:ident),*) => {
648        // Implement EncodeTypeDef for fn(owned*) -> R
649        impl<R, $($arg,)*> EncodeTypeDef for CallbackKey<fn($($arg),*) -> R>
650            where
651            $($arg: EncodeTypeDef + 'static, )*
652            R: EncodeTypeDef + 'static,
653        {
654            #[allow(unused)]
655            fn encode_type_def(buf: &mut Vec<u8>) {
656                buf.push(TypeTag::Callback as u8);
657                // Encode arg count
658                let mut count: u8 = 0;
659                $(
660                    let _ = PhantomData::<$arg>;
661                    count += 1;
662                )*
663                buf.push(count);
664                // Encode each argument type
665                $(<$arg as EncodeTypeDef>::encode_type_def(buf);)*
666                // Encode return type
667                <R as EncodeTypeDef>::encode_type_def(buf);
668            }
669        }
670
671        // Implement WasmClosure trait for dyn FnMut variants
672        impl<R, $($arg,)*> crate::WasmClosure<fn($($arg),*) -> R> for dyn FnMut($($arg),*) -> R
673            where
674            $($arg: BinaryDecode + EncodeTypeDef + 'static, )*
675            R: BinaryEncode + EncodeTypeDef + 'static,
676        {
677            #[allow(non_snake_case)]
678            #[allow(unused)]
679            fn into_js_closure(mut boxed: Box<Self>) -> crate::Closure<Self> {
680                crate::Closure::wrap_encode_decode_mut::<fn($($arg),*) -> R>(
681                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
682                        // Decode arguments and call the closure
683                        decode_args!(decoder; [$($arg,)*] => {
684                            let result = boxed($($arg),*);
685                            result.encode(encoder);
686                        });
687                    },
688                )
689            }
690        }
691
692        // Implement WasmClosure trait for dyn Fn variants (immutable closures)
693        // These CAN be called reentrantly since Fn only needs &self
694        impl<R, $($arg,)*> crate::WasmClosure<fn($($arg),*) -> R> for dyn Fn($($arg),*) -> R
695            where
696            $($arg: BinaryDecode + EncodeTypeDef + 'static, )*
697            R: BinaryEncode + EncodeTypeDef + 'static,
698        {
699            #[allow(non_snake_case)]
700            #[allow(unused)]
701            fn into_js_closure(boxed: Box<Self>) -> crate::Closure<Self> {
702                crate::Closure::wrap_encode_decode::<fn($($arg),*) -> R>(
703                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
704                        // Decode arguments and call the closure
705                        decode_args!(decoder; [$($arg,)*] => {
706                            let result = boxed($($arg),*);
707                            result.encode(encoder);
708                        });
709                    }
710                )
711            }
712        }
713
714        // IntoClosure for F: FnMut -> Closure<dyn FnMut>
715        impl<R, F, $($arg,)*> IntoClosure<fn($($arg),*) -> R, crate::Closure<dyn FnMut($($arg),*) -> R>> for F
716            where F: FnMut($($arg),*) -> R + 'static,
717            $($arg: BinaryDecode + EncodeTypeDef + 'static, )*
718            R: BinaryEncode + EncodeTypeDef + 'static,
719        {
720            #[allow(non_snake_case)]
721            #[allow(unused)]
722            fn into_closure(mut self) -> crate::Closure<dyn FnMut($($arg),*) -> R> {
723                crate::Closure::wrap_encode_decode_mut::<fn($($arg),*) -> R>(
724                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
725                        // Decode arguments and call the closure
726                        decode_args!(decoder; [$($arg,)*] => {
727                            let result = self($($arg),*);
728                            result.encode(encoder);
729                        });
730                    },
731                )
732            }
733        }
734
735        // IntoClosure for F: Fn -> Closure<dyn Fn>
736        impl<R, F, $($arg,)*> IntoClosure<fn($($arg),*) -> R, crate::Closure<dyn Fn($($arg),*) -> R>> for F
737            where F: Fn($($arg),*) -> R + 'static,
738            $($arg: BinaryDecode + EncodeTypeDef + 'static, )*
739            R: BinaryEncode + EncodeTypeDef + 'static,
740        {
741            #[allow(non_snake_case)]
742            #[allow(unused)]
743            fn into_closure(self) -> crate::Closure<dyn Fn($($arg),*) -> R> {
744                crate::Closure::wrap_encode_decode::<fn($($arg),*) -> R>(
745                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
746                        // Decode arguments and call the closure
747                        decode_args!(decoder; [$($arg,)*] => {
748                            let result = self($($arg),*);
749                            result.encode(encoder);
750                        });
751                    },
752                )
753            }
754        }
755
756    };
757}
758
759/// Macro to implement EncodeTypeDef and BinaryEncode for closure reference types.
760/// These are used by js-sys bindings like `&mut dyn FnMut(JsValue, u32, Array) -> bool`.
761/// Unlike the WasmClosure impls above, these use simple BinaryDecode arguments without markers.
762macro_rules! impl_closure_ref_encode {
763    ($($arg:ident),*) => {
764        // Implement EncodeTypeDef for &mut dyn FnMut(...) -> R
765        impl<R, $($arg,)*> EncodeTypeDef for &mut dyn FnMut($($arg),*) -> R
766            where
767            $($arg: EncodeTypeDef + 'static, )*
768            R: EncodeTypeDef + 'static,
769        {
770            #[allow(unused)]
771            fn encode_type_def(buf: &mut Vec<u8>) {
772                buf.push(TypeTag::Callback as u8);
773                // Encode arg count
774                let mut count: u8 = 0;
775                $(
776                    let _ = PhantomData::<$arg>;
777                    count += 1;
778                )*
779                buf.push(count);
780                // Encode each argument type
781                $(<$arg as EncodeTypeDef>::encode_type_def(buf);)*
782                // Encode return type
783                <R as EncodeTypeDef>::encode_type_def(buf);
784            }
785        }
786
787        // Implement BinaryEncode for &mut dyn FnMut(...) -> R
788        impl<R, $($arg,)*> BinaryEncode for &mut dyn FnMut($($arg),*) -> R
789            where
790            $($arg: BinaryDecode + EncodeTypeDef + 'static, )*
791            R: BinaryEncode + EncodeTypeDef + 'static,
792        {
793            #[allow(non_snake_case)]
794            #[allow(unused)]
795            fn encode(self, encoder: &mut EncodedData) {
796                // Mark that this batch needs to be flushed synchronously.
797                // Stack-allocated callbacks must be invoked before this function returns,
798                // otherwise the pointer becomes invalid when the closure goes out of scope.
799                encoder.mark_needs_flush();
800
801                // Decompose fat pointer to (data_ptr, vtable_ptr) to erase the lifetime.
802                // SAFETY: The closure reference must remain valid for the duration of the JS call.
803                // This is safe because JS callbacks are invoked synchronously during the call.
804                let ptr = self as *mut dyn FnMut($($arg),*) -> R;
805                let (data_ptr, vtable_ptr): (usize, usize) = unsafe { core::mem::transmute(ptr) };
806
807                // Register the callback directly (without wbg_cast which would make a nested JS call)
808                let callback = crate::function::RustCallback::new_fn_mut(
809                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
810                        // SAFETY: The pointer is valid for the duration of the JS call.
811                        // Reconstruct the fat pointer from the stored components.
812                        let ptr: *mut dyn FnMut($($arg),*) -> R = unsafe {
813                            core::mem::transmute((data_ptr, vtable_ptr))
814                        };
815                        let f: &mut dyn FnMut($($arg),*) -> R = unsafe { &mut *ptr };
816                        // Decode arguments and call the closure
817                        $(let $arg = <$arg as BinaryDecode>::decode(decoder).unwrap();)*
818                        let result = f($($arg),*);
819                        result.encode(encoder);
820                    },
821                );
822                let key: CallbackKey<fn($($arg),*) -> R> = CallbackKey::new(crate::object_store::insert_object(callback));
823                key.encode(encoder);
824            }
825        }
826
827        // Implement EncodeTypeDef for &dyn Fn(...) -> R
828        impl<R, $($arg,)*> EncodeTypeDef for &dyn Fn($($arg),*) -> R
829            where
830            $($arg: EncodeTypeDef + 'static, )*
831            R: EncodeTypeDef + 'static,
832        {
833            #[allow(unused)]
834            fn encode_type_def(buf: &mut Vec<u8>) {
835                buf.push(TypeTag::Callback as u8);
836                // Encode arg count
837                let mut count: u8 = 0;
838                $(
839                    let _ = PhantomData::<$arg>;
840                    count += 1;
841                )*
842                buf.push(count);
843                // Encode each argument type
844                $(<$arg as EncodeTypeDef>::encode_type_def(buf);)*
845                // Encode return type
846                <R as EncodeTypeDef>::encode_type_def(buf);
847            }
848        }
849
850        // Implement BinaryEncode for &dyn Fn(...) -> R (supports reentrant calls)
851        impl<R, $($arg,)*> BinaryEncode for &dyn Fn($($arg),*) -> R
852            where
853            $($arg: BinaryDecode + EncodeTypeDef + 'static, )*
854            R: BinaryEncode + EncodeTypeDef + 'static,
855        {
856            #[allow(non_snake_case)]
857            #[allow(unused)]
858            fn encode(self, encoder: &mut EncodedData) {
859                // Mark that this batch needs to be flushed synchronously.
860                // Stack-allocated callbacks must be invoked before this function returns,
861                // otherwise the pointer becomes invalid when the closure goes out of scope.
862                encoder.mark_needs_flush();
863
864                // Decompose fat pointer to (data_ptr, vtable_ptr) to erase the lifetime.
865                // SAFETY: The closure reference must remain valid for the duration of the JS call.
866                // This is safe because JS callbacks are invoked synchronously during the call.
867                let ptr = self as *const dyn Fn($($arg),*) -> R;
868                let (data_ptr, vtable_ptr): (usize, usize) = unsafe { core::mem::transmute(ptr) };
869
870                // Register the callback directly (without wbg_cast which would make a nested JS call)
871                let callback = crate::function::RustCallback::new_fn(
872                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
873                        // SAFETY: The pointer is valid for the duration of the JS call.
874                        // Reconstruct the fat pointer from the stored components.
875                        let ptr: *const dyn Fn($($arg),*) -> R = unsafe {
876                            core::mem::transmute((data_ptr, vtable_ptr))
877                        };
878                        let f: &dyn Fn($($arg),*) -> R = unsafe { &*ptr };
879                        // Decode arguments and call the closure
880                        $(let $arg = <$arg as BinaryDecode>::decode(decoder).unwrap();)*
881                        let result = f($($arg),*);
882                        result.encode(encoder);
883                    },
884                );
885                let key: CallbackKey<fn($($arg),*) -> R> = CallbackKey::new(crate::object_store::insert_object(callback));
886                key.encode(encoder);
887            }
888        }
889
890        // Implement EncodeTypeDef for &mut dyn Fn(...) -> R
891        impl<R, $($arg,)*> EncodeTypeDef for &mut dyn Fn($($arg),*) -> R
892            where
893            $($arg: EncodeTypeDef + 'static, )*
894            R: EncodeTypeDef + 'static,
895        {
896            #[allow(unused)]
897            fn encode_type_def(buf: &mut Vec<u8>) {
898                buf.push(TypeTag::Callback as u8);
899                // Encode arg count
900                let mut count: u8 = 0;
901                $(
902                    let _ = PhantomData::<$arg>;
903                    count += 1;
904                )*
905                buf.push(count);
906                // Encode each argument type
907                $(<$arg as EncodeTypeDef>::encode_type_def(buf);)*
908                // Encode return type
909                <R as EncodeTypeDef>::encode_type_def(buf);
910            }
911        }
912
913        // Implement BinaryEncode for &mut dyn Fn(...) -> R (supports reentrant calls)
914        impl<R, $($arg,)*> BinaryEncode for &mut dyn Fn($($arg),*) -> R
915            where
916            $($arg: BinaryDecode + EncodeTypeDef + 'static, )*
917            R: BinaryEncode + EncodeTypeDef + 'static,
918        {
919            #[allow(non_snake_case)]
920            #[allow(unused)]
921            fn encode(self, encoder: &mut EncodedData) {
922                // Mark that this batch needs to be flushed synchronously.
923                // Stack-allocated callbacks must be invoked before this function returns,
924                // otherwise the pointer becomes invalid when the closure goes out of scope.
925                encoder.mark_needs_flush();
926
927                // Decompose fat pointer to (data_ptr, vtable_ptr) to erase the lifetime.
928                // SAFETY: The closure reference must remain valid for the duration of the JS call.
929                // This is safe because JS callbacks are invoked synchronously during the call.
930                // We use *const because Fn only requires & to call
931                let ptr = self as *const dyn Fn($($arg),*) -> R;
932                let (data_ptr, vtable_ptr): (usize, usize) = unsafe { core::mem::transmute(ptr) };
933
934                // Register the callback directly (without wbg_cast which would make a nested JS call)
935                let callback = crate::function::RustCallback::new_fn(
936                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
937                        // SAFETY: The pointer is valid for the duration of the JS call.
938                        // Reconstruct the fat pointer from the stored components.
939                        let ptr: *const dyn Fn($($arg),*) -> R = unsafe {
940                            core::mem::transmute((data_ptr, vtable_ptr))
941                        };
942                        let f: &dyn Fn($($arg),*) -> R = unsafe { &*ptr };
943                        // Decode arguments and call the closure
944                        $(let $arg = <$arg as BinaryDecode>::decode(decoder).unwrap();)*
945                        let result = f($($arg),*);
946                        result.encode(encoder);
947                    },
948                );
949                let key: CallbackKey<fn($($arg),*) -> R> = CallbackKey::new(crate::object_store::insert_object(callback));
950                key.encode(encoder);
951            }
952        }
953    };
954}
955
956impl_closure_ref_encode!();
957impl_closure_ref_encode!(A1);
958impl_closure_ref_encode!(A1, A2);
959impl_closure_ref_encode!(A1, A2, A3);
960impl_closure_ref_encode!(A1, A2, A3, A4);
961impl_closure_ref_encode!(A1, A2, A3, A4, A5);
962impl_closure_ref_encode!(A1, A2, A3, A4, A5, A6);
963impl_closure_ref_encode!(A1, A2, A3, A4, A5, A6, A7);
964
965impl_fnmut_stub!();
966impl_fnmut_stub!(A1);
967impl_fnmut_stub!(A1, A2);
968impl_fnmut_stub!(A1, A2, A3);
969impl_fnmut_stub!(A1, A2, A3, A4);
970impl_fnmut_stub!(A1, A2, A3, A4, A5);
971impl_fnmut_stub!(A1, A2, A3, A4, A5, A6);
972impl_fnmut_stub!(A1, A2, A3, A4, A5, A6, A7);
973
974/// Marker type for closures that borrow the first argument.
975pub struct BorrowedFirstArg;
976
977/// Macro to implement WasmClosure and IntoClosure for closures that borrow the first argument.
978/// This uses RefFromBinaryDecode for the first arg and BinaryDecode for the rest.
979macro_rules! impl_fnmut_stub_ref {
980    ($first:ident $(, $rest:ident)*) => {
981        // Implement EncodeTypeDef for fn(borrowed, owned*) -> R
982        #[allow(coherence_leak_check)]
983        impl<R, $first, $($rest,)*> EncodeTypeDef for CallbackKey<fn(&$first, $($rest),*) -> R>
984            where
985            $first: EncodeTypeDef + 'static,
986            $($rest: EncodeTypeDef + 'static, )*
987            R: EncodeTypeDef + 'static,
988        {
989            #[allow(unused)]
990            fn encode_type_def(buf: &mut Vec<u8>) {
991                buf.push(TypeTag::Callback as u8);
992                // Encode arg count
993                let mut count: u8 = 1;
994                $(
995                    let _ = PhantomData::<$rest>;
996                    count += 1;
997                )*
998                buf.push(count);
999                // Encode each argument type
1000                buf.push(TypeTag::BorrowedRef as u8);
1001                $(<$rest as EncodeTypeDef>::encode_type_def(buf);)*
1002                // Encode return type
1003                <R as EncodeTypeDef>::encode_type_def(buf);
1004            }
1005        }
1006
1007        // WasmClosure for dyn FnMut(&First, ...) -> R
1008        impl<R, $first, $($rest,)*> crate::WasmClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R)> for dyn FnMut(&$first, $($rest),*) -> R
1009            where
1010            $first: RefFromBinaryDecode + EncodeTypeDef + 'static,
1011            $($rest: BinaryDecode + EncodeTypeDef + 'static,)*
1012            R: BinaryEncode + EncodeTypeDef + 'static,
1013        {
1014            #[allow(non_snake_case)]
1015            #[allow(unused)]
1016            fn into_js_closure(mut boxed: Box<Self>) -> crate::Closure<Self> {
1017                crate::Closure::wrap_encode_decode_mut::<fn(&$first, $($rest),*) -> R>(
1018                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
1019                        let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder).unwrap();
1020                        $(let $rest = <$rest as BinaryDecode>::decode(decoder).unwrap();)*
1021                        let result = boxed(&*anchor, $($rest),*);
1022                        result.encode(encoder);
1023                    },
1024                )
1025            }
1026        }
1027
1028        // WasmClosure for dyn Fn(&First, ...) -> R (supports reentrant calls)
1029        impl<R, $first, $($rest,)*> crate::WasmClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R)> for dyn Fn(&$first, $($rest),*) -> R
1030            where
1031            $first: RefFromBinaryDecode + EncodeTypeDef + 'static,
1032            $($rest: BinaryDecode + EncodeTypeDef + 'static,)*
1033            R: BinaryEncode + EncodeTypeDef + 'static,
1034        {
1035            #[allow(non_snake_case)]
1036            #[allow(unused)]
1037            fn into_js_closure(boxed: Box<Self>) -> crate::Closure<Self> {
1038                crate::Closure::wrap_encode_decode::<fn(&$first, $($rest),*) -> R>(
1039                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
1040                        let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder).unwrap();
1041                        $(let $rest = <$rest as BinaryDecode>::decode(decoder).unwrap();)*
1042                        let result = boxed(&*anchor, $($rest),*);
1043                        result.encode(encoder);
1044                    },
1045                )
1046            }
1047        }
1048
1049        // IntoClosure for F: FnMut(&First, ...) -> R -> Closure<dyn FnMut(&First, ...) -> R>
1050        impl<R, F, $first, $($rest,)*> IntoClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R), crate::Closure<dyn FnMut(&$first, $($rest),*) -> R>> for F
1051            where F: FnMut(&$first, $($rest),*) -> R + 'static,
1052            $first: RefFromBinaryDecode + EncodeTypeDef + 'static,
1053            $($rest: BinaryDecode + EncodeTypeDef + 'static,)*
1054            R: BinaryEncode + EncodeTypeDef + 'static,
1055        {
1056            #[allow(non_snake_case)]
1057            #[allow(unused)]
1058            fn into_closure(mut self) -> crate::Closure<dyn FnMut(&$first, $($rest),*) -> R> {
1059                crate::Closure::wrap_encode_decode_mut::<fn(&$first, $($rest),*) -> R>(
1060                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
1061                        let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder).unwrap();
1062                        $(let $rest = <$rest as BinaryDecode>::decode(decoder).unwrap();)*
1063                        let result = self(&*anchor, $($rest),*);
1064                        result.encode(encoder);
1065                    },
1066                )
1067            }
1068        }
1069
1070        // IntoClosure for F: Fn(&First, ...) -> R -> Closure<dyn Fn(&First, ...) -> R>
1071        impl<R, F, $first, $($rest,)*> IntoClosure<(BorrowedFirstArg, fn(&$first, $($rest),*) -> R), crate::Closure<dyn Fn(&$first, $($rest),*) -> R>> for F
1072            where F: Fn(&$first, $($rest),*) -> R + 'static,
1073            $first: RefFromBinaryDecode + EncodeTypeDef + 'static,
1074            $($rest: BinaryDecode + EncodeTypeDef + 'static,)*
1075            R: BinaryEncode + EncodeTypeDef + 'static,
1076        {
1077            #[allow(non_snake_case)]
1078            #[allow(unused)]
1079            fn into_closure(self) -> crate::Closure<dyn Fn(&$first, $($rest),*) -> R> {
1080                crate::Closure::wrap_encode_decode::<fn($first, $($rest),*) -> R>(
1081                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
1082                        let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder).unwrap();
1083                        $(let $rest = <$rest as BinaryDecode>::decode(decoder).unwrap();)*
1084                        let result = self(&*anchor, $($rest),*);
1085                        result.encode(encoder);
1086                    },
1087                )
1088            }
1089        }
1090    };
1091}
1092
1093impl_fnmut_stub_ref!(A1);
1094impl_fnmut_stub_ref!(A1, A2);
1095impl_fnmut_stub_ref!(A1, A2, A3);
1096impl_fnmut_stub_ref!(A1, A2, A3, A4);
1097impl_fnmut_stub_ref!(A1, A2, A3, A4, A5);
1098impl_fnmut_stub_ref!(A1, A2, A3, A4, A5, A6);
1099impl_fnmut_stub_ref!(A1, A2, A3, A4, A5, A6, A7);
1100
1101/// Macro to implement WasmClosureFnOnce for FnOnce closures of various arities.
1102/// This wraps an FnOnce in an FnMut that panics if called more than once.
1103macro_rules! impl_fn_once {
1104    ($($arg:ident),*) => {
1105        impl<R, F, $($arg,)*> WasmClosureFnOnce<dyn FnMut($($arg),*) -> R, fn($($arg),*) -> R> for F
1106        where
1107            F: FnOnce($($arg),*) -> R + 'static,
1108            $($arg: BinaryDecode + EncodeTypeDef + 'static,)*
1109            R: BinaryEncode + EncodeTypeDef + 'static,
1110        {
1111            #[allow(non_snake_case)]
1112            #[allow(unused_variables)]
1113            fn into_closure(self) -> Closure<dyn FnMut($($arg),*) -> R> {
1114                // Use Option to allow taking the FnOnce
1115                let mut me = Some(self);
1116                // Register the callback using the same pattern as impl_fnmut_stub
1117                crate::Closure::wrap_encode_decode_mut::<fn($($arg),*) -> R>(
1118                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
1119                        let f = me.take().expect("FnOnce closure called more than once");
1120                        decode_args!(decoder; [$($arg,)*] => {
1121                            let result = f($($arg),*);
1122                            result.encode(encoder);
1123                        });
1124                    },
1125                )
1126            }
1127        }
1128    };
1129}
1130
1131impl_fn_once!();
1132impl_fn_once!(A1);
1133impl_fn_once!(A1, A2);
1134impl_fn_once!(A1, A2, A3);
1135impl_fn_once!(A1, A2, A3, A4);
1136impl_fn_once!(A1, A2, A3, A4, A5);
1137impl_fn_once!(A1, A2, A3, A4, A5, A6);
1138impl_fn_once!(A1, A2, A3, A4, A5, A6, A7);
1139
1140/// Macro to implement WasmClosureFnOnce for FnOnce closures that borrow the first argument.
1141/// This uses RefFromBinaryDecode for the first arg and BinaryDecode for the rest.
1142macro_rules! impl_fn_once_ref {
1143    ($first:ident $(, $rest:ident)*) => {
1144        impl<R, F, $first, $($rest,)*> WasmClosureFnOnce<dyn FnMut(&$first, $($rest),*) -> R, (BorrowedFirstArg, fn(&$first, $($rest),*) -> R)> for F
1145        where
1146            F: FnOnce(&$first, $($rest),*) -> R + 'static,
1147            $first: RefFromBinaryDecode + EncodeTypeDef + 'static,
1148            $($rest: BinaryDecode + EncodeTypeDef + 'static,)*
1149            R: BinaryEncode + EncodeTypeDef + 'static,
1150        {
1151            #[allow(non_snake_case)]
1152            #[allow(unused_variables)]
1153            fn into_closure(self) -> Closure<dyn FnMut(&$first, $($rest),*) -> R> {
1154                let mut me = Some(self);
1155                crate::Closure::wrap_encode_decode_mut::<fn(&$first, $($rest),*) -> R>(
1156                    move |decoder: &mut DecodedData, encoder: &mut EncodedData| {
1157                        let f = me.take().expect("FnOnce closure called more than once");
1158                        let anchor = <$first as RefFromBinaryDecode>::ref_decode(decoder).unwrap();
1159                        $(let $rest = <$rest as BinaryDecode>::decode(decoder).unwrap();)*
1160                        let result = f(&*anchor, $($rest),*);
1161                        result.encode(encoder);
1162                    },
1163                )
1164            }
1165        }
1166    };
1167}
1168
1169impl_fn_once_ref!(A1);
1170impl_fn_once_ref!(A1, A2);
1171impl_fn_once_ref!(A1, A2, A3);
1172impl_fn_once_ref!(A1, A2, A3, A4);
1173impl_fn_once_ref!(A1, A2, A3, A4, A5);
1174impl_fn_once_ref!(A1, A2, A3, A4, A5, A6);
1175impl_fn_once_ref!(A1, A2, A3, A4, A5, A6, A7);
1176
1177impl<F: ?Sized> BinaryDecode for crate::Closure<F> {
1178    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
1179        // Decode the JsValue wrapping the closure
1180        let value = <crate::JsValue as BinaryDecode>::decode(decoder)?;
1181        Ok(Self {
1182            _phantom: PhantomData,
1183            value,
1184        })
1185    }
1186}
1187
1188impl<F: ?Sized> BinaryEncode for crate::Closure<F> {
1189    fn encode(self, encoder: &mut EncodedData) {
1190        // Encode the JsValue
1191        self.value.encode(encoder);
1192    }
1193}
1194
1195impl<F: ?Sized> BinaryEncode for &crate::Closure<F> {
1196    fn encode(self, encoder: &mut EncodedData) {
1197        // Encode the JsValue
1198        (&self.value).encode(encoder);
1199    }
1200}
1201
1202impl<T: EncodeTypeDef> EncodeTypeDef for Vec<T> {
1203    fn encode_type_def(buf: &mut Vec<u8>) {
1204        // Array type tag followed by element type
1205        buf.push(TypeTag::Array as u8);
1206        T::encode_type_def(buf);
1207    }
1208}
1209
1210impl<T: EncodeTypeDef> EncodeTypeDef for &[T] {
1211    fn encode_type_def(buf: &mut Vec<u8>) {
1212        // Array type tag followed by element type
1213        buf.push(TypeTag::Array as u8);
1214        T::encode_type_def(buf);
1215    }
1216}
1217
1218impl<T: EncodeTypeDef> EncodeTypeDef for &mut [T] {
1219    fn encode_type_def(buf: &mut Vec<u8>) {
1220        // Array type tag followed by element type
1221        buf.push(TypeTag::Array as u8);
1222        T::encode_type_def(buf);
1223    }
1224}
1225
1226impl<T: EncodeTypeDef> EncodeTypeDef for Box<[T]> {
1227    fn encode_type_def(buf: &mut Vec<u8>) {
1228        // Array type tag followed by element type
1229        buf.push(TypeTag::Array as u8);
1230        T::encode_type_def(buf);
1231    }
1232}
1233
1234impl<T: BinaryEncode> BinaryEncode for Box<[T]> {
1235    fn encode(self, encoder: &mut EncodedData) {
1236        encoder.push_u32(self.len() as u32);
1237        for val in self.into_vec() {
1238            val.encode(encoder);
1239        }
1240    }
1241}
1242
1243impl<T: BinaryEncode> BinaryEncode for Vec<T> {
1244    fn encode(self, encoder: &mut EncodedData) {
1245        encoder.push_u32(self.len() as u32);
1246        for val in self {
1247            val.encode(encoder);
1248        }
1249    }
1250}
1251
1252impl<T: BinaryDecode> BinaryDecode for Vec<T> {
1253    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
1254        let len = decoder.take_u32()? as usize;
1255        let mut vec = Vec::with_capacity(len);
1256        for _ in 0..len {
1257            vec.push(T::decode(decoder)?);
1258        }
1259        Ok(vec)
1260    }
1261}
1262
1263impl<T: BinaryDecode> BatchableResult for Vec<T> {}
1264
1265impl<T> BinaryEncode for &[T]
1266where
1267    for<'a> &'a T: BinaryEncode,
1268{
1269    fn encode(self, encoder: &mut EncodedData) {
1270        encoder.push_u32(self.len() as u32);
1271        for val in self {
1272            val.encode(encoder);
1273        }
1274    }
1275}
1276
1277impl<T> BinaryEncode for &mut [T]
1278where
1279    for<'a> &'a T: BinaryEncode,
1280{
1281    fn encode(self, encoder: &mut EncodedData) {
1282        encoder.push_u32(self.len() as u32);
1283        for val in self {
1284            val.encode(encoder);
1285        }
1286    }
1287}
1288
1289// ============ Clamped<T> implementations ============
1290
1291use crate::Clamped;
1292
1293impl EncodeTypeDef for Clamped<Vec<u8>> {
1294    fn encode_type_def(buf: &mut Vec<u8>) {
1295        buf.push(TypeTag::U8Clamped as u8);
1296    }
1297}
1298
1299impl EncodeTypeDef for Clamped<&[u8]> {
1300    fn encode_type_def(buf: &mut Vec<u8>) {
1301        buf.push(TypeTag::U8Clamped as u8);
1302    }
1303}
1304
1305impl EncodeTypeDef for Clamped<&mut [u8]> {
1306    fn encode_type_def(buf: &mut Vec<u8>) {
1307        buf.push(TypeTag::U8Clamped as u8);
1308    }
1309}
1310
1311impl BinaryEncode for Clamped<Vec<u8>> {
1312    fn encode(self, encoder: &mut EncodedData) {
1313        encoder.push_u32(self.0.len() as u32);
1314        for val in self.0 {
1315            encoder.push_u8(val);
1316        }
1317    }
1318}
1319
1320impl BinaryEncode for Clamped<&[u8]> {
1321    fn encode(self, encoder: &mut EncodedData) {
1322        encoder.push_u32(self.0.len() as u32);
1323        for &val in self.0 {
1324            encoder.push_u8(val);
1325        }
1326    }
1327}
1328
1329impl BinaryEncode for Clamped<&mut [u8]> {
1330    fn encode(self, encoder: &mut EncodedData) {
1331        encoder.push_u32(self.0.len() as u32);
1332        for &mut val in self.0 {
1333            encoder.push_u8(val);
1334        }
1335    }
1336}
1337
1338impl BinaryDecode for Clamped<Vec<u8>> {
1339    fn decode(decoder: &mut DecodedData) -> Result<Self, DecodeError> {
1340        let len = decoder.take_u32()? as usize;
1341        let mut vec = Vec::with_capacity(len);
1342        for _ in 0..len {
1343            vec.push(decoder.take_u8()?);
1344        }
1345        Ok(Clamped(vec))
1346    }
1347}
1348
1349impl BatchableResult for Clamped<Vec<u8>> {}