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 display_fragments(&'t self) -> DisplayFragments<'t> {
124 DisplayFragments {
125 frame: self,
126 iter: self.fragments().into_iter(),
127 }
128 }
129
130 pub fn fragments(&'t self) -> Vec<Fragment<'t>> {
137 defmt_parser::parse(self.format, ParserMode::ForwardsCompatible).unwrap()
138 }
139
140 pub fn level(&self) -> Option<Level> {
141 self.level
142 }
143
144 pub fn index(&self) -> u64 {
145 self.index
146 }
147
148 fn format_args(&self, format: &str, args: &[Arg], parent_hint: Option<&DisplayHint>) -> String {
149 let params = defmt_parser::parse(format, ParserMode::ForwardsCompatible).unwrap();
150 let mut buf = String::new();
151 for param in params {
152 self.format_fragment(param, &mut buf, args, parent_hint)
153 .unwrap(); }
155 buf
156 }
157
158 fn format_fragment(
159 &self,
160 param: Fragment<'_>,
161 buf: &mut String,
162 args: &[Arg],
163 parent_hint: Option<&DisplayHint>,
164 ) -> Result<(), fmt::Error> {
165 match param {
166 Fragment::Literal(lit) => {
167 buf.push_str(&lit);
168 }
169 Fragment::Parameter(param) => {
170 let hint = param.hint.as_ref().or(parent_hint);
171
172 match &args[param.index] {
173 Arg::Bool(x) => write!(buf, "{x}")?,
174 Arg::F32(x) => write!(buf, "{}", ryu::Buffer::new().format(*x))?,
175 Arg::F64(x) => write!(buf, "{}", ryu::Buffer::new().format(*x))?,
176 Arg::Uxx(x) => {
177 match param.ty {
178 Type::BitField(range) => {
179 let left_zeroes = mem::size_of::<u128>() * 8 - range.end as usize;
180 let right_zeroes = left_zeroes + range.start as usize;
181 let bitfields = (*x << left_zeroes) >> right_zeroes;
183
184 if let Some(DisplayHint::Ascii) = hint {
185 let bstr = bitfields
186 .to_be_bytes()
187 .iter()
188 .skip(right_zeroes / 8)
189 .copied()
190 .collect::<Vec<u8>>();
191 self.format_bytes(&bstr, hint, buf)?
192 } else {
193 self.format_u128(bitfields, hint, buf)?;
194 }
195 }
196 _ => match hint {
197 Some(DisplayHint::ISO8601(precision)) => {
198 self.format_iso8601(*x as u64, precision, buf)?
199 }
200 Some(DisplayHint::Debug) => {
201 self.format_u128(*x, parent_hint, buf)?
202 }
203 _ => self.format_u128(*x, hint, buf)?,
204 },
205 }
206 }
207 Arg::Ixx(x) => self.format_i128(*x, param.ty, hint, buf)?,
208 Arg::Str(x) | Arg::Preformatted(x) => self.format_str(x, hint, buf)?,
209 Arg::IStr(x) => self.format_str(x, hint, buf)?,
210 Arg::Format { format, args } => match parent_hint {
211 Some(DisplayHint::Ascii) => {
212 buf.push_str(&self.format_args(format, args, parent_hint));
213 }
214 _ => buf.push_str(&self.format_args(format, args, hint)),
215 },
216 Arg::FormatSequence { args } => {
217 for arg in args {
218 buf.push_str(&self.format_args("{=?}", &[arg.clone()], hint))
219 }
220 }
221 Arg::FormatSlice { elements } => {
222 match hint {
223 Some(DisplayHint::Ascii)
225 if elements.iter().filter(|e| e.format == "{=u8}").count() != 0 =>
226 {
227 let vals = elements
228 .iter()
229 .map(|e| match e.args.as_slice() {
230 [Arg::Uxx(v)] => {
231 u8::try_from(*v).expect("the value must be in u8 range")
232 }
233 _ => panic!("FormatSlice should only contain one argument"),
234 })
235 .collect::<Vec<u8>>();
236 self.format_bytes(&vals, hint, buf)?
237 }
238 _ => {
239 buf.write_str("[")?;
240 let mut is_first = true;
241 for element in elements {
242 if !is_first {
243 buf.write_str(", ")?;
244 }
245 is_first = false;
246 buf.write_str(&self.format_args(
247 element.format,
248 &element.args,
249 hint,
250 ))?;
251 }
252 buf.write_str("]")?;
253 }
254 }
255 }
256 Arg::Slice(x) => self.format_bytes(x, hint, buf)?,
257 Arg::Char(c) => write!(buf, "{c}")?,
258 }
259 }
260 }
261
262 Ok(())
263 }
264
265 fn format_u128(
266 &self,
267 x: u128,
268 hint: Option<&DisplayHint>,
269 buf: &mut String,
270 ) -> Result<(), fmt::Error> {
271 match hint {
272 Some(DisplayHint::NoHint { zero_pad }) => write!(buf, "{x:0zero_pad$}")?,
273 Some(DisplayHint::Binary {
274 alternate,
275 zero_pad,
276 }) => match alternate {
277 true => write!(buf, "{x:#0zero_pad$b}")?,
278 false => write!(buf, "{x:0zero_pad$b}")?,
279 },
280 Some(DisplayHint::Octal {
281 alternate,
282 zero_pad,
283 }) => match alternate {
284 true => write!(buf, "{x:#0zero_pad$o}")?,
285 false => write!(buf, "{x:0zero_pad$o}")?,
286 },
287 Some(DisplayHint::Hexadecimal {
288 uppercase,
289 alternate,
290 zero_pad,
291 }) => match (alternate, uppercase) {
292 (false, false) => write!(buf, "{x:0zero_pad$x}")?,
293 (false, true) => write!(buf, "{x:0zero_pad$X}")?,
294 (true, false) => write!(buf, "{x:#0zero_pad$x}")?,
295 (true, true) => write!(buf, "{x:#0zero_pad$X}")?,
296 },
297 Some(DisplayHint::Seconds(TimePrecision::Micros)) => {
298 let seconds = x / 1_000_000;
299 let micros = x % 1_000_000;
300 write!(buf, "{seconds}.{micros:06}")?;
301 }
302 Some(DisplayHint::Seconds(TimePrecision::Millis)) => {
303 let seconds = x / 1_000;
304 let millis = x % 1_000;
305 write!(buf, "{seconds}.{millis:03}")?;
306 }
307 Some(DisplayHint::Time(TimePrecision::Micros)) => {
308 self.format_time(x, &TimePrecision::Micros, buf)?;
309 }
310 Some(DisplayHint::Time(TimePrecision::Millis)) => {
311 self.format_time(x, &TimePrecision::Millis, buf)?;
312 }
313 Some(DisplayHint::Time(TimePrecision::Seconds)) => {
314 self.format_time(x, &TimePrecision::Seconds, buf)?;
315 }
316 Some(DisplayHint::Bitflags {
317 name,
318 package,
319 disambiguator,
320 crate_name,
321 }) => {
322 let key = BitflagsKey {
325 ident: name.clone(),
326 package: package.clone(),
327 disambig: disambiguator.clone(),
328 crate_name: crate_name.clone(),
329 };
330 match self.table.bitflags.get(&key) {
331 Some(flags) => {
332 let set_flags = flags
333 .iter()
334 .filter(|(_, value)| {
335 if *value == 0 && x != 0 {
336 false
337 } else {
338 x & value == *value
339 }
340 })
341 .map(|(name, _)| name.clone())
342 .collect::<Vec<_>>();
343 if set_flags.is_empty() {
344 write!(buf, "(empty)")?;
345 } else {
346 write!(buf, "{}", set_flags.join(" | "))?;
347 }
348 }
349 None => {
350 write!(buf, "{x}")?;
352 }
353 }
354 }
355 _ => write!(buf, "{x}")?,
356 }
357 Ok(())
358 }
359
360 fn format_i128(
361 &self,
362 x: i128,
363 ty: Type,
364 hint: Option<&DisplayHint>,
365 buf: &mut String,
366 ) -> Result<(), fmt::Error> {
367 match hint {
368 Some(DisplayHint::NoHint { zero_pad }) => write!(buf, "{x:0zero_pad$}")?,
369 Some(DisplayHint::Binary {
370 alternate,
371 zero_pad,
372 }) => match alternate {
373 true => write!(buf, "{x:#0zero_pad$b}")?,
374 false => write!(buf, "{x:0zero_pad$b}")?,
375 },
376 Some(DisplayHint::Octal {
377 alternate,
378 zero_pad,
379 }) => match alternate {
380 true => write!(buf, "{x:#0zero_pad$o}")?,
381 false => write!(buf, "{x:0zero_pad$o}")?,
382 },
383 Some(DisplayHint::Hexadecimal {
384 uppercase,
385 alternate,
386 zero_pad,
387 }) => {
388 let value = I128Hex(x, ty);
389 match (alternate, uppercase) {
390 (false, false) => write!(buf, "{value:0zero_pad$x}")?,
391 (false, true) => write!(buf, "{value:0zero_pad$X}")?,
392 (true, false) => write!(buf, "{value:#0zero_pad$x}")?,
393 (true, true) => write!(buf, "{value:#0zero_pad$X}")?,
394 }
395 }
396 _ => write!(buf, "{x}")?,
397 }
398 Ok(())
399 }
400
401 fn format_bytes(
402 &self,
403 bytes: &[u8],
404 hint: Option<&DisplayHint>,
405 buf: &mut String,
406 ) -> Result<(), fmt::Error> {
407 match hint {
408 Some(DisplayHint::Ascii) => {
409 buf.push_str("b\"");
411 for byte in bytes {
412 match byte {
413 b'\t' => buf.push_str("\\t"),
415 b'\n' => buf.push_str("\\n"),
416 b'\r' => buf.push_str("\\r"),
417 b' ' => buf.push(' '),
418 b'\"' => buf.push_str("\\\""),
419 b'\\' => buf.push_str("\\\\"),
420 _ => {
421 if byte.is_ascii_graphic() {
422 buf.push(*byte as char);
423 } else {
424 write!(buf, "\\x{byte:02x}").ok();
426 }
427 }
428 }
429 }
430 buf.push('\"');
431 }
432 Some(DisplayHint::Hexadecimal { .. })
433 | Some(DisplayHint::Octal { .. })
434 | Some(DisplayHint::Binary { .. }) => {
435 buf.push('[');
439 let mut is_first = true;
440 for byte in bytes {
441 if !is_first {
442 buf.push_str(", ");
443 }
444 is_first = false;
445 self.format_u128(*byte as u128, hint, buf)?;
446 }
447 buf.push(']');
448 }
449 Some(DisplayHint::Cbor) => {
450 use core::fmt::Write;
451 let parsed = cbor_edn::Sequence::from_cbor(bytes);
452 match parsed {
453 Ok(parsed) => buf.write_str(&parsed.serialize())?,
454 Err(err) => {
455 write!(buf, "invalid CBOR (error: {}, bytes: {:02x?})", err, bytes)?
456 }
457 }
458 }
459 _ => write!(buf, "{bytes:?}")?,
460 }
461 Ok(())
462 }
463
464 fn format_str(
465 &self,
466 s: &str,
467 hint: Option<&DisplayHint>,
468 buf: &mut String,
469 ) -> Result<(), fmt::Error> {
470 if hint == Some(&DisplayHint::Debug) {
471 write!(buf, "{s:?}")?;
472 } else {
473 buf.push_str(s);
474 }
475 Ok(())
476 }
477
478 fn format_time(
479 &self,
480 timestamp: u128,
481 precision: &TimePrecision,
482 buf: &mut String,
483 ) -> Result<(), fmt::Error> {
484 let div_rem = |x, y| (x / y, x % y);
485
486 let (timestamp, decimals) = match precision {
487 TimePrecision::Micros => div_rem(timestamp, 1_000_000),
488 TimePrecision::Millis => div_rem(timestamp, 1_000),
489 TimePrecision::Seconds => (timestamp, 0),
490 };
491
492 let (timestamp, seconds) = div_rem(timestamp, 60);
493 let (timestamp, minutes) = div_rem(timestamp, 60);
494 let (timestamp, hours) = div_rem(timestamp, 24);
495 let days = timestamp;
496
497 if days == 0 {
498 match precision {
499 TimePrecision::Micros => write!(
500 buf,
501 "{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>6}"
502 ),
503 TimePrecision::Millis => write!(
504 buf,
505 "{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>3}"
506 ),
507 TimePrecision::Seconds => write!(buf, "{hours:0>2}:{minutes:0>2}:{seconds:0>2}"),
508 }
509 } else {
510 match precision {
511 TimePrecision::Micros => write!(
512 buf,
513 "{days}:{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>6}"
514 ),
515 TimePrecision::Millis => write!(
516 buf,
517 "{days}:{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{decimals:0>3}"
518 ),
519 TimePrecision::Seconds => {
520 write!(buf, "{days}:{hours:0>2}:{minutes:0>2}:{seconds:0>2}")
521 }
522 }
523 }
524 }
525
526 fn format_iso8601(
527 &self,
528 timestamp: u64,
529 precision: &TimePrecision,
530 buf: &mut String,
531 ) -> Result<(), fmt::Error> {
532 let format = match precision {
533 TimePrecision::Micros => format_description!(
534 "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z"
535 ),
536 TimePrecision::Millis => format_description!(
537 "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:3]Z"
538 ),
539 TimePrecision::Seconds => {
540 format_description!("[year]-[month]-[day]T[hour]:[minute]:[second]Z")
541 }
542 };
543 let date_time = OffsetDateTime::from_unix_timestamp_nanos(match precision {
544 TimePrecision::Micros => timestamp as i128 * 1_000,
545 TimePrecision::Millis => timestamp as i128 * 1_000_000,
546 TimePrecision::Seconds => timestamp as i128 * 1_000_000_000,
547 })
548 .unwrap();
549 write!(buf, "{}", date_time.format(format).unwrap())
550 }
551}
552
553pub struct DisplayTimestamp<'t> {
554 frame: &'t Frame<'t>,
555}
556
557impl fmt::Display for DisplayTimestamp<'_> {
558 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
559 let args = self.frame.format_args(
560 self.frame.timestamp_format.unwrap(),
561 &self.frame.timestamp_args,
562 None,
563 );
564 f.write_str(&args)
565 }
566}
567
568pub struct DisplayMessage<'t> {
569 frame: &'t Frame<'t>,
570}
571
572impl fmt::Display for DisplayMessage<'_> {
573 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
574 let args = self
575 .frame
576 .format_args(self.frame.format, &self.frame.args, None);
577 f.write_str(&args)
578 }
579}
580
581pub struct DisplayFragments<'t> {
585 frame: &'t Frame<'t>,
586 iter: std::vec::IntoIter<Fragment<'t>>,
587}
588
589impl Iterator for DisplayFragments<'_> {
590 type Item = String;
591
592 fn next(&mut self) -> Option<Self::Item> {
593 let mut buf = String::new();
594 self.frame
595 .format_fragment(self.iter.next()?, &mut buf, &self.frame.args, None)
596 .ok()?;
597 Some(buf)
598 }
599}
600
601pub struct DisplayFrame<'t> {
604 frame: &'t Frame<'t>,
605 colored: bool,
606}
607
608impl fmt::Display for DisplayFrame<'_> {
609 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
610 let level = if let Some(level) = self.frame.level {
611 let level = if self.colored {
612 match level {
613 Level::Trace => "TRACE".dimmed().to_string(),
614 Level::Debug => "DEBUG".normal().to_string(),
615 Level::Info => "INFO".green().to_string(),
616 Level::Warn => "WARN".yellow().to_string(),
617 Level::Error => "ERROR".red().to_string(),
618 }
619 } else {
620 match level {
621 Level::Trace => "TRACE".to_string(),
622 Level::Debug => "DEBUG".to_string(),
623 Level::Info => "INFO".to_string(),
624 Level::Warn => "WARN".to_string(),
625 Level::Error => "ERROR".to_string(),
626 }
627 };
628 format!("{level} ")
629 } else {
630 "".to_string()
631 };
632
633 let timestamp = self
634 .frame
635 .timestamp_format
636 .map(|fmt| {
637 format!(
638 "{} ",
639 self.frame
640 .format_args(fmt, &self.frame.timestamp_args, None,),
641 )
642 })
643 .unwrap_or_default();
644
645 let args = self
646 .frame
647 .format_args(self.frame.format, &self.frame.args, None);
648
649 write!(f, "{timestamp}{level}{args}")
650 }
651}