use core::fmt::{self, Write}; use crate::sync::SyncUnsafe; const BUF_SIZE: usize = 65536; pub struct FlightRecorder { buf: [u8; BUF_SIZE], cursor: usize, total_written: usize, } impl FlightRecorder { const fn new() -> Self { Self { buf: [0u8; BUF_SIZE], cursor: 0, total_written: 0, } } pub fn append( &mut self, tsc: u64, severity: lancer_log::Severity, domain: &str, message: fmt::Arguments<'_>, ) { let letter = match severity { lancer_log::Severity::Error => 'E', lancer_log::Severity::Warn => 'W', lancer_log::Severity::Info => 'I', lancer_log::Severity::Debug => 'D', }; let _ = writeln!(self, "{:012} {} {:6} {}", tsc, letter, domain, message); } fn write_byte(&mut self, byte: u8) { self.buf[self.cursor] = byte; self.cursor = (self.cursor + 1) % BUF_SIZE; self.total_written += 1; } #[allow(dead_code)] pub fn total_written(&self) -> usize { self.total_written } pub fn read(&self, cursor: usize, dst: &mut [u8]) -> (usize, usize) { let oldest_valid = self.total_written.saturating_sub(BUF_SIZE); let start = match cursor < oldest_valid { true => self.fast_forward(oldest_valid), false => cursor, }; let available = self.total_written.saturating_sub(start); let copy_len = available.min(dst.len()); (0..copy_len).fold((), |(), i| { let ring_idx = (start + i) % BUF_SIZE; dst[i] = self.buf[ring_idx]; }); (start + copy_len, copy_len) } fn fast_forward(&self, oldest_valid: usize) -> usize { let search_len = self.total_written.saturating_sub(oldest_valid).min(BUF_SIZE); (0..search_len) .find(|&i| { let ring_idx = (oldest_valid + i) % BUF_SIZE; self.buf[ring_idx] == b'\n' }) .map(|i| oldest_valid + i + 1) .unwrap_or(self.total_written) } } impl Write for FlightRecorder { fn write_str(&mut self, s: &str) -> fmt::Result { s.as_bytes().iter().for_each(|&b| self.write_byte(b)); Ok(()) } } static FLIGHT: SyncUnsafe = SyncUnsafe::new(FlightRecorder::new()); #[allow(clippy::deref_addrof)] pub fn recorder() -> &'static mut FlightRecorder { unsafe { &mut *FLIGHT.get() } }