use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum BankCode {
Absa,
Access,
Akiba,
Amana,
Azania,
Baroda,
Boa,
Citi,
Crdb,
Dtb,
Ecobank,
Equity,
Exim,
Fnb,
Habib,
ImBank,
Kcb,
Nbc,
Ncba,
Nmb,
Pbz,
Scb,
Stanbic,
Tcb,
Uba,
Other(String),
}
impl BankCode {
pub fn as_str(&self) -> &str {
match self {
Self::Absa => "ABSA",
Self::Access => "ACCESS",
Self::Akiba => "AKIBA",
Self::Amana => "AMANA",
Self::Azania => "AZANIA",
Self::Baroda => "BARODA",
Self::Boa => "BOA",
Self::Citi => "CITI",
Self::Crdb => "CRDB",
Self::Dtb => "DTB",
Self::Ecobank => "ECOBANK",
Self::Equity => "EQUITY",
Self::Exim => "EXIM",
Self::Fnb => "FNB",
Self::Habib => "HABIB",
Self::ImBank => "IMBANK",
Self::Kcb => "KCB",
Self::Nbc => "NBC",
Self::Ncba => "NCBA",
Self::Nmb => "NMB",
Self::Pbz => "PBZ",
Self::Scb => "SCB",
Self::Stanbic => "STANBIC",
Self::Tcb => "TCB",
Self::Uba => "UBA",
Self::Other(s) => s.as_str(),
}
}
pub fn parse(s: &str) -> Self {
match s {
"ABSA" => Self::Absa,
"ACCESS" => Self::Access,
"AKIBA" => Self::Akiba,
"AMANA" => Self::Amana,
"AZANIA" => Self::Azania,
"BARODA" => Self::Baroda,
"BOA" => Self::Boa,
"CITI" => Self::Citi,
"CRDB" => Self::Crdb,
"DTB" => Self::Dtb,
"ECOBANK" => Self::Ecobank,
"EQUITY" => Self::Equity,
"EXIM" => Self::Exim,
"FNB" => Self::Fnb,
"HABIB" => Self::Habib,
"IMBANK" => Self::ImBank,
"KCB" => Self::Kcb,
"NBC" => Self::Nbc,
"NCBA" => Self::Ncba,
"NMB" => Self::Nmb,
"PBZ" => Self::Pbz,
"SCB" => Self::Scb,
"STANBIC" => Self::Stanbic,
"TCB" => Self::Tcb,
"UBA" => Self::Uba,
other => Self::Other(other.to_string()),
}
}
}
impl std::fmt::Display for BankCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
impl std::str::FromStr for BankCode {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::parse(s))
}
}
impl Serialize for BankCode {
fn serialize<S>(&self, ser: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
ser.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for BankCode {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(d)?;
Ok(Self::parse(&s))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn known_codes_round_trip() {
for code in [
"ABSA", "CRDB", "NMB", "NBC", "STANBIC", "EQUITY", "KCB", "UBA",
] {
let parsed = BankCode::parse(code);
assert!(!matches!(parsed, BankCode::Other(_)), "{}", code);
assert_eq!(parsed.as_str(), code);
}
}
#[test]
fn unknown_codes_preserve_raw() {
let code = BankCode::parse("FUTURE_BANK");
assert!(matches!(code, BankCode::Other(_)));
assert_eq!(code.as_str(), "FUTURE_BANK");
}
#[test]
fn fromstr_works_via_parse() {
let code: BankCode = "CRDB".parse().unwrap();
assert_eq!(code, BankCode::Crdb);
}
#[test]
fn serialises_as_string() {
let json = serde_json::to_string(&BankCode::Crdb).unwrap();
assert_eq!(json, r#""CRDB""#);
}
}