use crate::core::grammar::GrammarState;
use crate::core::heuristics::EngineReasonCode;
use crate::core::envelope::EnvelopeStatus;
#[derive(Debug, Clone, Copy)]
pub struct AuditEntry {
pub cycle: u32,
pub residual: f64,
pub drift: f64,
pub slew: f64,
pub envelope_position: f64,
pub envelope_status: EnvelopeStatus,
pub grammar_state: GrammarState,
pub reason_code: EngineReasonCode,
pub drift_persistence: u32,
pub slew_persistence: u32,
}
pub const AUDIT_TRAIL_CAPACITY: usize = 512;
#[derive(Debug)]
pub struct AuditTrail {
entries: [AuditEntry; AUDIT_TRAIL_CAPACITY],
len: usize,
}
impl AuditTrail {
#[must_use]
pub fn new() -> Self {
Self {
entries: [AuditEntry {
cycle: 0,
residual: 0.0,
drift: 0.0,
slew: 0.0,
envelope_position: 0.0,
envelope_status: EnvelopeStatus::Interior,
grammar_state: GrammarState::Admissible,
reason_code: EngineReasonCode::NoAnomaly,
drift_persistence: 0,
slew_persistence: 0,
}; AUDIT_TRAIL_CAPACITY],
len: 0,
}
}
pub fn push(&mut self, entry: AuditEntry) {
if self.len < AUDIT_TRAIL_CAPACITY {
self.entries[self.len] = entry;
self.len += 1;
}
}
#[must_use]
pub const fn len(&self) -> usize {
self.len
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[must_use]
pub fn entries(&self) -> &[AuditEntry] {
&self.entries[..self.len]
}
#[must_use]
pub fn first_state(&self, state: GrammarState) -> Option<&AuditEntry> {
let mut i = 0;
while i < self.len {
if self.entries[i].grammar_state == state {
return Some(&self.entries[i]);
}
i += 1;
}
None
}
}
impl Default for AuditTrail {
fn default() -> Self {
Self::new()
}
}