use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use serde::Serialize;
use crate::general::Snapshot;
use crate::helper::macros::{spec_impl_observe, spec_impl_ref_observe};
use crate::helper::{AsDeref, AsDerefMut, Pointer, QuasiObserver, Succ, Unsigned, Zero};
use crate::observe::{DefaultSpec, Observer, RefObserve, RefObserver, SerializeObserver};
use crate::{Mutations, Observe};
pub struct TupleObserver<O, S: ?Sized, D = Zero>(pub O, Pointer<S>, PhantomData<D>);
impl<O, S: ?Sized, D> Deref for TupleObserver<O, S, D> {
type Target = Pointer<S>;
fn deref(&self) -> &Self::Target {
&self.1
}
}
impl<O, S: ?Sized, D> DerefMut for TupleObserver<O, S, D> {
fn deref_mut(&mut self) -> &mut Self::Target {
std::ptr::from_mut(self).expose_provenance();
Pointer::invalidate(&mut self.1);
&mut self.1
}
}
impl<O, S: ?Sized, D> QuasiObserver for TupleObserver<O, S, D>
where
O: QuasiObserver<Target: Deref<Target: AsDeref<O::InnerDepth>>>,
D: Unsigned,
S: AsDeref<D>,
{
type Head = S;
type OuterDepth = Succ<Zero>;
type InnerDepth = D;
fn invalidate(this: &mut Self) {
O::invalidate(&mut this.0);
}
}
impl<O, S: ?Sized, D> Observer for TupleObserver<O, S, D>
where
D: Unsigned,
S: AsDerefMut<D, Target = (O::Head,)>,
O: Observer<InnerDepth = Zero>,
O::Head: Sized,
{
fn observe(head: &mut Self::Head) -> Self {
let tuple = head.as_deref_mut();
let ob = O::observe(&mut tuple.0);
let ptr = Pointer::new(head);
let this = Self(ob, ptr, PhantomData);
Pointer::register_observer(&this.1, &this.0);
this
}
unsafe fn relocate(this: &mut Self, head: &mut Self::Head) {
let tuple = head.as_deref_mut();
unsafe { O::relocate(&mut this.0, &mut tuple.0) }
Pointer::set(&this.1, head);
}
}
impl<O, S: ?Sized, D> RefObserver for TupleObserver<O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = (O::Head,)>,
O: RefObserver<InnerDepth = Zero>,
O::Head: Sized,
{
fn observe(head: &Self::Head) -> Self {
let tuple = head.as_deref();
let this = Self(O::observe(&tuple.0), Pointer::new(head), PhantomData);
Pointer::register_observer(&this.1, &this.0);
this
}
unsafe fn relocate(this: &mut Self, head: &Self::Head) {
Pointer::set(&this.1, head);
let tuple = head.as_deref();
unsafe { O::relocate(&mut this.0, &tuple.0) }
}
}
impl<O, S: ?Sized, D> SerializeObserver for TupleObserver<O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = (O::Head,)>,
O: SerializeObserver<InnerDepth = Zero>,
O::Head: Serialize + Sized + 'static,
{
unsafe fn flush(this: &mut Self) -> Mutations {
let mutations_0 = unsafe { SerializeObserver::flush(&mut this.0) };
if mutations_0.is_replace() {
Mutations::replace((*this).untracked_ref())
} else {
mutations_0.with_prefix(0)
}
}
}
impl<O, S: ?Sized, D> Debug for TupleObserver<O, S, D>
where
O: QuasiObserver<Target: Deref<Target: AsDeref<O::InnerDepth>>>,
D: Unsigned,
S: AsDeref<D>,
S::Target: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("TupleObserver").field(&self.untracked_ref()).finish()
}
}
impl<O, S: ?Sized, D, U> PartialEq<(U,)> for TupleObserver<O, S, D>
where
O: QuasiObserver<Target: Deref<Target: AsDeref<O::InnerDepth>>>,
D: Unsigned,
S: AsDeref<D>,
S::Target: PartialEq<(U,)>,
{
fn eq(&self, other: &(U,)) -> bool {
self.untracked_ref().eq(other)
}
}
impl<O1, O2, S1: ?Sized, S2: ?Sized, D1, D2> PartialEq<TupleObserver<O2, S2, D2>> for TupleObserver<O1, S1, D1>
where
O1: QuasiObserver<Target: Deref<Target: AsDeref<O1::InnerDepth>>>,
O2: QuasiObserver<Target: Deref<Target: AsDeref<O2::InnerDepth>>>,
D1: Unsigned,
D2: Unsigned,
S1: AsDeref<D1>,
S2: AsDeref<D2>,
S1::Target: PartialEq<S2::Target>,
{
fn eq(&self, other: &TupleObserver<O2, S2, D2>) -> bool {
self.untracked_ref().eq(other.untracked_ref())
}
}
impl<O, S: ?Sized, D> Eq for TupleObserver<O, S, D>
where
O: QuasiObserver<Target: Deref<Target: AsDeref<O::InnerDepth>>>,
D: Unsigned,
S: AsDeref<D>,
S::Target: Eq,
{
}
impl<O, S: ?Sized, D, U> PartialOrd<(U,)> for TupleObserver<O, S, D>
where
O: QuasiObserver<Target: Deref<Target: AsDeref<O::InnerDepth>>>,
D: Unsigned,
S: AsDeref<D>,
S::Target: PartialOrd<(U,)>,
{
fn partial_cmp(&self, other: &(U,)) -> Option<std::cmp::Ordering> {
self.untracked_ref().partial_cmp(other)
}
}
impl<O1, O2, S1: ?Sized, S2: ?Sized, D1, D2> PartialOrd<TupleObserver<O2, S2, D2>> for TupleObserver<O1, S1, D1>
where
O1: QuasiObserver<Target: Deref<Target: AsDeref<O1::InnerDepth>>>,
O2: QuasiObserver<Target: Deref<Target: AsDeref<O2::InnerDepth>>>,
D1: Unsigned,
D2: Unsigned,
S1: AsDeref<D1>,
S2: AsDeref<D2>,
S1::Target: PartialOrd<S2::Target>,
{
fn partial_cmp(&self, other: &TupleObserver<O2, S2, D2>) -> Option<std::cmp::Ordering> {
self.untracked_ref().partial_cmp(other.untracked_ref())
}
}
impl<O, S: ?Sized, D> Ord for TupleObserver<O, S, D>
where
O: QuasiObserver<Target: Deref<Target: AsDeref<O::InnerDepth>>>,
D: Unsigned,
S: AsDeref<D>,
S::Target: Ord,
{
fn cmp(&self, other: &TupleObserver<O, S, D>) -> std::cmp::Ordering {
self.untracked_ref().cmp(other.untracked_ref())
}
}
spec_impl_observe! {
#[cfg_attr(docsrs, doc(fake_variadic))]
#[cfg_attr(docsrs, doc = "This trait is implemented for tuples up to 12 items long.")]
TupleObserveImpl, (Self,), (T,), TupleObserver
}
spec_impl_ref_observe! {
#[cfg_attr(docsrs, doc(fake_variadic))]
#[cfg_attr(docsrs, doc = "This trait is implemented for tuples up to 12 items long.")]
TupleRefObserveImpl, (Self,), (T,), TupleObserver
}
#[cfg_attr(docsrs, doc(fake_variadic))]
#[cfg_attr(docsrs, doc = "This trait is implemented for tuples up to 12 items long.")]
impl<T: Snapshot> Snapshot for (T,) {
type Snapshot = (T::Snapshot,);
fn to_snapshot(&self) -> Self::Snapshot {
(self.0.to_snapshot(),)
}
fn eq_snapshot(&self, snapshot: &Self::Snapshot) -> bool {
self.0.eq_snapshot(&snapshot.0)
}
}
macro_rules! tuple_observer {
($ty:ident; $ptr:tt; $($o:ident, $p:ident, $t:ident, $u:ident, $n:tt);*) => {
#[doc = concat!("Observer implementation for tuple `", stringify!(($($t),*)), "`.")]
pub struct $ty<$($o,)* S: ?Sized, D = Zero>(
$(pub $o,)*
Pointer<S>,
PhantomData<D>,
);
impl<$($o,)* S: ?Sized, D> Deref for $ty<$($o,)* S, D> {
type Target = Pointer<S>;
fn deref(&self) -> &Self::Target {
&self.$ptr
}
}
impl<$($o,)* S: ?Sized, D> DerefMut for $ty<$($o,)* S, D>
where
$($o: QuasiObserver<Target: Deref<Target: AsDeref<$o::InnerDepth>>>,)*
{
fn deref_mut(&mut self) -> &mut Self::Target {
std::ptr::from_mut(self).expose_provenance();
Pointer::invalidate(&mut self.$ptr);
&mut self.$ptr
}
}
impl<$($o,)* S: ?Sized, D> QuasiObserver for $ty<$($o,)* S, D>
where
$($o: QuasiObserver<Target: Deref<Target: AsDeref<$o::InnerDepth>>>,)*
D: Unsigned,
S: AsDeref<D>,
{
type Head = S;
type OuterDepth = Succ<Zero>;
type InnerDepth = D;
fn invalidate(this: &mut Self) {
$($o::invalidate(&mut this.$n);)*
}
}
impl<$($o,)* S: ?Sized, D> Observer for $ty<$($o,)* S, D>
where
D: Unsigned,
S: AsDerefMut<D, Target = ($($o::Head,)*)>,
$($o: Observer<InnerDepth = Zero, Head: Sized>,)*
{
fn observe(head: &mut Self::Head) -> Self {
let tuple = head.as_deref_mut();
let this = Self(
$($o::observe(&mut tuple.$n),)*
Pointer::new(head),
PhantomData,
);
$(Pointer::register_observer(&this.$ptr, &this.$n);)*
this
}
unsafe fn relocate(this: &mut Self, head: &mut Self::Head) {
let tuple = head.as_deref_mut();
unsafe {
$($o::relocate(&mut this.$n, &mut tuple.$n);)*
}
Pointer::set(&this.$ptr, head);
}
}
impl<$($o,)* S: ?Sized, D> RefObserver for $ty<$($o,)* S, D>
where
D: Unsigned,
S: AsDeref<D, Target = ($($o::Head,)*)>,
$($o: RefObserver<InnerDepth = Zero, Head: Sized>,)*
{
fn observe(head: &Self::Head) -> Self {
let tuple = head.as_deref();
let this = Self(
$($o::observe(&tuple.$n),)*
Pointer::new(head),
PhantomData,
);
$(Pointer::register_observer(&this.$ptr, &this.$n);)*
this
}
unsafe fn relocate(this: &mut Self, head: &Self::Head) {
Pointer::set(&this.$ptr, head);
let tuple = head.as_deref();
unsafe {
$($o::relocate(&mut this.$n, &tuple.$n);)*
}
}
}
impl<$($o,)* S: ?Sized, D> SerializeObserver for $ty<$($o,)* S, D>
where
D: Unsigned,
S: AsDeref<D, Target = ($($o::Head,)*)>,
$($o: SerializeObserver<InnerDepth = Zero, Head: Serialize + Sized + 'static>,)*
{
unsafe fn flush(this: &mut Self) -> Mutations {
let mutations_tuple = ($(unsafe { SerializeObserver::flush(&mut this.$n).with_prefix($n) },)*);
let capacity = 0 $(+ mutations_tuple.$n.len())*;
if capacity == $ptr {
return Mutations::replace((*this).untracked_ref());
}
let mut mutations = Mutations::new().with_capacity(capacity);
$(
mutations.extend(mutations_tuple.$n);
)*
mutations
}
}
impl<$($o,)* S: ?Sized, D> Debug for $ty<$($o,)* S, D>
where
$($o: QuasiObserver<Target: Deref<Target: AsDeref<$o::InnerDepth>>>,)*
D: Unsigned,
S: AsDeref<D>,
S::Target: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(stringify!($ty)).field(&self.untracked_ref()).finish()
}
}
impl<$($o,)* S: ?Sized, D, U> PartialEq<(U,)> for $ty<$($o,)* S, D>
where
$($o: QuasiObserver<Target: Deref<Target: AsDeref<$o::InnerDepth>>>,)*
D: Unsigned,
S: AsDeref<D>,
S::Target: PartialEq<(U,)>,
{
fn eq(&self, other: &(U,)) -> bool {
self.untracked_ref().eq(other)
}
}
impl<$($o,)* $($p,)* S1: ?Sized, S2: ?Sized, D1, D2> PartialEq<$ty<$($p,)* S2, D2>>
for $ty<$($o,)* S1, D1>
where
$($o: QuasiObserver<Target: Deref<Target: AsDeref<$o::InnerDepth>>>,)*
$($p: QuasiObserver<Target: Deref<Target: AsDeref<$p::InnerDepth>>>,)*
D1: Unsigned,
D2: Unsigned,
S1: AsDeref<D1>,
S2: AsDeref<D2>,
S1::Target: PartialEq<S2::Target>,
{
fn eq(&self, other: &$ty<$($p,)* S2, D2>) -> bool {
self.untracked_ref().eq(other.untracked_ref())
}
}
impl<$($o,)* S: ?Sized, D> Eq for $ty<$($o,)* S, D>
where
$($o: QuasiObserver<Target: Deref<Target: AsDeref<$o::InnerDepth>>>,)*
D: Unsigned,
S: AsDeref<D>,
S::Target: Eq,
{
}
impl<$($o,)* S: ?Sized, D, U> PartialOrd<(U,)> for $ty<$($o,)* S, D>
where
$($o: QuasiObserver<Target: Deref<Target: AsDeref<$o::InnerDepth>>>,)*
D: Unsigned,
S: AsDeref<D>,
S::Target: PartialOrd<(U,)>,
{
fn partial_cmp(&self, other: &(U,)) -> Option<std::cmp::Ordering> {
self.untracked_ref().partial_cmp(other)
}
}
impl<$($o,)* $($p,)* S1: ?Sized, S2: ?Sized, D1, D2> PartialOrd<$ty<$($p,)* S2, D2>>
for $ty<$($o,)* S1, D1>
where
$($o: QuasiObserver<Target: Deref<Target: AsDeref<$o::InnerDepth>>>,)*
$($p: QuasiObserver<Target: Deref<Target: AsDeref<$p::InnerDepth>>>,)*
D1: Unsigned,
D2: Unsigned,
S1: AsDeref<D1>,
S2: AsDeref<D2>,
S1::Target: PartialOrd<S2::Target>,
{
fn partial_cmp(&self, other: &$ty<$($p,)* S2, D2>) -> Option<std::cmp::Ordering> {
self.untracked_ref().partial_cmp(other.untracked_ref())
}
}
impl<$($o,)* S: ?Sized, D> Ord for $ty<$($o,)* S, D>
where
$($o: QuasiObserver<Target: Deref<Target: AsDeref<$o::InnerDepth>>>,)*
D: Unsigned,
S: AsDeref<D>,
S::Target: Ord,
{
fn cmp(&self, other: &$ty<$($o,)* S, D>) -> std::cmp::Ordering {
self.untracked_ref().cmp(other.untracked_ref())
}
}
#[cfg_attr(docsrs, doc(hidden))]
impl<$($t,)*> Observe for ($($t,)*)
where
$($t: Observe,)*
{
type Observer<'ob, S, D>
= $ty<$($t::Observer<'ob, $t, Zero>,)* S, D>
where
Self: 'ob,
D: Unsigned,
S: AsDerefMut<D, Target = Self> + ?Sized + 'ob;
type Spec = DefaultSpec;
}
#[cfg_attr(docsrs, doc(hidden))]
impl<$($t,)*> RefObserve for ($($t,)*)
where
$($t: RefObserve,)*
{
type Observer<'ob, S, D>
= $ty<$($t::Observer<'ob, $t, Zero>,)* S, D>
where
Self: 'ob,
D: Unsigned,
S: AsDeref<D, Target = Self> + ?Sized + 'ob;
type Spec = DefaultSpec;
}
impl<$($t: Snapshot,)*> Snapshot for ($($t,)*) {
type Snapshot = ($($t::Snapshot,)*);
fn to_snapshot(&self) -> Self::Snapshot {
($(self.$n.to_snapshot(),)*)
}
fn eq_snapshot(&self, snapshot: &Self::Snapshot) -> bool {
$(self.$n.eq_snapshot(&snapshot.$n))&&+
}
}
};
}
tuple_observer!(TupleObserver2; 2; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1);
tuple_observer!(TupleObserver3; 3; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2);
tuple_observer!(TupleObserver4; 4; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2; O4, P4, T4, U4, 3);
tuple_observer!(TupleObserver5; 5; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2; O4, P4, T4, U4, 3; O5, P5, T5, U5, 4);
tuple_observer!(TupleObserver6; 6; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2; O4, P4, T4, U4, 3; O5, P5, T5, U5, 4; O6, P6, T6, U6, 5);
tuple_observer!(TupleObserver7; 7; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2; O4, P4, T4, U4, 3; O5, P5, T5, U5, 4; O6, P6, T6, U6, 5; O7, P7, T7, U7, 6);
tuple_observer!(TupleObserver8; 8; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2; O4, P4, T4, U4, 3; O5, P5, T5, U5, 4; O6, P6, T6, U6, 5; O7, P7, T7, U7, 6; O8, P8, T8, U8, 7);
tuple_observer!(TupleObserver9; 9; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2; O4, P4, T4, U4, 3; O5, P5, T5, U5, 4; O6, P6, T6, U6, 5; O7, P7, T7, U7, 6; O8, P8, T8, U8, 7; O9, P9, T9, U9, 8);
tuple_observer!(TupleObserver10; 10; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2; O4, P4, T4, U4, 3; O5, P5, T5, U5, 4; O6, P6, T6, U6, 5; O7, P7, T7, U7, 6; O8, P8, T8, U8, 7; O9, P9, T9, U9, 8; O10, P10, T10, U10, 9);
tuple_observer!(TupleObserver11; 11; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2; O4, P4, T4, U4, 3; O5, P5, T5, U5, 4; O6, P6, T6, U6, 5; O7, P7, T7, U7, 6; O8, P8, T8, U8, 7; O9, P9, T9, U9, 8; O10, P10, T10, U10, 9; O11, P11, T11, U11, 10);
tuple_observer!(TupleObserver12; 12; O1, P1, T1, U1, 0; O2, P2, T2, U2, 1; O3, P3, T3, U3, 2; O4, P4, T4, U4, 3; O5, P5, T5, U5, 4; O6, P6, T6, U6, 5; O7, P7, T7, U7, 6; O8, P8, T8, U8, 7; O9, P9, T9, U9, 8; O10, P10, T10, U10, 9; O11, P11, T11, U11, 10; O12, P12, T12, U12, 11);
#[cfg(test)]
mod tests {
use morphix_test_utils::*;
use serde_json::json;
use crate::adapter::Json;
use crate::helper::QuasiObserver;
use crate::observe::{ObserveExt, SerializeObserverExt};
#[test]
fn no_change_returns_none() {
let mut tuple = (String::from("hello"),);
let mut ob = tuple.__observe();
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, None);
}
#[test]
fn append_triggers_append() {
let mut tuple = (String::from("hello"),);
let mut ob = tuple.__observe();
ob.0.push_str(" world");
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(append!(0, json!(" world"))));
}
#[test]
fn read_inner_after_deref_mut() {
let mut tuple = (String::from("hello"),);
let mut ob = tuple.__observe();
*ob.tracked_mut() = (String::from("world"),);
let s: &String = ob.0.untracked_ref();
assert_eq!(s.as_str(), "world");
}
#[test]
fn deref_triggers_replace() {
let mut tuple = (String::from("hello"),);
let mut ob = tuple.__observe();
*ob.tracked_mut() = (String::from("world"),);
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(_, json!(["world"]))));
let mut tuple = (String::from("hello"),);
let mut ob = tuple.__observe();
**ob = (String::from("hello world"),);
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(_, json!(["hello world"]))));
}
}