use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum State {
AC = 0,
AL = 1,
AM = 2,
AP = 3,
BA = 4,
CE = 5,
DF = 6,
ES = 7,
GO = 8,
MA = 9,
MG = 10,
MS = 11,
MT = 12,
PA = 13,
PB = 14,
PE = 15,
PI = 16,
PR = 17,
RJ = 18,
RN = 19,
RO = 20,
RR = 21,
RS = 22,
SC = 23,
SE = 24,
SP = 25,
TO = 26,
}
pub const ALL: [State; 27] = [
State::AC,
State::AL,
State::AM,
State::AP,
State::BA,
State::CE,
State::DF,
State::ES,
State::GO,
State::MA,
State::MG,
State::MS,
State::MT,
State::PA,
State::PB,
State::PE,
State::PI,
State::PR,
State::RJ,
State::RN,
State::RO,
State::RR,
State::RS,
State::SC,
State::SE,
State::SP,
State::TO,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum Region {
Norte = 0,
Nordeste = 1,
CentroOeste = 2,
Sudeste = 3,
Sul = 4,
}
impl State {
pub fn abbreviation(self) -> &'static str {
match self {
State::AC => "AC",
State::AL => "AL",
State::AM => "AM",
State::AP => "AP",
State::BA => "BA",
State::CE => "CE",
State::DF => "DF",
State::ES => "ES",
State::GO => "GO",
State::MA => "MA",
State::MG => "MG",
State::MS => "MS",
State::MT => "MT",
State::PA => "PA",
State::PB => "PB",
State::PE => "PE",
State::PI => "PI",
State::PR => "PR",
State::RJ => "RJ",
State::RN => "RN",
State::RO => "RO",
State::RR => "RR",
State::RS => "RS",
State::SC => "SC",
State::SE => "SE",
State::SP => "SP",
State::TO => "TO",
}
}
pub fn name(self) -> &'static str {
match self {
State::AC => "Acre",
State::AL => "Alagoas",
State::AM => "Amazonas",
State::AP => "Amapá",
State::BA => "Bahia",
State::CE => "Ceará",
State::DF => "Distrito Federal",
State::ES => "EspÃrito Santo",
State::GO => "Goiás",
State::MA => "Maranhão",
State::MG => "Minas Gerais",
State::MS => "Mato Grosso do Sul",
State::MT => "Mato Grosso",
State::PA => "Pará",
State::PB => "ParaÃba",
State::PE => "Pernambuco",
State::PI => "PiauÃ",
State::PR => "Paraná",
State::RJ => "Rio de Janeiro",
State::RN => "Rio Grande do Norte",
State::RO => "Rondônia",
State::RR => "Roraima",
State::RS => "Rio Grande do Sul",
State::SC => "Santa Catarina",
State::SE => "Sergipe",
State::SP => "São Paulo",
State::TO => "Tocantins",
}
}
pub fn region(self) -> Region {
match self {
State::AC | State::AM | State::AP | State::PA | State::RO | State::RR | State::TO => {
Region::Norte
}
State::AL
| State::BA
| State::CE
| State::MA
| State::PB
| State::PE
| State::PI
| State::RN
| State::SE => Region::Nordeste,
State::DF | State::GO | State::MS | State::MT => Region::CentroOeste,
State::ES | State::MG | State::RJ | State::SP => Region::Sudeste,
State::PR | State::RS | State::SC => Region::Sul,
}
}
pub fn from_abbreviation(s: &str) -> Option<Self> {
ALL.into_iter()
.find(|state| state.abbreviation().eq_ignore_ascii_case(s))
}
}
impl fmt::Display for State {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.abbreviation())
}
}
impl fmt::Display for Region {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
Region::Norte => "Norte",
Region::Nordeste => "Nordeste",
Region::CentroOeste => "Centro-Oeste",
Region::Sudeste => "Sudeste",
Region::Sul => "Sul",
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_states_count() {
assert_eq!(ALL.len(), 27);
}
#[test]
fn abbreviation_roundtrip() {
for state in ALL {
let abbr = state.abbreviation();
assert_eq!(abbr.len(), 2);
assert_eq!(State::from_abbreviation(abbr), Some(state));
}
}
#[test]
fn from_abbreviation_case_insensitive() {
for state in ALL {
let [first, second] = state.abbreviation().as_bytes() else {
unreachable!()
};
for abbreviation in [
[*first, *second],
[first.to_ascii_lowercase(), *second],
[*first, second.to_ascii_lowercase()],
[first.to_ascii_lowercase(), second.to_ascii_lowercase()],
] {
let abbreviation = core::str::from_utf8(&abbreviation).unwrap();
assert_eq!(State::from_abbreviation(abbreviation), Some(state));
}
}
assert_eq!(State::from_abbreviation("XX"), None);
assert_eq!(State::from_abbreviation(""), None);
}
#[test]
fn display_shows_abbreviation() {
use alloc::string::ToString;
assert_eq!(State::SP.to_string(), "SP");
assert_eq!(State::RJ.to_string(), "RJ");
}
#[test]
fn region_classification() {
assert_eq!(State::SP.region(), Region::Sudeste);
assert_eq!(State::AM.region(), Region::Norte);
assert_eq!(State::BA.region(), Region::Nordeste);
assert_eq!(State::DF.region(), Region::CentroOeste);
assert_eq!(State::RS.region(), Region::Sul);
}
#[test]
fn name_not_empty() {
for state in ALL {
assert!(!state.name().is_empty());
}
}
}