use std::cell::UnsafeCell;
use std::fmt::Debug;
pub struct ValueVec<V: Copy> {
data: UnsafeCell<Vec<V>>,
}
impl<V: Copy> ValueVec<V> {
pub fn new() -> Self {
Self {
data: UnsafeCell::new(Vec::new()),
}
}
pub fn with_capacity(cap: usize) -> Self {
Self {
data: UnsafeCell::new(Vec::with_capacity(cap)),
}
}
#[inline]
pub fn len(&self) -> usize {
unsafe { (&*self.data.get()).len() }
}
#[inline]
pub fn capacity(&self) -> usize {
unsafe { (&*self.data.get()).capacity() }
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn reserve(&self, additional: usize) {
self.with_vec(|v| v.reserve(additional));
}
pub fn shrink_to_fit(&self) {
self.with_vec(|v| v.shrink_to_fit());
}
pub fn push(&self, value: V) {
self.with_vec(|v| v.push(value));
}
pub fn pop(&self) -> Option<V> {
self.with_vec(|v| v.pop())
}
pub fn get(&self, index: usize) -> Option<V> {
unsafe { (&*self.data.get()).get(index).copied() }
}
pub fn at(&self, index: usize) -> V {
unsafe { (&*self.data.get())[index] }
}
pub fn replace(&self, index: usize, value: V) -> V {
self.with_vec(|v| core::mem::replace(&mut v[index], value))
}
pub fn set(&self, index: usize, value: V) {
self.with_vec(|v| v[index] = value)
}
pub fn swap_value(&self, index: usize, value: &mut V) {
self.with_vec(|v| {
core::mem::swap(&mut v[index], value);
})
}
pub fn insert(&self, index: usize, value: V) {
self.with_vec(|v| {
v.insert(index, value);
})
}
pub fn remove(&self, index: usize) -> V {
self.with_vec(|v| v.remove(index))
}
pub fn swap_remove(&self, index: usize) -> V {
self.with_vec(|v| v.swap_remove(index))
}
pub fn contains(&self, value: &V) -> bool
where
V: PartialEq,
{
self.with_vec(|v| v.contains(value))
}
pub fn clear(&self) {
self.with_vec(|v| v.clear());
}
pub fn extend<I>(&self, iter: I)
where
I: IntoIterator<Item = V>,
{
self.with_vec(|v| v.extend(iter));
}
pub fn resize(&self, new_len: usize, value: V) {
self.with_vec(|v| v.resize(new_len, value));
}
pub fn resize_with<F>(&self, new_len: usize, f: F)
where
F: FnMut() -> V,
{
self.with_vec(|v| v.resize_with(new_len, f));
}
pub fn to_vec(&self) -> Vec<V>
where
V: Clone,
{
unsafe { (&*self.data.get()).clone() }
}
#[inline]
fn with_vec<R>(&self, f: impl FnOnce(&mut Vec<V>) -> R) -> R {
let vec: &mut Vec<V> = unsafe { &mut *self.data.get() };
f(vec)
}
}
impl<V: Copy> Default for ValueVec<V> {
fn default() -> Self {
Self::new()
}
}
impl<V: Copy + Debug> Debug for ValueVec<V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let vec = unsafe { &*self.data.get() };
vec.fmt(f)
}
}
impl<V: Copy> From<Vec<V>> for ValueVec<V> {
fn from(src: Vec<V>) -> Self {
Self {
data: UnsafeCell::new(src),
}
}
}
impl<V: Copy> From<ValueVec<V>> for Vec<V> {
fn from(val: ValueVec<V>) -> Self {
val.data.into_inner()
}
}
impl<V: Copy> IntoIterator for ValueVec<V> {
type Item = V;
type IntoIter = std::vec::IntoIter<V>;
fn into_iter(self) -> Self::IntoIter {
let vec = self.data.into_inner();
vec.into_iter()
}
}
impl<V: Copy> FromIterator<V> for ValueVec<V> {
fn from_iter<I: IntoIterator<Item = V>>(iter: I) -> Self {
Self::from(Vec::from_iter(iter))
}
}
#[cfg(test)]
mod tests {
use super::ValueVec;
#[test]
fn push_pop() {
let v = ValueVec::new();
assert!(v.is_empty());
v.push(1);
v.push(2);
v.push(3);
assert_eq!(v.len(), 3);
assert_eq!(v.pop(), Some(3));
assert_eq!(v.pop(), Some(2));
assert_eq!(v.pop(), Some(1));
assert_eq!(v.pop(), None);
}
#[test]
fn get_cloned_and_replace() {
let v = ValueVec::new();
v.extend([10, 20, 30]);
assert_eq!(v.get(1), Some(20));
assert_eq!(v.replace(1, 99), 20);
assert_eq!(v.get(1), Some(99));
}
#[test]
fn insert_and_remove() {
let v = ValueVec::new();
v.extend([1, 2, 3]);
v.insert(1, 9); assert_eq!(v.len(), 4);
assert_eq!(v.remove(2), 2); assert_eq!(v.get(0), Some(1));
assert_eq!(v.at(1), 9);
assert_eq!(v.at(2), 3);
assert_eq!(v.remove(1), 9);
}
#[test]
fn swap_remove_works() {
let v = ValueVec::new();
v.extend([10, 20, 30, 40]);
let got = v.swap_remove(1);
assert_eq!(got, 20);
assert_eq!(v.len(), 3);
let snapshot = v.to_vec();
assert!(snapshot.contains(&10));
assert!(snapshot.contains(&30));
assert!(snapshot.contains(&40));
assert!(!snapshot.contains(&20));
let v: Vec<i32> = v.into();
assert_eq!(snapshot, v);
}
#[test]
fn to_vec_clone_snapshot() {
let v = ValueVec::new();
v.extend(["a", "b"]);
let snap = v.to_vec();
assert_eq!(snap, vec!["a", "b"]);
v.push("c");
assert_eq!(v.len(), 3);
assert_eq!(snap.len(), 2);
}
#[test]
fn debug_impl() {
let v = ValueVec::from(vec![1, 2, 3]);
let s = format!("{v:?}");
println!("{}", s);
assert!(!s.contains("ValueVec"));
assert!(s.contains("[1, 2, 3]"));
}
#[test]
fn from_vec_wraps_without_copy() {
let v = vec![1, 2, 3];
let vv = ValueVec::from(v);
assert_eq!(vv.len(), 3);
assert_eq!(vv.at(0), 1);
assert_eq!(vv.at(1), 2);
assert_eq!(vv.at(2), 3);
}
#[test]
fn into_vec_unwraps_without_copy() {
let vv = ValueVec::from(vec!["a", "b"]);
let v: Vec<_> = vv.into(); assert_eq!(v, vec!["a", "b"]);
}
#[test]
fn round_trip_from_vec_into_vec() {
let original = vec![10, 20, 30];
let vv = ValueVec::from(original);
let roundtrip: Vec<_> = vv.into();
assert_eq!(roundtrip, vec![10, 20, 30]);
}
#[test]
fn into_iterator_consumes_valuevec() {
let vv = ValueVec::from(vec![1, 2, 3]);
let collected: Vec<_> = vv.into_iter().collect();
assert_eq!(collected, vec![1, 2, 3]);
}
#[test]
fn into_iterator_and_into_vec_equivalence() {
let vv1 = ValueVec::from(vec![5, 6, 7]);
let vv2 = ValueVec::from(vec![5, 6, 7]);
let collected_from_iter: Vec<_> = vv1.into_iter().collect();
let collected_from_into: Vec<_> = vv2.into();
assert_eq!(collected_from_iter, collected_from_into);
}
#[test]
fn from_iterator_collect() {
let source = [1, 2, 3, 4, 5];
let vv: ValueVec<i32> = source.iter().copied().collect();
assert_eq!(vv.len(), 5);
assert_eq!(vv.at(0), 1);
assert_eq!(vv.at(4), 5);
}
}