diff options
Diffstat (limited to 'rust/crates/bridge')
| -rw-r--r-- | rust/crates/bridge/src/bridge.rs | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/rust/crates/bridge/src/bridge.rs b/rust/crates/bridge/src/bridge.rs index 52dee731..99b00615 100644 --- a/rust/crates/bridge/src/bridge.rs +++ b/rust/crates/bridge/src/bridge.rs @@ -1,10 +1,36 @@ use proc_macro::TokenStream; use quote::quote; -use syn::{ItemFn, parse_macro_input}; +use syn::{FnArg, Item, ItemConst, ItemFn, parse_macro_input}; #[proc_macro_attribute] pub fn export(_attr: TokenStream, item: TokenStream) -> TokenStream { - let function = parse_macro_input!(item as ItemFn); + match parse_macro_input!(item as Item) { + Item::Fn(function) => export_fn(function), + Item::Const(constant) => export_const(constant), + other => syn::Error::new_spanned(other, "#[export] only supports fn and const items") + .to_compile_error() + .into(), + } +} + +fn export_fn(function: ItemFn) -> TokenStream { + let param_count = function + .sig + .inputs + .iter() + .filter(|arg| matches!(arg, FnArg::Typed(_))) + .count(); + + if param_count > 1 { + return syn::Error::new_spanned( + &function.sig.inputs, + "#[export] functions must accept a single options struct, not positional arguments. \ + Wrap parameters in a struct: `fn foo(FooOptions { a, b }: FooOptions)`", + ) + .to_compile_error() + .into(); + } + let js_name = snake_to_camel(&function.sig.ident.to_string()); quote! { @@ -14,6 +40,26 @@ pub fn export(_attr: TokenStream, item: TokenStream) -> TokenStream { .into() } +fn export_const(constant: ItemConst) -> TokenStream { + let js_name = constant.ident.to_string(); + let const_ident = &constant.ident; + let getter_ident = syn::Ident::new( + &format!("__const_{}", constant.ident.to_string().to_lowercase()), + constant.ident.span(), + ); + + quote! { + #constant + + #[cfg(feature = "wasm")] + #[::wasm_bindgen::prelude::wasm_bindgen(js_name = #js_name)] + pub fn #getter_ident() -> f64 { + #const_ident as f64 + } + } + .into() +} + fn snake_to_camel(name: &str) -> String { let mut camel = String::with_capacity(name.len()); let mut should_uppercase_next = false; |
