use crate::JsValue;
use crate::batch::with_runtime;
use crate::encode::{BinaryDecode, BinaryEncode, EncodeTypeDef};
use core::mem::ManuallyDrop;
use core::ops::Deref;
pub trait IntoWasmAbi: BinaryEncode + EncodeTypeDef {
#[inline]
fn into_abi(self) -> u32
where
Self: Sized + IntoAbiId,
{
self.into_abi_id()
}
}
pub trait FromWasmAbi: BinaryDecode + EncodeTypeDef {
#[inline]
unsafe fn from_abi(js: u32) -> Self
where
Self: Sized + FromAbiId,
{
unsafe { Self::from_abi_id(js) }
}
}
pub trait OptionIntoWasmAbi: IntoWasmAbi {}
pub trait OptionFromWasmAbi: FromWasmAbi {}
pub trait WasmAbi {}
pub trait RefFromWasmAbi {
#[inline]
unsafe fn ref_from_abi(js: u32) -> AbiRef<Self>
where
Self: Sized + FromAbiId,
{
AbiRef(ManuallyDrop::new(unsafe { Self::from_abi_id(js) }))
}
}
pub struct AbiRef<T>(ManuallyDrop<T>);
impl<T> Deref for AbiRef<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> AsRef<T> for AbiRef<T> {
#[inline]
fn as_ref(&self) -> &T {
self
}
}
#[doc(hidden)]
pub trait IntoAbiId {
fn into_abi_id(self) -> u32;
}
#[doc(hidden)]
pub trait FromAbiId {
unsafe fn from_abi_id(js: u32) -> Self;
}
impl<T> IntoAbiId for T
where
T: AsRef<JsValue>,
{
#[inline]
fn into_abi_id(self) -> u32 {
let id = self.as_ref().id();
core::mem::forget(self);
id as u32
}
}
impl<T> FromAbiId for T
where
T: JsCast,
{
#[inline]
unsafe fn from_abi_id(js: u32) -> Self {
T::unchecked_from_js(JsValue::from_id(js as u64))
}
}
impl<T> IntoWasmAbi for T where T: BinaryEncode + EncodeTypeDef {}
impl<T> FromWasmAbi for T where T: BinaryDecode + EncodeTypeDef {}
impl<T> OptionIntoWasmAbi for T where T: IntoWasmAbi {}
impl<T> OptionFromWasmAbi for T where T: FromWasmAbi {}
impl<T: ?Sized> WasmAbi for T {}
impl<T: ?Sized> RefFromWasmAbi for T {}
pub trait TryFromJsValue: Sized {
fn try_from_js_value(value: JsValue) -> Result<Self, JsValue> {
Self::try_from_js_value_ref(&value).ok_or(value)
}
fn try_from_js_value_ref(value: &JsValue) -> Option<Self>;
}
use crate::ipc::{DecodeError, DecodedData};
use crate::{__rt::marker::ErasableGeneric, JsCast};
use core::marker::PhantomData;
pub trait UpcastFrom<S: ?Sized> {}
pub trait Upcast<T: ?Sized> {
#[inline]
fn upcast(&self) -> &T
where
Self: ErasableGeneric,
T: Sized + ErasableGeneric<Repr = <Self as ErasableGeneric>::Repr>,
{
unsafe { &*(self as *const Self as *const T) }
}
#[inline]
fn upcast_into(self) -> T
where
Self: Sized + ErasableGeneric,
T: Sized + ErasableGeneric<Repr = <Self as ErasableGeneric>::Repr>,
{
unsafe { core::mem::transmute_copy(&core::mem::ManuallyDrop::new(self)) }
}
}
impl<S, T> Upcast<T> for S
where
T: UpcastFrom<S> + ?Sized,
S: ?Sized,
{
}
impl<'a, T, Target> UpcastFrom<&'a T> for &'a Target where Target: UpcastFrom<T> {}
impl<'a, T, Target> UpcastFrom<&'a mut T> for &'a mut Target where Target: UpcastFrom<T> {}
macro_rules! impl_tuple_upcast {
([$($ty:ident)+] [$($target:ident)+]) => {
impl<$($ty,)+ $($target,)+> UpcastFrom<($($ty,)+)> for ($($target,)+)
where
$($ty: JsGeneric,)+
$($target: JsGeneric + UpcastFrom<$ty>,)+
{
}
impl<$($ty,)+ $($target,)+> UpcastFrom<($($ty,)+)> for crate::sys::JsOption<($($target,)+)>
where
$($ty: JsGeneric,)+
$($target: JsGeneric + UpcastFrom<$ty>,)+
{
}
};
}
impl_tuple_upcast!([T1][Target1]);
impl_tuple_upcast!([T1 T2] [Target1 Target2]);
impl_tuple_upcast!([T1 T2 T3] [Target1 Target2 Target3]);
impl_tuple_upcast!([T1 T2 T3 T4] [Target1 Target2 Target3 Target4]);
impl_tuple_upcast!([T1 T2 T3 T4 T5] [Target1 Target2 Target3 Target4 Target5]);
impl_tuple_upcast!([T1 T2 T3 T4 T5 T6] [Target1 Target2 Target3 Target4 Target5 Target6]);
impl_tuple_upcast!([T1 T2 T3 T4 T5 T6 T7] [Target1 Target2 Target3 Target4 Target5 Target6 Target7]);
impl_tuple_upcast!([T1 T2 T3 T4 T5 T6 T7 T8] [Target1 Target2 Target3 Target4 Target5 Target6 Target7 Target8]);
macro_rules! impl_fn_upcasts {
() => {
impl_fn_upcasts!(@arities
[0 []]
[1 [A1 B1] O1]
[2 [A1 B1 A2 B2] O2]
[3 [A1 B1 A2 B2 A3 B3] O3]
[4 [A1 B1 A2 B2 A3 B3 A4 B4] O4]
[5 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5] O5]
[6 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6] O6]
[7 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7] O7]
[8 [A1 B1 A2 B2 A3 B3 A4 B4 A5 B5 A6 B6 A7 B7 A8 B8] O8]
);
};
(@arities) => {};
(@arities [$n:tt $args:tt $($opt:ident)?] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
impl_fn_upcasts!(@same $args);
impl_fn_upcasts!(@cross_all $args [] $([$rest_n $rest_args $($rest_opt)?])*);
impl_fn_upcasts!(@arities $([$rest_n $rest_args $($rest_opt)?])*);
};
(@same []) => {
impl<R1, R2> UpcastFrom<fn() -> R1> for fn() -> R2
where
R2: UpcastFrom<R1>,
{
}
impl<'a, R1, R2> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn() -> R2 + 'a
where
R2: UpcastFrom<R1>,
{
}
impl<'a, R1, R2> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut() -> R2 + 'a
where
R2: UpcastFrom<R1>,
{
}
};
(@same [$($A1:ident $A2:ident)+]) => {
impl<R1, R2, $($A1, $A2),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2),+) -> R2
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
{
}
impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
{
}
impl<'a, R1, R2, $($A1, $A2),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
{
}
};
(@cross_all $args:tt $opts:tt) => {};
(@cross_all $args:tt [$($opts:ident)*] [$next_n:tt $next_args:tt $next_opt:ident] $([$rest_n:tt $rest_args:tt $($rest_opt:ident)?])*) => {
impl_fn_upcasts!(@extend $args [$($opts)* $next_opt]);
impl_fn_upcasts!(@shrink $args [$($opts)* $next_opt]);
impl_fn_upcasts!(@cross_all $args [$($opts)* $next_opt] $([$rest_n $rest_args $($rest_opt)?])*);
};
(@extend [] [$($O:ident)+]) => {
impl<R1, R2, $($O),+> UpcastFrom<fn() -> R1> for fn($($O),+) -> R2
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn() -> R1 + 'a> for dyn Fn($($O),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut() -> R1 + 'a> for dyn FnMut($($O),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
};
(@extend [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1),+) -> R1> for fn($($A2,)+ $($O),+) -> R2
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1),+) -> R1 + 'a> for dyn Fn($($A2,)+ $($O),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1),+) -> R1 + 'a> for dyn FnMut($($A2,)+ $($O),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
};
(@shrink [] [$($O:ident)+]) => {
impl<R1, R2, $($O),+> UpcastFrom<fn($($O),+) -> R1> for fn() -> R2
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
impl<'a, R1, R2, $($O),+> UpcastFrom<dyn Fn($($O),+) -> R1 + 'a> for dyn Fn() -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
impl<'a, R1, R2, $($O),+> UpcastFrom<dyn FnMut($($O),+) -> R1 + 'a> for dyn FnMut() -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
};
(@shrink [$($A1:ident $A2:ident)+] [$($O:ident)+]) => {
impl<R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<fn($($A1,)+ $($O),+) -> R1> for fn($($A2),+) -> R2
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn Fn($($A1,)+ $($O),+) -> R1 + 'a> for dyn Fn($($A2),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
impl<'a, R1, R2, $($A1, $A2,)+ $($O),+> UpcastFrom<dyn FnMut($($A1,)+ $($O),+) -> R1 + 'a> for dyn FnMut($($A2),+) -> R2 + 'a
where
R2: UpcastFrom<R1>,
$($A1: UpcastFrom<$A2>,)+
$($O: UpcastFrom<crate::sys::Undefined>,)+
{
}
};
}
impl_fn_upcasts!();
pub trait JsGeneric:
crate::__rt::marker::ErasableGeneric<Repr = JsValue>
+ UpcastFrom<Self>
+ Upcast<Self>
+ Upcast<JsValue>
+ JsCast
+ crate::encode::EncodeTypeDef
+ crate::encode::BinaryEncode
+ crate::encode::BinaryDecode
+ crate::encode::BatchableResult
+ 'static
{
}
impl<T> JsGeneric for T where
T: crate::__rt::marker::ErasableGeneric<Repr = JsValue>
+ UpcastFrom<T>
+ Upcast<JsValue>
+ JsCast
+ crate::encode::EncodeTypeDef
+ crate::encode::BinaryEncode
+ crate::encode::BinaryDecode
+ crate::encode::BatchableResult
+ 'static
{
}
pub trait IntoJsGeneric {
type JsCanon: JsGeneric;
fn to_js(self) -> Self::JsCanon;
}
impl IntoJsGeneric for JsValue {
type JsCanon = JsValue;
#[inline]
fn to_js(self) -> JsValue {
self
}
}
impl<T: IntoJsGeneric + Clone> IntoJsGeneric for &T {
type JsCanon = T::JsCanon;
#[inline]
fn to_js(self) -> T::JsCanon {
self.clone().to_js()
}
}
impl UpcastFrom<JsValue> for JsValue {}
pub trait RefFromBinaryDecode {
type Anchor: core::ops::Deref<Target = Self>;
fn ref_decode(decoder: &mut DecodedData) -> Result<Self::Anchor, DecodeError>;
}
pub struct JsCastAnchor<T: JsCast> {
value: JsValue,
_marker: PhantomData<T>,
}
impl<T: JsCast> core::ops::Deref for JsCastAnchor<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
T::unchecked_from_js_ref(&self.value)
}
}
impl<T: JsCast + 'static> RefFromBinaryDecode for T {
type Anchor = JsCastAnchor<T>;
fn ref_decode(_decoder: &mut DecodedData) -> Result<Self::Anchor, DecodeError> {
let id = with_runtime(|runtime| runtime.get_next_borrow_id());
let value = JsValue::from_id(id);
Ok(JsCastAnchor {
value,
_marker: PhantomData,
})
}
}