1 //! This crate defines macros to easily define and use functions with a
2 //! versioned suffix, to facilitate using multiple versions of the same
3 //! crate that generate assembly.
4 //!
5 //! > **⚠️ Warning ⚠️**: this crate is an internal-only crate for the Wasmtime
6 //! > project and is not intended for general use. APIs are not strictly
7 //! > reviewed for safety and usage outside of Wasmtime may have bugs. If
8 //! > you're interested in using this feel free to file an issue on the
9 //! > Wasmtime repository to start a discussion about doing so, but otherwise
10 //! > be aware that your usage of this crate is not supported.
11 
12 use quote::ToTokens;
13 
14 const VERSION: &str = env!("CARGO_PKG_VERSION");
15 
version(value: impl std::fmt::Display) -> String16 fn version(value: impl std::fmt::Display) -> String {
17     format!("{}_{}", value, VERSION.replace('.', "_"))
18 }
19 
versioned_lit_str(value: impl std::fmt::Display) -> syn::LitStr20 fn versioned_lit_str(value: impl std::fmt::Display) -> syn::LitStr {
21     syn::LitStr::new(version(value).as_str(), proc_macro2::Span::call_site())
22 }
23 
24 #[proc_macro_attribute]
versioned_export( _attr: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> proc_macro::TokenStream25 pub fn versioned_export(
26     _attr: proc_macro::TokenStream,
27     item: proc_macro::TokenStream,
28 ) -> proc_macro::TokenStream {
29     let mut function = syn::parse_macro_input!(item as syn::ItemFn);
30 
31     let export_name = versioned_lit_str(&function.sig.ident);
32     function
33         .attrs
34         .push(syn::parse_quote! { #[unsafe(export_name = #export_name)] });
35 
36     function.to_token_stream().into()
37 }
38 
39 #[proc_macro_attribute]
versioned_link( _attr: proc_macro::TokenStream, item: proc_macro::TokenStream, ) -> proc_macro::TokenStream40 pub fn versioned_link(
41     _attr: proc_macro::TokenStream,
42     item: proc_macro::TokenStream,
43 ) -> proc_macro::TokenStream {
44     let mut function = syn::parse_macro_input!(item as syn::ForeignItemFn);
45 
46     let link_name = versioned_lit_str(&function.sig.ident);
47     function
48         .attrs
49         .push(syn::parse_quote! { #[link_name = #link_name] });
50 
51     function.to_token_stream().into()
52 }
53 
54 #[proc_macro]
versioned_stringify_ident(item: proc_macro::TokenStream) -> proc_macro::TokenStream55 pub fn versioned_stringify_ident(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
56     let ident = syn::parse_macro_input!(item as syn::Ident);
57 
58     versioned_lit_str(ident).to_token_stream().into()
59 }
60 
61 #[proc_macro]
versioned_suffix(item: proc_macro::TokenStream) -> proc_macro::TokenStream62 pub fn versioned_suffix(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
63     if !item.is_empty() {
64         return syn::Error::new(
65             proc_macro2::Span::call_site(),
66             "`versioned_suffix!` accepts no input",
67         )
68         .to_compile_error()
69         .into();
70     };
71 
72     versioned_lit_str("").to_token_stream().into()
73 }
74