use core::borrow::Borrow;
use core::fmt::Debug;
use core::ops::Deref;
use core::ops::DerefMut;
use crate::aligned_bytes::{
to_alignedslice_unchecked, to_alignedslice_unchecked_mut, AlignedSlice, Alignment, AsAligned,
A8,
};
pub struct AlignedBuf {
data: Vec<u8>,
}
impl Debug for AlignedBuf {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let x: &[u8] = self.as_ref();
std::fmt::Debug::fmt(x, f)
}
}
impl AlignedBuf {
pub fn new() -> Self {
AlignedBuf { data: vec![] }
}
pub fn with_vec<T>(&mut self, f: impl FnOnce(&mut Vec<u8>) -> T) -> T {
unalign(&mut self.data);
let guard = RealignGuard(&mut self.data);
f(guard.0)
}
}
struct RealignGuard<'a>(&'a mut Vec<u8>);
impl<'a> Drop for RealignGuard<'a> {
fn drop(&mut self) {
align(self.0)
}
}
impl Default for AlignedBuf {
fn default() -> Self {
Self::new()
}
}
fn offset_to_align(v: &[u8]) -> usize {
if v.is_empty() {
0
} else {
let p = &v[0] as *const u8 as usize;
let out = p.wrapping_neg() & 7;
debug_assert!((p + out) & 7 == 0);
out
}
}
#[inline]
fn is_aligned(v: &[u8]) -> bool {
v.is_empty() || (&v[0] as *const u8 as usize & 7) == 0
}
fn align(data: &mut Vec<u8>) {
if !is_aligned(data) {
align_cold(data)
}
}
#[cold]
#[inline(never)]
fn align_cold(data: &mut Vec<u8>) {
data.reserve(7);
let off = offset_to_align(data);
data.resize(data.len() + off, 0);
data.rotate_right(off)
}
fn unalign(data: &mut Vec<u8>) {
if !is_aligned(data) {
unalign_cold(data)
}
}
#[cold]
#[inline(never)]
fn unalign_cold(data: &mut Vec<u8>) {
let off = offset_to_align(data);
data.rotate_left(off);
data.truncate(data.len() - off);
}
impl From<Vec<u8>> for AlignedBuf {
fn from(mut data: Vec<u8>) -> Self {
align(&mut data);
Self { data }
}
}
impl From<AlignedBuf> for Vec<u8> {
fn from(mut b: AlignedBuf) -> Self {
unalign(&mut b.data);
b.data
}
}
impl Deref for AlignedBuf {
type Target = AlignedSlice<A8>;
fn deref(&self) -> &Self::Target {
let s = &self.data[offset_to_align(&self.data)..];
unsafe {
to_alignedslice_unchecked(s)
}
}
}
impl DerefMut for AlignedBuf {
fn deref_mut(&mut self) -> &mut Self::Target {
let off = offset_to_align(&self.data);
let s = &mut self.data[off..];
unsafe {
to_alignedslice_unchecked_mut(s)
}
}
}
impl<A: Alignment> Borrow<AlignedSlice<A>> for AlignedBuf {
fn borrow(&self) -> &AlignedSlice<A> {
(**self).as_aligned()
}
}
#[cfg(test)]
mod test {
use super::AlignedBuf;
fn read_to_buf(mut file: impl std::io::Read) -> AlignedBuf {
let mut v = vec![];
file.read_to_end(&mut v).unwrap();
v.into()
}
#[test]
fn test_read_to_buf() {
let mut d: Vec<u8> = vec![0; 16384];
for x in 0..16384 {
d[x] = (x % 256) as u8;
}
let s = read_to_buf(b"".as_ref());
assert_eq!(**s, *b"");
let s = read_to_buf(&d[..12]);
assert_eq!(**s, d[..12]);
let s = read_to_buf(&d[..8000]);
assert_eq!(**s, d[..8000]);
let s = read_to_buf(d.as_slice());
assert_eq!(&**s, d.as_slice());
}
}