signstar_config/state.rs
1//! State handling and comparison.
2
3use std::fmt::Display;
4
5/// The indicator for where state originates from.
6#[derive(Clone, Copy, Debug, strum::Display)]
7#[strum(serialize_all = "lowercase")]
8pub enum StateOrigin {
9 /// A backend.
10 Backend,
11
12 /// A configuration file.
13 Config,
14
15 /// The operating system.
16 System,
17}
18
19/// An interface for returning the name of an object providing state.
20pub trait StateOriginInfo: std::fmt::Debug {
21 /// The name of the state implementation.
22 fn state_name(&self) -> &str;
23
24 /// The origin of the state.
25 fn state_origin(&self) -> StateOrigin;
26}
27
28/// The target of an asymmetric [`StateDiffFailure`].
29///
30/// Asymmetric failure types are those, where a state is present in one, but not another state
31/// origin (i.e. [`StateDiffFailure::DoesNotExist`]).
32///
33/// Here, the target allows to mark the state origin that introduces the asymmetry (e.g. by not
34/// providing state that another state origin offers).
35#[derive(Clone, Copy, Debug, Eq, PartialEq)]
36pub enum StateDiffFailureTarget {
37 /// The target is the `one`.
38 One,
39
40 /// The target is the `other`.
41 Other,
42}
43
44/// A report on the state diff of two objects.
45#[derive(Debug)]
46pub enum StateDiffFailure<'a, 'b> {
47 /// An item exists only in the state of a single object.
48 DoesNotExist {
49 /// The name of the one object.
50 one: Box<&'a dyn StateOriginInfo>,
51
52 /// The name of the other object.
53 other: Box<&'b dyn StateOriginInfo>,
54
55 /// The indicator for where the item is missing.
56 ///
57 /// # Note
58 ///
59 /// If `target` is set to [`StateDiffFailureTarget::One`], the item is missing in `one`, if
60 /// `target` is set to [`StateDiffFailureTarget::Other`], the item is missing in `other`.
61 target: StateDiffFailureTarget,
62
63 /// The representation of a state item, present in `one` but not `other`
64 state: String,
65 },
66
67 /// Mismatching items exists in the state of the one object and in that of the other.
68 Mismatch {
69 /// The name of the one object.
70 one: Box<&'a dyn StateOriginInfo>,
71
72 /// The name of the other object.
73 other: Box<&'b dyn StateOriginInfo>,
74
75 /// The representation of a state item, present in `one`, different from the state
76 /// item present in `other` (`other_state`).
77 one_state: String,
78
79 /// The representation of a state item, present in `other`, different from the state
80 /// item present in `one` (`one_state`).
81 other_state: String,
82 },
83}
84
85impl<'a, 'b> Display for StateDiffFailure<'a, 'b> {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match self {
88 Self::DoesNotExist {
89 one,
90 other,
91 target,
92 state,
93 } => {
94 write!(
95 f,
96 "Present in A ({}) but not in B ({}): {state}",
97 match target {
98 StateDiffFailureTarget::One => other.state_name(),
99 StateDiffFailureTarget::Other => one.state_name(),
100 },
101 match target {
102 StateDiffFailureTarget::One => one.state_name(),
103 StateDiffFailureTarget::Other => other.state_name(),
104 },
105 )
106 }
107 Self::Mismatch {
108 one,
109 other,
110 one_state,
111 other_state,
112 } => write!(
113 f,
114 "Different in A ({}) and B ({}):\nA: {one_state}\nB: {other_state}",
115 one.state_name(),
116 other.state_name(),
117 ),
118 }
119 }
120}
121
122/// A report on the state diff of two objects.
123#[derive(Debug)]
124pub enum StateDiffReport<'a, 'b> {
125 /// The diff of two object states is not successful.
126 ///
127 /// This means that a discrepancy between the one and the other object exists.
128 Failure {
129 /// A list of messages, that each describe a specific state discrepancy.
130 messages: Vec<StateDiffFailure<'a, 'b>>,
131 },
132
133 /// The diff of two object states is successful.
134 Success,
135}
136
137/// An interface to compare the state of two objects.
138pub trait StateDiff<'a, 'b> {
139 /// Returns a [`StateDiffReport`] for two objects.
140 fn diff(&self) -> StateDiffReport<'a, 'b>;
141}