use std::ffi::c_void;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ops::DerefMut;
#[derive(Debug)]
pub struct VecStorage<T> {
ptr: *mut c_void,
capacity: usize,
is_locked: bool,
phantom: PhantomData<T>,
}
unsafe impl<T> Send for VecStorage<T> where T: Send {}
unsafe impl<T> Sync for VecStorage<T> where T: Sync {}
pub struct VecGuard<'s, TOrig, T> {
storage: &'s mut VecStorage<TOrig>,
borrow: Vec<T>,
}
impl<'s, TOrig, T> Deref for VecGuard<'s, TOrig, T> {
type Target = Vec<T>;
fn deref(&self) -> &Vec<T> {
&self.borrow
}
}
impl<'s, TOrig, T> DerefMut for VecGuard<'s, TOrig, T> {
fn deref_mut(&mut self) -> &mut Vec<T> {
&mut self.borrow
}
}
impl<'s, TOrig, T> Drop for VecGuard<'s, TOrig, T> {
fn drop(&mut self) {
self.borrow.clear();
self.storage.ptr = self.borrow.as_mut_ptr() as *mut c_void;
debug_assert_eq!(self.borrow.len(), 0);
self.storage.capacity = self.borrow.capacity();
let mut v = Vec::new();
mem::swap(&mut v, &mut self.borrow);
mem::forget(v);
self.storage.is_locked = false;
}
}
impl<T> VecStorage<T> {
pub fn with_capacity(capacity: usize) -> Self {
let mut vector: Vec<T> = Vec::with_capacity(capacity);
debug_assert_eq!(vector.len(), 0);
let result = Self {
is_locked: false,
ptr: vector.as_mut_ptr() as *mut c_void,
capacity: vector.capacity(),
phantom: PhantomData,
};
mem::forget(vector);
result
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn vec_guard<'s, TGuard>(&'s mut self) -> VecGuard<'s, T, TGuard> {
if self.is_locked {
panic!(
"`VecStorage` has been locked. \
Probably `mem::forget()` was called on a `VecGuard`."
);
}
use std::alloc::Layout;
if Layout::new::<TGuard>() != Layout::new::<T>() {
panic!(
"The data type of the guard must have the same size and alignment \
as the data type of the `VecStorage`."
);
}
self.is_locked = true;
let vector;
unsafe { vector = Vec::from_raw_parts(self.ptr as *mut TGuard, 0, self.capacity) }
VecGuard {
borrow: vector,
storage: self,
}
}
}
impl<T> Drop for VecStorage<T> {
fn drop(&mut self) {
if !self.is_locked {
unsafe {
mem::drop(Vec::from_raw_parts(self.ptr as *mut T, 0, self.capacity));
}
} else {
}
}
}
#[test]
#[should_panic(
expected = "`VecStorage` has been locked. Probably `mem::forget()` was called on a `VecGuard`"
)]
fn mem_forgetting_guard_leads_to_panic_with_new_guard() {
let mut v = VecStorage::<&u32>::with_capacity(2);
{
let x = 1;
let mut guard = v.vec_guard();
guard.push(&x);
mem::forget(guard);
}
{
let _guard = v.vec_guard::<&u32>();
}
}
#[test]
#[should_panic(
expected = "The data type of the guard must have the same size and alignment \
as the data type of the `VecStorage`."
)]
fn creating_guard_with_different_size_gives_leads_to_panic() {
let mut v = VecStorage::<u32>::with_capacity(2);
let _guard = v.vec_guard::<u64>();
}
#[test]
fn mem_forgetting_guard_does_not_lead_to_panic() {
let mut v = VecStorage::<&u32>::with_capacity(2);
{
let x = 1;
let mut guard = v.vec_guard();
guard.push(&x);
mem::forget(guard);
}
}
#[test]
fn vec_storage_mut_common_use_cases() {
let capacity;
let mut v = VecStorage::<&u32>::with_capacity(2);
{
let mut x = 1;
let mut y = 2;
let mut z = 3;
let mut guard = v.vec_guard();
assert_eq!(guard.capacity(), 2);
assert_eq!(guard.len(), 0);
guard.push(&mut x);
guard.push(&mut y);
guard.push(&mut z);
capacity = guard.capacity();
}
{
let mut a = 1;
let mut b = 2;
let mut guard = v.vec_guard();
assert_eq!(guard.len(), 0);
assert_eq!(capacity, guard.capacity());
guard.push(&mut a);
guard.push(&mut b);
}
}
#[cfg(test)]
fn impls_send<T: Send>() {}
#[test]
fn vecstorage_implements_send() {
impls_send::<VecStorage<u32>>();
}
#[cfg(test)]
fn impls_sync<T: Sync>() {}
#[test]
fn vecstorage_implements_sync() {
impls_sync::<VecStorage<u32>>();
}