osui::state
The state module provides OSUI's built-in reactivity system, allowing widgets to automatically update when their associated data changes. This is achieved through the State<T> struct and the DependencyHandler trait.
DependencyHandler Trait
A trait for types that can signal changes, triggering reactive updates in DynWidgets. State<T> is the primary implementer.
pub trait DependencyHandler: std::fmt::Debug + Send + Sync {
/// Called when a dependent widget registers itself with this dependency.
/// This typically increments an internal counter of dependents.
fn add(&self);
/// Returns `true` if the state has changed since the last `check()`.
/// If `true`, it typically "consumes" one change notification.
fn check(&self) -> bool;
}
State<T>
State<T> is a reactive data container. It wraps a value of type T and provides methods to get/set the value and signal changes to dependent widgets.
#[derive(Debug, Clone)]
pub struct State<T> {
inner: Arc<Mutex<Inner<T>>>,
}
#[derive(Debug)]
pub struct Inner<T> {
value: T,
dependencies: usize, // Count of widgets depending on this state
changed: usize, // Count of pending changes to be processed by dependents
}
Associated Functions
use_state<T>(v: T) -> State<T>
Creates a new State<T> instance, initialized with the provided value v.
This is the recommended way to create reactive state variables.
Arguments:
v: The initial value for the state.
Returns:
A new State<T> instance.
Example:
use osui::prelude::*;
let my_counter = use_state(0);
let my_text = use_state(String::from("Initial Text"));
Associated Methods
State::get_dl(&self) -> T
Returns a cloned copy of the inner value T.
This method is recommended for preventing potential deadlocks if you only need to read the value and don't need to hold a lock for extended periods. It does not mark the state as changed.
Returns:
A T (clone of the inner value).
Example:
use osui::prelude::*;
let my_state = use_state(42);
let value = my_state.get_dl(); // value is 42
State::get(&self) -> MutexGuard<'_, Inner<T>>
Acquires a MutexGuard for the inner Inner<T> struct, providing mutable (or immutable) access to the value within Inner<T>.
This method will block if another thread or part of the application is currently holding the lock.
Returns:
A MutexGuard that dereferences to Inner<T>. Since Inner<T> implements Deref and DerefMut for T, you can often treat state.get() as a direct reference to T.
Example (modifying value and marking as changed):
use osui::prelude::*;
let my_state = use_state(0);
{
let mut inner_guard = my_state.get(); // Acquire lock
*inner_guard += 1; // Modify value using DerefMut; automatically marks as changed
} // Lock is released here
State::set(&self, v: T)
Sets the inner value of the state to v and explicitly marks it as changed.
This is an alternative to acquiring a get() lock and reassigning.
Arguments:
v: The new value for the state.
Example:
use osui::prelude::*;
let my_state = use_state("hello".to_string());
my_state.set("world".to_string()); // State is updated and marked changed
State::update(&self)
Explicitly marks the state as updated without changing its value.
This is useful if you've modified the inner T through a method that doesn't trigger DerefMut on Inner<T> (e.g., if T is a complex mutable struct and you called a method on it while holding the MutexGuard without reassigning the T itself).
Example:
use osui::prelude::*;
#[derive(Debug, Clone)]
struct MyData { count: i32 }
let my_data_state = use_state(MyData { count: 0 });
{
let mut data_guard = my_data_state.get();
data_guard.count += 1; // Directly modify field within the guard
}
my_data_state.update(); // Manually signal that the state has changed
Implementations
impl<T: Debug + Send + Sync> DependencyHandler for State<T>
State<T> implements DependencyHandler.
add(): Incrementsinner.dependencies.check(): Returnstrueifinner.changed > 0, then decrementsinner.changed. This ensures each dependent consumes one change notification.
impl<T: Display> Display for State<T>
State<T> implements Display, allowing it to be formatted directly (e.g., in format! strings or debug output), by displaying its inner value.
Example:
use osui::prelude::*;
let count = use_state(10);
println!("Current count: {}", count); // Output: "Current count: 10"
impl<T> Deref for Inner<T>
Allows immutable dereferencing of Inner<T> to T.
This means state.get().value can be simply *state.get().
impl<T> DerefMut for Inner<T>
Allows mutable dereferencing of Inner<T> to T.
Crucially, when this is used, the changed counter within Inner<T> is set to dependencies, marking the state as changed for all its dependents.
This means *state.get() = new_value; will trigger the change notification.