
Разбор библиотеки для автоматизации конверсии
Cell<Struct>
-> Cell<Field>
.abubalay.com/blog/2020/01/05/cell-field-projection
Size: a a a
Cell<Struct>
-> Cell<Field>
.Apply
:trait Apply {
type Patch;
fn apply(&mut self, patch: Self::Patch) -> Self::Patch;
}
let changed = {
let mut changed = original.clone();
let undo = changed.apply(change);
changed.apply(undo);
changed
};
assert_eq!(original, changed);
let undo1 = state.apply(change1);
let undo2 = state.apply(change2);
let undo3 = state.apply(change3);
state.apply(undo3);
state.apply(undo2);
state.apply(undo1); // сейчас state находится в том же
// состоянии, что и до начала преобразований
Разумеется, хранить историю можно и в более организованном виде. Скажем, вот как организовывается обобщённая структура для поддержки отмены изменений:struct Undo<Data: Apply> {
data: Data,
changes: Vec<Data::Patch>,
}
impl<Data: Apply> Undo {
fn get(&self) -> &Data {
&self.data
}
fn apply(&mut self, patch: Data::Patch) {
self.changes.push(self.data.apply(patch));
}
fn undo(&mut self) {
if let Some(undo) = self.changes.pop() {
self.data.apply(undo);
}
}
}
struct Patching<Data>(Data);
struct Unapply<'a, Data: Apply> {
data: &'a mut Data,
undo: Option<Data::Patch>,
}
impl<Data: Apply> Patching<Data> {
fn applying(&mut self, patch: Data::Patch) -> Unapply<Data> {
let undo = self.0.apply(patch);
Unapply {
data: &mut self.0,
undo: Some(undo),
}
}
}
impl<Data: Apply> Unapply<'_, Data> {
fn applying<'a>(&'a mut self, patch: Data::Patch) -> Unapply<'a, Data> {
let undo = self.data.apply(patch);
Unapply {
data: &mut self.data,
undo: Some(undo),
}
}
}
impl<Data: Apply> Drop for Unapply<'_, Data> {
fn drop(&mut self) {
let undo = self.undo.take().unwrap();
self.data.apply(undo);
}
}