use std::ops::{Deref, DerefMut};
#[derive(Debug)]
pub struct SharedVec<T> {
borrow_count: usize,
ptr: *mut T,
len: usize,
cap: usize,
}
impl<T> SharedVec<T> {
pub fn from_vec(vec: Vec<T>) -> Self {
let (ptr, len, cap) = vec.into_raw_parts();
Self {
borrow_count: 0,
ptr,
len,
cap,
}
}
pub fn borrow(&mut self) -> SharedVecRef<T> {
self.borrow_count = self.borrow_count.checked_add(1).unwrap();
SharedVecRef {
ptr: self.ptr,
len: self.len,
}
}
pub fn try_return(&mut self, reference: SharedVecRef<T>) -> Result<(), SharedVecRef<T>> {
if !core::ptr::eq(self.ptr, reference.ptr) {
return Err(reference);
}
if size_of::<T>() == 0 {
if self.len != reference.len {
return Err(reference);
}
if let Some(new_count) = self.borrow_count.checked_sub(1) {
self.borrow_count = new_count;
let _ = core::mem::ManuallyDrop::new(reference);
Ok(())
} else {
Err(reference)
}
} else {
self.borrow_count -= 1;
let _ = core::mem::ManuallyDrop::new(reference);
Ok(())
}
}
pub fn try_into_vec(self) -> Result<Vec<T>, Self> {
if self.borrow_count > 0 {
Err(self)
} else {
let r = core::mem::ManuallyDrop::new(self);
Ok(unsafe { Vec::from_raw_parts(r.ptr, r.len, r.cap) })
}
}
pub fn get(&self) -> &[T] {
unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
}
}
unsafe impl<T: Send> Send for SharedVec<T> {}
unsafe impl<T: Sync> Sync for SharedVec<T> {}
impl<T> Drop for SharedVec<T> {
fn drop(&mut self) {
#[cfg(feature = "panic-on-drop")]
{
#[cfg(feature = "do-not-panic-when-panicking")]
if std::thread::panicking() {
return;
}
if self.borrow_count > 0 {
panic!("Dropping a SharedVec without giving back all SharedVecRef")
}
}
if self.borrow_count == 0 {
unsafe {
drop(Vec::from_raw_parts(self.ptr, self.len, self.cap));
}
}
}
}
impl<T> Deref for SharedVec<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.get()
}
}
#[derive(Debug)]
pub struct SharedVecRef<T> {
ptr: *const T,
len: usize,
}
impl<T> SharedVecRef<T> {
pub fn as_slice(&self) -> &[T] {
unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
}
}
impl<T> Drop for SharedVecRef<T> {
fn drop(&mut self) {
#[cfg(feature = "panic-on-drop")]
{
#[cfg(feature = "do-not-panic-when-panicking")]
if std::thread::panicking() {
return;
}
panic!("Dropping a SharedVecRef without returning it to the SharedVec")
}
}
}
unsafe impl<T: Sync + Send> Send for SharedVecRef<T> {}
unsafe impl<T: Sync> Sync for SharedVecRef<T> {}
impl<T> Deref for SharedVecRef<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
#[derive(Debug)]
pub struct SharedVecMut<T> {
borrow_count: usize,
ptr: *mut T,
len: usize,
cap: usize,
remain_start: usize,
remain_len: usize,
}
impl<T> SharedVecMut<T> {
pub fn from_vec(vec: Vec<T>) -> Self {
let (ptr, len, cap) = vec.into_raw_parts();
Self {
borrow_count: 0,
ptr,
len,
cap,
remain_start: 0,
remain_len: len,
}
}
pub fn split_off(&mut self, at: usize) -> Option<SharedVecPart<T>> {
if at > self.remain_len {
return None;
}
self.borrow_count = self.borrow_count.checked_add(1)?;
let last_len = self.remain_len;
self.remain_len = at;
Some(SharedVecPart {
ptr: self.ptr,
start: self.remain_start + at,
len: last_len - at,
})
}
pub fn split_to(&mut self, at: usize) -> Option<SharedVecPart<T>> {
if at > self.remain_len {
return None;
}
self.borrow_count = self.borrow_count.checked_add(1)?;
let last_start = self.remain_start;
self.remain_start += at;
self.remain_len -= at;
Some(SharedVecPart {
ptr: self.ptr,
start: last_start,
len: at,
})
}
pub fn try_unsplit_off(&mut self, part: SharedVecPart<T>) -> Result<(), SharedVecPart<T>> {
if !core::ptr::eq(self.ptr, part.ptr) {
return Err(part);
}
if part.start != self.remain_start + self.remain_len {
return Err(part);
}
self.remain_len += part.len;
self.consume_part(part)
}
pub fn try_unsplit_to(&mut self, part: SharedVecPart<T>) -> Result<(), SharedVecPart<T>> {
if !core::ptr::eq(self.ptr, part.ptr) {
return Err(part);
}
if self.remain_start != part.start + part.len {
return Err(part);
}
self.remain_start = part.start;
self.remain_len += part.len;
self.consume_part(part)
}
fn consume_part(&mut self, part: SharedVecPart<T>) -> Result<(), SharedVecPart<T>> {
if size_of::<T>() == 0 {
if let Some(new_count) = self.borrow_count.checked_sub(1) {
self.borrow_count = new_count;
let _ = core::mem::ManuallyDrop::new(part);
Ok(())
} else {
Err(part)
}
} else {
self.borrow_count -= 1;
let _ = core::mem::ManuallyDrop::new(part);
Ok(())
}
}
fn can_convert_back(&self) -> bool {
self.borrow_count == 0
&& self.remain_start == 0
&& if size_of::<T>() == 0 {
self.remain_len == self.len
} else {
true
}
}
pub fn try_into_vec(self) -> Result<Vec<T>, Self> {
if self.can_convert_back() {
let r = core::mem::ManuallyDrop::new(self);
let vec = unsafe { Vec::from_raw_parts(r.ptr, r.remain_len, r.cap) };
Ok(vec)
} else {
Err(self)
}
}
pub fn as_slice(&self) -> &[T] {
unsafe { core::slice::from_raw_parts(self.ptr.add(self.remain_start), self.remain_len) }
}
pub fn as_slice_mut(&mut self) -> &mut [T] {
unsafe { core::slice::from_raw_parts_mut(self.ptr.add(self.remain_start), self.remain_len) }
}
}
unsafe impl<T: Send> Send for SharedVecMut<T> {}
unsafe impl<T: Sync> Sync for SharedVecMut<T> {}
impl<T> Drop for SharedVecMut<T> {
fn drop(&mut self) {
#[cfg(feature = "panic-on-drop")]
{
#[cfg(feature = "do-not-panic-when-panicking")]
if std::thread::panicking() {
return;
}
if self.borrow_count > 0 {
panic!("Dropping a SharedVecMut without giving back all SharedVecRef")
}
}
if self.can_convert_back() {
unsafe {
drop(Vec::from_raw_parts(self.ptr, self.len, self.cap));
}
}
}
}
impl<T> Deref for SharedVecMut<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T> DerefMut for SharedVecMut<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_slice_mut()
}
}
#[derive(Debug)]
pub struct SharedVecPart<T> {
ptr: *mut T,
start: usize,
len: usize,
}
impl<T> SharedVecPart<T> {
pub fn as_slice(&self) -> &[T] {
unsafe { core::slice::from_raw_parts(self.ptr.add(self.start), self.len) }
}
pub fn as_slice_mut(&mut self) -> &mut [T] {
unsafe { core::slice::from_raw_parts_mut(self.ptr.add(self.start), self.len) }
}
}
impl<T> Drop for SharedVecPart<T> {
fn drop(&mut self) {
#[cfg(feature = "panic-on-drop")]
{
#[cfg(feature = "do-not-panic-when-panicking")]
if std::thread::panicking() {
return;
}
panic!("Dropping a SharedVecPart without returning it to the SharedVecMut")
}
}
}
unsafe impl<T: Send> Send for SharedVecPart<T> {}
unsafe impl<T: Sync> Sync for SharedVecPart<T> {}
impl<T> Deref for SharedVecPart<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<T> DerefMut for SharedVecPart<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_slice_mut()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn zst() {
let mut b1: SharedVec<()> = SharedVec::from_vec(Vec::new());
let mut b2: SharedVec<()> = SharedVec::from_vec(Vec::new());
let r11 = b1.borrow();
let r12 = b1.borrow();
let r2 = b2.borrow();
b1.try_return(r2).unwrap();
b1.try_return(r11).unwrap();
let r12 = b1.try_return(r12).unwrap_err();
b2.try_return(r12).unwrap();
}
#[test]
fn zst_different_length() {
let mut b1 = SharedVec::from_vec(vec![()]);
let mut b2 = SharedVec::from_vec(vec![(), ()]);
let r1 = b1.borrow();
let r2 = b2.borrow();
let r2 = b1.try_return(r2).unwrap_err();
let r1 = b2.try_return(r1).unwrap_err();
b1.try_return(r1).unwrap();
b2.try_return(r2).unwrap();
}
#[test]
fn mut_zst() {
let mut b1: SharedVecMut<()> = SharedVecMut::from_vec(Vec::new());
let mut b2: SharedVecMut<()> = SharedVecMut::from_vec(Vec::new());
let r11 = b1.split_off(0).unwrap();
let r12 = b1.split_off(0).unwrap();
let r2 = b2.split_off(0).unwrap();
b1.try_unsplit_off(r2).unwrap();
b1.try_unsplit_off(r11).unwrap();
let r12 = b1.try_unsplit_off(r12).unwrap_err();
b2.try_unsplit_off(r12).unwrap();
}
#[test]
fn mut_zst_different_length() {
let mut b1 = SharedVecMut::from_vec(vec![(), ()]);
let mut b2 = SharedVecMut::from_vec(vec![()]);
let r1 = b1.split_off(0).unwrap();
let r2 = b2.split_off(0).unwrap();
b1.try_unsplit_off(r2).unwrap();
let mut b1 = b1.try_into_vec().unwrap_err();
let r2 = b1.split_off(0).unwrap();
b1.try_unsplit_off(r1).unwrap();
b2.try_unsplit_off(r2).unwrap();
assert_eq!(b1.try_into_vec().unwrap(), [(), ()]);
assert_eq!(b2.try_into_vec().unwrap(), [()]);
}
}