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
//! Specifying the behavior of shared objects.
use std::fmt::Debug;
use std::hash::Hash;
pub mod etcd;
pub mod register;
pub mod snapshot;
/// A (sequential) specification of an object.
///
/// This trait defines how operations performed on the object affect its state.
///
/// # Examples
///
/// Consider the following specification for a register that stores a single
/// `u32` value. Initially, the register contains the value `0`.
///
/// ```
/// use todc_utils::Specification;
///
/// #[derive(Copy, Clone, Debug)]
/// enum RegisterOp {
/// Read(u32),
/// Write(u32),
/// }
///
/// use RegisterOp::{Read, Write};
///
/// struct RegisterSpec;
///
/// impl Specification for RegisterSpec {
/// type State = u32;
/// type Operation = RegisterOp;
///
/// fn init() -> Self::State {
/// 0
/// }
///
/// fn apply(operation: &Self::Operation, state: &Self::State) -> (bool, Self::State) {
/// match operation {
/// Read(value) => (value == state, *state),
/// Write(value) => (true, *value),
/// }
/// }
/// }
/// ```
///
/// A `Write` operation is always valid, as is a `Read` operation that returns
/// the value of the most-recent write.
///
/// ```
/// # use todc_utils::Specification;
/// # #[derive(Copy, Clone, Debug)]
/// # enum RegisterOp {
/// # Read(u32),
/// # Write(u32),
/// # }
/// # use RegisterOp::{Read, Write};
/// # struct RegisterSpec;
/// # impl Specification for RegisterSpec {
/// # type State = u32;
/// # type Operation = RegisterOp;
/// #
/// # fn init() -> Self::State {
/// # 0
/// # }
/// # fn apply(operation: &Self::Operation, state: &Self::State) -> (bool, Self::State) {
/// # match operation {
/// # Read(value) => (value == state, *state),
/// # Write(value) => (true, *value),
/// # }
/// # }
/// # }
/// let (is_valid, new_state) = RegisterSpec::apply(&Write(1), &RegisterSpec::init());
/// assert!(is_valid);
/// assert_eq!(new_state, 1);
///
/// let (is_valid, new_state) = RegisterSpec::apply(&Read(1), &new_state);
/// assert!(is_valid);
/// assert_eq!(new_state, 1);
/// ```
///
/// On the other hand, a `Read` operation that returns a different value to
/// the one currently stored in the register is **not** valid.
///
/// ```
/// # use todc_utils::Specification;
/// # #[derive(Copy, Clone, Debug)]
/// # enum RegisterOp {
/// # Read(u32),
/// # Write(u32),
/// # }
/// # use RegisterOp::{Read, Write};
/// # struct RegisterSpec;
/// # impl Specification for RegisterSpec {
/// # type State = u32;
/// # type Operation = RegisterOp;
/// #
/// # fn init() -> Self::State {
/// # 0
/// # }
/// # fn apply(operation: &Self::Operation, state: &Self::State) -> (bool, Self::State) {
/// # match operation {
/// # Read(value) => (value == state, *state),
/// # Write(value) => (true, *value),
/// # }
/// # }
/// # }
/// let (_, new_state) = RegisterSpec::apply(&Write(1), &RegisterSpec::init());
/// let (is_valid, _) = RegisterSpec::apply(&Read(42), &new_state);
/// assert!(!is_valid);
/// ```
pub trait Specification {
type State: Clone + Eq + Hash + Debug;
type Operation: Clone + Debug;
/// Returns an initial state for the object.
fn init() -> Self::State;
/// Returns whether applying an operation to a given state is valid, and
/// the new state that occurs after the operation has been applied.
///
/// If the operation is not valid, then the state of the object should not change.
fn apply(op: &Self::Operation, state: &Self::State) -> (bool, Self::State);
}