use std::fmt::Debug;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use serde::Serialize;
use crate::general::Snapshot;
use crate::helper::{AsDeref, AsDerefMut, Invalidate, Pointer, QuasiObserver, Succ, Unsigned, Zero};
use crate::impls::slice::{SliceObserver, SliceObserverState, SliceSerializeObserverState};
use crate::impls::slices::helper::SliceIndexImpl;
use crate::observe::{DefaultSpec, Observer, RoObserve, SerializeObserver};
use crate::{Mutations, Observe};
impl<O, const N: usize> Invalidate<[O::Head; N]> for [O; N]
where
O: QuasiObserver<InnerDepth = Zero, Head: Sized>,
{
fn invalidate(&mut self, _: &[O::Head; N]) {
for ob in self.as_mut_slice() {
O::invalidate(ob);
}
}
}
impl<O, const N: usize> SliceObserverState for [O; N]
where
O: Observer<InnerDepth = Zero, Head: Sized>,
{
type Target = [O::Head; N];
type Item = O;
unsafe fn observe(target: *mut Self::Target) -> Self {
std::array::from_fn(|i| unsafe { O::observe((target as *mut O::Head).add(i)) })
}
fn get<I: SliceIndexImpl>(&self, index: I, _slice: &mut Self::Target) -> Option<&I::Output<O>> {
index.get(self.as_slice())
}
fn get_mut<I: SliceIndexImpl>(&mut self, index: I, _slice: &mut Self::Target) -> Option<&mut I::Output<O>> {
index.get_mut(self.as_mut_slice())
}
}
impl<O, const N: usize, S, D> SliceSerializeObserverState<S, D> for [O; N]
where
D: Unsigned,
S: AsDeref<D, Target = [O::Head; N]> + ?Sized,
O: SerializeObserver<InnerDepth = Zero>,
O::Head: Serialize + Sized + 'static,
{
fn flush(&mut self, ptr: &mut Pointer<S>) -> Mutations {
let slice = (**ptr).as_deref();
let mut mutations = Mutations::new();
let mut is_replace = true;
for (index, ob) in self.iter_mut().enumerate() {
let inner_mutations = SerializeObserver::flush(ob);
is_replace &= inner_mutations.is_replace();
mutations.insert(index, inner_mutations);
}
if is_replace {
return Mutations::replace(slice.as_ref());
};
mutations
}
}
pub struct ArrayObserver<const N: usize, O, S: ?Sized, D = Zero> {
inner: SliceObserver<[O; N], S, D>,
}
impl<const N: usize, O, S: ?Sized, D, T> ArrayObserver<N, O, S, D>
where
D: Unsigned,
S: AsDerefMut<D, Target = [T; N]>,
O: Observer<InnerDepth = Zero, Head = T>,
{
pub fn as_mut_slice(&mut self) -> &mut [O] {
self.inner.force_mut()
}
pub fn each_mut(&mut self) -> [&mut O; N] {
self.inner.force_mut();
self.inner.state.each_mut()
}
}
impl<const N: usize, O, S: ?Sized, D> Deref for ArrayObserver<N, O, S, D> {
type Target = SliceObserver<[O; N], S, D>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<const N: usize, O, S: ?Sized, D> DerefMut for ArrayObserver<N, O, S, D> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<const N: usize, O, S: ?Sized, D> QuasiObserver for ArrayObserver<N, O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = [O::Head; N]>,
O: QuasiObserver<InnerDepth = Zero, Head: Sized>,
{
type Head = S;
type OuterDepth = Succ<Succ<Zero>>;
type InnerDepth = D;
fn invalidate(this: &mut Self) {
Invalidate::invalidate(&mut this.inner.state, (*this.inner.ptr).as_deref());
}
}
impl<const N: usize, O, S: ?Sized, D, T> Observer for ArrayObserver<N, O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = [T; N]>,
O: Observer<InnerDepth = Zero, Head = T>,
{
unsafe fn observe(head: *mut Self::Head) -> Self {
Self {
inner: unsafe { Observer::observe(head) },
}
}
unsafe fn relocate(this: &mut Self, head: *mut Self::Head) {
unsafe { Observer::relocate(&mut this.inner, head) }
}
}
impl<const N: usize, O, S: ?Sized, D, T> SerializeObserver for ArrayObserver<N, O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = [T; N]>,
O: SerializeObserver<InnerDepth = Zero, Head = T>,
T: Serialize + 'static,
{
fn flush(this: &mut Self) -> Mutations {
SliceObserver::flush(&mut this.inner)
}
}
impl<const N: usize, O, S: ?Sized, D> Debug for ArrayObserver<N, O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = [O::Head; N]>,
O: Observer<InnerDepth = Zero, Head: Sized + Debug>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("ArrayObserver").field(&self.untracked_ref()).finish()
}
}
impl<const N: usize, O1, O2, S1: ?Sized, S2: ?Sized, D1, D2> PartialEq<ArrayObserver<N, O2, S2, D2>>
for ArrayObserver<N, O1, S1, D1>
where
D1: Unsigned,
D2: Unsigned,
O1: Observer<InnerDepth = Zero, Head: Sized>,
O2: Observer<InnerDepth = Zero, Head: Sized>,
S1: AsDeref<D1, Target = [O1::Head; N]>,
S2: AsDeref<D2, Target = [O2::Head; N]>,
[O1::Head; N]: PartialEq<[O2::Head; N]>,
{
fn eq(&self, other: &ArrayObserver<N, O2, S2, D2>) -> bool {
self.untracked_ref().eq(other.untracked_ref())
}
}
impl<const N: usize, O, S: ?Sized, D> Eq for ArrayObserver<N, O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = [O::Head; N]>,
O: Observer<InnerDepth = Zero, Head: Sized + Eq>,
{
}
impl<const N: usize, O1, O2, S1: ?Sized, S2: ?Sized, D1, D2> PartialOrd<ArrayObserver<N, O2, S2, D2>>
for ArrayObserver<N, O1, S1, D1>
where
D1: Unsigned,
D2: Unsigned,
O1: Observer<InnerDepth = Zero, Head: Sized>,
O2: Observer<InnerDepth = Zero, Head: Sized>,
S1: AsDeref<D1, Target = [O1::Head; N]>,
S2: AsDeref<D2, Target = [O2::Head; N]>,
[O1::Head; N]: PartialOrd<[O2::Head; N]>,
{
fn partial_cmp(&self, other: &ArrayObserver<N, O2, S2, D2>) -> Option<std::cmp::Ordering> {
self.untracked_ref().partial_cmp(other.untracked_ref())
}
}
impl<const N: usize, O, S: ?Sized, D> Ord for ArrayObserver<N, O, S, D>
where
D: Unsigned,
S: AsDeref<D, Target = [O::Head; N]>,
O: Observer<InnerDepth = Zero, Head: Sized + Ord>,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.untracked_ref().cmp(other.untracked_ref())
}
}
impl<const N: usize, O, S: ?Sized, D, T, I> Index<I> for ArrayObserver<N, O, S, D>
where
D: Unsigned,
S: AsDerefMut<D, Target = [T; N]>,
O: Observer<InnerDepth = Zero, Head = T>,
I: SliceIndexImpl,
{
type Output = I::Output<O>;
fn index(&self, index: I) -> &Self::Output {
&self.inner[index]
}
}
impl<const N: usize, O, S: ?Sized, D, T, I> IndexMut<I> for ArrayObserver<N, O, S, D>
where
D: Unsigned,
S: AsDerefMut<D, Target = [T; N]>,
O: Observer<InnerDepth = Zero, Head = T>,
I: SliceIndexImpl,
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
&mut self.inner[index]
}
}
impl<T: Observe, const N: usize> Observe for [T; N] {
type Observer<'ob, S, D>
= ArrayObserver<N, T::Observer<'ob, T, Zero>, S, D>
where
Self: 'ob,
D: Unsigned,
S: AsDerefMut<D, Target = Self> + ?Sized + 'ob;
type Spec = DefaultSpec;
}
impl<T: RoObserve, const N: usize> RoObserve for [T; N] {
type Observer<'ob, S, D>
= ArrayObserver<N, 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, const N: usize> Snapshot for [T; N] {
type Snapshot = [T::Snapshot; N];
fn to_snapshot(&self) -> Self::Snapshot {
std::array::from_fn(|i| self[i].to_snapshot())
}
fn eq_snapshot(&self, snapshot: &Self::Snapshot) -> bool {
(0..N).all(|i| self[i].eq_snapshot(&snapshot[i]))
}
}
#[cfg(test)]
mod tests {
use muon_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 arr = [1u32, 2, 3];
let mut ob = arr.__observe();
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, None);
}
#[test]
fn index_by_usize() {
let mut arr = [10u32, 20, 30];
let mut ob = arr.__observe();
assert_eq!(*ob[1].untracked_ref(), 20);
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, None);
*ob[1].tracked_mut() = 99;
assert_eq!(*ob[1].untracked_ref(), 99);
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(1, json!(99))));
}
#[test]
fn multiple_index_mutations() {
let mut arr = [1u32, 2, 3];
let mut ob = arr.__observe();
*ob[0].tracked_mut() = 10;
*ob[2].tracked_mut() = 30;
let Json(mutation) = ob.flush().unwrap();
assert_eq!(
mutation,
Some(batch!(_, replace!(0, json!(10)), replace!(2, json!(30)))),
);
}
#[test]
fn deref_mut_triggers_replace() {
let mut arr = [1u32, 2, 3];
let mut ob = arr.__observe();
*ob.tracked_mut() = [4, 5, 6];
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(replace!(_, json!([4, 5, 6]))));
}
#[test]
fn deref_mut_same_value_returns_none() {
let mut arr = [1u32, 2, 3];
let mut ob = arr.__observe();
*ob.tracked_mut() = [1, 2, 3];
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, None);
}
#[test]
fn swap() {
let mut arr = [10u32, 20, 30];
let mut ob = arr.__observe();
ob.swap(0, 2);
assert_eq!(*ob.untracked_ref(), [30, 20, 10]);
let Json(mutation) = ob.flush().unwrap();
assert_eq!(
mutation,
Some(batch!(_, replace!(0, json!(30)), replace!(2, json!(10)))),
);
}
#[test]
fn nested_string_append() {
let mut arr = ["hello".to_string(), "world".to_string()];
let mut ob = arr.__observe();
ob[0].push_str("!");
let Json(mutation) = ob.flush().unwrap();
assert_eq!(mutation, Some(append!(0, json!("!"))));
}
#[test]
fn flush_resets_state() {
let mut arr = ["a".to_string(), "b".to_string()];
let mut ob = arr.__observe();
ob[0].push_str("!");
let Json(mutation) = ob.flush().unwrap();
assert!(mutation.is_some());
let Json(mutation) = ob.flush().unwrap();
assert!(mutation.is_none(), "expected None, got {mutation:?}");
}
#[test]
fn observe_provenance_write() {
let mut arr = [String::from("hello"), String::from("world")];
let mut ob = arr.__observe();
ob[0].push_str("!");
ob[1].push_str("?");
let Json(mutation) = ob.flush().unwrap();
assert_eq!(
mutation,
Some(batch!(_, append!(0, json!("!")), append!(1, json!("?"))))
);
}
}