1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
//! `Writer<T>`
//---------------------------------------------------------------------------------------------------- Use
use std::sync::Arc;
#[allow(unused_imports)] // docs
use crate::{Reader, Writer};
//---------------------------------------------------------------------------------------------------- Patch
/// Functions to be applied to your data `T`.
///
/// [`Patch`] is just a function that will be applied to your data `T`.
///
/// The [`Writer`] expects `T` modifications in the form of `Patch`'s.
///
/// The enumrated options are various forms of functions.
///
/// The 2 inputs you are given are:
/// - The `Writer`'s local mutable data, `T` (the thing you're modifying)
/// - The [`Reader`]'s latest head commit
///
/// ```rust
/// # use someday::*;
/// # use std::sync::*;
/// let (_, mut w) = someday::new::<String>("".into());
///
/// // Use a pre-defined function pointer.
/// fn fn_ptr(w: &mut String, r: &String) {
/// w.push_str("hello");
/// }
/// w.add(Patch::Ptr(fn_ptr));
///
/// // This non-capturing closure can also
/// // be coerced into a function pointer.
/// w.add(Patch::Ptr(|w, _| {
/// w.push_str("hello");
/// }));
///
/// // This capturing closure gets turned into
/// // a cheaply clone-able dynamic function.
/// let string = String::from("hello");
/// w.add(Patch::arc(move |w: &mut String ,_| {
/// let captured = &string;
/// w.push_str(&captured);
/// }));
/// ```
///
/// # ⚠️ Non-deterministic `Patch`
/// The `Patch`'s you use with [`Writer::add`] **must be deterministic**.
///
/// The `Writer` may apply your `Patch` twice, so any state that gets
/// modified or functions used in the `Patch` must result in the
/// same values as the first time the `Patch` was called.
///
/// Here is a **non-deterministic** example:
/// ```rust
/// # use someday::*;
/// # use std::sync::*;
/// static STATE: Mutex<usize> = Mutex::new(1);
///
/// let (_, mut w) = someday::new::<usize>(0);
///
/// w.add(Patch::boxed(move |w, _| {
/// let mut state = STATE.lock().unwrap();
/// *state *= 10; // 1*10 the first time, 10*10 the second time...
/// *w = *state;
/// }));
/// w.commit();
/// w.push();
///
/// // ⚠️⚠️⚠️ !!!
/// // The `Writer` reclaimed the old `Reader` data
/// // and applied our `Patch` again, except, the `Patch`
/// // was non-deterministic, so now the `Writer`
/// // and `Reader` have non-matching data...
/// assert_eq!(*w.data(), 100);
/// assert_eq!(w.reader().head().data, 10);
/// ```
///
/// # The 2nd apply
/// Note that if/when the `Writer` applies your `Patch` for the 2nd time
/// inside [`Writer::push`], the `Reader` side of the data has _just_ been updated.
/// This means your `Patch`'s 2nd input `&T` will be referencing the _just_ pushed data.
///
/// ```rust
/// # use someday::*;
/// let (_, mut writer) = someday::new::<usize>(0);
///
/// writer.add(Patch::Ptr(|w, r| {
/// // `w` on the first apply of this Patch
/// // is our local Writer data. `r` is the
/// // current `Reader` data (whether out-of-date or not).
/// //
/// // The 2nd time this applies, `w` will be
/// // the old `Reader` data we are attempting
/// // to reclaim and "reproduce" with this Patch,
/// // while `r` will be the data the `Writer` just pushed.
/// }));
/// ```
pub enum Patch<T: Clone> {
/// Dynamically dispatched, potentially capturing, boxed function.
///
/// ```rust
/// let string = String::new();
///
/// let mut boxed: Box<dyn FnMut()> = Box::new(move || {
/// // The outside string was captured.
/// println!("{string}");
/// });
///
/// // This cannot be cloned.
/// boxed();
/// ```
Box(Box<dyn FnMut(&mut T, &T) + Send + 'static>),
/// Dynamically dispatched, potentially capturing, cheaply [`Clone`]-able function.
///
/// ```rust
/// # use std::sync::*;
/// let string = String::new();
///
/// let arc: Arc<dyn Fn()> = Arc::new(move || {
/// // The outside string was captured.
/// println!("{string}");
/// });
///
/// // We can clone this as much as we want though.
/// let arc2 = Arc::clone(&arc);
/// let arc3 = Arc::clone(&arc);
/// arc();
/// arc2();
/// arc3();
/// ```
Arc(Arc<dyn Fn(&mut T, &T) + Send + Sync + 'static>),
/// Non-capturing, static function pointer.
///
/// ```rust
/// let ptr: fn() = || {
/// // Nothing was captured.
/// //
/// // This closure can be coerced into
/// // a function pointer, same as `fn()`.
/// let string = String::new();
/// println!("{string}");
/// };
///
/// // Can copy it infinitely, it's just a pointer.
/// let ptr2 = ptr;
/// let ptr3 = ptr;
/// ptr();
/// ptr2();
/// ptr3();
/// ```
Ptr(fn(&mut T, &T)),
}
impl<T: Clone> Patch<T> {
#[inline]
/// Short-hand for `Self::Box(Box::new(patch))`.
///
/// ```rust
/// # use someday::*;
/// let string = String::new();
///
/// let boxed_patch = Patch::<String>::boxed(move |_, _| {
/// let captured_variable = &string;
/// });
/// assert!(boxed_patch.is_box());
/// ```
pub fn boxed<P>(patch: P) -> Self
where
P: FnMut(&mut T, &T) + Send + 'static,
{
Self::Box(Box::new(patch))
}
#[inline]
/// Short-hand for `Self::Arc(Arc::new(patch))`.
///
/// ```rust
/// # use someday::*;
/// let string = String::new();
///
/// let arc_patch = Patch::<String>::arc(move |_, _| {
/// let captured_variable = &string;
/// });
/// assert!(arc_patch.is_arc());
/// ```
pub fn arc<P>(patch: P) -> Self
where
P: Fn(&mut T, &T) + Send + Sync + 'static,
{
Self::Arc(Arc::new(patch))
}
#[inline]
/// Apply the [`Patch`] onto the [`Writer`] data.
pub(crate) fn apply(&mut self, writer: &mut T, reader: &T) {
match self {
Self::Box(f) => f(writer, reader),
Self::Arc(f) => f(writer, reader),
Self::Ptr(f) => f(writer, reader),
}
}
#[must_use]
/// If `self` is the `Patch::Box` variant.
pub const fn is_box(&self) -> bool {
matches!(self, Self::Box(_))
}
#[must_use]
/// If `self` is the `Patch::Arc` variant.
pub const fn is_arc(&self) -> bool {
matches!(self, Self::Arc(_))
}
#[must_use]
/// If `self` is the `Patch::Ptr` variant.
///
/// ```rust
/// # use someday::*;
/// let ptr_patch = Patch::<String>::Ptr(|w, _| {
/// // No captured variables, "pure" function.
/// w.push_str("hello");
/// });
/// assert!(ptr_patch.is_ptr());
/// ```
pub const fn is_ptr(&self) -> bool {
matches!(self, Self::Ptr(_))
}
}
impl<T: Clone> From<Box<dyn FnMut(&mut T, &T) + Send + 'static>> for Patch<T> {
/// ```rust
/// # use someday::*;
/// let string = String::new();
///
/// let boxed: Box<dyn FnMut(&mut String, &String) + Send + 'static> = Box::new(move |_, _| {
/// let captured_variable = &string;
/// });
///
/// let patch = Patch::from(boxed);
/// assert!(patch.is_box());
/// ```
fn from(patch: Box<dyn FnMut(&mut T, &T) + Send + 'static>) -> Self {
Self::Box(patch)
}
}
impl<T: Clone> From<Arc<dyn Fn(&mut T, &T) + Send + Sync + 'static>> for Patch<T> {
/// ```rust
/// # use someday::*;
/// # use std::sync::*;
/// let string = String::new();
///
/// let arc: Arc<dyn Fn(&mut String, &String) + Send + Sync + 'static> = Arc::new(move |_, _| {
/// let captured_variable = &string;
/// });
///
/// let patch = Patch::from(arc);
/// assert!(patch.is_arc());
/// ```
fn from(patch: Arc<dyn Fn(&mut T, &T) + Send + Sync + 'static>) -> Self {
Self::Arc(patch)
}
}
impl<T: Clone> From<&Arc<dyn Fn(&mut T, &T) + Send + Sync + 'static>> for Patch<T> {
/// ```rust
/// # use someday::*;
/// # use std::sync::*;
/// let string = String::new();
///
/// let arc: Arc<dyn Fn(&mut String, &String) + Send + Sync + 'static> = Arc::new(move |_, _| {
/// let captured_variable = &string;
/// });
///
/// let patch = Patch::from(&arc);
/// assert!(patch.is_arc());
/// ```
fn from(patch: &Arc<dyn Fn(&mut T, &T) + Send + Sync + 'static>) -> Self {
Self::Arc(Arc::clone(patch))
}
}
impl<T: Clone> From<fn(&mut T, &T)> for Patch<T> {
/// ```rust
/// # use someday::*;
/// let ptr: fn(&mut String, &String) = |w, _| {
/// w.push_str("hello");
/// };
///
/// let patch = Patch::from(ptr);
/// assert!(patch.is_ptr());
/// ```
fn from(patch: fn(&mut T, &T)) -> Self {
Self::Ptr(patch)
}
}