diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2021-12-04 02:26:21 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-12-04 02:26:21 +0100 |
| commit | 0bd4ee79e099a75a13396de272278c9ad8192bd5 (patch) | |
| tree | 32f416cc481be4a995c6090f5769225ce8a9eca8 | |
| parent | f99cd4022a0f0974f183f8459c9dda86568a90a8 (diff) | |
| parent | 4ec5cdc94b83e1a37c628033597c17c4d7645128 (diff) | |
| download | rust-0bd4ee79e099a75a13396de272278c9ad8192bd5.tar.gz rust-0bd4ee79e099a75a13396de272278c9ad8192bd5.zip | |
Rollup merge of #90851 - ibraheemdev:downcast-unchecked, r=scottmcm
Add unchecked downcast methods
```rust
impl dyn Any (+ Send + Sync) {
pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T;
pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T;
}
impl<A: Allocator> Box<dyn Any (+ Send + Sync), A> {
pub unsafe fn downcast_unchecked<T: Any>(&self) -> Box<T, A>;
}
```
| -rw-r--r-- | library/alloc/src/boxed.rs | 137 | ||||
| -rw-r--r-- | library/core/src/any.rs | 174 |
2 files changed, 275 insertions, 36 deletions
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 0b72b3f0ee7..ab41f5646e5 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1518,8 +1518,6 @@ impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> { } impl<A: Allocator> Box<dyn Any, A> { - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. /// /// # Examples @@ -1537,21 +1535,48 @@ impl<A: Allocator> Box<dyn Any, A> { /// print_if_string(Box::new(my_string)); /// print_if_string(Box::new(0i8)); /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> { - if self.is::<T>() { - unsafe { - let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); - Ok(Box::from_raw_in(raw as *mut T, alloc)) - } - } else { - Err(self) + if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) } + } + + /// Downcasts the box to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box<dyn Any> = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::<usize>(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// [`downcast`]: Self::downcast + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "90850")] + pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> { + debug_assert!(self.is::<T>()); + unsafe { + let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) } } } impl<A: Allocator> Box<dyn Any + Send, A> { - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. /// /// # Examples @@ -1569,21 +1594,48 @@ impl<A: Allocator> Box<dyn Any + Send, A> { /// print_if_string(Box::new(my_string)); /// print_if_string(Box::new(0i8)); /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> { - if self.is::<T>() { - unsafe { - let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); - Ok(Box::from_raw_in(raw as *mut T, alloc)) - } - } else { - Err(self) + if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) } + } + + /// Downcasts the box to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box<dyn Any + Send> = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::<usize>(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// [`downcast`]: Self::downcast + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "90850")] + pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> { + debug_assert!(self.is::<T>()); + unsafe { + let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) } } } impl<A: Allocator> Box<dyn Any + Send + Sync, A> { - #[inline] - #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")] /// Attempt to downcast the box to a concrete type. /// /// # Examples @@ -1601,15 +1653,44 @@ impl<A: Allocator> Box<dyn Any + Send + Sync, A> { /// print_if_string(Box::new(my_string)); /// print_if_string(Box::new(0i8)); /// ``` + #[inline] + #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")] pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> { - if self.is::<T>() { - unsafe { - let (raw, alloc): (*mut (dyn Any + Send + Sync), _) = - Box::into_raw_with_allocator(self); - Ok(Box::from_raw_in(raw as *mut T, alloc)) - } - } else { - Err(self) + if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) } + } + + /// Downcasts the box to a concrete type. + /// + /// For a safe alternative see [`downcast`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::<usize>(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + /// + /// [`downcast`]: Self::downcast + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "90850")] + pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> { + debug_assert!(self.is::<T>()); + unsafe { + let (raw, alloc): (*mut (dyn Any + Send + Sync), _) = + Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) } } } diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 1fd5aa27fce..72528185707 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -164,7 +164,7 @@ impl fmt::Debug for dyn Any + Send + Sync { } impl dyn Any { - /// Returns `true` if the boxed type is the same as `T`. + /// Returns `true` if the inner type is the same as `T`. /// /// # Examples /// @@ -195,7 +195,7 @@ impl dyn Any { t == concrete } - /// Returns some reference to the boxed value if it is of type `T`, or + /// Returns some reference to the inner value if it is of type `T`, or /// `None` if it isn't. /// /// # Examples @@ -221,13 +221,13 @@ impl dyn Any { // SAFETY: just checked whether we are pointing to the correct type, and we can rely on // that check for memory safety because we have implemented Any for all types; no other // impls can exist as they would conflict with our impl. - unsafe { Some(&*(self as *const dyn Any as *const T)) } + unsafe { Some(self.downcast_ref_unchecked()) } } else { None } } - /// Returns some mutable reference to the boxed value if it is of type `T`, or + /// Returns some mutable reference to the inner value if it is of type `T`, or /// `None` if it isn't. /// /// # Examples @@ -257,15 +257,73 @@ impl dyn Any { // SAFETY: just checked whether we are pointing to the correct type, and we can rely on // that check for memory safety because we have implemented Any for all types; no other // impls can exist as they would conflict with our impl. - unsafe { Some(&mut *(self as *mut dyn Any as *mut T)) } + unsafe { Some(self.downcast_mut_unchecked()) } } else { None } } + + /// Returns a reference to the inner value as type `dyn T`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box<dyn Any> = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + #[unstable(feature = "downcast_unchecked", issue = "90850")] + #[inline] + pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T { + debug_assert!(self.is::<T>()); + // SAFETY: caller guarantees that T is the correct type + unsafe { &*(self as *const dyn Any as *const T) } + } + + /// Returns a mutable reference to the inner value as type `dyn T`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let mut x: Box<dyn Any> = Box::new(1_usize); + /// + /// unsafe { + /// *x.downcast_mut_unchecked::<usize>() += 1; + /// } + /// + /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2); + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + #[unstable(feature = "downcast_unchecked", issue = "90850")] + #[inline] + pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T { + debug_assert!(self.is::<T>()); + // SAFETY: caller guarantees that T is the correct type + unsafe { &mut *(self as *mut dyn Any as *mut T) } + } } impl dyn Any + Send { - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Any`. /// /// # Examples /// @@ -289,7 +347,7 @@ impl dyn Any + Send { <dyn Any>::is::<T>(self) } - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Any`. /// /// # Examples /// @@ -313,7 +371,7 @@ impl dyn Any + Send { <dyn Any>::downcast_ref::<T>(self) } - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Any`. /// /// # Examples /// @@ -340,6 +398,60 @@ impl dyn Any + Send { pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { <dyn Any>::downcast_mut::<T>(self) } + + /// Forwards to the method defined on the type `dyn Any`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box<dyn Any> = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// Same as the method on the type `dyn Any`. + #[unstable(feature = "downcast_unchecked", issue = "90850")] + #[inline] + pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T { + // SAFETY: guaranteed by caller + unsafe { <dyn Any>::downcast_ref_unchecked::<T>(self) } + } + + /// Forwards to the method defined on the type `dyn Any`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let mut x: Box<dyn Any> = Box::new(1_usize); + /// + /// unsafe { + /// *x.downcast_mut_unchecked::<usize>() += 1; + /// } + /// + /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2); + /// ``` + /// + /// # Safety + /// + /// Same as the method on the type `dyn Any`. + #[unstable(feature = "downcast_unchecked", issue = "90850")] + #[inline] + pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T { + // SAFETY: guaranteed by caller + unsafe { <dyn Any>::downcast_mut_unchecked::<T>(self) } + } } impl dyn Any + Send + Sync { @@ -418,6 +530,52 @@ impl dyn Any + Send + Sync { pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { <dyn Any>::downcast_mut::<T>(self) } + + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box<dyn Any> = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_ref_unchecked::<usize>(), 1); + /// } + /// ``` + #[unstable(feature = "downcast_unchecked", issue = "90850")] + #[inline] + pub unsafe fn downcast_ref_unchecked<T: Any>(&self) -> &T { + // SAFETY: guaranteed by caller + unsafe { <dyn Any>::downcast_ref_unchecked::<T>(self) } + } + + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let mut x: Box<dyn Any> = Box::new(1_usize); + /// + /// unsafe { + /// *x.downcast_mut_unchecked::<usize>() += 1; + /// } + /// + /// assert_eq!(*x.downcast_ref::<usize>().unwrap(), 2); + /// ``` + #[unstable(feature = "downcast_unchecked", issue = "90850")] + #[inline] + pub unsafe fn downcast_mut_unchecked<T: Any>(&mut self) -> &mut T { + // SAFETY: guaranteed by caller + unsafe { <dyn Any>::downcast_mut_unchecked::<T>(self) } + } } /////////////////////////////////////////////////////////////////////////////// |
