Skip to main content

ixa_fips/
errors.rs

1//!
2//! We only have one error case, namely when a value is out of range. Instances of `FIPSError` are constructed
3//! with the `FIPSError::from_*_code()` constructor methods in the `FIPSCode::encode_*()` constructor methods.
4//!
5
6use std::error::Error;
7use std::fmt::{Debug, Display, Formatter};
8
9use crate::{CountyCode, DataCode, IdCode, SettingCategoryCode, StateCode, TractCode};
10
11#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
12pub struct FIPSError {
13    parameter_name: &'static str,
14    value: u64,
15    min: u64,
16    max: u64,
17}
18
19impl Display for FIPSError {
20    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
21        write!(
22            f,
23            "value {} provided for {} is outside valid range of {}..{}",
24            self.value, self.parameter_name, self.min, self.max
25        )
26    }
27}
28
29impl Error for FIPSError {}
30
31impl FIPSError {
32    #[must_use]
33    pub fn new(parameter_name: &'static str, value: u64, min: u64, max: u64) -> Self {
34        Self {
35            parameter_name,
36            value,
37            min,
38            max,
39        }
40    }
41
42    // Convenience constructors for the code types. These should be kept in sync with the module-level documentation
43    // in `fips_code.rs`.
44
45    /// This one is unique in that it represents an error converting a (presumably valid) [`StateCode`] to a [`USState`]
46    /// variant. We lie a little bit and claim that values in 1..57 are valid when 3, 7, 14, 43, and 52 are not.
47    #[must_use]
48    pub fn from_us_state(value: StateCode) -> Self {
49        Self {
50            parameter_name: "USState Code",
51            value: value as u64,
52            min: 1,
53            max: 57, // 1..57
54        }
55    }
56
57    #[must_use]
58    pub fn from_state_code(value: StateCode) -> Self {
59        Self {
60            parameter_name: "StateCode",
61            value: value as u64,
62            min: 1,
63            max: 100, // Two decimal digits
64        }
65    }
66
67    #[must_use]
68    pub fn from_county_code(value: CountyCode) -> Self {
69        Self {
70            parameter_name: "CountyCode",
71            value: value as u64,
72            min: 0,
73            max: 1000, // Three decimal digits
74        }
75    }
76
77    #[must_use]
78    pub fn from_tract_code(value: TractCode) -> Self {
79        Self {
80            parameter_name: "TractCode",
81            value: value as u64,
82            min: 0,
83            max: 1_000_000, // Six decimal digits
84        }
85    }
86
87    #[must_use]
88    pub fn from_setting_category_code(value: SettingCategoryCode) -> Self {
89        Self {
90            parameter_name: "SettingCategoryCode",
91            value: value as u64,
92            min: 0,
93            max: 16, // 2^4
94        }
95    }
96
97    #[must_use]
98    pub fn from_id_code(value: IdCode) -> Self {
99        Self {
100            parameter_name: "IdCode",
101            value: value as u64,
102            min: 0,
103            max: 16_384, // 2^14
104        }
105    }
106
107    #[must_use]
108    pub fn from_data_code(value: DataCode) -> Self {
109        Self {
110            parameter_name: "DataCode",
111            value: value as u64,
112            min: 0,
113            max: 512, // 2^9
114        }
115    }
116}
117
118// Tested in `fips_code.rs`.