use std::fmt;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CurrencyCode {
Sek,
}
impl CurrencyCode {
pub fn as_str(&self) -> &'static str {
match self {
Self::Sek => "SEK",
}
}
}
impl Default for CurrencyCode {
fn default() -> Self {
Self::Sek
}
}
impl std::str::FromStr for CurrencyCode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
s if s.eq_ignore_ascii_case("sek") => Ok(Self::Sek),
s => Err(format!(
"Invalid currency `{s}`. Supported currencies: [SEK]"
)),
}
}
}
impl std::fmt::Display for CurrencyCode {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Sek => write!(f, "SEK"),
}
}
}
impl serde::Serialize for CurrencyCode {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = CurrencyCode;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(r#"a string containing a valid currency code"#)
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
use std::str::FromStr;
CurrencyCode::from_str(s).map_err(E::custom)
}
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(CurrencyCode::Sek)
}
fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
where
D: serde::de::Deserializer<'de>,
{
d.deserialize_str(self)
}
}
impl<'de> serde::Deserialize<'de> for CurrencyCode {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
deserializer.deserialize_option(Visitor)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json as js;
#[test]
fn serialize_currency() {
assert_eq!(
r#""SEK""#,
js::to_string(&CurrencyCode::Sek).expect("Serializing")
);
}
#[test]
fn deserialize_currency() {
assert_eq!(
CurrencyCode::Sek,
js::from_str(r#""SEK""#).expect("Deserializing")
);
assert_eq!(
CurrencyCode::Sek,
js::from_str(r#""sek""#).expect("Deserializing")
);
assert_eq!(
CurrencyCode::Sek,
js::from_str(r#""Sek""#).expect("Deserializing")
);
assert_eq!(
CurrencyCode::Sek,
js::from_str(r#""sEk""#).expect("Deserializing")
);
assert_eq!(
CurrencyCode::Sek,
js::from_str(r#""seK""#).expect("Deserializing")
);
}
}