todc_utils/specifications.rs
1//! Specifying the behavior of shared objects.
2use std::fmt::Debug;
3use std::hash::Hash;
4
5pub mod etcd;
6pub mod register;
7pub mod snapshot;
8
9/// A (sequential) specification of an object.
10///
11/// This trait defines how operations performed on the object affect its state.
12///
13/// # Examples
14///
15/// Consider the following specification for a register that stores a single
16/// `u32` value. Initially, the register contains the value `0`.
17///
18/// ```
19/// use todc_utils::Specification;
20///
21/// #[derive(Copy, Clone, Debug)]
22/// enum RegisterOp {
23/// Read(u32),
24/// Write(u32),
25/// }
26///
27/// use RegisterOp::{Read, Write};
28///
29/// struct RegisterSpec;
30///
31/// impl Specification for RegisterSpec {
32/// type State = u32;
33/// type Operation = RegisterOp;
34///
35/// fn init() -> Self::State {
36/// 0
37/// }
38///
39/// fn apply(operation: &Self::Operation, state: &Self::State) -> (bool, Self::State) {
40/// match operation {
41/// Read(value) => (value == state, *state),
42/// Write(value) => (true, *value),
43/// }
44/// }
45/// }
46/// ```
47///
48/// A `Write` operation is always valid, as is a `Read` operation that returns
49/// the value of the most-recent write.
50///
51/// ```
52/// # use todc_utils::Specification;
53/// # #[derive(Copy, Clone, Debug)]
54/// # enum RegisterOp {
55/// # Read(u32),
56/// # Write(u32),
57/// # }
58/// # use RegisterOp::{Read, Write};
59/// # struct RegisterSpec;
60/// # impl Specification for RegisterSpec {
61/// # type State = u32;
62/// # type Operation = RegisterOp;
63/// #
64/// # fn init() -> Self::State {
65/// # 0
66/// # }
67/// # fn apply(operation: &Self::Operation, state: &Self::State) -> (bool, Self::State) {
68/// # match operation {
69/// # Read(value) => (value == state, *state),
70/// # Write(value) => (true, *value),
71/// # }
72/// # }
73/// # }
74/// let (is_valid, new_state) = RegisterSpec::apply(&Write(1), &RegisterSpec::init());
75/// assert!(is_valid);
76/// assert_eq!(new_state, 1);
77///
78/// let (is_valid, new_state) = RegisterSpec::apply(&Read(1), &new_state);
79/// assert!(is_valid);
80/// assert_eq!(new_state, 1);
81/// ```
82///
83/// On the other hand, a `Read` operation that returns a different value to
84/// the one currently stored in the register is **not** valid.
85///
86/// ```
87/// # use todc_utils::Specification;
88/// # #[derive(Copy, Clone, Debug)]
89/// # enum RegisterOp {
90/// # Read(u32),
91/// # Write(u32),
92/// # }
93/// # use RegisterOp::{Read, Write};
94/// # struct RegisterSpec;
95/// # impl Specification for RegisterSpec {
96/// # type State = u32;
97/// # type Operation = RegisterOp;
98/// #
99/// # fn init() -> Self::State {
100/// # 0
101/// # }
102/// # fn apply(operation: &Self::Operation, state: &Self::State) -> (bool, Self::State) {
103/// # match operation {
104/// # Read(value) => (value == state, *state),
105/// # Write(value) => (true, *value),
106/// # }
107/// # }
108/// # }
109/// let (_, new_state) = RegisterSpec::apply(&Write(1), &RegisterSpec::init());
110/// let (is_valid, _) = RegisterSpec::apply(&Read(42), &new_state);
111/// assert!(!is_valid);
112/// ```
113
114pub trait Specification {
115 type State: Clone + Eq + Hash + Debug;
116 type Operation: Clone + Debug;
117
118 /// Returns an initial state for the object.
119 fn init() -> Self::State;
120
121 /// Returns whether applying an operation to a given state is valid, and
122 /// the new state that occurs after the operation has been applied.
123 ///
124 /// If the operation is not valid, then the state of the object should not change.
125 fn apply(op: &Self::Operation, state: &Self::State) -> (bool, Self::State);
126}