use std::fmt::Debug;
use std::str::FromStr;
type ParseError<T> = <T as FromStr>::Err;
pub struct StringValue<T: FromStr>
where
ParseError<T>: Debug + Clone + PartialEq + Eq,
{
raw: String,
value: Result<T, ParseError<T>>,
}
impl<T> StringValue<T>
where
T: FromStr,
ParseError<T>: Debug + Clone + PartialEq + Eq,
{
pub fn from_value(value: T) -> Self
where
T: ToString,
{
Self {
raw: value.to_string(),
value: Ok(value),
}
}
#[must_use]
pub fn new(raw: impl Into<String>) -> Self {
let raw = raw.into();
let value = T::from_str(&raw);
Self { raw, value }
}
pub const fn value(&self) -> &Result<T, ParseError<T>> {
&self.value
}
pub fn raw(&self) -> &str {
&self.raw
}
}
impl<T: Debug + FromStr> Debug for StringValue<T>
where
ParseError<T>: Debug + Clone + PartialEq + Eq,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("StringValue")
.field("raw", &self.raw)
.field("value", &self.value)
.finish()
}
}
impl<T: FromStr + Clone> Clone for StringValue<T>
where
ParseError<T>: Debug + Clone + PartialEq + Eq,
{
fn clone(&self) -> Self {
Self {
raw: self.raw.clone(),
value: self.value.clone(),
}
}
}
impl<T: FromStr + PartialEq> PartialEq for StringValue<T>
where
ParseError<T>: Debug + Clone + PartialEq + Eq,
{
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw && self.value == other.value
}
}
impl<T: FromStr + Eq> Eq for StringValue<T> where ParseError<T>: Debug + Clone + PartialEq + Eq {}
impl<T> AsRef<Result<T, ParseError<T>>> for StringValue<T>
where
T: FromStr,
ParseError<T>: Debug + Clone + PartialEq + Eq,
{
fn as_ref(&self) -> &Result<T, ParseError<T>> {
&self.value
}
}
impl<T: std::fmt::Display + FromStr> std::fmt::Display for StringValue<T>
where
ParseError<T>: Debug + Clone + PartialEq + Eq,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.raw, f)
}
}
#[cfg(feature = "serde")]
impl<T: FromStr> serde::Serialize for StringValue<T>
where
ParseError<T>: Debug + Clone + PartialEq + Eq,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.raw.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: FromStr> serde::Deserialize<'de> for StringValue<T>
where
ParseError<T>: Debug + Clone + PartialEq + Eq,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let raw = String::deserialize(deserializer)?;
Ok(Self::new(raw))
}
}