use std::fs::File;
use std::io;
use std::ops::Deref;
use std::path::Path;
#[derive(Debug)]
pub struct Blob(Inner);
#[derive(Debug)]
enum Inner {
Mapped(memmap2::Mmap),
Owned(Vec<u8>),
}
impl Blob {
pub fn map(path: impl AsRef<Path>) -> io::Result<Self> {
let file = File::open(path)?;
if file.metadata()?.len() == 0 {
return Ok(Self(Inner::Owned(Vec::new())));
}
let map = unsafe { memmap2::Mmap::map(&file)? };
Ok(Self(Inner::Mapped(map)))
}
#[must_use]
pub fn owned(bytes: Vec<u8>) -> Self {
Self(Inner::Owned(bytes))
}
#[must_use]
pub fn is_mapped(&self) -> bool {
matches!(self.0, Inner::Mapped(_))
}
}
impl Deref for Blob {
type Target = [u8];
fn deref(&self) -> &[u8] {
match &self.0 {
Inner::Mapped(m) => m,
Inner::Owned(v) => v,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn maps_a_file() {
let path = std::env::temp_dir().join(format!("kime-blob-{}", std::process::id()));
std::fs::write(&path, b"hello").unwrap();
let b = Blob::map(&path).unwrap();
assert!(b.is_mapped());
assert_eq!(&*b, b"hello");
drop(b);
std::fs::write(&path, b"").unwrap();
assert_eq!(Blob::map(&path).unwrap().len(), 0);
std::fs::remove_file(path).unwrap();
}
}