use std::{
alloc::{alloc_zeroed, dealloc, Layout},
ptr::NonNull,
sync::Arc,
};
use crate::{BufferRef, ALIGNMENT};
pub struct Buffer {
ptr: NonNull<u8>,
layout: Layout,
len: usize,
}
impl Buffer {
pub fn new(len: usize) -> Self {
if len == 0 {
return Self {
ptr: std::ptr::NonNull::dangling(),
layout: Layout::from_size_align(64, 64).unwrap(),
len,
};
}
let padded_len = len.checked_next_multiple_of(ALIGNMENT).unwrap();
let layout = Layout::from_size_align(padded_len, ALIGNMENT).unwrap();
let ptr = unsafe { alloc_zeroed(layout) };
let ptr = NonNull::new(ptr).unwrap();
Self { ptr, layout, len }
}
pub fn as_ptr(&self) -> *const u8 {
self.ptr.as_ptr()
}
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.ptr.as_ptr()
}
pub fn as_slice(&self) -> &[u8] {
unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len) }
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}
pub fn cold_load(&mut self, src: &[u8]) {
assert!(self.len >= src.len());
unsafe { crate::cold_load::cold_copy(src.as_ptr(), self.as_mut_ptr(), src.len()) }
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn from_slice(src: &[u8]) -> Self {
#[allow(unused_mut)]
let mut buf = Self::new(src.len());
unsafe {
std::ptr::copy_nonoverlapping(src.as_ptr(), buf.as_mut_ptr(), buf.len);
}
buf
}
pub fn from_slice_cold(src: &[u8]) -> Self {
let mut buf = Self::new(src.len());
buf.cold_load(src);
buf
}
pub fn into_ref(self) -> BufferRef {
let len = self.len;
BufferRef::new(Arc::new(self), 0, len)
}
}
impl Drop for Buffer {
fn drop(&mut self) {
unsafe {
if self.len > 0 {
dealloc(self.as_mut_ptr(), self.layout);
}
}
}
}
impl Clone for Buffer {
fn clone(&self) -> Self {
unsafe {
#[allow(unused_mut)]
let mut other = Self::new(self.len);
std::ptr::copy_nonoverlapping(self.as_ptr(), other.as_mut_ptr(), self.len);
other
}
}
}
unsafe impl Send for Buffer {}
unsafe impl Sync for Buffer {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_sized() {
let _buf = Buffer::new(0);
}
#[test]
fn big_sized() {
let _buf = Buffer::new(1331);
}
#[test]
fn cold_copy() {
let src = &[1, 2, 3];
let mut buf = Buffer::from_slice_cold(src);
assert_eq!(buf.as_slice(), src);
let src = &[5, 4];
buf.cold_load(src);
assert_eq!(buf.as_slice(), &[5, 4, 3]);
let src = (0..244).collect::<Vec<u8>>();
let buf = Buffer::from_slice_cold(&src);
assert_eq!(buf.as_slice(), src);
}
}