Nothing to see here, move along
1use core::fmt::{self, Write};
2
3use crate::sync::SyncUnsafe;
4
5const BUF_SIZE: usize = 65536;
6
7pub struct FlightRecorder {
8 buf: [u8; BUF_SIZE],
9 cursor: usize,
10 total_written: usize,
11}
12
13impl FlightRecorder {
14 const fn new() -> Self {
15 Self {
16 buf: [0u8; BUF_SIZE],
17 cursor: 0,
18 total_written: 0,
19 }
20 }
21
22 pub fn append(
23 &mut self,
24 tsc: u64,
25 severity: lancer_log::Severity,
26 domain: &str,
27 message: fmt::Arguments<'_>,
28 ) {
29 let letter = match severity {
30 lancer_log::Severity::Error => 'E',
31 lancer_log::Severity::Warn => 'W',
32 lancer_log::Severity::Info => 'I',
33 lancer_log::Severity::Debug => 'D',
34 };
35 let _ = writeln!(self, "{:012} {} {:6} {}", tsc, letter, domain, message);
36 }
37
38 fn write_byte(&mut self, byte: u8) {
39 self.buf[self.cursor] = byte;
40 self.cursor = (self.cursor + 1) % BUF_SIZE;
41 self.total_written += 1;
42 }
43
44 #[allow(dead_code)]
45 pub fn total_written(&self) -> usize {
46 self.total_written
47 }
48
49 pub fn read(&self, cursor: usize, dst: &mut [u8]) -> (usize, usize) {
50 let oldest_valid = self.total_written.saturating_sub(BUF_SIZE);
51 let start = match cursor < oldest_valid {
52 true => self.fast_forward(oldest_valid),
53 false => cursor,
54 };
55
56 let available = self.total_written.saturating_sub(start);
57 let copy_len = available.min(dst.len());
58
59 (0..copy_len).fold((), |(), i| {
60 let ring_idx = (start + i) % BUF_SIZE;
61 dst[i] = self.buf[ring_idx];
62 });
63
64 (start + copy_len, copy_len)
65 }
66
67 fn fast_forward(&self, oldest_valid: usize) -> usize {
68 let search_len = self.total_written.saturating_sub(oldest_valid).min(BUF_SIZE);
69 (0..search_len)
70 .find(|&i| {
71 let ring_idx = (oldest_valid + i) % BUF_SIZE;
72 self.buf[ring_idx] == b'\n'
73 })
74 .map(|i| oldest_valid + i + 1)
75 .unwrap_or(self.total_written)
76 }
77}
78
79impl Write for FlightRecorder {
80 fn write_str(&mut self, s: &str) -> fmt::Result {
81 s.as_bytes().iter().for_each(|&b| self.write_byte(b));
82 Ok(())
83 }
84}
85
86static FLIGHT: SyncUnsafe<FlightRecorder> = SyncUnsafe::new(FlightRecorder::new());
87
88#[allow(clippy::deref_addrof)]
89pub fn recorder() -> &'static mut FlightRecorder {
90 unsafe { &mut *FLIGHT.get() }
91}