wasm_bindgen_backend/
codegen.rs

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
15/// A trait for converting AST structs into Tokens and adding them to a TokenStream,
16/// or providing a diagnostic if conversion fails.
17pub trait TryToTokens {
18    /// Attempt to convert a `Self` into tokens and add it to the `TokenStream`
19    fn try_to_tokens(&self, tokens: &mut TokenStream) -> Result<(), Diagnostic>;
20
21    /// Attempt to convert a `Self` into a new `TokenStream`
22    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    // Generate wrappers for all the items that we've found
31    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 there is a js namespace, check that name isn't a type. If it is,
55            // this import might be a method on that type.
56            if let Some(nss) = &i.js_namespace {
57                // When the namespace is `A.B`, the type name should be `B`.
58                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        // Generate a static which will eventually be what lives in a custom section
88        // of the Wasm executable. For now it's just a plain old static, but we'll
89        // eventually have it actually in its own section.
90
91        // See comments in `crates/cli-support/src/lib.rs` about what this
92        // `schema_version` is.
93        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                    // encode expr as str
113                    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        // concatenate all encoded chunks and write the length in front of the chunk;
131        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        // We already consumed the contents of included files when generating
148        // the custom section, but we want to make sure that updates to the
149        // generated files will cause this macro to rerun incrementally. To do
150        // that we use `include_str!` to force rustc to think it has a
151        // dependency on these files. That way when the file changes Cargo will
152        // automatically rerun rustc which will rerun this macro. Other than
153        // this we don't actually need the results of the `include_str!`, so
154        // it's just shoved into an anonymous static.
155        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                // `allow_delayed` is whether it's ok to not actually free the `ptr` immediately
308                // if it's still borrowed.
309                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                        // Just drop the implicit `Rc` owned by JS, and then if the value is still
314                        // referenced it'll be kept alive by its other `Rc`s.
315                        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                        // Claim ownership of the value, which will panic if it's borrowed.
320                        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                        // Don't run `JsValue`'s destructor, `unwrap_fn` already did that for us.
406                        #[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        // Split this out so that it isn't affected by `quote_spanned!`.
487        //
488        // If we don't do this, it might end up being unable to reference `js`
489        // properly because it doesn't have the same span.
490        //
491        // See https://github.com/rustwasm/wasm-bindgen/pull/3725.
492        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        // For an `async` function we always run it through `future_to_promise`
734        // since we're returning a promise to JS, and this will implicitly
735        // require that the function returns a `Future<Output = Result<...>>`
736        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            // little helper function to make sure the check points to the
804            // location of the function causing the assert to fail
805            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        // In addition to generating the shim function above which is what
871        // our generated JS will invoke, we *also* generate a "descriptor"
872        // shim. This descriptor shim uses the `WasmDescribe` trait to
873        // programmatically describe the type signature of the generated
874        // shim above. This in turn is then used to inform the
875        // `wasm-bindgen` CLI tool exactly what types and such it should be
876        // using in JS.
877        //
878        // Note that this descriptor function is a purely an internal detail
879        // of `#[wasm_bindgen]` and isn't intended to be exported to anyone
880        // or actually part of the final was binary. Additionally, this is
881        // literally executed when the `wasm-bindgen` tool executes.
882        //
883        // In any case, there's complications in `wasm-bindgen` to handle
884        // this, but the tl;dr; is that this is stripped from the final wasm
885        // binary along with anything it references.
886        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                // TODO: remove this on the next major version
1082                #[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                        // Should be safe because `#rust_name` is a transparent
1139                        // wrapper around `val`
1140                        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        // A vector of EnumName::VariantName tokens for this enum
1210        let variant_paths: Vec<TokenStream> = self
1211            .variants
1212            .iter()
1213            .map(|v| quote!(#enum_name::#v).into_token_stream())
1214            .collect();
1215
1216        // Borrow variant_paths because we need to use it multiple times inside the quote! macro
1217        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        // Route any errors pointing to this imported function to the identifier
1463        // of the function we're imported from so we at least know what function
1464        // is causing issues.
1465        //
1466        // Note that this is where type errors like "doesn't implement
1467        // FromWasmAbi" or "doesn't implement IntoWasmAbi" currently get routed.
1468        // I suspect that's because they show up in the signature via trait
1469        // projections as types of arguments, and all that needs to typecheck
1470        // before the body can be typechecked. Due to rust-lang/rust#60980 (and
1471        // probably related issues) we can't really get a precise span.
1472        //
1473        // Ideally what we want is to point errors for particular types back to
1474        // the specific argument/type that generated the error, but it looks
1475        // like rustc itself doesn't do great in that regard so let's just do
1476        // the best we can in the meantime.
1477        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            // This is due to `#[automatically_derived]` attribute cannot be
1500            // placed onto bare functions.
1501            #[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
1535// See comment above in ast::Export for what's going on here.
1536struct 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            // async functions always return a JsValue, even if they say to return ()
1555            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
1845/// Emits the necessary glue tokens for "descriptor", generating an appropriate
1846/// symbol name as well as attributes around the descriptor function itself.
1847struct 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        // It's possible for the same descriptor to be emitted in two different
1857        // modules (aka a value imported twice in a crate, each in a separate
1858        // module). In this case no need to emit duplicate descriptors (which
1859        // leads to duplicate symbol errors), instead just emit one.
1860        //
1861        // It's up to the descriptors themselves to ensure they have unique
1862        // names for unique items imported, currently done via `ShortHash` and
1863        // hashing appropriate data into the symbol name.
1864        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                    // See definition of `link_mem_intrinsics` for what this is doing
1889                    #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
1925/// Splats an argument with the given name and ABI type into 4 arguments, one
1926/// for each primitive that the ABI type splits into.
1927///
1928/// Returns an `(args, names)` pair, where `args` is the list of arguments to
1929/// be inserted into the function signature, and `names` is a list of the names
1930/// of those arguments.
1931fn 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
1951/// Converts `span` into a stream of tokens, and attempts to ensure that `input`
1952/// has all the appropriate span information so errors in it point to `span`.
1953fn 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}