-
Notifications
You must be signed in to change notification settings - Fork 43
/
wasm_bindgen.rs
141 lines (115 loc) · 4.16 KB
/
wasm_bindgen.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse_quote;
use crate::{container::Container, decl::Decl};
pub fn expand(cont: &Container, decl: Decl) -> TokenStream {
let attrs = &cont.attrs;
let ident = cont.ident();
let decl_str = decl.to_string();
let (impl_generics, ty_generics, where_clause) = cont.generics().split_for_impl();
let typescript_custom_section = quote! {
#[wasm_bindgen(typescript_custom_section)]
const TS_APPEND_CONTENT: &'static str = #decl_str;
};
let wasm_abi = attrs.into_wasm_abi || attrs.from_wasm_abi;
let wasm_describe = wasm_abi.then(|| {
quote! {
impl #impl_generics WasmDescribe for #ident #ty_generics #where_clause {
#[inline]
fn describe() {
<Self as Tsify>::JsType::describe()
}
}
}
});
let use_serde = wasm_abi.then(|| match cont.serde_container.attrs.custom_serde_path() {
Some(path) => quote! {
use #path as _serde;
},
None => quote! {
extern crate serde as _serde;
},
});
let into_wasm_abi = attrs.into_wasm_abi.then(|| expand_into_wasm_abi(cont));
let from_wasm_abi = attrs.from_wasm_abi.then(|| expand_from_wasm_abi(cont));
let typescript_type = decl.id();
quote! {
#[automatically_derived]
const _: () = {
#use_serde
use tsify::Tsify;
use wasm_bindgen::{
convert::{FromWasmAbi, IntoWasmAbi, OptionFromWasmAbi, OptionIntoWasmAbi},
describe::WasmDescribe,
prelude::*,
};
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(typescript_type = #typescript_type)]
pub type JsType;
}
impl #impl_generics Tsify for #ident #ty_generics #where_clause {
type JsType = JsType;
const DECL: &'static str = #decl_str;
}
#typescript_custom_section
#wasm_describe
#into_wasm_abi
#from_wasm_abi
};
}
}
fn expand_into_wasm_abi(cont: &Container) -> TokenStream {
let ident = cont.ident();
let serde_path = cont.serde_container.attrs.serde_path();
let mut generics = cont.generics().clone();
generics
.make_where_clause()
.predicates
.push(parse_quote!(Self: #serde_path::Serialize));
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
quote! {
impl #impl_generics IntoWasmAbi for #ident #ty_generics #where_clause {
type Abi = <JsType as IntoWasmAbi>::Abi;
#[inline]
fn into_abi(self) -> Self::Abi {
self.into_js().unwrap_throw().into_abi()
}
}
impl #impl_generics OptionIntoWasmAbi for #ident #ty_generics #where_clause {
#[inline]
fn none() -> Self::Abi {
<JsType as OptionIntoWasmAbi>::none()
}
}
}
}
fn expand_from_wasm_abi(cont: &Container) -> TokenStream {
let ident = cont.ident();
let serde_path = cont.serde_container.attrs.serde_path();
let mut generics = cont.generics().clone();
generics
.make_where_clause()
.predicates
.push(parse_quote!(Self: #serde_path::de::DeserializeOwned));
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
quote! {
impl #impl_generics FromWasmAbi for #ident #ty_generics #where_clause {
type Abi = <JsType as FromWasmAbi>::Abi;
#[inline]
unsafe fn from_abi(js: Self::Abi) -> Self {
let result = Self::from_js(&JsType::from_abi(js));
if let Err(err) = result {
wasm_bindgen::throw_str(err.to_string().as_ref());
}
result.unwrap_throw()
}
}
impl #impl_generics OptionFromWasmAbi for #ident #ty_generics #where_clause {
#[inline]
fn is_none(js: &Self::Abi) -> bool {
<JsType as OptionFromWasmAbi>::is_none(js)
}
}
}
}