Просмотр исходного кода

Add a custom debug formatter implementation for RollingBitField (#3078)

dmakarov 1 год назад
Родитель
Сommit
a07da92692
1 измененных файлов с 77 добавлено и 1 удалено
  1. 77 1
      accounts-db/src/rolling_bit_field.rs

+ 77 - 1
accounts-db/src/rolling_bit_field.rs

@@ -9,7 +9,7 @@ use {
 };
 
 #[cfg_attr(feature = "frozen-abi", derive(AbiExample))]
-#[derive(Debug, Clone)]
+#[derive(Clone)]
 pub struct RollingBitField {
     max_width: u64,
     min: u64,
@@ -38,6 +38,60 @@ impl PartialEq<RollingBitField> for RollingBitField {
     }
 }
 
+impl std::fmt::Debug for RollingBitField {
+    /// Custom debug formatter that outputs the possibly long and
+    /// sparse vector of bits in a compact representation, where each
+    /// sequence of equal values is compacted into value;length pair
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let mut bits = String::from("[");
+        let mut prev = self.bits[0];
+        bits.push_str(&format!("{}", prev));
+        let mut index = 1;
+        while index < self.bits.len() {
+            if self.bits[index] != prev {
+                prev = self.bits[index];
+                break;
+            }
+            index += 1;
+        }
+        if index > 1 {
+            bits.push_str(&format!(";{}", index));
+        }
+        if index < self.bits.len() {
+            bits.push_str(&format!(", {}", prev));
+        }
+        let mut count = 0;
+        while index < self.bits.len() {
+            if self.bits[index] != prev {
+                if count > 1 {
+                    bits.push_str(&format!(";{}", count));
+                }
+                count = 0;
+                prev = self.bits[index];
+                bits.push_str(&format!(", {}", prev));
+            }
+            count += 1;
+            index += 1;
+        }
+        if count > 1 {
+            bits.push_str(&format!(";{}", count));
+        }
+        bits.push(']');
+        // The order of the `count` and `bits` fields is changed on
+        // purpose so that possibly very long output of `bits` doesn't
+        // make it more difficult to read the value of the `count`
+        // field.
+        f.debug_struct("RollingBitField")
+            .field("max_width", &self.max_width)
+            .field("min", &self.min)
+            .field("max_exclusive", &self.max_exclusive)
+            .field("count", &self.count)
+            .field("bits", &bits)
+            .field("excess", &self.excess)
+            .finish()
+    }
+}
+
 /// functionally similar to a hashset
 /// Relies on there being a sliding window of key values. The key values continue to increase.
 /// Old key values are removed from the lesser values and do not accumulate.
@@ -1002,4 +1056,26 @@ pub mod tests {
             assert_eq!(count, count2);
         }
     }
+
+    #[test]
+    fn test_debug_formatter() {
+        let mut bitfield = RollingBitField::new(1);
+        assert_eq!("RollingBitField { max_width: 1, min: 0, max_exclusive: 0, count: 0, bits: \"[false]\", excess: {} }", format!("{bitfield:?}"));
+        bitfield.insert(0);
+        assert_eq!("RollingBitField { max_width: 1, min: 0, max_exclusive: 1, count: 1, bits: \"[true]\", excess: {} }", format!("{bitfield:?}"));
+        let mut bitfield = RollingBitField::new(2);
+        assert_eq!("RollingBitField { max_width: 2, min: 0, max_exclusive: 0, count: 0, bits: \"[false;2]\", excess: {} }", format!("{bitfield:?}"));
+        bitfield.insert(0);
+        assert_eq!("RollingBitField { max_width: 2, min: 0, max_exclusive: 1, count: 1, bits: \"[true, false]\", excess: {} }", format!("{bitfield:?}"));
+        bitfield.insert(1);
+        assert_eq!("RollingBitField { max_width: 2, min: 0, max_exclusive: 2, count: 2, bits: \"[true;2]\", excess: {} }", format!("{bitfield:?}"));
+        let mut bitfield = RollingBitField::new(4096);
+        assert_eq!("RollingBitField { max_width: 4096, min: 0, max_exclusive: 0, count: 0, bits: \"[false;4096]\", excess: {} }", format!("{bitfield:?}"));
+        bitfield.insert(4095);
+        assert_eq!("RollingBitField { max_width: 4096, min: 4095, max_exclusive: 4096, count: 1, bits: \"[false;4095, true]\", excess: {} }", format!("{bitfield:?}"));
+        bitfield.clear();
+        bitfield.insert(2);
+        bitfield.insert(3);
+        assert_eq!("RollingBitField { max_width: 4096, min: 2, max_exclusive: 4, count: 2, bits: \"[false;2, true;2, false;4092]\", excess: {} }", format!("{bitfield:?}"));
+    }
 }