use std::any::Any;
use std::fmt;
use std::ops::Deref;
use std::ptr::NonNull;
use std::sync::Arc;
pub enum Buffer<T> {
Owned(Arc<Vec<T>>),
Borrowed {
ptr: NonNull<T>,
len: usize,
guard: Arc<dyn Any + Send + Sync>,
},
}
unsafe impl<T: Send + Sync> Send for Buffer<T> {}
unsafe impl<T: Send + Sync> Sync for Buffer<T> {}
impl<T> Buffer<T> {
#[inline]
pub fn from_vec(v: Vec<T>) -> Self {
Buffer::Owned(Arc::new(v))
}
#[inline]
pub unsafe fn from_foreign(ptr: NonNull<T>, len: usize, guard: Arc<dyn Any + Send + Sync>) -> Self {
Buffer::Borrowed { ptr, len, guard }
}
#[inline]
pub fn len(&self) -> usize {
match self {
Buffer::Owned(a) => a.len(),
Buffer::Borrowed { len, .. } => *len,
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn as_slice(&self) -> &[T] {
match self {
Buffer::Owned(a) => a.as_slice(),
Buffer::Borrowed { ptr, len, .. } => unsafe {
std::slice::from_raw_parts(ptr.as_ptr(), *len)
},
}
}
#[inline]
pub fn as_ptr(&self) -> *const T {
self.as_slice().as_ptr()
}
}
impl<T: Send + Sync + 'static> Buffer<T> {
#[inline]
pub fn keepalive(&self) -> Arc<dyn Any + Send + Sync> {
match self {
Buffer::Owned(a) => a.clone(),
Buffer::Borrowed { guard, .. } => guard.clone(),
}
}
}
impl<T: Clone> Buffer<T> {
#[inline]
pub fn make_mut(&mut self) -> &mut Vec<T> {
if matches!(self, Buffer::Borrowed { .. }) {
let owned = self.as_slice().to_vec();
*self = Buffer::Owned(Arc::new(owned));
}
match self {
Buffer::Owned(a) => Arc::make_mut(a),
Buffer::Borrowed { .. } => unreachable!("materialised to Owned above"), }
}
#[inline]
pub fn into_vec(self) -> Vec<T> {
match self {
Buffer::Owned(a) => Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone()),
Buffer::Borrowed { .. } => self.as_slice().to_vec(),
}
}
}
impl<T> Deref for Buffer<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<T: Clone> Clone for Buffer<T> {
#[inline]
fn clone(&self) -> Self {
match self {
Buffer::Owned(a) => Buffer::Owned(Arc::clone(a)),
Buffer::Borrowed { ptr, len, guard } => Buffer::Borrowed {
ptr: *ptr,
len: *len,
guard: Arc::clone(guard),
},
}
}
}
impl<T: PartialEq> PartialEq for Buffer<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<T: fmt::Debug> fmt::Debug for Buffer<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.as_slice().iter()).finish()
}
}
impl<T> From<Vec<T>> for Buffer<T> {
#[inline]
fn from(v: Vec<T>) -> Self {
Buffer::from_vec(v)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn borrowed(v: Vec<f64>) -> Buffer<f64> {
let arc = Arc::new(v);
let ptr = NonNull::new(arc.as_slice().as_ptr() as *mut f64).unwrap();
let len = arc.len();
unsafe { Buffer::from_foreign(ptr, len, arc) }
}
#[test]
fn owned_basics() {
let b = Buffer::from_vec(vec![1.0, 2.0, 3.0]);
assert_eq!(b.len(), 3);
assert!(!b.is_empty());
assert_eq!(b.as_slice(), &[1.0, 2.0, 3.0]);
assert_eq!(&*b, &[1.0, 2.0, 3.0]); assert!(Buffer::<f64>::from_vec(vec![]).is_empty());
assert_eq!(Buffer::from(vec![1.0]).into_vec(), vec![1.0]); assert_eq!(format!("{:?}", b), "[1.0, 2.0, 3.0]"); assert_eq!(b, b.clone()); }
#[test]
fn borrowed_reads_zero_copy() {
let b = borrowed(vec![1.0, 2.0, 3.0]);
assert_eq!(b.len(), 3);
assert!(!b.is_empty());
assert_eq!(b.as_slice(), &[1.0, 2.0, 3.0]);
let c = b.clone(); assert_eq!(c.as_slice(), &[1.0, 2.0, 3.0]);
assert_eq!(b, c); assert_eq!(format!("{:?}", b), "[1.0, 2.0, 3.0]");
}
#[test]
fn borrowed_make_mut_materialises_cow() {
let mut b = borrowed(vec![1.0, 2.0]);
assert!(matches!(b, Buffer::Borrowed { .. }));
b.make_mut().push(3.0); assert!(matches!(b, Buffer::Owned(_)));
assert_eq!(b.as_slice(), &[1.0, 2.0, 3.0]);
b.make_mut().push(4.0);
assert_eq!(b.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
}
#[test]
fn borrowed_into_vec_copies() {
assert_eq!(borrowed(vec![7.0, 8.0]).into_vec(), vec![7.0, 8.0]);
let a = Buffer::from_vec(vec![5.0]);
let _alias = a.clone();
assert_eq!(a.into_vec(), vec![5.0]);
}
}