use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Default)]
pub struct Metrics {
pub verifications: AtomicU64,
pub trusted: AtomicU64,
pub valid: AtomicU64,
pub invalid: AtomicU64,
pub no_manifest: AtomicU64,
pub errors: AtomicU64,
pub panics: AtomicU64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct MetricsSnapshot {
pub verifications: u64,
pub trusted: u64,
pub valid: u64,
pub invalid: u64,
pub no_manifest: u64,
pub errors: u64,
pub panics: u64,
}
impl Metrics {
pub const fn new() -> Self {
Metrics {
verifications: AtomicU64::new(0),
trusted: AtomicU64::new(0),
valid: AtomicU64::new(0),
invalid: AtomicU64::new(0),
no_manifest: AtomicU64::new(0),
errors: AtomicU64::new(0),
panics: AtomicU64::new(0),
}
}
pub fn record_state(&self, state: crate::c2pa_validate::ValidationState) {
self.verifications.fetch_add(1, Ordering::Relaxed);
match state {
crate::c2pa_validate::ValidationState::Trusted => &self.trusted,
crate::c2pa_validate::ValidationState::Valid => &self.valid,
crate::c2pa_validate::ValidationState::Invalid => &self.invalid,
crate::c2pa_validate::ValidationState::None => &self.no_manifest,
}
.fetch_add(1, Ordering::Relaxed);
}
pub fn record_no_manifest(&self) {
self.no_manifest.fetch_add(1, Ordering::Relaxed);
}
pub fn record_error(&self) {
self.errors.fetch_add(1, Ordering::Relaxed);
}
pub fn record_panic(&self) {
self.panics.fetch_add(1, Ordering::Relaxed);
}
pub fn snapshot(&self) -> MetricsSnapshot {
MetricsSnapshot {
verifications: self.verifications.load(Ordering::Relaxed),
trusted: self.trusted.load(Ordering::Relaxed),
valid: self.valid.load(Ordering::Relaxed),
invalid: self.invalid.load(Ordering::Relaxed),
no_manifest: self.no_manifest.load(Ordering::Relaxed),
errors: self.errors.load(Ordering::Relaxed),
panics: self.panics.load(Ordering::Relaxed),
}
}
}
pub fn global() -> &'static Metrics {
static GLOBAL: Metrics = Metrics::new();
&GLOBAL
}
#[cfg(test)]
mod tests {
use super::*;
use crate::c2pa_validate::ValidationState;
#[test]
fn counts_states() {
let m = Metrics::new();
m.record_state(ValidationState::Trusted);
m.record_state(ValidationState::Valid);
m.record_state(ValidationState::Invalid);
m.record_state(ValidationState::Invalid);
m.record_no_manifest();
m.record_error();
m.record_panic();
let s = m.snapshot();
assert_eq!(s.verifications, 4);
assert_eq!(s.trusted, 1);
assert_eq!(s.valid, 1);
assert_eq!(s.invalid, 2);
assert_eq!(s.no_manifest, 1);
assert_eq!(s.errors, 1);
assert_eq!(s.panics, 1);
}
#[test]
fn global_is_shared() {
let before = global().snapshot().verifications;
global().record_state(ValidationState::Valid);
assert_eq!(global().snapshot().verifications, before + 1);
}
}