1use super::config::MAX_LOG_MESSAGE_LENGTH;
7use super::level::LogLevel;
8use core::cmp::min;
9use core::fmt::{self, Write};
10use core::sync::atomic::{AtomicUsize, Ordering};
11
12#[repr(C, align(8))]
19#[derive(Debug)]
20pub struct LogEntry {
21 seq: AtomicUsize,
23 level: LogLevel,
25 cpu_id: usize,
27 length: usize,
29 task_id: u32,
31 timestamp: usize,
33 message: [u8; MAX_LOG_MESSAGE_LENGTH],
35}
36
37impl LogEntry {
38 pub const fn empty() -> Self {
43 Self {
44 seq: AtomicUsize::new(0),
45 level: LogLevel::Debug,
46 cpu_id: 0,
47 length: 0,
48 task_id: 0,
49 timestamp: 0,
50 message: [0; MAX_LOG_MESSAGE_LENGTH],
51 }
52 }
53
54 pub(super) fn from_args(
64 level: LogLevel,
65 cpu_id: usize,
66 task_id: u32,
67 timestamp: usize,
68 args: fmt::Arguments,
69 ) -> Self {
70 let mut entry = Self {
71 seq: AtomicUsize::new(0),
72 level,
73 cpu_id,
74 length: 0,
75 task_id,
76 timestamp,
77 message: [0; MAX_LOG_MESSAGE_LENGTH],
78 };
79
80 let mut writer = MessageWriter::new(&mut entry.message);
82 let _ = core::fmt::write(&mut writer, args);
83
84 entry.length = writer.len();
85
86 entry
87 }
88
89 pub fn message(&self) -> &str {
91 unsafe { core::str::from_utf8_unchecked(&self.message[..self.length]) }
93 }
94
95 pub fn level(&self) -> LogLevel {
97 self.level
98 }
99
100 pub fn cpu_id(&self) -> usize {
102 self.cpu_id
103 }
104
105 pub fn task_id(&self) -> u32 {
107 self.task_id
108 }
109
110 pub fn timestamp(&self) -> usize {
112 self.timestamp
113 }
114}
115
116impl LogEntry {
117 pub(super) unsafe fn copy_data_to(&self, dest: *mut LogEntry) {
126 unsafe {
129 (*dest).level = self.level;
130 (*dest).cpu_id = self.cpu_id;
131 (*dest).length = self.length;
132 (*dest).task_id = self.task_id;
133 (*dest).timestamp = self.timestamp;
134 (*dest).message.copy_from_slice(&self.message);
135 }
136 }
137
138 pub(super) unsafe fn publish(&self, dest: *mut LogEntry, seq_num: usize) {
147 unsafe {
150 (*dest).seq.store(seq_num, Ordering::Release);
151 }
152 }
153
154 pub(super) unsafe fn is_ready(&self, slot_ptr: *const LogEntry, expected_seq: usize) -> bool {
163 unsafe { (*slot_ptr).seq.load(Ordering::Acquire) == expected_seq }
165 }
166}
167
168impl Clone for LogEntry {
169 fn clone(&self) -> Self {
170 Self {
171 seq: AtomicUsize::new(self.seq.load(Ordering::Relaxed)),
172 level: self.level,
173 cpu_id: self.cpu_id,
174 length: self.length,
175 task_id: self.task_id,
176 timestamp: self.timestamp,
177 message: self.message,
178 }
179 }
180}
181
182impl fmt::Display for LogEntry {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 write!(
185 f,
186 "[{:12}] [{}] [CPU{}/T{:3}] {}",
187 self.timestamp,
188 self.level.as_str(),
189 self.cpu_id,
190 self.task_id,
191 self.message()
192 )
193 }
194}
195
196struct MessageWriter<'a> {
201 buffer: &'a mut [u8],
202 pos: usize,
203}
204
205impl<'a> MessageWriter<'a> {
206 fn new(buffer: &'a mut [u8]) -> Self {
208 Self { buffer, pos: 0 }
209 }
210
211 fn len(&self) -> usize {
213 self.pos
214 }
215}
216
217impl Write for MessageWriter<'_> {
218 fn write_str(&mut self, s: &str) -> fmt::Result {
220 let bytes = s.as_bytes();
221 let remaining = self.buffer.get_mut(self.pos..).unwrap_or(&mut []);
222 let to_copy = min(bytes.len(), remaining.len());
223
224 remaining[..to_copy].copy_from_slice(&bytes[..to_copy]);
225 self.pos += to_copy;
226 Ok(())
227 }
228}