1use std::{
2 convert::TryFrom,
3 fmt::{self, Write as _},
4 mem,
5};
6
7use crate::{Arg, BitflagsKey, Table};
8use colored::Colorize;
9use defmt_parser::{DisplayHint, Fragment, Level, ParserMode, TimePrecision, Type};
10use time::{macros::format_description, OffsetDateTime};
11
12struct I128Hex(i128, Type);
14
15impl std::fmt::LowerHex for I128Hex {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 match self.1 {
18 Type::I8 => fmt::LowerHex::fmt(&(self.0 as i8), f),
19 Type::I16 => fmt::LowerHex::fmt(&(self.0 as i16), f),
20 Type::I32 => fmt::LowerHex::fmt(&(self.0 as i32), f),
21 Type::I64 => fmt::LowerHex::fmt(&(self.0 as i64), f),
22 Type::I128 => fmt::LowerHex::fmt(&self.0, f),
23 _ => panic!("Unsupported type '{:?}' found.", self.1),
24 }
25 }
26}
27
28impl std::fmt::UpperHex for I128Hex {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self.1 {
31 Type::I8 => fmt::UpperHex::fmt(&(self.0 as i8), f),
32 Type::I16 => fmt::UpperHex::fmt(&(self.0 as i16), f),
33 Type::I32 => fmt::UpperHex::fmt(&(self.0 as i32), f),
34 Type::I64 => fmt::UpperHex::fmt(&(self.0 as i64), f),
35 Type::I128 => fmt::UpperHex::fmt(&self.0, f),
36 _ => panic!("Unsupported type '{:?}' found.", self.1),
37 }
38 }
39}
40
41#[derive(Debug, PartialEq)]
43pub struct Frame<'t> {
44 table: &'t Table,
45 level: Option<Level>,
46 index: u64,
47 timestamp_format: Option<&'t str>,
48 timestamp_args: Vec<Arg<'t>>,
49 format: &'t str,
51 args: Vec<Arg<'t>>,
52}
53
54impl<'t> Frame<'t> {
55 pub(crate) fn new(
56 table: &'t Table,
57 level: Option<Level>,
58 index: u64,
59 timestamp_format: Option<&'t str>,
60 timestamp_args: Vec<Arg<'t>>,
61 format: &'t str,
62 args: Vec<Arg<'t>>,
63 ) -> Self {
64 Self {
65 table,
66 level,
67 index,
68 timestamp_format,
69 timestamp_args,
70 format,
71 args,
72 }
73 }
74
75 pub fn display(&'t self, colored: bool) -> DisplayFrame<'t> {
78 DisplayFrame {
79 frame: self,
80 colored,
81 }
82 }
83
84 pub fn display_timestamp(&'t self) -> Option<DisplayTimestamp<'t>> {
85 self.timestamp_format
86 .map(|_| DisplayTimestamp { frame: self })
87 }
88
89 pub fn display_message(&'t self) -> DisplayMessage<'t> {
91 DisplayMessage { frame: self }
92 }
93
94 pub fn level(&self) -> Option<Level> {
95 self.level
96 }
97
98 pub fn index(&self) -> u64 {
99 self.index
100 }
101
102 fn format_args(&self, format: &str, args: &[Arg], parent_hint: Option<&DisplayHint>) -> String {
103 self.format_args_real(format, args, parent_hint).unwrap() }
105
106 fn format_args_real(
107 &self,
108 format: &str,
109 args: &[Arg],
110 parent_hint: Option<&DisplayHint>,
111 ) -> Result<String, fmt::Error> {
112 let params = defmt_parser::parse(format, ParserMode::ForwardsCompatible).unwrap();
113 let mut buf = String::new();
114 for param in params {
115 match param {
116 Fragment::Literal(lit) => {
117 buf.push_str(&lit);
118 }
119 Fragment::Parameter(param) => {
120 let hint = param.hint.as_ref().or(parent_hint);
121
122 match &args[param.index] {
123 Arg::Bool(x) => write!(buf, "{x}")?,
124 Arg::F32(x) => write!(buf, "{}", ryu::Buffer::new().format(*x))?,
125 Arg::F64(x) => write!(buf, "{}", ryu::Buffer::new().format(*x))?,
126 Arg::Uxx(x) => {
127 match param.ty {
128 Type::BitField(range) => {
129 let left_zeroes =
130 mem::size_of::<u128>() * 8 - range.end as usize;
131 let right_zeroes = left_zeroes + range.start as usize;
132 let bitfields = (*x << left_zeroes) >> right_zeroes;
134
135 if let Some(DisplayHint::Ascii) = hint {
136 let bstr = bitfields
137 .to_be_bytes()
138 .iter()
139 .skip(right_zeroes / 8)
140 .copied()
141 .collect::<Vec<u8>>();
142 self.format_bytes(&bstr, hint, &mut buf)?
143 } else {
144 self.format_u128(bitfields, hint, &mut buf)?;
145 }
146 }
147 _ => match hint {
148 Some(DisplayHint::ISO8601(precision)) => {
149 self.format_iso8601(*x as u64, precision, &mut buf)?
150 }
151 Some(DisplayHint::Debug) => {
152 self.format_u128(*x, parent_hint, &mut buf)?
153 }
154 _ => self.format_u128(*x, hint, &mut buf)?,
155 },
156 }
157 }
158 Arg::Ixx(x) => self.format_i128(*x, param.ty, hint, &mut buf)?,
159 Arg::Str(x) | Arg::Preformatted(x) => self.format_str(x, hint, &mut buf)?,
160 Arg::IStr(x) => self.format_str(x, hint, &mut buf)?,
161 Arg::Format { format, args } => match parent_hint {
162 Some(DisplayHint::Ascii) => {
163 buf.push_str(&self.format_args(format, args, parent_hint));
164 }
165 _ => buf.push_str(&self.format_args(format, args, hint)),
166 },
167 Arg::FormatSequence { args } => {
168 for arg in args {
169 buf.push_str(&self.format_args("{=?}", &[arg.clone()], hint))
170 }
171 }
172 Arg::FormatSlice { elements } => {
173 match hint {
174 Some(DisplayHint::Ascii)
176 if elements.iter().filter(|e| e.format == "{=u8}").count()
177 != 0 =>
178 {
179 let vals = elements
180 .iter()
181 .map(|e| match e.args.as_slice() {
182 [Arg::Uxx(v)] => u8::try_from(*v)
183 .expect("the value must be in u8 range"),
184 _ => panic!(
185 "FormatSlice should only contain one argument"
186 ),
187 })
188 .collect::<Vec<u8>>();
189 self.format_bytes(&vals, hint, &mut buf)?
190 }
191 _ => {
192 buf.write_str("[")?;
193 let mut is_first = true;
194 for element in elements {
195 if !is_first {
196 buf.write_str(", ")?;
197 }
198 is_first = false;
199 buf.write_str(&self.format_args(
200 element.format,
201 &element.args,
202 hint,
203 ))?;
204 }
205 buf.write_str("]")?;
206 }
207 }
208 }
209 Arg::Slice(x) => self.format_bytes(x, hint, &mut buf)?,
210 Arg::Char(c) => write!(buf, "{c}")?,
211 }
212 }
213 }
214 }
215 Ok(buf)
216 }
217
218 fn format_u128(
219 &self,
220 x: u128,
221 hint: Option<&DisplayHint>,
222 buf: &mut String,
223 ) -> Result<(), fmt::Error> {
224 match hint {
225 Some(DisplayHint::NoHint { zero_pad }) => write!(buf, "{x:0zero_pad$}")?,
226 Some(DisplayHint::Binary {
227 alternate,
228 zero_pad,
229 }) => match alternate {
230 true => write!(buf, "{x:#0zero_pad$b}")?,
231 false => write!(buf, "{x:0zero_pad$b}")?,
232 },
233 Some(DisplayHint::Octal {
234 alternate,
235 zero_pad,
236 }) => match alternate {
237 true => write!(buf, "{x:#0zero_pad$o}")?,
238 false => write!(buf, "{x:0zero_pad$o}")?,
239 },
240 Some(DisplayHint::Hexadecimal {
241 uppercase,
242 alternate,
243 zero_pad,
244 }) => match (alternate, uppercase) {
245 (false, false) => write!(buf, "{x:0zero_pad$x}")?,
246 (false, true) => write!(buf, "{x:0zero_pad$X}")?,
247 (true, false) => write!(buf, "{x:#0zero_pad$x}")?,
248 (true, true) => write!(buf, "{x:#0zero_pad$X}")?,
249 },
250 Some(DisplayHint::Seconds(TimePrecision::Micros)) => {
251 let seconds = x / 1_000_000;
252 let micros = x % 1_000_000;
253 write!(buf, "{seconds}.{micros:06}")?;
254 }
255 Some(DisplayHint::Seconds(TimePrecision::Millis)) => {
256 let seconds = x / 1_000;
257 let millis = x % 1_000;
258 write!(buf, "{seconds}.{millis:03}")?;
259 }
260 Some(DisplayHint::Time(TimePrecision::Micros)) => {
261 self.format_time(x, &TimePrecision::Micros, buf)?;
262 }
263 Some(DisplayHint::Time(TimePrecision::Millis)) => {
264 self.format_time(x, &TimePrecision::Millis, buf)?;
265 }
266 Some(DisplayHint::Time(TimePrecision::Seconds)) => {
267 self.format_time(x, &TimePrecision::Seconds, buf)?;
268 }
269 Some(DisplayHint::Bitflags {
270 name,
271 package,
272 disambiguator,
273 crate_name,
274 }) => {
275 let key = BitflagsKey {
278 ident: name.clone(),
279 package: package.clone(),
280 disambig: disambiguator.clone(),
281 crate_name: crate_name.clone(),
282 };
283 match self.table.bitflags.get(&key) {
284 Some(flags) => {
285 let set_flags = flags
286 .iter()
287 .filter(|(_, value)| {
288 if *value == 0 && x != 0 {
289 false
290 } else {
291 x & value == *value
292 }
293 })
294 .map(|(name, _)| name.clone())
295 .collect::<Vec<_>>();
296 if set_flags.is_empty() {
297 write!(buf, "(empty)")?;
298 } else {
299 write!(buf, "{}", set_flags.join(" | "))?;
300 }
301 }
302 None => {
303 write!(buf, "{x}")?;
305 }
306 }
307 }
308 _ => write!(buf, "{x}")?,
309 }
310 Ok(())
311 }
312
313 fn format_i128(
314 &self,
315 x: i128,
316 ty: Type,
317 hint: Option<&DisplayHint>,
318 buf: &mut String,
319 ) -> Result<(), fmt::Error> {
320 match hint {
321 Some(DisplayHint::NoHint { zero_pad }) => write!(buf, "{x:0zero_pad$}")?,
322 Some(DisplayHint::Binary {
323 alternate,
324 zero_pad,
325 }) => match alternate {
326 true => write!(buf, "{x:#0zero_pad$b}")?,
327 false => write!(buf, "{x:0zero_pad$b}")?,
328 },
329 Some(DisplayHint::Octal {
330 alternate,
331 zero_pad,
332 }) => match alternate {
333 true => write!(buf, "{x:#0zero_pad$o}")?,
334 false => write!(buf, "{x:0zero_pad$o}")?,
335 },
336 Some(DisplayHint::Hexadecimal {
337 uppercase,
338 alternate,
339 zero_pad,
340 }) => {
341 let value = I128Hex(x, ty);
342 match (alternate, uppercase) {
343 (false, false) => write!(buf, "{value:0zero_pad$x}")?,
344 (false, true) => write!(buf, "{value:0zero_pad$X}")?,
345 (true, false) => write!(buf, "{value:#0zero_pad$x}")?,
346 (true, true) => write!(buf, "{value:#0zero_pad$X}")?,
347 }
348 }
349 _ => write!(buf, "{x}")?,
350 }
351 Ok(())
352 }
353
354 fn format_bytes(
355 &self,
356 bytes: &[u8],
357 hint: Option<&DisplayHint>,
358 buf: &mut String,
359 ) -> Result<(), fmt::Error> {
360 match hint {
361 Some(DisplayHint::Ascii) => {
362 buf.push_str("b\"");
364 for byte in bytes {
365 match byte {
366 b'\t' => buf.push_str("\\t"),
368 b'\n' => buf.push_str("\\n"),
369 b'\r' => buf.push_str("\\r"),
370 b' ' => buf.push(' '),
371 b'\"' => buf.push_str("\\\""),
372 b'\\' => buf.push_str("\\\\"),
373 _ => {
374 if byte.is_ascii_graphic() {
375 buf.push(*byte as char);
376 } else {
377 write!(buf, "\\x{byte:02x}").ok();
379 }
380 }
381 }
382 }
383 buf.push('\"');
384 }
385 Some(DisplayHint::Hexadecimal { .. })
386 | Some(DisplayHint::Octal { .. })
387 | Some(DisplayHint::Binary { .. }) => {
388 buf.push('[');
392 let mut is_first = true;
393 for byte in bytes {
394 if !is_first {
395 buf.push_str(", ");
396 }
397 is_first = false;
398 self.format_u128(*byte as u128, hint, buf)?;
399 }
400 buf.push(']');
401 }
402 _ => write!(buf, "{bytes:?}")?,
403 }
404 Ok(())
405 }
406
407 fn format_str(
408 &self,
409 s: &str,
410 hint: Option<&DisplayHint>,
411 buf: &mut String,
412 ) -> Result<(), fmt::Error> {
413 if hint == Some(&DisplayHint::Debug) {
414 write!(buf, "{s:?}")?;
415 } else {
416 buf.push_str(s);
417 }
418 Ok(())
419 }
420
421 fn format_time(
422 &self,
423 timestamp: u128,
424 precision: &TimePrecision,
425 buf: &mut String,
426 ) -> Result<(), fmt::Error> {
427 let div_rem = |x, y| (x / y, x % y);
428
429 let (timestamp, decimals) = match precision {
430 TimePrecision::Micros => div_rem(timestamp, 1_000_000),
431 TimePrecision::Millis => div_rem(timestamp, 1_000),
432 TimePrecision::Seconds => (timestamp, 0),
433 };
434
435 let (timestamp, seconds) = div_rem(timestamp, 60);
436 let (timestamp, minutes) = div_rem(timestamp, 60);
437 let (timestamp, hours) = div_rem(timestamp, 24);
438 let days = timestamp;
439
440 if days == 0 {
441 match precision {
442 TimePrecision::Micros => write!(
443 buf,
444 "{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>6}"
445 ),
446 TimePrecision::Millis => write!(
447 buf,
448 "{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>3}"
449 ),
450 TimePrecision::Seconds => write!(buf, "{hours:0>2}:{minutes:0>2}:{seconds:0>2}"),
451 }
452 } else {
453 match precision {
454 TimePrecision::Micros => write!(
455 buf,
456 "{days}:{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>6}"
457 ),
458 TimePrecision::Millis => write!(
459 buf,
460 "{days}:{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>3}"
461 ),
462 TimePrecision::Seconds => {
463 write!(buf, "{days}:{hours:0>2}:{minutes:0>2}:{seconds:0>2}")
464 }
465 }
466 }
467 }
468
469 fn format_iso8601(
470 &self,
471 timestamp: u64,
472 precision: &TimePrecision,
473 buf: &mut String,
474 ) -> Result<(), fmt::Error> {
475 let format = match precision {
476 TimePrecision::Micros => format_description!(
477 "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z"
478 ),
479 TimePrecision::Millis => format_description!(
480 "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z"
481 ),
482 TimePrecision::Seconds => {
483 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]Z")
484 }
485 };
486 let date_time = OffsetDateTime::from_unix_timestamp_nanos(match precision {
487 TimePrecision::Micros => timestamp as i128 * 1_000,
488 TimePrecision::Millis => timestamp as i128 * 1_000_000,
489 TimePrecision::Seconds => timestamp as i128 * 1_000_000_000,
490 })
491 .unwrap();
492 write!(buf, "{}", date_time.format(format).unwrap())
493 }
494}
495
496pub struct DisplayTimestamp<'t> {
497 frame: &'t Frame<'t>,
498}
499
500impl fmt::Display for DisplayTimestamp<'_> {
501 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
502 let args = self.frame.format_args(
503 self.frame.timestamp_format.unwrap(),
504 &self.frame.timestamp_args,
505 None,
506 );
507 f.write_str(&args)
508 }
509}
510
511pub struct DisplayMessage<'t> {
512 frame: &'t Frame<'t>,
513}
514
515impl fmt::Display for DisplayMessage<'_> {
516 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
517 let args = self
518 .frame
519 .format_args(self.frame.format, &self.frame.args, None);
520 f.write_str(&args)
521 }
522}
523
524pub struct DisplayFrame<'t> {
527 frame: &'t Frame<'t>,
528 colored: bool,
529}
530
531impl fmt::Display for DisplayFrame<'_> {
532 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533 let level = if let Some(level) = self.frame.level {
534 let level = if self.colored {
535 match level {
536 Level::Trace => "TRACE".dimmed().to_string(),
537 Level::Debug => "DEBUG".normal().to_string(),
538 Level::Info => "INFO".green().to_string(),
539 Level::Warn => "WARN".yellow().to_string(),
540 Level::Error => "ERROR".red().to_string(),
541 }
542 } else {
543 match level {
544 Level::Trace => "TRACE".to_string(),
545 Level::Debug => "DEBUG".to_string(),
546 Level::Info => "INFO".to_string(),
547 Level::Warn => "WARN".to_string(),
548 Level::Error => "ERROR".to_string(),
549 }
550 };
551 format!("{level} ")
552 } else {
553 "".to_string()
554 };
555
556 let timestamp = self
557 .frame
558 .timestamp_format
559 .map(|fmt| {
560 format!(
561 "{} ",
562 self.frame
563 .format_args(fmt, &self.frame.timestamp_args, None,),
564 )
565 })
566 .unwrap_or_default();
567
568 let args = self
569 .frame
570 .format_args(self.frame.format, &self.frame.args, None);
571
572 write!(f, "{timestamp}{level}{args}")
573 }
574}