use core::alloc::Layout;
use core::fmt;
use core::mem::{align_of, size_of};
use core::ptr;
use core::slice::{from_raw_parts, from_raw_parts_mut};
use alloc::alloc::{alloc, dealloc, handle_alloc_error, realloc};
use crate::Frame;
use crate::buf::{Aligned, Alloc, max_size_for_align, padding_to};
pub(crate) type AlignType = u64;
pub(crate) struct AlignedBuf {
data: ptr::NonNull<u8>,
capacity: usize,
len: usize,
}
impl AlignedBuf {
pub(crate) const fn new() -> Self {
Self {
data: ptr::NonNull::<AlignType>::dangling().cast(),
capacity: 0,
len: 0,
}
}
pub(crate) fn as_aligned(&self) -> Aligned<'_> {
let len = self.len();
let data = unsafe { ptr::NonNull::new_unchecked(self.data.as_ptr()) };
Aligned::new(data, len)
}
pub(crate) fn alloc<T>(&mut self) -> Alloc<T>
where
T: Frame,
{
self.align_mut::<T>();
let at = self.len;
unsafe {
self.zero(size_of::<T>());
}
Alloc::new(at)
}
pub(crate) fn store_at<T>(&mut self, at: Alloc<T>, frame: T)
where
T: Frame,
{
let at = at.into_usize();
assert!(at + size_of::<T>() <= self.len, "write underflow");
unsafe {
self.data.as_ptr().add(at).cast::<T>().write(frame);
}
}
pub(crate) fn store<T>(&mut self, frame: T)
where
T: Frame,
{
self.align_mut::<T>();
unsafe {
self.data.as_ptr().add(self.len).cast::<T>().write(frame);
self.len += size_of::<T>();
}
}
pub(crate) fn extend_from_slice(&mut self, bytes: &[u8]) {
let requested = self.len + bytes.len();
self.ensure_capacity(requested);
unsafe {
self.data
.as_ptr()
.add(self.len)
.copy_from(bytes.as_ptr(), bytes.len());
}
self.len += bytes.len();
}
pub(crate) fn extend_from_slice_nul(&mut self, bytes: &[u8]) {
let requested = self.len + bytes.len() + 1;
self.ensure_capacity(requested);
unsafe {
let ptr = self.data.as_ptr().add(self.len);
ptr.copy_from(bytes.as_ptr(), bytes.len());
ptr.add(bytes.len()).write(0u8);
}
self.len += bytes.len() + 1;
}
pub(crate) fn reserve_bytes(&mut self, bytes: usize) {
let requested = self.len + bytes;
self.ensure_capacity(requested);
}
#[inline]
pub(crate) fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub(crate) fn len(&self) -> usize {
self.len
}
pub(crate) fn get(&self) -> &[u8] {
unsafe {
let at = self.data.as_ptr();
from_raw_parts(at, self.len())
}
}
pub(crate) fn get_mut(&mut self) -> &mut [u8] {
unsafe {
let len = self.capacity - self.len;
let at = self.data.as_ptr().add(self.len);
from_raw_parts_mut(at, len)
}
}
pub(crate) fn advance(&mut self, n: usize) {
self.len += n;
}
pub(crate) fn clear(&mut self) {
self.len = 0;
}
fn ensure_capacity(&mut self, capacity: usize) {
if capacity <= self.capacity {
return;
}
let capacity = 16usize.max(capacity.next_power_of_two());
assert!(
capacity <= max_size_for_align(align_of::<AlignType>()),
"capacity overflow"
);
self.realloc(capacity);
self.capacity = capacity;
}
fn realloc(&mut self, capacity: usize) {
unsafe {
if self.capacity == 0 {
let layout = Layout::from_size_align_unchecked(capacity, align_of::<AlignType>());
let ptr = alloc(layout);
if ptr.is_null() {
handle_alloc_error(layout);
}
self.data = ptr::NonNull::new_unchecked(ptr);
} else {
let layout =
Layout::from_size_align_unchecked(self.capacity, align_of::<AlignType>());
let ptr = realloc(self.data.as_ptr(), layout, capacity);
if ptr.is_null() {
handle_alloc_error(layout);
}
self.data = ptr::NonNull::new_unchecked(ptr);
}
}
}
pub(crate) fn align_mut<T>(&mut self) {
let padding = padding_to::<T>(self.len);
let requested = self.len + padding + size_of::<T>();
self.ensure_capacity(requested);
unsafe {
self.zero(padding);
}
}
pub(crate) fn align_mut_to(&mut self, align: usize) {
assert!(align.is_power_of_two(), "alignment must be a power of two");
let padding = unsafe { crate::buf::padding_to_with(align, self.len) };
let requested = self.len + padding + align;
self.ensure_capacity(requested);
unsafe {
self.zero(padding);
}
}
unsafe fn zero(&mut self, len: usize) {
unsafe {
let at = self.data.as_ptr().wrapping_add(self.len);
at.write_bytes(0, len);
}
self.len += len;
}
}
unsafe impl Send for AlignedBuf {}
unsafe impl Sync for AlignedBuf {}
impl fmt::Debug for AlignedBuf {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("AlignedBuf")
.field("len", &self.len())
.field("capacity", &self.capacity)
.finish()
}
}
impl Default for AlignedBuf {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Drop for AlignedBuf {
fn drop(&mut self) {
unsafe {
if self.capacity > 0 {
let layout =
Layout::from_size_align_unchecked(self.capacity, align_of::<AlignType>());
dealloc(self.data.as_ptr(), layout);
self.capacity = 0;
}
}
}
}
impl PartialEq<AlignedBuf> for AlignedBuf {
#[inline]
fn eq(&self, other: &AlignedBuf) -> bool {
self.get() == other.get()
}
}
impl PartialEq<Aligned<'_>> for AlignedBuf {
#[inline]
fn eq(&self, other: &Aligned<'_>) -> bool {
self.get() == other.get()
}
}
impl Eq for AlignedBuf {}
impl Clone for AlignedBuf {
#[inline]
fn clone(&self) -> Self {
let mut buf = Self::new();
buf.extend_from_slice(self.get());
buf
}
}
impl From<Aligned<'_>> for AlignedBuf {
#[inline]
fn from(value: Aligned<'_>) -> Self {
let mut buf = Self::new();
buf.extend_from_slice(value.get());
buf
}
}