#![no_std]
#![forbid(unsafe_code)]
extern crate alloc;
use alloc::vec::Vec;
use core::ops::{Deref, DerefMut, Index, IndexMut};
pub struct PreallocRefVec<T: ?Sized + 'static> {
buffer: Vec<&'static mut T>,
}
impl<T: ?Sized + 'static> PreallocRefVec<T> {
pub fn new(capacity: usize) -> Self {
let mut buffer = Vec::new();
buffer.reserve_exact(capacity);
Self { buffer }
}
pub fn get_tmp<'a>(&'a mut self) -> TmpRefVec<'a, T> {
let mut tmp: Vec<&'static mut T> = Vec::new();
core::mem::swap(&mut self.buffer, &mut tmp);
tmp.clear();
TmpRefVec {
data: tmp.into_iter().map(|_| unreachable!()).collect(),
buffer: &mut self.buffer,
}
}
pub fn get_tmp_mut<'a>(&'a mut self) -> TmpRefMutVec<'a, T> {
let mut tmp: Vec<&'static mut T> = Vec::new();
core::mem::swap(&mut self.buffer, &mut tmp);
tmp.clear();
TmpRefMutVec {
data: tmp.into_iter().map(|_| unreachable!()).collect(),
buffer: &mut self.buffer,
}
}
pub fn with_tmp<'a>(&'a mut self, f: impl FnOnce(&mut Vec<&'a T>)) {
let mut v = self.get_tmp();
(f)(&mut v.data);
}
pub fn with_tmp_mut<'a>(&'a mut self, f: impl FnOnce(&mut Vec<&'a mut T>)) {
let mut v = self.get_tmp_mut();
(f)(&mut v.data);
}
pub const fn capacity(&self) -> usize {
self.buffer.capacity()
}
}
impl<T: ?Sized + 'static> From<Vec<&'static mut T>> for PreallocRefVec<T> {
fn from(buffer: Vec<&'static mut T>) -> Self {
Self { buffer }
}
}
impl<T: ?Sized + 'static> From<PreallocRefVec<T>> for Vec<&'static mut T> {
fn from(vec: PreallocRefVec<T>) -> Self {
vec.buffer
}
}
pub struct TmpRefVec<'a, T: ?Sized + 'static> {
pub data: Vec<&'a T>,
buffer: &'a mut Vec<&'static mut T>,
}
impl<'a, T: ?Sized + 'static> Deref for TmpRefVec<'a, T> {
type Target = Vec<&'a T>;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<'a, T: ?Sized + 'static> DerefMut for TmpRefVec<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<'a, T: ?Sized + 'static> Index<usize> for TmpRefVec<'a, T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.data[index]
}
}
impl<'a, T: ?Sized + 'static> Drop for TmpRefVec<'a, T> {
fn drop(&mut self) {
let mut tmp: Vec<&'a T> = Vec::new();
core::mem::swap(&mut self.data, &mut tmp);
tmp.clear();
*self.buffer = tmp.into_iter().map(|_| unreachable!()).collect();
}
}
pub struct TmpRefMutVec<'a, T: ?Sized + 'static> {
pub data: Vec<&'a mut T>,
buffer: &'a mut Vec<&'static mut T>,
}
impl<'a, T: ?Sized + 'static> Deref for TmpRefMutVec<'a, T> {
type Target = Vec<&'a mut T>;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<'a, T: ?Sized + 'static> DerefMut for TmpRefMutVec<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<'a, T: ?Sized + 'static> Index<usize> for TmpRefMutVec<'a, T> {
type Output = T;
fn index(&self, index: usize) -> &Self::Output {
&self.data[index]
}
}
impl<'a, T: ?Sized + 'static> IndexMut<usize> for TmpRefMutVec<'a, T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.data[index]
}
}
impl<'a, T: ?Sized + 'static> Drop for TmpRefMutVec<'a, T> {
fn drop(&mut self) {
let mut tmp: Vec<&'a mut T> = Vec::new();
core::mem::swap(&mut self.data, &mut tmp);
tmp.clear();
*self.buffer = tmp.into_iter().map(|_| unreachable!()).collect();
}
}
#[cfg(test)]
mod tests {
use super::*;
use assert_no_alloc::*;
#[global_allocator]
static A: AllocDisabler = AllocDisabler;
#[test]
fn test() {
const CAPACITY: usize = 10;
let mut v: PreallocRefVec<[f32]> = PreallocRefVec::new(CAPACITY);
assert_no_alloc(|| test_inner(&mut v, CAPACITY));
}
#[inline(never)]
fn test_inner(v: &mut PreallocRefVec<[f32]>, capacity: usize) {
let mut data: [f32; 4] = [0.0; 4];
let v_ptr = v.buffer.as_ptr();
assert!(v.capacity() >= capacity);
assert_eq!(v.buffer.len(), 0);
{
let mut r = v.get_tmp();
assert!(r.capacity() >= capacity);
assert_eq!(r.data.len(), 0);
assert!(core::ptr::addr_eq(v_ptr, r.data.as_ptr()));
r.data.push(&data);
}
assert!(v.capacity() >= capacity);
assert_eq!(v.buffer.len(), 0);
assert!(core::ptr::addr_eq(v_ptr, v.buffer.as_ptr()));
{
let mut r = v.get_tmp_mut();
assert!(r.capacity() >= capacity);
assert_eq!(r.data.len(), 0);
assert!(core::ptr::addr_eq(v_ptr, r.data.as_ptr()));
r.data.push(&mut data);
}
assert!(v.capacity() >= capacity);
assert_eq!(v.buffer.len(), 0);
assert!(core::ptr::addr_eq(v_ptr, v.buffer.as_ptr()));
}
}