1use std::fmt;
2
3use bytes::{Bytes, BytesMut};
4
5pub struct ByteSize(pub u64);
20
21impl fmt::Debug for ByteSize {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 const KIB: u64 = 1024;
24 const MIB: u64 = 1024 * KIB;
25 const GIB: u64 = 1024 * MIB;
26 const TIB: u64 = 1024 * GIB;
27
28 macro_rules! fmt_unit {
29 ($val:expr, $unit:expr, $unit_str:expr) => {{
30 let whole = $val / $unit;
31 let rem = $val % $unit;
32 if rem == 0 {
33 write!(f, "{}{}", whole, $unit_str)
34 } else {
35 let frac = rem * 100 / $unit;
38 if frac % 10 == 0 {
39 write!(f, "{}.{}{}", whole, frac / 10, $unit_str)
41 } else {
42 write!(f, "{}.{:02}{}", whole, frac, $unit_str)
43 }
44 }
45 }};
46 }
47
48 match self.0 {
49 b if b >= TIB => fmt_unit!(b, TIB, "TiB"),
50 b if b >= GIB => fmt_unit!(b, GIB, "GiB"),
51 b if b >= MIB => fmt_unit!(b, MIB, "MiB"),
52 b if b >= KIB => fmt_unit!(b, KIB, "KiB"),
53 b => write!(f, "{}B", b),
54 }
55 }
56}
57
58pub struct PrettyBytes<'a>(pub &'a [u8]);
70
71impl fmt::Debug for PrettyBytes<'_> {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 write!(f, "b\"")?;
74 for &b in self.0 {
75 match b {
76 b' '..=b'~' => write!(f, "{}", b as char)?,
78 _ => write!(f, "\\x{:02x}", b)?,
80 }
81 }
82 write!(f, "\"")
83 }
84}
85
86macro_rules! impl_hex {
87 ($name:ident, $type:ty) => {
88 impl_hex!($name, $type, $type);
89 };
90 ($name:ident, $type:ty, $unsigned:ty) => {
91 #[doc = concat!(
92 "Helper struct that wraps a [`",
93 stringify!($type),
94 "`] and improves its [`std::fmt::Debug`] formatting. ",
95 "Formats the value as a zero-padded hexadecimal number with a `0x` prefix, ",
96 "padded to the full bit-width of [`",
97 stringify!($type),
98 "`]. ",
99 "Signed types are cast to their unsigned counterpart before formatting, ",
100 "giving the two's complement representation without a sign prefix.",
101 )]
102 pub struct $name(pub $type);
103
104 impl fmt::Debug for $name {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 write!(f, "0x{:x}", self.0 as $unsigned)
107 }
108 }
109 };
110}
111
112impl_hex!(HexU8, u8);
113impl_hex!(HexU16, u16);
114impl_hex!(HexU32, u32);
115impl_hex!(HexU64, u64);
116impl_hex!(HexI8, i8, u8);
117impl_hex!(HexI16, i16, u16);
118impl_hex!(HexI32, i32, u32);
119impl_hex!(HexI64, i64, u64);
120
121#[inline(always)]
122pub fn contains_null(v: impl AsRef<[u8]>) -> bool {
123 let v = v.as_ref();
124 memchr::memchr(0, v).is_some()
125}
126
127pub fn next_prefix(prefix: &[u8]) -> Option<Bytes> {
128 let mut buf = BytesMut::from(prefix);
129 while buf.last() == Some(&0xFF) {
130 buf.truncate(buf.len() - 1);
131 }
132 let last = buf.last_mut()?;
133 *last += 1;
134 Some(buf.freeze())
135}