frequenz_microgrid_component_graph/
error.rs1#[derive(Debug, Clone, PartialEq)]
15#[non_exhaustive]
16pub enum ErrorKind {
17 ComponentNotFound,
19
20 Internal,
22
23 InvalidComponent,
25
26 InvalidConnection,
28
29 InvalidGraph,
32
33 ValidationErrors(Vec<ValidationError>),
36}
37
38impl std::fmt::Display for ErrorKind {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 let name = match self {
41 Self::ComponentNotFound => "ComponentNotFound",
42 Self::Internal => "Internal",
43 Self::InvalidComponent => "InvalidComponent",
44 Self::InvalidConnection => "InvalidConnection",
45 Self::InvalidGraph => "InvalidGraph",
46 Self::ValidationErrors(_) => "ValidationErrors",
47 };
48 f.write_str(name)
49 }
50}
51
52#[derive(Debug, Clone, PartialEq)]
55pub struct Error {
56 kind: ErrorKind,
57 desc: String,
58}
59
60impl Error {
61 pub fn kind(&self) -> &ErrorKind {
63 &self.kind
64 }
65
66 pub(crate) fn into_validation_errors(self) -> Result<Vec<ValidationError>, Error> {
72 match self.kind {
73 ErrorKind::ValidationErrors(errors) => Ok(errors),
74 kind => Err(Error {
75 kind,
76 desc: self.desc,
77 }),
78 }
79 }
80}
81
82impl Error {
84 pub(crate) fn component_not_found(desc: impl Into<String>) -> Self {
87 Self {
88 kind: ErrorKind::ComponentNotFound,
89 desc: desc.into(),
90 }
91 }
92
93 pub(crate) fn internal(desc: impl Into<String>) -> Self {
96 Self {
97 kind: ErrorKind::Internal,
98 desc: desc.into(),
99 }
100 }
101
102 pub(crate) fn invalid_component(desc: impl Into<String>) -> Self {
105 Self {
106 kind: ErrorKind::InvalidComponent,
107 desc: desc.into(),
108 }
109 }
110
111 pub(crate) fn invalid_connection(desc: impl Into<String>) -> Self {
114 Self {
115 kind: ErrorKind::InvalidConnection,
116 desc: desc.into(),
117 }
118 }
119
120 pub(crate) fn invalid_graph(desc: impl Into<String>) -> Self {
123 Self {
124 kind: ErrorKind::InvalidGraph,
125 desc: desc.into(),
126 }
127 }
128
129 pub(crate) fn validation_errors(errors: Vec<ValidationError>) -> Self {
132 Self {
135 kind: ErrorKind::ValidationErrors(errors),
136 desc: String::new(),
137 }
138 }
139}
140
141impl std::fmt::Display for Error {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 match &self.kind {
144 ErrorKind::ValidationErrors(errors) => {
145 write!(f, "Graph validation failed:")?;
146 for error in errors {
147 write!(f, "\n {error}")?;
148 }
149 Ok(())
150 }
151 kind => write!(f, "{kind}: {}", self.desc),
152 }
153 }
154}
155
156impl std::error::Error for Error {}
157
158#[derive(Debug, Clone, PartialEq)]
167pub struct ValidationError {
168 message: String,
169 component_ids: Vec<u64>,
170}
171
172impl ValidationError {
173 pub(crate) fn new(message: impl Into<String>, component_ids: impl Into<Vec<u64>>) -> Self {
176 Self {
177 message: message.into(),
178 component_ids: component_ids.into(),
179 }
180 }
181
182 pub fn message(&self) -> &str {
184 &self.message
185 }
186
187 pub fn component_ids(&self) -> &[u64] {
189 &self.component_ids
190 }
191}
192
193impl std::fmt::Display for ValidationError {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 f.write_str(&self.message)
196 }
197}
198
199impl std::error::Error for ValidationError {}
200
201impl From<ValidationError> for Error {
202 fn from(error: ValidationError) -> Self {
203 Error::validation_errors(vec![error])
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
212 fn validation_error_exposes_its_message_and_components() {
213 let error = ValidationError::new("boom", [3u64, 4]);
214 assert_eq!(error.message(), "boom");
215 assert_eq!(error.component_ids(), &[3, 4]);
216 assert_eq!(error.to_string(), "boom");
218 }
219
220 #[test]
221 fn leaf_error_display_is_unchanged() {
222 assert_eq!(
223 Error::invalid_graph("No grid component found.").to_string(),
224 "InvalidGraph: No grid component found."
225 );
226 }
227
228 #[test]
229 fn validation_errors_display_lists_each_failure() {
230 let error = Error::validation_errors(vec![
231 ValidationError::new("first problem", [1u64]),
232 ValidationError::new("second problem", [2u64, 3]),
233 ]);
234 assert_eq!(
235 error.to_string(),
236 "Graph validation failed:\n first problem\n second problem"
237 );
238 }
239
240 #[test]
241 fn into_validation_errors_unwraps_the_collected_failures() {
242 let error: Error = ValidationError::new("boom", [1u64]).into();
243 assert_eq!(
244 error.into_validation_errors(),
245 Ok(vec![ValidationError::new("boom", [1u64])])
246 );
247 }
248
249 #[test]
250 fn into_validation_errors_passes_other_kinds_through() {
251 assert_eq!(
252 Error::internal("bug").into_validation_errors(),
253 Err(Error::internal("bug"))
254 );
255 }
256}