use super::utils::{safe_copy, set_zero};
use libc::{c_void, free, malloc, posix_memalign};
use nix::errno::Errno;
use std::slice;
use std::{
fmt,
ops::{Deref, DerefMut},
ptr::{NonNull, null_mut},
};
#[repr(C)]
pub struct Buffer {
buf_ptr: NonNull<c_void>,
pub(crate) size: u32,
pub(crate) cap: u32,
}
impl fmt::Debug for Buffer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "buffer {:p} size {}", self.get_raw(), self.len())
}
}
unsafe impl Send for Buffer {}
unsafe impl Sync for Buffer {}
pub const MIN_ALIGN: u32 = 512;
pub const MAX_BUFFER_SIZE: usize = 1 << 31;
fn is_aligned(offset: usize, size: usize) -> bool {
return (offset & (MIN_ALIGN as usize - 1) == 0) && (size & (MIN_ALIGN as usize - 1) == 0);
}
impl Buffer {
#[inline]
pub fn aligned(size: i32) -> Result<Buffer, Errno> {
let mut _buf = Self::_alloc(MIN_ALIGN, size)?;
#[cfg(all(feature = "fail", feature = "rand"))]
fail::fail_point!("alloc_buf", |_| {
rand_buffer(&mut _buf);
return Ok(_buf);
});
return Ok(_buf);
}
#[inline]
pub fn aligned_by(size: i32, align: u32) -> Result<Buffer, Errno> {
let mut _buf = Self::_alloc(align, size)?;
#[cfg(all(feature = "fail", feature = "rand"))]
fail::fail_point!("alloc_buf", |_| {
rand_buffer(&mut _buf);
return Ok(_buf);
});
return Ok(_buf);
}
#[inline]
pub fn alloc(size: i32) -> Result<Buffer, Errno> {
let mut _buf = Self::_alloc(0, size)?;
#[cfg(all(feature = "fail", feature = "rand"))]
fail::fail_point!("alloc_buf", |_| {
rand_buffer(&mut _buf);
return Ok(_buf);
});
return Ok(_buf);
}
#[inline]
fn _alloc(align: u32, size: i32) -> Result<Self, Errno> {
assert!(size > 0);
let mut ptr: *mut c_void = null_mut();
if align > 0 {
debug_assert!((align & (MIN_ALIGN - 1)) == 0);
debug_assert!((size as u32 & (align - 1)) == 0);
unsafe {
let res = posix_memalign(&mut ptr, align as libc::size_t, size as libc::size_t);
if res != 0 {
return Err(Errno::ENOMEM);
}
}
} else {
ptr = unsafe { malloc(size as libc::size_t) };
if ptr.is_null() {
return Err(Errno::ENOMEM);
}
}
let _size = size as u32 | MAX_BUFFER_SIZE as u32;
let _cap = _size;
Ok(Self { buf_ptr: unsafe { NonNull::new_unchecked(ptr) }, size: _size, cap: _cap })
}
#[inline]
pub fn from_c_ref_mut(ptr: *mut c_void, size: i32) -> Self {
assert!(size >= 0);
assert!(!ptr.is_null());
let _cap = size as u32 | MAX_BUFFER_SIZE as u32;
Self { buf_ptr: unsafe { NonNull::new_unchecked(ptr) }, size: size as u32, cap: _cap }
}
#[inline]
pub fn from_c_ref_const(ptr: *const c_void, size: i32) -> Self {
assert!(size >= 0);
assert!(!ptr.is_null());
Self {
buf_ptr: unsafe { NonNull::new_unchecked(ptr as *mut c_void) },
size: size as u32,
cap: size as u32,
}
}
#[inline(always)]
pub fn is_owned(&self) -> bool {
self.size & (MAX_BUFFER_SIZE as u32) != 0
}
#[inline(always)]
pub fn is_mutable(&self) -> bool {
self.cap & (MAX_BUFFER_SIZE as u32) != 0
}
#[inline(always)]
pub fn len(&self) -> usize {
let size = self.size & (MAX_BUFFER_SIZE as u32 - 1);
size as usize
}
#[inline(always)]
pub fn capacity(&self) -> usize {
let cap = self.cap & (MAX_BUFFER_SIZE as u32 - 1);
cap as usize
}
#[inline(always)]
pub fn set_len(&mut self, len: usize) {
assert!(len < MAX_BUFFER_SIZE, "size {} >= {} is not supported", len, MAX_BUFFER_SIZE);
assert!(len <= self.cap as usize, "size {} must be <= {}", len, self.cap);
let owned: u32 = self.size & MAX_BUFFER_SIZE as u32;
self.size = owned | len as u32;
}
#[inline(always)]
pub fn as_ref(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.buf_ptr.as_ptr() as *const u8, self.len()) }
}
#[inline(always)]
pub fn as_mut(&mut self) -> &mut [u8] {
#[cfg(debug_assertions)]
{
if !self.is_mutable() {
panic!("Cannot change a mutable buffer")
}
}
unsafe { slice::from_raw_parts_mut(self.buf_ptr.as_ptr() as *mut u8, self.len()) }
}
#[inline(always)]
pub fn is_aligned(&self) -> bool {
is_aligned(self.buf_ptr.as_ptr() as usize, self.capacity())
}
#[inline]
pub fn get_raw(&self) -> *const u8 {
self.buf_ptr.as_ptr() as *const u8
}
#[inline]
pub fn get_raw_mut(&mut self) -> *mut u8 {
self.buf_ptr.as_ptr() as *mut u8
}
#[inline]
pub fn copy_from(&mut self, offset: usize, src: &[u8]) {
let size = self.len();
let dst = self.as_mut();
if offset > 0 {
assert!(offset < size);
safe_copy(&mut dst[offset..], src);
} else {
safe_copy(dst, src);
}
}
#[inline]
pub fn copy_and_clean(&mut self, offset: usize, other: &[u8]) {
let end: usize;
let size = self.len();
let dst = self.as_mut();
assert!(offset < size);
if offset > 0 {
set_zero(&mut dst[0..offset]);
end = offset + safe_copy(&mut dst[offset..], other);
} else {
end = safe_copy(dst, other);
}
if size > end {
set_zero(&mut dst[end..]);
}
}
#[inline]
pub fn zero(&mut self) {
set_zero(self);
}
#[inline]
pub fn set_zero(&mut self, offset: usize, len: usize) {
let _len = self.len();
let mut end = offset + len;
if end > _len {
end = _len;
}
let buf = self.as_mut();
if offset > 0 || end < _len {
set_zero(&mut buf[offset..end]);
} else {
set_zero(buf);
}
}
}
impl Clone for Buffer {
fn clone(&self) -> Self {
let mut new_buf = if self.is_aligned() {
Self::aligned(self.capacity() as i32).unwrap()
} else {
Self::alloc(self.capacity() as i32).unwrap()
};
if self.len() != self.capacity() {
new_buf.set_len(self.len());
}
safe_copy(new_buf.as_mut(), self.as_ref());
new_buf
}
}
impl Drop for Buffer {
fn drop(&mut self) {
if self.is_owned() {
unsafe {
free(self.buf_ptr.as_ptr());
}
}
}
}
impl Into<Vec<u8>> for Buffer {
fn into(mut self) -> Vec<u8> {
if !self.is_owned() {
panic!("buffer is c ref, not owned");
}
self.size &= MAX_BUFFER_SIZE as u32 - 1;
return unsafe {
Vec::<u8>::from_raw_parts(self.buf_ptr.as_ptr() as *mut u8, self.len(), self.capacity())
};
}
}
impl From<Vec<u8>> for Buffer {
fn from(buf: Vec<u8>) -> Self {
let size = buf.len();
let cap = buf.capacity();
assert!(size < MAX_BUFFER_SIZE, "size {} >= {} is not supported", size, MAX_BUFFER_SIZE);
assert!(cap < MAX_BUFFER_SIZE, "cap {} >= {} is not supported", cap, MAX_BUFFER_SIZE);
let _size = size as u32 | MAX_BUFFER_SIZE as u32;
let _cap = cap as u32 | MAX_BUFFER_SIZE as u32;
Buffer {
buf_ptr: unsafe { NonNull::new_unchecked(buf.leak().as_mut_ptr() as *mut c_void) },
size: _size,
cap: _cap,
}
}
}
impl Deref for Buffer {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.as_ref()
}
}
impl AsRef<[u8]> for Buffer {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_ref()
}
}
impl AsMut<[u8]> for Buffer {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
self.as_mut()
}
}
impl DerefMut for Buffer {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
self.as_mut()
}
}