diff --git a/src/send.rs b/src/send.rs index a253cdf..c63d6af 100644 --- a/src/send.rs +++ b/src/send.rs @@ -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(&mut self) -> Option> 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(&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(&mut self) -> Option> @@ -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(&mut self) -> ContentGuard<'_, T> where T: $first_bound $(+ $remaining_bound)*, diff --git a/src/tests.rs b/src/tests.rs index 7ec344a..8757fbf 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -160,6 +160,40 @@ macro_rules! assert_thread_safe_erased_vec_api { let mut erased = <$wrapper>::new(Vec::::new()); assert!(erased.try_as_type::().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::().is_none()); + assert!( + panic::catch_unwind(panic::AssertUnwindSafe(|| { + let _ = erased.as_type::(); + })) + .is_err() + ); + assert!(erased.try_as_type_scoped::().is_none()); + assert!( + panic::catch_unwind(panic::AssertUnwindSafe(|| { + let _ = erased.as_type_scoped::(); + })) + .is_err() + ); + assert_eq!(erased.layout(), Layout::new::>()); + 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 type. + let guard = unsafe { erased.cast_type::>() }; + 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::() }.as_slice(), &[1_u32]);