use std::io;
use std::path::Path;
use std::sync::{Arc, Weak};
use std::time::SystemTime;
#[derive(Debug)]
enum Inner {
Mapped(memmap2::Mmap),
Memory(Vec<u8>),
}
impl Inner {
fn data(&self) -> &[u8] {
match self {
Self::Mapped(mmap) => &*mmap,
Self::Memory(vec) => &vec,
}
}
}
#[derive(Clone, Debug)]
#[repr(transparent)]
pub struct SharedData {
inner: Arc<Inner>,
}
#[derive(Clone, Debug)]
#[repr(transparent)]
pub struct WeakSharedData {
inner: Weak<Inner>,
}
impl WeakSharedData {
pub fn upgrade(&self) -> Option<SharedData> {
Some(SharedData {
inner: self.inner.upgrade()?,
})
}
}
impl SharedData {
pub fn new(data: Vec<u8>) -> Self {
Self {
inner: Arc::new(Inner::Memory(data)),
}
}
pub fn from_file(
path: impl AsRef<Path>,
mmap: bool,
timestamp: Option<SystemTime>,
) -> Result<Self, io::Error> {
let path = path.as_ref();
if let Some(timestamp) = timestamp {
let metadata = path.metadata()?;
let current_timestamp = metadata.modified()?;
if timestamp != current_timestamp {
return Err(io::Error::from(io::ErrorKind::InvalidData));
}
}
let inner = Arc::new(if mmap {
let file = std::fs::File::open(path)?;
let map = unsafe { memmap2::Mmap::map(&file)? };
Inner::Mapped(map)
} else {
let data = std::fs::read(path)?;
Inner::Memory(data)
});
Ok(Self { inner })
}
pub fn downgrade(&self) -> WeakSharedData {
WeakSharedData {
inner: Arc::downgrade(&self.inner),
}
}
pub fn as_bytes(&self) -> &[u8] {
self.inner.data()
}
pub fn strong_count(&self) -> usize {
Arc::strong_count(&self.inner)
}
}
impl std::ops::Deref for SharedData {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.inner.data()
}
}
impl AsRef<[u8]> for SharedData {
fn as_ref(&self) -> &[u8] {
self.inner.data()
}
}