pretty_print.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /*! Pretty-printing of packet representation.
  2. The `pretty_print` module provides bits and pieces for printing concise,
  3. easily human readable packet listings.
  4. # Example
  5. A packet can be formatted using the `PrettyPrinter` wrapper:
  6. ```rust,ignore
  7. use smoltcp::wire::*;
  8. let buffer = vec![
  9. // Ethernet II
  10. 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  11. 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
  12. 0x08, 0x00,
  13. // IPv4
  14. 0x45, 0x00, 0x00, 0x18,
  15. 0x00, 0x00, 0x40, 0x00,
  16. 0x40, 0x01, 0xd2, 0x79,
  17. 0x11, 0x12, 0x13, 0x14,
  18. 0x21, 0x22, 0x23, 0x24,
  19. // ICMPv4
  20. 0x08, 0x00, 0x8e, 0xfe,
  21. 0x12, 0x34, 0xab, 0xcd,
  22. 0xaa, 0x00, 0x00, 0xff
  23. ];
  24. print!("{}", PrettyPrinter::<EthernetFrame<&'static [u8]>>::new("", &buffer));
  25. ```
  26. */
  27. use core::fmt;
  28. use core::marker::PhantomData;
  29. /// Indentation state.
  30. #[derive(Debug)]
  31. #[cfg_attr(feature = "defmt", derive(defmt::Format))]
  32. pub struct PrettyIndent {
  33. prefix: &'static str,
  34. level: usize,
  35. }
  36. impl PrettyIndent {
  37. /// Create an indentation state. The entire listing will be indented by the width
  38. /// of `prefix`, and `prefix` will appear at the start of the first line.
  39. pub fn new(prefix: &'static str) -> PrettyIndent {
  40. PrettyIndent { prefix, level: 0 }
  41. }
  42. /// Increase indentation level.
  43. pub fn increase(&mut self, f: &mut fmt::Formatter) -> fmt::Result {
  44. writeln!(f)?;
  45. self.level += 1;
  46. Ok(())
  47. }
  48. }
  49. impl fmt::Display for PrettyIndent {
  50. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  51. if self.level == 0 {
  52. write!(f, "{}", self.prefix)
  53. } else {
  54. write!(f, "{0:1$}{0:2$}\\ ", "", self.prefix.len(), self.level - 1)
  55. }
  56. }
  57. }
  58. /// Interface for printing listings.
  59. pub trait PrettyPrint {
  60. /// Write a concise, formatted representation of a packet contained in the provided
  61. /// buffer, and any nested packets it may contain.
  62. ///
  63. /// `pretty_print` accepts a buffer and not a packet wrapper because the packet might
  64. /// be truncated, and so it might not be possible to create the packet wrapper.
  65. fn pretty_print(
  66. buffer: &dyn AsRef<[u8]>,
  67. fmt: &mut fmt::Formatter,
  68. indent: &mut PrettyIndent,
  69. ) -> fmt::Result;
  70. }
  71. /// Wrapper for using a `PrettyPrint` where a `Display` is expected.
  72. pub struct PrettyPrinter<'a, T: PrettyPrint> {
  73. prefix: &'static str,
  74. buffer: &'a dyn AsRef<[u8]>,
  75. phantom: PhantomData<T>,
  76. }
  77. impl<'a, T: PrettyPrint> PrettyPrinter<'a, T> {
  78. /// Format the listing with the recorded parameters when Display::fmt is called.
  79. pub fn new(prefix: &'static str, buffer: &'a dyn AsRef<[u8]>) -> PrettyPrinter<'a, T> {
  80. PrettyPrinter {
  81. prefix: prefix,
  82. buffer: buffer,
  83. phantom: PhantomData,
  84. }
  85. }
  86. }
  87. impl<'a, T: PrettyPrint + AsRef<[u8]>> PrettyPrinter<'a, T> {
  88. /// Create a `PrettyPrinter` which prints the given object.
  89. pub fn print(printable: &'a T) -> PrettyPrinter<'a, T> {
  90. PrettyPrinter {
  91. prefix: "",
  92. buffer: printable,
  93. phantom: PhantomData,
  94. }
  95. }
  96. }
  97. impl<'a, T: PrettyPrint> fmt::Display for PrettyPrinter<'a, T> {
  98. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  99. T::pretty_print(&self.buffer, f, &mut PrettyIndent::new(self.prefix))
  100. }
  101. }