Skip to main content

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, Uniform};
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 uniform distribution.
214///
215/// The delay will subject to a uniform distribution in [lower_bound, upper_bound]
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/// Default values for lower_bound and upper_bound are 0ms and 10ms, respectively.
222///
223/// ```
224/// # use netem_trace::model::UniformDelayPerPacketConfig;
225/// # use netem_trace::{Delay, DelayPerPacketTrace};
226/// let mut uniform_delay = UniformDelayPerPacketConfig::new()
227///     .upper_bound(Delay::from_micros(12100))
228///     .lower_bound(Delay::from_micros(11900))
229///     .count(2)
230///     .seed(42)
231///     .build();
232/// assert_eq!(uniform_delay.next_delay(), Some(Delay::from_nanos(12005311)));
233/// assert_eq!(uniform_delay.next_delay(), Some(Delay::from_nanos(12008545)));
234/// assert_eq!(uniform_delay.next_delay(), None);
235/// ```
236#[derive(Debug, Clone, Copy, PartialEq)]
237pub struct UniformDelayPerPacket<Rng = StdRng>
238where
239    Rng: RngCore,
240{
241    pub upper_bound: Delay,
242    pub lower_bound: Delay,
243    pub seed: u64,
244    pub count: usize,
245    current_count: usize,
246    rng: Rng,
247    uniform: Uniform<f64>,
248}
249
250/// The configuration struct for [`UniformDelayPerPacket`].
251///
252/// See [`UniformDelayPerPacket`] for more details.
253#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
254#[derive(Default, Debug, Clone, Copy, PartialEq)]
255pub struct UniformDelayPerPacketConfig {
256    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
257    #[cfg_attr(
258        all(feature = "serde", feature = "human"),
259        serde(with = "humantime_serde")
260    )]
261    pub upper_bound: Option<Delay>,
262    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
263    #[cfg_attr(
264        all(feature = "serde", feature = "human"),
265        serde(with = "humantime_serde")
266    )]
267    pub lower_bound: Option<Delay>,
268    #[cfg_attr(feature = "serde", serde(default))]
269    pub count: usize,
270    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
271    pub seed: Option<u64>,
272}
273
274/// The model of a per-packet delay trace subjects to a normal distribution.
275///
276/// The delay will subject to N(mean, std_dev²), but bounded within [lower_bound, upper_bound] (optional)
277///
278/// If the `count` is 0, the delay will be repeated forever, else it will be repeated `count` times.
279///
280/// ## Examples
281///
282/// A simple example without any bound on delay:
283///
284/// ```
285/// # use netem_trace::model::NormalizedDelayPerPacketConfig;
286/// # use netem_trace::{Delay, DelayPerPacketTrace};
287/// let mut normal_delay = NormalizedDelayPerPacketConfig::new()
288///     .mean(Delay::from_millis(12))
289///     .std_dev(Delay::from_millis(1))
290///     .count(2)
291///     .seed(42)
292///     .build();
293/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12069428)));
294/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12132938)));
295/// assert_eq!(normal_delay.next_delay(), None);
296/// ```
297///
298/// A more complex example with bounds on delay:
299///
300/// ```
301/// # use netem_trace::model::NormalizedDelayPerPacketConfig;
302/// # use netem_trace::{Delay, DelayPerPacketTrace};
303/// let mut normal_delay = NormalizedDelayPerPacketConfig::new()
304///     .mean(Delay::from_millis(12))
305///     .std_dev(Delay::from_millis(1))
306///     .count(2)
307///     .seed(42)
308///     .upper_bound(Delay::from_micros(12100))
309///     .lower_bound(Delay::from_micros(11900))
310///     .build();
311/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12069428)));
312/// assert_eq!(normal_delay.next_delay(), Some(Delay::from_nanos(12100000)));
313/// assert_eq!(normal_delay.next_delay(), None);
314/// ```
315#[derive(Debug, Clone, Copy, PartialEq)]
316pub struct NormalizedDelayPerPacket<Rng = StdRng>
317where
318    Rng: RngCore,
319{
320    pub mean: Delay,
321    pub std_dev: Delay,
322    pub upper_bound: Option<Delay>,
323    pub lower_bound: Delay,
324    pub seed: u64,
325    pub count: usize,
326    current_count: usize,
327    rng: Rng,
328    normal: Normal<f64>,
329}
330
331/// The configuration struct for [`NormalizedDelayPerPacket`].
332///
333/// See [`NormalizedDelayPerPacket`] for more details.
334#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
335#[derive(Default, Debug, Clone, Copy, PartialEq)]
336pub struct NormalizedDelayPerPacketConfig {
337    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
338    #[cfg_attr(
339        all(feature = "serde", feature = "human"),
340        serde(with = "humantime_serde")
341    )]
342    pub mean: Option<Delay>,
343    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
344    #[cfg_attr(
345        all(feature = "serde", feature = "human"),
346        serde(with = "humantime_serde")
347    )]
348    pub std_dev: Option<Delay>,
349    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
350    #[cfg_attr(
351        all(feature = "serde", feature = "human"),
352        serde(with = "humantime_serde")
353    )]
354    pub upper_bound: Option<Delay>,
355    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
356    #[cfg_attr(
357        all(feature = "serde", feature = "human"),
358        serde(with = "humantime_serde")
359    )]
360    pub lower_bound: Option<Delay>,
361    #[cfg_attr(feature = "serde", serde(default))]
362    pub count: usize,
363    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
364    pub seed: Option<u64>,
365}
366/// The model of a per-packet delay trace subjects to a log-normal distribution.
367///
368/// The delay will subject to Lognormal(μ, σ²), but bounded within [lower_bound, upper_bound] (optional)
369/// The provided mean and std_dev are the one of the log-normal law and not the one of the underlying normal law.
370///
371/// If the `count` is 0, the delay will be repeated forever, else it will be repeated `count` times.
372///
373/// ## Examples
374///
375/// A simple example without any bound on delay:
376///
377/// ```
378/// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
379/// # use netem_trace::{Delay, DelayPerPacketTrace};
380/// let mut log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
381///     .mean(Delay::from_millis(12))
382///     .std_dev(Delay::from_millis(1))
383///     .count(2)
384///     .seed(42)
385///     .build();
386/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12027817)));
387/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12091533)));
388/// assert_eq!(log_normal_delay.next_delay(), None);
389/// ```
390///
391/// A more complex example with bounds on delay:
392///
393/// ```
394/// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
395/// # use netem_trace::{Delay, DelayPerPacketTrace};
396/// let mut log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
397///     .mean(Delay::from_millis(12))
398///     .std_dev(Delay::from_millis(1))
399///     .count(3)
400///     .seed(42)
401///     .upper_bound(Delay::from_micros(12100))
402///     .lower_bound(Delay::from_micros(11900))
403///     .build();
404/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12027817)));
405/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12091533)));
406/// assert_eq!(log_normal_delay.next_delay(), Some(Delay::from_nanos(12100000)));
407/// assert_eq!(log_normal_delay.next_delay(), None);
408/// ```
409#[derive(Debug, Clone, Copy, PartialEq)]
410pub struct LogNormalizedDelayPerPacket<Rng = StdRng>
411where
412    Rng: RngCore,
413{
414    pub mean: Delay,
415    pub std_dev: Delay,
416    pub upper_bound: Option<Delay>,
417    pub lower_bound: Delay,
418    pub seed: u64,
419    pub count: usize,
420    current_count: usize,
421    rng: Rng,
422    log_normal: LogNormal<f64>,
423}
424
425/// The configuration struct for [`LogNormalizedDelayPerPacket`].
426///
427/// See [`LogNormalizedDelayPerPacket`] for more details.
428#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
429#[derive(Default, Debug, Clone, Copy, PartialEq)]
430pub struct LogNormalizedDelayPerPacketConfig {
431    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
432    #[cfg_attr(
433        all(feature = "serde", feature = "human"),
434        serde(with = "humantime_serde")
435    )]
436    pub mean: Option<Delay>,
437    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
438    #[cfg_attr(
439        all(feature = "serde", feature = "human"),
440        serde(with = "humantime_serde")
441    )]
442    pub std_dev: Option<Delay>,
443    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
444    #[cfg_attr(
445        all(feature = "serde", feature = "human"),
446        serde(with = "humantime_serde")
447    )]
448    pub upper_bound: Option<Delay>,
449    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
450    #[cfg_attr(
451        all(feature = "serde", feature = "human"),
452        serde(with = "humantime_serde")
453    )]
454    pub lower_bound: Option<Delay>,
455    #[cfg_attr(feature = "serde", serde(default))]
456    pub count: usize,
457    #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
458    pub seed: Option<u64>,
459}
460
461impl DelayPerPacketTrace for StaticDelayPerPacket {
462    fn next_delay(&mut self) -> Option<Delay> {
463        if self.count != 0 && self.count == self.current_count {
464            None
465        } else {
466            self.current_count += 1;
467            Some(self.delay)
468        }
469    }
470}
471
472impl DelayPerPacketTrace for RepeatedDelayPerPacketPattern {
473    fn next_delay(&mut self) -> Option<Delay> {
474        if self.pattern.is_empty() || (self.count != 0 && self.current_cycle >= self.count) {
475            None
476        } else {
477            if self.current_model.is_none() {
478                self.current_model = Some(self.pattern[self.current_pattern].clone().into_model());
479            }
480            match self.current_model.as_mut().unwrap().next_delay() {
481                Some(delay) => Some(delay),
482                None => {
483                    self.current_model = None;
484                    self.current_pattern += 1;
485                    if self.current_pattern >= self.pattern.len() {
486                        self.current_pattern = 0;
487                        self.current_cycle += 1;
488                        if self.count != 0 && self.current_cycle >= self.count {
489                            return None;
490                        }
491                    }
492                    self.next_delay()
493                }
494            }
495        }
496    }
497}
498
499impl<Rng: RngCore + Send> DelayPerPacketTrace for UniformDelayPerPacket<Rng> {
500    fn next_delay(&mut self) -> Option<Delay> {
501        if self.count != 0 && self.count == self.current_count {
502            None
503        } else {
504            self.current_count += 1;
505            let delay = self.uniform.sample(&mut self.rng).max(0.0);
506            Some(Delay::from_secs_f64(delay))
507        }
508    }
509}
510
511impl<Rng: RngCore + Send> DelayPerPacketTrace for NormalizedDelayPerPacket<Rng> {
512    fn next_delay(&mut self) -> Option<Delay> {
513        if self.count != 0 && self.count == self.current_count {
514            None
515        } else {
516            self.current_count += 1;
517            let delay = self.normal.sample(&mut self.rng).max(0.0);
518            let mut delay = Delay::from_secs_f64(delay);
519            delay = delay.max(self.lower_bound);
520            if let Some(upper_bound) = self.upper_bound {
521                delay = delay.min(upper_bound);
522            }
523            Some(delay)
524        }
525    }
526}
527
528impl<Rng: RngCore + Send> DelayPerPacketTrace for LogNormalizedDelayPerPacket<Rng> {
529    fn next_delay(&mut self) -> Option<Delay> {
530        if self.count != 0 && self.count == self.current_count {
531            None
532        } else {
533            self.current_count += 1;
534            let delay = self.log_normal.sample(&mut self.rng).max(0.0);
535            let mut delay = Delay::from_secs_f64(delay);
536            delay = delay.max(self.lower_bound);
537            if let Some(upper_bound) = self.upper_bound {
538                delay = delay.min(upper_bound);
539            }
540            Some(delay)
541        }
542    }
543}
544
545impl StaticDelayPerPacketConfig {
546    pub fn new() -> Self {
547        Self {
548            delay: None,
549            count: 0,
550        }
551    }
552
553    pub fn delay(mut self, delay: Delay) -> Self {
554        self.delay = Some(delay);
555        self
556    }
557
558    pub fn count(mut self, count: usize) -> Self {
559        self.count = count;
560        self
561    }
562
563    pub fn build(self) -> StaticDelayPerPacket {
564        StaticDelayPerPacket {
565            delay: self.delay.unwrap_or_else(|| Delay::from_millis(10)),
566            count: self.count,
567            current_count: 0,
568        }
569    }
570}
571
572impl RepeatedDelayPerPacketPatternConfig {
573    pub fn new() -> Self {
574        Self {
575            pattern: vec![],
576            count: 0,
577        }
578    }
579
580    pub fn pattern(mut self, pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>) -> Self {
581        self.pattern = pattern;
582        self
583    }
584
585    pub fn count(mut self, count: usize) -> Self {
586        self.count = count;
587        self
588    }
589
590    pub fn build(self) -> RepeatedDelayPerPacketPattern {
591        RepeatedDelayPerPacketPattern {
592            pattern: self.pattern,
593            count: self.count,
594            current_model: None,
595            current_cycle: 0,
596            current_pattern: 0,
597        }
598    }
599}
600
601impl UniformDelayPerPacketConfig {
602    /// Creates an uninitialized config
603    pub fn new() -> Self {
604        Self {
605            upper_bound: None,
606            lower_bound: None,
607            count: 0,
608            seed: None,
609        }
610    }
611
612    /// Sets the upper bound
613    ///
614    /// If the upper bound is not set, the upper bound will be 10ms.
615    pub fn upper_bound(mut self, upper_bound: Delay) -> Self {
616        self.upper_bound = Some(upper_bound);
617        self
618    }
619
620    /// Sets the lower bound
621    ///
622    /// If the lower bound is not set, 0ms will be used.
623    pub fn lower_bound(mut self, lower_bound: Delay) -> Self {
624        self.lower_bound = Some(lower_bound);
625        self
626    }
627
628    /// Sets the number of packets to repeat
629    ///
630    /// If the count is not set, it will be set to 0 (ie, infinite repeat).
631    pub fn count(mut self, count: usize) -> Self {
632        self.count = count;
633        self
634    }
635
636    /// Set the seed for a random generator
637    ///
638    /// If the seed is not set, `42` will be used.
639    pub fn seed(mut self, seed: u64) -> Self {
640        self.seed = Some(seed);
641        self
642    }
643
644    /// Allows to use a randomly generated seed
645    ///
646    /// This is equivalent to: `self.seed(rand::random())`
647    pub fn random_seed(mut self) -> Self {
648        self.seed = Some(rand::random());
649        self
650    }
651
652    /// Creates a new [`UniformDelayPerPacket`] corresponding to this config.
653    ///
654    /// The created model will use [`StdRng`] as source of randomness (the call is equivalent to `self.build_with_rng::<StdRng>()`).
655    /// It should be sufficient for most cases, but [`StdRng`] is not a portable random number generator,
656    /// so one may want to use a portable random number generator like [`ChaCha`](https://crates.io/crates/rand_chacha),
657    /// to this end one can use [`build_with_rng`](Self::build_with_rng).
658    pub fn build(self) -> UniformDelayPerPacket {
659        self.build_with_rng()
660    }
661
662    /// Creates a new [`UniformDelayPerPacket`] corresponding to this config.
663    ///
664    /// Unlike [`build`](Self::build), this method let you choose the random generator.
665    ///
666    /// # Example
667    /// ```rust
668    /// # use netem_trace::model::UniformDelayPerPacketConfig;
669    /// # use netem_trace::{Delay, DelayPerPacketTrace};
670    /// # use rand::rngs::StdRng;
671    /// # use rand_chacha::ChaCha20Rng;
672    ///
673    /// let uniform_delay = UniformDelayPerPacketConfig::new()
674    ///     .upper_bound(Delay::from_micros(12100))
675    ///     .lower_bound(Delay::from_micros(11900))
676    ///     .count(3)
677    ///     .seed(42);
678    ///
679    /// let mut default_build = uniform_delay.clone().build();
680    /// let mut std_build = uniform_delay.clone().build_with_rng::<StdRng>();
681    /// // ChaCha is deterministic and portable, unlike StdRng
682    /// let mut chacha_build = uniform_delay.clone().build_with_rng::<ChaCha20Rng>();
683    ///
684    /// for cha in [12002810, 11982040, 11919563] {
685    ///     let default = default_build.next_delay();
686    ///     let std = std_build.next_delay();
687    ///     let chacha = chacha_build.next_delay();
688    ///
689    ///     assert!(default.is_some());
690    ///     assert_eq!(default, std);
691    ///     assert_ne!(default, chacha);
692    ///     assert_eq!(chacha, Some(Delay::from_nanos(cha)));
693    /// }
694    ///
695    /// assert_eq!(default_build.next_delay(), None);
696    /// assert_eq!(std_build.next_delay(), None);
697    /// assert_eq!(chacha_build.next_delay(), None);
698    /// ```
699    pub fn build_with_rng<Rng: RngCore + SeedableRng>(self) -> UniformDelayPerPacket<Rng> {
700        let upper_bound = self.upper_bound.unwrap_or(Delay::from_millis(10));
701        let lower_bound = self.lower_bound.unwrap_or(Delay::ZERO);
702        let count = self.count;
703        let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
704        let rng = Rng::seed_from_u64(seed);
705        let uniform: Uniform<f64> =
706            Uniform::new(lower_bound.as_secs_f64(), upper_bound.as_secs_f64()).unwrap();
707        UniformDelayPerPacket {
708            upper_bound,
709            lower_bound,
710            count,
711            current_count: 0,
712            seed,
713            rng,
714            uniform,
715        }
716    }
717}
718
719impl NormalizedDelayPerPacketConfig {
720    /// Creates an uninitialized config
721    pub fn new() -> Self {
722        Self {
723            mean: None,
724            std_dev: None,
725            upper_bound: None,
726            lower_bound: None,
727            count: 0,
728            seed: None,
729        }
730    }
731
732    /// Sets the mean
733    ///
734    /// If the mean is not set, 10ms will be used.
735    pub fn mean(mut self, mean: Delay) -> Self {
736        self.mean = Some(mean);
737        self
738    }
739
740    /// Sets the standard deviation
741    ///
742    /// If the standard deviation is not set, 0ms will be used.
743    pub fn std_dev(mut self, std_dev: Delay) -> Self {
744        self.std_dev = Some(std_dev);
745        self
746    }
747
748    /// Sets the upper bound
749    ///
750    /// If the upper bound is not set, the upper bound will be the one of [`Delay`].
751    pub fn upper_bound(mut self, upper_bound: Delay) -> Self {
752        self.upper_bound = Some(upper_bound);
753        self
754    }
755
756    /// Sets the lower bound
757    ///
758    /// If the lower bound is not set, 0ms will be used.
759    pub fn lower_bound(mut self, lower_bound: Delay) -> Self {
760        self.lower_bound = Some(lower_bound);
761        self
762    }
763
764    /// Sets the number of packets to repeat
765    ///
766    /// If the count is not set, it will be set to 0 (ie, infinite repeat).
767    pub fn count(mut self, count: usize) -> Self {
768        self.count = count;
769        self
770    }
771
772    /// Set the seed for a random generator
773    ///
774    /// If the seed is not set, `42` will be used.
775    pub fn seed(mut self, seed: u64) -> Self {
776        self.seed = Some(seed);
777        self
778    }
779
780    /// Allows to use a randomly generated seed
781    ///
782    /// This is equivalent to: `self.seed(rand::random())`
783    pub fn random_seed(mut self) -> Self {
784        self.seed = Some(rand::random());
785        self
786    }
787
788    /// Creates a new [`NormalizedDelayPerPacket`] corresponding to this config.
789    ///
790    /// The created model will use [`StdRng`] as source of randomness (the call is equivalent to `self.build_with_rng::<StdRng>()`).
791    /// It should be sufficient for most cases, but [`StdRng`] is not a portable random number generator,
792    /// so one may want to use a portable random number generator like [`ChaCha`](https://crates.io/crates/rand_chacha),
793    /// to this end one can use [`build_with_rng`](Self::build_with_rng).
794    pub fn build(self) -> NormalizedDelayPerPacket {
795        self.build_with_rng()
796    }
797
798    /// Creates a new [`NormalizedDelayPerPacket`] corresponding to this config.
799    ///
800    /// Unlike [`build`](Self::build), this method let you choose the random generator.
801    ///
802    /// # Example
803    /// ```rust
804    /// # use netem_trace::model::NormalizedDelayPerPacketConfig;
805    /// # use netem_trace::{Delay, DelayPerPacketTrace};
806    /// # use rand::rngs::StdRng;
807    /// # use rand_chacha::ChaCha20Rng;
808    ///
809    /// let normal_delay = NormalizedDelayPerPacketConfig::new()
810    ///     .mean(Delay::from_millis(12))
811    ///     .std_dev(Delay::from_millis(1))
812    ///     .count(3)
813    ///     .seed(42);
814    ///
815    /// let mut default_build = normal_delay.clone().build();
816    /// let mut std_build = normal_delay.clone().build_with_rng::<StdRng>();
817    /// // ChaCha is deterministic and portable, unlike StdRng
818    /// let mut chacha_build = normal_delay.clone().build_with_rng::<ChaCha20Rng>();
819    ///
820    /// for cha in [12044676, 11754367, 11253775] {
821    ///     let default = default_build.next_delay();
822    ///     let std = std_build.next_delay();
823    ///     let chacha = chacha_build.next_delay();
824    ///
825    ///     assert!(default.is_some());
826    ///     assert_eq!(default, std);
827    ///     assert_ne!(default, chacha);
828    ///     assert_eq!(chacha, Some(Delay::from_nanos(cha)));
829    /// }
830    ///
831    /// assert_eq!(default_build.next_delay(), None);
832    /// assert_eq!(std_build.next_delay(), None);
833    /// assert_eq!(chacha_build.next_delay(), None);
834    /// ```
835    pub fn build_with_rng<Rng: RngCore + SeedableRng>(self) -> NormalizedDelayPerPacket<Rng> {
836        let mean = self.mean.unwrap_or_else(|| Delay::from_millis(10));
837        let std_dev = self.std_dev.unwrap_or(Delay::ZERO);
838        let upper_bound = self.upper_bound;
839        let lower_bound = self.lower_bound.unwrap_or(Delay::ZERO);
840        let count = self.count;
841        let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
842        let rng = Rng::seed_from_u64(seed);
843        let delay_mean = mean.as_secs_f64();
844        let delay_std_dev = std_dev.as_secs_f64();
845        let normal: Normal<f64> = Normal::new(delay_mean, delay_std_dev).unwrap();
846        NormalizedDelayPerPacket {
847            mean,
848            std_dev,
849            upper_bound,
850            lower_bound,
851            count,
852            current_count: 0,
853            seed,
854            rng,
855            normal,
856        }
857    }
858}
859
860#[cfg(feature = "truncated-normal")]
861impl NormalizedDelayPerPacketConfig {
862    /// This is another implementation for converting NormalizedPerPacketConfig into NormalizedDelayPerPacket, where the impact
863    /// of truncation (`lower_bound` and `upper_bound` field) on the mathematical expectation of the distribution
864    /// is taking account by modifying the center of the distribution.
865    ///
866    /// ## Examples
867    ///
868    /// ```
869    ///
870    /// # use netem_trace::model::NormalizedDelayPerPacketConfig;
871    /// # use netem_trace::{Delay, DelayPerPacketTrace};
872    ///
873    /// let normal_delay = NormalizedDelayPerPacketConfig::new()
874    ///     .mean(Delay::from_millis(12))
875    ///     .std_dev(Delay::from_millis(12))
876    ///     .count(1_000_000)
877    ///     .seed(42);
878    ///
879    /// let mut default_build = normal_delay.clone().build();
880    /// let mut truncate_build = normal_delay.clone().build_truncated();
881    ///
882    /// fn avg_delay(mut model: impl DelayPerPacketTrace) -> Delay {
883    ///     let mut count = 0;
884    ///     std::iter::from_fn( move ||{
885    ///         model.next_delay()
886    ///     }).inspect(|_| count += 1).sum::<Delay>() / count
887    /// }
888    ///
889    /// assert_eq!(avg_delay(default_build), Delay::from_nanos(12998335)); // significantly higher than the expected mean
890    /// assert_eq!(avg_delay(truncate_build), Delay::from_nanos(11998818));
891    ///
892    /// let normal_delay = NormalizedDelayPerPacketConfig::new()
893    ///     .mean(Delay::from_millis(12))
894    ///     .std_dev(Delay::from_millis(12))
895    ///     .lower_bound(Delay::from_millis(8))
896    ///     .upper_bound(Delay::from_millis(20))
897    ///     .count(1_000_000)
898    ///     .seed(42);
899    ///
900    /// let mut default_build = normal_delay.clone().build();
901    /// let mut truncate_build = normal_delay.clone().build_truncated();
902    ///
903    /// assert_eq!(avg_delay(default_build),  Delay::from_nanos(13234261)); // significantly higher than the expected mean
904    /// assert_eq!(avg_delay(truncate_build), Delay::from_nanos(11999151));
905    ///
906    /// ```
907    pub fn build_truncated(self) -> NormalizedDelayPerPacket {
908        self.build_truncated_with_rng()
909    }
910
911    /// Similar to [`build_truncated`](Self::build_truncated) but let you choose the random generator.
912    ///
913    /// See [`build`](Self::build) for details about the reason for using another random number generator than [`StdRng`].
914    pub fn build_truncated_with_rng<Rng: SeedableRng + RngCore>(
915        mut self,
916    ) -> NormalizedDelayPerPacket<Rng> {
917        let mean = self
918            .mean
919            .unwrap_or_else(|| Delay::from_millis(12))
920            .as_secs_f64();
921        let sigma = self.std_dev.unwrap_or(Delay::ZERO).as_secs_f64() / mean;
922        let lower = self.lower_bound.unwrap_or(Delay::ZERO).as_secs_f64() / mean;
923        let upper = self.upper_bound.map(|upper| upper.as_secs_f64() / mean);
924        let new_mean = mean * solve(1f64, sigma, Some(lower), upper).unwrap_or(1f64);
925        self.mean = Some(Delay::from_secs_f64(new_mean));
926        self.build_with_rng()
927    }
928}
929
930impl LogNormalizedDelayPerPacketConfig {
931    /// Creates an uninitialized config
932    pub fn new() -> Self {
933        Self {
934            mean: None,
935            std_dev: None,
936            upper_bound: None,
937            lower_bound: None,
938            count: 0,
939            seed: None,
940        }
941    }
942
943    /// Sets the mean
944    ///
945    /// If the mean is not set, 10ms will be used.
946    pub fn mean(mut self, mean: Delay) -> Self {
947        self.mean = Some(mean);
948        self
949    }
950
951    /// Sets the standard deviation
952    ///
953    /// If the standard deviation is not set, 0ms will be used.
954    pub fn std_dev(mut self, std_dev: Delay) -> Self {
955        self.std_dev = Some(std_dev);
956        self
957    }
958
959    /// Sets the upper bound
960    ///
961    /// If the upper bound is not set, the upper bound will be the one of [`Delay`].
962    pub fn upper_bound(mut self, upper_bound: Delay) -> Self {
963        self.upper_bound = Some(upper_bound);
964        self
965    }
966
967    /// Sets the lower bound
968    ///
969    /// If the lower bound is not set, 0ms will be used.
970    pub fn lower_bound(mut self, lower_bound: Delay) -> Self {
971        self.lower_bound = Some(lower_bound);
972        self
973    }
974
975    /// Sets the number of packets to repeat
976    ///
977    /// If the count is not set, it will be set to 0 (ie, infinite repeat).
978    pub fn count(mut self, count: usize) -> Self {
979        self.count = count;
980        self
981    }
982
983    /// Set the seed for a random generator
984    ///
985    /// If the seed is not set, `42` will be used.
986    pub fn seed(mut self, seed: u64) -> Self {
987        self.seed = Some(seed);
988        self
989    }
990
991    /// Allows to use a randomly generated seed
992    ///
993    /// This is equivalent to: `self.seed(rand::random())`
994    pub fn random_seed(mut self) -> Self {
995        self.seed = Some(rand::random());
996        self
997    }
998
999    /// Creates a new [`LogNormalizedDelayPerPacket`] corresponding to this config.
1000    ///
1001    /// The created model will use [`StdRng`] as source of randomness (the call is equivalent to `self.build_with_rng::<StdRng>()`).
1002    /// It should be sufficient for most cases, but [`StdRng`] is not a portable random number generator,
1003    /// so one may want to use a portable random number generator like [`ChaCha`](https://crates.io/crates/rand_chacha),
1004    /// to this end one can use [`build_with_rng`](Self::build_with_rng).
1005    pub fn build(self) -> LogNormalizedDelayPerPacket {
1006        self.build_with_rng()
1007    }
1008
1009    /// Creates a new [`LogNormalizedDelayPerPacket`] corresponding to this config.
1010    ///
1011    /// Unlike [`build`](Self::build), this method let you choose the random generator.
1012    ///
1013    /// # Example
1014    /// ```rust
1015    /// # use netem_trace::model::LogNormalizedDelayPerPacketConfig;
1016    /// # use netem_trace::{Delay, DelayPerPacketTrace};
1017    /// # use rand::rngs::StdRng;
1018    /// # use rand_chacha::ChaCha20Rng;
1019    ///
1020    /// let log_normal_delay = LogNormalizedDelayPerPacketConfig::new()
1021    ///     .mean(Delay::from_millis(12))
1022    ///     .std_dev(Delay::from_millis(1))
1023    ///     .count(3)
1024    ///     .seed(42);
1025    ///
1026    /// let mut default_build = log_normal_delay.clone().build();
1027    /// let mut std_build = log_normal_delay.clone().build_with_rng::<StdRng>();
1028    /// // ChaCha is deterministic and portable, unlike StdRng
1029    /// let mut chacha_build = log_normal_delay.clone().build_with_rng::<ChaCha20Rng>();
1030    ///
1031    /// for cha in [12003077, 11716668, 11238761] {
1032    ///     let default = default_build.next_delay();
1033    ///     let std = std_build.next_delay();
1034    ///     let chacha = chacha_build.next_delay();
1035    ///
1036    ///     assert!(default.is_some());
1037    ///     assert_eq!(default, std);
1038    ///     assert_ne!(default, chacha);
1039    ///     assert_eq!(chacha, Some(Delay::from_nanos(cha)));
1040    /// }
1041    ///
1042    /// assert_eq!(default_build.next_delay(), None);
1043    /// assert_eq!(std_build.next_delay(), None);
1044    /// assert_eq!(chacha_build.next_delay(), None);
1045    /// ```
1046    pub fn build_with_rng<Rng: SeedableRng + RngCore>(self) -> LogNormalizedDelayPerPacket<Rng> {
1047        let mean = self.mean.unwrap_or_else(|| Delay::from_millis(10));
1048        let std_dev = self.std_dev.unwrap_or(Delay::ZERO);
1049        let upper_bound = self.upper_bound;
1050        let lower_bound = self.lower_bound.unwrap_or(Delay::ZERO);
1051        let count = self.count;
1052        let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
1053        let rng = Rng::seed_from_u64(seed);
1054        let delay_mean = mean.as_secs_f64();
1055        let delay_std_dev = std_dev.as_secs_f64();
1056
1057        // Computing the mean and standard deviation of underlying normal Law
1058        // Because Lognormal(μ , σ²) has a mean of exp(μ + σ²/2) and a standard deviation of sqrt((exp(σ²) - 1) exp(2μ + σ²))
1059        // So we need to comput μ and σ, given the mean and standard deviation of the log-normal law
1060        let normal_std_dev = f64::sqrt(f64::ln(
1061            1.0 + (delay_std_dev.powi(2)) / (delay_mean.powi(2)),
1062        ));
1063        let normal_mean = f64::ln(delay_mean) - normal_std_dev.powi(2) / 2.;
1064        let log_normal: LogNormal<f64> = LogNormal::new(normal_mean, normal_std_dev).unwrap();
1065
1066        LogNormalizedDelayPerPacket {
1067            mean,
1068            std_dev,
1069            upper_bound,
1070            lower_bound,
1071            count,
1072            current_count: 0,
1073            seed,
1074            rng,
1075            log_normal,
1076        }
1077    }
1078}
1079
1080macro_rules! impl_delay_per_packet_trace_config {
1081    ($name:ident) => {
1082        #[cfg_attr(feature = "serde", typetag::serde)]
1083        impl DelayPerPacketTraceConfig for $name {
1084            fn into_model(self: Box<$name>) -> Box<dyn DelayPerPacketTrace> {
1085                Box::new(self.build())
1086            }
1087        }
1088    };
1089}
1090
1091impl_delay_per_packet_trace_config!(StaticDelayPerPacketConfig);
1092impl_delay_per_packet_trace_config!(UniformDelayPerPacketConfig);
1093impl_delay_per_packet_trace_config!(NormalizedDelayPerPacketConfig);
1094impl_delay_per_packet_trace_config!(LogNormalizedDelayPerPacketConfig);
1095impl_delay_per_packet_trace_config!(RepeatedDelayPerPacketPatternConfig);
1096
1097impl<Model: DelayPerPacketTrace + 'static> From<Model> for Box<dyn DelayPerPacketTrace> {
1098    fn from(model: Model) -> Self {
1099        Box::new(model)
1100    }
1101}
1102
1103/// Turn a [`DelayPerPacketTraceConfig`] into a forever repeated [`RepeatedDelayPerPacketPatternConfig`].
1104pub trait Forever: DelayPerPacketTraceConfig {
1105    fn forever(self) -> RepeatedDelayPerPacketPatternConfig;
1106}
1107
1108/// Implement the [`Forever`] trait for the per-packet delay trace model config (any struct implements [`DelayPerPacketTraceConfig`]).
1109#[macro_export]
1110macro_rules! impl_forever_delay_per_packet {
1111    ($name:ident) => {
1112        impl Forever for $name {
1113            fn forever(self) -> RepeatedDelayPerPacketPatternConfig {
1114                RepeatedDelayPerPacketPatternConfig::new()
1115                    .pattern(vec![Box::new(self)])
1116                    .count(0)
1117            }
1118        }
1119    };
1120}
1121
1122impl_forever_delay_per_packet!(StaticDelayPerPacketConfig);
1123impl_forever_delay_per_packet!(NormalizedDelayPerPacketConfig);
1124
1125impl Forever for RepeatedDelayPerPacketPatternConfig {
1126    fn forever(self) -> RepeatedDelayPerPacketPatternConfig {
1127        self.count(0)
1128    }
1129}
1130
1131#[cfg(test)]
1132mod test {
1133    use super::*;
1134    use crate::model::StaticDelayPerPacketConfig;
1135    use crate::DelayPerPacketTrace;
1136
1137    #[test]
1138    fn test_static_delay_model() {
1139        let mut static_delay = StaticDelayPerPacketConfig::new()
1140            .delay(Delay::from_millis(10))
1141            .count(1)
1142            .build();
1143        assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
1144        assert_eq!(static_delay.next_delay(), None);
1145    }
1146
1147    #[test]
1148    #[cfg(feature = "serde")]
1149    fn test_serde() {
1150        let a = vec![
1151            Box::new(
1152                StaticDelayPerPacketConfig::new()
1153                    .delay(Delay::from_millis(10))
1154                    .count(1),
1155            ) as Box<dyn DelayPerPacketTraceConfig>,
1156            Box::new(
1157                StaticDelayPerPacketConfig::new()
1158                    .delay(Delay::from_millis(20))
1159                    .count(1),
1160            ) as Box<dyn DelayPerPacketTraceConfig>,
1161        ];
1162        let ser = Box::new(
1163            RepeatedDelayPerPacketPatternConfig::new()
1164                .pattern(a)
1165                .count(2),
1166        ) as Box<dyn DelayPerPacketTraceConfig>;
1167        let ser_str = serde_json::to_string(&ser).unwrap();
1168        #[cfg(feature = "human")]
1169        let des_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
1170        #[cfg(not(feature = "human"))]
1171        let des_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
1172        assert_eq!(ser_str, des_str);
1173        let des: Box<dyn DelayPerPacketTraceConfig> = serde_json::from_str(des_str).unwrap();
1174        let mut model = des.into_model();
1175        assert_eq!(model.next_delay(), Some(Delay::from_millis(10)));
1176    }
1177}