Verify wrapper mismatch preservation

This commit is contained in:
2026-07-31 03:54:16 +02:00
parent 78159657ae
commit 417e811273
2 changed files with 44 additions and 2 deletions
+10 -2
View File
@@ -90,6 +90,9 @@ macro_rules! define_thread_safe_erased_vec {
}
/// Clear the vector and access its allocation as a vector of `T`.
///
/// A layout mismatch returns `None` without changing the erased
/// vector.
pub fn try_as_type<T>(&mut self) -> Option<ContentGuard<'_, T>>
where
T: $first_bound $(+ $remaining_bound)* + 'static,
@@ -100,7 +103,8 @@ macro_rules! define_thread_safe_erased_vec {
/// Clear the vector and access its allocation as a vector of `T`.
///
/// # Panics
/// Panics if `T` does not have the erased allocation's layout.
/// Panics if `T` does not have the erased allocation's layout. A
/// layout-mismatch panic leaves the erased vector unchanged.
pub fn as_type<T>(&mut self) -> ContentGuard<'_, T>
where
T: $first_bound $(+ $remaining_bound)* + 'static,
@@ -111,6 +115,9 @@ macro_rules! define_thread_safe_erased_vec {
/// Clear the vector and access its allocation using a possibly
/// non-`'static` type that does not need drop.
///
/// A layout mismatch returns `None` without changing the erased
/// vector.
///
/// # Panics
/// Panics if `T` needs drop.
pub fn try_as_type_scoped<T>(&mut self) -> Option<ContentGuard<'_, T>>
@@ -125,7 +132,8 @@ macro_rules! define_thread_safe_erased_vec {
///
/// # Panics
/// Panics if `T` needs drop or does not have the erased allocation's
/// layout.
/// layout. A layout-mismatch panic leaves the erased vector
/// unchanged.
pub fn as_type_scoped<T>(&mut self) -> ContentGuard<'_, T>
where
T: $first_bound $(+ $remaining_bound)*,
+34
View File
@@ -160,6 +160,40 @@ macro_rules! assert_thread_safe_erased_vec_api {
let mut erased = <$wrapper>::new(Vec::<u32>::new());
assert!(erased.try_as_type::<u64>().is_none());
let retained = Arc::new(7_i32);
let mut retained_values = Vec::with_capacity(4);
retained_values.push(Arc::clone(&retained));
let retained_ptr = retained_values.as_ptr();
let retained_capacity = retained_values.capacity();
let mut erased = <$wrapper>::new(retained_values);
assert!(erased.try_as_type::<u8>().is_none());
assert!(
panic::catch_unwind(panic::AssertUnwindSafe(|| {
let _ = erased.as_type::<u8>();
}))
.is_err()
);
assert!(erased.try_as_type_scoped::<u8>().is_none());
assert!(
panic::catch_unwind(panic::AssertUnwindSafe(|| {
let _ = erased.as_type_scoped::<u8>();
}))
.is_err()
);
assert_eq!(erased.layout(), Layout::new::<Arc<i32>>());
assert_eq!(erased.length(), 1);
assert_eq!(erased.capacity(), retained_capacity);
assert_eq!(Arc::strong_count(&retained), 2);
{
// SAFETY: Every failed probe preserved the original Arc<i32> type.
let guard = unsafe { erased.cast_type::<Arc<i32>>() };
assert_eq!(guard.as_slice().as_ptr(), retained_ptr);
}
drop(erased);
assert_eq!(Arc::strong_count(&retained), 1);
let mut erased = <$wrapper>::new(vec![1_u32]);
// SAFETY: The erased elements are still `u32`.
assert_eq!(unsafe { erased.cast_type::<u32>() }.as_slice(), &[1_u32]);