1use crate::JsValue;
7use crate::batch::with_runtime;
8use crate::encode::{BinaryDecode, BinaryEncode, EncodeTypeDef};
9use core::mem::ManuallyDrop;
10use core::ops::Deref;
11
12pub trait IntoWasmAbi: BinaryEncode + EncodeTypeDef {
20 #[inline]
21 fn into_abi(self) -> u32
22 where
23 Self: Sized + IntoAbiId,
24 {
25 self.into_abi_id()
26 }
27}
28
29pub trait FromWasmAbi: BinaryDecode + EncodeTypeDef {
32 #[inline]
43 unsafe fn from_abi(js: u32) -> Self
44 where
45 Self: Sized + FromAbiId,
46 {
47 unsafe { Self::from_abi_id(js) }
48 }
49}
50
51pub trait OptionIntoWasmAbi: IntoWasmAbi {}
53
54pub trait OptionFromWasmAbi: FromWasmAbi {}
56
57pub trait WasmAbi {}
59
60pub trait RefFromWasmAbi {
62 #[inline]
69 unsafe fn ref_from_abi(js: u32) -> AbiRef<Self>
70 where
71 Self: Sized + FromAbiId,
72 {
73 AbiRef(ManuallyDrop::new(unsafe { Self::from_abi_id(js) }))
74 }
75}
76
77pub struct AbiRef<T>(ManuallyDrop<T>);
79
80impl<T> Deref for AbiRef<T> {
81 type Target = T;
82
83 #[inline]
84 fn deref(&self) -> &Self::Target {
85 &self.0
86 }
87}
88
89impl<T> AsRef<T> for AbiRef<T> {
90 #[inline]
91 fn as_ref(&self) -> &T {
92 self
93 }
94}
95
96#[doc(hidden)]
97pub trait IntoAbiId {
98 fn into_abi_id(self) -> u32;
99}
100
101#[doc(hidden)]
102pub trait FromAbiId {
103 unsafe fn from_abi_id(js: u32) -> Self;
104}
105
106impl<T> IntoAbiId for T
107where
108 T: AsRef<JsValue>,
109{
110 #[inline]
111 fn into_abi_id(self) -> u32 {
112 let id = self.as_ref().id();
113 core::mem::forget(self);
114 id as u32
115 }
116}
117
118impl<T> FromAbiId for T
119where
120 T: JsCast,
121{
122 #[inline]
123 unsafe fn from_abi_id(js: u32) -> Self {
124 T::unchecked_from_js(JsValue::from_id(js as u64))
125 }
126}
127
128impl<T> IntoWasmAbi for T where T: BinaryEncode + EncodeTypeDef {}
129impl<T> FromWasmAbi for T where T: BinaryDecode + EncodeTypeDef {}
130impl<T> OptionIntoWasmAbi for T where T: IntoWasmAbi {}
131impl<T> OptionFromWasmAbi for T where T: FromWasmAbi {}
132impl<T: ?Sized> WasmAbi for T {}
133impl<T: ?Sized> RefFromWasmAbi for T {}
134
135pub trait TryFromJsValue: Sized {
137 fn try_from_js_value(value: JsValue) -> Result<Self, JsValue> {
138 Self::try_from_js_value_ref(&value).ok_or(value)
139 }
140
141 fn try_from_js_value_ref(value: &JsValue) -> Option<Self>;
142}
143
144use crate::ipc::{DecodeError, DecodedData};
145use crate::{__rt::marker::ErasableGeneric, JsCast};
146use core::marker::PhantomData;
147
148pub trait UpcastFrom<S: ?Sized> {}
150
151pub trait Upcast<T: ?Sized> {
153 #[inline]
154 fn upcast(&self) -> &T
155 where
156 Self: ErasableGeneric,
157 T: Sized + ErasableGeneric<Repr = <Self as ErasableGeneric>::Repr>,
158 {
159 unsafe { &*(self as *const Self as *const T) }
160 }
161
162 #[inline]
163 fn upcast_into(self) -> T
164 where
165 Self: Sized + ErasableGeneric,
166 T: Sized + ErasableGeneric<Repr = <Self as ErasableGeneric>::Repr>,
167 {
168 unsafe { core::mem::transmute_copy(&core::mem::ManuallyDrop::new(self)) }
169 }
170}
171
172impl<S, T> Upcast<T> for S
173where
174 T: UpcastFrom<S> + ?Sized,
175 S: ?Sized,
176{
177}
178
179impl<'a, T, Target> UpcastFrom<&'a T> for &'a Target where Target: UpcastFrom<T> {}
180impl<'a, T, Target> UpcastFrom<&'a mut T> for &'a mut Target where Target: UpcastFrom<T> {}
181
182macro_rules! impl_tuple_upcast {
183 ([$($ty:ident)+] [$($target:ident)+]) => {
184 impl<$($ty,)+ $($target,)+> UpcastFrom<($($ty,)+)> for ($($target,)+)
185 where
186 $($ty: JsGeneric,)+
187 $($target: JsGeneric + UpcastFrom<$ty>,)+
188 {
189 }
190
191 impl<$($ty,)+ $($target,)+> UpcastFrom<($($ty,)+)> for crate::sys::JsOption<($($target,)+)>
192 where
193 $($ty: JsGeneric,)+
194 $($target: JsGeneric + UpcastFrom<$ty>,)+
195 {
196 }
197 };
198}
199
200impl_tuple_upcast!([T1][Target1]);
201impl_tuple_upcast!([T1 T2] [Target1 Target2]);
202impl_tuple_upcast!([T1 T2 T3] [Target1 Target2 Target3]);
203impl_tuple_upcast!([T1 T2 T3 T4] [Target1 Target2 Target3 Target4]);
204impl_tuple_upcast!([T1 T2 T3 T4 T5] [Target1 Target2 Target3 Target4 Target5]);
205impl_tuple_upcast!([T1 T2 T3 T4 T5 T6] [Target1 Target2 Target3 Target4 Target5 Target6]);
206impl_tuple_upcast!([T1 T2 T3 T4 T5 T6 T7] [Target1 Target2 Target3 Target4 Target5 Target6 Target7]);
207impl_tuple_upcast!([T1 T2 T3 T4 T5 T6 T7 T8] [Target1 Target2 Target3 Target4 Target5 Target6 Target7 Target8]);
208
209macro_rules! impl_fn_upcasts {
210 () => {
211 impl_fn_upcasts!(@arities
212 [0 []]
213 [1 [A1 B1] O1]
214 [2 [A1 B1 A2 B2] O2]
215 [3 [A1 B1 A2 B2 A3 B3] O3]
216 [4 [A1 B1 A2 B2 A3 B3 A4 B4] O4]
217 [5 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5] O5]
218 [6 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6] O6]
219 [7 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7] O7]
220 [8 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7 A8 B8] O8]
221 );
222 };
223
224 (@arities) => {};
225
226 (@arities [$n:tt $args:tt $($opt:ident)?] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
227 impl_fn_upcasts!(@same $args);
228 impl_fn_upcasts!(@cross_all $args [] $([$rest_n $rest_args $($rest_opt)?])*);
229 impl_fn_upcasts!(@arities $([$rest_n $rest_args $($rest_opt)?])*);
230 };
231
232 (@same []) => {
233 impl<R1, R2> UpcastFrom<fn() -> R1> for fn() -> R2
234 where
235 R2: UpcastFrom<R1>,
236 {
237 }
238
239 impl<'a, R1, R2> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn() -> R2 + 'a
240 where
241 R2: UpcastFrom<R1>,
242 {
243 }
244
245 impl<'a, R1, R2> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut() -> R2 + 'a
246 where
247 R2: UpcastFrom<R1>,
248 {
249 }
250 };
251
252 (@same [$($A1:ident $A2:ident)+]) => {
253 impl<R1, R2, $($A1, $A2),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2),+) -> R2
254 where
255 R2: UpcastFrom<R1>,
256 $($A1: UpcastFrom<$A2>,)+
257 {
258 }
259
260 impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
261 where
262 R2: UpcastFrom<R1>,
263 $($A1: UpcastFrom<$A2>,)+
264 {
265 }
266
267 impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
268 where
269 R2: UpcastFrom<R1>,
270 $($A1: UpcastFrom<$A2>,)+
271 {
272 }
273 };
274
275 (@cross_all $args:tt $opts:tt) => {};
276
277 (@cross_all $args:tt [$($opts:ident)*] [$next_n:tt $next_args:tt $next_opt:ident] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
278 impl_fn_upcasts!(@extend $args [$($opts)* $next_opt]);
279 impl_fn_upcasts!(@shrink $args [$($opts)* $next_opt]);
280 impl_fn_upcasts!(@cross_all $args [$($opts)* $next_opt] $([$rest_n $rest_args $($rest_opt)?])*);
281 };
282
283 (@extend [] [$($O:ident)+]) => {
284 impl<R1, R2, $($O),+> UpcastFrom<fn() -> R1> for fn($($O),+) -> R2
285 where
286 R2: UpcastFrom<R1>,
287 $($O: UpcastFrom<crate::sys::Undefined>,)+
288 {
289 }
290
291 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn($($O),+) -> R2 + 'a
292 where
293 R2: UpcastFrom<R1>,
294 $($O: UpcastFrom<crate::sys::Undefined>,)+
295 {
296 }
297
298 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut($($O),+) -> R2 + 'a
299 where
300 R2: UpcastFrom<R1>,
301 $($O: UpcastFrom<crate::sys::Undefined>,)+
302 {
303 }
304 };
305
306 (@extend [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
307 impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2,)+ $($O),+) -> R2
308 where
309 R2: UpcastFrom<R1>,
310 $($A1: UpcastFrom<$A2>,)+
311 $($O: UpcastFrom<crate::sys::Undefined>,)+
312 {
313 }
314
315 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2,)+ $($O),+) -> R2 + 'a
316 where
317 R2: UpcastFrom<R1>,
318 $($A1: UpcastFrom<$A2>,)+
319 $($O: UpcastFrom<crate::sys::Undefined>,)+
320 {
321 }
322
323 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2,)+ $($O),+) -> R2 + 'a
324 where
325 R2: UpcastFrom<R1>,
326 $($A1: UpcastFrom<$A2>,)+
327 $($O: UpcastFrom<crate::sys::Undefined>,)+
328 {
329 }
330 };
331
332 (@shrink [] [$($O:ident)+]) => {
333 impl<R1, R2, $($O),+> UpcastFrom<fn($($O),+) -> R1> for fn() -> R2
334 where
335 R2: UpcastFrom<R1>,
336 $($O: UpcastFrom<crate::sys::Undefined>,)+
337 {
338 }
339
340 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn($($O),+) -> R1 + 'a> for dyn Fn() -> R2 + 'a
341 where
342 R2: UpcastFrom<R1>,
343 $($O: UpcastFrom<crate::sys::Undefined>,)+
344 {
345 }
346
347 impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut($($O),+) -> R1 + 'a> for dyn FnMut() -> R2 + 'a
348 where
349 R2: UpcastFrom<R1>,
350 $($O: UpcastFrom<crate::sys::Undefined>,)+
351 {
352 }
353 };
354
355 (@shrink [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
356 impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1,)+ $($O),+) -> R1> for fn($($A2),+) -> R2
357 where
358 R2: UpcastFrom<R1>,
359 $($A1: UpcastFrom<$A2>,)+
360 $($O: UpcastFrom<crate::sys::Undefined>,)+
361 {
362 }
363
364 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1,)+ $($O),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
365 where
366 R2: UpcastFrom<R1>,
367 $($A1: UpcastFrom<$A2>,)+
368 $($O: UpcastFrom<crate::sys::Undefined>,)+
369 {
370 }
371
372 impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1,)+ $($O),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
373 where
374 R2: UpcastFrom<R1>,
375 $($A1: UpcastFrom<$A2>,)+
376 $($O: UpcastFrom<crate::sys::Undefined>,)+
377 {
378 }
379 };
380}
381
382impl_fn_upcasts!();
383
384pub trait JsGeneric:
386 crate::__rt::marker::ErasableGeneric<Repr = JsValue>
387 + UpcastFrom<Self>
388 + Upcast<Self>
389 + Upcast<JsValue>
390 + JsCast
391 + crate::encode::EncodeTypeDef
392 + crate::encode::BinaryEncode
393 + crate::encode::BinaryDecode
394 + crate::encode::BatchableResult
395 + 'static
396{
397}
398
399impl<T> JsGeneric for T where
400 T: crate::__rt::marker::ErasableGeneric<Repr = JsValue>
401 + UpcastFrom<T>
402 + Upcast<JsValue>
403 + JsCast
404 + crate::encode::EncodeTypeDef
405 + crate::encode::BinaryEncode
406 + crate::encode::BinaryDecode
407 + crate::encode::BatchableResult
408 + 'static
409{
410}
411
412pub trait IntoJsGeneric {
414 type JsCanon: JsGeneric;
415
416 fn to_js(self) -> Self::JsCanon;
417}
418
419impl IntoJsGeneric for JsValue {
420 type JsCanon = JsValue;
421
422 #[inline]
423 fn to_js(self) -> JsValue {
424 self
425 }
426}
427
428impl<T: IntoJsGeneric + Clone> IntoJsGeneric for &T {
429 type JsCanon = T::JsCanon;
430
431 #[inline]
432 fn to_js(self) -> T::JsCanon {
433 self.clone().to_js()
434 }
435}
436
437impl UpcastFrom<JsValue> for JsValue {}
438
439pub trait RefFromBinaryDecode {
445 type Anchor: core::ops::Deref<Target = Self>;
447
448 fn ref_decode(decoder: &mut DecodedData) -> Result<Self::Anchor, DecodeError>;
450}
451
452pub struct JsCastAnchor<T: JsCast> {
457 value: JsValue,
458 _marker: PhantomData<T>,
459}
460
461impl<T: JsCast> core::ops::Deref for JsCastAnchor<T> {
462 type Target = T;
463
464 fn deref(&self) -> &Self::Target {
465 T::unchecked_from_js_ref(&self.value)
466 }
467}
468
469impl<T: JsCast + 'static> RefFromBinaryDecode for T {
471 type Anchor = JsCastAnchor<T>;
472
473 fn ref_decode(_decoder: &mut DecodedData) -> Result<Self::Anchor, DecodeError> {
474 let id = with_runtime(|runtime| runtime.get_next_borrow_id());
478 let value = JsValue::from_id(id);
479 Ok(JsCastAnchor {
480 value,
481 _marker: PhantomData,
482 })
483 }
484}