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}