1use crate::ast;
2use crate::encode;
3use crate::encode::EncodeChunk;
4use crate::Diagnostic;
5use proc_macro2::{Ident, Span, TokenStream};
6use quote::format_ident;
7use quote::quote_spanned;
8use quote::{quote, ToTokens};
9use std::cell::RefCell;
10use std::collections::{HashMap, HashSet};
11use syn::parse_quote;
12use syn::spanned::Spanned;
13use wasm_bindgen_shared as shared;
14
15pub trait TryToTokens {
18 fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic>;
20
21 fn try_to_token_stream(&self) -> Result<TokenStream, Diagnostic> {
23 let mut tokens = TokenStream::new();
24 self.try_to_tokens(&mut tokens)?;
25 Ok(tokens)
26 }
27}
28
29impl TryToTokens for ast::Program {
30 fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
32 let mut errors = Vec::new();
33 for export in self.exports.iter() {
34 if let Err(e) = export.try_to_tokens(tokens) {
35 errors.push(e);
36 }
37 }
38 for s in self.structs.iter() {
39 s.to_tokens(tokens);
40 }
41 let mut types = HashMap::new();
42 for i in self.imports.iter() {
43 if let ast::ImportKind::Type(t) = &i.kind {
44 types.insert(t.rust_name.to_string(), t.rust_name.clone());
45 }
46 }
47 for i in self.imports.iter() {
48 DescribeImport {
49 kind: &i.kind,
50 wasm_bindgen: &self.wasm_bindgen,
51 }
52 .to_tokens(tokens);
53
54 if let Some(nss) = &i.js_namespace {
57 if let Some(ns) = nss.last().and_then(|t| types.get(t)) {
59 if i.kind.fits_on_impl() {
60 let kind = match i.kind.try_to_token_stream() {
61 Ok(kind) => kind,
62 Err(e) => {
63 errors.push(e);
64 continue;
65 }
66 };
67 (quote! {
68 #[automatically_derived]
69 impl #ns { #kind }
70 })
71 .to_tokens(tokens);
72 continue;
73 }
74 }
75 }
76
77 if let Err(e) = i.kind.try_to_tokens(tokens) {
78 errors.push(e);
79 }
80 }
81 for e in self.enums.iter() {
82 e.to_tokens(tokens);
83 }
84
85 Diagnostic::from_vec(errors)?;
86
87 let prefix_json = format!(
94 r#"{{"schema_version":"{}","version":"{}"}}"#,
95 shared::SCHEMA_VERSION,
96 shared::version()
97 );
98
99 let wasm_bindgen = &self.wasm_bindgen;
100
101 let encoded = encode::encode(self)?;
102
103 let encoded_chunks: Vec<_> = encoded
104 .custom_section
105 .iter()
106 .map(|chunk| match chunk {
107 EncodeChunk::EncodedBuf(buf) => {
108 let buf = syn::LitByteStr::new(buf.as_slice(), Span::call_site());
109 quote!(#buf)
110 }
111 EncodeChunk::StrExpr(expr) => {
112 quote!({
114 use #wasm_bindgen::__rt::{encode_u32_to_fixed_len_bytes};
115 const _STR_EXPR: &str = #expr;
116 const _STR_EXPR_BYTES: &[u8] = _STR_EXPR.as_bytes();
117 const _STR_EXPR_BYTES_LEN: usize = _STR_EXPR_BYTES.len() + 5;
118 const _ENCODED_BYTES: [u8; _STR_EXPR_BYTES_LEN] = flat_byte_slices([
119 &encode_u32_to_fixed_len_bytes(_STR_EXPR_BYTES.len() as u32),
120 _STR_EXPR_BYTES,
121 ]);
122 &_ENCODED_BYTES
123 })
124 }
125 })
126 .collect();
127
128 let chunk_len = encoded_chunks.len();
129
130 let encode_bytes = quote!({
132 const _CHUNK_SLICES: [&[u8]; #chunk_len] = [
133 #(#encoded_chunks,)*
134 ];
135 #[allow(long_running_const_eval)]
136 const _CHUNK_LEN: usize = flat_len(_CHUNK_SLICES);
137 #[allow(long_running_const_eval)]
138 const _CHUNKS: [u8; _CHUNK_LEN] = flat_byte_slices(_CHUNK_SLICES);
139
140 const _LEN_BYTES: [u8; 4] = (_CHUNK_LEN as u32).to_le_bytes();
141 const _ENCODED_BYTES_LEN: usize = _CHUNK_LEN + 4;
142 #[allow(long_running_const_eval)]
143 const _ENCODED_BYTES: [u8; _ENCODED_BYTES_LEN] = flat_byte_slices([&_LEN_BYTES, &_CHUNKS]);
144 &_ENCODED_BYTES
145 });
146
147 let file_dependencies = encoded.included_files.iter().map(|file| {
156 let file = file.to_str().unwrap();
157 quote! { include_str!(#file) }
158 });
159
160 let len = prefix_json.len() as u32;
161 let prefix_json_bytes = [&len.to_le_bytes()[..], prefix_json.as_bytes()].concat();
162 let prefix_json_bytes = syn::LitByteStr::new(&prefix_json_bytes, Span::call_site());
163
164 (quote! {
165 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
166 #[automatically_derived]
167 const _: () = {
168 use #wasm_bindgen::__rt::{flat_len, flat_byte_slices};
169
170 static _INCLUDED_FILES: &[&str] = &[#(#file_dependencies),*];
171
172 const _ENCODED_BYTES: &[u8] = #encode_bytes;
173 const _PREFIX_JSON_BYTES: &[u8] = #prefix_json_bytes;
174 const _ENCODED_BYTES_LEN: usize = _ENCODED_BYTES.len();
175 const _PREFIX_JSON_BYTES_LEN: usize = _PREFIX_JSON_BYTES.len();
176 const _LEN: usize = _PREFIX_JSON_BYTES_LEN + _ENCODED_BYTES_LEN;
177
178 #[link_section = "__wasm_bindgen_unstable"]
179 #[allow(long_running_const_eval)]
180 static _GENERATED: [u8; _LEN] = flat_byte_slices([_PREFIX_JSON_BYTES, _ENCODED_BYTES]);
181 };
182 })
183 .to_tokens(tokens);
184
185 Ok(())
186 }
187}
188
189impl TryToTokens for ast::LinkToModule {
190 fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
191 let mut program = TokenStream::new();
192 self.0.try_to_tokens(&mut program)?;
193 let link_function_name = self.0.link_function_name(0);
194 let name = Ident::new(&link_function_name, Span::call_site());
195 let wasm_bindgen = &self.0.wasm_bindgen;
196 let abi_ret = quote! { #wasm_bindgen::convert::WasmRet<<#wasm_bindgen::__rt::alloc::string::String as #wasm_bindgen::convert::FromWasmAbi>::Abi> };
197 let extern_fn = extern_fn(&name, &[], &[], &[], abi_ret);
198 (quote! {
199 {
200 #program
201 #extern_fn
202
203 static __VAL: #wasm_bindgen::__rt::LazyLock<#wasm_bindgen::__rt::alloc::string::String> =
204 #wasm_bindgen::__rt::LazyLock::new(|| unsafe {
205 <#wasm_bindgen::__rt::alloc::string::String as #wasm_bindgen::convert::FromWasmAbi>::from_abi(#name().join())
206 });
207
208 #wasm_bindgen::__rt::alloc::string::String::clone(&__VAL)
209 }
210 })
211 .to_tokens(tokens);
212 Ok(())
213 }
214}
215
216impl ToTokens for ast::Struct {
217 fn to_tokens(&self, tokens: &mut TokenStream) {
218 let name = &self.rust_name;
219 let name_str = self.js_name.to_string();
220 let name_len = name_str.len() as u32;
221 let name_chars: Vec<u32> = name_str.chars().map(|c| c as u32).collect();
222 let new_fn = Ident::new(&shared::new_function(&name_str), Span::call_site());
223 let free_fn = Ident::new(&shared::free_function(&name_str), Span::call_site());
224 let unwrap_fn = Ident::new(&shared::unwrap_function(&name_str), Span::call_site());
225 let wasm_bindgen = &self.wasm_bindgen;
226 (quote! {
227 #[automatically_derived]
228 impl #wasm_bindgen::__rt::marker::SupportsConstructor for #name {}
229 #[automatically_derived]
230 impl #wasm_bindgen::__rt::marker::SupportsInstanceProperty for #name {}
231 #[automatically_derived]
232 impl #wasm_bindgen::__rt::marker::SupportsStaticProperty for #name {}
233
234 #[automatically_derived]
235 impl #wasm_bindgen::describe::WasmDescribe for #name {
236 fn describe() {
237 use #wasm_bindgen::describe::*;
238 inform(RUST_STRUCT);
239 inform(#name_len);
240 #(inform(#name_chars);)*
241 }
242 }
243
244 #[automatically_derived]
245 impl #wasm_bindgen::convert::IntoWasmAbi for #name {
246 type Abi = u32;
247
248 fn into_abi(self) -> u32 {
249 use #wasm_bindgen::__rt::alloc::rc::Rc;
250 use #wasm_bindgen::__rt::WasmRefCell;
251 Rc::into_raw(Rc::new(WasmRefCell::new(self))) as u32
252 }
253 }
254
255 #[automatically_derived]
256 impl #wasm_bindgen::convert::FromWasmAbi for #name {
257 type Abi = u32;
258
259 unsafe fn from_abi(js: u32) -> Self {
260 use #wasm_bindgen::__rt::alloc::rc::Rc;
261 use #wasm_bindgen::__rt::core::result::Result::{Ok, Err};
262 use #wasm_bindgen::__rt::{assert_not_null, WasmRefCell};
263
264 let ptr = js as *mut WasmRefCell<#name>;
265 assert_not_null(ptr);
266 let rc = Rc::from_raw(ptr);
267 match Rc::try_unwrap(rc) {
268 Ok(cell) => cell.into_inner(),
269 Err(_) => #wasm_bindgen::throw_str(
270 "attempted to take ownership of Rust value while it was borrowed"
271 ),
272 }
273 }
274 }
275
276 #[automatically_derived]
277 impl #wasm_bindgen::__rt::core::convert::From<#name> for
278 #wasm_bindgen::JsValue
279 {
280 fn from(value: #name) -> Self {
281 let ptr = #wasm_bindgen::convert::IntoWasmAbi::into_abi(value);
282
283 #[link(wasm_import_module = "__wbindgen_placeholder__")]
284 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
285 extern "C" {
286 fn #new_fn(ptr: u32) -> u32;
287 }
288
289 #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
290 unsafe fn #new_fn(_: u32) -> u32 {
291 panic!("cannot convert to JsValue outside of the Wasm target")
292 }
293
294 unsafe {
295 <#wasm_bindgen::JsValue as #wasm_bindgen::convert::FromWasmAbi>
296 ::from_abi(#new_fn(ptr))
297 }
298 }
299 }
300
301 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
302 #[automatically_derived]
303 const _: () = {
304 #wasm_bindgen::__wbindgen_coverage! {
305 #[no_mangle]
306 #[doc(hidden)]
307 pub unsafe extern "C" fn #free_fn(ptr: u32, allow_delayed: u32) {
310 use #wasm_bindgen::__rt::alloc::rc::Rc;
311
312 if allow_delayed != 0 {
313 let ptr = ptr as *mut #wasm_bindgen::__rt::WasmRefCell<#name>;
316 #wasm_bindgen::__rt::assert_not_null(ptr);
317 drop(Rc::from_raw(ptr));
318 } else {
319 let _ = <#name as #wasm_bindgen::convert::FromWasmAbi>::from_abi(ptr);
321 }
322 }
323 }
324 };
325
326 #[automatically_derived]
327 impl #wasm_bindgen::convert::RefFromWasmAbi for #name {
328 type Abi = u32;
329 type Anchor = #wasm_bindgen::__rt::RcRef<#name>;
330
331 unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
332 use #wasm_bindgen::__rt::alloc::rc::Rc;
333
334 let js = js as *mut #wasm_bindgen::__rt::WasmRefCell<#name>;
335 #wasm_bindgen::__rt::assert_not_null(js);
336
337 Rc::increment_strong_count(js);
338 let rc = Rc::from_raw(js);
339 #wasm_bindgen::__rt::RcRef::new(rc)
340 }
341 }
342
343 #[automatically_derived]
344 impl #wasm_bindgen::convert::RefMutFromWasmAbi for #name {
345 type Abi = u32;
346 type Anchor = #wasm_bindgen::__rt::RcRefMut<#name>;
347
348 unsafe fn ref_mut_from_abi(js: Self::Abi) -> Self::Anchor {
349 use #wasm_bindgen::__rt::alloc::rc::Rc;
350
351 let js = js as *mut #wasm_bindgen::__rt::WasmRefCell<#name>;
352 #wasm_bindgen::__rt::assert_not_null(js);
353
354 Rc::increment_strong_count(js);
355 let rc = Rc::from_raw(js);
356 #wasm_bindgen::__rt::RcRefMut::new(rc)
357 }
358 }
359
360 #[automatically_derived]
361 impl #wasm_bindgen::convert::LongRefFromWasmAbi for #name {
362 type Abi = u32;
363 type Anchor = #wasm_bindgen::__rt::RcRef<#name>;
364
365 unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor {
366 <Self as #wasm_bindgen::convert::RefFromWasmAbi>::ref_from_abi(js)
367 }
368 }
369
370 #[automatically_derived]
371 impl #wasm_bindgen::convert::OptionIntoWasmAbi for #name {
372 #[inline]
373 fn none() -> Self::Abi { 0 }
374 }
375
376 #[automatically_derived]
377 impl #wasm_bindgen::convert::OptionFromWasmAbi for #name {
378 #[inline]
379 fn is_none(abi: &Self::Abi) -> bool { *abi == 0 }
380 }
381
382 #[automatically_derived]
383 impl #wasm_bindgen::convert::TryFromJsValue for #name {
384 type Error = #wasm_bindgen::JsValue;
385
386 fn try_from_js_value(value: #wasm_bindgen::JsValue)
387 -> #wasm_bindgen::__rt::core::result::Result<Self, Self::Error> {
388 let idx = #wasm_bindgen::convert::IntoWasmAbi::into_abi(&value);
389
390 #[link(wasm_import_module = "__wbindgen_placeholder__")]
391 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
392 extern "C" {
393 fn #unwrap_fn(ptr: u32) -> u32;
394 }
395
396 #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
397 unsafe fn #unwrap_fn(_: u32) -> u32 {
398 panic!("cannot convert from JsValue outside of the Wasm target")
399 }
400
401 let ptr = unsafe { #unwrap_fn(idx) };
402 if ptr == 0 {
403 #wasm_bindgen::__rt::core::result::Result::Err(value)
404 } else {
405 #[allow(clippy::mem_forget)]
407 #wasm_bindgen::__rt::core::mem::forget(value);
408 unsafe {
409 #wasm_bindgen::__rt::core::result::Result::Ok(
410 <Self as #wasm_bindgen::convert::FromWasmAbi>::from_abi(ptr)
411 )
412 }
413 }
414 }
415 }
416
417 #[automatically_derived]
418 impl #wasm_bindgen::describe::WasmDescribeVector for #name {
419 fn describe_vector() {
420 use #wasm_bindgen::describe::*;
421 inform(VECTOR);
422 inform(NAMED_EXTERNREF);
423 inform(#name_len);
424 #(inform(#name_chars);)*
425 }
426 }
427
428 #[automatically_derived]
429 impl #wasm_bindgen::convert::VectorIntoWasmAbi for #name {
430 type Abi = <
431 #wasm_bindgen::__rt::alloc::boxed::Box<[#wasm_bindgen::JsValue]>
432 as #wasm_bindgen::convert::IntoWasmAbi
433 >::Abi;
434
435 fn vector_into_abi(
436 vector: #wasm_bindgen::__rt::alloc::boxed::Box<[#name]>
437 ) -> Self::Abi {
438 #wasm_bindgen::convert::js_value_vector_into_abi(vector)
439 }
440 }
441
442 #[automatically_derived]
443 impl #wasm_bindgen::convert::VectorFromWasmAbi for #name {
444 type Abi = <
445 #wasm_bindgen::__rt::alloc::boxed::Box<[#wasm_bindgen::JsValue]>
446 as #wasm_bindgen::convert::FromWasmAbi
447 >::Abi;
448
449 unsafe fn vector_from_abi(
450 js: Self::Abi
451 ) -> #wasm_bindgen::__rt::alloc::boxed::Box<[#name]> {
452 #wasm_bindgen::convert::js_value_vector_from_abi(js)
453 }
454 }
455
456 #[automatically_derived]
457 impl #wasm_bindgen::__rt::VectorIntoJsValue for #name {
458 fn vector_into_jsvalue(vector: #wasm_bindgen::__rt::alloc::boxed::Box<[#name]>) -> #wasm_bindgen::JsValue {
459 #wasm_bindgen::__rt::js_value_vector_into_jsvalue(vector)
460 }
461 }
462 })
463 .to_tokens(tokens);
464
465 for field in self.fields.iter() {
466 field.to_tokens(tokens);
467 }
468 }
469}
470
471impl ToTokens for ast::StructField {
472 fn to_tokens(&self, tokens: &mut TokenStream) {
473 let rust_name = &self.rust_name;
474 let struct_name = &self.struct_name;
475 let ty = &self.ty;
476 let getter = &self.getter;
477 let setter = &self.setter;
478
479 let maybe_assert_copy = if self.getter_with_clone.is_some() {
480 quote! {}
481 } else {
482 quote! { assert_copy::<#ty>() }
483 };
484 let maybe_assert_copy = respan(maybe_assert_copy, ty);
485
486 let js_token = quote! { js };
493 let mut val = quote_spanned!(self.rust_name.span()=> (*#js_token).borrow().#rust_name);
494 if let Some(span) = self.getter_with_clone {
495 val = quote_spanned!(span=> <#ty as Clone>::clone(&#val) );
496 }
497
498 let wasm_bindgen = &self.wasm_bindgen;
499
500 (quote! {
501 #[automatically_derived]
502 const _: () = {
503 #wasm_bindgen::__wbindgen_coverage! {
504 #[cfg_attr(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")), no_mangle)]
505 #[doc(hidden)]
506 pub unsafe extern "C" fn #getter(js: u32)
507 -> #wasm_bindgen::convert::WasmRet<<#ty as #wasm_bindgen::convert::IntoWasmAbi>::Abi>
508 {
509 use #wasm_bindgen::__rt::{WasmRefCell, assert_not_null};
510 use #wasm_bindgen::convert::IntoWasmAbi;
511
512 fn assert_copy<T: Copy>(){}
513 #maybe_assert_copy;
514
515 let js = js as *mut WasmRefCell<#struct_name>;
516 assert_not_null(js);
517 let val = #val;
518 <#ty as IntoWasmAbi>::into_abi(val).into()
519 }
520 }
521 };
522 })
523 .to_tokens(tokens);
524
525 Descriptor {
526 ident: getter,
527 inner: quote! {
528 <#ty as WasmDescribe>::describe();
529 },
530 attrs: vec![],
531 wasm_bindgen: &self.wasm_bindgen,
532 }
533 .to_tokens(tokens);
534
535 if self.readonly {
536 return;
537 }
538
539 let abi = quote! { <#ty as #wasm_bindgen::convert::FromWasmAbi>::Abi };
540 let (args, names) = splat(wasm_bindgen, &Ident::new("val", rust_name.span()), &abi);
541
542 (quote! {
543 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
544 #[automatically_derived]
545 const _: () = {
546 #wasm_bindgen::__wbindgen_coverage! {
547 #[no_mangle]
548 #[doc(hidden)]
549 pub unsafe extern "C" fn #setter(
550 js: u32,
551 #(#args,)*
552 ) {
553 use #wasm_bindgen::__rt::{WasmRefCell, assert_not_null};
554 use #wasm_bindgen::convert::FromWasmAbi;
555
556 let js = js as *mut WasmRefCell<#struct_name>;
557 assert_not_null(js);
558 let val = <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#names),*);
559 let val = <#ty as FromWasmAbi>::from_abi(val);
560 (*js).borrow_mut().#rust_name = val;
561 }
562 }
563 };
564 })
565 .to_tokens(tokens);
566 }
567}
568
569impl TryToTokens for ast::Export {
570 fn try_to_tokens(self: &ast::Export, into: &mut TokenStream) -> Result<(), Diagnostic> {
571 let generated_name = self.rust_symbol();
572 let export_name = self.export_name();
573 let mut args = vec![];
574 let mut arg_conversions = vec![];
575 let mut converted_arguments = vec![];
576 let ret = Ident::new("_ret", Span::call_site());
577
578 let offset = if self.method_self.is_some() {
579 args.push(quote! { me: u32 });
580 1
581 } else {
582 0
583 };
584
585 let name = &self.rust_name;
586 let wasm_bindgen = &self.wasm_bindgen;
587 let wasm_bindgen_futures = &self.wasm_bindgen_futures;
588 let receiver = match self.method_self {
589 Some(ast::MethodSelf::ByValue) => {
590 let class = self.rust_class.as_ref().unwrap();
591 arg_conversions.push(quote! {
592 let me = unsafe {
593 <#class as #wasm_bindgen::convert::FromWasmAbi>::from_abi(me)
594 };
595 });
596 quote! { me.#name }
597 }
598 Some(ast::MethodSelf::RefMutable) => {
599 let class = self.rust_class.as_ref().unwrap();
600 arg_conversions.push(quote! {
601 let mut me = unsafe {
602 <#class as #wasm_bindgen::convert::RefMutFromWasmAbi>
603 ::ref_mut_from_abi(me)
604 };
605 let me = &mut *me;
606 });
607 quote! { me.#name }
608 }
609 Some(ast::MethodSelf::RefShared) => {
610 let class = self.rust_class.as_ref().unwrap();
611 let (trait_, func, borrow) = if self.function.r#async {
612 (
613 quote!(LongRefFromWasmAbi),
614 quote!(long_ref_from_abi),
615 quote!(
616 <<#class as #wasm_bindgen::convert::LongRefFromWasmAbi>
617 ::Anchor as #wasm_bindgen::__rt::core::borrow::Borrow<#class>>
618 ::borrow(&me)
619 ),
620 )
621 } else {
622 (quote!(RefFromWasmAbi), quote!(ref_from_abi), quote!(&*me))
623 };
624 arg_conversions.push(quote! {
625 let me = unsafe {
626 <#class as #wasm_bindgen::convert::#trait_>::#func(me)
627 };
628 let me = #borrow;
629 });
630 quote! { me.#name }
631 }
632 None => match &self.rust_class {
633 Some(class) => quote! { #class::#name },
634 None => quote! { #name },
635 },
636 };
637
638 let mut argtys = Vec::new();
639 for (i, arg) in self.function.arguments.iter().enumerate() {
640 argtys.push(&*arg.pat_type.ty);
641 let i = i + offset;
642 let ident = Ident::new(&format!("arg{}", i), Span::call_site());
643 fn unwrap_nested_types(ty: &syn::Type) -> &syn::Type {
644 match &ty {
645 syn::Type::Group(syn::TypeGroup { ref elem, .. }) => unwrap_nested_types(elem),
646 syn::Type::Paren(syn::TypeParen { ref elem, .. }) => unwrap_nested_types(elem),
647 _ => ty,
648 }
649 }
650 let ty = unwrap_nested_types(&arg.pat_type.ty);
651
652 match &ty {
653 syn::Type::Reference(syn::TypeReference {
654 mutability: Some(_),
655 elem,
656 ..
657 }) => {
658 let abi = quote! { <#elem as #wasm_bindgen::convert::RefMutFromWasmAbi>::Abi };
659 let (prim_args, prim_names) = splat(wasm_bindgen, &ident, &abi);
660 args.extend(prim_args);
661 arg_conversions.push(quote! {
662 let mut #ident = unsafe {
663 <#elem as #wasm_bindgen::convert::RefMutFromWasmAbi>
664 ::ref_mut_from_abi(
665 <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#prim_names),*)
666 )
667 };
668 let #ident = &mut *#ident;
669 });
670 }
671 syn::Type::Reference(syn::TypeReference { elem, .. }) => {
672 if self.function.r#async {
673 let abi =
674 quote! { <#elem as #wasm_bindgen::convert::LongRefFromWasmAbi>::Abi };
675 let (prim_args, prim_names) = splat(wasm_bindgen, &ident, &abi);
676 args.extend(prim_args);
677 arg_conversions.push(quote! {
678 let #ident = unsafe {
679 <#elem as #wasm_bindgen::convert::LongRefFromWasmAbi>
680 ::long_ref_from_abi(
681 <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#prim_names),*)
682 )
683 };
684 let #ident = <<#elem as #wasm_bindgen::convert::LongRefFromWasmAbi>
685 ::Anchor as core::borrow::Borrow<#elem>>
686 ::borrow(&#ident);
687 });
688 } else {
689 let abi = quote! { <#elem as #wasm_bindgen::convert::RefFromWasmAbi>::Abi };
690 let (prim_args, prim_names) = splat(wasm_bindgen, &ident, &abi);
691 args.extend(prim_args);
692 arg_conversions.push(quote! {
693 let #ident = unsafe {
694 <#elem as #wasm_bindgen::convert::RefFromWasmAbi>
695 ::ref_from_abi(
696 <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#prim_names),*)
697 )
698 };
699 let #ident = &*#ident;
700 });
701 }
702 }
703 _ => {
704 let abi = quote! { <#ty as #wasm_bindgen::convert::FromWasmAbi>::Abi };
705 let (prim_args, prim_names) = splat(wasm_bindgen, &ident, &abi);
706 args.extend(prim_args);
707 arg_conversions.push(quote! {
708 let #ident = unsafe {
709 <#ty as #wasm_bindgen::convert::FromWasmAbi>
710 ::from_abi(
711 <#abi as #wasm_bindgen::convert::WasmAbi>::join(#(#prim_names),*)
712 )
713 };
714 });
715 }
716 }
717 converted_arguments.push(quote! { #ident });
718 }
719 let syn_unit = syn::Type::Tuple(syn::TypeTuple {
720 elems: Default::default(),
721 paren_token: Default::default(),
722 });
723 let syn_ret = self
724 .function
725 .ret
726 .as_ref()
727 .map(|ret| &ret.r#type)
728 .unwrap_or(&syn_unit);
729 if let syn::Type::Reference(_) = syn_ret {
730 bail_span!(syn_ret, "cannot return a borrowed ref with #[wasm_bindgen]",)
731 }
732
733 let (ret_ty, inner_ret_ty, ret_expr) = if self.function.r#async {
737 if self.start {
738 (
739 quote! { () },
740 quote! { () },
741 quote! {
742 <#syn_ret as #wasm_bindgen::__rt::Start>::start(#ret.await)
743 },
744 )
745 } else {
746 (
747 quote! { #wasm_bindgen::JsValue },
748 quote! { #syn_ret },
749 quote! {
750 <#syn_ret as #wasm_bindgen::__rt::IntoJsResult>::into_js_result(#ret.await)
751 },
752 )
753 }
754 } else if self.start {
755 (
756 quote! { () },
757 quote! { () },
758 quote! { <#syn_ret as #wasm_bindgen::__rt::Start>::start(#ret) },
759 )
760 } else {
761 (quote! { #syn_ret }, quote! { #syn_ret }, quote! { #ret })
762 };
763
764 let mut call = quote! {
765 {
766 #(#arg_conversions)*
767 let #ret = #receiver(#(#converted_arguments),*);
768 #ret_expr
769 }
770 };
771
772 if self.function.r#async {
773 if self.start {
774 call = quote! {
775 #wasm_bindgen_futures::spawn_local(async move {
776 #call
777 })
778 }
779 } else {
780 call = quote! {
781 #wasm_bindgen_futures::future_to_promise(async move {
782 #call
783 }).into()
784 }
785 }
786 }
787
788 let projection = quote! { <#ret_ty as #wasm_bindgen::convert::ReturnWasmAbi> };
789 let convert_ret = quote! { #projection::return_abi(#ret).into() };
790 let describe_ret = quote! {
791 <#ret_ty as WasmDescribe>::describe();
792 <#inner_ret_ty as WasmDescribe>::describe();
793 };
794 let nargs = self.function.arguments.len() as u32;
795 let attrs = &self.function.rust_attrs;
796
797 let mut checks = Vec::new();
798 if self.start {
799 checks.push(quote! { const _ASSERT: fn() = || -> #projection::Abi { loop {} }; });
800 };
801
802 if let Some(class) = self.rust_class.as_ref() {
803 let mut add_check = |token_stream| {
806 checks.push(respan(token_stream, &self.rust_name));
807 };
808
809 match &self.method_kind {
810 ast::MethodKind::Constructor => {
811 add_check(quote! {
812 let _: #wasm_bindgen::__rt::marker::CheckSupportsConstructor<#class>;
813 });
814 }
815 ast::MethodKind::Operation(operation) => match operation.kind {
816 ast::OperationKind::Getter(_) | ast::OperationKind::Setter(_) => {
817 if operation.is_static {
818 add_check(quote! {
819 let _: #wasm_bindgen::__rt::marker::CheckSupportsStaticProperty<#class>;
820 });
821 } else {
822 add_check(quote! {
823 let _: #wasm_bindgen::__rt::marker::CheckSupportsInstanceProperty<#class>;
824 });
825 }
826 }
827 _ => {}
828 },
829 }
830 }
831
832 (quote! {
833 #[automatically_derived]
834 const _: () = {
835 #wasm_bindgen::__wbindgen_coverage! {
836 #(#attrs)*
837 #[cfg_attr(
838 all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")),
839 export_name = #export_name,
840 )]
841 pub unsafe extern "C" fn #generated_name(#(#args),*) -> #wasm_bindgen::convert::WasmRet<#projection::Abi> {
842 const _: () = {
843 #(#checks)*
844 };
845
846 let #ret = #call;
847 #convert_ret
848 }
849 }
850 };
851 })
852 .to_tokens(into);
853
854 let describe_args: TokenStream = argtys
855 .iter()
856 .map(|ty| match ty {
857 syn::Type::Reference(reference)
858 if self.function.r#async && reference.mutability.is_none() =>
859 {
860 let inner = &reference.elem;
861 quote! {
862 inform(LONGREF);
863 <#inner as WasmDescribe>::describe();
864 }
865 }
866 _ => quote! { <#ty as WasmDescribe>::describe(); },
867 })
868 .collect();
869
870 let export = Ident::new(&export_name, Span::call_site());
887 Descriptor {
888 ident: &export,
889 inner: quote! {
890 inform(FUNCTION);
891 inform(0);
892 inform(#nargs);
893 #describe_args
894 #describe_ret
895 },
896 attrs: attrs.clone(),
897 wasm_bindgen: &self.wasm_bindgen,
898 }
899 .to_tokens(into);
900
901 Ok(())
902 }
903}
904
905impl TryToTokens for ast::ImportKind {
906 fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
907 match *self {
908 ast::ImportKind::Function(ref f) => f.try_to_tokens(tokens)?,
909 ast::ImportKind::Static(ref s) => s.to_tokens(tokens),
910 ast::ImportKind::String(ref s) => s.to_tokens(tokens),
911 ast::ImportKind::Type(ref t) => t.to_tokens(tokens),
912 ast::ImportKind::Enum(ref e) => e.to_tokens(tokens),
913 }
914
915 Ok(())
916 }
917}
918
919impl ToTokens for ast::ImportType {
920 fn to_tokens(&self, tokens: &mut TokenStream) {
921 let vis = &self.vis;
922 let rust_name = &self.rust_name;
923 let attrs = &self.attrs;
924 let doc_comment = match &self.doc_comment {
925 None => "",
926 Some(comment) => comment,
927 };
928 let instanceof_shim = Ident::new(&self.instanceof_shim, Span::call_site());
929
930 let wasm_bindgen = &self.wasm_bindgen;
931 let internal_obj = match self.extends.first() {
932 Some(target) => {
933 quote! { #target }
934 }
935 None => {
936 quote! { #wasm_bindgen::JsValue }
937 }
938 };
939
940 let description = if let Some(typescript_type) = &self.typescript_type {
941 let typescript_type_len = typescript_type.len() as u32;
942 let typescript_type_chars = typescript_type.chars().map(|c| c as u32);
943 quote! {
944 use #wasm_bindgen::describe::*;
945 inform(NAMED_EXTERNREF);
946 inform(#typescript_type_len);
947 #(inform(#typescript_type_chars);)*
948 }
949 } else {
950 quote! {
951 JsValue::describe()
952 }
953 };
954
955 let is_type_of = self.is_type_of.as_ref().map(|is_type_of| {
956 quote! {
957 #[inline]
958 fn is_type_of(val: &JsValue) -> bool {
959 let is_type_of: fn(&JsValue) -> bool = #is_type_of;
960 is_type_of(val)
961 }
962 }
963 });
964
965 let no_deref = self.no_deref;
966
967 let doc = if doc_comment.is_empty() {
968 quote! {}
969 } else {
970 quote! {
971 #[doc = #doc_comment]
972 }
973 };
974
975 (quote! {
976 #[automatically_derived]
977 #(#attrs)*
978 #doc
979 #[repr(transparent)]
980 #vis struct #rust_name {
981 obj: #internal_obj
982 }
983
984 #[automatically_derived]
985 const _: () = {
986 use #wasm_bindgen::convert::TryFromJsValue;
987 use #wasm_bindgen::convert::{IntoWasmAbi, FromWasmAbi};
988 use #wasm_bindgen::convert::{OptionIntoWasmAbi, OptionFromWasmAbi};
989 use #wasm_bindgen::convert::{RefFromWasmAbi, LongRefFromWasmAbi};
990 use #wasm_bindgen::describe::WasmDescribe;
991 use #wasm_bindgen::{JsValue, JsCast, JsObject};
992 use #wasm_bindgen::__rt::core;
993
994 #[automatically_derived]
995 impl WasmDescribe for #rust_name {
996 fn describe() {
997 #description
998 }
999 }
1000
1001 #[automatically_derived]
1002 impl IntoWasmAbi for #rust_name {
1003 type Abi = <JsValue as IntoWasmAbi>::Abi;
1004
1005 #[inline]
1006 fn into_abi(self) -> Self::Abi {
1007 self.obj.into_abi()
1008 }
1009 }
1010
1011 #[automatically_derived]
1012 impl OptionIntoWasmAbi for #rust_name {
1013 #[inline]
1014 fn none() -> Self::Abi {
1015 0
1016 }
1017 }
1018
1019 #[automatically_derived]
1020 impl<'a> OptionIntoWasmAbi for &'a #rust_name {
1021 #[inline]
1022 fn none() -> Self::Abi {
1023 0
1024 }
1025 }
1026
1027 #[automatically_derived]
1028 impl FromWasmAbi for #rust_name {
1029 type Abi = <JsValue as FromWasmAbi>::Abi;
1030
1031 #[inline]
1032 unsafe fn from_abi(js: Self::Abi) -> Self {
1033 #rust_name {
1034 obj: JsValue::from_abi(js).into(),
1035 }
1036 }
1037 }
1038
1039 #[automatically_derived]
1040 impl OptionFromWasmAbi for #rust_name {
1041 #[inline]
1042 fn is_none(abi: &Self::Abi) -> bool { *abi == 0 }
1043 }
1044
1045 #[automatically_derived]
1046 impl<'a> IntoWasmAbi for &'a #rust_name {
1047 type Abi = <&'a JsValue as IntoWasmAbi>::Abi;
1048
1049 #[inline]
1050 fn into_abi(self) -> Self::Abi {
1051 (&self.obj).into_abi()
1052 }
1053 }
1054
1055 #[automatically_derived]
1056 impl RefFromWasmAbi for #rust_name {
1057 type Abi = <JsValue as RefFromWasmAbi>::Abi;
1058 type Anchor = core::mem::ManuallyDrop<#rust_name>;
1059
1060 #[inline]
1061 unsafe fn ref_from_abi(js: Self::Abi) -> Self::Anchor {
1062 let tmp = <JsValue as RefFromWasmAbi>::ref_from_abi(js);
1063 core::mem::ManuallyDrop::new(#rust_name {
1064 obj: core::mem::ManuallyDrop::into_inner(tmp).into(),
1065 })
1066 }
1067 }
1068
1069 #[automatically_derived]
1070 impl LongRefFromWasmAbi for #rust_name {
1071 type Abi = <JsValue as LongRefFromWasmAbi>::Abi;
1072 type Anchor = #rust_name;
1073
1074 #[inline]
1075 unsafe fn long_ref_from_abi(js: Self::Abi) -> Self::Anchor {
1076 let tmp = <JsValue as LongRefFromWasmAbi>::long_ref_from_abi(js);
1077 #rust_name { obj: tmp.into() }
1078 }
1079 }
1080
1081 #[automatically_derived]
1083 impl From<JsValue> for #rust_name {
1084 #[inline]
1085 fn from(obj: JsValue) -> #rust_name {
1086 #rust_name { obj: obj.into() }
1087 }
1088 }
1089
1090 #[automatically_derived]
1091 impl AsRef<JsValue> for #rust_name {
1092 #[inline]
1093 fn as_ref(&self) -> &JsValue { self.obj.as_ref() }
1094 }
1095
1096 #[automatically_derived]
1097 impl AsRef<#rust_name> for #rust_name {
1098 #[inline]
1099 fn as_ref(&self) -> &#rust_name { self }
1100 }
1101
1102
1103 #[automatically_derived]
1104 impl From<#rust_name> for JsValue {
1105 #[inline]
1106 fn from(obj: #rust_name) -> JsValue {
1107 obj.obj.into()
1108 }
1109 }
1110
1111 #[automatically_derived]
1112 impl JsCast for #rust_name {
1113 fn instanceof(val: &JsValue) -> bool {
1114 #[link(wasm_import_module = "__wbindgen_placeholder__")]
1115 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1116 extern "C" {
1117 fn #instanceof_shim(val: u32) -> u32;
1118 }
1119 #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
1120 unsafe fn #instanceof_shim(_: u32) -> u32 {
1121 panic!("cannot check instanceof on non-wasm targets");
1122 }
1123 unsafe {
1124 let idx = val.into_abi();
1125 #instanceof_shim(idx) != 0
1126 }
1127 }
1128
1129 #is_type_of
1130
1131 #[inline]
1132 fn unchecked_from_js(val: JsValue) -> Self {
1133 #rust_name { obj: val.into() }
1134 }
1135
1136 #[inline]
1137 fn unchecked_from_js_ref(val: &JsValue) -> &Self {
1138 unsafe { &*(val as *const JsValue as *const #rust_name) }
1141 }
1142 }
1143
1144 impl JsObject for #rust_name {}
1145 };
1146 })
1147 .to_tokens(tokens);
1148
1149 if !no_deref {
1150 (quote! {
1151 #[automatically_derived]
1152 impl core::ops::Deref for #rust_name {
1153 type Target = #internal_obj;
1154
1155 #[inline]
1156 fn deref(&self) -> &#internal_obj {
1157 &self.obj
1158 }
1159 }
1160 })
1161 .to_tokens(tokens);
1162 }
1163
1164 for superclass in self.extends.iter() {
1165 (quote! {
1166 #[automatically_derived]
1167 impl From<#rust_name> for #superclass {
1168 #[inline]
1169 fn from(obj: #rust_name) -> #superclass {
1170 use #wasm_bindgen::JsCast;
1171 #superclass::unchecked_from_js(obj.into())
1172 }
1173 }
1174
1175 #[automatically_derived]
1176 impl AsRef<#superclass> for #rust_name {
1177 #[inline]
1178 fn as_ref(&self) -> &#superclass {
1179 use #wasm_bindgen::JsCast;
1180 #superclass::unchecked_from_js_ref(self.as_ref())
1181 }
1182 }
1183 })
1184 .to_tokens(tokens);
1185 }
1186 }
1187}
1188
1189impl ToTokens for ast::StringEnum {
1190 fn to_tokens(&self, tokens: &mut TokenStream) {
1191 let vis = &self.vis;
1192 let enum_name = &self.name;
1193 let name_str = &self.js_name;
1194 let name_len = name_str.len() as u32;
1195 let name_chars = name_str.chars().map(u32::from);
1196 let variants = &self.variants;
1197 let variant_count = self.variant_values.len() as u32;
1198 let variant_values = &self.variant_values;
1199 let variant_indices = (0..variant_count).collect::<Vec<_>>();
1200 let invalid = variant_count;
1201 let hole = variant_count + 1;
1202 let attrs = &self.rust_attrs;
1203
1204 let invalid_to_str_msg = format!(
1205 "Converting an invalid string enum ({}) back to a string is currently not supported",
1206 enum_name
1207 );
1208
1209 let variant_paths: Vec<TokenStream> = self
1211 .variants
1212 .iter()
1213 .map(|v| quote!(#enum_name::#v).into_token_stream())
1214 .collect();
1215
1216 let variant_paths_ref = &variant_paths;
1218
1219 let wasm_bindgen = &self.wasm_bindgen;
1220
1221 (quote! {
1222 #(#attrs)*
1223 #[non_exhaustive]
1224 #[repr(u32)]
1225 #vis enum #enum_name {
1226 #(#variants = #variant_indices,)*
1227 #[automatically_derived]
1228 #[doc(hidden)]
1229 __Invalid
1230 }
1231
1232 #[automatically_derived]
1233 impl #enum_name {
1234 fn from_str(s: &str) -> Option<#enum_name> {
1235 match s {
1236 #(#variant_values => Some(#variant_paths_ref),)*
1237 _ => None,
1238 }
1239 }
1240
1241 fn to_str(&self) -> &'static str {
1242 match self {
1243 #(#variant_paths_ref => #variant_values,)*
1244 #enum_name::__Invalid => panic!(#invalid_to_str_msg),
1245 }
1246 }
1247
1248 #vis fn from_js_value(obj: &#wasm_bindgen::JsValue) -> Option<#enum_name> {
1249 obj.as_string().and_then(|obj_str| Self::from_str(obj_str.as_str()))
1250 }
1251 }
1252
1253 #[automatically_derived]
1254 impl #wasm_bindgen::convert::IntoWasmAbi for #enum_name {
1255 type Abi = u32;
1256
1257 #[inline]
1258 fn into_abi(self) -> u32 {
1259 self as u32
1260 }
1261 }
1262
1263 #[automatically_derived]
1264 impl #wasm_bindgen::convert::FromWasmAbi for #enum_name {
1265 type Abi = u32;
1266
1267 unsafe fn from_abi(val: u32) -> Self {
1268 match val {
1269 #(#variant_indices => #variant_paths_ref,)*
1270 #invalid => #enum_name::__Invalid,
1271 _ => unreachable!("The JS binding should only ever produce a valid value or the specific 'invalid' value"),
1272 }
1273 }
1274 }
1275
1276 #[automatically_derived]
1277 impl #wasm_bindgen::convert::OptionFromWasmAbi for #enum_name {
1278 #[inline]
1279 fn is_none(val: &u32) -> bool { *val == #hole }
1280 }
1281
1282 #[automatically_derived]
1283 impl #wasm_bindgen::convert::OptionIntoWasmAbi for #enum_name {
1284 #[inline]
1285 fn none() -> Self::Abi { #hole }
1286 }
1287
1288 #[automatically_derived]
1289 impl #wasm_bindgen::describe::WasmDescribe for #enum_name {
1290 fn describe() {
1291 use #wasm_bindgen::describe::*;
1292 inform(STRING_ENUM);
1293 inform(#name_len);
1294 #(inform(#name_chars);)*
1295 inform(#variant_count);
1296 }
1297 }
1298
1299 #[automatically_derived]
1300 impl #wasm_bindgen::__rt::core::convert::From<#enum_name> for
1301 #wasm_bindgen::JsValue
1302 {
1303 fn from(val: #enum_name) -> Self {
1304 #wasm_bindgen::JsValue::from_str(val.to_str())
1305 }
1306 }
1307 })
1308 .to_tokens(tokens);
1309 }
1310}
1311
1312impl TryToTokens for ast::ImportFunction {
1313 fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic> {
1314 let mut class_ty = None;
1315 let mut is_method = false;
1316 match self.kind {
1317 ast::ImportFunctionKind::Method {
1318 ref ty, ref kind, ..
1319 } => {
1320 if let ast::MethodKind::Operation(ast::Operation {
1321 is_static: false, ..
1322 }) = kind
1323 {
1324 is_method = true;
1325 }
1326 class_ty = Some(ty);
1327 }
1328 ast::ImportFunctionKind::Normal => {}
1329 }
1330 let vis = &self.function.rust_vis;
1331 let ret = match self.function.ret.as_ref().map(|ret| &ret.r#type) {
1332 Some(ty) => quote! { -> #ty },
1333 None => quote!(),
1334 };
1335
1336 let mut abi_argument_names = Vec::new();
1337 let mut abi_arguments = Vec::new();
1338 let mut arg_conversions = Vec::new();
1339 let mut arguments = Vec::new();
1340 let ret_ident = Ident::new("_ret", Span::call_site());
1341 let wasm_bindgen = &self.wasm_bindgen;
1342 let wasm_bindgen_futures = &self.wasm_bindgen_futures;
1343
1344 for (i, arg) in self.function.arguments.iter().enumerate() {
1345 let ty = &arg.pat_type.ty;
1346 let name = match &*arg.pat_type.pat {
1347 syn::Pat::Ident(syn::PatIdent {
1348 by_ref: None,
1349 ident,
1350 subpat: None,
1351 ..
1352 }) => ident.clone(),
1353 syn::Pat::Wild(_) => syn::Ident::new(&format!("__genarg_{}", i), Span::call_site()),
1354 _ => bail_span!(
1355 arg.pat_type.pat,
1356 "unsupported pattern in #[wasm_bindgen] imported function",
1357 ),
1358 };
1359
1360 let abi = quote! { <#ty as #wasm_bindgen::convert::IntoWasmAbi>::Abi };
1361 let (prim_args, prim_names) = splat(wasm_bindgen, &name, &abi);
1362 abi_arguments.extend(prim_args);
1363 abi_argument_names.extend(prim_names.iter().cloned());
1364
1365 let var = if i == 0 && is_method {
1366 quote! { self }
1367 } else {
1368 arguments.push(quote! { #name: #ty });
1369 quote! { #name }
1370 };
1371 arg_conversions.push(quote! {
1372 let #name = <#ty as #wasm_bindgen::convert::IntoWasmAbi>
1373 ::into_abi(#var);
1374 let (#(#prim_names),*) = <#abi as #wasm_bindgen::convert::WasmAbi>::split(#name);
1375 });
1376 }
1377 let abi_ret;
1378 let mut convert_ret;
1379 match &self.js_ret {
1380 Some(syn::Type::Reference(_)) => {
1381 bail_span!(
1382 self.js_ret,
1383 "cannot return references in #[wasm_bindgen] imports yet"
1384 );
1385 }
1386 Some(ref ty) => {
1387 if self.function.r#async {
1388 abi_ret = quote! {
1389 #wasm_bindgen::convert::WasmRet<<#wasm_bindgen_futures::js_sys::Promise as #wasm_bindgen::convert::FromWasmAbi>::Abi>
1390 };
1391 let future = quote! {
1392 #wasm_bindgen_futures::JsFuture::from(
1393 <#wasm_bindgen_futures::js_sys::Promise as #wasm_bindgen::convert::FromWasmAbi>
1394 ::from_abi(#ret_ident.join())
1395 ).await
1396 };
1397 convert_ret = if self.catch {
1398 quote! { Ok(#wasm_bindgen::JsCast::unchecked_from_js(#future?)) }
1399 } else {
1400 quote! { #wasm_bindgen::JsCast::unchecked_from_js(#future.expect("unexpected exception")) }
1401 };
1402 } else {
1403 abi_ret = quote! {
1404 #wasm_bindgen::convert::WasmRet<<#ty as #wasm_bindgen::convert::FromWasmAbi>::Abi>
1405 };
1406 convert_ret = quote! {
1407 <#ty as #wasm_bindgen::convert::FromWasmAbi>
1408 ::from_abi(#ret_ident.join())
1409 };
1410 }
1411 }
1412 None => {
1413 if self.function.r#async {
1414 abi_ret = quote! {
1415 #wasm_bindgen::convert::WasmRet<<#wasm_bindgen_futures::js_sys::Promise as #wasm_bindgen::convert::FromWasmAbi>::Abi>
1416 };
1417 let future = quote! {
1418 #wasm_bindgen_futures::JsFuture::from(
1419 <#wasm_bindgen_futures::js_sys::Promise as #wasm_bindgen::convert::FromWasmAbi>
1420 ::from_abi(#ret_ident.join())
1421 ).await
1422 };
1423 convert_ret = if self.catch {
1424 quote! { #future?; Ok(()) }
1425 } else {
1426 quote! { #future.expect("uncaught exception"); }
1427 };
1428 } else {
1429 abi_ret = quote! { () };
1430 convert_ret = quote! { () };
1431 }
1432 }
1433 }
1434
1435 let mut exceptional_ret = quote!();
1436 if self.catch && !self.function.r#async {
1437 convert_ret = quote! { Ok(#convert_ret) };
1438 exceptional_ret = quote! {
1439 #wasm_bindgen::__rt::take_last_exception()?;
1440 };
1441 }
1442
1443 let rust_name = &self.rust_name;
1444 let import_name = &self.shim;
1445 let attrs = &self.function.rust_attrs;
1446 let arguments = &arguments;
1447 let abi_arguments = &abi_arguments[..];
1448 let abi_argument_names = &abi_argument_names[..];
1449
1450 let doc = if self.doc_comment.is_empty() {
1451 quote! {}
1452 } else {
1453 let doc_comment = &self.doc_comment;
1454 quote! { #[doc = #doc_comment] }
1455 };
1456 let me = if is_method {
1457 quote! { &self, }
1458 } else {
1459 quote!()
1460 };
1461
1462 let extern_fn = respan(
1478 extern_fn(
1479 import_name,
1480 attrs,
1481 abi_arguments,
1482 abi_argument_names,
1483 abi_ret,
1484 ),
1485 &self.rust_name,
1486 );
1487
1488 let maybe_unsafe = if self.function.r#unsafe {
1489 Some(quote! {unsafe})
1490 } else {
1491 None
1492 };
1493 let maybe_async = if self.function.r#async {
1494 Some(quote! {async})
1495 } else {
1496 None
1497 };
1498 let invocation = quote! {
1499 #[allow(nonstandard_style)]
1502 #[allow(clippy::all, clippy::nursery, clippy::pedantic, clippy::restriction)]
1503 #(#attrs)*
1504 #doc
1505 #vis #maybe_async #maybe_unsafe fn #rust_name(#me #(#arguments),*) #ret {
1506 #extern_fn
1507
1508 unsafe {
1509 let #ret_ident = {
1510 #(#arg_conversions)*
1511 #import_name(#(#abi_argument_names),*)
1512 };
1513 #exceptional_ret
1514 #convert_ret
1515 }
1516 }
1517 };
1518
1519 if let Some(class) = class_ty {
1520 (quote! {
1521 #[automatically_derived]
1522 impl #class {
1523 #invocation
1524 }
1525 })
1526 .to_tokens(tokens);
1527 } else {
1528 invocation.to_tokens(tokens);
1529 }
1530
1531 Ok(())
1532 }
1533}
1534
1535struct DescribeImport<'a> {
1537 kind: &'a ast::ImportKind,
1538 wasm_bindgen: &'a syn::Path,
1539}
1540
1541impl ToTokens for DescribeImport<'_> {
1542 fn to_tokens(&self, tokens: &mut TokenStream) {
1543 let f = match *self.kind {
1544 ast::ImportKind::Function(ref f) => f,
1545 ast::ImportKind::Static(_) => return,
1546 ast::ImportKind::String(_) => return,
1547 ast::ImportKind::Type(_) => return,
1548 ast::ImportKind::Enum(_) => return,
1549 };
1550 let argtys = f.function.arguments.iter().map(|arg| &arg.pat_type.ty);
1551 let nargs = f.function.arguments.len() as u32;
1552 let inform_ret = match &f.js_ret {
1553 Some(ref t) => quote! { <#t as WasmDescribe>::describe(); },
1554 None if f.function.r#async => quote! { <JsValue as WasmDescribe>::describe(); },
1556 None => quote! { <() as WasmDescribe>::describe(); },
1557 };
1558
1559 Descriptor {
1560 ident: &f.shim,
1561 inner: quote! {
1562 inform(FUNCTION);
1563 inform(0);
1564 inform(#nargs);
1565 #(<#argtys as WasmDescribe>::describe();)*
1566 #inform_ret
1567 #inform_ret
1568 },
1569 attrs: f.function.rust_attrs.clone(),
1570 wasm_bindgen: self.wasm_bindgen,
1571 }
1572 .to_tokens(tokens);
1573 }
1574}
1575
1576impl ToTokens for ast::Enum {
1577 fn to_tokens(&self, into: &mut TokenStream) {
1578 let enum_name = &self.rust_name;
1579 let name_str = self.js_name.to_string();
1580 let name_len = name_str.len() as u32;
1581 let name_chars = name_str.chars().map(|c| c as u32);
1582 let hole = &self.hole;
1583 let underlying = if self.signed {
1584 quote! { i32 }
1585 } else {
1586 quote! { u32 }
1587 };
1588 let cast_clauses = self.variants.iter().map(|variant| {
1589 let variant_name = &variant.name;
1590 quote! {
1591 if js == #enum_name::#variant_name as #underlying {
1592 #enum_name::#variant_name
1593 }
1594 }
1595 });
1596 let try_from_cast_clauses = cast_clauses.clone();
1597 let wasm_bindgen = &self.wasm_bindgen;
1598 (quote! {
1599 #[automatically_derived]
1600 impl #wasm_bindgen::convert::IntoWasmAbi for #enum_name {
1601 type Abi = #underlying;
1602
1603 #[inline]
1604 fn into_abi(self) -> #underlying {
1605 self as #underlying
1606 }
1607 }
1608
1609 #[automatically_derived]
1610 impl #wasm_bindgen::convert::FromWasmAbi for #enum_name {
1611 type Abi = #underlying;
1612
1613 #[inline]
1614 unsafe fn from_abi(js: #underlying) -> Self {
1615 #(#cast_clauses else)* {
1616 #wasm_bindgen::throw_str("invalid enum value passed")
1617 }
1618 }
1619 }
1620
1621 #[automatically_derived]
1622 impl #wasm_bindgen::convert::OptionFromWasmAbi for #enum_name {
1623 #[inline]
1624 fn is_none(val: &Self::Abi) -> bool { *val == #hole as #underlying }
1625 }
1626
1627 #[automatically_derived]
1628 impl #wasm_bindgen::convert::OptionIntoWasmAbi for #enum_name {
1629 #[inline]
1630 fn none() -> Self::Abi { #hole as #underlying }
1631 }
1632
1633 #[automatically_derived]
1634 impl #wasm_bindgen::describe::WasmDescribe for #enum_name {
1635 fn describe() {
1636 use #wasm_bindgen::describe::*;
1637 inform(ENUM);
1638 inform(#name_len);
1639 #(inform(#name_chars);)*
1640 inform(#hole);
1641 }
1642 }
1643
1644 #[automatically_derived]
1645 impl #wasm_bindgen::__rt::core::convert::From<#enum_name> for
1646 #wasm_bindgen::JsValue
1647 {
1648 fn from(value: #enum_name) -> Self {
1649 #wasm_bindgen::JsValue::from_f64((value as #underlying).into())
1650 }
1651 }
1652
1653 #[automatically_derived]
1654 impl #wasm_bindgen::convert::TryFromJsValue for #enum_name {
1655 type Error = #wasm_bindgen::JsValue;
1656
1657 fn try_from_js_value(value: #wasm_bindgen::JsValue)
1658 -> #wasm_bindgen::__rt::core::result::Result<Self, <#enum_name as #wasm_bindgen::convert::TryFromJsValue>::Error> {
1659 use #wasm_bindgen::__rt::core::convert::TryFrom;
1660 let js = f64::try_from(&value)? as #underlying;
1661
1662 #wasm_bindgen::__rt::core::result::Result::Ok(
1663 #(#try_from_cast_clauses else)* {
1664 return #wasm_bindgen::__rt::core::result::Result::Err(value)
1665 }
1666 )
1667 }
1668 }
1669
1670 #[automatically_derived]
1671 impl #wasm_bindgen::describe::WasmDescribeVector for #enum_name {
1672 fn describe_vector() {
1673 use #wasm_bindgen::describe::*;
1674 inform(VECTOR);
1675 <#wasm_bindgen::JsValue as #wasm_bindgen::describe::WasmDescribe>::describe();
1676 }
1677 }
1678
1679 #[automatically_derived]
1680 impl #wasm_bindgen::convert::VectorIntoWasmAbi for #enum_name {
1681 type Abi = <
1682 #wasm_bindgen::__rt::alloc::boxed::Box<[#wasm_bindgen::JsValue]>
1683 as #wasm_bindgen::convert::IntoWasmAbi
1684 >::Abi;
1685
1686 fn vector_into_abi(
1687 vector: #wasm_bindgen::__rt::alloc::boxed::Box<[#enum_name]>
1688 ) -> Self::Abi {
1689 #wasm_bindgen::convert::js_value_vector_into_abi(vector)
1690 }
1691 }
1692
1693 #[automatically_derived]
1694 impl #wasm_bindgen::convert::VectorFromWasmAbi for #enum_name {
1695 type Abi = <
1696 #wasm_bindgen::__rt::alloc::boxed::Box<[#wasm_bindgen::JsValue]>
1697 as #wasm_bindgen::convert::FromWasmAbi
1698 >::Abi;
1699
1700 unsafe fn vector_from_abi(
1701 js: Self::Abi
1702 ) -> #wasm_bindgen::__rt::alloc::boxed::Box<[#enum_name]> {
1703 #wasm_bindgen::convert::js_value_vector_from_abi(js)
1704 }
1705 }
1706
1707 #[automatically_derived]
1708 impl #wasm_bindgen::__rt::VectorIntoJsValue for #enum_name {
1709 fn vector_into_jsvalue(vector: #wasm_bindgen::__rt::alloc::boxed::Box<[#enum_name]>) -> #wasm_bindgen::JsValue {
1710 #wasm_bindgen::__rt::js_value_vector_into_jsvalue(vector)
1711 }
1712 }
1713 })
1714 .to_tokens(into);
1715 }
1716}
1717
1718impl ToTokens for ast::ImportStatic {
1719 fn to_tokens(&self, into: &mut TokenStream) {
1720 let ty = &self.ty;
1721
1722 if let Some(thread_local) = self.thread_local {
1723 thread_local_import(
1724 &self.vis,
1725 &self.rust_name,
1726 &self.wasm_bindgen,
1727 ty,
1728 ty,
1729 &self.shim,
1730 thread_local,
1731 )
1732 .to_tokens(into)
1733 } else {
1734 let vis = &self.vis;
1735 let name = &self.rust_name;
1736 let wasm_bindgen = &self.wasm_bindgen;
1737 let ty = &self.ty;
1738 let shim_name = &self.shim;
1739 let init = static_init(wasm_bindgen, ty, shim_name);
1740
1741 into.extend(quote! {
1742 #[automatically_derived]
1743 #[deprecated = "use with `#[wasm_bindgen(thread_local_v2)]` instead"]
1744 });
1745 into.extend(
1746 quote_spanned! { name.span() => #vis static #name: #wasm_bindgen::JsStatic<#ty> = {
1747 fn init() -> #ty {
1748 #init
1749 }
1750 #wasm_bindgen::__rt::std::thread_local!(static _VAL: #ty = init(););
1751 #wasm_bindgen::JsStatic {
1752 __inner: &_VAL,
1753 }
1754 };
1755 },
1756 );
1757 }
1758
1759 Descriptor {
1760 ident: &self.shim,
1761 inner: quote! {
1762 <#ty as WasmDescribe>::describe();
1763 },
1764 attrs: vec![],
1765 wasm_bindgen: &self.wasm_bindgen,
1766 }
1767 .to_tokens(into);
1768 }
1769}
1770
1771impl ToTokens for ast::ImportString {
1772 fn to_tokens(&self, into: &mut TokenStream) {
1773 let js_sys = &self.js_sys;
1774 let actual_ty: syn::Type = parse_quote!(#js_sys::JsString);
1775
1776 thread_local_import(
1777 &self.vis,
1778 &self.rust_name,
1779 &self.wasm_bindgen,
1780 &actual_ty,
1781 &self.ty,
1782 &self.shim,
1783 self.thread_local,
1784 )
1785 .to_tokens(into);
1786 }
1787}
1788
1789fn thread_local_import(
1790 vis: &syn::Visibility,
1791 name: &Ident,
1792 wasm_bindgen: &syn::Path,
1793 actual_ty: &syn::Type,
1794 ty: &syn::Type,
1795 shim_name: &Ident,
1796 thread_local: ast::ThreadLocal,
1797) -> TokenStream {
1798 let init = static_init(wasm_bindgen, ty, shim_name);
1799
1800 match thread_local {
1801 ast::ThreadLocal::V1 => quote! {
1802 #wasm_bindgen::__rt::std::thread_local! {
1803 #[automatically_derived]
1804 #[deprecated = "use with `#[wasm_bindgen(thread_local_v2)]` instead"]
1805 #vis static #name: #actual_ty = {
1806 #init
1807 };
1808 }
1809 },
1810 ast::ThreadLocal::V2 => {
1811 quote! {
1812 #vis static #name: #wasm_bindgen::JsThreadLocal<#actual_ty> = {
1813 fn init() -> #actual_ty {
1814 #init
1815 }
1816 #wasm_bindgen::__wbindgen_thread_local!(#wasm_bindgen, #actual_ty)
1817 };
1818 }
1819 }
1820 }
1821}
1822
1823fn static_init(wasm_bindgen: &syn::Path, ty: &syn::Type, shim_name: &Ident) -> TokenStream {
1824 let abi_ret = quote! {
1825 #wasm_bindgen::convert::WasmRet<<#ty as #wasm_bindgen::convert::FromWasmAbi>::Abi>
1826 };
1827 quote! {
1828 #[link(wasm_import_module = "__wbindgen_placeholder__")]
1829 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1830 extern "C" {
1831 fn #shim_name() -> #abi_ret;
1832 }
1833
1834 #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
1835 unsafe fn #shim_name() -> #abi_ret {
1836 panic!("cannot access imported statics on non-wasm targets")
1837 }
1838
1839 unsafe {
1840 <#ty as #wasm_bindgen::convert::FromWasmAbi>::from_abi(#shim_name().join())
1841 }
1842 }
1843}
1844
1845struct Descriptor<'a, T> {
1848 ident: &'a Ident,
1849 inner: T,
1850 attrs: Vec<syn::Attribute>,
1851 wasm_bindgen: &'a syn::Path,
1852}
1853
1854impl<T: ToTokens> ToTokens for Descriptor<'_, T> {
1855 fn to_tokens(&self, tokens: &mut TokenStream) {
1856 thread_local! {
1865 static DESCRIPTORS_EMITTED: RefCell<HashSet<String>> = RefCell::default();
1866 }
1867
1868 let ident = self.ident;
1869
1870 if !DESCRIPTORS_EMITTED.with(|list| list.borrow_mut().insert(ident.to_string())) {
1871 return;
1872 }
1873
1874 let name = Ident::new(&format!("__wbindgen_describe_{}", ident), ident.span());
1875 let inner = &self.inner;
1876 let attrs = &self.attrs;
1877 let wasm_bindgen = &self.wasm_bindgen;
1878 (quote! {
1879 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1880 #[automatically_derived]
1881 const _: () = {
1882 #wasm_bindgen::__wbindgen_coverage! {
1883 #(#attrs)*
1884 #[no_mangle]
1885 #[doc(hidden)]
1886 pub extern "C" fn #name() {
1887 use #wasm_bindgen::describe::*;
1888 #wasm_bindgen::__rt::link_mem_intrinsics();
1890 #inner
1891 }
1892 }
1893 };
1894 })
1895 .to_tokens(tokens);
1896 }
1897}
1898
1899fn extern_fn(
1900 import_name: &Ident,
1901 attrs: &[syn::Attribute],
1902 abi_arguments: &[TokenStream],
1903 abi_argument_names: &[Ident],
1904 abi_ret: TokenStream,
1905) -> TokenStream {
1906 quote! {
1907 #[cfg(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none")))]
1908 #(#attrs)*
1909 #[link(wasm_import_module = "__wbindgen_placeholder__")]
1910 extern "C" {
1911 fn #import_name(#(#abi_arguments),*) -> #abi_ret;
1912 }
1913
1914 #[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))]
1915 unsafe fn #import_name(#(#abi_arguments),*) -> #abi_ret {
1916 #(
1917 drop(#abi_argument_names);
1918 )*
1919 panic!("cannot call wasm-bindgen imported functions on \
1920 non-wasm targets");
1921 }
1922 }
1923}
1924
1925fn splat(
1932 wasm_bindgen: &syn::Path,
1933 name: &Ident,
1934 abi: &TokenStream,
1935) -> (Vec<TokenStream>, Vec<Ident>) {
1936 let mut args = Vec::new();
1937 let mut names = Vec::new();
1938
1939 for n in 1_u32..=4 {
1940 let arg_name = format_ident!("{}_{}", name, n);
1941 let prim_name = format_ident!("Prim{}", n);
1942 args.push(quote! {
1943 #arg_name: <#abi as #wasm_bindgen::convert::WasmAbi>::#prim_name
1944 });
1945 names.push(arg_name);
1946 }
1947
1948 (args, names)
1949}
1950
1951fn respan(input: TokenStream, span: &dyn ToTokens) -> TokenStream {
1954 let mut first_span = Span::call_site();
1955 let mut last_span = Span::call_site();
1956 let mut spans = TokenStream::new();
1957 span.to_tokens(&mut spans);
1958
1959 for (i, token) in spans.into_iter().enumerate() {
1960 if i == 0 {
1961 first_span = Span::call_site().located_at(token.span());
1962 }
1963 last_span = Span::call_site().located_at(token.span());
1964 }
1965
1966 let mut new_tokens = Vec::new();
1967 for (i, mut token) in input.into_iter().enumerate() {
1968 if i == 0 {
1969 token.set_span(first_span);
1970 } else {
1971 token.set_span(last_span);
1972 }
1973 new_tokens.push(token);
1974 }
1975 new_tokens.into_iter().collect()
1976}