use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
use crate::reactive::{next_signal_id, track_signal, trigger_signal, SignalId};
pub struct Signal<T> {
id: SignalId,
cell: Rc<RefCell<T>>,
drop_guard: Option<Rc<dyn Any>>,
}
impl<T> Clone for Signal<T> {
fn clone(&self) -> Self {
Signal {
id: self.id,
cell: self.cell.clone(),
drop_guard: self.drop_guard.clone(),
}
}
}
pub struct Setter<T> {
id: SignalId,
cell: Rc<RefCell<T>>,
}
impl<T> Clone for Setter<T> {
fn clone(&self) -> Self {
Setter {
id: self.id,
cell: self.cell.clone(),
}
}
}
pub struct RwSignal<T> {
id: SignalId,
cell: Rc<RefCell<T>>,
}
impl<T> Clone for RwSignal<T> {
fn clone(&self) -> Self {
RwSignal {
id: self.id,
cell: self.cell.clone(),
}
}
}
pub fn signal<T: 'static>(initial: T) -> (Signal<T>, Setter<T>) {
let id = next_signal_id();
let cell = Rc::new(RefCell::new(initial));
(
Signal {
id,
cell: cell.clone(),
drop_guard: None,
},
Setter { id, cell },
)
}
pub fn rw_signal<T: 'static>(initial: T) -> RwSignal<T> {
let id = next_signal_id();
let cell = Rc::new(RefCell::new(initial));
RwSignal { id, cell }
}
impl<T: Clone + 'static> Signal<T> {
pub fn get(&self) -> T {
track_signal(self.id);
self.cell.borrow().clone()
}
}
impl<T: 'static> Signal<T> {
pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
track_signal(self.id);
f(&self.cell.borrow())
}
pub fn id(&self) -> SignalId {
self.id
}
pub fn with_drop_guard<G: 'static>(mut self, guard: G) -> Self {
self.drop_guard = Some(Rc::new(guard));
self
}
}
impl<T: PartialEq + 'static> Setter<T> {
pub fn set(&self, value: T) {
if *self.cell.borrow() == value {
return;
}
*self.cell.borrow_mut() = value;
trigger_signal(self.id);
}
}
impl<T: 'static> Setter<T> {
pub fn set_force(&self, value: T) {
*self.cell.borrow_mut() = value;
trigger_signal(self.id);
}
pub fn update(&self, f: impl FnOnce(&mut T)) {
f(&mut self.cell.borrow_mut());
trigger_signal(self.id);
}
pub fn id(&self) -> SignalId {
self.id
}
}
impl<T: Clone + 'static> RwSignal<T> {
pub fn get(&self) -> T {
track_signal(self.id);
self.cell.borrow().clone()
}
}
impl<T: PartialEq + 'static> RwSignal<T> {
pub fn set(&self, value: T) {
if *self.cell.borrow() == value {
return;
}
*self.cell.borrow_mut() = value;
trigger_signal(self.id);
}
}
impl<T: 'static> RwSignal<T> {
pub fn with<R>(&self, f: impl FnOnce(&T) -> R) -> R {
track_signal(self.id);
f(&self.cell.borrow())
}
pub fn set_force(&self, value: T) {
*self.cell.borrow_mut() = value;
trigger_signal(self.id);
}
pub fn update(&self, f: impl FnOnce(&mut T)) {
f(&mut self.cell.borrow_mut());
trigger_signal(self.id);
}
pub fn id(&self) -> SignalId {
self.id
}
pub fn split(self) -> (Signal<T>, Setter<T>) {
(
Signal {
id: self.id,
cell: self.cell.clone(),
drop_guard: None,
},
Setter {
id: self.id,
cell: self.cell,
},
)
}
}