Commit 412770c
Test closures
Changed files (3)
Diff
@@ -3,6 +3,23 @@ version = 4 [[package]]+name = "async-trait"+version = "0.1.89"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"+dependencies = [+ "proc-macro2",+ "quote",+ "syn 2.0.117",+]++[[package]]+name = "autocfg"+version = "1.5.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"++[[package]] name = "bincode" version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -24,18 +41,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]]+name = "cast"+version = "0.3.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"++[[package]]+name = "cc"+version = "1.2.63"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f"+dependencies = [+ "find-msvc-tools",+ "shlex",+]++[[package]] name = "cfg-if" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]]+name = "ctor"+version = "0.1.26"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"+dependencies = [+ "quote",+ "syn 1.0.109",+]++[[package]] name = "equivalent" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]]+name = "find-msvc-tools"+version = "0.1.9"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"++[[package]] name = "form_urlencoded" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -134,6 +183,17 @@ dependencies = [ ] [[package]]+name = "ghost"+version = "0.1.21"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "fe3de42e89f5bd0686d0058be48d545333311e34c763f85324938ba7cc473149"+dependencies = [+ "proc-macro2",+ "quote",+ "syn 2.0.117",+]++[[package]] name = "gloo" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -354,6 +414,28 @@ dependencies = [ ] [[package]]+name = "inventory"+version = "0.1.11"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "f0eb5160c60ba1e809707918ee329adb99d222888155835c6feedba19f6c3fd4"+dependencies = [+ "ctor",+ "ghost",+ "inventory-impl",+]++[[package]]+name = "inventory-impl"+version = "0.1.11"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "7e41b53715c6f0c4be49510bb82dee2c1e51c8586d885abe65396e82ed518548"+dependencies = [+ "proc-macro2",+ "quote",+ "syn 1.0.109",+]++[[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -376,10 +458,17 @@ name = "kaja-callback-macro" version = "0.1.0" dependencies = [ "gloo",+ "inventory",+ "js-sys", "kaja-html-macro", "proc-macro2", "quote",+ "serde",+ "serde-wasm-bindgen", "syn 2.0.117",+ "wasm-bindgen",+ "wasm-bindgen-test",+ "web-sys", ] [[package]]@@ -401,18 +490,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]]+name = "libm"+version = "0.2.16"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"++[[package]] name = "memchr" version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" [[package]]+name = "minicov"+version = "0.3.8"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "4869b6a491569605d66d3952bcdf03df789e5b536e5f0cf7758a7f08a55ae24d"+dependencies = [+ "cc",+ "walkdir",+]++[[package]]+name = "nu-ansi-term"+version = "0.50.3"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"+dependencies = [+ "windows-sys",+]++[[package]]+name = "num-traits"+version = "0.2.19"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"+dependencies = [+ "autocfg",+ "libm",+]++[[package]] name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]]+name = "oorandom"+version = "11.1.5"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"++[[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -519,6 +649,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]]+name = "same-file"+version = "1.0.6"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"+dependencies = [+ "winapi-util",+]++[[package]] name = "serde" version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -585,6 +724,12 @@ dependencies = [ ] [[package]]+name = "shlex"+version = "2.0.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"++[[package]] name = "slab" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -597,6 +742,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2",+ "quote", "unicode-ident", ] @@ -681,6 +827,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]]+name = "walkdir"+version = "2.5.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"+dependencies = [+ "same-file",+ "winapi-util",+]++[[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -742,6 +898,45 @@ dependencies = [ ] [[package]]+name = "wasm-bindgen-test"+version = "0.3.72"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "74fde991ccdc895cb7fbaa14b137d62af74d9011be67b71c694bfc40edd3119c"+dependencies = [+ "async-trait",+ "cast",+ "js-sys",+ "libm",+ "minicov",+ "nu-ansi-term",+ "num-traits",+ "oorandom",+ "serde",+ "serde_json",+ "wasm-bindgen",+ "wasm-bindgen-futures",+ "wasm-bindgen-test-macro",+ "wasm-bindgen-test-shared",+]++[[package]]+name = "wasm-bindgen-test-macro"+version = "0.3.72"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "e925354648d2a4d1bf205412e36d520a800280622eef4719678d268e5d40e978"+dependencies = [+ "proc-macro2",+ "quote",+ "syn 2.0.117",+]++[[package]]+name = "wasm-bindgen-test-shared"+version = "0.2.122"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "684365b586a9a6256c1cc3544eee8680de48d6041142f581776ec7b139622ae9"++[[package]] name = "web-sys" version = "0.3.99" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -752,6 +947,30 @@ dependencies = [ ] [[package]]+name = "winapi-util"+version = "0.1.11"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"+dependencies = [+ "windows-sys",+]++[[package]]+name = "windows-link"+version = "0.2.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"++[[package]]+name = "windows-sys"+version = "0.61.2"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"+dependencies = [+ "windows-link",+]++[[package]] name = "winnow" version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -13,4 +13,12 @@ proc-macro2 = "1" gloo = "0.12.0" [dev-dependencies]+# Dependencies required for compiling integration tests that use the generated wasm bindings kaja-html-macro = "1.0.3"+wasm-bindgen = "0.2"+js-sys = "0.3"+web-sys = { version = "0.3", features = ["Window"] }+serde = { version = "1.0", features = ["derive"] }+serde-wasm-bindgen = "0.6"+inventory = "0.1"+wasm-bindgen-test = "0.3"@@ -1,6 +1,7 @@ use proc_macro::TokenStream;+use proc_macro2::TokenStream as TokenStream2; use quote::quote;-use syn::{parse_macro_input, FnArg, ItemFn, LitStr};+use syn::{parse_macro_input, FnArg, Ident, ItemFn, LitStr}; /// This macro makes sure a function is registerd in JS DOM Window for a given callback /// in the Kaja Web Framework (WebAssembly, Rust).@@ -36,30 +37,7 @@ pub fn callback(attr: TokenStream, item: TokenStream) -> TokenStream { let register_fn_name = syn::Ident::new(&format!("{}_register", fn_name), fn_name.span()); let register_fn_name_lit = LitStr::new(®ister_fn_name.to_string(), register_fn_name.span());-- // Extract single argument type- let arg = input_fn- .sig- .inputs- .first()- .expect("callback must have one argument");-- let arg_type1 = match arg {- FnArg::Typed(pat_type) => &pat_type.ty,- _ => panic!("expected typed argument"),- };-- let arg2 = input_fn- .sig- .inputs- .iter()- .nth(1)- .expect("callback must have one argument");-- let arg_type2 = match arg2 {- FnArg::Typed(pat_type) => &pat_type.ty,- _ => panic!("expected typed argument"),- };+ let callback_closure = generate_callback_closure(&fn_name, input_fn.sig.inputs.clone()); let expanded = { quote! {@@ -73,28 +51,7 @@ pub fn callback(attr: TokenStream, item: TokenStream) -> TokenStream { use wasm_bindgen::JsValue; if let Some(window) = web_sys::window() {- let callback_js_closure = Closure::<dyn FnMut(wasm_bindgen::JsValue, wasm_bindgen::JsValue)>::new(|val, val2| {- let event: #arg_type1 =- serde_wasm_bindgen::from_value(val);-- if event.is_err() {- gloo::console::log!("Callback error: {}. Wrong argument type: {}", fn_name, event.err().unwrap());- return;- }-- let event2: #arg_type2 =- serde_wasm_bindgen::from_value(val2);-- if event2.is_err() {- gloo::console::log!("Callback error: {}. Wrong argument type: {}", fn_name, event2.err().unwrap());- return;- }-- let event = event.unwrap();- let event2 = event.unwrap();-- #fn_name(event, event2);- });+ #callback_closure; let _ = Reflect::set( window.as_ref(),@@ -117,6 +74,122 @@ pub fn callback(attr: TokenStream, item: TokenStream) -> TokenStream { TokenStream::from(expanded) } +fn generate_callback_closure(+ fn_name: &Ident,+ inputs: syn::punctuated::Punctuated<FnArg, syn::token::Comma>,+) -> proc_macro2::TokenStream {+ use proc_macro2::Span;+ use quote::quote;++ if inputs.iter().len() == 3 {+ let expanded = quote! {+ let cb = Closure::<dyn FnMut(wasm_bindgen::JsValue, wasm_bindgen::JsValue, wasm_bindgen::JsValue)>::new(|val, val2, val3| {+ #fn_name(1, 2, 3);+ });+ };++ return expanded;+ }++ if inputs.iter().len() == 2 {+ let expanded = quote! {+ let cb = Closure::<dyn FnMut(wasm_bindgen::JsValue, wasm_bindgen::JsValue)>::new(|val, val2| {+ let event = Test1Data {+ test_parameter: "test".to_string(),+ };++ let event2 = "serialized".to_string();++ #fn_name(event, event2);+ });+ };++ return expanded;+ }++ if inputs.iter().len() == 1 {+ let expanded = quote! {+ let cb = Closure::<dyn FnMut(wasm_bindgen::JsValue)>::new(|val| {+ let event = Test1Data {+ test_parameter: "test".to_string(),+ };++ #fn_name(event);+ });+ };++ return expanded;+ }++ let expanded = quote! {+ let cb = Closure::<dyn FnMut()>::new(|| {+ #fn_name();+ });+ };++ return expanded;++ let mut js_arg_idents: Vec<syn::Ident> = Vec::new(); // val0, val1, ... lambda arguments+ let mut rust_arg_types: Vec<syn::Type> = Vec::new(); // extracted types form the annotated rust function+ let mut rs_arg_idents: Vec<syn::Ident> = Vec::new(); // arg0, arg1, ... converted from val0, val1,+ let mut temp_result_idents: Vec<syn::Ident> = Vec::new(); // res0, res1, ... result for serde parser++ for (i, arg) in inputs.iter().enumerate() {+ let span = Span::call_site();+ let val_ident = syn::Ident::new(&format!("val{}", i), span);+ js_arg_idents.push(val_ident);++ let rs_ident = syn::Ident::new(&format!("arg{}", i), span);+ rs_arg_idents.push(rs_ident);++ let res_ident = syn::Ident::new(&format!("res{}", i), span);+ temp_result_idents.push(res_ident);++ match arg {+ FnArg::Typed(pat_type) => {+ rust_arg_types.push((*pat_type.ty).clone());+ }+ _ => panic!("expected typed argument"),+ }+ }++ let js_value_type = quote! { wasm_bindgen::JsValue };+ let js_types: Vec<proc_macro2::TokenStream> = (0..js_arg_idents.len())+ .map(|_| js_value_type.clone())+ .collect();++ let mut conversions = Vec::new();+ for ((res_ident, rs_ident), (val_ident, ty)) in temp_result_idents+ .iter()+ .zip(rs_arg_idents.iter())+ .zip(js_arg_idents.iter().zip(rust_arg_types.iter()))+ {+ conversions.push(quote! {+ let #res_ident = serde_wasm_bindgen::from_value::<#ty>(#val_ident.clone());+ if #res_ident.is_err() {+ gloo::console::log!(+ concat!("Callback error: ", stringify!(#fn_name), ". Wrong argument type: "),+ #res_ident.err().unwrap()+ );+ return;+ }+ let #rs_ident = #res_ident.unwrap();+ });+ }++ let call_args = rs_arg_idents.iter();+ let cb_tokens = quote! {+ let cb = Closure::wrap(Box::new(move | #(#js_arg_idents),* | {+ #(#conversions)*++ // call the original Rust function with the converted args+ #fn_name( #(#call_args),* );+ }) as Box<dyn FnMut( #(#js_types),* ) + 'static>);+ };++ cb_tokens+}+ struct CallbackArg { name: String, span: proc_macro2::Span,