use memmap2::{Mmap, MmapMut};
use std::fs::File;
use std::io::{self, Read};
use std::ops::{Deref, DerefMut};
mod examples;
#[cfg(feature = "npz")]
mod npz;
mod primitive;
mod round_trip;
pub struct MaybeAlignedBytes {
buf: Vec<u8>,
start: usize,
len: usize,
align: usize,
}
impl MaybeAlignedBytes {
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn maybe_align(&self) -> usize {
self.align
}
pub fn is_aligned(&self) -> bool {
(self.buf.as_ptr() as usize + self.start) % self.align == 0
}
pub fn aligned_zeros(len: usize, align: usize) -> MaybeAlignedBytes {
let buf = vec![0; len + align];
let start = align - buf.as_ptr() as usize % align;
let out = MaybeAlignedBytes {
buf,
start,
len,
align,
};
debug_assert!(out.is_aligned());
out
}
pub fn misaligned_zeros(len: usize, align: usize) -> MaybeAlignedBytes {
assert!(
align > 1,
"`align` must be > 1 in order to create misaligned bytes."
);
let mut out = MaybeAlignedBytes::aligned_zeros(len, align);
if out.start > 0 {
out.start -= 1;
} else {
out.start += 1;
}
debug_assert!(!out.is_aligned());
debug_assert!(out.buf.len() >= out.start + out.len);
out
}
pub fn aligned_from_bytes(bytes: Vec<u8>, align: usize) -> MaybeAlignedBytes {
let len = bytes.len();
if bytes.as_ptr() as usize % align == 0 {
MaybeAlignedBytes {
buf: bytes,
start: 0,
len,
align,
}
} else {
let mut out = MaybeAlignedBytes::aligned_zeros(len, align);
out.copy_from_slice(&bytes);
out
}
}
pub fn misaligned_from_bytes(bytes: Vec<u8>, align: usize) -> MaybeAlignedBytes {
let len = bytes.len();
if bytes.as_ptr() as usize % align != 0 {
MaybeAlignedBytes {
buf: bytes,
start: 0,
len,
align,
}
} else {
let mut out = MaybeAlignedBytes::misaligned_zeros(len, align);
out.copy_from_slice(&bytes);
out
}
}
}
impl Deref for MaybeAlignedBytes {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.buf[self.start..self.start + self.len]
}
}
impl DerefMut for MaybeAlignedBytes {
fn deref_mut(&mut self) -> &mut [u8] {
&mut self.buf[self.start..self.start + self.len]
}
}
macro_rules! impl_file_to_aligned_bytes {
($name:ident, $deref:ident, $mmap:path) => {
pub unsafe fn $name(mut file: &File) -> io::Result<Box<dyn $deref<Target = [u8]>>> {
const ALIGN: usize = 64;
if cfg!(miri) {
let mut bytes = Vec::new();
file.read_to_end(&mut bytes)?;
Ok(Box::new(MaybeAlignedBytes::aligned_from_bytes(
bytes, ALIGN,
)))
} else {
let out = Box::new($mmap(file)?);
assert_eq!(0, out.as_ptr() as usize % ALIGN);
Ok(out)
}
}
};
}
impl_file_to_aligned_bytes!(file_to_aligned_bytes, Deref, Mmap::map);
impl_file_to_aligned_bytes!(file_to_aligned_mut_bytes, DerefMut, MmapMut::map_mut);