Cover zero-sized vector semantics
This commit is contained in:
+109
@@ -6,9 +6,11 @@
|
||||
use super::*;
|
||||
use std::alloc::Layout;
|
||||
use std::cell::Cell;
|
||||
use std::marker::PhantomData;
|
||||
use std::panic;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
struct DropTracker {
|
||||
counter: Rc<Cell<usize>>,
|
||||
@@ -723,6 +725,113 @@ fn test_erased_layout_and_capacity_bytes() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ordinary_zst_uses_logical_max_capacity() {
|
||||
let mut erased = TypeErasedVec::new(vec![(), (), ()]);
|
||||
|
||||
assert_erased_state(&erased, 3, Layout::new::<()>());
|
||||
assert_eq!(erased.capacity(), usize::MAX);
|
||||
assert_eq!(erased.capacity_bytes(), 0);
|
||||
|
||||
erased.clear();
|
||||
assert!(erased.is_empty());
|
||||
assert_eq!(erased.capacity(), usize::MAX);
|
||||
|
||||
let mut guard = erased.as_type::<()>();
|
||||
guard.push(());
|
||||
assert_eq!(guard.length(), 1);
|
||||
assert_eq!(guard.capacity(), usize::MAX);
|
||||
|
||||
let restored = guard.take();
|
||||
assert_eq!(restored, vec![()]);
|
||||
assert_eq!(restored.capacity(), usize::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zst_destructors_run_exactly_once() {
|
||||
static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
struct DropZst;
|
||||
|
||||
impl Drop for DropZst {
|
||||
fn drop(&mut self) {
|
||||
DROP_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
DROP_COUNT.store(0, Ordering::Relaxed);
|
||||
let mut erased = TypeErasedVec::new(vec![DropZst, DropZst, DropZst]);
|
||||
|
||||
assert_eq!(erased.capacity(), usize::MAX);
|
||||
erased.clear();
|
||||
assert_eq!(DROP_COUNT.load(Ordering::Relaxed), 3);
|
||||
|
||||
let mut guard = erased.as_type::<DropZst>();
|
||||
guard.push(DropZst);
|
||||
guard.push(DropZst);
|
||||
drop(erased);
|
||||
assert_eq!(DROP_COUNT.load(Ordering::Relaxed), 5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compatible_zst_retained_cast() {
|
||||
struct SourceZst;
|
||||
struct TargetZst;
|
||||
|
||||
let mut erased = TypeErasedVec::new(vec![SourceZst, SourceZst]);
|
||||
|
||||
{
|
||||
// SAFETY: Both unit structs accept every value and have identical
|
||||
// zero-sized, align-one layouts.
|
||||
let mut guard = unsafe { erased.cast_type::<TargetZst>() };
|
||||
assert_eq!(guard.length(), 2);
|
||||
assert_eq!(guard.capacity(), usize::MAX);
|
||||
guard.push(TargetZst);
|
||||
}
|
||||
|
||||
// SAFETY: Both ZST types accept every possible value and share a layout.
|
||||
let restored = unsafe { erased.cast_into_vec::<SourceZst>() };
|
||||
assert_eq!(restored.len(), 3);
|
||||
assert_eq!(restored.capacity(), usize::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aligned_zst_layout_mismatch_is_non_destructive() {
|
||||
#[repr(align(8))]
|
||||
struct AlignedZst;
|
||||
|
||||
let mut erased = TypeErasedVec::new(vec![(), ()]);
|
||||
|
||||
assert!(erased.try_as_type::<AlignedZst>().is_none());
|
||||
assert_erased_state(&erased, 2, Layout::new::<()>());
|
||||
assert_eq!(erased.capacity(), usize::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scoped_borrowed_zst_behavior() {
|
||||
struct BorrowedZst<'a>(PhantomData<&'a u8>);
|
||||
|
||||
impl<'a> BorrowedZst<'a> {
|
||||
fn new(_: &'a u8) -> Self {
|
||||
Self(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
let local = 42_u8;
|
||||
let mut erased = TypeErasedVec::new(Vec::<()>::new());
|
||||
|
||||
{
|
||||
let mut guard = erased.as_type_scoped::<BorrowedZst<'_>>();
|
||||
guard.push(BorrowedZst::new(&local));
|
||||
assert_eq!(guard.length(), 1);
|
||||
assert_eq!(guard.capacity(), usize::MAX);
|
||||
}
|
||||
|
||||
erased.clear();
|
||||
assert!(erased.is_empty());
|
||||
assert_eq!(erased.capacity(), usize::MAX);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unchecked_methods() {
|
||||
let vec = vec![123_u32];
|
||||
|
||||
Reference in New Issue
Block a user