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 DynWidget
s. 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()
: Returnstrue
ifinner.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.