Commit 45ddf9d
ArcSwap instead of lock
Changed files (10)
modifiedCargo.lockmodifiedCargo.tomlmodifiedexamples/main-component/Cargo.lockmodifiedexamples/main-component/src/main_component.rsmodifiedexamples/threads/Cargo.lockmodifiedexamples/threads/src/main_component.rsmodifiedexamples/threads2/Cargo.lockmodifiedexamples/threads2/src/main_component.rsmodifiedsrc/lib.rsmodifiedsrc/prelude.rs
Diff
@@ -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",@@ -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" }@@ -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",@@ -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); } }@@ -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",@@ -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));@@ -501,6 +501,7 @@ dependencies = [ name = "kaja-web" version = "1.0.2" dependencies = [+ "arc-swap", "gloo", "gloo-console", "inventory",@@ -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());@@ -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. ///@@ -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};