use std::fmt; use std::ops::{Deref, DerefMut}; use std::str::FromStr; use std::time::Duration; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; /// Represents a time in seconds. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct Seconds(Duration); impl FromStr for Seconds { type Err = ParseSecondsError; fn from_str(s: &str) -> Result { match f64::from_str(s) { Ok(secs) => Ok(Self::try_from(secs)?), Err(_) => Err(ParseSecondsError::NotANumber), } } } impl fmt::Display for Seconds { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0.as_secs_f32()) } } impl Deref for Seconds { type Target = Duration; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for Seconds { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl TryFrom for Seconds { type Error = std::num::TryFromIntError; fn try_from(secs: i8) -> Result { Ok(Self(Duration::from_secs(u64::try_from(secs)?))) } } impl TryFrom for Seconds { type Error = std::num::TryFromIntError; fn try_from(secs: i16) -> Result { Ok(Self(Duration::from_secs(u64::try_from(secs)?))) } } impl TryFrom for Seconds { type Error = std::num::TryFromIntError; fn try_from(secs: i32) -> Result { Ok(Self(Duration::from_secs(u64::try_from(secs)?))) } } impl TryFrom for Seconds { type Error = std::num::TryFromIntError; fn try_from(secs: i64) -> Result { Ok(Self(Duration::from_secs(u64::try_from(secs)?))) } } impl From for Seconds { fn from(secs: u8) -> Self { Self(Duration::from_secs(u64::from(secs))) } } impl From for Seconds { fn from(secs: u16) -> Self { Self(Duration::from_secs(u64::from(secs))) } } impl From for Seconds { fn from(secs: u32) -> Self { Self(Duration::from_secs(u64::from(secs))) } } impl From for Seconds { fn from(secs: u64) -> Self { Self(Duration::from_secs(secs)) } } impl TryFrom for Seconds { type Error = NegativeSeconds; fn try_from(secs: f32) -> Result { if secs.is_sign_negative() { Err(NegativeSeconds) } else { Ok(Self(Duration::from_secs_f32(secs))) } } } impl TryFrom for Seconds { type Error = NegativeSeconds; fn try_from(secs: f64) -> Result { if secs.is_sign_negative() { Err(NegativeSeconds) } else { Ok(Self(Duration::from_secs_f64(secs))) } } } impl From for Seconds { fn from(d: Duration) -> Self { Self(d) } } impl From for Duration { fn from(secs: Seconds) -> Self { secs.0 } } pub use self::errors::{NegativeSeconds, ParseSecondsError}; mod errors { use super::*; /// Represents errors that can occur when parsing seconds. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum ParseSecondsError { NegativeSeconds, NotANumber, } impl std::error::Error for ParseSecondsError {} impl fmt::Display for ParseSecondsError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::NegativeSeconds => write!(f, "seconds cannot be negative"), Self::NotANumber => write!(f, "seconds must be a number"), } } } impl From for ParseSecondsError { fn from(_: NegativeSeconds) -> Self { Self::NegativeSeconds } } /// Error type when provided seconds is negative. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct NegativeSeconds; impl std::error::Error for NegativeSeconds {} impl fmt::Display for NegativeSeconds { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "seconds cannot be negative") } } } mod ser { use super::*; impl Serialize for Seconds { fn serialize(&self, serializer: S) -> Result where S: Serializer, { serializer.serialize_f32(self.as_secs_f32()) } } impl<'de> Deserialize<'de> for Seconds { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_f32(SecondsVisitor) } } struct SecondsVisitor; impl<'de> de::Visitor<'de> for SecondsVisitor { type Value = Seconds; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a valid amount of seconds") } fn visit_i8(self, value: i8) -> Result where E: de::Error, { Seconds::try_from(value).map_err(de::Error::custom) } fn visit_i16(self, value: i16) -> Result where E: de::Error, { Seconds::try_from(value).map_err(de::Error::custom) } fn visit_i32(self, value: i32) -> Result where E: de::Error, { Seconds::try_from(value).map_err(de::Error::custom) } fn visit_i64(self, value: i64) -> Result where E: de::Error, { Seconds::try_from(value).map_err(de::Error::custom) } fn visit_u8(self, value: u8) -> Result where E: de::Error, { Ok(Seconds::from(value)) } fn visit_u16(self, value: u16) -> Result where E: de::Error, { Ok(Seconds::from(value)) } fn visit_u32(self, value: u32) -> Result where E: de::Error, { Ok(Seconds::from(value)) } fn visit_u64(self, value: u64) -> Result where E: de::Error, { Ok(Seconds::from(value)) } fn visit_f32(self, value: f32) -> Result where E: de::Error, { Seconds::try_from(value).map_err(de::Error::custom) } fn visit_f64(self, value: f64) -> Result where E: de::Error, { Seconds::try_from(value).map_err(de::Error::custom) } fn visit_str(self, s: &str) -> Result where E: de::Error, { s.parse().map_err(de::Error::custom) } } }