use std::{
fs::{self, File},
io,
num::Wrapping,
path::Path,
};
use tempfile::Builder;
pub fn write_atomic<F>(path: impl AsRef<Path>, write: F) -> std::io::Result<()>
where
F: FnOnce(&mut std::fs::File) -> std::io::Result<()>,
{
let parent = path.as_ref().parent().ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"cannot create file without parent directory",
)
})?;
fs::create_dir_all(parent)?;
let mut tmpfile = Builder::new().prefix(".m2dir.tmp.").tempfile_in(parent)?;
write(tmpfile.as_file_mut())?;
tmpfile.as_file().sync_all()?;
tmpfile.persist_noclobber(&path)?;
Ok(())
}
pub fn copy_atomic(from: impl AsRef<Path>, to: impl AsRef<Path>) -> std::io::Result<()> {
let mut from = File::open(&from)?;
write_atomic(to, |f| {
io::copy(&mut from, f)?;
Ok(())
})
}
pub fn fnv64(salt: &[u8], data: &[u8]) -> u64 {
let prime = Wrapping(1099511628211u64);
let offset: u64 = 14695981039346656037;
let mut sum = Wrapping(offset);
for b in salt {
let byte = Wrapping(u64::from(*b));
sum ^= byte;
sum *= prime;
}
for b in data {
let byte = Wrapping(u64::from(*b));
sum ^= byte;
sum *= prime;
}
sum.0
}