use std::sync::{LazyLock, OnceLock};
use generational_box::{Owner, SyncStorage};
use crate::{ReactiveHandle, ReactiveMutRef, ReactiveRef, WakerMap};
mod use_atom;
pub use use_atom::UseAtom;
pub(crate) static OWNER: LazyLock<Owner<SyncStorage>> = LazyLock::new(Owner::default);
pub type AtomState<T> = ReactiveHandle<T, WakerMap>;
pub type AtomStateRef<'a, T> = ReactiveRef<'a, T, WakerMap>;
pub type AtomStateMut<'a, T> = ReactiveMutRef<'a, T, WakerMap>;
pub struct Atom<T>
where
T: Send + Sync + 'static,
{
init: fn() -> T,
cell: OnceLock<AtomState<T>>,
}
impl<T> Atom<T>
where
T: Send + Sync + 'static,
{
pub const fn new(init: fn() -> T) -> Self {
Self {
init,
cell: OnceLock::new(),
}
}
pub fn state(&self) -> AtomState<T> {
*self.cell.get_or_init(|| AtomState::new((self.init)()))
}
pub fn get(&self) -> T
where
T: Copy,
{
self.state().get()
}
pub fn set(&self, value: T) {
self.state().set(value);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add_and_sub_assign_mutate_value() {
let mut state = AtomState::new(0i32);
state += 5;
assert_eq!(state.get(), 5);
state -= 2;
assert_eq!(state.get(), 3);
}
#[test]
fn set_overwrites_and_get_reads() {
let mut state = AtomState::new(10i32);
state.set(42);
assert_eq!(state.get(), 42);
}
#[test]
fn copy_handles_share_storage() {
let mut state = AtomState::new(1i32);
let state2 = state;
state += 41;
assert_eq!(state.get(), 42);
assert_eq!(state2.get(), 42);
}
static A: Atom<i32> = Atom::new(|| 7);
#[test]
fn atom_lazy_init_and_get_set() {
assert_eq!(A.get(), 7);
A.set(10);
assert_eq!(A.get(), 10);
}
#[test]
fn atom_state_handle_shares_value() {
static B: Atom<i32> = Atom::new(|| 0);
let mut handle = B.state();
handle += 5;
assert_eq!(B.get(), 5);
assert_eq!(B.state().get(), 5);
}
}