use std::fmt;
use std::ops::Deref;
use super::{Artifact, Error};
pub(crate) struct IndexBytes(Inner);
enum Inner {
#[cfg(any(target_os = "macos", target_os = "linux"))]
Mapped {
start: std::ptr::NonNull<u8>,
len: usize,
},
Owned(Vec<u8>),
}
#[cfg(any(target_os = "macos", target_os = "linux"))]
unsafe impl Send for IndexBytes {}
#[cfg(any(target_os = "macos", target_os = "linux"))]
unsafe impl Sync for IndexBytes {}
impl IndexBytes {
pub(crate) fn of(artifact: &Artifact) -> Result<Self, Error> {
#[cfg(any(target_os = "macos", target_os = "linux"))]
if artifact.len != 0 {
use rustix::mm::{MapFlags, ProtFlags, mmap};
let mapped = unsafe {
mmap(
std::ptr::null_mut(),
artifact.len,
ProtFlags::READ,
MapFlags::PRIVATE,
&*artifact.file,
0,
)
};
if let Ok(start) = mapped
&& let Some(start) = std::ptr::NonNull::new(start.cast::<u8>())
{
#[cfg(test)]
artifact
.bytes_read
.fetch_add(artifact.len, std::sync::atomic::Ordering::Relaxed);
return Ok(Self(Inner::Mapped {
start,
len: artifact.len,
}));
}
}
artifact
.bytes(0, artifact.len)
.map(|bytes| Self(Inner::Owned(bytes)))
}
#[cfg(test)]
pub(crate) fn is_mapped(&self) -> bool {
!matches!(self.0, Inner::Owned(_))
}
}
impl Deref for IndexBytes {
type Target = [u8];
fn deref(&self) -> &[u8] {
match &self.0 {
#[cfg(any(target_os = "macos", target_os = "linux"))]
Inner::Mapped { start, len } => unsafe {
std::slice::from_raw_parts(start.as_ptr(), *len)
},
Inner::Owned(bytes) => bytes,
}
}
}
impl Drop for IndexBytes {
fn drop(&mut self) {
#[cfg(any(target_os = "macos", target_os = "linux"))]
if let Inner::Mapped { start, len } = self.0 {
let _ = unsafe { rustix::mm::munmap(start.as_ptr().cast(), len) };
}
}
}
impl fmt::Debug for IndexBytes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("IndexBytes")
.field("len", &self.len())
.finish_non_exhaustive()
}
}