1use core::fmt;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10#[repr(u8)]
11pub enum State {
12 AC = 0,
13 AL = 1,
14 AM = 2,
15 AP = 3,
16 BA = 4,
17 CE = 5,
18 DF = 6,
19 ES = 7,
20 GO = 8,
21 MA = 9,
22 MG = 10,
23 MS = 11,
24 MT = 12,
25 PA = 13,
26 PB = 14,
27 PE = 15,
28 PI = 16,
29 PR = 17,
30 RJ = 18,
31 RN = 19,
32 RO = 20,
33 RR = 21,
34 RS = 22,
35 SC = 23,
36 SE = 24,
37 SP = 25,
38 TO = 26,
39}
40
41pub const ALL: [State; 27] = [
43 State::AC,
44 State::AL,
45 State::AM,
46 State::AP,
47 State::BA,
48 State::CE,
49 State::DF,
50 State::ES,
51 State::GO,
52 State::MA,
53 State::MG,
54 State::MS,
55 State::MT,
56 State::PA,
57 State::PB,
58 State::PE,
59 State::PI,
60 State::PR,
61 State::RJ,
62 State::RN,
63 State::RO,
64 State::RR,
65 State::RS,
66 State::SC,
67 State::SE,
68 State::SP,
69 State::TO,
70];
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
74#[repr(u8)]
75pub enum Region {
76 Norte = 0,
77 Nordeste = 1,
78 CentroOeste = 2,
79 Sudeste = 3,
80 Sul = 4,
81}
82
83impl State {
84 pub fn abbreviation(self) -> &'static str {
86 match self {
87 State::AC => "AC",
88 State::AL => "AL",
89 State::AM => "AM",
90 State::AP => "AP",
91 State::BA => "BA",
92 State::CE => "CE",
93 State::DF => "DF",
94 State::ES => "ES",
95 State::GO => "GO",
96 State::MA => "MA",
97 State::MG => "MG",
98 State::MS => "MS",
99 State::MT => "MT",
100 State::PA => "PA",
101 State::PB => "PB",
102 State::PE => "PE",
103 State::PI => "PI",
104 State::PR => "PR",
105 State::RJ => "RJ",
106 State::RN => "RN",
107 State::RO => "RO",
108 State::RR => "RR",
109 State::RS => "RS",
110 State::SC => "SC",
111 State::SE => "SE",
112 State::SP => "SP",
113 State::TO => "TO",
114 }
115 }
116
117 pub fn name(self) -> &'static str {
119 match self {
120 State::AC => "Acre",
121 State::AL => "Alagoas",
122 State::AM => "Amazonas",
123 State::AP => "Amapá",
124 State::BA => "Bahia",
125 State::CE => "Ceará",
126 State::DF => "Distrito Federal",
127 State::ES => "Espírito Santo",
128 State::GO => "Goiás",
129 State::MA => "Maranhão",
130 State::MG => "Minas Gerais",
131 State::MS => "Mato Grosso do Sul",
132 State::MT => "Mato Grosso",
133 State::PA => "Pará",
134 State::PB => "Paraíba",
135 State::PE => "Pernambuco",
136 State::PI => "Piauí",
137 State::PR => "Paraná",
138 State::RJ => "Rio de Janeiro",
139 State::RN => "Rio Grande do Norte",
140 State::RO => "Rondônia",
141 State::RR => "Roraima",
142 State::RS => "Rio Grande do Sul",
143 State::SC => "Santa Catarina",
144 State::SE => "Sergipe",
145 State::SP => "São Paulo",
146 State::TO => "Tocantins",
147 }
148 }
149
150 pub fn region(self) -> Region {
152 match self {
153 State::AC | State::AM | State::AP | State::PA | State::RO | State::RR | State::TO => {
154 Region::Norte
155 }
156 State::AL
157 | State::BA
158 | State::CE
159 | State::MA
160 | State::PB
161 | State::PE
162 | State::PI
163 | State::RN
164 | State::SE => Region::Nordeste,
165 State::DF | State::GO | State::MS | State::MT => Region::CentroOeste,
166 State::ES | State::MG | State::RJ | State::SP => Region::Sudeste,
167 State::PR | State::RS | State::SC => Region::Sul,
168 }
169 }
170
171 pub fn from_abbreviation(s: &str) -> Option<Self> {
173 match s.as_bytes() {
174 b"AC" | b"ac" | b"Ac" => Some(State::AC),
175 b"AL" | b"al" | b"Al" => Some(State::AL),
176 b"AM" | b"am" | b"Am" => Some(State::AM),
177 b"AP" | b"ap" | b"Ap" => Some(State::AP),
178 b"BA" | b"ba" | b"Ba" => Some(State::BA),
179 b"CE" | b"ce" | b"Ce" => Some(State::CE),
180 b"DF" | b"df" | b"Df" => Some(State::DF),
181 b"ES" | b"es" | b"Es" => Some(State::ES),
182 b"GO" | b"go" | b"Go" => Some(State::GO),
183 b"MA" | b"ma" | b"Ma" => Some(State::MA),
184 b"MG" | b"mg" | b"Mg" => Some(State::MG),
185 b"MS" | b"ms" | b"Ms" => Some(State::MS),
186 b"MT" | b"mt" | b"Mt" => Some(State::MT),
187 b"PA" | b"pa" | b"Pa" => Some(State::PA),
188 b"PB" | b"pb" | b"Pb" => Some(State::PB),
189 b"PE" | b"pe" | b"Pe" => Some(State::PE),
190 b"PI" | b"pi" | b"Pi" => Some(State::PI),
191 b"PR" | b"pr" | b"Pr" => Some(State::PR),
192 b"RJ" | b"rj" | b"Rj" => Some(State::RJ),
193 b"RN" | b"rn" | b"Rn" => Some(State::RN),
194 b"RO" | b"ro" | b"Ro" => Some(State::RO),
195 b"RR" | b"rr" | b"Rr" => Some(State::RR),
196 b"RS" | b"rs" | b"Rs" => Some(State::RS),
197 b"SC" | b"sc" | b"Sc" => Some(State::SC),
198 b"SE" | b"se" | b"Se" => Some(State::SE),
199 b"SP" | b"sp" | b"Sp" => Some(State::SP),
200 b"TO" | b"to" | b"To" => Some(State::TO),
201 _ => None,
202 }
203 }
204}
205
206impl fmt::Display for State {
207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208 f.write_str(self.abbreviation())
209 }
210}
211
212impl fmt::Display for Region {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 f.write_str(match self {
215 Region::Norte => "Norte",
216 Region::Nordeste => "Nordeste",
217 Region::CentroOeste => "Centro-Oeste",
218 Region::Sudeste => "Sudeste",
219 Region::Sul => "Sul",
220 })
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn all_states_count() {
230 assert_eq!(ALL.len(), 27);
231 }
232
233 #[test]
234 fn abbreviation_roundtrip() {
235 for state in ALL {
236 let abbr = state.abbreviation();
237 assert_eq!(abbr.len(), 2);
238 assert_eq!(State::from_abbreviation(abbr), Some(state));
239 }
240 }
241
242 #[test]
243 fn from_abbreviation_case_insensitive() {
244 assert_eq!(State::from_abbreviation("sp"), Some(State::SP));
245 assert_eq!(State::from_abbreviation("SP"), Some(State::SP));
246 assert_eq!(State::from_abbreviation("Sp"), Some(State::SP));
247 assert_eq!(State::from_abbreviation("XX"), None);
248 assert_eq!(State::from_abbreviation(""), None);
249 }
250
251 #[test]
252 fn display_shows_abbreviation() {
253 use alloc::string::ToString;
254 assert_eq!(State::SP.to_string(), "SP");
255 assert_eq!(State::RJ.to_string(), "RJ");
256 }
257
258 #[test]
259 fn region_classification() {
260 assert_eq!(State::SP.region(), Region::Sudeste);
261 assert_eq!(State::AM.region(), Region::Norte);
262 assert_eq!(State::BA.region(), Region::Nordeste);
263 assert_eq!(State::DF.region(), Region::CentroOeste);
264 assert_eq!(State::RS.region(), Region::Sul);
265 }
266
267 #[test]
268 fn name_not_empty() {
269 for state in ALL {
270 assert!(!state.name().is_empty());
271 }
272 }
273}