codes_check_digits/
error.rs

1/*!
2Provides the crate's Error and Result types as well as helper
3functions.
4
5 */
6
7use codes_common::CodeParseError;
8use std::{
9    fmt::{Debug, Display},
10    ops::RangeInclusive,
11};
12use tracing::warn;
13
14// ------------------------------------------------------------------------------------------------
15// Public Types
16// ------------------------------------------------------------------------------------------------
17
18///
19/// Errors resulting from the Check Digit [crate::Calculator]
20///
21#[derive(Clone, Debug, PartialEq, Eq)]
22pub enum CheckDigitError {
23    /// Input string length is invalid.
24    InvalidLength { min: usize, max: usize, got: usize },
25    /// Input string does not conform to the expected alphabet.
26    InvalidAlphabet { alphabet: String },
27    /// The calculated check digit does not match the input.
28    InvalidCheckDigit { expecting: String, got: String },
29}
30
31///
32/// A Result type that specifically uses this crate's Error.
33///
34pub type Result<T> = std::result::Result<T, CheckDigitError>;
35
36// ------------------------------------------------------------------------------------------------
37// Public Functions
38// ------------------------------------------------------------------------------------------------
39
40pub fn invalid_length(expecting: RangeInclusive<usize>, got: usize) -> CheckDigitError {
41    warn!("Invalid input length, {} not in {:?}", got, expecting);
42    CheckDigitError::InvalidLength {
43        min: *expecting.start(),
44        max: *expecting.end(),
45        got,
46    }
47}
48
49pub fn invalid_alphabet<S>(alphabet: S) -> CheckDigitError
50where
51    S: Into<String>,
52{
53    let alphabet = alphabet.into();
54    warn!(
55        "One or more input characters not in the alphabet {}",
56        alphabet
57    );
58    CheckDigitError::InvalidAlphabet { alphabet }
59}
60
61pub fn invalid_check_digit<T1, T2>(expecting: T1, got: T2) -> CheckDigitError
62where
63    T1: Display,
64    T2: Display,
65{
66    warn!("Invalid check digit expecting {}, got {}", expecting, got);
67    CheckDigitError::InvalidCheckDigit {
68        expecting: expecting.to_string(),
69        got: got.to_string(),
70    }
71}
72
73// ------------------------------------------------------------------------------------------------
74// Implementations
75// ------------------------------------------------------------------------------------------------
76
77impl Display for CheckDigitError {
78    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79        write!(
80            f,
81            "{}",
82            match self {
83                CheckDigitError::InvalidLength { min, max, got } => format!(
84                    "Expecting input length in the range {}..={}, not {}",
85                    min, max, got
86                ),
87                CheckDigitError::InvalidAlphabet { alphabet } =>
88                    format!("Expecting characters from the alphabet {:?}", alphabet),
89                CheckDigitError::InvalidCheckDigit { expecting, got } => format!(
90                    "Invalid check digit in string, expecting {}, got {}",
91                    expecting, got
92                ),
93            }
94        )
95    }
96}
97
98impl std::error::Error for CheckDigitError {}
99
100impl From<CheckDigitError> for CodeParseError {
101    fn from(e: CheckDigitError) -> Self {
102        Self::CheckDigit(Box::new(e))
103    }
104}