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
use super::FromTo;
use crate::zones::{stock, waste};
use crate::{action, undo};
#[derive(Debug, Clone, Copy)]
pub struct DrawCount(pub usize);
#[derive(Debug)]
pub struct Action;
#[derive(Debug)]
pub struct Value(Undo);
#[derive(Debug)]
enum Undo {
Draw(stock::draw::Value, waste::place::Value),
Replace(waste::empty::Value, stock::replace::Value),
}
impl action::Action for Action {
type State<'s> = &'s DrawCount;
type Value = Value;
type Error = !;
}
impl<'a, S, W> action::Target<Action> for FromTo<'a, S, W>
where
S: action::Target<stock::draw::Action> + action::Target<stock::replace::Action>,
W: action::Target<waste::empty::Action> + action::Target<waste::place::Action>,
{
fn update(&mut self, _: Action, DrawCount(draw_count): &DrawCount) -> Result<Value, !> {
let FromTo(stock, waste) = self;
match stock.update(stock::draw::Action(*draw_count), ()) {
Ok(draw_value) => {
let to_place = draw_value.drawn().clone();
let Ok(place_value) = waste.update(waste::place::Action(to_place), ());
Ok(Value(Undo::Draw(draw_value, place_value)))
}
Err(stock::draw::Error::Empty) => {
let Ok(empty_value) = waste.update(waste::empty::Action, ());
let to_replace = empty_value.emptied().clone();
match stock.update(stock::replace::Action(to_replace), ()) {
Ok(replace_value) => Ok(Value(Undo::Replace(empty_value, replace_value))),
Err(stock::replace::Error::NotEmpty) => {
panic!("Call Shroedinger: The stock is both empty and not empty!")
}
}
}
}
}
}
impl<'a, S, W> undo::Target<Value> for FromTo<'a, S, W>
where
S: undo::Target<stock::draw::Value> + undo::Target<stock::replace::Value>,
W: undo::Target<waste::empty::Value> + undo::Target<waste::place::Value>,
{
fn revert(&mut self, Value(undo): Value) {
let FromTo(stock, waste) = self;
match undo {
Undo::Draw(draw_value, place_value) => {
waste.revert(place_value);
stock.revert(draw_value);
}
Undo::Replace(empty_value, replace_value) => {
stock.revert(replace_value);
waste.revert(empty_value);
}
}
}
}