From 5777a555f60b780b7db430fa7bfa66a3bcb2623f Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Sun, 29 Mar 2026 14:25:25 +0200 Subject: feat: add shared Rust crates for cross-platform time utilities Introduce `bridge` proc-macro crate with `#[export]` attribute that conditionally applies `wasm_bindgen` for WASM builds, and `time` crate porting all timecode/frame utilities from TypeScript to Rust. --- rust/crates/bridge/src/bridge.rs | 49 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 rust/crates/bridge/src/bridge.rs (limited to 'rust/crates/bridge/src/bridge.rs') diff --git a/rust/crates/bridge/src/bridge.rs b/rust/crates/bridge/src/bridge.rs new file mode 100644 index 00000000..52dee731 --- /dev/null +++ b/rust/crates/bridge/src/bridge.rs @@ -0,0 +1,49 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{ItemFn, parse_macro_input}; + +#[proc_macro_attribute] +pub fn export(_attr: TokenStream, item: TokenStream) -> TokenStream { + let function = parse_macro_input!(item as ItemFn); + let js_name = snake_to_camel(&function.sig.ident.to_string()); + + quote! { + #[cfg_attr(feature = "wasm", ::wasm_bindgen::prelude::wasm_bindgen(js_name = #js_name))] + #function + } + .into() +} + +fn snake_to_camel(name: &str) -> String { + let mut camel = String::with_capacity(name.len()); + let mut should_uppercase_next = false; + + for character in name.chars() { + if character == '_' { + should_uppercase_next = true; + continue; + } + + if should_uppercase_next { + camel.push(character.to_ascii_uppercase()); + should_uppercase_next = false; + continue; + } + + camel.push(character); + } + + camel +} + +#[cfg(test)] +mod tests { + use super::snake_to_camel; + + #[test] + fn converts_snake_case_to_camel_case() { + assert_eq!(snake_to_camel("do_something"), "doSomething"); + assert_eq!(snake_to_camel("a_b_c"), "aBC"); + assert_eq!(snake_to_camel("already"), "already"); + } +} -- cgit v1.3.1