use {
anyhow::anyhow,
lazy_regex::*,
schemars::{
JsonSchema,
Schema,
SchemaGenerator,
json_schema,
},
serde::{
Deserialize,
Deserializer,
de,
},
std::{
borrow::Cow,
str::FromStr,
time::Duration,
},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Period {
pub duration: Duration,
}
impl Period {
pub const fn is_zero(&self) -> bool {
self.duration.is_zero()
}
pub fn sleep(&self) {
std::thread::sleep(self.duration);
}
}
impl From<Duration> for Period {
fn from(duration: Duration) -> Self {
Self { duration }
}
}
impl FromStr for Period {
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let duration = regex_switch!(s,
r"^(?<n>\d+)\s*ns$" => Duration::from_nanos(n.parse()?),
r"^(?<n>\d+)\s*ms$" => Duration::from_millis(n.parse()?),
r"^(?<n>\d+)\s*s$" => Duration::from_secs(n.parse()?),
r"^[^1-9]*$" => Duration::new(0, 0), )
.ok_or_else(|| anyhow!("Invalid period: {s}"))?;
Ok(Self { duration })
}
}
impl<'de> Deserialize<'de> for Period {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(de::Error::custom)
}
}
impl JsonSchema for Period {
fn schema_name() -> Cow<'static, str> {
"Period".into()
}
fn schema_id() -> Cow<'static, str> {
concat!(module_path!(), "::Period").into()
}
fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
json_schema!({
"type": "string",
"description": "Duration expressed as a human-readable string such as \"15ms\" or \"2s\".",
})
}
fn inline_schema() -> bool {
true
}
}