use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use serde::Serialize;
use crate::helper::Invalidate;
use crate::mutation::Mutations;
impl<T: ?Sized> Invalidate<T> for bool {
fn invalidate(&mut self, _: &T) {
*self = true;
}
}
pub trait ObserverState<T: ?Sized>: Invalidate<T> {
fn observe(value: &T) -> Self;
}
pub trait SerializeObserverState<T: ?Sized>: ObserverState<T> {
fn flush(&mut self, value: &T) -> Mutations;
fn flat_flush(&mut self, _value: &T) -> Mutations {
panic!("flat_flush is not supported for this type")
}
}
impl<T: ?Sized> ObserverState<T> for bool {
fn observe(_: &T) -> Self {
false
}
}
impl<T: Serialize + ?Sized + 'static> SerializeObserverState<T> for bool {
fn flush(&mut self, value: &T) -> Mutations {
if std::mem::take(self) {
Mutations::replace(value)
} else {
Mutations::new()
}
}
}
pub struct ShallowDelegate<V: ?Sized> {
state: *mut V,
}
impl<V: ?Sized> ShallowDelegate<V> {
pub fn new(state: *mut V) -> Self {
Self { state }
}
}
impl<T: ?Sized, V: Invalidate<T> + ?Sized> Invalidate<T> for ShallowDelegate<V> {
fn invalidate(&mut self, value: &T) {
unsafe { Invalidate::invalidate(&mut *self.state, value) }
}
}
pub struct ShallowMut<'ob, T: ?Sized, V: ?Sized> {
pub(crate) inner: &'ob mut T,
pub(crate) state: *mut V,
}
impl<'ob, T: ?Sized, V: ?Sized> ShallowMut<'ob, T, V> {
pub fn new(inner: &'ob mut T, state: *mut V) -> Self {
Self { inner, state }
}
}
impl<'ob, T: ?Sized, V: ?Sized> Deref for ShallowMut<'ob, T, V> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.inner
}
}
impl<'ob, T: ?Sized, V: Invalidate<()> + ?Sized> DerefMut for ShallowMut<'ob, T, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { Invalidate::invalidate(&mut *self.state, &()) }
self.inner
}
}
impl<'ob, T: Debug + ?Sized, V: ?Sized> Debug for ShallowMut<'ob, T, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("ShallowMut").field(&self.inner).finish()
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __shallow_observer {
() => {};
($(#[$meta:meta])* struct $ob:ident ($($arg:tt)*); $($rest:tt)*) => {
$crate::__shallow_observer!(@impl $(#[$meta])* struct $ob [] ($($arg)*););
$crate::__shallow_observer!($($rest)*);
};
($(#[$meta:meta])* struct $ob:ident < $($rest:tt)*) => {
$crate::__shallow_observer!(@gen $(#[$meta])* struct $ob [] $($rest)*);
};
(@gen $(#[$meta:meta])* struct $ob:ident [$($gen:tt)*] > ($($arg:tt)*); $($rest:tt)*) => {
$crate::__shallow_observer!(@impl $(#[$meta])* struct $ob [$($gen)* ,] ($($arg)*););
$crate::__shallow_observer!($($rest)*);
};
(@gen $(#[$meta:meta])* struct $ob:ident [$($gen:tt)*] >> ($($arg:tt)*); $($rest:tt)*) => {
$crate::__shallow_observer!(@impl $(#[$meta])* struct $ob [$($gen)* >,] ($($arg)*););
$crate::__shallow_observer!($($rest)*);
};
(@gen $(#[$meta:meta])* struct $ob:ident [$($gen:tt)*] $tt:tt $($rest:tt)*) => {
$crate::__shallow_observer!(@gen $(#[$meta])* struct $ob [$($gen)* $tt] $($rest)*);
};
// Single-param with use<>: ty_gen in impls only, state = bool
(@impl $(#[$meta:meta])* struct $ob:ident [$($sg:tt)*] (use<$($tg:ident),*> $ty:ty);) => {
$crate::__shallow_observer!(@impl_body $(#[$meta])* struct $ob [$($sg)* $($tg,)*] [$($sg)*] ($ty) (bool););
};
(@impl $(#[$meta:meta])* struct $ob:ident [$($sg:tt)*] ($ty:ty);) => {
$crate::__shallow_observer!(@impl_body $(#[$meta])* struct $ob [$($sg)*] [$($sg)*] ($ty) (bool););
};
(@impl $(#[$meta:meta])* struct $ob:ident [$($sg:tt)*] (use<$($tg:ident),*> $vis_ptr:vis $ty:ty, $vis_state:vis $state:ty);) => {
$crate::__shallow_observer!(@impl_body $(#[$meta])* struct $ob [$($sg)* $($tg,)*] [$($sg)*] ($vis_ptr $ty) ($vis_state $state););
};
// Two-param without use<>: state_gen on struct
(@impl $(#[$meta:meta])* struct $ob:ident [$($sg:tt)*] ($vis_ptr:vis $ty:ty, $vis_state:vis $state:ty);) => {
$crate::__shallow_observer!(@impl_body $(#[$meta])* struct $ob [$($sg)*] [$($sg)*] ($vis_ptr $ty) ($vis_state $state););
};
(@impl_body $(#[$meta:meta])* struct $ob:ident [$($tg:tt)*] [$($sg:tt)*] ($vis_ptr:vis $ty:ty) ($vis_state:vis $state:ty);) => {
$(#[$meta])*
pub struct $ob<'ob, $($sg)* S: ?Sized, D = $crate::helper::Zero> {
$vis_ptr ptr: $crate::helper::Pointer<S>,
$vis_state state: $state,
pub(crate) phantom: ::std::marker::PhantomData<&'ob mut D>,
}
impl<'ob, $($sg)* S: ?Sized, D> ::std::ops::Deref for $ob<'ob, $($sg)* S, D> {
type Target = $crate::helper::Pointer<S>;
fn deref(&self) -> &Self::Target {
&self.ptr
}
}
impl<'ob, $($tg)* S: ?Sized, D> ::std::ops::DerefMut for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDeref<D, Target = $ty>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
::std::ptr::from_mut(self).expose_provenance();
$crate::helper::QuasiObserver::invalidate(&mut self.ptr);
&mut self.ptr
}
}
impl<'ob, $($tg)* S: ?Sized, D> $crate::helper::QuasiObserver for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDeref<D, Target = $ty>,
$state: $crate::helper::Invalidate<$ty>,
{
type Head = S;
type OuterDepth = $crate::helper::Succ<$crate::helper::Zero>;
type InnerDepth = D;
fn invalidate(this: &mut Self) {
$crate::helper::Invalidate::invalidate(&mut this.state, (*this.ptr).as_deref());
}
}
impl<'ob, $($tg)* S: ?Sized, D> $crate::observe::Observer for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDeref<D, Target = $ty>,
$state: $crate::helper::shallow::ObserverState<$ty>,
{
unsafe fn observe(head: *mut Self::Head) -> Self {
unsafe {
let this = Self {
state: $crate::helper::shallow::ObserverState::observe((&*head).as_deref()),
ptr: $crate::helper::Pointer::new_unchecked(head),
phantom: ::std::marker::PhantomData,
};
$crate::helper::Pointer::register_state::<_, D>(&this.ptr, &this.state);
this
}
}
unsafe fn relocate(this: &mut Self, head: *mut Self::Head) {
unsafe { $crate::helper::Pointer::set_unchecked(this, head) };
}
}
impl<'ob, $($tg)* S: ?Sized, D> $crate::observe::SerializeObserver for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDeref<D, Target = $ty>,
$state: $crate::helper::shallow::SerializeObserverState<$ty>,
{
fn flush(this: &mut Self) -> $crate::mutation::Mutations {
$crate::helper::shallow::SerializeObserverState::flush(
&mut this.state,
(*this.ptr).as_deref(),
)
}
fn flat_flush(this: &mut Self) -> $crate::mutation::Mutations {
$crate::helper::shallow::SerializeObserverState::flat_flush(
&mut this.state,
(*this.ptr).as_deref(),
)
}
}
impl<'ob, $($tg)* S: ?Sized, D> AsMut<$ty> for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDerefMut<D, Target = $ty>,
$state: $crate::helper::Invalidate<$ty>,
{
fn as_mut(&mut self) -> &mut $ty {
$crate::helper::QuasiObserver::tracked_mut(self)
}
}
impl<'ob, $($tg)* S: ?Sized, D> std::fmt::Debug for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDeref<D, Target = $ty>,
$state: $crate::helper::Invalidate<$ty>,
$ty: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(stringify!($ob)).field(&$crate::helper::QuasiObserver::untracked_ref(self)).finish()
}
}
impl<'ob, $($tg)* S: ?Sized, D> PartialEq for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDeref<D, Target = $ty>,
$state: $crate::helper::Invalidate<$ty>,
$ty: PartialEq,
{
fn eq(&self, other: &$ob<'ob, $($sg)* S, D>) -> bool {
$crate::helper::QuasiObserver::untracked_ref(self).eq($crate::helper::QuasiObserver::untracked_ref(other))
}
}
impl<'ob, $($tg)* S: ?Sized, D> Eq for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDeref<D, Target = $ty>,
$state: $crate::helper::Invalidate<$ty>,
$ty: Eq,
{
}
#[allow(clippy::non_canonical_partial_ord_impl)]
impl<'ob, $($tg)* S: ?Sized, D> PartialOrd for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDeref<D, Target = $ty>,
$state: $crate::helper::Invalidate<$ty>,
$ty: PartialOrd,
{
fn partial_cmp(&self, other: &$ob<'ob, $($sg)* S, D>) -> Option<std::cmp::Ordering> {
$crate::helper::QuasiObserver::untracked_ref(self).partial_cmp($crate::helper::QuasiObserver::untracked_ref(other))
}
}
impl<'ob, $($tg)* S: ?Sized, D> Ord for $ob<'ob, $($sg)* S, D>
where
D: $crate::helper::Unsigned,
S: $crate::helper::AsDeref<D, Target = $ty>,
$state: $crate::helper::Invalidate<$ty>,
$ty: Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
$crate::helper::QuasiObserver::untracked_ref(self).cmp($crate::helper::QuasiObserver::untracked_ref(other))
}
}
};
}
#[doc(inline)]
pub use crate::__shallow_observer as shallow_observer;