Skip to main content

tsain_core/
ts.rs

1use crate as tsain;
2use crate::Error;
3use serde::{Serialize, de::DeserializeOwned};
4use std::{marker::PhantomData, mem::ManuallyDrop};
5use wasm_bindgen::{
6    convert::{
7        FromWasmAbi, IntoWasmAbi, LongRefFromWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi,
8        RefFromWasmAbi, VectorFromWasmAbi, VectorIntoWasmAbi,
9    },
10    describe::{WasmDescribe, WasmDescribeVector},
11    prelude::*,
12};
13
14#[repr(transparent)]
15pub struct Ts<T>(JsValue, PhantomData<T>);
16
17impl<T> Clone for Ts<T> {
18    fn clone(&self) -> Self {
19        Self(self.0.clone(), PhantomData)
20    }
21}
22
23impl<T> std::fmt::Debug for Ts<T> {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        f.debug_tuple("Ts").finish()
26    }
27}
28
29impl<T> Ts<T> {
30    pub fn new(js: JsValue) -> Self {
31        Self(js, std::marker::PhantomData)
32    }
33
34    pub fn js_value(&self) -> &JsValue {
35        &self.0
36    }
37
38    pub fn from_rust(value: &T) -> Result<Self, Error>
39    where
40        T: Serialize,
41    {
42        let x = tsain::to_value(value)?;
43        Ok(Self(x, PhantomData))
44    }
45
46    pub fn to_rust(self) -> Result<T, Error>
47    where
48        T: DeserializeOwned,
49    {
50        tsain::from_value(self.0)
51    }
52}
53
54impl<T> WasmDescribe for Ts<T> {
55    fn describe() {
56        JsValue::describe();
57    }
58}
59
60impl<T> IntoWasmAbi for Ts<T> {
61    type Abi = <JsValue as IntoWasmAbi>::Abi;
62    fn into_abi(self) -> Self::Abi {
63        self.0.into_abi()
64    }
65}
66
67impl<T> IntoWasmAbi for &Ts<T> {
68    type Abi = <JsValue as IntoWasmAbi>::Abi;
69    fn into_abi(self) -> Self::Abi {
70        self.0.clone().into_abi()
71    }
72}
73
74impl<T> FromWasmAbi for Ts<T> {
75    type Abi = <JsValue as IntoWasmAbi>::Abi;
76    unsafe fn from_abi(js: Self::Abi) -> Self {
77        Self(unsafe { JsValue::from_abi(js) }, PhantomData)
78    }
79}
80
81impl<T> OptionIntoWasmAbi for Ts<T> {
82    fn none() -> Self::Abi {
83        <JsValue as OptionIntoWasmAbi>::none()
84    }
85}
86
87impl<T> OptionFromWasmAbi for Ts<T> {
88    fn is_none(abi: &Self::Abi) -> bool {
89        JsValue::is_none(abi)
90    }
91}
92
93impl<T> RefFromWasmAbi for Ts<T> {
94    type Anchor = ManuallyDrop<Ts<T>>;
95    type Abi = <JsValue as RefFromWasmAbi>::Abi;
96    unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
97        let js_type_anchor = unsafe { JsValue::ref_from_abi(js) };
98        let anchor_inner = ManuallyDrop::into_inner(js_type_anchor);
99        ManuallyDrop::new(Ts::new(anchor_inner))
100    }
101}
102
103impl<T> LongRefFromWasmAbi for Ts<T> {
104    type Abi = <JsValue as LongRefFromWasmAbi>::Abi;
105    type Anchor = Ts<T>;
106    unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor {
107        let js_value = unsafe { <JsValue as LongRefFromWasmAbi>::long_ref_from_abi(js) };
108        Self::new(js_value)
109    }
110}
111
112impl<T> WasmDescribeVector for Ts<T> {
113    fn describe_vector() {
114        JsValue::describe_vector();
115    }
116}
117
118impl<T> VectorFromWasmAbi for Ts<T> {
119    type Abi = <JsValue as VectorFromWasmAbi>::Abi;
120
121    unsafe fn vector_from_abi(js: Self::Abi) -> Box<[Self]> {
122        let vec_js = unsafe { <JsValue as VectorFromWasmAbi>::vector_from_abi(js) };
123        let vec = Vec::from(vec_js);
124        vec.into_iter()
125            .map(|js_item| Ts::new(js_item))
126            .collect::<Vec<Ts<T>>>()
127            .into_boxed_slice()
128    }
129}
130
131impl<T> VectorIntoWasmAbi for Ts<T> {
132    type Abi = <JsValue as VectorIntoWasmAbi>::Abi;
133
134    fn vector_into_abi(vector: Box<[Self]>) -> Self::Abi {
135        let vec_js: Vec<JsValue> = vector
136            .into_vec()
137            .into_iter()
138            .map(|ts_item| ts_item.0)
139            .collect();
140        JsValue::vector_into_abi(vec_js.into_boxed_slice())
141    }
142}