mod user_stats_value;
use alloc::borrow::Cow;
use core::{fmt, num::NonZero};
use libafl_bolts::nonzero;
use serde::{Deserialize, Serialize};
pub use user_stats_value::*;
use super::manager::ClientStatsManager;
pub type UserStatsTag = NonZero<u64>;
pub const TAG_MAP: UserStatsTag = nonzero!(0xC07E9A6EC07E9A6E);
pub const TAG_AFL_STATS_CYCLES_DONE: UserStatsTag = nonzero!(0xAF157A75_C1C135D0);
pub const TAG_AFL_STATS_PENDING: UserStatsTag = nonzero!(0x0AF1_57A7_5934_D146);
pub const TAG_AFL_STATS_PENDING_FAVORED: UserStatsTag = nonzero!(0xAF157A75_934D146F);
pub const TAG_AFL_STATS_PENDING_FAV: UserStatsTag = nonzero!(0xAF157A75_FA1702ED);
pub const TAG_AFL_STATS_OWN_FINDS: UserStatsTag = nonzero!(0xAF157A75_0C4F11D5);
pub const TAG_AFL_STATS_IMPORTED: UserStatsTag = nonzero!(0xAF157A75_1AAF07ED);
pub const TAG_AFL_STATS_CYCLES_WO_FINDS: UserStatsTag = nonzero!(0xAF157A75_C1C0F1D5);
pub const TAG_CALIBRATE_STABILITY: UserStatsTag = nonzero!(0x57AB1117157AB171);
pub const TAG_CORE_ID: UserStatsTag = nonzero!(0xC093C093C093C093);
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum PlotConfig {
None,
Color(u8, u8, u8),
SimpleColor(u8),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct UserStats {
tag: Option<UserStatsTag>,
value: UserStatsValue,
aggregator_op: AggregatorOps,
}
impl UserStats {
#[must_use]
pub fn aggregator_op(&self) -> &AggregatorOps {
&self.aggregator_op
}
#[must_use]
pub fn value(&self) -> &UserStatsValue {
&self.value
}
#[must_use]
pub fn tag(&self) -> Option<UserStatsTag> {
self.tag
}
#[must_use]
pub fn new(value: UserStatsValue, aggregator_op: AggregatorOps) -> Self {
Self {
tag: None,
value,
aggregator_op,
}
}
#[must_use]
pub fn with_tag(
value: UserStatsValue,
aggregator_op: AggregatorOps,
tag: UserStatsTag,
) -> Self {
Self {
value,
aggregator_op,
tag: Some(tag),
}
}
}
impl fmt::Display for UserStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.value())
}
}
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
pub enum AggregatorOps {
None,
Sum,
Avg,
Min,
Max,
}
#[allow(clippy::ptr_arg)]
pub(super) fn aggregate_user_stats(
client_stats_manager: &mut ClientStatsManager,
name: &Cow<'static, str>,
) {
let mut gather = client_stats_manager
.client_stats()
.iter()
.filter_map(|(_, client)| client.user_stats.get(name.as_ref()));
let gather_count = gather.clone().count();
let (mut init, op) = match gather.next() {
Some(x) => (x.value().clone(), *x.aggregator_op()),
_ => {
return;
}
};
for item in gather {
match op {
AggregatorOps::None => {
return;
}
AggregatorOps::Avg | AggregatorOps::Sum => {
init = match init.stats_add(item.value()) {
Some(x) => x,
_ => {
return;
}
};
}
AggregatorOps::Min => {
init = match init.stats_min(item.value()) {
Some(x) => x,
_ => {
return;
}
};
}
AggregatorOps::Max => {
init = match init.stats_max(item.value()) {
Some(x) => x,
_ => {
return;
}
};
}
}
}
if let AggregatorOps::Avg = op {
init = match init.stats_div(gather_count) {
Some(x) => x,
_ => {
return;
}
}
}
client_stats_manager
.cached_aggregated_user_stats
.insert(name.clone(), init);
}