mod contributors;
mod ring;
mod sample;
mod view;
pub use contributors::{
Contributor, ContributorMetric, ContributorSet, ContributorTrend, MAX_RETAINED_COMMAND_WIDTH,
MAX_RETAINED_NAME_WIDTH, MetricContributors,
};
pub use ring::{
ClampReason, ClampedValue, DEFAULT_HISTORY_DURATION, DEFAULT_MEMORY_BUDGET_BYTES,
DEFAULT_SAMPLE_INTERVAL, DEFAULT_TOP_CONTRIBUTORS_PER_METRIC, HistoryClamp, HistoryConfig,
HistoryField, HistoryLimits, HistoryRing, MAX_HISTORY_DURATION, MAX_MEMORY_BUDGET_BYTES,
MAX_SAMPLE_INTERVAL, MAX_TOP_CONTRIBUTORS_PER_METRIC, MIN_HISTORY_DURATION,
MIN_MEMORY_BUDGET_BYTES, MIN_SAMPLE_INTERVAL, RecordOutcome,
};
pub use sample::{HistoricalSample, HistoricalSystemMetrics, HistoryMetric};
pub use view::{
COMPARISON_LOOKBACK, ComparisonBaseline, HISTORY_STEP_MULTIPLIER, HistoryPosition, HistoryView,
MetricComparison, MetricComparisons, SeekOutcome,
};
use crate::model::{MetricState, UnavailableReason};
const fn unavailable_rank<T>(state: &MetricState<T>) -> u8 {
match state {
MetricState::PermissionDenied => 4,
MetricState::TemporarilyUnavailable(_) => 3,
MetricState::Stale { .. } => 2,
MetricState::WarmingUp => 1,
MetricState::Unsupported | MetricState::Available(_) => 0,
}
}
fn most_representative<T>(
current: Option<MetricState<T>>,
candidate: MetricState<T>,
) -> MetricState<T> {
match current {
Some(current) if unavailable_rank(¤t) >= unavailable_rank(&candidate) => current,
_ => candidate,
}
}
fn propagate_unavailable<T, U>(state: MetricState<T>) -> MetricState<U> {
match state {
MetricState::Available(_) | MetricState::Stale { .. } => {
MetricState::TemporarilyUnavailable(UnavailableReason::NeedsSecondSample)
}
MetricState::WarmingUp => MetricState::WarmingUp,
MetricState::PermissionDenied => MetricState::PermissionDenied,
MetricState::Unsupported => MetricState::Unsupported,
MetricState::TemporarilyUnavailable(reason) => MetricState::TemporarilyUnavailable(reason),
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::time::Duration;
#[test]
fn a_permission_problem_outranks_every_other_explanation() {
let group: MetricState<u64> =
most_representative(Some(MetricState::WarmingUp), MetricState::PermissionDenied);
assert_eq!(group, MetricState::PermissionDenied);
let group: MetricState<u64> = most_representative(
Some(MetricState::PermissionDenied),
MetricState::TemporarilyUnavailable(UnavailableReason::CounterReset),
);
assert_eq!(group, MetricState::PermissionDenied);
}
#[test]
fn a_typed_transient_reason_beats_warming_up_and_unsupported() {
let reset = MetricState::TemporarilyUnavailable(UnavailableReason::CounterReset);
let group: MetricState<u64> = most_representative(Some(MetricState::Unsupported), reset);
assert_eq!(group, reset);
let group: MetricState<u64> = most_representative(Some(reset), MetricState::WarmingUp);
assert_eq!(group, reset);
}
#[test]
fn the_first_candidate_is_kept_when_nothing_is_ranked_yet() {
let group: MetricState<u64> = most_representative(None, MetricState::Unsupported);
assert_eq!(group, MetricState::Unsupported);
}
#[test]
fn propagation_preserves_the_reason_a_metric_was_missing() {
let denied: MetricState<u64> = MetricState::PermissionDenied;
assert_eq!(
propagate_unavailable::<u64, f32>(denied),
MetricState::PermissionDenied
);
let reset: MetricState<u64> =
MetricState::TemporarilyUnavailable(UnavailableReason::CounterReset);
assert_eq!(
propagate_unavailable::<u64, f32>(reset),
MetricState::TemporarilyUnavailable(UnavailableReason::CounterReset)
);
assert_eq!(
propagate_unavailable::<u64, f32>(MetricState::Unsupported),
MetricState::Unsupported
);
assert_eq!(
propagate_unavailable::<u64, f32>(MetricState::WarmingUp),
MetricState::WarmingUp
);
}
#[test]
fn a_retained_stale_reading_never_becomes_a_derived_total() {
let stale = MetricState::Stale {
value: 7u64,
age: Duration::from_secs(4),
};
assert_eq!(
propagate_unavailable::<u64, f32>(stale),
MetricState::TemporarilyUnavailable(UnavailableReason::NeedsSecondSample)
);
}
}