use crate::{Delay, DelayPerPacketTrace};
use dyn_clone::DynClone;
const DEFAULT_RNG_SEED: u64 = 42;
#[cfg_attr(feature = "serde", typetag::serde)]
pub trait DelayPerPacketTraceConfig: DynClone + Send + std::fmt::Debug {
fn into_model(self: Box<Self>) -> Box<dyn DelayPerPacketTrace>;
}
dyn_clone::clone_trait_object!(DelayPerPacketTraceConfig);
use rand::{rngs::StdRng, RngCore, SeedableRng};
use rand_distr::{Distribution, LogNormal, Normal};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "truncated-normal")]
use super::solve_truncate::solve;
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct StaticDelayPerPacket {
pub delay: Delay,
pub count: usize,
current_count: usize,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct StaticDelayPerPacketConfig {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub delay: Option<Delay>,
pub count: usize,
}
#[derive(Default)]
pub struct RepeatedDelayPerPacketPattern {
pub pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>,
pub count: usize,
current_model: Option<Box<dyn DelayPerPacketTrace>>,
current_cycle: usize,
current_pattern: usize,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
#[derive(Default, Debug, Clone)]
pub struct RepeatedDelayPerPacketPatternConfig {
pub pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>,
pub count: usize,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NormalizedDelayPerPacket<Rng = StdRng>
where
Rng: RngCore,
{
pub mean: Delay,
pub std_dev: Delay,
pub upper_bound: Option<Delay>,
pub lower_bound: Delay,
pub seed: u64,
pub count: usize,
current_count: usize,
rng: Rng,
normal: Normal<f64>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct NormalizedDelayPerPacketConfig {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub mean: Option<Delay>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub std_dev: Option<Delay>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub upper_bound: Option<Delay>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub lower_bound: Option<Delay>,
#[cfg_attr(feature = "serde", serde(default))]
pub count: usize,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub seed: Option<u64>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LogNormalizedDelayPerPacket<Rng = StdRng>
where
Rng: RngCore,
{
pub mean: Delay,
pub std_dev: Delay,
pub upper_bound: Option<Delay>,
pub lower_bound: Delay,
pub seed: u64,
pub count: usize,
current_count: usize,
rng: Rng,
log_normal: LogNormal<f64>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct LogNormalizedDelayPerPacketConfig {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub mean: Option<Delay>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub std_dev: Option<Delay>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub upper_bound: Option<Delay>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub lower_bound: Option<Delay>,
#[cfg_attr(feature = "serde", serde(default))]
pub count: usize,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub seed: Option<u64>,
}
impl DelayPerPacketTrace for StaticDelayPerPacket {
fn next_delay(&mut self) -> Option<Delay> {
if self.count != 0 && self.count == self.current_count {
None
} else {
self.current_count += 1;
Some(self.delay)
}
}
}
impl DelayPerPacketTrace for RepeatedDelayPerPacketPattern {
fn next_delay(&mut self) -> Option<Delay> {
if self.pattern.is_empty() || (self.count != 0 && self.current_cycle >= self.count) {
None
} else {
if self.current_model.is_none() {
self.current_model = Some(self.pattern[self.current_pattern].clone().into_model());
}
match self.current_model.as_mut().unwrap().next_delay() {
Some(delay) => Some(delay),
None => {
self.current_model = None;
self.current_pattern += 1;
if self.current_pattern >= self.pattern.len() {
self.current_pattern = 0;
self.current_cycle += 1;
if self.count != 0 && self.current_cycle >= self.count {
return None;
}
}
self.next_delay()
}
}
}
}
}
impl<Rng: RngCore + Send> DelayPerPacketTrace for NormalizedDelayPerPacket<Rng> {
fn next_delay(&mut self) -> Option<Delay> {
if self.count != 0 && self.count == self.current_count {
None
} else {
self.current_count += 1;
let delay = self.normal.sample(&mut self.rng).max(0.0);
let mut delay = Delay::from_secs_f64(delay);
delay = delay.max(self.lower_bound);
if let Some(upper_bound) = self.upper_bound {
delay = delay.min(upper_bound);
}
Some(delay)
}
}
}
impl<Rng: RngCore + Send> DelayPerPacketTrace for LogNormalizedDelayPerPacket<Rng> {
fn next_delay(&mut self) -> Option<Delay> {
if self.count != 0 && self.count == self.current_count {
None
} else {
self.current_count += 1;
let delay = self.log_normal.sample(&mut self.rng).max(0.0);
let mut delay = Delay::from_secs_f64(delay);
delay = delay.max(self.lower_bound);
if let Some(upper_bound) = self.upper_bound {
delay = delay.min(upper_bound);
}
Some(delay)
}
}
}
impl StaticDelayPerPacketConfig {
pub fn new() -> Self {
Self {
delay: None,
count: 0,
}
}
pub fn delay(mut self, delay: Delay) -> Self {
self.delay = Some(delay);
self
}
pub fn count(mut self, count: usize) -> Self {
self.count = count;
self
}
pub fn build(self) -> StaticDelayPerPacket {
StaticDelayPerPacket {
delay: self.delay.unwrap_or_else(|| Delay::from_millis(10)),
count: self.count,
current_count: 0,
}
}
}
impl RepeatedDelayPerPacketPatternConfig {
pub fn new() -> Self {
Self {
pattern: vec![],
count: 0,
}
}
pub fn pattern(mut self, pattern: Vec<Box<dyn DelayPerPacketTraceConfig>>) -> Self {
self.pattern = pattern;
self
}
pub fn count(mut self, count: usize) -> Self {
self.count = count;
self
}
pub fn build(self) -> RepeatedDelayPerPacketPattern {
RepeatedDelayPerPacketPattern {
pattern: self.pattern,
count: self.count,
current_model: None,
current_cycle: 0,
current_pattern: 0,
}
}
}
impl NormalizedDelayPerPacketConfig {
pub fn new() -> Self {
Self {
mean: None,
std_dev: None,
upper_bound: None,
lower_bound: None,
count: 0,
seed: None,
}
}
pub fn mean(mut self, mean: Delay) -> Self {
self.mean = Some(mean);
self
}
pub fn std_dev(mut self, std_dev: Delay) -> Self {
self.std_dev = Some(std_dev);
self
}
pub fn upper_bound(mut self, upper_bound: Delay) -> Self {
self.upper_bound = Some(upper_bound);
self
}
pub fn lower_bound(mut self, lower_bound: Delay) -> Self {
self.lower_bound = Some(lower_bound);
self
}
pub fn count(mut self, count: usize) -> Self {
self.count = count;
self
}
pub fn seed(mut self, seed: u64) -> Self {
self.seed = Some(seed);
self
}
pub fn random_seed(mut self) -> Self {
self.seed = Some(rand::random());
self
}
pub fn build(self) -> NormalizedDelayPerPacket {
self.build_with_rng()
}
pub fn build_with_rng<Rng: RngCore + SeedableRng>(self) -> NormalizedDelayPerPacket<Rng> {
let mean = self.mean.unwrap_or_else(|| Delay::from_millis(10));
let std_dev = self.std_dev.unwrap_or(Delay::ZERO);
let upper_bound = self.upper_bound;
let lower_bound = self.lower_bound.unwrap_or(Delay::ZERO);
let count = self.count;
let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
let rng = Rng::seed_from_u64(seed);
let delay_mean = mean.as_secs_f64();
let delay_std_dev = std_dev.as_secs_f64();
let normal: Normal<f64> = Normal::new(delay_mean, delay_std_dev).unwrap();
NormalizedDelayPerPacket {
mean,
std_dev,
upper_bound,
lower_bound,
count,
current_count: 0,
seed,
rng,
normal,
}
}
}
#[cfg(feature = "truncated-normal")]
impl NormalizedDelayPerPacketConfig {
pub fn build_truncated(self) -> NormalizedDelayPerPacket {
self.build_truncated_with_rng()
}
pub fn build_truncated_with_rng<Rng: SeedableRng + RngCore>(
mut self,
) -> NormalizedDelayPerPacket<Rng> {
let mean = self
.mean
.unwrap_or_else(|| Delay::from_millis(12))
.as_secs_f64();
let sigma = self.std_dev.unwrap_or(Delay::ZERO).as_secs_f64() / mean;
let lower = self.lower_bound.unwrap_or(Delay::ZERO).as_secs_f64() / mean;
let upper = self.upper_bound.map(|upper| upper.as_secs_f64() / mean);
let new_mean = mean * solve(1f64, sigma, Some(lower), upper).unwrap_or(1f64);
self.mean = Some(Delay::from_secs_f64(new_mean));
self.build_with_rng()
}
}
impl LogNormalizedDelayPerPacketConfig {
pub fn new() -> Self {
Self {
mean: None,
std_dev: None,
upper_bound: None,
lower_bound: None,
count: 0,
seed: None,
}
}
pub fn mean(mut self, mean: Delay) -> Self {
self.mean = Some(mean);
self
}
pub fn std_dev(mut self, std_dev: Delay) -> Self {
self.std_dev = Some(std_dev);
self
}
pub fn upper_bound(mut self, upper_bound: Delay) -> Self {
self.upper_bound = Some(upper_bound);
self
}
pub fn lower_bound(mut self, lower_bound: Delay) -> Self {
self.lower_bound = Some(lower_bound);
self
}
pub fn count(mut self, count: usize) -> Self {
self.count = count;
self
}
pub fn seed(mut self, seed: u64) -> Self {
self.seed = Some(seed);
self
}
pub fn random_seed(mut self) -> Self {
self.seed = Some(rand::random());
self
}
pub fn build(self) -> LogNormalizedDelayPerPacket {
self.build_with_rng()
}
pub fn build_with_rng<Rng: SeedableRng + RngCore>(self) -> LogNormalizedDelayPerPacket<Rng> {
let mean = self.mean.unwrap_or_else(|| Delay::from_millis(10));
let std_dev = self.std_dev.unwrap_or(Delay::ZERO);
let upper_bound = self.upper_bound;
let lower_bound = self.lower_bound.unwrap_or(Delay::ZERO);
let count = self.count;
let seed = self.seed.unwrap_or(DEFAULT_RNG_SEED);
let rng = Rng::seed_from_u64(seed);
let delay_mean = mean.as_secs_f64();
let delay_std_dev = std_dev.as_secs_f64();
let normal_std_dev = f64::sqrt(f64::ln(
1.0 + (delay_std_dev.powi(2)) / (delay_mean.powi(2)),
));
let normal_mean = f64::ln(delay_mean) - normal_std_dev.powi(2) / 2.;
let log_normal: LogNormal<f64> = LogNormal::new(normal_mean, normal_std_dev).unwrap();
LogNormalizedDelayPerPacket {
mean,
std_dev,
upper_bound,
lower_bound,
count,
current_count: 0,
seed,
rng,
log_normal,
}
}
}
macro_rules! impl_delay_per_packet_trace_config {
($name:ident) => {
#[cfg_attr(feature = "serde", typetag::serde)]
impl DelayPerPacketTraceConfig for $name {
fn into_model(self: Box<$name>) -> Box<dyn DelayPerPacketTrace> {
Box::new(self.build())
}
}
};
}
impl_delay_per_packet_trace_config!(StaticDelayPerPacketConfig);
impl_delay_per_packet_trace_config!(NormalizedDelayPerPacketConfig);
impl_delay_per_packet_trace_config!(LogNormalizedDelayPerPacketConfig);
impl_delay_per_packet_trace_config!(RepeatedDelayPerPacketPatternConfig);
impl<Model: DelayPerPacketTrace + 'static> From<Model> for Box<dyn DelayPerPacketTrace> {
fn from(model: Model) -> Self {
Box::new(model)
}
}
pub trait Forever: DelayPerPacketTraceConfig {
fn forever(self) -> RepeatedDelayPerPacketPatternConfig;
}
#[macro_export]
macro_rules! impl_forever_delay_per_packet {
($name:ident) => {
impl Forever for $name {
fn forever(self) -> RepeatedDelayPerPacketPatternConfig {
RepeatedDelayPerPacketPatternConfig::new()
.pattern(vec![Box::new(self)])
.count(0)
}
}
};
}
impl_forever_delay_per_packet!(StaticDelayPerPacketConfig);
impl_forever_delay_per_packet!(NormalizedDelayPerPacketConfig);
impl Forever for RepeatedDelayPerPacketPatternConfig {
fn forever(self) -> RepeatedDelayPerPacketPatternConfig {
self.count(0)
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::model::StaticDelayPerPacketConfig;
use crate::DelayPerPacketTrace;
#[test]
fn test_static_delay_model() {
let mut static_delay = StaticDelayPerPacketConfig::new()
.delay(Delay::from_millis(10))
.count(1)
.build();
assert_eq!(static_delay.next_delay(), Some(Delay::from_millis(10)));
assert_eq!(static_delay.next_delay(), None);
}
#[test]
#[cfg(feature = "serde")]
fn test_serde() {
let a = vec![
Box::new(
StaticDelayPerPacketConfig::new()
.delay(Delay::from_millis(10))
.count(1),
) as Box<dyn DelayPerPacketTraceConfig>,
Box::new(
StaticDelayPerPacketConfig::new()
.delay(Delay::from_millis(20))
.count(1),
) as Box<dyn DelayPerPacketTraceConfig>,
];
let ser = Box::new(
RepeatedDelayPerPacketPatternConfig::new()
.pattern(a)
.count(2),
) as Box<dyn DelayPerPacketTraceConfig>;
let ser_str = serde_json::to_string(&ser).unwrap();
#[cfg(feature = "human")]
let des_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":\"10ms\",\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":\"20ms\",\"count\":1}}],\"count\":2}}";
#[cfg(not(feature = "human"))]
let des_str = "{\"RepeatedDelayPerPacketPatternConfig\":{\"pattern\":[{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":10000000},\"count\":1}},{\"StaticDelayPerPacketConfig\":{\"delay\":{\"secs\":0,\"nanos\":20000000},\"count\":1}}],\"count\":2}}";
assert_eq!(ser_str, des_str);
let des: Box<dyn DelayPerPacketTraceConfig> = serde_json::from_str(des_str).unwrap();
let mut model = des.into_model();
assert_eq!(model.next_delay(), Some(Delay::from_millis(10)));
}
}