1 //! A set of convenience macros for our wasmtime-c-api crate.
2 //!
3 //! These are intended to mirror the macros in the `wasm.h` header file and
4 //! largely facilitate the `declare_ref` macro.
5 
6 use proc_macro2::{Ident, TokenStream, TokenTree};
7 use quote::quote;
8 
9 fn extract_ident(input: proc_macro::TokenStream) -> Ident {
10     let input = TokenStream::from(input);
11     let i = match input.into_iter().next().unwrap() {
12         TokenTree::Ident(i) => i,
13         _ => panic!("expected an ident"),
14     };
15     let name = i.to_string();
16     assert!(name.ends_with("_t"));
17     return i;
18 }
19 
20 #[proc_macro]
21 pub fn declare_own(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
22     let ty = extract_ident(input);
23     let name = ty.to_string();
24     let delete = quote::format_ident!("{}_delete", &name[..name.len() - 2]);
25     let docs = format!("Deletes the [`{name}`].");
26 
27     (quote! {
28         #[doc = #docs]
29         #[unsafe(no_mangle)]
30         pub extern fn #delete(_: Box<#ty>) {}
31     })
32     .into()
33 }
34 
35 #[proc_macro]
36 pub fn declare_ty(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
37     let ty = extract_ident(input);
38     let name = ty.to_string();
39     let prefix = &name[..name.len() - 2];
40     let copy = quote::format_ident!("{}_copy", &prefix);
41     let docs = format!(
42         "Creates a new [`{name}`] which matches the provided one.\n\n\
43         The caller is responsible for deleting the returned value via [`{prefix}_delete`].\n\n\
44     "
45     );
46 
47     (quote! {
48         wasmtime_c_api_macros::declare_own!(#ty);
49 
50         #[doc = #docs]
51         #[unsafe(no_mangle)]
52         pub extern fn #copy(src: &#ty) -> Box<#ty> {
53             Box::new(src.clone())
54         }
55     })
56     .into()
57 }
58 
59 #[proc_macro]
60 pub fn declare_ref(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
61     let ty = extract_ident(input);
62     let name = ty.to_string();
63     let prefix = &name[..name.len() - 2];
64     let same = quote::format_ident!("{}_same", prefix);
65     let same_docs = format!(
66         "Returns `true` if the given references are pointing to the same [`{name}`].\n\n\
67         This is not yet supported and aborts the process upon use."
68     );
69     let get_host_info = quote::format_ident!("{}_get_host_info", prefix);
70     let get_host_info_docs = format!(
71         "Returns the host information of the [`{name}`].\n\n\
72         This is not yet supported and always returns `NULL`."
73     );
74     let set_host_info = quote::format_ident!("{}_set_host_info", prefix);
75     let set_host_info_docs = format!(
76         "Sets the host information of the [`{name}`].\n\n\
77         This is not yet supported and aborts the process upon use."
78     );
79     let set_host_info_final = quote::format_ident!("{}_set_host_info_with_finalizer", prefix);
80     let set_host_info_final_docs = format!(
81         "Sets the host information finalizer of the [`{name}`].\n\n\
82         This is not yet supported and aborts the process upon use."
83     );
84     let as_ref = quote::format_ident!("{}_as_ref", prefix);
85     let as_ref_docs = format!(
86         "Returns the [`{name}`] as mutable reference.\n\n\
87         This is not yet supported and aborts the process upon use."
88     );
89     let as_ref_const = quote::format_ident!("{}_as_ref_const", prefix);
90     let as_ref_const_docs = format!(
91         "Returns the [`{name}`] as immutable reference.\n\n\
92         This is not yet supported and aborts the process upon use."
93     );
94 
95     (quote! {
96         wasmtime_c_api_macros::declare_ty!(#ty);
97 
98         #[doc = #same_docs]
99         #[unsafe(no_mangle)]
100         pub extern fn #same(_a: &#ty, _b: &#ty) -> bool {
101             eprintln!("`{}` is not implemented", stringify!(#same));
102             std::process::abort();
103         }
104 
105         #[doc = #get_host_info_docs]
106         #[unsafe(no_mangle)]
107         pub extern fn #get_host_info(a: &#ty) -> *mut std::os::raw::c_void {
108             std::ptr::null_mut()
109         }
110 
111         #[doc = #set_host_info_docs]
112         #[unsafe(no_mangle)]
113         pub extern fn #set_host_info(a: &#ty, info: *mut std::os::raw::c_void) {
114             eprintln!("`{}` is not implemented", stringify!(#set_host_info));
115             std::process::abort();
116         }
117 
118         #[doc = #set_host_info_final_docs]
119         #[unsafe(no_mangle)]
120         pub extern fn #set_host_info_final(
121             a: &#ty,
122             info: *mut std::os::raw::c_void,
123             finalizer: Option<extern "C" fn(*mut std::os::raw::c_void)>,
124         ) {
125             eprintln!("`{}` is not implemented", stringify!(#set_host_info_final));
126             std::process::abort();
127         }
128 
129         #[doc = #as_ref_docs]
130         #[unsafe(no_mangle)]
131         pub extern fn #as_ref(a: &#ty) -> Box<crate::wasm_ref_t> {
132             eprintln!("`{}` is not implemented", stringify!(#as_ref));
133             std::process::abort();
134         }
135 
136         #[doc = #as_ref_const_docs]
137         #[unsafe(no_mangle)]
138         pub extern fn #as_ref_const(a: &#ty) -> Box<crate::wasm_ref_t> {
139             eprintln!("`{}` is not implemented", stringify!(#as_ref_const));
140             std::process::abort();
141         }
142 
143         // TODO: implement `wasm_ref_as_#name#`
144         // TODO: implement `wasm_ref_as_#name#_const`
145     })
146     .into()
147 }
148