Skip to main content

openquant/util/
input_error.rs

1//! The error returned by functions whose only failure mode is an invalid argument.
2//!
3//! [`InputError`] is shared by modules that validate their arguments but have no richer error
4//! type of their own (for example [`crate::util::fast_ewma`], [`crate::sampling`],
5//! [`crate::ef3m`] and [`crate::backtest_statistics`]). Each variant names the offending
6//! argument, so the [`Display`](std::fmt::Display) message can be shown to a user as is.
7//!
8//! ```
9//! use openquant::util::fast_ewma::ewma;
10//! use openquant::util::InputError;
11//!
12//! let err = ewma(&[1.0, 2.0], 0).unwrap_err();
13//! assert_eq!(
14//!     err,
15//!     InputError::OutOfRange { name: "window", value: 0.0, expected: "a positive integer" }
16//! );
17//! assert_eq!(err.to_string(), "'window' is 0, expected a positive integer");
18//! ```
19
20use std::fmt;
21
22/// An argument was rejected before any computation ran.
23///
24/// `name` is the argument (or, for rows of a matrix, a short description of it) as it appears
25/// in the function signature.
26#[derive(Debug, Clone, PartialEq)]
27pub enum InputError {
28    /// `name` must contain at least `min` values.
29    TooShort {
30        /// The argument that was too short.
31        name: &'static str,
32        /// Its actual length.
33        len: usize,
34        /// The minimum length the function needs.
35        min: usize,
36    },
37    /// `name` must be as long as the series it is paired with.
38    LengthMismatch {
39        /// The argument whose length is wrong.
40        name: &'static str,
41        /// Its actual length.
42        len: usize,
43        /// The length it must have to match its partner.
44        expected: usize,
45    },
46    /// `name` holds a value outside the range the function is defined on.
47    OutOfRange {
48        /// The argument that is out of range.
49        name: &'static str,
50        /// The offending value (converted to `f64` for integer arguments).
51        value: f64,
52        /// A human-readable description of the accepted range.
53        expected: &'static str,
54    },
55}
56
57impl fmt::Display for InputError {
58    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59        match self {
60            InputError::TooShort { name, len, min } => {
61                write!(f, "'{name}' has length {len}, need at least {min}")
62            }
63            InputError::LengthMismatch { name, len, expected } => {
64                write!(f, "'{name}' has length {len}, expected {expected}")
65            }
66            InputError::OutOfRange { name, value, expected } => {
67                write!(f, "'{name}' is {value}, expected {expected}")
68            }
69        }
70    }
71}
72
73impl std::error::Error for InputError {}
74
75pub(crate) fn same_length(
76    name: &'static str,
77    values: &[f64],
78    expected: usize,
79) -> Result<(), InputError> {
80    if values.len() == expected {
81        Ok(())
82    } else {
83        Err(InputError::LengthMismatch { name, len: values.len(), expected })
84    }
85}