Skip to main content

raft_log/
dump_writer.rs

1use std::fmt;
2use std::io;
3
4use codeq::OffsetSize;
5
6use crate::ChunkId;
7use crate::Types;
8use crate::WALRecord;
9use crate::num::format_pad9_u64;
10use crate::types::Segment;
11
12struct DebugAsDisplay<'a, T: fmt::Debug>(&'a T);
13
14impl<T: fmt::Debug> fmt::Display for DebugAsDisplay<'_, T> {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        fmt::Debug::fmt(self.0, f)
17    }
18}
19
20pub fn write_record_debug<T: Types, W: io::Write>(
21    w: &mut W,
22    chunk_id: ChunkId,
23    in_chunk_record_index: u64,
24    res: Result<(Segment, WALRecord<T>), io::Error>,
25) -> Result<(), io::Error> {
26    match res {
27        Ok((seg, rec)) => write_ok(
28            w,
29            chunk_id,
30            in_chunk_record_index,
31            &seg,
32            &DebugAsDisplay(&rec),
33        ),
34        Err(e) => writeln!(w, "Error: {}", e),
35    }
36}
37
38/// Write each record using `std::fmt::Display` instead of using
39/// `std::fmt::Debug`
40pub fn write_record_display<T: Types, W: io::Write>(
41    w: &mut W,
42    chunk_id: ChunkId,
43    in_chunk_record_index: u64,
44    res: Result<(Segment, WALRecord<T>), io::Error>,
45) -> Result<(), io::Error>
46where
47    WALRecord<T>: fmt::Display,
48{
49    match res {
50        Ok((seg, rec)) => {
51            write_ok(w, chunk_id, in_chunk_record_index, &seg, &rec)
52        }
53        Err(e) => writeln!(w, "Error: {}", e),
54    }
55}
56
57fn write_ok<W: io::Write>(
58    w: &mut W,
59    chunk_id: ChunkId,
60    in_chunk_record_index: u64,
61    seg: &Segment,
62    rec: &dyn fmt::Display,
63) -> Result<(), io::Error> {
64    if seg.offset().0 == 0 {
65        writeln!(w, "{}", chunk_id)?;
66    }
67    writeln!(
68        w,
69        "  R-{in_chunk_record_index:05}: [{}, {}) {}: {}",
70        format_pad9_u64(*seg.offset()),
71        format_pad9_u64(*seg.end()),
72        seg.size(),
73        rec
74    )
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80    use crate::testing::TestDisplayTypes;
81
82    fn make_input() -> Result<(Segment, WALRecord<TestDisplayTypes>), io::Error>
83    {
84        Ok((
85            Segment::new(0, 10),
86            WALRecord::Append(3, "hello".to_string()),
87        ))
88    }
89
90    #[test]
91    fn test_write_record_debug_vs_display() {
92        let mut debug_buf = Vec::new();
93        write_record_debug(&mut debug_buf, ChunkId(0), 0, make_input())
94            .unwrap();
95        let debug_out = String::from_utf8(debug_buf).unwrap();
96
97        let mut display_buf = Vec::new();
98        write_record_display(&mut display_buf, ChunkId(0), 0, make_input())
99            .unwrap();
100        let display_out = String::from_utf8(display_buf).unwrap();
101
102        // Debug uses derived format: Append(3, "hello")
103        assert!(
104            debug_out.contains(r#"Append(3, "hello")"#),
105            "got: {debug_out}"
106        );
107        // Display uses manual format: Append(log_id: 3, payload: hello)
108        assert!(
109            display_out.contains("Append(log_id: 3, payload: hello)"),
110            "got: {display_out}"
111        );
112    }
113}