morphix/observe/
mod.rs

1use std::ops::DerefMut;
2
3use serde::{Serialize, Serializer};
4
5use crate::Change;
6use crate::adapter::Adapter;
7
8mod shallow;
9mod string;
10mod vec;
11
12pub use shallow::ShallowObserver;
13
14/// A trait for types that can be observed for changes.
15///
16/// Types implementing `Observe` can be wrapped in [Observers] that track mutations.
17/// The trait is typically derived using the `#[derive(Observe)]` macro.
18///
19/// ## Example
20///
21/// ```
22/// use morphix::Observe;
23/// use serde::Serialize;
24///
25/// #[derive(Serialize, Observe)]
26/// struct MyStruct {
27///     field: String,
28/// }
29///
30/// let mut data = MyStruct { field: "value".to_string() };
31/// let mut data_observer = data.observe();
32/// // Mutations through observer are tracked
33/// data_observer.field.push_str(" modified");
34/// ```
35///
36/// [`Observers`]: crate::Observer
37pub trait Observe: Serialize {
38    /// Associated observer type.
39    type Observer<'i>: Observer<'i, Self>
40    where
41        Self: 'i;
42
43    /// Creates an observer for this value.
44    ///
45    /// ## Returns
46    ///
47    /// An observer that wraps this value and tracks mutations.
48    #[inline]
49    fn observe<'i>(&'i mut self) -> Self::Observer<'i> {
50        Self::Observer::observe(self)
51    }
52
53    /// Serializes only the appended portion of the value.
54    ///
55    /// This method is used for optimizing append operations by only
56    /// serializing the new data rather than the entire value.
57    ///
58    /// ## Arguments
59    ///
60    /// - `serializer` - serializer to use
61    /// - `start_index` - index from which to start serialization
62    ///
63    /// ## Errors
64    ///
65    /// - Returns serialization errors from the underlying serializer.
66    ///
67    /// ## Panics
68    ///
69    /// - Panics if called on types that don't support append operations.
70    #[inline]
71    #[expect(unused_variables)]
72    fn serialize_append<S: Serializer>(&self, serializer: S, start_index: usize) -> Result<S::Ok, S::Error> {
73        unimplemented!()
74    }
75}
76
77/// A trait for observer types that wrap and track mutations to values.
78///
79/// Observers provide transparent access to the underlying value while
80/// recording any mutations that occur.
81pub trait Observer<'i, T: ?Sized>: DerefMut<Target = T> {
82    /// Creates a new observer for the given value.
83    ///
84    /// ## Arguments
85    ///
86    /// - `value` - value to observe
87    fn observe(value: &'i mut T) -> Self;
88
89    /// Collects all recorded changes using the specified adapter.
90    ///
91    /// ## Type Parameters
92    ///
93    /// - `A` - adapter to use for serialization
94    ///
95    /// ## Returns
96    ///
97    /// - `None` if no changes were recorded,
98    /// - otherwise a `Change` containing all mutations that occurred.
99    ///
100    /// ## Errors
101    ///
102    /// - Returns an error if serialization fails.
103    fn collect<A: Adapter>(this: Self) -> Result<Option<Change<A>>, A::Error>
104    where
105        T: Serialize;
106}
107
108#[doc(hidden)]
109#[derive(Clone, Copy)]
110pub enum Mutation {
111    Replace,
112    Append(usize),
113}
114
115#[doc(hidden)]
116pub trait MutationObserver<'i, T>: Observer<'i, T> {
117    fn mutation(this: &mut Self) -> &mut Option<Mutation>;
118
119    fn mark_replace(this: &mut Self) {
120        *Self::mutation(this) = Some(Mutation::Replace);
121    }
122
123    fn mark_append(this: &mut Self, start_index: usize) {
124        let mutation = Self::mutation(this);
125        if mutation.is_some() {
126            return;
127        }
128        *mutation = Some(Mutation::Append(start_index));
129    }
130}