Skip to main content

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}