Clone in a terminal:
Commit 45ddf9d
Johan Mattsson - 2026-07-12T10:50:06+00:00
45ddf9d1ffdf373bb40944b0edd3a4ee97a626f9johan.mattsson.m@gmail.com

ArcSwap instead of lock

Changed files (10)

Diff

diff --git a/Cargo.lock b/Cargo.lockindex 9676dc1..345e287 100644--- a/Cargo.lock+++ b/Cargo.lock@@ -3,6 +3,15 @@ version = 4  [[package]]+name = "arc-swap"+version = "1.9.2"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b"+dependencies = [+ "rustversion",+]++[[package]] name = "bincode" version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -406,6 +415,7 @@ dependencies = [ name = "kaja-web" version = "1.0.2" dependencies = [+ "arc-swap",  "gloo",  "gloo-console",  "inventory",diff --git a/Cargo.toml b/Cargo.tomlindex 9f96c38..3c43db6 100644--- a/Cargo.toml+++ b/Cargo.toml@@ -21,5 +21,6 @@ serde-wasm-bindgen = "0.5" inventory = "0.3.24" js-sys = "0.3" wasm-bindgen-futures = "0.4.72"+arc-swap = "1.9.2" kaja-callback-macro = { path = "../kaja-callback-macro" } kaja-web-component = { path = "../kaja-web-component" }diff --git a/examples/main-component/Cargo.lock b/examples/main-component/Cargo.lockindex 233b2ad..011d56a 100644--- a/examples/main-component/Cargo.lock+++ b/examples/main-component/Cargo.lock@@ -9,6 +9,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"  [[package]]+name = "arc-swap"+version = "1.9.2"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b"+dependencies = [+ "rustversion",+]++[[package]] name = "async-channel" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -520,6 +529,7 @@ dependencies = [ name = "kaja-web" version = "1.0.2" dependencies = [+ "arc-swap",  "gloo",  "gloo-console",  "inventory",diff --git a/examples/main-component/src/main_component.rs b/examples/main-component/src/main_component.rsindex 2ed92c8..e2aba05 100644--- a/examples/main-component/src/main_component.rs+++ b/examples/main-component/src/main_component.rs@@ -1,5 +1,6 @@ use kaja_web::prelude::*; +#[derive(Clone)] #[component("main-component")] struct Main {     test: bool,@@ -21,18 +22,20 @@ impl Component for Main {     fn update(id: &str) {         log!("Main update:", id); -        let Some(handle) = Self::get_component(id) else {-            error!("Main component not found:", id);+        let Some(element) = get_element_by_id(id) else {+            error!("Element not found:", id);             return;         }; -        let Some(element) = get_element_by_id(id) else {-            error!("Element not found:", id);+        let Some(handle) = Self::get_component(id) else {+            error!("Main component not found:", id);             return;         }; -        let mut component = handle.lock().unwrap();-        component.test = !component.test;+        let component = update_shared_component(&handle, |component| {+            component.test = !component.test;+        });+         component.render(&element);     } }diff --git a/examples/threads/Cargo.lock b/examples/threads/Cargo.lockindex adc78bd..c1c4c48 100644--- a/examples/threads/Cargo.lock+++ b/examples/threads/Cargo.lock@@ -3,6 +3,15 @@ version = 4  [[package]]+name = "arc-swap"+version = "1.9.2"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b"+dependencies = [+ "rustversion",+]++[[package]] name = "async-channel" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -492,6 +501,7 @@ dependencies = [ name = "kaja-web" version = "1.0.2" dependencies = [+ "arc-swap",  "gloo",  "gloo-console",  "inventory",diff --git a/examples/threads/src/main_component.rs b/examples/threads/src/main_component.rsindex d2d99a7..161acc2 100644--- a/examples/threads/src/main_component.rs+++ b/examples/threads/src/main_component.rs@@ -1,6 +1,7 @@ use kaja_web::prelude::*; use std::time::Duration; +#[derive(Clone)] #[component("main-component")] struct Main {     test: bool,@@ -17,17 +18,16 @@ impl Component for Main {             id         ); -        let Some(handle) = Self::get_component(id) else {-            error!("Main component not found:", id);+        let Some(element) = get_element_by_id(id) else {+            error!("Element not found:", id);             return;         }; -        let Some(element) = get_element_by_id(id) else {-            error!("Element not found:", id);+        let Some(component) = Self::read_component(id) else {+            error!("Main component not found:", id);             return;         }; -        let mut component = handle.lock().unwrap();         component.render(&element);     } }@@ -40,16 +40,16 @@ impl Main {  fn start_background_thread(id: &str) {     let component_id = id.to_string();+    let Some(handle) = Main::get_component(id) else {+        error!("Main component not found:", id);+        return;+    }; -    crate::thread::spawn(move || {+    let _ = crate::thread::spawn(move || {         loop {-            let Some(handle) = Main::get_component(&component_id) else {-                error!("Main component not found:", &component_id);-                break;-            };--            let mut component = handle.lock().unwrap();-            component.test = !component.test;+            update_shared_component(&handle, |component| {+                component.test = !component.test;+            });              Main::post_ui_thread_update(component_id.as_str());             std::thread::sleep(Duration::from_millis(1000));diff --git a/examples/threads2/Cargo.lock b/examples/threads2/Cargo.lockindex 7eee037..54e7e2b 100644--- a/examples/threads2/Cargo.lock+++ b/examples/threads2/Cargo.lock@@ -501,6 +501,7 @@ dependencies = [ name = "kaja-web" version = "1.0.2" dependencies = [+ "arc-swap",  "gloo",  "gloo-console",  "inventory",diff --git a/examples/threads2/src/main_component.rs b/examples/threads2/src/main_component.rsindex 4ea862e..774f9a8 100644--- a/examples/threads2/src/main_component.rs+++ b/examples/threads2/src/main_component.rs@@ -7,6 +7,7 @@ use std::sync::RwLock; use std::time::Duration;  static THREAD_ID: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);+ std::thread_local! {     static THREAD_COMPONENT_MAP: RefCell<HashMap<String, ThreadComponent>> =         RefCell::new(HashMap::new());@@ -68,8 +69,9 @@ impl ThreadComponent { fn sync_and_update(thread_component: ThreadComponent, component_id: String) {}  fn start_background_threads(id: &str) {+    gloo::console::warn!("start_background_threads:", id);     let handle = Main::get_component(id).expect("Component not found");-    let component = handle.lock().unwrap().clone();+    let component = (*handle.load_full()).clone();      let thread_component = ThreadComponent::new(component, id);     start_background_updater(thread_component.shallow_clone(), id.to_string());diff --git a/src/lib.rs b/src/lib.rsindex fb7f425..aabe35d 100644--- a/src/lib.rs+++ b/src/lib.rs@@ -7,6 +7,8 @@ use gloo_console::{error, log}; use wasm_bindgen::JsCast; use web_sys::{Element, HtmlDocument, HtmlElement, HtmlInputElement, NodeList}; +pub use arc_swap::ArcSwap;+ pub mod prelude;  pub struct InitFn(pub fn());@@ -40,11 +42,26 @@ pub struct CallbackRegistration { inventory::collect!(CallbackRegistration);  pub trait ComponentStorage: Default + Sized {-    fn storage() -> &'static std::sync::RwLock<-        Option<std::collections::HashMap<String, std::sync::Arc<std::sync::Mutex<Self>>>>,+    fn storage() -> &'static std::thread::LocalKey<+        std::cell::RefCell<std::collections::HashMap<String, std::sync::Arc<ArcSwap<Self>>>>,     >; } +pub fn update_shared_component<T: Clone, F>(+    handle: &std::sync::Arc<ArcSwap<T>>,+    updater: F,+) -> std::sync::Arc<T>+where+    F: FnOnce(&mut T),+{+    let mut next = (*handle.load_full()).clone();+    updater(&mut next);++    let next = std::sync::Arc::new(next);+    handle.store(next.clone());+    next+}+ /// Register callbacks that can be used in JS to run Rust functions in the WASM /// module. This needs to run when the WASM bundle is loaded. ///diff --git a/src/prelude.rs b/src/prelude.rsindex 2d61f46..e4bf4b5 100644--- a/src/prelude.rs+++ b/src/prelude.rs@@ -1,13 +1,14 @@ pub use crate::{-    CallbackRegistration, Component, ComponentStorage, Error, InitComponentFn, InitFn, Result,-    get_callback, get_cookie_value, get_element, get_element_by_id, get_elements, get_value,-    init_callbacks, inner_html, inner_text, try_get_value, try_inner_html, try_inner_text,+    CallbackRegistration, Component, Error, InitComponentFn, InitFn, Result, get_callback,+    get_cookie_value, get_element, get_element_by_id, get_elements, get_value, init_callbacks,+    inner_html, inner_text, try_get_value, try_inner_html, try_inner_text, };  pub use gloo::console::error; pub use gloo::console::log; pub use serde_wasm_bindgen; +pub use arc_swap::ArcSwap; pub use std::collections::HashMap; pub use std::sync::{MutexGuard, RwLock}; 

Contact

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