1use std::time::Duration;
2
3pub type Distribution = crate::Distribution<Latency>;
4
5#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
6pub struct Latency {
7 millis: u64,
8}
9
10impl From<u64> for Latency {
11 fn from(millis: u64) -> Self {
12 Self { millis }
13 }
14}
15
16impl From<Latency> for u64 {
17 fn from(Latency { millis }: Latency) -> u64 {
18 millis
19 }
20}
21
22impl std::str::FromStr for Latency {
23 type Err = crate::InvalidDuration;
24
25 fn from_str(s: &str) -> Result<Self, Self::Err> {
26 let d = crate::parse_duration(s)?;
27 Ok((d.as_millis() as u64).into())
28 }
29}
30
31impl rand::distributions::Distribution<Duration> for Distribution {
32 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Duration {
33 let Latency { millis } = self.get(rng.gen());
34 Duration::from_millis(millis)
35 }
36}
37
38pub fn parse_duration(s: &str) -> Result<Duration, InvalidDuration> {
41 use regex::Regex;
42
43 let re = Regex::new(r"^\s*(\d+)(ms|s)?\s*$").expect("duration regex");
44 let cap = re.captures(s).ok_or(InvalidDuration(()))?;
45 let magnitude = cap[1].parse().map_err(|_| InvalidDuration(()))?;
46 match cap.get(2).map(|m| m.as_str()) {
47 None if magnitude == 0 => Ok(Duration::from_millis(0)),
48 Some("ms") => Ok(Duration::from_millis(magnitude)),
49 Some("s") => Ok(Duration::from_secs(magnitude)),
50 _ => Err(InvalidDuration(())),
51 }
52}
53
54#[derive(Copy, Clone, Debug)]
55pub struct InvalidDuration(());
56
57impl std::fmt::Display for InvalidDuration {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 write!(f, "invalid duration")
60 }
61}
62
63impl std::error::Error for InvalidDuration {}