use super::{guards::WriteGuard, ArcWriteSignal};
use crate::{
owner::{ArenaItem, FromLocal, LocalStorage, Storage, SyncStorage},
traits::{
DefinedAt, Dispose, IntoInner, IsDisposed, Notify, UntrackableGuard,
Write,
},
};
use core::fmt::Debug;
use guardian::ArcRwLockWriteGuardian;
use std::{hash::Hash, ops::DerefMut, panic::Location, sync::Arc};
pub struct WriteSignal<T, S = SyncStorage> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
pub(crate) defined_at: &'static Location<'static>,
pub(crate) inner: ArenaItem<ArcWriteSignal<T>, S>,
}
impl<T, S> Dispose for WriteSignal<T, S> {
fn dispose(self) {
self.inner.dispose()
}
}
impl<T, S> Copy for WriteSignal<T, S> {}
impl<T, S> Clone for WriteSignal<T, S> {
fn clone(&self) -> Self {
*self
}
}
impl<T, S> Debug for WriteSignal<T, S>
where
S: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WriteSignal")
.field("type", &std::any::type_name::<T>())
.field("store", &self.inner)
.finish()
}
}
impl<T, S> PartialEq for WriteSignal<T, S> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<T, S> Eq for WriteSignal<T, S> {}
impl<T, S> Hash for WriteSignal<T, S> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
impl<T, S> DefinedAt for WriteSignal<T, S> {
fn defined_at(&self) -> Option<&'static Location<'static>> {
#[cfg(any(debug_assertions, leptos_debuginfo))]
{
Some(self.defined_at)
}
#[cfg(not(any(debug_assertions, leptos_debuginfo)))]
{
None
}
}
}
impl<T> From<ArcWriteSignal<T>> for WriteSignal<T>
where
T: Send + Sync + 'static,
{
#[track_caller]
fn from(value: ArcWriteSignal<T>) -> Self {
WriteSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}
}
}
impl<T> FromLocal<ArcWriteSignal<T>> for WriteSignal<T, LocalStorage>
where
T: 'static,
{
#[track_caller]
fn from_local(value: ArcWriteSignal<T>) -> Self {
WriteSignal {
#[cfg(any(debug_assertions, leptos_debuginfo))]
defined_at: Location::caller(),
inner: ArenaItem::new_with_storage(value),
}
}
}
impl<T, S> IsDisposed for WriteSignal<T, S> {
fn is_disposed(&self) -> bool {
self.inner.is_disposed()
}
}
impl<T, S> IntoInner for WriteSignal<T, S>
where
S: Storage<ArcWriteSignal<T>>,
{
type Value = T;
#[inline(always)]
fn into_inner(self) -> Option<Self::Value> {
self.inner.into_inner()?.into_inner()
}
}
impl<T, S> Notify for WriteSignal<T, S>
where
T: 'static,
S: Storage<ArcWriteSignal<T>>,
{
fn notify(&self) {
if let Some(inner) = self.inner.try_get_value() {
inner.notify();
}
}
}
impl<T, S> Write for WriteSignal<T, S>
where
T: 'static,
S: Storage<ArcWriteSignal<T>>,
{
type Value = T;
fn try_write(&self) -> Option<impl UntrackableGuard<Target = Self::Value>> {
let guard = self.inner.try_with_value(|n| {
ArcRwLockWriteGuardian::take(Arc::clone(&n.value)).ok()
})??;
Some(WriteGuard::new(*self, guard))
}
fn try_write_untracked(
&self,
) -> Option<impl DerefMut<Target = Self::Value>> {
self.inner
.try_with_value(|n| n.try_write_untracked())
.flatten()
}
}