netem_trace/model/
bw.rs

1//! This module contains some predefined bandwidth trace models.
2//!
3//! Enabled with feature `bw-model` or `model`.
4//!
5//! ## Predefined models
6//!
7//! - [`StaticBw`]: A trace model with static bandwidth.
8//! - [`NormalizedBw`]: A trace model whose bandwidth subjects to a normal distribution (can set upper and lower bounds, and can configure it to be truncated with `truncated-normal` feature enabled).
9//! - [`RepeatedBwPattern`]: A trace model with a repeated bandwidth pattern.
10//! - [`TraceBw`]: A trace model to replay compact bandwidth changes from file, especially useful for online sampled records.
11//!
12//! ## Examples
13//!
14//! An example to build model from configuration:
15//!
16//! ```
17//! # use netem_trace::model::StaticBwConfig;
18//! # use netem_trace::{Bandwidth, Duration, BwTrace};
19//! let mut static_bw = StaticBwConfig::new()
20//!     .bw(Bandwidth::from_mbps(24))
21//!     .duration(Duration::from_secs(1))
22//!     .build();
23//! assert_eq!(static_bw.next_bw(), Some((Bandwidth::from_mbps(24), Duration::from_secs(1))));
24//! assert_eq!(static_bw.next_bw(), None);
25//! ```
26//!
27//! A more common use case is to build model from a configuration file (e.g. json file):
28//!
29//! ```
30//! # use netem_trace::model::{StaticBwConfig, BwTraceConfig};
31//! # use netem_trace::{Bandwidth, Duration, BwTrace};
32//! # #[cfg(feature = "human")]
33//! # let config_file_content = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":\"12Mbps\",\"duration\":\"1s\"}},{\"StaticBwConfig\":{\"bw\":\"24Mbps\",\"duration\":\"1s\"}}],\"count\":2}}";
34//! // The content would be "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":12000000},\"duration\":{\"secs\":1,\"nanos\":0}}},{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":24000000},\"duration\":{\"secs\":1,\"nanos\":0}}}],\"count\":2}}"
35//! // if the `human` feature is not enabled.
36//! # #[cfg(not(feature = "human"))]
37//! let config_file_content = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":12000000},\"duration\":{\"secs\":1,\"nanos\":0}}},{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":24000000},\"duration\":{\"secs\":1,\"nanos\":0}}}],\"count\":2}}";
38//! let des: Box<dyn BwTraceConfig> = serde_json::from_str(config_file_content).unwrap();
39//! let mut model = des.into_model();
40//! assert_eq!(
41//!     model.next_bw(),
42//!     Some((Bandwidth::from_mbps(12), Duration::from_secs(1)))
43//! );
44//! assert_eq!(
45//!     model.next_bw(),
46//!     Some((Bandwidth::from_mbps(24), Duration::from_secs(1)))
47//! );
48//! assert_eq!(
49//!     model.next_bw(),
50//!     Some((Bandwidth::from_mbps(12), Duration::from_secs(1)))
51//! );
52//! assert_eq!(
53//!     model.next_bw(),
54//!     Some((Bandwidth::from_mbps(24), Duration::from_secs(1)))
55//! );
56//! assert_eq!(model.next_bw(), None);
57//! ```
58use crate::{Bandwidth, BwTrace, Duration};
59use dyn_clone::DynClone;
60use rand::{rngs::StdRng, RngCore, SeedableRng};
61use rand_distr::{Distribution, Normal};
62
63const DEFAULT_RNG_SEED: u64 = 42;
64
65/// This trait is used to convert a bandwidth trace configuration into a bandwidth trace model.
66///
67/// Since trace model is often configured with files and often has inner states which
68/// is not suitable to be serialized/deserialized, this trait makes it possible to
69/// separate the configuration part into a simple struct for serialization/deserialization, and
70/// construct the model from the configuration.
71#[cfg_attr(feature = "serde", typetag::serde)]
72pub trait BwTraceConfig: DynClone + Send {
73    fn into_model(self: Box<Self>) -> Box<dyn BwTrace>;
74}
75
76dyn_clone::clone_trait_object!(BwTraceConfig);
77
78#[cfg(feature = "serde")]
79use serde::{Deserialize, Serialize};
80
81#[cfg(feature = "truncated-normal")]
82use super::solve_truncate::solve;
83
84/// The model of a static bandwidth trace.
85///
86/// ## Examples
87///
88/// ```
89/// # use netem_trace::model::StaticBwConfig;
90/// # use netem_trace::{Bandwidth, Duration, BwTrace};
91/// let mut static_bw = StaticBwConfig::new()
92///     .bw(Bandwidth::from_mbps(24))
93///     .duration(Duration::from_secs(1))
94///     .build();
95/// assert_eq!(static_bw.next_bw(), Some((Bandwidth::from_mbps(24), Duration::from_secs(1))));
96/// assert_eq!(static_bw.next_bw(), None);
97/// ```
98#[derive(Debug, Clone)]
99pub struct StaticBw {
100    pub bw: Bandwidth,
101    pub duration: Option<Duration>,
102}
103
104/// The configuration struct for [`StaticBw`].
105///
106/// See [`StaticBw`] for more details.
107#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
108#[derive(Debug, Clone, Default)]
109pub struct StaticBwConfig {
110    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
111    #[cfg_attr(
112        all(feature = "serde", feature = "human"),
113        serde(with = "human_bandwidth::serde")
114    )]
115    pub bw: Option<Bandwidth>,
116    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
117    #[cfg_attr(
118        all(feature = "serde", feature = "human"),
119        serde(with = "humantime_serde")
120    )]
121    pub duration: Option<Duration>,
122}
123
124/// The model of a bandwidth trace subjects to a normal distribution.
125///
126/// The bandwidth will subject to N(mean, std_dev), but bounded within [lower_bound, upper_bound] (optional)
127///
128/// ## Examples
129///
130/// A simple example without any bound on bandwidth:
131///
132/// ```
133/// # use netem_trace::model::NormalizedBwConfig;
134/// # use netem_trace::{Bandwidth, Duration, BwTrace};
135/// let mut normal_bw = NormalizedBwConfig::new()
136///     .mean(Bandwidth::from_mbps(12))
137///     .std_dev(Bandwidth::from_mbps(1))
138///     .duration(Duration::from_secs(1))
139///     .step(Duration::from_millis(100))
140///     .seed(42)
141///     .build();
142/// assert_eq!(normal_bw.next_bw(), Some((Bandwidth::from_bps(12069427), Duration::from_millis(100))));
143/// assert_eq!(normal_bw.next_bw(), Some((Bandwidth::from_bps(12132938), Duration::from_millis(100))));
144/// ```
145///
146/// A more complex example with bounds on bandwidth:
147///
148/// ```
149/// # use netem_trace::model::NormalizedBwConfig;
150/// # use netem_trace::{Bandwidth, Duration, BwTrace};
151/// let mut normal_bw = NormalizedBwConfig::new()
152///     .mean(Bandwidth::from_mbps(12))
153///     .std_dev(Bandwidth::from_mbps(1))
154///     .duration(Duration::from_secs(1))
155///     .step(Duration::from_millis(100))
156///     .seed(42)
157///     .upper_bound(Bandwidth::from_kbps(12100))
158///     .lower_bound(Bandwidth::from_kbps(11900))
159///     .build();
160/// assert_eq!(normal_bw.next_bw(), Some((Bandwidth::from_bps(12069427), Duration::from_millis(100))));
161/// assert_eq!(normal_bw.next_bw(), Some((Bandwidth::from_bps(12100000), Duration::from_millis(100))));
162/// ```
163#[derive(Debug, Clone)]
164pub struct NormalizedBw<Rng = StdRng>
165where
166    Rng: RngCore,
167{
168    pub mean: Bandwidth,
169    pub std_dev: Bandwidth,
170    pub upper_bound: Option<Bandwidth>,
171    pub lower_bound: Option<Bandwidth>,
172    pub duration: Duration,
173    pub step: Duration,
174    pub seed: u64,
175    rng: Rng,
176    normal: Normal<f64>,
177}
178
179/// The configuration struct for [`NormalizedBw`].
180///
181/// See [`NormalizedBw`] for more details.
182#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
183#[derive(Debug, Clone, Default)]
184pub struct NormalizedBwConfig {
185    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
186    #[cfg_attr(
187        all(feature = "serde", feature = "human"),
188        serde(with = "human_bandwidth::serde")
189    )]
190    pub mean: Option<Bandwidth>,
191    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
192    #[cfg_attr(
193        all(feature = "serde", feature = "human"),
194        serde(with = "human_bandwidth::serde")
195    )]
196    pub std_dev: Option<Bandwidth>,
197    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
198    #[cfg_attr(
199        all(feature = "serde", feature = "human"),
200        serde(with = "human_bandwidth::serde")
201    )]
202    pub upper_bound: Option<Bandwidth>,
203    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
204    #[cfg_attr(
205        all(feature = "serde", feature = "human"),
206        serde(with = "human_bandwidth::serde")
207    )]
208    pub lower_bound: Option<Bandwidth>,
209    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
210    #[cfg_attr(
211        all(feature = "serde", feature = "human"),
212        serde(with = "humantime_serde")
213    )]
214    pub duration: Option<Duration>,
215    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
216    #[cfg_attr(
217        all(feature = "serde", feature = "human"),
218        serde(with = "humantime_serde")
219    )]
220    pub step: Option<Duration>,
221    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
222    pub seed: Option<u64>,
223}
224
225/// The model of a bandwidth trace whose waveform is sawtooth.
226///
227/// The lowest value of the sawtooth is set by `bottom` while the highest value is set by `top`.
228/// The `interval` describes how long a sawtooth lasts. The `duty_ratio` describes how much the rising time of a sawtooth
229/// occupies the `interval`.
230///
231/// The `step` describes how long between two consecutive bandwidth samples.
232///
233/// The noise of the sawtooth bandwidth will subject to N(0, std_dev), but bounded within [-lower_noise_bound, upper_noise_bound] (optional)
234///
235/// ## Examples
236///
237/// A simple example without any bound on bandwidth:
238///
239/// ```
240/// # use netem_trace::model::SawtoothBwConfig;
241/// # use netem_trace::{Bandwidth, Duration, BwTrace};
242/// let mut sawtooth_bw = SawtoothBwConfig::new()
243///     .bottom(Bandwidth::from_mbps(12))
244///     .top(Bandwidth::from_mbps(16))
245///     .duration(Duration::from_secs(1))
246///     .step(Duration::from_millis(100))
247///     .interval(Duration::from_millis(500))
248///     .duty_ratio(0.8)
249///     .build();
250/// assert_eq!(
251///     sawtooth_bw.next_bw(),
252///     Some((Bandwidth::from_mbps(12), Duration::from_millis(100)))
253/// );
254/// assert_eq!(
255///     sawtooth_bw.next_bw(),
256///     Some((Bandwidth::from_mbps(13), Duration::from_millis(100)))
257/// );
258/// assert_eq!(
259///     sawtooth_bw.next_bw(),
260///     Some((Bandwidth::from_mbps(14), Duration::from_millis(100)))
261/// );
262/// assert_eq!(
263///     sawtooth_bw.next_bw(),
264///     Some((Bandwidth::from_mbps(15), Duration::from_millis(100)))
265/// );
266/// assert_eq!(
267///     sawtooth_bw.next_bw(),
268///     Some((Bandwidth::from_mbps(16), Duration::from_millis(100)))
269/// );
270/// assert_eq!(
271///     sawtooth_bw.next_bw(),
272///     Some((Bandwidth::from_mbps(12), Duration::from_millis(100)))
273/// );
274/// assert_eq!(
275///     sawtooth_bw.next_bw(),
276///     Some((Bandwidth::from_mbps(13), Duration::from_millis(100)))
277/// );
278/// assert_eq!(
279///     sawtooth_bw.next_bw(),
280///     Some((Bandwidth::from_mbps(14), Duration::from_millis(100)))
281/// );
282/// assert_eq!(
283///     sawtooth_bw.next_bw(),
284///     Some((Bandwidth::from_mbps(15), Duration::from_millis(100)))
285/// );
286/// ```
287///
288/// A more complex example with bounds on noise:
289///
290/// ```
291/// # use netem_trace::model::SawtoothBwConfig;
292/// # use netem_trace::{Bandwidth, Duration, BwTrace};
293/// let mut sawtooth_bw = SawtoothBwConfig::new()
294///     .bottom(Bandwidth::from_mbps(12))
295///     .top(Bandwidth::from_mbps(16))
296///     .duration(Duration::from_secs(1))
297///     .step(Duration::from_millis(100))
298///     .interval(Duration::from_millis(500))
299///     .duty_ratio(0.8)
300///     .std_dev(Bandwidth::from_mbps(5))
301///     .upper_noise_bound(Bandwidth::from_mbps(1))
302///     .lower_noise_bound(Bandwidth::from_kbps(500))
303///     .build();
304/// assert_eq!(
305///     sawtooth_bw.next_bw(),
306///     Some((Bandwidth::from_bps(12347139), Duration::from_millis(100)))
307/// );
308/// assert_eq!(
309///     sawtooth_bw.next_bw(),
310///     Some((Bandwidth::from_bps(13664690), Duration::from_millis(100)))
311/// );
312/// assert_eq!(
313///     sawtooth_bw.next_bw(),
314///     Some((Bandwidth::from_mbps(15), Duration::from_millis(100)))
315/// );
316/// assert_eq!(
317///     sawtooth_bw.next_bw(),
318///     Some((Bandwidth::from_bps(14500000), Duration::from_millis(100)))
319/// );
320/// ```
321#[derive(Debug, Clone)]
322pub struct SawtoothBw<Rng = StdRng>
323where
324    Rng: RngCore,
325{
326    pub bottom: Bandwidth,
327    pub top: Bandwidth,
328    pub interval: Duration,
329    pub duty_ratio: f64,
330    pub duration: Duration,
331    pub step: Duration,
332    pub seed: u64,
333    pub std_dev: Bandwidth,
334    pub upper_noise_bound: Option<Bandwidth>,
335    pub lower_noise_bound: Option<Bandwidth>,
336    current: Duration,
337    rng: Rng,
338    noise: Normal<f64>,
339}
340
341/// The configuration struct for [`SawtoothBw`].
342///
343/// See [`SawtoothBw`] for more details.
344#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
345#[derive(Debug, Clone, Default)]
346pub struct SawtoothBwConfig {
347    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
348    #[cfg_attr(
349        all(feature = "serde", feature = "human"),
350        serde(with = "human_bandwidth::serde")
351    )]
352    pub bottom: Option<Bandwidth>,
353    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
354    #[cfg_attr(
355        all(feature = "serde", feature = "human"),
356        serde(with = "human_bandwidth::serde")
357    )]
358    pub top: Option<Bandwidth>,
359    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
360    #[cfg_attr(
361        all(feature = "serde", feature = "human"),
362        serde(with = "humantime_serde")
363    )]
364    pub interval: Option<Duration>,
365    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
366    pub duty_ratio: Option<f64>,
367    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
368    #[cfg_attr(
369        all(feature = "serde", feature = "human"),
370        serde(with = "humantime_serde")
371    )]
372    pub duration: Option<Duration>,
373    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
374    #[cfg_attr(
375        all(feature = "serde", feature = "human"),
376        serde(with = "humantime_serde")
377    )]
378    pub step: Option<Duration>,
379    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
380    pub seed: Option<u64>,
381    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
382    #[cfg_attr(
383        all(feature = "serde", feature = "human"),
384        serde(with = "human_bandwidth::serde")
385    )]
386    pub std_dev: Option<Bandwidth>,
387    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
388    #[cfg_attr(
389        all(feature = "serde", feature = "human"),
390        serde(with = "human_bandwidth::serde")
391    )]
392    pub upper_noise_bound: Option<Bandwidth>,
393    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
394    #[cfg_attr(
395        all(feature = "serde", feature = "human"),
396        serde(with = "human_bandwidth::serde")
397    )]
398    pub lower_noise_bound: Option<Bandwidth>,
399}
400
401/// The model contains an array of bandwidth trace models.
402///
403/// Combine multiple bandwidth trace models into one bandwidth pattern,
404/// and repeat the pattern for `count` times.
405///
406/// If `count` is 0, the pattern will be repeated forever.
407///
408/// ## Examples
409///
410/// The most common use case is to read from a configuration file and
411/// deserialize it into a [`RepeatedBwPatternConfig`]:
412///
413/// ```
414/// # use netem_trace::model::{StaticBwConfig, BwTraceConfig};
415/// # use netem_trace::{Bandwidth, Duration, BwTrace};
416/// # #[cfg(feature = "human")]
417/// # let config_file_content = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":\"12Mbps\",\"duration\":\"1s\"}},{\"StaticBwConfig\":{\"bw\":\"24Mbps\",\"duration\":\"1s\"}}],\"count\":2}}";
418/// // The content would be "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":12000000},\"duration\":{\"secs\":1,\"nanos\":0}}},{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":24000000},\"duration\":{\"secs\":1,\"nanos\":0}}}],\"count\":2}}"
419/// // if the `human` feature is not enabled.
420/// # #[cfg(not(feature = "human"))]
421/// let config_file_content = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":12000000},\"duration\":{\"secs\":1,\"nanos\":0}}},{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":24000000},\"duration\":{\"secs\":1,\"nanos\":0}}}],\"count\":2}}";
422/// let des: Box<dyn BwTraceConfig> = serde_json::from_str(config_file_content).unwrap();
423/// let mut model = des.into_model();
424/// assert_eq!(
425///     model.next_bw(),
426///     Some((Bandwidth::from_mbps(12), Duration::from_secs(1)))
427/// );
428/// assert_eq!(
429///     model.next_bw(),
430///     Some((Bandwidth::from_mbps(24), Duration::from_secs(1)))
431/// );
432/// assert_eq!(
433///     model.next_bw(),
434///     Some((Bandwidth::from_mbps(12), Duration::from_secs(1)))
435/// );
436/// assert_eq!(
437///     model.next_bw(),
438///     Some((Bandwidth::from_mbps(24), Duration::from_secs(1)))
439/// );
440/// assert_eq!(model.next_bw(), None);
441/// ```
442///
443/// You can also build manually:
444///
445/// ```
446/// # use netem_trace::model::{StaticBwConfig, BwTraceConfig, RepeatedBwPatternConfig};
447/// # use netem_trace::{Bandwidth, Duration, BwTrace};
448/// let pat = vec![
449///     Box::new(
450///         StaticBwConfig::new()
451///             .bw(Bandwidth::from_mbps(12))
452///             .duration(Duration::from_secs(1)),
453///     ) as Box<dyn BwTraceConfig>,
454///     Box::new(
455///         StaticBwConfig::new()
456///             .bw(Bandwidth::from_mbps(24))
457///             .duration(Duration::from_secs(1)),
458///     ) as Box<dyn BwTraceConfig>,
459/// ];
460/// let ser = Box::new(RepeatedBwPatternConfig::new().pattern(pat).count(2)) as Box<dyn BwTraceConfig>;
461/// let ser_str = serde_json::to_string(&ser).unwrap();
462/// # #[cfg(feature = "human")]
463/// # let json_str = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":\"12Mbps\",\"duration\":\"1s\"}},{\"StaticBwConfig\":{\"bw\":\"24Mbps\",\"duration\":\"1s\"}}],\"count\":2}}";
464/// // The json string would be "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":12000000},\"duration\":{\"secs\":1,\"nanos\":0}}},{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":24000000},\"duration\":{\"secs\":1,\"nanos\":0}}}],\"count\":2}}"
465/// // if the `human` feature is not enabled.
466/// # #[cfg(not(feature = "human"))]
467/// let json_str = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":12000000},\"duration\":{\"secs\":1,\"nanos\":0}}},{\"StaticBwConfig\":{\"bw\":{\"gbps\":0,\"bps\":24000000},\"duration\":{\"secs\":1,\"nanos\":0}}}],\"count\":2}}";
468/// assert_eq!(ser_str, json_str);
469/// ```
470pub struct RepeatedBwPattern {
471    pub pattern: Vec<Box<dyn BwTraceConfig>>,
472    pub count: usize,
473    current_model: Option<Box<dyn BwTrace>>,
474    current_cycle: usize,
475    current_pattern: usize,
476}
477
478/// The configuration struct for [`RepeatedBwPattern`].
479///
480/// See [`RepeatedBwPattern`] for more details.
481#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
482#[derive(Default, Clone)]
483pub struct RepeatedBwPatternConfig {
484    pub pattern: Vec<Box<dyn BwTraceConfig>>,
485    pub count: usize,
486}
487
488/// This model is used to enable a more compact trace.
489/// It replays the bandwidth changes according to a trace file,
490/// and is necessary for replaying sampled traces from Internet or production.
491///
492/// ## Examples
493///
494/// ```
495/// # use netem_trace::model::TraceBwConfig;
496/// # use netem_trace::{Bandwidth, Duration, BwTrace};
497/// use crate::netem_trace::model::Forever;
498/// use netem_trace::model::BwTraceConfig;
499///
500/// let mut tracebw = TraceBwConfig::new().pattern(
501///     vec![
502///         (Duration::from_millis(1), vec![Bandwidth::from_mbps(2),Bandwidth::from_mbps(4),]),
503///         (Duration::from_millis(2), vec![Bandwidth::from_mbps(1)]),
504///        ]
505/// ).build();
506///
507/// assert_eq!(tracebw.next_bw(), Some((Bandwidth::from_mbps(2), Duration::from_millis(1))));
508/// assert_eq!(tracebw.next_bw(), Some((Bandwidth::from_mbps(4), Duration::from_millis(1))));
509/// assert_eq!(tracebw.next_bw(), Some((Bandwidth::from_mbps(1), Duration::from_millis(2))));
510/// assert_eq!(tracebw.next_bw(), None);
511/// assert_eq!(tracebw.next_bw(), None);
512/// assert_eq!(tracebw.next_bw(), None);
513///
514/// let repeated_tracebw_config = TraceBwConfig::new().pattern(
515///     vec![
516///         (Duration::from_millis(1), vec![Bandwidth::from_mbps(2),Bandwidth::from_mbps(4),]),
517///         (Duration::from_millis(2), vec![Bandwidth::from_mbps(1)]),
518///        ]
519/// ).forever();
520///
521/// let mut repeated_tracebw = repeated_tracebw_config.clone().build();
522///
523/// assert_eq!(repeated_tracebw.next_bw(), Some((Bandwidth::from_mbps(2), Duration::from_millis(1))));
524/// assert_eq!(repeated_tracebw.next_bw(), Some((Bandwidth::from_mbps(4), Duration::from_millis(1))));
525/// assert_eq!(repeated_tracebw.next_bw(), Some((Bandwidth::from_mbps(1), Duration::from_millis(2))));
526///
527/// assert_eq!(repeated_tracebw.next_bw(), Some((Bandwidth::from_mbps(2), Duration::from_millis(1))));
528/// assert_eq!(repeated_tracebw.next_bw(), Some((Bandwidth::from_mbps(4), Duration::from_millis(1))));
529/// assert_eq!(repeated_tracebw.next_bw(), Some((Bandwidth::from_mbps(1), Duration::from_millis(2))));
530///
531/// assert_eq!(repeated_tracebw.next_bw(), Some((Bandwidth::from_mbps(2), Duration::from_millis(1))));
532/// assert_eq!(repeated_tracebw.next_bw(), Some((Bandwidth::from_mbps(4), Duration::from_millis(1))));
533/// assert_eq!(repeated_tracebw.next_bw(), Some((Bandwidth::from_mbps(1), Duration::from_millis(2))));
534///
535/// let ser : Box<dyn BwTraceConfig> = Box::new(repeated_tracebw_config);
536/// let ser_str = serde_json::to_string(&ser).unwrap();
537///
538/// # #[cfg(feature = "human")]
539/// let json_str = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"TraceBwConfig\":{\"pattern\":[[\"1ms\",[\"2Mbps\",\"4Mbps\"]],[\"2ms\",[\"1Mbps\"]]]}}],\"count\":0}}";
540/// // The json string would be "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"TraceBwConfig\":{\"pattern\":[[{\"secs\":0,\"nanos\":1000000},[{\"gbps\":0,\"bps\":2000000},{\"gbps\":0,\"bps\":4000000}]],[{\"secs\":0,\"nanos\":2000000},[{\"gbps\":0,\"bps\":1000000}]]]}}],\"count\":0}}"
541/// // if the `human` feature is not enabled.
542/// #[cfg(not(feature = "human"))]
543/// let json_str = "{\"RepeatedBwPatternConfig\":{\"pattern\":[{\"TraceBwConfig\":{\"pattern\":[[{\"secs\":0,\"nanos\":1000000},[{\"gbps\":0,\"bps\":2000000},{\"gbps\":0,\"bps\":4000000}]],[{\"secs\":0,\"nanos\":2000000},[{\"gbps\":0,\"bps\":1000000}]]]}}],\"count\":0}}";
544/// assert_eq!(ser_str, json_str);
545///
546/// let des: Box<dyn BwTraceConfig> = serde_json::from_str(json_str).unwrap();
547/// let mut model = des.into_model();
548///
549/// assert_eq!(model.next_bw(), Some((Bandwidth::from_mbps(2), Duration::from_millis(1))));
550/// assert_eq!(model.next_bw(), Some((Bandwidth::from_mbps(4), Duration::from_millis(1))));
551/// assert_eq!(model.next_bw(), Some((Bandwidth::from_mbps(1), Duration::from_millis(2))));
552///
553/// assert_eq!(model.next_bw(), Some((Bandwidth::from_mbps(2), Duration::from_millis(1))));
554/// assert_eq!(model.next_bw(), Some((Bandwidth::from_mbps(4), Duration::from_millis(1))));
555/// assert_eq!(model.next_bw(), Some((Bandwidth::from_mbps(1), Duration::from_millis(2))));
556/// ```
557pub struct TraceBw {
558    pub pattern: Vec<(Duration, Vec<Bandwidth>)>, // inner vector is never empty
559    pub outer_index: usize,
560    pub inner_index: usize,
561}
562
563/// The configuration struct for [`TraceBw`].
564///
565/// See [`TraceBw`] for more details.
566///
567#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
568#[derive(Debug, Clone, Default)]
569pub struct TraceBwConfig {
570    #[cfg_attr(
571        all(feature = "serde", feature = "human"),
572        serde(with = "tracebw_serde")
573    )]
574    pub pattern: Vec<(Duration, Vec<Bandwidth>)>,
575}
576
577impl TraceBwConfig {
578    pub fn new() -> Self {
579        Self { pattern: vec![] }
580    }
581
582    pub fn pattern(mut self, pattern: Vec<(Duration, Vec<Bandwidth>)>) -> Self {
583        self.pattern = pattern;
584        self
585    }
586
587    pub fn build(self) -> TraceBw {
588        TraceBw {
589            pattern: self
590                .pattern
591                .into_iter()
592                .filter(|(_, bandwidths)| !bandwidths.is_empty())
593                .collect(),
594            outer_index: 0,
595            inner_index: 0,
596        }
597    }
598}
599
600#[cfg(all(feature = "serde", feature = "human"))]
601mod tracebw_serde {
602    use super::*;
603    use serde::ser::SerializeSeq;
604    use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
605    use std::fmt;
606    use std::ops::{Deref, DerefMut};
607    /// Deserializes a `Bandwidth` in human-readable format.
608    ///
609    /// This function can be used with `serde_derive`'s `with` and
610    /// `deserialize_with` annotations.
611    pub fn deserialize<'a, T, D>(d: D) -> Result<T, D::Error>
612    where
613        Serde<T>: Deserialize<'a>,
614        D: Deserializer<'a>,
615    {
616        Serde::deserialize(d).map(Serde::into_inner)
617    }
618
619    /// Serializes a `Bandwidth` in human-readable format.
620    ///
621    /// This function can be used with `serde_derive`'s `with` and
622    /// `serialize_with` annotations.
623    pub fn serialize<T, S>(d: &T, s: S) -> Result<S::Ok, S::Error>
624    where
625        for<'a> Serde<&'a T>: Serialize,
626        S: Serializer,
627    {
628        Serde::from(d).serialize(s)
629    }
630
631    /// A wrapper type which implements `Serialize` and `Deserialize` for
632    /// types involving `Bandwidth`.
633    #[derive(Copy, Clone, Eq, Hash, PartialEq)]
634    pub struct Serde<T>(T);
635
636    impl<T> fmt::Debug for Serde<T>
637    where
638        T: fmt::Debug,
639    {
640        fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
641            self.0.fmt(formatter)
642        }
643    }
644
645    impl<T> Deref for Serde<T> {
646        type Target = T;
647
648        fn deref(&self) -> &T {
649            &self.0
650        }
651    }
652
653    impl<T> DerefMut for Serde<T> {
654        fn deref_mut(&mut self) -> &mut T {
655            &mut self.0
656        }
657    }
658
659    impl<T> Serde<T> {
660        /// Consumes the `De`, returning the inner value.
661        pub fn into_inner(self) -> T {
662            self.0
663        }
664    }
665
666    impl<T> From<T> for Serde<T> {
667        fn from(val: T) -> Serde<T> {
668            Serde(val)
669        }
670    }
671
672    impl<'de> Deserialize<'de> for Serde<Vec<(Duration, Vec<Bandwidth>)>> {
673        fn deserialize<D>(d: D) -> Result<Serde<Vec<(Duration, Vec<Bandwidth>)>>, D::Error>
674        where
675            D: Deserializer<'de>,
676        {
677            struct V;
678
679            impl<'de> de::Visitor<'de> for V {
680                type Value = Vec<(Duration, Vec<Bandwidth>)>;
681
682                fn expecting(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
683                    fmt.write_str("a sequence of [str, [str, str, ...]]")
684                }
685
686                fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
687                where
688                    A: serde::de::SeqAccess<'de>,
689                {
690                    let mut pattern = Vec::with_capacity(seq.size_hint().unwrap_or(0));
691
692                    while let Some((duration_str, bandwidths_str)) =
693                        seq.next_element::<(String, Vec<String>)>()?
694                    {
695                        let duration =
696                            humantime_serde::re::humantime::parse_duration(duration_str.as_str())
697                                .map_err(|e| {
698                                serde::de::Error::custom(format!(
699                                    "Failed to parse duration '{}': {}",
700                                    duration_str, e
701                                ))
702                            })?;
703
704                        let bandwidths = bandwidths_str
705                            .into_iter()
706                            .map(|b| {
707                                human_bandwidth::parse_bandwidth(&b).map_err(|e| {
708                                    serde::de::Error::custom(format!(
709                                        "Failed to parse bandwidth '{}': {}",
710                                        b, e
711                                    ))
712                                })
713                            })
714                            .collect::<Result<Vec<_>, _>>()?;
715                        pattern.push((duration, bandwidths));
716                    }
717                    Ok(pattern)
718                }
719            }
720
721            d.deserialize_seq(V).map(Serde)
722        }
723    }
724
725    impl ser::Serialize for Serde<Vec<(Duration, Vec<Bandwidth>)>> {
726        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
727        where
728            S: ser::Serializer,
729        {
730            let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
731            for (duration, bandwidths) in &self.0 {
732                let time = humantime_serde::re::humantime::format_duration(*duration).to_string();
733                let bandwidths = bandwidths
734                    .iter()
735                    .map(|item| human_bandwidth::format_bandwidth(*item).to_string())
736                    .collect::<Vec<_>>();
737                seq.serialize_element(&(time, bandwidths))?;
738            }
739            seq.end()
740        }
741    }
742
743    impl ser::Serialize for Serde<&Vec<(Duration, Vec<Bandwidth>)>> {
744        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
745        where
746            S: ser::Serializer,
747        {
748            let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
749            for (duration, bandwidths) in self.0 {
750                let time = humantime_serde::re::humantime::format_duration(*duration).to_string();
751                let bandwidths = bandwidths
752                    .iter()
753                    .map(|item| human_bandwidth::format_bandwidth(*item).to_string())
754                    .collect::<Vec<_>>();
755                seq.serialize_element(&(time, bandwidths))?;
756            }
757            seq.end()
758        }
759    }
760}
761
762impl BwTrace for StaticBw {
763    fn next_bw(&mut self) -> Option<(Bandwidth, Duration)> {
764        if let Some(duration) = self.duration.take() {
765            if duration.is_zero() {
766                None
767            } else {
768                Some((self.bw, duration))
769            }
770        } else {
771            None
772        }
773    }
774}
775
776impl<Rng: RngCore + Send> BwTrace for NormalizedBw<Rng> {
777    fn next_bw(&mut self) -> Option<(Bandwidth, Duration)> {
778        if self.duration.is_zero() {
779            None
780        } else {
781            let bw = self.sample() as u64;
782            let mut bw = Bandwidth::from_bps(bw);
783            if let Some(lower_bound) = self.lower_bound {
784                bw = bw.max(lower_bound);
785            }
786            if let Some(upper_bound) = self.upper_bound {
787                bw = bw.min(upper_bound);
788            }
789            let duration = self.step.min(self.duration);
790            self.duration -= duration;
791            Some((bw, duration))
792        }
793    }
794}
795
796impl<Rng: RngCore + Send> BwTrace for SawtoothBw<Rng> {
797    fn next_bw(&mut self) -> Option<(Bandwidth, Duration)> {
798        if self.duration.is_zero() {
799            None
800        } else {
801            let current = self.current.as_secs_f64();
802            let change_point = self.interval.as_secs_f64() * self.duty_ratio;
803            let base_bw = if current < change_point {
804                let ratio = current / change_point;
805                self.bottom + (self.top - self.bottom).mul_f64(ratio)
806            } else {
807                let ratio = (current - change_point) / (self.interval.as_secs_f64() - change_point);
808                self.top - (self.top - self.bottom).mul_f64(ratio)
809            };
810            let mut offset = self.noise.sample(&mut self.rng);
811            if let Some(upper_noise_bound) = self.upper_noise_bound {
812                offset = offset.min(upper_noise_bound.as_bps() as f64);
813            }
814            if let Some(lower_noise_bound) = self.lower_noise_bound {
815                offset = offset.max(-(lower_noise_bound.as_bps() as f64));
816            }
817            let bw = Bandwidth::from_bps((base_bw.as_bps() as f64 + offset) as u64);
818            let duration = self.step.min(self.duration);
819            self.duration -= duration;
820            self.current += duration;
821            if self.current >= self.interval {
822                self.current -= self.interval;
823            }
824            Some((bw, duration))
825        }
826    }
827}
828
829impl BwTrace for RepeatedBwPattern {
830    fn next_bw(&mut self) -> Option<(Bandwidth, Duration)> {
831        if self.pattern.is_empty() || (self.count != 0 && self.current_cycle >= self.count) {
832            None
833        } else {
834            if self.current_model.is_none() {
835                self.current_model = Some(self.pattern[self.current_pattern].clone().into_model());
836            }
837            match self.current_model.as_mut().unwrap().next_bw() {
838                Some(bw) => Some(bw),
839                None => {
840                    self.current_model = None;
841                    self.current_pattern += 1;
842                    if self.current_pattern >= self.pattern.len() {
843                        self.current_pattern = 0;
844                        self.current_cycle += 1;
845                        if self.count != 0 && self.current_cycle >= self.count {
846                            return None;
847                        }
848                    }
849                    self.next_bw()
850                }
851            }
852        }
853    }
854}
855
856impl BwTrace for TraceBw {
857    fn next_bw(&mut self) -> Option<(Bandwidth, Duration)> {
858        let result = self
859            .pattern
860            .get(self.outer_index)
861            .and_then(|(duration, bandwidth)| {
862                bandwidth
863                    .get(self.inner_index)
864                    .map(|bandwidth| (*bandwidth, *duration))
865            });
866        if result.is_some() {
867            if self.pattern[self.outer_index].1.len() > self.inner_index + 1 {
868                self.inner_index += 1;
869            } else {
870                self.outer_index += 1;
871                self.inner_index = 0;
872            }
873        }
874        result
875    }
876}
877
878impl<Rng: RngCore> NormalizedBw<Rng> {
879    pub fn sample(&mut self) -> f64 {
880        self.normal.sample(&mut self.rng)
881    }
882}
883
884impl StaticBwConfig {
885    pub fn new() -> Self {
886        Self {
887            bw: None,
888            duration: None,
889        }
890    }
891
892    pub fn bw(mut self, bw: Bandwidth) -> Self {
893        self.bw = Some(bw);
894        self
895    }
896
897    pub fn duration(mut self, duration: Duration) -> Self {
898        self.duration = Some(duration);
899        self
900    }
901
902    pub fn build(self) -> StaticBw {
903        StaticBw {
904            bw: self.bw.unwrap_or_else(|| Bandwidth::from_mbps(12)),
905            duration: Some(self.duration.unwrap_or_else(|| Duration::from_secs(1))),
906        }
907    }
908}
909
910/// Convert a bandwidth to bps as u64 with saturating operation.
911macro_rules! saturating_bandwidth_as_bps_u64 {
912    ($bw:expr) => {
913        $bw.as_gbps()
914            .saturating_mul(1_000_000_000)
915            .saturating_add($bw.subgbps_bps() as u64)
916    };
917}
918
919impl NormalizedBwConfig {
920    /// Creates an uninitialized config
921    pub fn new() -> Self {
922        Self {
923            mean: None,
924            std_dev: None,
925            upper_bound: None,
926            lower_bound: None,
927            duration: None,
928            step: None,
929            seed: None,
930        }
931    }
932
933    /// Sets the mean
934    ///
935    /// If the mean is not set, 12Mbps will be used.
936    pub fn mean(mut self, mean: Bandwidth) -> Self {
937        self.mean = Some(mean);
938        self
939    }
940
941    /// Sets the standard deviation
942    ///
943    /// If the standard deviation is not set, 0Mbps will be used.
944    pub fn std_dev(mut self, std_dev: Bandwidth) -> Self {
945        self.std_dev = Some(std_dev);
946        self
947    }
948
949    /// Sets the upper bound
950    ///
951    /// If the upper bound is not set, the upper bound will be the one of [`Bandwidth`].
952    pub fn upper_bound(mut self, upper_bound: Bandwidth) -> Self {
953        self.upper_bound = Some(upper_bound);
954        self
955    }
956
957    /// Sets the lower bound
958    ///
959    /// If the lower bound is not set, the lower bound will be the one of [`Bandwidth`].
960    pub fn lower_bound(mut self, lower_bound: Bandwidth) -> Self {
961        self.lower_bound = Some(lower_bound);
962        self
963    }
964
965    /// Sets the total duration of the trace
966    ///
967    /// If the total duration is not set, 1 second will be used.
968    pub fn duration(mut self, duration: Duration) -> Self {
969        self.duration = Some(duration);
970        self
971    }
972
973    /// Sets the duration of each value
974    ///
975    /// If the step is not set, 1ms will be used.
976    pub fn step(mut self, step: Duration) -> Self {
977        self.step = Some(step);
978        self
979    }
980
981    /// Set the seed for a random generator
982    ///
983    /// If the seed is not set, `42` will be used.
984    pub fn seed(mut self, seed: u64) -> Self {
985        self.seed = Some(seed);
986        self
987    }
988
989    /// Allows to use a randomly generated seed
990    ///
991    /// This is equivalent to: `self.seed(rand::random())`
992    pub fn random_seed(mut self) -> Self {
993        self.seed = Some(rand::random());
994        self
995    }
996
997    /// Creates a new [`NormalizedBw`] corresponding to this config.
998    ///
999    /// The created model will use [`StdRng`] as source of randomness (the call is equivalent to `self.build_with_rng::<StdRng>()`).
1000    /// It should be sufficient for most cases, but [`StdRng`] is not a portable random number generator,
1001    /// so one may want to use a portable random number generator like [`ChaCha`](https://crates.io/crates/rand_chacha),
1002    /// to this end one can use [`build_with_rng`](Self::build_with_rng).
1003    pub fn build(self) -> NormalizedBw {
1004        self.build_with_rng()
1005    }
1006
1007    /// Creates a new [`NormalizedBw`] corresponding to this config.
1008    ///
1009    /// Unlike [`build`](Self::build), this method let you choose the random generator.
1010    ///
1011    /// # Example
1012    /// ```rust
1013    /// # use netem_trace::model::NormalizedBwConfig;
1014    /// # use netem_trace::{Bandwidth, BwTrace};
1015    /// # use std::time::Duration;
1016    /// # use rand::rngs::StdRng;
1017    /// # use rand_chacha::ChaCha20Rng;
1018    ///
1019    /// let normal_bw = NormalizedBwConfig::new()
1020    ///     .mean(Bandwidth::from_mbps(12))
1021    ///     .std_dev(Bandwidth::from_mbps(1))
1022    ///     .duration(Duration::from_millis(3))
1023    ///     .seed(42);
1024    ///
1025    /// let mut default_build = normal_bw.clone().build();
1026    /// let mut std_build = normal_bw.clone().build_with_rng::<StdRng>();
1027    /// // ChaCha is deterministic and portable, unlike StdRng
1028    /// let mut chacha_build = normal_bw.clone().build_with_rng::<ChaCha20Rng>();
1029    ///
1030    /// for cha in [12044676, 11754367, 11253775] {
1031    ///     let default = default_build.next_bw();
1032    ///     let std = std_build.next_bw();
1033    ///     let chacha = chacha_build.next_bw();
1034    ///
1035    ///     assert!(default.is_some());
1036    ///     assert_eq!(default, std);
1037    ///     assert_ne!(default, chacha);
1038    ///     assert_eq!(chacha, Some((Bandwidth::from_bps(cha), Duration::from_millis(1))));
1039    /// }
1040    ///
1041    /// assert_eq!(default_build.next_bw(), None);
1042    /// assert_eq!(std_build.next_bw(), None);
1043    /// assert_eq!(chacha_build.next_bw(), None);
1044    /// ```
1045    pub fn build_with_rng<Rng: SeedableRng + RngCore>(self) -> NormalizedBw<Rng> {
1046        let mean = self.mean.unwrap_or_else(|| Bandwidth::from_mbps(12));
1047        let std_dev = self.std_dev.unwrap_or_else(|| Bandwidth::from_mbps(0));
1048        let upper_bound = self.upper_bound;
1049        let lower_bound = self.lower_bound;
1050        let duration = self.duration.unwrap_or_else(|| Duration::from_secs(1));
1051        let step = self.step.unwrap_or_else(|| Duration::from_millis(1));
1052        let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
1053        let rng = Rng::seed_from_u64(seed);
1054        let bw_mean = saturating_bandwidth_as_bps_u64!(mean) as f64;
1055        let bw_std_dev = saturating_bandwidth_as_bps_u64!(std_dev) as f64;
1056        let normal: Normal<f64> = Normal::new(bw_mean, bw_std_dev).unwrap();
1057        NormalizedBw {
1058            mean,
1059            std_dev,
1060            upper_bound,
1061            lower_bound,
1062            duration,
1063            step,
1064            seed,
1065            rng,
1066            normal,
1067        }
1068    }
1069}
1070
1071#[cfg(feature = "truncated-normal")]
1072impl NormalizedBwConfig {
1073    /// This is another implementation for converting NormalizedBwConfig into NormalizedBw, where the impact
1074    /// of truncation (`lower_bound` and `upper_bound` field) on the mathematical expectation of the distribution
1075    /// is taking account by modifying the center of the distribution.
1076    ///
1077    /// ## Examples
1078    ///
1079    /// ```
1080    ///
1081    /// # use netem_trace::model::NormalizedBwConfig;
1082    /// # use netem_trace::{Bandwidth, Duration, BwTrace};
1083    /// # use crate::netem_trace::model::Forever;
1084    /// let normal_bw = NormalizedBwConfig::new()
1085    ///     .mean(Bandwidth::from_mbps(12))
1086    ///     .std_dev(Bandwidth::from_mbps(12))
1087    ///     .duration(Duration::from_secs(100))
1088    ///     .step(Duration::from_millis(1))
1089    ///     .seed(42);
1090    ///
1091    /// let mut default_build = normal_bw.clone().build();
1092    /// let mut truncate_build = normal_bw.clone().build_truncated();
1093    ///
1094    /// fn avg_mbps(mut model: impl BwTrace) -> f64{
1095    ///     let mut count = 0;
1096    ///     std::iter::from_fn( move ||{
1097    ///         model.next_bw().map(|b| b.0.as_gbps_f64() * 1000.0)
1098    ///     }).inspect(|_| count += 1).sum::<f64>() / count as f64
1099    /// }
1100    ///
1101    /// assert_eq!(avg_mbps(default_build), 12.974758080079994); // significantly higher than the expected mean
1102    /// assert_eq!(avg_mbps(truncate_build), 11.97642456625989);
1103    ///
1104    /// let normal_bw = NormalizedBwConfig::new()
1105    ///     .mean(Bandwidth::from_mbps(12))
1106    ///     .std_dev(Bandwidth::from_mbps(12))
1107    ///     .duration(Duration::from_secs(100))
1108    ///     .lower_bound(Bandwidth::from_mbps(8))
1109    ///     .upper_bound(Bandwidth::from_mbps(20))
1110    ///     .step(Duration::from_millis(1))
1111    ///     .seed(42);
1112    ///
1113    /// let mut default_build = normal_bw.clone().build();
1114    /// let mut truncate_build = normal_bw.clone().build_truncated();
1115    ///
1116    /// assert_eq!(avg_mbps(default_build),  13.221356471729928); // significantly higher than the expected mean
1117    /// assert_eq!(avg_mbps(truncate_build), 11.978819427569897);
1118    ///
1119    /// ```
1120    pub fn build_truncated(self) -> NormalizedBw {
1121        self.build_truncated_with_rng()
1122    }
1123
1124    /// Similar to [`build_truncated`](Self::build_truncated) but let you choose the random generator.
1125    ///
1126    /// See [`build`](Self::build) for details about the reason for using another random number generator than [`StdRng`].
1127    pub fn build_truncated_with_rng<Rng: SeedableRng + RngCore>(mut self) -> NormalizedBw<Rng> {
1128        let mean = self
1129            .mean
1130            .unwrap_or_else(|| Bandwidth::from_mbps(12))
1131            .as_gbps_f64();
1132        let sigma = self
1133            .std_dev
1134            .unwrap_or_else(|| Bandwidth::from_mbps(0))
1135            .as_gbps_f64()
1136            / mean;
1137        let lower = self
1138            .lower_bound
1139            .unwrap_or_else(|| Bandwidth::from_mbps(0))
1140            .as_gbps_f64()
1141            / mean;
1142        let upper = self.upper_bound.map(|upper| upper.as_gbps_f64() / mean);
1143        let new_mean = mean * solve(1f64, sigma, Some(lower), upper).unwrap_or(1f64);
1144        self.mean = Some(Bandwidth::from_gbps_f64(new_mean));
1145        self.build_with_rng()
1146    }
1147}
1148
1149impl SawtoothBwConfig {
1150    /// Creates an uninitialized config
1151    pub fn new() -> Self {
1152        Self {
1153            bottom: None,
1154            top: None,
1155            interval: None,
1156            duty_ratio: None,
1157            duration: None,
1158            step: None,
1159            seed: None,
1160            std_dev: None,
1161            upper_noise_bound: None,
1162            lower_noise_bound: None,
1163        }
1164    }
1165
1166    pub fn bottom(mut self, bottom: Bandwidth) -> Self {
1167        self.bottom = Some(bottom);
1168        self
1169    }
1170
1171    pub fn top(mut self, top: Bandwidth) -> Self {
1172        self.top = Some(top);
1173        self
1174    }
1175
1176    pub fn interval(mut self, interval: Duration) -> Self {
1177        self.interval = Some(interval);
1178        self
1179    }
1180
1181    pub fn duty_ratio(mut self, duty_ratio: f64) -> Self {
1182        self.duty_ratio = Some(duty_ratio);
1183        self
1184    }
1185
1186    /// Sets the total duration of the trace
1187    ///
1188    /// If the total duration is not set, 1 second will be used.
1189    pub fn duration(mut self, duration: Duration) -> Self {
1190        self.duration = Some(duration);
1191        self
1192    }
1193
1194    /// Sets the duration of each value
1195    ///
1196    /// If the step is not set, 1ms will be used.
1197    pub fn step(mut self, step: Duration) -> Self {
1198        self.step = Some(step);
1199        self
1200    }
1201
1202    /// Set the seed for a random generator
1203    ///
1204    /// If the seed is not set, `42` will be used.
1205    pub fn seed(mut self, seed: u64) -> Self {
1206        self.seed = Some(seed);
1207        self
1208    }
1209
1210    /// Allows to use a randomly generated seed
1211    ///
1212    /// This is equivalent to: `self.seed(rand::random())`
1213    pub fn random_seed(mut self) -> Self {
1214        self.seed = Some(rand::random());
1215        self
1216    }
1217
1218    /// Sets the standard deviation
1219    ///
1220    /// If the standard deviation is not set, 0Mbps will be used.
1221    pub fn std_dev(mut self, std_dev: Bandwidth) -> Self {
1222        self.std_dev = Some(std_dev);
1223        self
1224    }
1225
1226    pub fn upper_noise_bound(mut self, upper_noise_bound: Bandwidth) -> Self {
1227        self.upper_noise_bound = Some(upper_noise_bound);
1228        self
1229    }
1230
1231    pub fn lower_noise_bound(mut self, lower_noise_bound: Bandwidth) -> Self {
1232        self.lower_noise_bound = Some(lower_noise_bound);
1233        self
1234    }
1235
1236    /// Creates a new [`SawtoothBw`] corresponding to this config.
1237    ///
1238    /// The created model will use [`StdRng`] as source of randomness (the call is equivalent to `self.build_with_rng::<StdRng>()`).
1239    /// It should be sufficient for most cases, but [`StdRng`] is not a portable random number generator,
1240    /// so one may want to use a portable random number generator like [`ChaCha`](https://crates.io/crates/rand_chacha),
1241    /// to this end one can use [`build_with_rng`](Self::build_with_rng).
1242    pub fn build(self) -> SawtoothBw {
1243        self.build_with_rng()
1244    }
1245
1246    /// Creates a new [`SawtoothBw`] corresponding to this config.
1247    ///
1248    /// Unlike [`build`](Self::build), this method let you choose the random generator.
1249    ///
1250    /// # Example
1251    /// ```rust
1252    /// # use netem_trace::model::SawtoothBwConfig;
1253    /// # use netem_trace::{Bandwidth, BwTrace};
1254    /// # use std::time::Duration;
1255    /// # use rand::rngs::StdRng;
1256    /// # use rand_chacha::ChaCha20Rng;
1257    ///
1258    /// let sawtooth_bw = SawtoothBwConfig::new()
1259    ///     .bottom(Bandwidth::from_mbps(12))
1260    ///     .top(Bandwidth::from_mbps(16))
1261    ///     .std_dev(Bandwidth::from_mbps(1))
1262    ///     .duration(Duration::from_millis(3))
1263    ///     .interval(Duration::from_millis(5))
1264    ///     .duty_ratio(0.8)
1265    ///     .seed(42);
1266    ///
1267    /// let mut default_build = sawtooth_bw.clone().build();
1268    /// let mut std_build = sawtooth_bw.clone().build_with_rng::<StdRng>();
1269    /// // ChaCha is deterministic and portable, unlike StdRng
1270    /// let mut chacha_build = sawtooth_bw.clone().build_with_rng::<ChaCha20Rng>();
1271    ///
1272    /// for cha in [12044676, 12754367, 13253775] {
1273    ///     let default = default_build.next_bw();
1274    ///     let std = std_build.next_bw();
1275    ///     let chacha = chacha_build.next_bw();
1276    ///
1277    ///     assert!(default.is_some());
1278    ///     assert_eq!(default, std);
1279    ///     assert_ne!(default, chacha);
1280    ///     assert_eq!(chacha, Some((Bandwidth::from_bps(cha), Duration::from_millis(1))));
1281    /// }
1282    ///
1283    /// assert_eq!(default_build.next_bw(), None);
1284    /// assert_eq!(std_build.next_bw(), None);
1285    /// assert_eq!(chacha_build.next_bw(), None);
1286    /// ```
1287    pub fn build_with_rng<Rng: RngCore + SeedableRng>(self) -> SawtoothBw<Rng> {
1288        let bottom = self.bottom.unwrap_or_else(|| Bandwidth::from_mbps(0));
1289        let top = self.top.unwrap_or_else(|| Bandwidth::from_mbps(12));
1290        if bottom > top {
1291            panic!("SawtoothBw: bottom bw must be less than top bw");
1292        }
1293        let interval = self.interval.unwrap_or_else(|| Duration::from_secs(1));
1294        let duty_ratio = self.duty_ratio.unwrap_or(0.5);
1295        let duration = self.duration.unwrap_or_else(|| Duration::from_secs(1));
1296        let step = self.step.unwrap_or_else(|| Duration::from_millis(1));
1297        let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
1298        let rng = Rng::seed_from_u64(seed);
1299        let std_dev = self.std_dev.unwrap_or_else(|| Bandwidth::from_mbps(0));
1300        let upper_noise_bound = self.upper_noise_bound;
1301        let lower_noise_bound = self.lower_noise_bound;
1302        let current = Duration::ZERO;
1303        let bw_std_dev = saturating_bandwidth_as_bps_u64!(std_dev) as f64;
1304        let noise: Normal<f64> = Normal::new(0.0, bw_std_dev).unwrap();
1305        SawtoothBw {
1306            bottom,
1307            top,
1308            interval,
1309            duty_ratio,
1310            duration,
1311            step,
1312            seed,
1313            std_dev,
1314            upper_noise_bound,
1315            lower_noise_bound,
1316            current,
1317            rng,
1318            noise,
1319        }
1320    }
1321}
1322
1323impl RepeatedBwPatternConfig {
1324    pub fn new() -> Self {
1325        Self {
1326            pattern: vec![],
1327            count: 0,
1328        }
1329    }
1330
1331    pub fn pattern(mut self, pattern: Vec<Box<dyn BwTraceConfig>>) -> Self {
1332        self.pattern = pattern;
1333        self
1334    }
1335
1336    pub fn count(mut self, count: usize) -> Self {
1337        self.count = count;
1338        self
1339    }
1340
1341    pub fn build(self) -> RepeatedBwPattern {
1342        RepeatedBwPattern {
1343            pattern: self.pattern,
1344            count: self.count,
1345            current_model: None,
1346            current_cycle: 0,
1347            current_pattern: 0,
1348        }
1349    }
1350}
1351
1352macro_rules! impl_bw_trace_config {
1353    ($name:ident) => {
1354        #[cfg_attr(feature = "serde", typetag::serde)]
1355        impl BwTraceConfig for $name {
1356            fn into_model(self: Box<$name>) -> Box<dyn BwTrace> {
1357                Box::new(self.build())
1358            }
1359        }
1360    };
1361}
1362
1363impl_bw_trace_config!(StaticBwConfig);
1364impl_bw_trace_config!(NormalizedBwConfig);
1365impl_bw_trace_config!(SawtoothBwConfig);
1366impl_bw_trace_config!(RepeatedBwPatternConfig);
1367impl_bw_trace_config!(TraceBwConfig);
1368
1369/// Turn a [`BwTraceConfig`] into a forever repeated [`RepeatedBwPatternConfig`].
1370pub trait Forever: BwTraceConfig {
1371    fn forever(self) -> RepeatedBwPatternConfig;
1372}
1373
1374/// Implement the [`Forever`] trait for the bandwidth trace model config (any struct implements [`BwTraceConfig`]).
1375#[macro_export]
1376macro_rules! impl_forever {
1377    ($name:ident) => {
1378        impl Forever for $name {
1379            fn forever(self) -> RepeatedBwPatternConfig {
1380                RepeatedBwPatternConfig::new()
1381                    .pattern(vec![Box::new(self)])
1382                    .count(0)
1383            }
1384        }
1385    };
1386}
1387
1388impl_forever!(StaticBwConfig);
1389impl_forever!(NormalizedBwConfig);
1390impl_forever!(SawtoothBwConfig);
1391impl_forever!(TraceBwConfig);
1392
1393impl Forever for RepeatedBwPatternConfig {
1394    fn forever(self) -> RepeatedBwPatternConfig {
1395        self.count(0)
1396    }
1397}