Enum someday::Patch

source ·
pub enum Patch<T: Clone> {
    Box(Box<dyn FnMut(&mut T, &T) + Send + 'static>),
    Arc(Arc<dyn Fn(&mut T, &T) + Send + Sync + 'static>),
    Ptr(fn(_: &mut T, _: &T)),
}
Expand description

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
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:

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.

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.
}));

Variants§

§

Box(Box<dyn FnMut(&mut T, &T) + Send + 'static>)

Dynamically dispatched, potentially capturing, boxed function.

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();
§

Arc(Arc<dyn Fn(&mut T, &T) + Send + Sync + 'static>)

Dynamically dispatched, potentially capturing, cheaply Clone-able function.

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();
§

Ptr(fn(_: &mut T, _: &T))

Non-capturing, static function pointer.

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();

Implementations§

source§

impl<T: Clone> Patch<T>

source

pub fn boxed<P>(patch: P) -> Self
where P: FnMut(&mut T, &T) + Send + 'static,

Short-hand for Self::Box(Box::new(patch)).

let string = String::new();

let boxed_patch = Patch::<String>::boxed(move |_, _| {
    let captured_variable = &string;
});
assert!(boxed_patch.is_box());
source

pub fn arc<P>(patch: P) -> Self
where P: Fn(&mut T, &T) + Send + Sync + 'static,

Short-hand for Self::Arc(Arc::new(patch)).

let string = String::new();

let arc_patch = Patch::<String>::arc(move |_, _| {
    let captured_variable = &string;
});
assert!(arc_patch.is_arc());
source

pub const fn is_box(&self) -> bool

If self is the Patch::Box variant.

source

pub const fn is_arc(&self) -> bool

If self is the Patch::Arc variant.

source

pub const fn is_ptr(&self) -> bool

If self is the Patch::Ptr variant.

let ptr_patch = Patch::<String>::Ptr(|w, _| {
    // No captured variables, "pure" function.
    w.push_str("hello");
});
assert!(ptr_patch.is_ptr());

Trait Implementations§

source§

impl<T: Clone> From<&Arc<dyn Fn(&mut T, &T) + Send + Sync>> for Patch<T>

source§

fn from(patch: &Arc<dyn Fn(&mut T, &T) + Send + Sync + 'static>) -> Self

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());
source§

impl<T: Clone> From<Arc<dyn Fn(&mut T, &T) + Send + Sync>> for Patch<T>

source§

fn from(patch: Arc<dyn Fn(&mut T, &T) + Send + Sync + 'static>) -> Self

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());
source§

impl<T: Clone> From<Box<dyn FnMut(&mut T, &T) + Send>> for Patch<T>

source§

fn from(patch: Box<dyn FnMut(&mut T, &T) + Send + 'static>) -> Self

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());
source§

impl<T: Clone> From<fn(_: &mut T, _: &T)> for Patch<T>

source§

fn from(patch: fn(_: &mut T, _: &T)) -> Self

let ptr: fn(&mut String, &String) = |w, _| {
    w.push_str("hello");
};

let patch = Patch::from(ptr);
assert!(patch.is_ptr());

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for Patch<T>

§

impl<T> Send for Patch<T>

§

impl<T> !Sync for Patch<T>

§

impl<T> Unpin for Patch<T>

§

impl<T> !UnwindSafe for Patch<T>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.