falco_event/types/
bytebuf.rs

1use crate::fields::{FromBytes, FromBytesError, ToBytes};
2use std::fmt::{Debug, Formatter, Write as _};
3use std::io::Write;
4
5impl<'a> FromBytes<'a> for &'a [u8] {
6    #[inline]
7    fn from_bytes(buf: &mut &'a [u8]) -> Result<Self, FromBytesError> {
8        Ok(std::mem::take(buf))
9    }
10}
11
12impl ToBytes for &[u8] {
13    #[inline]
14    fn binary_size(&self) -> usize {
15        self.len()
16    }
17
18    #[inline]
19    fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
20        writer.write_all(self)
21    }
22
23    #[inline]
24    fn default_repr() -> impl ToBytes {
25        &[] as &[u8]
26    }
27}
28
29/// Falco-style byte buffer formatter
30///
31/// The default [`Debug`] impl prints out the buffer as an ASCII string, replacing non-printable
32/// characters with dots (`.`).
33///
34/// The hex debug implementation (`{:x?}`) generates a hex dump of the whole buffer.
35pub struct ByteBufFormatter<'a>(pub &'a [u8]);
36
37impl Debug for ByteBufFormatter<'_> {
38    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
39        // https://users.rust-lang.org/t/idiomatic-to-implement-the-debug-trait-for-x-syntax/84955
40        #[allow(deprecated)]
41        if f.flags() & 16 != 0 {
42            let mut first = true;
43            for c in self.0 {
44                if first {
45                    first = false;
46                } else {
47                    write!(f, " ")?;
48                }
49                write!(f, "{:02x}", *c)?;
50            }
51        } else {
52            for c in self.0 {
53                let c = *c;
54                if !(b' '..=0x7e).contains(&c) {
55                    f.write_char('.')?;
56                } else {
57                    f.write_char(c as char)?;
58                }
59            }
60        }
61
62        Ok(())
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use crate::fields::{FromBytes, ToBytes};
69
70    #[test]
71    fn test_bytebuf() {
72        let data = b"foo".as_slice();
73        let mut binary = Vec::new();
74
75        data.write(&mut binary).unwrap();
76        hexdump::hexdump(binary.as_slice());
77
78        assert_eq!(binary.as_slice(), "foo".as_bytes());
79
80        let mut buf = binary.as_slice();
81        let loaded = <&[u8]>::from_bytes(&mut buf).unwrap();
82        assert_eq!(loaded, "foo".as_bytes());
83    }
84
85    #[test]
86    fn test_bytebuf_inner_nul() {
87        let data = b"f\0oo".as_slice();
88        let mut binary = Vec::new();
89
90        data.write(&mut binary).unwrap();
91        hexdump::hexdump(binary.as_slice());
92
93        assert_eq!(binary.as_slice(), "f\0oo".as_bytes());
94
95        let mut buf = binary.as_slice();
96        let loaded = <&[u8]>::from_bytes(&mut buf).unwrap();
97        assert_eq!(loaded, "f\0oo".as_bytes());
98    }
99}