qsm_core/error.rs
1//! The error an algorithm returns when it is handed input it cannot process.
2
3/// Input an algorithm cannot process: too few echoes, echo times it cannot use, buffers that do
4/// not match the grid, a singular affine, and so on. The message says what was wrong and with
5/// what values, so a host can pass it straight to its user.
6///
7/// Algorithms return this instead of panicking. A host that wants to reject a run before any
8/// work starts should still check its parameters itself (the message here is the last line of
9/// defence, not a substitute for validating a config).
10///
11/// The pipeline stages convert it to [`PipelineError::InvalidInput`](crate::pipeline::PipelineError::InvalidInput).
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct InputError(pub String);
14
15impl InputError {
16 /// An error with this message.
17 pub fn new(msg: impl Into<String>) -> Self {
18 Self(msg.into())
19 }
20
21 /// A parameter outside the range the algorithm accepts, as
22 /// `"{name} = {value} is out of range: must be {allowed}"`. `name` should say whose
23 /// parameter it is (`"V-SHARP min_radius"`), and `allowed` the range with its unit
24 /// (`"finite and > 0 mm"`), so the message stands on its own in a host's error report.
25 pub fn param(name: &str, value: impl std::fmt::Display, allowed: &str) -> Self {
26 Self(format!("{name} = {value} is out of range: must be {allowed}"))
27 }
28}
29
30impl std::fmt::Display for InputError {
31 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32 f.write_str(&self.0)
33 }
34}
35
36impl std::error::Error for InputError {}
37
38/// `Err(InputError)` unless `len == expected`, naming the buffer.
39pub(crate) fn check_len(name: &str, len: usize, expected: usize) -> Result<(), InputError> {
40 if len == expected {
41 Ok(())
42 } else {
43 Err(InputError(format!("{name} has {len} values, expected {expected}")))
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn param_error_names_parameter_value_and_range() {
53 let e = InputError::param("V-SHARP min_radius", 0.0, "finite and > 0 mm");
54 assert_eq!(e.to_string(), "V-SHARP min_radius = 0 is out of range: must be finite and > 0 mm");
55 }
56}