summaryrefslogtreecommitdiff
path: root/rust/crates/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'rust/crates/bridge')
-rw-r--r--rust/crates/bridge/src/bridge.rs50
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;