Experiments with incremental functions and state machines in Rust.
///
/// Trait for a type that can have mutable diffs applied to them.
///
/// Useful for storing any mutable changes made to a value so they can be replayed
///  or reverted in the future.
///
pub trait Diffable {
    type Diff;

    fn diff(self: &Self, other: &Self) -> Self::Diff;

    fn patch(self: &mut Self, diff: Self::Diff);
}

///
/// A trait for diffs which are inherently reversible. In other words,
///  diffs that can be applied "in reverse" to undo the original diff operation.
///
trait Reversible: Diffable {
    type ReversibleDiff;

    fn reversible_diff(self: &Self, other: &Self) -> Self::ReversibleDiff;

    fn as_diff(diff: Self::ReversibleDiff) -> Self::Diff;

    fn revert(self: &mut Self, diff: Self::ReversibleDiff);
}

impl Diffable for i32 {
    type Diff = i32;

    fn diff(self: &i32, other: &i32) -> i32 {
        *other
    }

    fn patch(self: &mut i32, other: i32) {
        *self = other;
    }
}

impl<A, B> Diffable for (A, B)
where
    A: Diffable,
    B: Diffable,
{
    type Diff = (A::Diff, B::Diff);

    fn diff(self: &(A, B), other: &(A, B)) -> (A::Diff, B::Diff) {
        (self.0.diff(&other.0), self.1.diff(&other.1))
    }

    fn patch(self: &mut (A, B), patch: (A::Diff, B::Diff)) {
        self.0.patch(patch.0);
        self.1.patch(patch.1);
    }
}

/// The possible atomic operations that can be made when modifying a list.
pub enum EditScript<A, D> {
    Add(usize, A),
    Remove(usize, A),
    Diff(usize, D),
}

impl<A: Diffable> Diffable for Vec<A> {
    type Diff = Vec<EditScript<A, A::Diff>>;

    fn diff(self: &Vec<A>, other: &Vec<A>) -> Vec<EditScript<A, A::Diff>> {
        todo!()
    }

    fn patch(self: &mut Self, diff: Self::Diff) {
        for operation in diff {
            todo!()
        }
    }
}