use anyhow::Result;
use std::fs::File;
use std::io::Write;
use std::sync::Mutex;
use zisk_common::io::{StreamError, StreamSink};
pub struct HintsFile {
file: Mutex<File>,
}
impl HintsFile {
pub fn new(filename: String) -> Result<Self> {
let file = File::create(&filename)?;
Ok(Self { file: Mutex::new(file) })
}
}
impl StreamSink for HintsFile {
#[inline]
fn submit(&self, processed: &[u64]) -> Result<(), StreamError> {
let mut file = self.file.lock().unwrap();
for value in processed {
file.write_all(&value.to_le_bytes())?;
}
file.flush()?;
Ok(())
}
}
impl Drop for HintsFile {
fn drop(&mut self) {
if let Ok(mut file) = self.file.lock() {
let _ = file.flush();
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Read;
use zisk_common::io::StreamSink;
#[test]
fn submit_writes_u64s_little_endian_then_flushes_on_drop() {
let path =
std::env::temp_dir().join(format!("zisk_hintsfile_test_{}.bin", std::process::id()));
let path_str = path.to_str().unwrap().to_string();
let values = [1u64, 0x0203, u64::MAX];
{
let hf = HintsFile::new(path_str.clone()).unwrap();
hf.submit(&values).unwrap();
}
let mut bytes = Vec::new();
std::fs::File::open(&path).unwrap().read_to_end(&mut bytes).unwrap();
let expected: Vec<u8> = values.iter().flat_map(|v| v.to_le_bytes()).collect();
assert_eq!(bytes, expected);
std::fs::remove_file(&path).ok();
}
#[test]
fn submit_appends_across_calls() {
let path =
std::env::temp_dir().join(format!("zisk_hintsfile_append_{}.bin", std::process::id()));
let path_str = path.to_str().unwrap().to_string();
{
let hf = HintsFile::new(path_str).unwrap();
hf.submit(&[1u64]).unwrap();
hf.submit(&[2u64]).unwrap();
}
let mut bytes = Vec::new();
std::fs::File::open(&path).unwrap().read_to_end(&mut bytes).unwrap();
assert_eq!(bytes.len(), 16); std::fs::remove_file(&path).ok();
}
}