use crate::config::version_error::VersionError;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::str::FromStr;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(i64)]
pub enum ConfigFileVersion {
#[default]
V1 = 1,
}
impl Display for ConfigFileVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::V1 => write!(f, "v1"),
}
}
}
impl TryFrom<i64> for ConfigFileVersion {
type Error = VersionError;
fn try_from(value: i64) -> Result<Self, Self::Error> {
match value {
1 => Ok(Self::V1),
_ => Err(VersionError::UnsupportedVersion(value)),
}
}
}
impl FromStr for ConfigFileVersion {
type Err = VersionError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"1" | "v1" | "V1" => Ok(Self::V1),
_ => Err(VersionError::UnsupportedVersionString(s.to_string())),
}
}
}
impl Serialize for ConfigFileVersion {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_i64(*self as i64)
}
}
impl<'de> Deserialize<'de> for ConfigFileVersion {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct ConfigFileVersionVisitor;
impl serde::de::Visitor<'_> for ConfigFileVersionVisitor {
type Value = ConfigFileVersion;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("1 or v1 or V1")
}
fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<Self::Value, E> {
v.try_into().map_err(serde::de::Error::custom)
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
v.parse().map_err(serde::de::Error::custom)
}
fn visit_string<E: serde::de::Error>(self, v: String) -> Result<Self::Value, E> {
self.visit_str(&v)
}
}
deserializer.deserialize_any(ConfigFileVersionVisitor)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn config_file_version_from_str_v1() {
let config_file_version = ConfigFileVersion::from_str("1").unwrap();
assert_eq!(config_file_version, ConfigFileVersion::V1);
}
#[test]
fn config_file_version_from_str_v1_lowercase() {
let config_file_version = ConfigFileVersion::from_str("v1").unwrap();
assert_eq!(config_file_version, ConfigFileVersion::V1);
}
#[test]
fn config_file_version_from_str_v1_uppercase() {
let config_file_version = ConfigFileVersion::from_str("V1").unwrap();
assert_eq!(config_file_version, ConfigFileVersion::V1);
}
#[test]
fn config_file_version_from_str_invalid() {
let result = ConfigFileVersion::from_str("invalid");
match result {
Err(VersionError::UnsupportedVersionString(s)) => assert_eq!(s, "invalid"),
_ => panic!("Unexpected error type"),
}
}
#[test]
fn config_file_version_from_i64_v1() {
let config_file_version = ConfigFileVersion::try_from(1).unwrap();
assert_eq!(config_file_version, ConfigFileVersion::V1);
}
#[test]
fn config_file_version_from_i64_invalid() {
let result = ConfigFileVersion::try_from(-1);
match result {
Err(VersionError::UnsupportedVersion(v)) => assert_eq!(v, -1),
_ => panic!("Unexpected error type"),
}
}
}