use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut, Range, RangeFrom, RangeInclusive, RangeTo};
use serde::Serialize;
use crate::Mutations;
use crate::general::Snapshot;
use crate::helper::macros::{spec_impl_observe, spec_impl_observe_from_ref, spec_impl_ref_observe};
use crate::helper::{AsDeref, AsDerefMut, Pointer, QuasiObserver, Succ, Unsigned, Zero};
use crate::observe::{Observer, RefObserver, SerializeObserver};
macro_rules! impl_range {
($($ty:ident ($($field:ident),* $(,)?) => $ob:ident, $helper_ref:ident, $helper_mut:ident;)*) => {
$(
/// Observer implementation for [`Range<Idx>`].
#[doc = concat!("Observer implementation for [`", stringify!($ty), "<Idx>`].")]
pub struct $ob<O, S: ?Sized, D = Zero> {
$(
#[doc = concat!("See [`", stringify!($ty), "::", stringify!($field), "`].")]
pub $field: O,
)*
ptr: Pointer<S>,
phantom: PhantomData<D>,
}
impl<O, S: ?Sized, D> Deref for $ob<O, S, D> {
type Target = Pointer<S>;
fn deref(&self) -> &Self::Target {
&self.ptr
}
}
impl<O, S: ?Sized, D> DerefMut for $ob<O, 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<O, S: ?Sized, D> QuasiObserver for $ob<O, S, D>
where
O: QuasiObserver,
D: Unsigned,
S: AsDeref<D>,
{
type Head = S;
type OuterDepth = Succ<Zero>;
type InnerDepth = D;
fn invalidate(this: &mut Self) {
$(O::invalidate(&mut this.$field);)*
}
}
impl<O, S: ?Sized, D> Observer for $ob<O, S, D>
where
D: Unsigned,
S: AsDerefMut<D, Target = $ty<O::Head>>,
O: Observer<InnerDepth = Zero>,
O::Head: Sized,
{
fn observe(head: &mut Self::Head) -> Self {
let value = head.as_deref_mut();
let this = Self {
$($field: O::observe(&mut value.$field),)*
ptr: Pointer::new(head),
phantom: PhantomData,
};
$(Pointer::register_observer(&this.ptr, &this.$field);)*
this
}
unsafe fn relocate(this: &mut Self, head: &mut Self::Head) {
let value = head.as_deref_mut();
unsafe {
$(O::relocate(&mut this.$field, &mut value.$field);)*
}
Pointer::set(this, head);
}
}
impl<O, S: ?Sized, D> RefObserver for $ob<O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = $ty<O::Head>>,
O: RefObserver<InnerDepth = Zero>,
O::Head: Sized,
{
fn observe(head: &Self::Head) -> Self {
let value = head.as_deref();
let this = Self {
$($field: O::observe(&value.$field),)*
ptr: Pointer::new(head),
phantom: PhantomData,
};
$(Pointer::register_observer(&this.ptr, &this.$field);)*
this
}
unsafe fn relocate(this: &mut Self, head: &Self::Head) {
Pointer::set(this, head);
let value = head.as_deref();
unsafe {
$(O::relocate(&mut this.$field, &value.$field);)*
}
}
}
impl<O, S: ?Sized, D> SerializeObserver for $ob<O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = $ty<O::Head>>,
O: SerializeObserver<InnerDepth = Zero>,
O::Head: Serialize + Sized + 'static,
{
unsafe fn flush(this: &mut Self) -> Mutations {
$(
let $field = unsafe { SerializeObserver::flush(&mut this.$field).with_prefix(stringify!($field)) };
)*
if $($field.is_replace())&&* {
Mutations::replace((*this).untracked_ref())
} else {
let mut mutations = Mutations::new();
$(mutations.extend($field);)*
mutations
}
}
unsafe fn flat_flush(this: &mut Self) -> Mutations {
$(
let $field = unsafe { SerializeObserver::flush(&mut this.$field).with_prefix(stringify!($field)) };
)*
let mut mutations = Mutations::new().with_replace($($field.is_replace())&&*);
$(mutations.extend($field);)*
mutations
}
}
impl<O, S: ?Sized, D> Debug for $ob<O, S, D>
where
O: QuasiObserver,
D: Unsigned,
S: AsDeref<D>,
S::Target: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple(stringify!($ob)).field(&self.untracked_ref()).finish()
}
}
impl<O, S: ?Sized, D, U> PartialEq<$ty<U>> for $ob<O, S, D>
where
O: QuasiObserver,
D: Unsigned,
S: AsDeref<D>,
S::Target: PartialEq<$ty<U>>,
{
fn eq(&self, other: &$ty<U>) -> bool {
self.untracked_ref().eq(other)
}
}
impl<O1, O2, S1: ?Sized, S2: ?Sized, D1, D2> PartialEq<$ob<O2, S2, D2>> for $ob<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: &$ob<O2, S2, D2>) -> bool {
self.untracked_ref().eq(other.untracked_ref())
}
}
impl<O, S: ?Sized, D> Eq for $ob<O, S, D>
where
O: QuasiObserver,
D: Unsigned,
S: AsDeref<D>,
S::Target: Eq,
{
}
spec_impl_observe!($helper_ref, $ty<Self>, $ty<T>, $ob);
spec_impl_ref_observe!($helper_mut, $ty<Self>, $ty<T>, $ob);
impl<T: Snapshot> Snapshot for $ty<T> {
type Snapshot = $ty<T::Snapshot>;
fn to_snapshot(&self) -> Self::Snapshot {
$ty {
$($field: self.$field.to_snapshot(),)*
}
}
fn eq_snapshot(&self, snapshot: &Self::Snapshot) -> bool {
$(self.$field.eq_snapshot(&snapshot.$field))&&*
}
}
)*
};
}
impl_range! {
Range (start, end) => RangeObserver, RangeObserveImpl, RangeRefObserveImpl;
RangeFrom (start) => RangeFromObserver, RangeFromObserveImpl, RangeFromRefObserveImpl;
RangeTo (end) => RangeToObserver, RangeToObserveImpl, RangeToRefObserveImpl;
}
pub struct RangeInclusiveObserver<O, S: ?Sized, D = Zero> {
start: O,
end: O,
ptr: Pointer<S>,
phantom: PhantomData<D>,
}
impl<O, S: ?Sized, D> Deref for RangeInclusiveObserver<O, S, D> {
type Target = Pointer<S>;
fn deref(&self) -> &Self::Target {
&self.ptr
}
}
impl<O, S: ?Sized, D> DerefMut for RangeInclusiveObserver<O, 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<O, S: ?Sized, D> QuasiObserver for RangeInclusiveObserver<O, S, D>
where
O: QuasiObserver,
D: Unsigned,
S: AsDeref<D>,
{
type Head = S;
type OuterDepth = Succ<Zero>;
type InnerDepth = D;
fn invalidate(this: &mut Self) {
O::invalidate(&mut this.start);
O::invalidate(&mut this.end);
}
}
impl<O, S: ?Sized, D> Observer for RangeInclusiveObserver<O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = RangeInclusive<O::Head>>,
O: RefObserver<InnerDepth = Zero>,
O::Head: Sized,
{
fn observe(head: &mut Self::Head) -> Self {
let value = (*head).as_deref();
let this = Self {
start: O::observe(value.start()),
end: O::observe(value.end()),
ptr: Pointer::new(head),
phantom: PhantomData,
};
Pointer::register_observer(&this.ptr, &this.start);
Pointer::register_observer(&this.ptr, &this.end);
this
}
unsafe fn relocate(this: &mut Self, head: &mut Self::Head) {
let value = (*head).as_deref();
unsafe {
O::relocate(&mut this.start, value.start());
O::relocate(&mut this.end, value.end());
}
Pointer::set(this, head);
}
}
impl<O, S: ?Sized, D> RefObserver for RangeInclusiveObserver<O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = RangeInclusive<O::Head>>,
O: RefObserver<InnerDepth = Zero>,
O::Head: Sized,
{
fn observe(head: &Self::Head) -> Self {
let value = head.as_deref();
let this = Self {
ptr: Pointer::new(head),
start: O::observe(value.start()),
end: O::observe(value.end()),
phantom: PhantomData,
};
Pointer::register_observer(&this.ptr, &this.start);
Pointer::register_observer(&this.ptr, &this.end);
this
}
unsafe fn relocate(this: &mut Self, head: &Self::Head) {
Pointer::set(this, head);
let value = head.as_deref();
unsafe {
O::relocate(&mut this.start, value.start());
O::relocate(&mut this.end, value.end());
}
}
}
impl<O, S: ?Sized, D> SerializeObserver for RangeInclusiveObserver<O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = RangeInclusive<O::Head>>,
O: SerializeObserver<InnerDepth = Zero>,
O::Head: Serialize + Sized + 'static,
{
unsafe fn flush(this: &mut Self) -> Mutations {
let mutations_start = unsafe { SerializeObserver::flush(&mut this.start).with_prefix("start") };
let mutations_end = unsafe { SerializeObserver::flush(&mut this.end).with_prefix("end") };
if mutations_start.is_replace() && mutations_end.is_replace() {
Mutations::replace((*this).untracked_ref())
} else {
let mut mutations = Mutations::new();
mutations.extend(mutations_start);
mutations.extend(mutations_end);
mutations
}
}
unsafe fn flat_flush(this: &mut Self) -> Mutations {
let mutations_start = unsafe { SerializeObserver::flush(&mut this.start).with_prefix("start") };
let mutations_end = unsafe { SerializeObserver::flush(&mut this.end).with_prefix("end") };
let mut mutations = Mutations::new().with_replace(mutations_start.is_replace() && mutations_end.is_replace());
mutations.extend(mutations_start);
mutations.extend(mutations_end);
mutations
}
}
impl<O, S: ?Sized, D> Debug for RangeInclusiveObserver<O, S, D>
where
O: QuasiObserver,
D: Unsigned,
S: AsDeref<D>,
S::Target: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("RangeInclusiveObserver")
.field(&self.untracked_ref())
.finish()
}
}
impl<O, S: ?Sized, D, U> PartialEq<RangeInclusive<U>> for RangeInclusiveObserver<O, S, D>
where
O: QuasiObserver,
D: Unsigned,
S: AsDeref<D>,
S::Target: PartialEq<RangeInclusive<U>>,
{
fn eq(&self, other: &RangeInclusive<U>) -> bool {
self.untracked_ref().eq(other)
}
}
impl<O1, O2, S1: ?Sized, S2: ?Sized, D1, D2> PartialEq<RangeInclusiveObserver<O2, S2, D2>>
for RangeInclusiveObserver<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: &RangeInclusiveObserver<O2, S2, D2>) -> bool {
self.untracked_ref().eq(other.untracked_ref())
}
}
impl<O, S: ?Sized, D> Eq for RangeInclusiveObserver<O, S, D>
where
O: QuasiObserver,
D: Unsigned,
S: AsDeref<D>,
S::Target: Eq,
{
}
spec_impl_observe_from_ref!(
RangeInclusiveObserveImpl,
RangeInclusive<Self>,
RangeInclusive<T>,
RangeInclusiveObserver
);
spec_impl_ref_observe!(
RangeInclusiveRefObserveImpl,
RangeInclusive<Self>,
RangeInclusive<T>,
RangeInclusiveObserver
);
impl<T: Snapshot> Snapshot for RangeInclusive<T> {
type Snapshot = (T::Snapshot, T::Snapshot);
fn to_snapshot(&self) -> Self::Snapshot {
(self.start().to_snapshot(), self.end().to_snapshot())
}
fn eq_snapshot(&self, snapshot: &Self::Snapshot) -> bool {
self.start().eq_snapshot(&snapshot.0) && self.end().eq_snapshot(&snapshot.1)
}
}
#[cfg(test)]
mod tests {
use morphix_test_utils::*;
use serde_json::json;
use super::*;
use crate::adapter::Json;
use crate::general::GeneralObserver;
use crate::observe::{ObserveExt, SerializeObserverExt};
#[test]
fn range_no_change_returns_none() {
let mut range = 0..10i32;
let mut ob = range.__observe();
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, None);
}
#[test]
fn range_deref_triggers_replace() {
let mut range = 0..10i32;
let mut ob = range.__observe();
**ob = 5..15;
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(_, json!({"start": 5, "end": 15}))));
}
#[test]
fn range_granular_start_change() {
let mut range = String::from("a")..String::from("z");
let mut ob = range.__observe();
ob.start.push_str("bc");
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(append!(start, json!("bc"))));
}
#[test]
fn range_granular_end_change() {
let mut range = String::from("a")..String::from("z");
let mut ob = range.__observe();
ob.end.push_str("yx");
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(append!(end, json!("yx"))));
}
#[test]
fn range_both_fields_replace_collapse() {
let mut range = String::from("a")..String::from("z");
let mut ob = range.__observe();
**ob = String::from("b")..String::from("y");
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(_, json!({"start": "b", "end": "y"}))));
}
#[test]
fn range_specialization() {
let mut range = 0..10i32;
let ob: GeneralObserver<_, _, _> = range.__observe();
assert_eq!(format!("{ob:?}"), "SnapshotObserver(0..10)");
let mut range = String::from("a")..String::from("z");
let ob: RangeObserver<_, _, _> = range.__observe();
assert_eq!(format!("{ob:?}"), r#"RangeObserver("a".."z")"#);
}
}