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}