use crate::*;
impl<T> Signal<T>
where
T: Clone + PartialEq + 'static,
{
pub fn create(value: T) -> Self {
let signal_inner: Rc<RefCell<SignalInner<T>>> =
Rc::new(RefCell::new(SignalInner::new(value, Vec::new(), true)));
let addr: usize = Rc::as_ptr(&signal_inner) as usize;
signal_inner_registry_mut().insert(addr, signal_inner as Rc<dyn Any>);
let mut signal: Self = Self::new(0, std::marker::PhantomData);
signal.set_inner(addr);
signal
}
fn inner_ref(&self) -> &'static RefCell<SignalInner<T>> {
get_signal_inner_ref(self.get_inner())
}
pub fn get(&self) -> T {
let inner_ref: &RefCell<SignalInner<T>> = self.inner_ref();
let Ok(inner) = inner_ref.try_borrow() else {
return unsafe { (*inner_ref.as_ptr()).get_value().clone() };
};
inner.get_value().clone()
}
pub fn subscribe<F>(&self, callback: F)
where
F: FnMut() + 'static,
{
if let Ok(mut inner) = self.inner_ref().try_borrow_mut() {
inner.get_mut_listeners().push(Box::new(callback));
}
}
pub(crate) fn replace_subscribe<F>(&self, callback: F)
where
F: FnMut() + 'static,
{
if let Ok(mut inner) = self.inner_ref().try_borrow_mut() {
let listeners: &mut Vec<Box<dyn FnMut()>> = inner.get_mut_listeners();
listeners.clear();
listeners.push(Box::new(callback));
}
}
pub(crate) fn clear_listeners(&self) {
if let Ok(mut inner) = self.inner_ref().try_borrow_mut() {
inner.set_alive(false);
inner.get_mut_listeners().clear();
}
}
fn update_and_notify(&self, value: T) -> bool {
let inner_ref: &RefCell<SignalInner<T>> = self.inner_ref();
let mut listeners: Vec<Box<dyn FnMut()>> = Vec::new();
let Ok(mut inner) = inner_ref.try_borrow_mut() else {
return false;
};
if !inner.get_alive() {
return false;
}
if *inner.get_value() == value {
return false;
}
inner.set_value(value);
swap(inner.get_mut_listeners(), &mut listeners);
for listener in listeners.iter_mut() {
listener();
}
if let Ok(mut inner) = inner_ref.try_borrow_mut() {
swap(inner.get_mut_listeners(), &mut listeners);
}
true
}
pub fn set(&self, value: T) {
if self.update_and_notify(value) {
schedule_signal_update();
}
}
pub fn set_silent(&self, value: T) {
self.update_and_notify(value);
}
pub fn set_untracked(&self, value: T) {
let inner_ref: &RefCell<SignalInner<T>> = self.inner_ref();
if let Ok(mut inner) = inner_ref.try_borrow_mut() {
inner.set_value(value);
}
}
}
impl<T> Clone for Signal<T>
where
T: Clone + PartialEq + 'static,
{
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Signal<T> where T: Clone + PartialEq + 'static {}
unsafe impl<T> Sync for SignalCell<T> where T: Clone + PartialEq + 'static {}
impl<T> SignalCell<T>
where
T: Clone + PartialEq + 'static,
{
pub const fn none() -> Self {
Self {
inner: UnsafeCell::new(None),
}
}
pub fn set(&self, signal: Signal<T>) {
unsafe {
let ptr: &mut Option<Signal<T>> = &mut *self.get_inner().get();
if ptr.is_some() {
panic!("SignalCell::set called on an already-initialized cell");
}
*ptr = Some(signal);
}
}
pub fn get(&self) -> Signal<T> {
unsafe {
let ptr: &Option<Signal<T>> = &*self.get_inner().get();
match ptr {
Some(signal) => *signal,
None => panic!("SignalCell::get called on an uninitialized cell"),
}
}
}
}
impl<T> Default for SignalCell<T>
where
T: Clone + PartialEq + 'static,
{
fn default() -> Self {
Self {
inner: UnsafeCell::new(None),
}
}
}
unsafe impl Sync for SignalInnerRegistryCell {}