use std::fs::File;
use std::io::{BufWriter, Write};
pub struct FileArenaWriter {
file: File,
writer: BufWriter<File>,
cursor: usize,
}
impl FileArenaWriter {
pub fn new() -> std::io::Result<Self> {
let file = tempfile::tempfile()?;
let writer = BufWriter::new(file.try_clone()?);
Ok(Self {
file,
writer,
cursor: 0,
})
}
pub fn push(&mut self, data: impl AsRef<[u8]>) -> std::io::Result<(usize, usize)> {
let data = data.as_ref();
if data.is_empty() {
return Ok((0, 0));
}
let offset = self.cursor;
self.writer.write_all(data)?;
self.cursor += data.len();
Ok((offset, data.len()))
}
pub fn len(&self) -> usize {
self.cursor
}
pub fn is_empty(&self) -> bool {
self.cursor == 0
}
pub fn finish(mut self) -> std::io::Result<Option<File>> {
self.writer.flush()?;
if self.is_empty() {
Ok(None)
} else {
Ok(Some(self.file))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn push_empty_is_noop() {
let mut writer = FileArenaWriter::new().unwrap();
let (offset, len) = writer.push("").unwrap();
assert_eq!(offset, 0);
assert_eq!(len, 0);
assert!(writer.is_empty());
}
#[test]
fn finish_returns_none_when_empty() {
let writer = FileArenaWriter::new().unwrap();
assert!(writer.finish().unwrap().is_none());
}
#[test]
fn finish_returns_none_after_only_empty_pushes() {
let mut writer = FileArenaWriter::new().unwrap();
writer.push("").unwrap();
writer.push(b"").unwrap();
assert!(writer.finish().unwrap().is_none());
}
}