use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use serde::Serialize;
use crate::Mutations;
use crate::helper::{AsDeref, AsDerefMut, AsDerefPtrExt, Invalidate, Pointer, QuasiObserver, Succ, Unsigned, Zero};
use crate::observe::{Observer, SerializeObserver};
pub trait GeneralHandler: Invalidate<Self::Target> {
type Target: ?Sized;
fn observe(value: &Self::Target) -> Self;
}
pub trait SerializeHandler: GeneralHandler {
fn flush(&mut self, value: &Self::Target) -> Mutations;
}
pub trait ReplaceHandler: GeneralHandler {
fn is_replace(&self, value: &Self::Target) -> bool;
}
impl<H> SerializeHandler for H
where
H: ReplaceHandler,
H::Target: Serialize + 'static,
{
fn flush(&mut self, value: &Self::Target) -> Mutations {
let is_replace = ReplaceHandler::is_replace(self, value);
*self = H::observe(value);
if is_replace {
Mutations::replace(value)
} else {
Mutations::new()
}
}
}
pub trait DebugHandler: GeneralHandler {
const NAME: &'static str;
}
pub struct GeneralObserver<'ob, H, S: ?Sized, D = Zero> {
ptr: Pointer<S>,
handler: H,
phantom: PhantomData<&'ob mut D>,
}
impl<'ob, H, S: ?Sized, D> Deref for GeneralObserver<'ob, H, S, D> {
type Target = Pointer<S>;
fn deref(&self) -> &Self::Target {
&self.ptr
}
}
impl<'ob, H, S: ?Sized, D> DerefMut for GeneralObserver<'ob, H, S, D> {
fn deref_mut(&mut self) -> &mut Self::Target {
std::ptr::from_mut(self).expose_provenance();
Pointer::invalidate(&mut self.ptr);
&mut self.ptr
}
}
impl<'ob, H, S: ?Sized, D, T: ?Sized> QuasiObserver for GeneralObserver<'ob, H, S, D>
where
S: AsDeref<D, Target = T>,
H: GeneralHandler<Target = T>,
D: Unsigned,
{
type Head = S;
type OuterDepth = Succ<Zero>;
type InnerDepth = D;
fn invalidate(this: &mut Self) {
H::invalidate(&mut this.handler, (*this.ptr).as_deref());
}
}
impl<'ob, H, S: ?Sized, D, T: ?Sized> Observer for GeneralObserver<'ob, H, S, D>
where
S: AsDeref<D, Target = T>,
H: GeneralHandler<Target = T>,
D: Unsigned,
{
unsafe fn observe(head: *mut Self::Head) -> Self {
unsafe {
let this = Self {
handler: H::observe(&*head.as_deref_ptr::<D>()),
ptr: Pointer::new_unchecked(head),
phantom: PhantomData,
};
Pointer::register_state::<_, D>(&this.ptr, &this.handler);
this
}
}
unsafe fn relocate(this: &mut Self, head: *mut Self::Head) {
unsafe { Pointer::set_unchecked(this, head) };
}
}
impl<'ob, H, S: ?Sized, D, T: ?Sized> SerializeObserver for GeneralObserver<'ob, H, S, D>
where
S: AsDeref<D, Target = T>,
H: SerializeHandler<Target = T>,
D: Unsigned,
{
fn flush(this: &mut Self) -> Mutations {
this.handler.flush((*this.ptr).as_deref())
}
}
macro_rules! impl_fmt {
($($trait:ident),* $(,)?) => {
$(
impl<'ob, H, S: ?Sized, D> std::fmt::$trait for GeneralObserver<'ob, H, S, D>
where
H: GeneralHandler<Target = S::Target>,
S: AsDeref<D>,
D: Unsigned,
S::Target: std::fmt::$trait,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::$trait::fmt(self.untracked_ref(), f)
}
}
)*
};
}
impl_fmt! {
Binary,
Display,
LowerExp,
LowerHex,
Octal,
Pointer,
UpperExp,
UpperHex,
}
impl<'ob, H, S: ?Sized, D, T: ?Sized> Debug for GeneralObserver<'ob, H, S, D>
where
S: AsDeref<D, Target = T>,
H: DebugHandler<Target = T>,
D: Unsigned,
T: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(H::NAME).field(&self.untracked_ref()).finish()
}
}
impl<'ob, H, S: ?Sized, D, I> std::ops::Index<I> for GeneralObserver<'ob, H, S, D>
where
H: GeneralHandler<Target = S::Target>,
S: AsDeref<D>,
D: Unsigned,
S::Target: std::ops::Index<I>,
{
type Output = <S::Target as std::ops::Index<I>>::Output;
fn index(&self, index: I) -> &Self::Output {
self.untracked_ref().index(index)
}
}
impl<'ob, H, S: ?Sized, D, I> std::ops::IndexMut<I> for GeneralObserver<'ob, H, S, D>
where
S: AsDerefMut<D>,
H: GeneralHandler<Target = S::Target>,
D: Unsigned,
S::Target: std::ops::IndexMut<I>,
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
self.tracked_mut().index_mut(index)
}
}
impl<'ob, H1, H2, S1: ?Sized, S2: ?Sized, D1, D2> PartialEq<GeneralObserver<'ob, H2, S2, D2>>
for GeneralObserver<'ob, H1, S1, D1>
where
H1: GeneralHandler<Target = S1::Target>,
H2: GeneralHandler<Target = S2::Target>,
S1: AsDeref<D1>,
S2: AsDeref<D2>,
D1: Unsigned,
D2: Unsigned,
S1::Target: PartialEq<S2::Target>,
{
fn eq(&self, other: &GeneralObserver<'ob, H2, S2, D2>) -> bool {
self.untracked_ref().eq(other.untracked_ref())
}
}
impl<'ob, H, S: ?Sized, D> Eq for GeneralObserver<'ob, H, S, D>
where
H: GeneralHandler<Target = S::Target>,
S: AsDeref<D>,
D: Unsigned,
S::Target: Eq,
{
}
impl<'ob, H1, H2, S1: ?Sized, S2: ?Sized, D1, D2> PartialOrd<GeneralObserver<'ob, H2, S2, D2>>
for GeneralObserver<'ob, H1, S1, D1>
where
H1: GeneralHandler<Target = S1::Target>,
H2: GeneralHandler<Target = S2::Target>,
S1: AsDeref<D1>,
S2: AsDeref<D2>,
D1: Unsigned,
D2: Unsigned,
S1::Target: PartialOrd<S2::Target>,
{
fn partial_cmp(&self, other: &GeneralObserver<'ob, H2, S2, D2>) -> Option<std::cmp::Ordering> {
self.untracked_ref().partial_cmp(other.untracked_ref())
}
}
impl<'ob, H, S: ?Sized, D> Ord for GeneralObserver<'ob, H, S, D>
where
H: GeneralHandler<Target = S::Target>,
S: AsDeref<D>,
D: Unsigned,
S::Target: Ord,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.untracked_ref().cmp(other.untracked_ref())
}
}
macro_rules! impl_ops_assign {
($($trait:ident => $method:ident),* $(,)?) => {
$(
impl<'ob, H, S: ?Sized, D, T: ?Sized, U> std::ops::$trait<U> for GeneralObserver<'ob, H, S, D>
where
S: AsDerefMut<D, Target = T>,
H: GeneralHandler<Target = T>,
D: Unsigned,
T: std::ops::$trait<U>,
{
fn $method(&mut self, rhs: U) {
self.tracked_mut().$method(rhs);
}
}
)*
};
}
impl_ops_assign! {
AddAssign => add_assign,
SubAssign => sub_assign,
MulAssign => mul_assign,
DivAssign => div_assign,
RemAssign => rem_assign,
BitAndAssign => bitand_assign,
BitOrAssign => bitor_assign,
BitXorAssign => bitxor_assign,
ShlAssign => shl_assign,
ShrAssign => shr_assign,
}
macro_rules! impl_ops_copy {
($($trait:ident => $method:ident),* $(,)?) => {
$(
impl<'ob, H, S: ?Sized, D, T: ?Sized, U> std::ops::$trait<U> for GeneralObserver<'ob, H, S, D>
where
H: GeneralHandler<Target = T>,
S: AsDeref<D, Target = T>,
D: Unsigned,
T: std::ops::$trait<U> + Copy,
{
type Output = <T as std::ops::$trait<U>>::Output;
fn $method(self, rhs: U) -> Self::Output {
self.untracked_ref().$method(rhs)
}
}
)*
};
}
impl_ops_copy! {
Add => add,
Sub => sub,
Mul => mul,
Div => div,
Rem => rem,
BitAnd => bitand,
BitOr => bitor,
BitXor => bitxor,
Shl => shl,
Shr => shr,
}
macro_rules! impl_ops_copy_unary {
($($trait:ident => $method:ident),* $(,)?) => {
$(
impl<'ob, H, S: ?Sized, D, T: ?Sized> std::ops::$trait for GeneralObserver<'ob, H, S, D>
where
H: GeneralHandler<Target = T>,
S: AsDeref<D, Target = T>,
D: Unsigned,
T: std::ops::$trait + Copy,
{
type Output = <T as std::ops::$trait>::Output;
fn $method(self) -> Self::Output {
(*self.untracked_ref()).$method()
}
}
)*
}
}
impl_ops_copy_unary! {
Neg => neg,
Not => not,
}