#![allow(unsafe_code)]
use std::{
marker::PhantomData,
slice,
};
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct RawVec<T> {
pub ptr: *mut T,
pub len: usize,
pub cap: usize,
pub _phantom: PhantomData<T>,
}
impl<T> RawVec<T> {
#[inline]
pub const unsafe fn new(ptr: *mut T, len: usize, cap: usize) -> Self {
Self { ptr, len, cap, _phantom: PhantomData }
}
#[inline]
pub unsafe fn into_vec(self) -> Vec<T> {
Vec::from_raw_parts(self.ptr, self.len, self.cap)
}
#[inline]
pub fn from_vec_ref(vec: &Vec<T>) -> Self {
Self {
ptr: vec.as_ptr() as *mut T,
len: vec.len(),
cap: vec.capacity(),
_phantom: PhantomData,
}
}
#[inline]
pub unsafe fn as_slice(&self) -> &[T] {
slice::from_raw_parts(self.ptr, self.len)
}
#[inline]
pub unsafe fn as_slice_mut(&mut self) -> &mut [T] {
slice::from_raw_parts_mut(self.ptr, self.len)
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.len == 0
}
#[inline]
pub const fn len(&self) -> usize {
self.len
}
#[inline]
pub const fn capacity(&self) -> usize {
self.cap
}
}
pub struct ZeroCopyBuffer<T> {
raw: RawVec<T>,
}
impl<T> ZeroCopyBuffer<T> {
#[inline]
pub unsafe fn from_raw_parts(ptr: *mut T, len: usize, cap: usize) -> Self {
Self { raw: RawVec::new(ptr, len, cap) }
}
#[inline]
pub fn from_zig_vec(raw: RawVec<T>) -> Self {
unsafe { Self::from_raw_vec(raw) }
}
#[inline]
pub const unsafe fn from_raw_vec(raw: RawVec<T>) -> Self {
Self { raw }
}
#[inline]
pub fn into_vec(self) -> Vec<T> {
unsafe { self.raw.into_vec() }
}
#[inline]
pub const fn raw(&self) -> &RawVec<T> {
&self.raw
}
#[inline]
pub fn as_slice(&self) -> &[T] {
unsafe { self.raw.as_slice() }
}
#[inline]
pub const fn len(&self) -> usize {
self.raw.len()
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.raw.is_empty()
}
#[inline]
pub const fn capacity(&self) -> usize {
self.raw.capacity()
}
}
impl<T> From<ZeroCopyBuffer<T>> for Vec<T> {
#[inline]
fn from(buffer: ZeroCopyBuffer<T>) -> Self {
buffer.into_vec()
}
}
impl<T> AsRef<[T]> for ZeroCopyBuffer<T> {
#[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
#[cfg(test)]
mod layout_tests {
use std::mem;
use super::*;
#[test]
fn test_raw_vec_layout() {
assert_eq!(
mem::size_of::<RawVec<u8>>(),
mem::size_of::<Vec<u8>>(),
"RawVec size must match Vec size"
);
assert_eq!(
mem::align_of::<RawVec<u8>>(),
mem::align_of::<Vec<u8>>(),
"RawVec alignment must match Vec alignment"
);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zero_copy_buffer_basic() {
let vec = vec![1, 2, 3, 4, 5];
let ptr = vec.as_ptr() as *mut i32;
let len = vec.len();
let cap = vec.capacity();
std::mem::forget(vec);
let buffer = unsafe { ZeroCopyBuffer::from_raw_parts(ptr, len, cap) };
assert_eq!(buffer.len(), 5);
assert_eq!(buffer.as_slice(), &[1, 2, 3, 4, 5]);
let recovered = buffer.into_vec();
assert_eq!(recovered, vec![1, 2, 3, 4, 5]);
}
#[test]
fn test_raw_vec_from_vec_ref() {
let vec = vec![10, 20, 30];
let raw = RawVec::from_vec_ref(&vec);
assert_eq!(raw.len(), 3);
assert_eq!(raw.capacity(), vec.capacity());
unsafe {
assert_eq!(raw.as_slice(), &[10, 20, 30]);
}
}
#[test]
fn test_zero_copy_buffer_empty() {
let vec: Vec<i32> = Vec::new();
let ptr = vec.as_ptr() as *mut i32;
let len = vec.len();
let cap = vec.capacity();
std::mem::forget(vec);
let buffer = unsafe { ZeroCopyBuffer::from_raw_parts(ptr, len, cap) };
assert!(buffer.is_empty());
assert_eq!(buffer.len(), 0);
let recovered = buffer.into_vec();
assert!(recovered.is_empty());
}
#[test]
fn test_zero_copy_buffer_large() {
let size = 1_000_000;
let vec: Vec<u32> = (0..size).collect();
let ptr = vec.as_ptr() as *mut u32;
let len = vec.len();
let cap = vec.capacity();
std::mem::forget(vec);
let buffer = unsafe { ZeroCopyBuffer::from_raw_parts(ptr, len, cap) };
assert_eq!(buffer.len(), size as usize);
assert!(buffer
.as_slice()
.iter()
.enumerate()
.all(|(i, &v)| v == i as u32));
let recovered = buffer.into_vec();
assert_eq!(recovered.len(), size as usize);
assert_eq!(recovered[0], 0);
assert_eq!(recovered[size as usize - 1], (size - 1));
}
}