1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
use std::{
    ops::{Div, Mul},
    time::Duration,
};

use derive_more::*;

#[derive(Debug, Deref, Display, Into, Mul, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[display(fmt = "{_0} bytes")]
pub struct ByteCount(pub u64);

impl From<ByteCount> for usize {
    fn from(value: ByteCount) -> Self {
        value.0 as usize
    }
}

impl Div<PacketSize> for ByteCount {
    type Output = PacketCount;

    fn div(self, rhs: PacketSize) -> Self::Output {
        PacketCount(self.0 / rhs.0)
    }
}

#[derive(Debug, Deref, Display, Into, Add, Sub, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[display(fmt = "{_0} bytes")]
pub struct PacketSize(pub u64);

impl From<PacketSize> for usize {
    fn from(value: PacketSize) -> Self {
        value.0 as usize
    }
}

#[derive(Debug, Deref, Display, Into, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[display(fmt = "{_0} packets")]
pub struct PacketCount(pub u64);

impl From<PacketCount> for usize {
    fn from(value: PacketCount) -> Self {
        value.0 as usize
    }
}

impl Mul<PacketCount> for PacketSize {
    type Output = ByteCount;

    fn mul(self, rhs: PacketCount) -> Self::Output {
        ByteCount(self.0 * rhs.0)
    }
}

impl Mul<PacketSize> for PacketCount {
    type Output = ByteCount;

    fn mul(self, rhs: PacketSize) -> Self::Output {
        rhs * self
    }
}

impl PacketCount {
    pub fn for_time_window(window: Duration, packet_spacing: Duration) -> PacketCount {
        PacketCount((window.as_micros() / packet_spacing.as_micros()) as u64)
    }
}

#[derive(Debug, Deref, Display, Into, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[display(fmt = "{_0} bytes/s")]
pub struct DataRate(pub u64);

impl Mul<Duration> for DataRate {
    type Output = ByteCount;

    fn mul(self, rhs: Duration) -> Self::Output {
        let bytes_nearest_second = self.0 * rhs.as_secs();
        let bytes_scaled_for_micros = self.0.saturating_mul(u64::from(rhs.subsec_micros()));
        let bytes_remaining_micros = bytes_scaled_for_micros / 1_000_000;
        ByteCount(bytes_nearest_second + bytes_remaining_micros)
    }
}

impl Mul<DataRate> for Duration {
    type Output = ByteCount;

    fn mul(self, rhs: DataRate) -> Self::Output {
        rhs * self
    }
}

impl DataRate {
    pub fn as_mbps_f64(&self) -> f64 {
        self.0 as f64 / 1_000_000.
    }
}

#[derive(Debug, Deref, Display, Into, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[display(fmt = "{_0} packets/s")]
pub struct PacketRate(pub u64);

impl Mul<Duration> for PacketRate {
    type Output = PacketCount;

    fn mul(self, rhs: Duration) -> Self::Output {
        let packets_nearest_second = self.0 * rhs.as_secs();
        let packets_scaled_for_micros =
            (self.0 as usize).saturating_mul(rhs.subsec_micros() as usize);
        let packets_remaining_micros = (packets_scaled_for_micros / 1_000_000) as u64;
        PacketCount(packets_nearest_second + packets_remaining_micros)
    }
}

impl Mul<PacketRate> for Duration {
    type Output = PacketCount;

    fn mul(self, rhs: PacketRate) -> Self::Output {
        rhs * self
    }
}

impl Div<PacketRate> for DataRate {
    type Output = PacketSize;

    fn div(self, rhs: PacketRate) -> Self::Output {
        PacketSize(self.0 / rhs.0)
    }
}

#[derive(Debug, Deref, Display, Into, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[display(fmt = "{} s/p", "_0.as_secs_f64()")]
pub struct PacketPeriod(pub Duration);

impl Mul<PacketCount> for PacketPeriod {
    type Output = Duration;

    fn mul(self, rhs: PacketCount) -> Self::Output {
        self.0 * rhs.0 as u32
    }
}

impl Mul<PacketPeriod> for PacketCount {
    type Output = Duration;

    fn mul(self, rhs: PacketPeriod) -> Self::Output {
        rhs * self
    }
}

impl PacketPeriod {
    pub fn try_from(data_rate: DataRate, packet_size: PacketSize) -> Option<Duration> {
        // multiply size to adjust data rate to microseconds (i.e. x 1,000,000)
        if packet_size.0 > 0 {
            let period = packet_size.0 * 1_000_000 / data_rate.0;
            if period > 0 {
                return Some(Duration::from_micros(period));
            }
        }
        None
    }
}

#[derive(Debug, Deref, Display, Into, Add, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[display(fmt = "{_0}%")]
pub struct Percent(pub u64);

impl Mul<DataRate> for Percent {
    type Output = DataRate;

    fn mul(self, rhs: DataRate) -> Self::Output {
        DataRate(self.0 * rhs.0 / 100)
    }
}

impl Mul<Percent> for DataRate {
    type Output = DataRate;

    fn mul(self, rhs: Percent) -> Self::Output {
        rhs * self
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn data_rate_and_duration_multiplication() {
        let data_rate = DataRate(1_000_000);
        let period = Duration::from_millis(1);

        let bytes = data_rate * period;

        assert_eq!(bytes, ByteCount(1_000))
    }

    #[test]
    fn packet_rate_and_duration_multiplication() {
        let packet_rate = PacketRate(1_000_000);
        let period = Duration::from_millis(1);

        let packets = packet_rate * period;

        assert_eq!(packets, PacketCount(1_000))
    }

    #[test]
    fn packet_period_from_data_rate_and_packet_size() {
        let data_rate = DataRate(20_000);
        let packet_size = PacketSize(500);

        let period = PacketPeriod::try_from(data_rate, packet_size);

        assert_eq!(period, Some(Duration::from_millis(25)))
    }

    #[test]
    fn display() {
        assert_eq!(format!("{}", ByteCount(100)), "100 bytes");
        assert_eq!(format!("{}", PacketSize(100)), "100 bytes");
        assert_eq!(format!("{}", PacketCount(100)), "100 packets");
        assert_eq!(format!("{}", DataRate(100)), "100 bytes/s");
        assert_eq!(format!("{}", PacketRate(100)), "100 packets/s");
        assert_eq!(format!("{}", Percent(100)), "100%");
    }
}