pict-rs-aggregator/src/optional.rs
2022-06-21 13:28:05 -05:00

73 lines
1.6 KiB
Rust

use serde::{de::Error, Deserialize};
use std::{
fmt::Display,
ops::{Deref, DerefMut},
str::FromStr,
};
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, serde::Serialize)]
#[serde(transparent)]
pub(crate) struct Optional<T> {
#[serde(skip_serializing_if = "Option::is_none")]
inner: Option<T>,
}
impl<T> Deref for Optional<T> {
type Target = Option<T>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<T> DerefMut for Optional<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<T> From<Option<T>> for Optional<T> {
fn from(inner: Option<T>) -> Self {
Optional { inner }
}
}
impl<T> From<Optional<T>> for Option<T> {
fn from(e: Optional<T>) -> Self {
e.inner
}
}
impl<T> Optional<T> {
pub fn as_ref(&self) -> Option<&T> {
self.inner.as_ref()
}
pub fn as_deref(&self) -> Option<&T::Target>
where
T: Deref,
{
self.inner.as_deref()
}
}
impl<'de, T> Deserialize<'de> for Optional<T>
where
T: FromStr,
T::Err: Display,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s: Option<String> = Deserialize::<'de>::deserialize(deserializer)?;
match s.as_deref().map(|s| s.trim()) {
None | Some("") => Ok(Optional { inner: None }),
Some(s) => T::from_str(&s)
.map_err(D::Error::custom)
.map(Some)
.map(|inner| Optional { inner }),
}
}
}