netem_trace/model/
delay_per_packet.rs

1//! This module contains some predefined delay per-packet trace models.
2//!
3//! Enabled with feature `delay-per-packet-model` or `model`.
4//!
5//! ## Predefined models
6//!
7//! - [`StaticDelayPerPacket`]: A trace model with static delay.
8//! - [`RepeatedDelayPerPacketPattern`]: A trace model with a repeated delay pattern.
9//! - [`NormalizedDelayPerPacket`]: A trace model whose delay subjects to a normal distribution (can set upper and lower bounds, and can configure it to be truncated with `truncated-normal` feature enabled).
10//!
11//! ## Examples
12//!
13//! An example to build model from configuration:
14//!
15//! ```
16//! # use netem_trace::model::StaticDelayPerPacketConfig;
17//! # use netem_trace::{Delay, DelayPerPacketTrace};
18//! let mut static_delay = StaticDelayPerPacketConfig::new()
19//!     .delay(Delay::from_millis(10))
20//!     .count(2)
21//!     .build();
22//! assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
23//! assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
24//! assert_eq!(static_delay.next_delay(), 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::DelayPerPacketTraceConfig;
31//! # use netem_trace::{Delay, DelayPerPacketTrace};
32//! # #[cfg(feature = "human")]
33//! # let config_file_content = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
34//! // The content would be "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}"
35//! // if the `human` feature is not enabled.
36//! # #[cfg(not(feature = "human"))]
37//! let config_file_content = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
38//! let des: Box<dyn DelayPerPacketTraceConfig> = serde_json::from_str(config_file_content).unwrap();
39//! let mut model = des.into_model();
40//! assert_eq!(
41//!     model.next_delay(),
42//!     Some(Delay::from_millis(10))
43//! );
44//! assert_eq!(
45//!     model.next_delay(),
46//!     Some(Delay::from_millis(20))
47//! );
48//! assert_eq!(
49//!     model.next_delay(),
50//!     Some(Delay::from_millis(10))
51//! );
52//! assert_eq!(
53//!     model.next_delay(),
54//!     Some(Delay::from_millis(20))
55//! );
56//! assert_eq!(model.next_delay(), None);
57//! ```
58use crate::{Delay, DelayPerPacketTrace};
59use dyn_clone::DynClone;
60
61const DEFAULT_RNG_SEED: u64 = 42; // Some documentation will need corrections if this changes
62
63/// This trait is used to convert a per-packet delay trace configuration into a per-packet delay trace model.
64///
65/// Since trace model is often configured with files and often has inner states which
66/// is not suitable to be serialized/deserialized, this trait makes it possible to
67/// separate the configuration part into a simple struct for serialization/deserialization, and
68/// construct the model from the configuration.
69#[cfg_attr(feature = "serde", typetag::serde)]
70pub trait DelayPerPacketTraceConfig: DynClone + Send + std::fmt::Debug {
71    fn into_model(self: Box<Self>) -> Box<dyn DelayPerPacketTrace>;
72}
73
74dyn_clone::clone_trait_object!(DelayPerPacketTraceConfig);
75
76use rand::{rngs::StdRng, RngCore, SeedableRng};
77use rand_distr::{Distribution, LogNormal, Normal};
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 per-packet delay trace.
85///
86/// This model always returns the same delay for the given amount of packets.
87///
88/// If the `count` is 0, the delay will be repeated forever.
89///
90/// ## Examples
91///
92/// ```
93/// # use netem_trace::model::StaticDelayPerPacketConfig;
94/// # use netem_trace::{Delay, DelayPerPacketTrace};
95/// let mut static_delay = StaticDelayPerPacketConfig::new()
96///     .delay(Delay::from_millis(10))
97///     .count(2)
98///     .build();
99/// assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
100/// assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
101/// assert_eq!(static_delay.next_delay(), None);
102/// ```
103#[derive(Default, Debug, Clone, Copy, PartialEq)]
104pub struct StaticDelayPerPacket {
105    pub delay: Delay,
106    pub count: usize,
107    current_count: usize,
108}
109
110/// The configuration struct for [`StaticDelayPerPacket`].
111///
112/// See [`StaticDelayPerPacket`] for more details.
113#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
114#[derive(Default, Debug, Clone, Copy, PartialEq)]
115pub struct StaticDelayPerPacketConfig {
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 delay: Option<Delay>,
122    pub count: usize,
123}
124
125/// The model contains an array of per-packet delay trace models.
126///
127/// Combine multiple per-packet delay trace models into one per-packet delay pattern,
128/// and repeat the pattern for `count` times.
129///
130/// If `count` is 0, the pattern will be repeated forever.
131///
132/// ## Examples
133///
134/// The most common use case is to read from a configuration file and
135/// deserialize it into a [`RepeatedDelayPerPacketPatternConfig`]:
136///
137/// ```
138/// use netem_trace::model::{StaticDelayPerPacketConfig, DelayPerPacketTraceConfig};
139/// use netem_trace::{Delay, DelayPerPacketTrace};
140/// #[cfg(feature = "human")]
141/// let config_file_content = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
142/// // The content would be "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}"
143/// // if the `human` feature is not enabled.
144/// #[cfg(not(feature = "human"))]
145/// let config_file_content = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
146/// let des: Box<dyn DelayPerPacketTraceConfig> = serde_json::from_str(config_file_content).unwrap();
147/// let mut model = des.into_model();
148/// assert_eq!(
149///     model.next_delay(),
150///     Some(Delay::from_millis(10))
151/// );
152/// assert_eq!(
153///     model.next_delay(),
154///     Some(Delay::from_millis(20))
155/// );
156/// assert_eq!(
157///     model.next_delay(),
158///     Some(Delay::from_millis(10))
159/// );
160/// assert_eq!(
161///     model.next_delay(),
162///     Some(Delay::from_millis(20))
163/// );
164/// assert_eq!(model.next_delay(), None);
165/// ```
166///
167/// You can also build manually:
168///
169/// ```
170/// # use netem_trace::model::{StaticDelayPerPacketConfig, DelayPerPacketTraceConfig, RepeatedDelayPerPacketPatternConfig};
171/// # use netem_trace::{Delay, DelayPerPacketTrace};
172/// let pat = vec![
173///     Box::new(
174///         StaticDelayPerPacketConfig::new()
175///             .delay(Delay::from_millis(10))
176///             .count(1),
177///     ) as Box<dyn DelayPerPacketTraceConfig>,
178///     Box::new(
179///         StaticDelayPerPacketConfig::new()
180///             .delay(Delay::from_millis(20))
181///             .count(1),
182///     ) as Box<dyn DelayPerPacketTraceConfig>,
183/// ];
184/// let ser = Box::new(RepeatedDelayPerPacketPatternConfig::new().pattern(pat).count(2)) as Box<dyn DelayPerPacketTraceConfig>;
185/// let ser_str = serde_json::to_string(&ser).unwrap();
186/// #[cfg(feature = "human")]
187/// let json_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
188/// // The content would be "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}"
189/// // if the `human` feature is not enabled.
190/// #[cfg(not(feature = "human"))]
191/// let json_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
192/// assert_eq!(ser_str, json_str);
193/// ```
194#[derive(Default)]
195pub struct RepeatedDelayPerPacketPattern {
196    pub pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>,
197    pub count: usize,
198    current_model: Option<Box<dyn DelayPerPacketTrace>>,
199    current_cycle: usize,
200    current_pattern: usize,
201}
202
203/// The configuration struct for [`RepeatedDelayPerPacketPattern`].
204///
205/// See [`RepeatedDelayPerPacketPattern`] for more details.
206#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
207#[derive(Default, Debug, Clone)]
208pub struct RepeatedDelayPerPacketPatternConfig {
209    pub pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>,
210    pub count: usize,
211}
212
213/// The model of a per-packet delay trace subjects to a normal distribution.
214///
215/// The delay will subject to N(mean, std_dev²), but bounded within [lower_bound, upper_bound] (optional)
216///
217/// If the `count` is 0, the delay will be repeated forever, else it will be repeated `count` times.
218///
219/// ## Examples
220///
221/// A simple example without any bound on delay:
222///
223/// ```
224/// # use netem_trace::model::NormalizedDelayPerPacketConfig;
225/// # use netem_trace::{Delay, DelayPerPacketTrace};
226/// let mut normal_delay = NormalizedDelayPerPacketConfig::new()
227///     .mean(Delay::from_millis(12))
228///     .std_dev(Delay::from_millis(1))
229///     .count(2)
230///     .seed(42)
231///     .build();
232/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12069428)));
233/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12132938)));
234/// assert_eq!(normal_delay.next_delay(), None);
235/// ```
236///
237/// A more complex example with bounds on delay:
238///
239/// ```
240/// # use netem_trace::model::NormalizedDelayPerPacketConfig;
241/// # use netem_trace::{Delay, DelayPerPacketTrace};
242/// let mut normal_delay = NormalizedDelayPerPacketConfig::new()
243///     .mean(Delay::from_millis(12))
244///     .std_dev(Delay::from_millis(1))
245///     .count(2)
246///     .seed(42)
247///     .upper_bound(Delay::from_micros(12100))
248///     .lower_bound(Delay::from_micros(11900))
249///     .build();
250/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12069428)));
251/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12100000)));
252/// assert_eq!(normal_delay.next_delay(), None);
253/// ```
254#[derive(Debug, Clone, Copy, PartialEq)]
255pub struct NormalizedDelayPerPacket<Rng = StdRng>
256where
257    Rng: RngCore,
258{
259    pub mean: Delay,
260    pub std_dev: Delay,
261    pub upper_bound: Option<Delay>,
262    pub lower_bound: Delay,
263    pub seed: u64,
264    pub count: usize,
265    current_count: usize,
266    rng: Rng,
267    normal: Normal<f64>,
268}
269
270/// The configuration struct for [`NormalizedDelayPerPacket`].
271///
272/// See [`NormalizedDelayPerPacket`] for more details.
273#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
274#[derive(Default, Debug, Clone, Copy, PartialEq)]
275pub struct NormalizedDelayPerPacketConfig {
276    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
277    #[cfg_attr(
278        all(feature = "serde", feature = "human"),
279        serde(with = "humantime_serde")
280    )]
281    pub mean: Option<Delay>,
282    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
283    #[cfg_attr(
284        all(feature = "serde", feature = "human"),
285        serde(with = "humantime_serde")
286    )]
287    pub std_dev: Option<Delay>,
288    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
289    #[cfg_attr(
290        all(feature = "serde", feature = "human"),
291        serde(with = "humantime_serde")
292    )]
293    pub upper_bound: Option<Delay>,
294    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
295    #[cfg_attr(
296        all(feature = "serde", feature = "human"),
297        serde(with = "humantime_serde")
298    )]
299    pub lower_bound: Option<Delay>,
300    #[cfg_attr(feature = "serde", serde(default))]
301    pub count: usize,
302    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
303    pub seed: Option<u64>,
304}
305/// The model of a per-packet delay trace subjects to a log-normal distribution.
306///
307/// The delay will subject to Lognormal(μ, σ²), but bounded within [lower_bound, upper_bound] (optional)
308/// The provided mean and std_dev are the one of the log-normal law and not the one of the underlying normal law.
309///
310/// If the `count` is 0, the delay will be repeated forever, else it will be repeated `count` times.
311///
312/// ## Examples
313///
314/// A simple example without any bound on delay:
315///
316/// ```
317/// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
318/// # use netem_trace::{Delay, DelayPerPacketTrace};
319/// let mut log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
320///     .mean(Delay::from_millis(12))
321///     .std_dev(Delay::from_millis(1))
322///     .count(2)
323///     .seed(42)
324///     .build();
325/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12027817)));
326/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12091533)));
327/// assert_eq!(log_normal_delay.next_delay(), None);
328/// ```
329///
330/// A more complex example with bounds on delay:
331///
332/// ```
333/// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
334/// # use netem_trace::{Delay, DelayPerPacketTrace};
335/// let mut log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
336///     .mean(Delay::from_millis(12))
337///     .std_dev(Delay::from_millis(1))
338///     .count(3)
339///     .seed(42)
340///     .upper_bound(Delay::from_micros(12100))
341///     .lower_bound(Delay::from_micros(11900))
342///     .build();
343/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12027817)));
344/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12091533)));
345/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12100000)));
346/// assert_eq!(log_normal_delay.next_delay(), None);
347/// ```
348#[derive(Debug, Clone, Copy, PartialEq)]
349pub struct LogNormalizedDelayPerPacket<Rng = StdRng>
350where
351    Rng: RngCore,
352{
353    pub mean: Delay,
354    pub std_dev: Delay,
355    pub upper_bound: Option<Delay>,
356    pub lower_bound: Delay,
357    pub seed: u64,
358    pub count: usize,
359    current_count: usize,
360    rng: Rng,
361    log_normal: LogNormal<f64>,
362}
363
364/// The configuration struct for [`LogNormalizedDelayPerPacket`].
365///
366/// See [`LogNormalizedDelayPerPacket`] for more details.
367#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
368#[derive(Default, Debug, Clone, Copy, PartialEq)]
369pub struct LogNormalizedDelayPerPacketConfig {
370    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
371    #[cfg_attr(
372        all(feature = "serde", feature = "human"),
373        serde(with = "humantime_serde")
374    )]
375    pub mean: Option<Delay>,
376    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
377    #[cfg_attr(
378        all(feature = "serde", feature = "human"),
379        serde(with = "humantime_serde")
380    )]
381    pub std_dev: Option<Delay>,
382    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
383    #[cfg_attr(
384        all(feature = "serde", feature = "human"),
385        serde(with = "humantime_serde")
386    )]
387    pub upper_bound: Option<Delay>,
388    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
389    #[cfg_attr(
390        all(feature = "serde", feature = "human"),
391        serde(with = "humantime_serde")
392    )]
393    pub lower_bound: Option<Delay>,
394    #[cfg_attr(feature = "serde", serde(default))]
395    pub count: usize,
396    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
397    pub seed: Option<u64>,
398}
399
400impl DelayPerPacketTrace for StaticDelayPerPacket {
401    fn next_delay(&mut self) -> Option<Delay> {
402        if self.count != 0 && self.count == self.current_count {
403            None
404        } else {
405            self.current_count += 1;
406            Some(self.delay)
407        }
408    }
409}
410
411impl DelayPerPacketTrace for RepeatedDelayPerPacketPattern {
412    fn next_delay(&mut self) -> Option<Delay> {
413        if self.pattern.is_empty() || (self.count != 0 && self.current_cycle >= self.count) {
414            None
415        } else {
416            if self.current_model.is_none() {
417                self.current_model = Some(self.pattern[self.current_pattern].clone().into_model());
418            }
419            match self.current_model.as_mut().unwrap().next_delay() {
420                Some(delay) => Some(delay),
421                None => {
422                    self.current_model = None;
423                    self.current_pattern += 1;
424                    if self.current_pattern >= self.pattern.len() {
425                        self.current_pattern = 0;
426                        self.current_cycle += 1;
427                        if self.count != 0 && self.current_cycle >= self.count {
428                            return None;
429                        }
430                    }
431                    self.next_delay()
432                }
433            }
434        }
435    }
436}
437
438impl<Rng: RngCore + Send> DelayPerPacketTrace for NormalizedDelayPerPacket<Rng> {
439    fn next_delay(&mut self) -> Option<Delay> {
440        if self.count != 0 && self.count == self.current_count {
441            None
442        } else {
443            self.current_count += 1;
444            let delay = self.normal.sample(&mut self.rng).max(0.0);
445            let mut delay = Delay::from_secs_f64(delay);
446            delay = delay.max(self.lower_bound);
447            if let Some(upper_bound) = self.upper_bound {
448                delay = delay.min(upper_bound);
449            }
450            Some(delay)
451        }
452    }
453}
454
455impl<Rng: RngCore + Send> DelayPerPacketTrace for LogNormalizedDelayPerPacket<Rng> {
456    fn next_delay(&mut self) -> Option<Delay> {
457        if self.count != 0 && self.count == self.current_count {
458            None
459        } else {
460            self.current_count += 1;
461            let delay = self.log_normal.sample(&mut self.rng).max(0.0);
462            let mut delay = Delay::from_secs_f64(delay);
463            delay = delay.max(self.lower_bound);
464            if let Some(upper_bound) = self.upper_bound {
465                delay = delay.min(upper_bound);
466            }
467            Some(delay)
468        }
469    }
470}
471
472impl StaticDelayPerPacketConfig {
473    pub fn new() -> Self {
474        Self {
475            delay: None,
476            count: 0,
477        }
478    }
479
480    pub fn delay(mut self, delay: Delay) -> Self {
481        self.delay = Some(delay);
482        self
483    }
484
485    pub fn count(mut self, count: usize) -> Self {
486        self.count = count;
487        self
488    }
489
490    pub fn build(self) -> StaticDelayPerPacket {
491        StaticDelayPerPacket {
492            delay: self.delay.unwrap_or_else(|| Delay::from_millis(10)),
493            count: self.count,
494            current_count: 0,
495        }
496    }
497}
498
499impl RepeatedDelayPerPacketPatternConfig {
500    pub fn new() -> Self {
501        Self {
502            pattern: vec![],
503            count: 0,
504        }
505    }
506
507    pub fn pattern(mut self, pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>) -> Self {
508        self.pattern = pattern;
509        self
510    }
511
512    pub fn count(mut self, count: usize) -> Self {
513        self.count = count;
514        self
515    }
516
517    pub fn build(self) -> RepeatedDelayPerPacketPattern {
518        RepeatedDelayPerPacketPattern {
519            pattern: self.pattern,
520            count: self.count,
521            current_model: None,
522            current_cycle: 0,
523            current_pattern: 0,
524        }
525    }
526}
527
528impl NormalizedDelayPerPacketConfig {
529    /// Creates an uninitialized config
530    pub fn new() -> Self {
531        Self {
532            mean: None,
533            std_dev: None,
534            upper_bound: None,
535            lower_bound: None,
536            count: 0,
537            seed: None,
538        }
539    }
540
541    /// Sets the mean
542    ///
543    /// If the mean is not set, 10ms will be used.
544    pub fn mean(mut self, mean: Delay) -> Self {
545        self.mean = Some(mean);
546        self
547    }
548
549    /// Sets the standard deviation
550    ///
551    /// If the standard deviation is not set, 0ms will be used.
552    pub fn std_dev(mut self, std_dev: Delay) -> Self {
553        self.std_dev = Some(std_dev);
554        self
555    }
556
557    /// Sets the upper bound
558    ///
559    /// If the upper bound is not set, the upper bound will be the one of [`Delay`].
560    pub fn upper_bound(mut self, upper_bound: Delay) -> Self {
561        self.upper_bound = Some(upper_bound);
562        self
563    }
564
565    /// Sets the lower bound
566    ///
567    /// If the lower bound is not set, 0ms will be used.
568    pub fn lower_bound(mut self, lower_bound: Delay) -> Self {
569        self.lower_bound = Some(lower_bound);
570        self
571    }
572
573    /// Sets the number of packets to repeat
574    ///
575    /// If the count is not set, it will be set to 0 (ie, infinite repeat).
576    pub fn count(mut self, count: usize) -> Self {
577        self.count = count;
578        self
579    }
580
581    /// Set the seed for a random generator
582    ///
583    /// If the seed is not set, `42` will be used.
584    pub fn seed(mut self, seed: u64) -> Self {
585        self.seed = Some(seed);
586        self
587    }
588
589    /// Allows to use a randomly generated seed
590    ///
591    /// This is equivalent to: `self.seed(rand::random())`
592    pub fn random_seed(mut self) -> Self {
593        self.seed = Some(rand::random());
594        self
595    }
596
597    /// Creates a new [`NormalizedDelayPerPacket`] corresponding to this config.
598    ///
599    /// The created model will use [`StdRng`] as source of randomness (the call is equivalent to `self.build_with_rng::<StdRng>()`).
600    /// It should be sufficient for most cases, but [`StdRng`] is not a portable random number generator,
601    /// so one may want to use a portable random number generator like [`ChaCha`](https://crates.io/crates/rand_chacha),
602    /// to this end one can use [`build_with_rng`](Self::build_with_rng).
603    pub fn build(self) -> NormalizedDelayPerPacket {
604        self.build_with_rng()
605    }
606
607    /// Creates a new [`NormalizedDelayPerPacket`] corresponding to this config.
608    ///
609    /// Unlike [`build`](Self::build), this method let you choose the random generator.
610    ///
611    /// # Example
612    /// ```rust
613    /// # use netem_trace::model::NormalizedDelayPerPacketConfig;
614    /// # use netem_trace::{Delay, DelayPerPacketTrace};
615    /// # use rand::rngs::StdRng;
616    /// # use rand_chacha::ChaCha20Rng;
617    ///
618    /// let normal_delay = NormalizedDelayPerPacketConfig::new()
619    ///     .mean(Delay::from_millis(12))
620    ///     .std_dev(Delay::from_millis(1))
621    ///     .count(3)
622    ///     .seed(42);
623    ///
624    /// let mut default_build = normal_delay.clone().build();
625    /// let mut std_build = normal_delay.clone().build_with_rng::<StdRng>();
626    /// // ChaCha is deterministic and portable, unlike StdRng
627    /// let mut chacha_build = normal_delay.clone().build_with_rng::<ChaCha20Rng>();
628    ///
629    /// for cha in [12044676, 11754367, 11253775] {
630    ///     let default = default_build.next_delay();
631    ///     let std = std_build.next_delay();
632    ///     let chacha = chacha_build.next_delay();
633    ///
634    ///     assert!(default.is_some());
635    ///     assert_eq!(default, std);
636    ///     assert_ne!(default, chacha);
637    ///     assert_eq!(chacha, Some(Delay::from_nanos(cha)));
638    /// }
639    ///
640    /// assert_eq!(default_build.next_delay(), None);
641    /// assert_eq!(std_build.next_delay(), None);
642    /// assert_eq!(chacha_build.next_delay(), None);
643    /// ```
644    pub fn build_with_rng<Rng: RngCore + SeedableRng>(self) -> NormalizedDelayPerPacket<Rng> {
645        let mean = self.mean.unwrap_or_else(|| Delay::from_millis(10));
646        let std_dev = self.std_dev.unwrap_or(Delay::ZERO);
647        let upper_bound = self.upper_bound;
648        let lower_bound = self.lower_bound.unwrap_or(Delay::ZERO);
649        let count = self.count;
650        let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
651        let rng = Rng::seed_from_u64(seed);
652        let delay_mean = mean.as_secs_f64();
653        let delay_std_dev = std_dev.as_secs_f64();
654        let normal: Normal<f64> = Normal::new(delay_mean, delay_std_dev).unwrap();
655        NormalizedDelayPerPacket {
656            mean,
657            std_dev,
658            upper_bound,
659            lower_bound,
660            count,
661            current_count: 0,
662            seed,
663            rng,
664            normal,
665        }
666    }
667}
668
669#[cfg(feature = "truncated-normal")]
670impl NormalizedDelayPerPacketConfig {
671    /// This is another implementation for converting NormalizedPerPacketConfig into NormalizedDelayPerPacket, where the impact
672    /// of truncation (`lower_bound` and `upper_bound` field) on the mathematical expectation of the distribution
673    /// is taking account by modifying the center of the distribution.
674    ///
675    /// ## Examples
676    ///
677    /// ```
678    ///
679    /// # use netem_trace::model::NormalizedDelayPerPacketConfig;
680    /// # use netem_trace::{Delay, DelayPerPacketTrace};
681    ///
682    /// let normal_delay = NormalizedDelayPerPacketConfig::new()
683    ///     .mean(Delay::from_millis(12))
684    ///     .std_dev(Delay::from_millis(12))
685    ///     .count(1_000_000)
686    ///     .seed(42);
687    ///
688    /// let mut default_build = normal_delay.clone().build();
689    /// let mut truncate_build = normal_delay.clone().build_truncated();
690    ///
691    /// fn avg_delay(mut model: impl DelayPerPacketTrace) -> Delay {
692    ///     let mut count = 0;
693    ///     std::iter::from_fn( move ||{
694    ///         model.next_delay()
695    ///     }).inspect(|_| count += 1).sum::<Delay>() / count
696    /// }
697    ///
698    /// assert_eq!(avg_delay(default_build), Delay::from_nanos(12998335)); // significantly higher than the expected mean
699    /// assert_eq!(avg_delay(truncate_build), Delay::from_nanos(11998818));
700    ///
701    /// let normal_delay = NormalizedDelayPerPacketConfig::new()
702    ///     .mean(Delay::from_millis(12))
703    ///     .std_dev(Delay::from_millis(12))
704    ///     .lower_bound(Delay::from_millis(8))
705    ///     .upper_bound(Delay::from_millis(20))
706    ///     .count(1_000_000)
707    ///     .seed(42);
708    ///
709    /// let mut default_build = normal_delay.clone().build();
710    /// let mut truncate_build = normal_delay.clone().build_truncated();
711    ///
712    /// assert_eq!(avg_delay(default_build),  Delay::from_nanos(13234261)); // significantly higher than the expected mean
713    /// assert_eq!(avg_delay(truncate_build), Delay::from_nanos(11999151));
714    ///
715    /// ```
716    pub fn build_truncated(self) -> NormalizedDelayPerPacket {
717        self.build_truncated_with_rng()
718    }
719
720    /// Similar to [`build_truncated`](Self::build_truncated) but let you choose the random generator.
721    ///
722    /// See [`build`](Self::build) for details about the reason for using another random number generator than [`StdRng`].
723    pub fn build_truncated_with_rng<Rng: SeedableRng + RngCore>(
724        mut self,
725    ) -> NormalizedDelayPerPacket<Rng> {
726        let mean = self
727            .mean
728            .unwrap_or_else(|| Delay::from_millis(12))
729            .as_secs_f64();
730        let sigma = self.std_dev.unwrap_or(Delay::ZERO).as_secs_f64() / mean;
731        let lower = self.lower_bound.unwrap_or(Delay::ZERO).as_secs_f64() / mean;
732        let upper = self.upper_bound.map(|upper| upper.as_secs_f64() / mean);
733        let new_mean = mean * solve(1f64, sigma, Some(lower), upper).unwrap_or(1f64);
734        self.mean = Some(Delay::from_secs_f64(new_mean));
735        self.build_with_rng()
736    }
737}
738
739impl LogNormalizedDelayPerPacketConfig {
740    /// Creates an uninitialized config
741    pub fn new() -> Self {
742        Self {
743            mean: None,
744            std_dev: None,
745            upper_bound: None,
746            lower_bound: None,
747            count: 0,
748            seed: None,
749        }
750    }
751
752    /// Sets the mean
753    ///
754    /// If the mean is not set, 10ms will be used.
755    pub fn mean(mut self, mean: Delay) -> Self {
756        self.mean = Some(mean);
757        self
758    }
759
760    /// Sets the standard deviation
761    ///
762    /// If the standard deviation is not set, 0ms will be used.
763    pub fn std_dev(mut self, std_dev: Delay) -> Self {
764        self.std_dev = Some(std_dev);
765        self
766    }
767
768    /// Sets the upper bound
769    ///
770    /// If the upper bound is not set, the upper bound will be the one of [`Delay`].
771    pub fn upper_bound(mut self, upper_bound: Delay) -> Self {
772        self.upper_bound = Some(upper_bound);
773        self
774    }
775
776    /// Sets the lower bound
777    ///
778    /// If the lower bound is not set, 0ms will be used.
779    pub fn lower_bound(mut self, lower_bound: Delay) -> Self {
780        self.lower_bound = Some(lower_bound);
781        self
782    }
783
784    /// Sets the number of packets to repeat
785    ///
786    /// If the count is not set, it will be set to 0 (ie, infinite repeat).
787    pub fn count(mut self, count: usize) -> Self {
788        self.count = count;
789        self
790    }
791
792    /// Set the seed for a random generator
793    ///
794    /// If the seed is not set, `42` will be used.
795    pub fn seed(mut self, seed: u64) -> Self {
796        self.seed = Some(seed);
797        self
798    }
799
800    /// Allows to use a randomly generated seed
801    ///
802    /// This is equivalent to: `self.seed(rand::random())`
803    pub fn random_seed(mut self) -> Self {
804        self.seed = Some(rand::random());
805        self
806    }
807
808    /// Creates a new [`LogNormalizedDelayPerPacket`] corresponding to this config.
809    ///
810    /// The created model will use [`StdRng`] as source of randomness (the call is equivalent to `self.build_with_rng::<StdRng>()`).
811    /// It should be sufficient for most cases, but [`StdRng`] is not a portable random number generator,
812    /// so one may want to use a portable random number generator like [`ChaCha`](https://crates.io/crates/rand_chacha),
813    /// to this end one can use [`build_with_rng`](Self::build_with_rng).
814    pub fn build(self) -> LogNormalizedDelayPerPacket {
815        self.build_with_rng()
816    }
817
818    /// Creates a new [`LogNormalizedDelayPerPacket`] corresponding to this config.
819    ///
820    /// Unlike [`build`](Self::build), this method let you choose the random generator.
821    ///
822    /// # Example
823    /// ```rust
824    /// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
825    /// # use netem_trace::{Delay, DelayPerPacketTrace};
826    /// # use rand::rngs::StdRng;
827    /// # use rand_chacha::ChaCha20Rng;
828    ///
829    /// let log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
830    ///     .mean(Delay::from_millis(12))
831    ///     .std_dev(Delay::from_millis(1))
832    ///     .count(3)
833    ///     .seed(42);
834    ///
835    /// let mut default_build = log_normal_delay.clone().build();
836    /// let mut std_build = log_normal_delay.clone().build_with_rng::<StdRng>();
837    /// // ChaCha is deterministic and portable, unlike StdRng
838    /// let mut chacha_build = log_normal_delay.clone().build_with_rng::<ChaCha20Rng>();
839    ///
840    /// for cha in [12003077, 11716668, 11238761] {
841    ///     let default = default_build.next_delay();
842    ///     let std = std_build.next_delay();
843    ///     let chacha = chacha_build.next_delay();
844    ///
845    ///     assert!(default.is_some());
846    ///     assert_eq!(default, std);
847    ///     assert_ne!(default, chacha);
848    ///     assert_eq!(chacha, Some(Delay::from_nanos(cha)));
849    /// }
850    ///
851    /// assert_eq!(default_build.next_delay(), None);
852    /// assert_eq!(std_build.next_delay(), None);
853    /// assert_eq!(chacha_build.next_delay(), None);
854    /// ```
855    pub fn build_with_rng<Rng: SeedableRng + RngCore>(self) -> LogNormalizedDelayPerPacket<Rng> {
856        let mean = self.mean.unwrap_or_else(|| Delay::from_millis(10));
857        let std_dev = self.std_dev.unwrap_or(Delay::ZERO);
858        let upper_bound = self.upper_bound;
859        let lower_bound = self.lower_bound.unwrap_or(Delay::ZERO);
860        let count = self.count;
861        let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
862        let rng = Rng::seed_from_u64(seed);
863        let delay_mean = mean.as_secs_f64();
864        let delay_std_dev = std_dev.as_secs_f64();
865
866        // Computing the mean and standard deviation of underlying normal Law
867        // Because Lognormal(μ , σ²) has a mean of exp(μ + σ²/2) and a standard deviation of sqrt((exp(σ²) - 1) exp(2μ + σ²))
868        // So we need to comput μ and σ, given the mean and standard deviation of the log-normal law
869        let normal_std_dev = f64::sqrt(f64::ln(
870            1.0 + (delay_std_dev.powi(2)) / (delay_mean.powi(2)),
871        ));
872        let normal_mean = f64::ln(delay_mean) - normal_std_dev.powi(2) / 2.;
873        let log_normal: LogNormal<f64> = LogNormal::new(normal_mean, normal_std_dev).unwrap();
874
875        LogNormalizedDelayPerPacket {
876            mean,
877            std_dev,
878            upper_bound,
879            lower_bound,
880            count,
881            current_count: 0,
882            seed,
883            rng,
884            log_normal,
885        }
886    }
887}
888
889macro_rules! impl_delay_per_packet_trace_config {
890    ($name:ident) => {
891        #[cfg_attr(feature = "serde", typetag::serde)]
892        impl DelayPerPacketTraceConfig for $name {
893            fn into_model(self: Box<$name>) -> Box<dyn DelayPerPacketTrace> {
894                Box::new(self.build())
895            }
896        }
897    };
898}
899
900impl_delay_per_packet_trace_config!(StaticDelayPerPacketConfig);
901impl_delay_per_packet_trace_config!(NormalizedDelayPerPacketConfig);
902impl_delay_per_packet_trace_config!(LogNormalizedDelayPerPacketConfig);
903impl_delay_per_packet_trace_config!(RepeatedDelayPerPacketPatternConfig);
904
905impl<Model: DelayPerPacketTrace + 'static> From<Model> for Box<dyn DelayPerPacketTrace> {
906    fn from(model: Model) -> Self {
907        Box::new(model)
908    }
909}
910
911/// Turn a [`DelayPerPacketTraceConfig`] into a forever repeated [`RepeatedDelayPerPacketPatternConfig`].
912pub trait Forever: DelayPerPacketTraceConfig {
913    fn forever(self) -> RepeatedDelayPerPacketPatternConfig;
914}
915
916/// Implement the [`Forever`] trait for the per-packet delay trace model config (any struct implements [`DelayPerPacketTraceConfig`]).
917#[macro_export]
918macro_rules! impl_forever_delay_per_packet {
919    ($name:ident) => {
920        impl Forever for $name {
921            fn forever(self) -> RepeatedDelayPerPacketPatternConfig {
922                RepeatedDelayPerPacketPatternConfig::new()
923                    .pattern(vec![Box::new(self)])
924                    .count(0)
925            }
926        }
927    };
928}
929
930impl_forever_delay_per_packet!(StaticDelayPerPacketConfig);
931impl_forever_delay_per_packet!(NormalizedDelayPerPacketConfig);
932
933impl Forever for RepeatedDelayPerPacketPatternConfig {
934    fn forever(self) -> RepeatedDelayPerPacketPatternConfig {
935        self.count(0)
936    }
937}
938
939#[cfg(test)]
940mod test {
941    use super::*;
942    use crate::model::StaticDelayPerPacketConfig;
943    use crate::DelayPerPacketTrace;
944
945    #[test]
946    fn test_static_delay_model() {
947        let mut static_delay = StaticDelayPerPacketConfig::new()
948            .delay(Delay::from_millis(10))
949            .count(1)
950            .build();
951        assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
952        assert_eq!(static_delay.next_delay(), None);
953    }
954
955    #[test]
956    #[cfg(feature = "serde")]
957    fn test_serde() {
958        let a = vec![
959            Box::new(
960                StaticDelayPerPacketConfig::new()
961                    .delay(Delay::from_millis(10))
962                    .count(1),
963            ) as Box<dyn DelayPerPacketTraceConfig>,
964            Box::new(
965                StaticDelayPerPacketConfig::new()
966                    .delay(Delay::from_millis(20))
967                    .count(1),
968            ) as Box<dyn DelayPerPacketTraceConfig>,
969        ];
970        let ser = Box::new(
971            RepeatedDelayPerPacketPatternConfig::new()
972                .pattern(a)
973                .count(2),
974        ) as Box<dyn DelayPerPacketTraceConfig>;
975        let ser_str = serde_json::to_string(&ser).unwrap();
976        #[cfg(feature = "human")]
977        let des_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
978        #[cfg(not(feature = "human"))]
979        let des_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
980        assert_eq!(ser_str, des_str);
981        let des: Box<dyn DelayPerPacketTraceConfig> = serde_json::from_str(des_str).unwrap();
982        let mut model = des.into_model();
983        assert_eq!(model.next_delay(), Some(Delay::from_millis(10)));
984    }
985}