pub struct SharedContext<S>{ /* private fields */ }Expand description
Thread-safe shared state container.
SharedContext wraps user-defined shared state in an Arc<RwLock<S>>,
enabling safe concurrent access from multiple views. Each view receives
a cloned reference to the same underlying state.
§Type Parameters
S- The shared state type. Must implement:UiBindablefor XML binding access (e.g.,{shared.field})Send + Syncfor thread safety'staticfor Arc storage
§Example
use dampen_core::SharedContext;
use dampen_core::{UiBindable, BindingValue};
#[derive(Default, Clone)]
struct SharedState {
theme: String,
user_name: Option<String>,
}
impl UiBindable for SharedState {
fn get_field(&self, path: &[&str]) -> Option<BindingValue> {
match path {
["theme"] => Some(BindingValue::String(self.theme.clone())),
["user_name"] => match &self.user_name {
Some(name) => Some(BindingValue::String(name.clone())),
None => Some(BindingValue::None),
},
_ => None,
}
}
fn available_fields() -> Vec<String> {
vec!["theme".to_string(), "user_name".to_string()]
}
}
let ctx = SharedContext::new(SharedState::default());
let ctx2 = ctx.clone(); // Same underlying state
ctx.write().theme = "dark".to_string();
assert_eq!(ctx2.read().theme, "dark");§Lock Poisoning
If a thread panics while holding a write lock, the lock becomes “poisoned”.
The read() and write() methods will panic in this case. Use try_read()
and try_write() for fallible access.
Implementations§
Sourcepub fn new(initial: S) -> Self
pub fn new(initial: S) -> Self
Create a new SharedContext with initial state.
§Arguments
initial- The initial shared state value
§Example
use dampen_core::SharedContext;
use dampen_core::{UiBindable, BindingValue};
#[derive(Default)]
struct MyState { counter: i32 }
impl UiBindable for MyState {
fn get_field(&self, path: &[&str]) -> Option<BindingValue> {
match path {
["counter"] => Some(BindingValue::Integer(self.counter as i64)),
_ => None,
}
}
fn available_fields() -> Vec<String> { vec!["counter".to_string()] }
}
let ctx = SharedContext::new(MyState { counter: 42 });
assert_eq!(ctx.read().counter, 42);Sourcepub fn read(&self) -> RwLockReadGuard<'_, S>
pub fn read(&self) -> RwLockReadGuard<'_, S>
Acquire read access to shared state.
Returns a guard that provides immutable access to the shared state. Multiple readers can hold guards simultaneously.
§Panics
Panics if the lock is poisoned (a thread panicked while holding write lock).
Use try_read for fallible access.
§Example
use dampen_core::SharedContext;
use dampen_core::{UiBindable, BindingValue};
#[derive(Default)]
struct MyState { value: String }
impl UiBindable for MyState {
fn get_field(&self, path: &[&str]) -> Option<BindingValue> {
match path {
["value"] => Some(BindingValue::String(self.value.clone())),
_ => None,
}
}
fn available_fields() -> Vec<String> { vec!["value".to_string()] }
}
let ctx = SharedContext::new(MyState { value: "hello".to_string() });
let guard = ctx.read();
assert_eq!(guard.value, "hello");Sourcepub fn write(&self) -> RwLockWriteGuard<'_, S>
pub fn write(&self) -> RwLockWriteGuard<'_, S>
Acquire write access to shared state.
Returns a guard that provides mutable access to the shared state. Only one writer can hold the guard at a time, and no readers can access the state while a write guard is held.
§Panics
Panics if the lock is poisoned.
Use try_write for fallible access.
§Example
use dampen_core::SharedContext;
use dampen_core::{UiBindable, BindingValue};
#[derive(Default)]
struct MyState { counter: i32 }
impl UiBindable for MyState {
fn get_field(&self, path: &[&str]) -> Option<BindingValue> {
match path {
["counter"] => Some(BindingValue::Integer(self.counter as i64)),
_ => None,
}
}
fn available_fields() -> Vec<String> { vec!["counter".to_string()] }
}
let ctx = SharedContext::new(MyState { counter: 0 });
ctx.write().counter += 1;
assert_eq!(ctx.read().counter, 1);Sourcepub fn try_read(&self) -> Option<RwLockReadGuard<'_, S>>
pub fn try_read(&self) -> Option<RwLockReadGuard<'_, S>>
Try to acquire read access without blocking.
Returns None if the lock is currently held for writing or is poisoned.
This is useful when you want to avoid blocking on a potentially
long-held write lock.
§Example
use dampen_core::SharedContext;
use dampen_core::{UiBindable, BindingValue};
#[derive(Default)]
struct MyState { value: i32 }
impl UiBindable for MyState {
fn get_field(&self, path: &[&str]) -> Option<BindingValue> {
match path {
["value"] => Some(BindingValue::Integer(self.value as i64)),
_ => None,
}
}
fn available_fields() -> Vec<String> { vec!["value".to_string()] }
}
let ctx = SharedContext::new(MyState { value: 42 });
if let Some(guard) = ctx.try_read() {
assert_eq!(guard.value, 42);
}Sourcepub fn try_write(&self) -> Option<RwLockWriteGuard<'_, S>>
pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, S>>
Try to acquire write access without blocking.
Returns None if the lock is currently held (for reading or writing)
or is poisoned.
§Example
use dampen_core::SharedContext;
use dampen_core::{UiBindable, BindingValue};
#[derive(Default)]
struct MyState { value: i32 }
impl UiBindable for MyState {
fn get_field(&self, path: &[&str]) -> Option<BindingValue> {
match path {
["value"] => Some(BindingValue::Integer(self.value as i64)),
_ => None,
}
}
fn available_fields() -> Vec<String> { vec!["value".to_string()] }
}
let ctx = SharedContext::new(MyState { value: 0 });
if let Some(mut guard) = ctx.try_write() {
guard.value = 100;
}This allows applications that don’t use shared state to still compile without requiring a real shared state type.
Sourcepub fn empty() -> Self
pub fn empty() -> Self
Create an empty shared context (no-op).
Used internally when an application doesn’t configure shared state.
The resulting context holds unit type () and is essentially a no-op.
§Example
use dampen_core::SharedContext;
let ctx = SharedContext::<()>::empty();
// Can still call read/write, but they just return ()
let _guard = ctx.read();Trait Implementations§
This allows SharedContext to be used directly in widget builders and bindings without needing to extract the inner state first.
§Example
use dampen_core::{SharedContext, UiBindable, BindingValue};
#[derive(Default)]
struct MyState { value: i32 }
impl UiBindable for MyState {
fn get_field(&self, path: &[&str]) -> Option<BindingValue> {
match path {
["value"] => Some(BindingValue::Integer(self.value as i64)),
_ => None,
}
}
fn available_fields() -> Vec<String> { vec!["value".to_string()] }
}
let ctx = SharedContext::new(MyState { value: 42 });
// Can use ctx directly as &dyn UiBindable
assert_eq!(ctx.get_field(&["value"]), Some(BindingValue::Integer(42)));