pretty_print.rs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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
  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. pub struct PrettyIndent {
  32. prefix: &'static str,
  33. level: usize
  34. }
  35. impl PrettyIndent {
  36. /// Create an indentation state. The entire listing will be indented by the width
  37. /// of `prefix`, and `prefix` will appear at the start of the first line.
  38. pub fn new(prefix: &'static str) -> PrettyIndent {
  39. PrettyIndent { prefix: prefix, level: 0 }
  40. }
  41. /// Increase indentation level.
  42. pub fn increase(&mut self, f: &mut fmt::Formatter) -> fmt::Result {
  43. write!(f, "\n")?;
  44. self.level += 1;
  45. Ok(())
  46. }
  47. }
  48. impl fmt::Display for PrettyIndent {
  49. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  50. if self.level == 0 {
  51. write!(f, "{}", self.prefix)
  52. } else {
  53. write!(f, "{0:1$}{0:2$}\\ ", "", self.prefix.len(), self.level - 1)
  54. }
  55. }
  56. }
  57. /// Interface for printing listings.
  58. pub trait PrettyPrint {
  59. /// Write a concise, formatted representation of a packet contained in the provided
  60. /// buffer, and any nested packets it may contain.
  61. ///
  62. /// `pretty_print` accepts a buffer and not a packet wrapper because the packet might
  63. /// be truncated, and so it might not be possible to create the packet wrapper.
  64. fn pretty_print(buffer: &AsRef<[u8]>, fmt: &mut fmt::Formatter,
  65. indent: &mut PrettyIndent) -> fmt::Result;
  66. }
  67. /// Wrapper for using a `PrettyPrint` where a `Display` is expected.
  68. pub struct PrettyPrinter<'a, T: PrettyPrint> {
  69. prefix: &'static str,
  70. buffer: &'a AsRef<[u8]>,
  71. phantom: PhantomData<T>
  72. }
  73. impl<'a, T: PrettyPrint> PrettyPrinter<'a, T> {
  74. /// Format the listing with the recorded parameters when Display::fmt is called.
  75. pub fn new(prefix: &'static str, buffer: &'a AsRef<[u8]>) -> PrettyPrinter<'a, T> {
  76. PrettyPrinter {
  77. prefix: prefix,
  78. buffer: buffer,
  79. phantom: PhantomData
  80. }
  81. }
  82. }
  83. impl<'a, T: PrettyPrint> fmt::Display for PrettyPrinter<'a, T> {
  84. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  85. T::pretty_print(&self.buffer, f, &mut PrettyIndent::new(self.prefix))
  86. }
  87. }