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
use std::result::Result;

// ===================================================================
// Transformable
// ===================================================================

/// A trait describing something which can be _transformed_ by
/// applying a _delta_.  For example, an array `[0,1,2]` can be
/// transformed into another `[3,1,2]` by applying a delta which
/// assigns element `0` to `3`.  This trait describes the functional
/// case, where the receiver is not modified.
pub trait Transformer {
    type Delta;
    /// Apply a given delta to this transformable item, yielding a
    /// potentially updated version of this item.
    fn transform_into(&self,d: &Self::Delta) -> Self;    
}

/// A trait describing something which can be _transformed_ by
/// applying a _delta_.  For example, an array `[0,1,2]` can be
/// transformed into another `[3,1,2]` by applying a delta which
/// assigns element `0` to `3`.  This trait describes the functional
/// case, where the receiver is not modified.  **Furthermore, this
/// trait allows for the possibility that the transformation may not
/// succeed**.
pub trait PartialTransformer: Sized {
    type Delta;
    type Error;
    /// Apply a given delta to this transformable item, yielded a
    /// potentially updated version of this item or an error..
    fn transform_into(&self,d: &Self::Delta) -> Result<Self,Self::Error>;    
}

// ===================================================================
// Transformable
// ===================================================================

/// A trait describing something which can be _transformed_ in place
/// by applying a _delta_.  For example, an array `[0,1,2]` can be
/// transformed into another `[3,1,2]` by applying a delta which
/// assigns element `0` to `3`.  This trait describes the imperative
/// case where the receiver is modified in place.
pub trait Transformable {
    type Delta;
    /// Apply a given delta to this transformable item, yielded a
    /// potentially updated version of this item.
    fn transform(&mut self,d: &Self::Delta);
}

/// Provides a default trait implementation for every type which is
/// transformable.  This first clones the item, and then transforms it
/// in place.
impl<T: Transformable + Clone> Transformer for T {
    type Delta = T::Delta;

    fn transform_into(&self,d: &Self::Delta) -> Self {
        // Clone
        let mut r = self.clone();
        // Transform
        r.transform(d);
        // Done
        r
    }
}

/// A trait describing something which can be _transformed_ in place
/// by applying a _delta_.  For example, an array `[0,1,2]` can be
/// transformed into another `[3,1,2]` by applying a delta which
/// assigns element `0` to `3`.  This trait describes the imperatice
/// case where the receiver is modified in place.  **Furthermore, this
/// trait allows for the possibility that an error is returned**.
pub trait PartiallyTransformable : Sized {
    type Delta;
    type Error;
    /// Apply a given delta to this transformable item, yielding a
    /// potentially updated version of this item.
    fn transform(&mut self,d: &Self::Delta) -> Result<(),Self::Error>;
}

/// Provides a default trait implementation for every type which is
/// transformable.  This first clones the item, and then transforms it
/// in place.
impl<T: PartiallyTransformable + Clone> PartialTransformer for T {
    type Delta = T::Delta;
    type Error = T::Error;

    fn transform_into(&self,d: &Self::Delta) -> Result<Self,Self::Error> {
        // Clone
        let mut r = self.clone();
        // Transform
        r.transform(d)?;
        // Done
        Ok(r)
    }
}

// ===================================================================
// Diffable
// ===================================================================

/// A trait capturing the notion of a type where a _delta_ can be
/// computed between two of its items.  For example, given
/// `a1=[0,1,2]` and `a2=[1,1,2]`, we could compute a delta `d` such
/// that `a1.transform_into(d)` returns `a2`.  Observe that the delta
/// has an _orientation_ which (implicitly) means it goes from _this_
/// item to the _other_,
pub trait Diffable {
    type Delta;
    /// Compute a diff between this item and another, yielding a delta
    /// `d` such that `this.transform(d) == other` holds.
    fn diff(&self, other: &Self) -> Self::Delta;
}

/// A trait capturing the essence of an incremental computation from
/// `self` to some item `T`.  This is similar to the `Into` trait, but
/// with the ability to work with _deltas_.  To understand this,
/// consider the following:
///
/// ```Rust
/// let t1 : T = self.into()
/// //
/// self.transform(&d1);
/// //
/// let t2 : T = self.into()
/// ```
///
/// This assumes some delta `d` which can be applied to `self`.  The
/// issue with this is that the final transformation to `t2` is
/// _computed from scratch_.  This could be expensive, though it might
/// be necessary.  However, for some computations, however, we can
/// reduce the amount of work done by _incrementally_ applying `into`
/// through the delta `d`.  That would look like this:
///
/// ```Rust
/// let t1 : T = self.into()
/// //
/// let d2 = self.update(&t1,&d1);
/// //
/// let t2 = t1.transform_into(&d2);
/// ```
///
/// This update version produces the same `t2` as the original, but
/// allows for the computation to exploit existing information about
/// `t1`.  In some cases, this can make a big difference.  For
/// example, consider parsing algorithm which turns a _source file_
/// into an _Abstract Syntax Tree_.  In this case, a delta is some
/// change to the source file.  Then, given the AST for a source file
/// and a change to that source file, the resulting AST might be
/// almost entirely (or actually) the same as the original file.  For
/// example, if the change removed a line of whitespace then nothing
/// changes.
pub trait Incremental<T:Transformer> : Transformable + Into<T> {
   fn update(&self, to: &T, delta: &Self::Delta) -> T::Delta;
}