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
//! Defines the [`ApplicableTo`] trait and related types.
use Arc;
use crateLogEntry;
use crateLogEntryOf;
use crateOutcomeOf;
use crateState;
/// Shorthand to extract `Projected` type out of `A as ApplicableTo<S>`.
pub type ProjectedOf<A, S> = Projected;
/// Shorthand to extract `Projection` type out of `A as ApplicableTo<S>`.
pub type ProjectionOf<A, S> = Projection;
/// Describes values that may be [applied][State::apply] to type `S`.
///
/// For any given `State` implementation there is usually a wide range of
/// possible operations. These are encoded by its corresponding `LogEntry` type,
/// which commonly contains (or is) an enum value whose variants correspond to
/// the state's operations. Different operations usually have different
/// outcome types, which is why [State::Outcome] is also commonly an enum.
///
/// This presents an ergonomics challenge. Imagine `enum MyLogEntry { A, B }`
/// and `enum MyOutcome { A(i64), B(bool) }`. When appending a `MyLogEntry::A`
/// we'd like to get back an `i64` rather than a `MyOutcome`. This can be
/// achieved as follows.
///
/// ```
/// # use std::convert::Infallible;
/// # use std::sync::Arc;
/// #
/// # #[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
/// # enum MyLogEntry {
/// # A,
/// # B,
/// # }
/// #
/// # #[derive(Clone, Debug)]
/// # enum MyOutcome {
/// # A(i64),
/// # B(bool),
/// # }
/// #
/// # #[derive(Clone, Debug)]
/// # struct MyState;
/// #
/// # impl paxakos::LogEntry for MyLogEntry {
/// # type Id = ();
/// #
/// # fn id(&self) -> Self::Id {
/// # unimplemented!()
/// # }
/// # }
/// # impl paxakos::State for MyState {
/// # type Frozen = Self;
/// #
/// # type LogEntry = MyLogEntry;
/// #
/// # type Context = ();
/// #
/// # type Outcome = MyOutcome;
/// #
/// # type Effect = ();
/// #
/// # type Error = Infallible;
/// #
/// # type Node = ();
/// #
/// # fn apply(
/// # &mut self,
/// # _log_entry: &Self::LogEntry,
/// # _context: &mut Self::Context,
/// # ) -> Result<(Self::Outcome, Self::Effect), Self::Error> {
/// # unimplemented!()
/// # }
/// #
/// # fn cluster_at(&self, _round_offset: std::num::NonZeroUsize) -> Vec<Self::Node> {
/// # unimplemented!()
/// # }
/// #
/// # fn freeze(&self, _context: &mut Self::Context) -> Self::Frozen {
/// # unimplemented!()
/// # }
/// # }
/// #
/// struct A;
///
/// impl paxakos::applicable::ApplicableTo<MyState> for A {
/// type Projection = ProjectionA;
///
/// fn into_log_entry(self) -> Arc<MyLogEntry> {
/// Arc::new(MyLogEntry::A)
/// }
/// }
///
/// struct ProjectionA;
///
/// impl paxakos::applicable::Projection<MyOutcome> for ProjectionA {
/// type Projected = i64;
///
/// fn project(val: MyOutcome) -> Self::Projected {
/// match val {
/// MyOutcome::A(i) => i,
/// _ => panic!("unexpected: {:?}", val)
/// }
/// }
/// }
/// ```
/// A projection from `T` to `Self::Projected`.
/// The identity projection.
;