use crate::{DuplicatePattern, DuplicateTrace, Duration};
use dyn_clone::DynClone;
#[cfg_attr(feature = "serde", typetag::serde)]
pub trait DuplicateTraceConfig: DynClone + Send {
fn into_model(self: Box<Self>) -> Box<dyn DuplicateTrace>;
}
dyn_clone::clone_trait_object!(DuplicateTraceConfig);
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
pub struct StaticDuplicate {
pub duplicate: DuplicatePattern,
pub duration: Option<Duration>,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
#[derive(Debug, Clone, Default)]
pub struct StaticDuplicateConfig {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
pub duplicate: Option<DuplicatePattern>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(
all(feature = "serde", feature = "human"),
serde(with = "humantime_serde")
)]
pub duration: Option<Duration>,
}
pub struct RepeatedDuplicatePattern {
pub pattern: Vec<Box<dyn DuplicateTraceConfig>>,
pub count: usize,
current_model: Option<Box<dyn DuplicateTrace>>,
current_cycle: usize,
current_pattern: usize,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(default))]
#[derive(Default, Clone)]
pub struct RepeatedDuplicatePatternConfig {
pub pattern: Vec<Box<dyn DuplicateTraceConfig>>,
pub count: usize,
}
impl DuplicateTrace for StaticDuplicate {
fn next_duplicate(&mut self) -> Option<(DuplicatePattern, Duration)> {
if let Some(duration) = self.duration.take() {
if duration.is_zero() {
None
} else {
Some((self.duplicate.clone(), duration))
}
} else {
None
}
}
}
impl DuplicateTrace for RepeatedDuplicatePattern {
fn next_duplicate(&mut self) -> Option<(DuplicatePattern, Duration)> {
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_duplicate() {
Some(duplicate) => Some(duplicate),
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_duplicate()
}
}
}
}
}
impl StaticDuplicateConfig {
pub fn new() -> Self {
Self {
duplicate: None,
duration: None,
}
}
pub fn duplicate(mut self, duplicate: DuplicatePattern) -> Self {
self.duplicate = Some(duplicate);
self
}
pub fn duration(mut self, duration: Duration) -> Self {
self.duration = Some(duration);
self
}
pub fn build(self) -> StaticDuplicate {
StaticDuplicate {
duplicate: self.duplicate.unwrap_or_else(|| vec![0.1, 0.2]),
duration: Some(self.duration.unwrap_or_else(|| Duration::from_secs(1))),
}
}
}
impl RepeatedDuplicatePatternConfig {
pub fn new() -> Self {
Self {
pattern: vec![],
count: 0,
}
}
pub fn pattern(mut self, pattern: Vec<Box<dyn DuplicateTraceConfig>>) -> Self {
self.pattern = pattern;
self
}
pub fn count(mut self, count: usize) -> Self {
self.count = count;
self
}
pub fn build(self) -> RepeatedDuplicatePattern {
RepeatedDuplicatePattern {
pattern: self.pattern,
count: self.count,
current_model: None,
current_cycle: 0,
current_pattern: 0,
}
}
}
macro_rules! impl_duplicate_trace_config {
($name:ident) => {
#[cfg_attr(feature = "serde", typetag::serde)]
impl DuplicateTraceConfig for $name {
fn into_model(self: Box<$name>) -> Box<dyn DuplicateTrace> {
Box::new(self.build())
}
}
};
}
impl_duplicate_trace_config!(StaticDuplicateConfig);
impl_duplicate_trace_config!(RepeatedDuplicatePatternConfig);
#[cfg(test)]
mod test {
use super::*;
use crate::model::StaticDuplicateConfig;
use crate::DuplicateTrace;
#[test]
fn test_static_loss_model() {
let mut static_loss = StaticDuplicateConfig::new()
.duplicate(vec![0.1, 0.2])
.duration(Duration::from_secs(1))
.build();
assert_eq!(
static_loss.next_duplicate(),
Some((vec![0.1, 0.2], Duration::from_secs(1)))
);
assert_eq!(static_loss.next_duplicate(), None);
}
#[test]
#[cfg(feature = "serde")]
fn test_serde() {
let a = vec![
Box::new(
StaticDuplicateConfig::new()
.duplicate(vec![0.1, 0.2])
.duration(Duration::from_secs(1)),
) as Box<dyn DuplicateTraceConfig>,
Box::new(
StaticDuplicateConfig::new()
.duplicate(vec![0.2, 0.4])
.duration(Duration::from_secs(1)),
) as Box<dyn DuplicateTraceConfig>,
];
let ser = Box::new(RepeatedDuplicatePatternConfig::new().pattern(a).count(2))
as Box<dyn DuplicateTraceConfig>;
let ser_str = serde_json::to_string(&ser).unwrap();
#[cfg(feature = "human")]
let des_str = "{\"RepeatedDuplicatePatternConfig\":{\"pattern\":[{\"StaticDuplicateConfig\":{\"duplicate\":[0.1,0.2],\"duration\":\"1s\"}},{\"StaticDuplicateConfig\":{\"duplicate\":[0.2,0.4],\"duration\":\"1s\"}}],\"count\":2}}";
#[cfg(not(feature = "human"))]
let des_str = "{\"RepeatedDuplicatePatternConfig\":{\"pattern\":[{\"StaticDuplicateConfig\":{\"duplicate\":[0.1,0.2],\"duration\":{\"secs\":1,\"nanos\":0}}},{\"StaticDuplicateConfig\":{\"duplicate\":[0.2,0.4],\"duration\":{\"secs\":1,\"nanos\":0}}}],\"count\":2}}";
assert_eq!(ser_str, des_str);
let des: Box<dyn DuplicateTraceConfig> = serde_json::from_str(des_str).unwrap();
let mut model = des.into_model();
assert_eq!(
model.next_duplicate(),
Some((vec![0.1, 0.2], Duration::from_secs(1)))
);
}
}