Struct Signal

Source
pub struct Signal<T> { /* private fields */ }
Expand description

Mutable UI-local reactive cell with retained dependency observation.

Clones alias the same RefCell, source revision, historical invalidation callback, and dynamic retained consumers. A successful read during Build, Layout, or Paint records the innermost exact consumer; a read outside such a callback is passive. After a retained callback succeeds, its newly observed sources replace its previous sources as one update. This makes conditional reads follow the branch that actually committed; a panic keeps the previous observations. Unmounting a consumer removes its observations while leaving externally owned signals readable and mutable.

Mutations commit the value and revision, snapshot live retained consumers, release all value and subscriber borrows, notify those consumers, and then invoke the historical callback. Do not rely on ordering among retained consumers. Notification is synchronous and reentrant; if a retained consumer panics, later consumers and the historical callback are not invoked for that mutation. The Rc-based handle is neither Send nor Sync and must remain on its owning UI thread.

§Examples

use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(1)), Rc::new(|| {}));
let alias = signal.clone();
alias.set(2);
assert_eq!(signal.read(), 2);
assert_eq!(signal.revision(), 1);

Implementations§

Source§

impl<T> Signal<T>

Provides the operations defined for Signal<T>.

Source

pub fn new(value: Rc<RefCell<T>>, invalidate: Rc<dyn Fn()>) -> Self

Creates a signal around caller-owned storage and a historical callback.

The initial revision is zero. Multiple calls using the same value do not share revisions unless the resulting Signal itself is cloned. The callback is the historical, owner-provided invalidator: it may capture UI scheduling state and runs synchronously after exact retained consumers on every successful mutation. It remains installed even when no retained consumer has observed the signal. Reads establish dynamic dependencies independently of this callback.

§Examples
use std::{cell::{Cell, RefCell}, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let calls = Rc::new(Cell::new(0));
let observed = calls.clone();
let signal = Signal::new(Rc::new(RefCell::new("a")), Rc::new(move || observed.set(observed.get() + 1)));
signal.set("b");
assert_eq!(calls.get(), 1);
Source

pub fn set(&self, value: T)

Replaces the value, advances revision, then notifies all consumers.

Equality is not checked, so setting an equal value still invalidates. Revisions advance from zero to one and wrap from u64::MAX back to one; compare them for inequality, not ordering.

§Panics

Panics on a conflicting RefCell borrow or when a notification callback panics. In the callback case, the new value and revision remain committed. Retained consumers run before the historical callback; a retained panic stops the remaining notification sequence. All signal borrows are released before callbacks run, so a callback may read or mutate the signal again.

§Examples
use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(3)), Rc::new(|| {}));
signal.set(3);
assert_eq!(signal.read(), 3);
assert_eq!(signal.revision(), 1);
Source

pub fn update(&self, f: impl FnOnce(&mut T))

Mutates the value in place, advances revision, then notifies consumers.

The closure is called exactly once under a mutable RefCell borrow. This method does not detect whether the closure actually changed T.

§Panics

Panics on conflicting borrowing. If f panics, its partial mutation is retained but revision and notification are skipped. A notification panic propagates after mutation and revision commit, with the value borrow gone.

§Examples
use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(vec![1])), Rc::new(|| {}));
signal.update(|items| items.push(2));
assert_eq!(signal.read(), vec![1, 2]);
Source

pub fn revision(&self) -> u64

Returns and observes the shared mutation revision without borrowing T.

Zero means no successful mutating method has completed. The revision is nonzero thereafter but can repeat after u64 wraparound. In a retained observation scope this registers the same source as Self::read.

§Examples
use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(0)), Rc::new(|| {}));
assert_eq!(signal.revision(), 0);
signal.set(1);
assert_eq!(signal.revision(), 1);
Source§

impl<T: PartialEq> Signal<T>

Provides the operations defined for Signal<T>.

Source

pub fn set_if_changed(&self, value: T) -> bool

Replaces a small comparable value only when it actually changed.

This avoids needless invalidations for scalar/domain revision signals; it is not intended as a substitute for retained models or for comparing complete trees.

A false result performs no invalidation and does not advance revision. A true result commits the value before synchronously invalidating.

§Panics

Panics on a conflicting RefCell borrow, a panicking equality operation, or a panicking invalidation callback.

§Examples
use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(4)), Rc::new(|| {}));
assert!(!signal.set_if_changed(4));
assert!(signal.set_if_changed(5));
assert_eq!((signal.read(), signal.revision()), (5, 1));
Source§

impl<T: Clone> Signal<T>

Provides the operations defined for Signal<T>.

Source

pub fn read(&self) -> T

Clones, observes, and returns the current value.

§Panics

A successful read is attributed only to the innermost retained build, layout, or paint callback. Outside those callbacks it schedules no future frame. Panics when the value is already mutably borrowed through another alias.

§Examples
use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(String::from("hello"))), Rc::new(|| {}));
let copy = signal.read();
assert_eq!(copy, "hello");
Source

pub fn map<U: 'static>(&self, f: impl Fn(T) -> U + 'static) -> Memo<U>
where T: 'static,

Creates a lazy derived value whose revision mirrors this signal.

No value is cached: every Memo::read clones the current T and calls f. The mapping itself installs no additional historical callback. Reading the memo transitively observes this signal in the active retained consumer scope.

§Examples
use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(2)), Rc::new(|| {}));
let doubled = signal.map(|value| value * 2);
assert_eq!(doubled.read(), 4);
signal.set(3);
assert_eq!((doubled.read(), doubled.revision()), (6, 1));
Source§

impl<T> Signal<T>
where T: Clone + Display + 'static,

Source

pub fn to_text(&self) -> Memo<String>

Creates a lazy string memo using ToString::to_string.

§Examples
use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(42)), Rc::new(|| {}));
assert_eq!(signal.to_text().read(), "42");
Source§

impl<T> Signal<T>
where T: Clone + 'static,

Source

pub fn to_text_with<F>(&self, format: F) -> Memo<String>
where F: Fn(T) -> String + 'static,

Creates a lazy string memo using a custom owned-value formatter.

§Examples
use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(3)), Rc::new(|| {}));
assert_eq!(signal.to_text_with(|value| format!("#{value}")).read(), "#3");
Source§

impl<T: Default> Signal<T>

Provides the operations defined for Signal<T>.

Source

pub fn take(&self) -> T

Replaces the current value with Default and returns the old value.

Revision and invalidation always occur, even when the old value already equaled its default.

§Panics

Panics on conflicting borrowing or a panicking invalidation callback.

§Examples
use std::{cell::RefCell, rc::Rc};
use ailloli_ui_runtime::component::Signal;
let signal = Signal::new(Rc::new(RefCell::new(String::from("take"))), Rc::new(|| {}));
assert_eq!(signal.take(), "take");
assert_eq!(signal.take(), "");
assert_eq!(signal.revision(), 2);

Trait Implementations§

Source§

impl<T> Clone for Signal<T>

Implements the Clone contract for Signal<T>.

Source§

fn clone(&self) -> Self

Produces the clone required by the standard cloning contract.

1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T> From<Signal<T>> for Binding<T>

Implements the From<Signal<T>> contract for Binding<T>.

Source§

fn from(value: Signal<T>) -> Self

Performs the documented infallible conversion.

Source§

impl<T> From<State<T>> for Signal<T>

Implements the From<State<T>> contract for Signal<T>.

Source§

fn from(value: State<T>) -> Self

Performs the documented infallible conversion.

Auto Trait Implementations§

§

impl<T> Freeze for Signal<T>

§

impl<T> !RefUnwindSafe for Signal<T>

§

impl<T> !Send for Signal<T>

§

impl<T> !Sync for Signal<T>

§

impl<T> Unpin for Signal<T>

§

impl<T> !UnwindSafe for Signal<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<A> IntoClickAction<A> for A
where A: Clone + 'static,

Source§

fn into_click_action(self) -> ClickAction<A>

Implements the into_click_action helper used by this module.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> Props for T
where T: Clone + 'static,