use std::{
fmt::Display,
io::{self, BufWriter, Write},
};
#[inline]
pub fn display_buffered<I, T, W>(values: I, writer: W) -> Result<(), io::Error>
where
T: Display,
I: IntoIterator<Item = T>,
W: Write,
{
let values = values.into_iter().map(|item| format!("{item}\n"));
write_buffered(values, writer)
}
#[inline]
pub fn write_buffered<T, I, W>(values: I, writer: W) -> Result<(), io::Error>
where
T: AsRef<[u8]>,
I: IntoIterator<Item = T>,
W: Write,
{
let mut writer = BufWriter::new(writer);
for bytes in values {
writer.write_all(bytes.as_ref())?
}
writer.flush()
}
#[inline]
pub fn write_buffered_separated<T, I, W>(
values: I,
mut writer: W,
sep: &[u8],
) -> Result<(), io::Error>
where
T: AsRef<[u8]>,
I: IntoIterator<Item = T>,
W: Write,
{
let mut values = values.into_iter();
let mut buf_writer;
match values.next() {
Some(val) => {
buf_writer = BufWriter::new(writer);
buf_writer.write_all(val.as_ref())?
}
None => return writer.flush(),
}
for bytes in values {
buf_writer.write_all(sep)?;
buf_writer.write_all(bytes.as_ref())?
}
buf_writer.flush()
}
#[inline]
pub fn write_buffered_separated_with<T, I, W, U, F>(
values: I,
mut writer: W,
mut f: F,
) -> Result<(), io::Error>
where
T: AsRef<[u8]>,
I: IntoIterator<Item = T>,
W: Write,
U: AsRef<[u8]>,
F: FnMut(usize, &[u8]) -> U,
{
let mut values = values.into_iter().enumerate();
let mut buf_writer;
match values.next() {
Some((_, val)) => {
buf_writer = BufWriter::new(writer);
buf_writer.write_all(val.as_ref())?
}
None => return writer.flush(),
}
for (pos, bytes) in values {
let bytes = bytes.as_ref();
buf_writer.write_all(f(pos, bytes).as_ref())?;
buf_writer.write_all(bytes)?
}
buf_writer.flush()
}
#[cfg(test)]
mod tests {
use super::*;
struct Writer(Vec<u8>);
impl Writer {
fn new() -> Self {
Self(Vec::new())
}
fn into_inner(self) -> Vec<u8> {
self.0
}
}
impl Write for Writer {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.extend(buf);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[test]
fn test_display_buffered() {
let mut writer = Writer::new();
display_buffered([10, 20], &mut writer).unwrap();
assert_eq!(writer.into_inner(), b"10\n20\n")
}
#[test]
fn test_write_buffered_with_slices() {
let mut writer = Writer::new();
write_buffered(["It ", "Works"], &mut writer).unwrap();
assert_eq!(writer.into_inner(), b"It Works")
}
#[test]
fn test_write_buffered_with_strings() {
let mut writer = Writer::new();
write_buffered(["It ".to_owned(), "Works".to_owned()], &mut writer).unwrap();
assert_eq!(writer.into_inner(), b"It Works")
}
#[test]
fn test_write_buffered_with_bytes() {
let mut writer = Writer::new();
let values: [&[u8]; 2] = [b"It ", b"Works"];
write_buffered(values, &mut writer).unwrap();
assert_eq!(writer.into_inner(), b"It Works")
}
#[test]
fn test_write_buffered_with_separator() {
let mut writer = Writer::new();
write_buffered_separated(["It", "Just", "Works"], &mut writer, b" ").unwrap();
assert_eq!(writer.into_inner(), b"It Just Works")
}
#[test]
fn test_write_buffered_separated_with() {
let mut writer = Writer::new();
write_buffered_separated_with(["It", "Just", "Works"], &mut writer, |i, _| {
if i % 2 == 0 {
"_"
} else {
"-"
}
})
.unwrap();
assert_eq!(
String::from_utf8(writer.into_inner()).unwrap(),
"It-Just_Works"
)
}
}