use crate::alignment::Alignment;
use crate::bytes::AlignedBytes;
use crate::iterators::AlignedBlockIterator;
use std::borrow::{Borrow, BorrowMut};
use std::mem;
use std::ops::{Deref, DerefMut};
mod cmp;
#[doc(inline)]
#[allow(unreachable_pub)] pub use cmp::*;
#[repr(transparent)]
pub struct AlignedSlice<A: Alignment> {
phantom: std::marker::PhantomData<A>,
bytes: [u8],
}
impl<A: Alignment> AlignedSlice<A> {
#[must_use]
#[inline]
pub fn offset(&self, count: isize) -> &Self {
let offset_in_bytes = A::size() * (count as usize);
if self.bytes.len() < offset_in_bytes {
panic!(
"offset {count} out of range for AlignedSlice of {} aligned blocks",
self.bytes.len() / A::size()
)
}
unsafe { std::mem::transmute(&self[offset_in_bytes..]) }
}
#[must_use]
#[inline(always)]
pub fn alignment_size(&self) -> usize {
A::size()
}
#[must_use]
#[inline]
pub fn iter_blocks(&self) -> AlignedBlockIterator<A> {
AlignedBlockIterator::new(self)
}
#[must_use]
#[inline]
pub fn relax_alignment<B: Alignment>(&self) -> &AlignedSlice<B> {
if A::size() < B::size() {
panic!("target alignment is larger than source alignment, the 'relax_alignment' conversion is not valid")
}
unsafe { mem::transmute(self) }
}
}
impl<A: Alignment> AsRef<AlignedSlice<A>> for AlignedBytes<A> {
#[inline(always)]
fn as_ref(&self) -> &AlignedSlice<A> {
self
}
}
impl<A: Alignment> AsMut<AlignedSlice<A>> for AlignedBytes<A> {
#[inline(always)]
fn as_mut(&mut self) -> &mut AlignedSlice<A> {
self
}
}
impl<A: Alignment> AsRef<[u8]> for AlignedSlice<A> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self
}
}
impl<A: Alignment> AsMut<[u8]> for AlignedSlice<A> {
#[inline(always)]
fn as_mut(&mut self) -> &mut [u8] {
self
}
}
impl<A: Alignment> Borrow<AlignedSlice<A>> for AlignedBytes<A> {
#[inline(always)]
fn borrow(&self) -> &AlignedSlice<A> {
self
}
}
impl<A: Alignment> BorrowMut<AlignedSlice<A>> for AlignedBytes<A> {
#[inline(always)]
fn borrow_mut(&mut self) -> &mut AlignedSlice<A> {
self
}
}
impl<A: Alignment> Clone for AlignedBytes<A> {
#[inline]
fn clone(&self) -> AlignedBytes<A> {
let slice: &AlignedSlice<A> = self;
slice.into()
}
#[inline]
fn clone_from(&mut self, other: &AlignedBytes<A>) {
let source: &AlignedSlice<A> = other;
let target: &mut AlignedSlice<A> = self;
target.clone_from_slice(source);
}
}
impl<A: Alignment> Deref for AlignedBytes<A> {
type Target = AlignedSlice<A>;
#[inline]
fn deref(&self) -> &AlignedSlice<A> {
unsafe {
let slice = std::slice::from_raw_parts(self.as_ptr(), self.len());
std::mem::transmute(slice)
}
}
}
impl<A: Alignment> DerefMut for AlignedBytes<A> {
#[inline]
fn deref_mut<'a>(&'a mut self) -> &'a mut AlignedSlice<A> {
unsafe {
let slice: &'a mut [u8] = std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len());
std::mem::transmute(slice)
}
}
}
impl<A: Alignment> Deref for AlignedSlice<A> {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
unsafe { std::mem::transmute(self) }
}
}
impl<A: Alignment> DerefMut for AlignedSlice<A> {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
unsafe { std::mem::transmute(self) }
}
}
impl<A: Alignment> std::fmt::Debug for AlignedSlice<A> {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let deref: &[u8] = self;
std::fmt::Debug::fmt(deref, f)
}
}
impl<A: Alignment> Default for &AlignedSlice<A> {
#[inline]
fn default() -> Self {
let default_bytes: AlignedBytes<A> = Default::default();
unsafe {
let slice = std::slice::from_raw_parts(default_bytes.as_ptr(), 0);
std::mem::transmute(slice)
}
}
}
impl<A: Alignment> Default for &mut AlignedSlice<A> {
#[inline]
fn default() -> Self {
let mut default_bytes: AlignedBytes<A> = Default::default();
unsafe {
let slice = std::slice::from_raw_parts_mut(default_bytes.as_mut_ptr(), 0);
std::mem::transmute(slice)
}
}
}
#[cfg(test)]
mod tests {
use crate::test::assert_aligned;
use crate::{alignment, AlignedBytes, AlignedSlice};
#[test]
fn empty_slice_is_aligned() {
let empty: &AlignedSlice<alignment::Eight> = Default::default();
assert_aligned(empty.as_ptr(), 8);
}
#[test]
fn empty_mut_slice_is_aligned() {
let empty: &mut AlignedSlice<alignment::Eight> = Default::default();
assert_aligned(empty.as_ptr(), 8);
}
#[test]
fn alignment_size_equal_to_alignment_type() {
let bytes: AlignedBytes<alignment::TwoTo<7>> = AlignedBytes::new_zeroed(1024);
let slice: &AlignedSlice<alignment::TwoTo<7>> = &bytes;
assert_eq!(128, slice.alignment_size());
}
}