1#![allow(clippy::too_many_arguments)]
8#![allow(clippy::type_complexity)]
9
10use alloc::vec::Vec;
11use core::cell::RefCell;
12use core::marker::PhantomData;
13
14use crate::batch::{force_flush, run_js_sync, with_runtime};
15use crate::encode::{BatchableResult, BinaryEncode, EncodeTypeDef, TYPE_CACHED, TYPE_FULL};
16use crate::ipc::DecodeError;
17use crate::ipc::DecodedData;
18use crate::ipc::EncodedData;
19
20pub const DROP_NATIVE_REF_FN_ID: u32 = 0xFFFFFFFF;
23
24pub const CALL_EXPORT_FN_ID: u32 = 0xFFFFFFFE;
27
28fn encode_function_types(encoder: &mut EncodedData, encode_types: impl FnOnce(&mut Vec<u8>)) {
35 let mut type_buf = Vec::new();
36 encode_types(&mut type_buf);
37
38 with_runtime(|state| {
39 let (id, can_use_cached) = state.get_or_create_type_id(&type_buf);
40 if can_use_cached {
41 encoder.push_u8(TYPE_CACHED);
42 encoder.push_u32(id);
43 } else {
44 encoder.push_u8(TYPE_FULL);
45 encoder.push_u32(id);
46 encoder.register_pending_type_id(id);
47 for byte in type_buf {
48 encoder.push_u8(byte);
49 }
50 }
51 });
52}
53
54pub struct JSFunction<T> {
59 id: u32,
60 function: PhantomData<T>,
61}
62
63impl<T> JSFunction<T> {
64 pub const fn new(id: u32) -> Self {
65 Self {
66 id,
67 function: PhantomData,
68 }
69 }
70
71 pub fn id(&self) -> u32 {
73 self.id
74 }
75}
76
77macro_rules! impl_js_function_call {
78 (0,) => {
80 impl<R: BatchableResult + EncodeTypeDef> JSFunction<fn() -> R> {
81 pub fn call(&self) -> R {
82 run_js_sync::<R>(self.id, |encoder| {
83 encode_function_types(encoder, |buf| {
84 buf.push(0);
85 R::encode_type_def(buf);
86 });
87 })
88 }
89 }
90 };
91 ($n:expr, $($T:ident $arg:ident),+) => {
93 impl<$($T: EncodeTypeDef,)+ R: BatchableResult + EncodeTypeDef>
94 JSFunction<fn($($T),+) -> R>
95 {
96 pub fn call(&self, $($arg: $T),+) -> R
97 where
98 $($T: BinaryEncode,)+
99 {
100 run_js_sync::<R>(self.id, |encoder| {
101 encode_function_types(encoder, |buf| {
102 buf.push($n);
103 $($T::encode_type_def(buf);)+
104 R::encode_type_def(buf);
105 });
106 $($arg.encode(encoder);)+
107 })
108 }
109 }
110 };
111}
112
113impl_js_function_call!(0,);
114impl_js_function_call!(1, T1 arg1);
115impl_js_function_call!(2, T1 arg1, T2 arg2);
116impl_js_function_call!(3, T1 arg1, T2 arg2, T3 arg3);
117impl_js_function_call!(4, T1 arg1, T2 arg2, T3 arg3, T4 arg4);
118impl_js_function_call!(5, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);
119impl_js_function_call!(6, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);
120impl_js_function_call!(7, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);
121impl_js_function_call!(8, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);
122impl_js_function_call!(9, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9);
123impl_js_function_call!(10, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10);
124impl_js_function_call!(11, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11);
125impl_js_function_call!(12, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12);
126impl_js_function_call!(13, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13);
127impl_js_function_call!(14, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14);
128impl_js_function_call!(15, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15);
129impl_js_function_call!(16, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16);
130impl_js_function_call!(17, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17);
131impl_js_function_call!(18, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18);
132impl_js_function_call!(19, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19);
133impl_js_function_call!(20, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20);
134impl_js_function_call!(21, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21);
135impl_js_function_call!(22, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22);
136impl_js_function_call!(23, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23);
137impl_js_function_call!(24, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23, T24 arg24);
138impl_js_function_call!(25, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23, T24 arg24, T25 arg25);
139impl_js_function_call!(26, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23, T24 arg24, T25 arg25, T26 arg26);
140impl_js_function_call!(27, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23, T24 arg24, T25 arg25, T26 arg26, T27 arg27);
141impl_js_function_call!(28, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23, T24 arg24, T25 arg25, T26 arg26, T27 arg27, T28 arg28);
142impl_js_function_call!(29, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23, T24 arg24, T25 arg25, T26 arg26, T27 arg27, T28 arg28, T29 arg29);
143impl_js_function_call!(30, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23, T24 arg24, T25 arg25, T26 arg26, T27 arg27, T28 arg28, T29 arg29, T30 arg30);
144impl_js_function_call!(31, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23, T24 arg24, T25 arg25, T26 arg26, T27 arg27, T28 arg28, T29 arg29, T30 arg30, T31 arg31);
145impl_js_function_call!(32, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8, T9 arg9, T10 arg10, T11 arg11, T12 arg12, T13 arg13, T14 arg14, T15 arg15, T16 arg16, T17 arg17, T18 arg18, T19 arg19, T20 arg20, T21 arg21, T22 arg22, T23 arg23, T24 arg24, T25 arg25, T26 arg26, T27 arg27, T28 arg28, T29 arg29, T30 arg30, T31 arg31, T32 arg32);
146
147type CallbackFn = dyn Fn(&mut DecodedData, &mut EncodedData) -> Result<(), DecodeError>;
152
153pub(crate) struct RustCallback {
154 f: alloc::rc::Rc<CallbackFn>,
155}
156
157impl RustCallback {
158 pub fn new_fn<F>(f: F) -> Self
163 where
164 F: Fn(&mut DecodedData, &mut EncodedData) -> Result<(), DecodeError> + 'static,
165 {
166 Self {
167 f: alloc::rc::Rc::new(move |data: &mut DecodedData, encoder: &mut EncodedData| {
168 let result = f(data, encoder);
169 force_flush();
170 result
171 }),
172 }
173 }
174
175 pub fn new_fn_mut<F>(f: F) -> Self
177 where
178 F: FnMut(&mut DecodedData, &mut EncodedData) -> Result<(), DecodeError> + 'static,
179 {
180 let cell = RefCell::new(f);
182 Self {
183 f: alloc::rc::Rc::new(move |data: &mut DecodedData, encoder: &mut EncodedData| {
184 let result = {
185 let mut f = cell.borrow_mut();
186 f(data, encoder)
187 };
188 force_flush();
189 result
190 }),
191 }
192 }
193
194 pub fn clone_rc(&self) -> alloc::rc::Rc<CallbackFn> {
196 self.f.clone()
197 }
198}