Clone in a terminal:
Commit c71203e
Johan Mattsson - 2026-06-29T11:46:58+00:00
c71203e17ed83c8ff14c2e2593af07f4b94c63edjohan.mattsson.m@gmail.com

Global store

Changed files (2)

Diff

diff --git a/src/init.rs b/src/init.rsindex c1eb5d9..776e535 100644--- a/src/init.rs+++ b/src/init.rs@@ -65,8 +65,10 @@ pub fn component_impl(attr: pm::TokenStream, item: pm::TokenStream) -> pm::Token     let observed_fn = observed_quote(&observed_js, struct_name_ident);     let changed_fn = changed_quote(&changed_js, struct_name_ident);     let self_from_id = component_from_id(component_struct_item.clone());+    let component_id_counter = component_counter();      let expanded = quote! {+        #component_id_counter         #global_store         #rs_self         #component_struct_item@@ -78,7 +80,10 @@ pub fn component_impl(attr: pm::TokenStream, item: pm::TokenStream) -> pm::Token         #changed_fn     }; -    expanded.into()+    ex+++    panded.into() }  fn attach_quote(atach_state_js_fn: &str, struct_name: &Ident) -> proc_macro2::TokenStream {@@ -251,19 +256,32 @@ fn gen_rust_self(struct_item: ItemStruct, js_name: Ident) -> proc_macro2::TokenS     let store_ident = Ident::new(&store_name_str, Span::call_site());      let struct_name_str = struct_ident.to_string();+    let var_name_str = from_pascal_to_snake(struct_name_str.as_str());+    let var_ident = Ident::new(&var_name_str, Span::call_site());+     let rust_name = format!(         "init_component_self_{}",         from_pascal_to_snake(struct_name_str.as_str())     );     let rust_ident = Ident::new(&rust_name, Span::call_site()); +    let log_msg = LitStr::new(+        &format!("Run {} init rs state.", struct_name_str),+        Span::call_site(),+    );+     let expanded = quote! {         #[callback(#js_name)]         #[allow(non_snake_case)]         pub fn #rust_ident() -> String {  // init_component_state_struct_name, returns id for the instance of the element-            log!("Run counter init rs state.");-            let mut counter = #struct_ident::default();-            let wasm_id = ::kaja_web::NEXT_COMPONENT_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);            let mut store = #store_ident.write().expect("failed to acquire write lock");+            gloo::console::log!(#log_msg);++            let mut #var_ident = #struct_ident::default();+            let wasm_id = ::kaja_web::NEXT_COMPONENT_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);++            let mut store = #store_ident+                .write()+                .expect("failed to acquire write lock");              if store.is_none() {                 *store = Some(std::collections::HashMap::new());@@ -271,7 +289,7 @@ fn gen_rust_self(struct_item: ItemStruct, js_name: Ident) -> proc_macro2::TokenS              let key = wasm_id.to_string();             let store_map = store.as_mut().unwrap();-            store_map.insert(key.clone(), counter);+            store_map.insert(key.clone(), #var_ident);             key         }     };@@ -279,6 +297,20 @@ fn gen_rust_self(struct_item: ItemStruct, js_name: Ident) -> proc_macro2::TokenS     expanded } +fn component_counter() -> proc_macro2::TokenStream {+    let expanded = quote! {+        #[callback(nextComponentId)]+        pub fn next_component_id() -> String {+            let wasm_id = ::kaja_web::NEXT_COMPONENT_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);+            let next_id = wasm_id.to_string();+            log!("Next ID", next_id);+            next_id+        }+    };++    expanded+}+ fn create_class(     class_creator: Ident,     tag: LitStr,@@ -308,18 +340,12 @@ fn create_class(                     return class extends HTMLElement {                         constructor() {                             super();-                            this.setAttribute("componentid", "-1");+                            let componentId = nextComponentId();+                            this.setAttribute("componentid", componentId);                         }                          connectedCallback() {                             let componentid = this.getAttribute("componentid");--                            if (componentid === "-1") {-                                let id = __INIT_CALLBACK();-                                this.setAttribute("componentid", id);-                                componentid = id;-                            }-                             __ATTACH_CALLBACK(this, componentid);                         } diff --git a/src/lib.rs b/src/lib.rsindex 94519aa..8381b78 100644--- a/src/lib.rs+++ b/src/lib.rs@@ -7,16 +7,21 @@ use syn::ItemStruct;  #[proc_macro_attribute] pub fn component(attr: pm::TokenStream, item: pm::TokenStream) -> pm::TokenStream {+    // Clone the attribute token stream so we can pass ownership into the helper+    // without risking accidental moves causing "use of moved value" errors when+    // the macro is expanded multiple times.+    let attr_clone = attr.clone();+     // Add `#[derive(Default)]` to the struct.     let item_ts2 = TokenStream2::from(item.clone());     let mut input = match syn::parse2::<ItemStruct>(item_ts2.clone()) {         Ok(s) => s,-        Err(_) => return init::component_impl(attr, item),+        Err(_) => return init::component_impl(attr_clone.clone(), item),     };      input.attrs.push(syn::parse_quote!(#[derive(Default)]));      // Add the functions needed for a complete web component using kaja-web     let new_item_ts2 = quote!(#input);-    init::component_impl(attr, pm::TokenStream::from(new_item_ts2))+    init::component_impl(attr_clone, pm::TokenStream::from(new_item_ts2)) }

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112