errgonomic/types/
prefixer.rs1use std::fmt;
2use std::io::{self, Write};
3
4pub struct Prefixer<'w> {
9 pub first_line_prefix: String,
11 pub next_line_prefix: String,
13 pub writer: &'w mut dyn Write,
15 pub is_first_line: bool,
17 pub needs_prefix: bool,
19}
20
21impl<'w> fmt::Debug for Prefixer<'w> {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 f.debug_struct("Prefixer")
24 .field("first_line_prefix", &self.first_line_prefix)
25 .field("next_line_prefix", &self.next_line_prefix)
26 .field("is_first_line", &self.is_first_line)
27 .field("needs_prefix", &self.needs_prefix)
28 .finish()
29 }
30}
31
32impl<'w> Prefixer<'w> {
33 pub fn new(first_line_prefix: impl Into<String>, next_line_prefix: impl Into<String>, writer: &'w mut dyn Write) -> Self {
35 Self {
36 first_line_prefix: first_line_prefix.into(),
37 next_line_prefix: next_line_prefix.into(),
38 writer,
39 is_first_line: true,
40 needs_prefix: true,
41 }
42 }
43}
44
45impl<'w> Write for Prefixer<'w> {
46 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
47 if buf.is_empty() {
48 return Ok(0);
49 }
50
51 let mut start = 0;
52 while start < buf.len() {
53 if self.needs_prefix {
54 let prefix = if self.is_first_line { &self.first_line_prefix } else { &self.next_line_prefix };
55 self.writer.write_all(prefix.as_bytes())?;
56 self.is_first_line = false;
57 self.needs_prefix = false;
58 }
59
60 match buf[start..].iter().position(|&b| b == b'\n') {
61 Some(relative_idx) => {
62 let end = start + relative_idx + 1;
63 self.writer.write_all(&buf[start..end])?;
64 start = end;
65 self.needs_prefix = true;
66 }
67 None => {
68 self.writer.write_all(&buf[start..])?;
69 start = buf.len();
70 }
71 }
72 }
73
74 Ok(buf.len())
75 }
76
77 fn flush(&mut self) -> io::Result<()> {
78 self.writer.flush()
79 }
80}