crlify/
lib.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5//! [`BufWriterWithLineEndingFix`].
6
7use std::io::{BufWriter, Result, Write};
8
9/// A small helper class to convert LF to CRLF on Windows.
10/// Workaround for <https://github.com/serde-rs/json/issues/535>
11pub struct BufWriterWithLineEndingFix<W: Write> {
12    inner: BufWriter<W>,
13    #[cfg(windows)]
14    last_written: Option<u8>,
15}
16
17impl<W: Write> BufWriterWithLineEndingFix<W> {
18    pub fn new(inner: W) -> Self {
19        Self {
20            inner: BufWriter::with_capacity(4096, inner),
21            #[cfg(windows)]
22            last_written: None,
23        }
24    }
25}
26
27impl<W: Write> Write for BufWriterWithLineEndingFix<W> {
28    #[cfg(windows)]
29    fn write(&mut self, buf: &[u8]) -> Result<usize> {
30        for &b in buf.iter() {
31            if b == b'\n' && self.last_written != Some(b'\r') {
32                // Note: Since we need to emit the \r, we are adding extra bytes than were in
33                // the input buffer. BufWriter helps because short writes (less than 4096 B)
34                // will always write or fail in their entirety.
35                self.inner.write(b"\r\n")
36            } else {
37                self.last_written = Some(b);
38                self.inner.write(&[b])
39            }?;
40        }
41        // The return value is the number of *input* bytes that were written.
42        Ok(buf.len())
43    }
44
45    #[cfg(not(windows))]
46    #[inline]
47    fn write(&mut self, buf: &[u8]) -> Result<usize> {
48        self.inner.write(buf)
49    }
50
51    #[inline]
52    fn flush(&mut self) -> Result<()> {
53        self.inner.flush()
54    }
55}