From 29403eeef0b175b4a65cc3c7865708ee15d8a7e8 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Fri, 12 Nov 2021 22:53:26 -0500 Subject: [PATCH 1/4] add unchecked downcast methods --- library/alloc/src/boxed.rs | 131 +++++++++++++++++++++------ library/core/src/any.rs | 178 +++++++++++++++++++++++++++++++++++-- 2 files changed, 273 insertions(+), 36 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index f6332b072cf30..81ac37a306b44 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1482,8 +1482,6 @@ impl TryFrom> for Box<[T; N]> { } impl Box { - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. /// /// # Examples @@ -1501,21 +1499,46 @@ impl Box { /// 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(self) -> Result, Self> { - if self.is::() { - 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::() { unsafe { Ok(self.downcast_unchecked::()) } } 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 = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "none")] + pub unsafe fn downcast_unchecked(self) -> Box { + debug_assert!(self.is::()); + unsafe { + let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) } } } impl Box { - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. /// /// # Examples @@ -1533,21 +1556,46 @@ impl Box { /// 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(self) -> Result, Self> { - if self.is::() { - 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::() { unsafe { Ok(self.downcast_unchecked::()) } } 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 = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "none")] + pub unsafe fn downcast_unchecked(self) -> Box { + debug_assert!(self.is::()); + unsafe { + let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self); + Box::from_raw_in(raw as *mut T, alloc) } } } impl Box { - #[inline] - #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")] /// Attempt to downcast the box to a concrete type. /// /// # Examples @@ -1565,15 +1613,42 @@ impl Box { /// 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(self) -> Result, Self> { - if self.is::() { - 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::() { unsafe { Ok(self.downcast_unchecked::()) } } 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 = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_unchecked::(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// The contained value must be of type `T`. Calling this method + /// with the incorrect type is *undefined behavior*. + #[inline] + #[unstable(feature = "downcast_unchecked", issue = "none")] + pub unsafe fn downcast_unchecked(self) -> Box { + debug_assert!(self.is::()); + 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 1fd5aa27fce46..8ff38e52a6f8e 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,77 @@ 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`. + /// + /// For a safe alternative see [`downcast_ref`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_ref_unchecked::(), 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 = "none")] + #[inline] + pub unsafe fn downcast_ref_unchecked(&self) -> &T { + debug_assert!(self.is::()); + // 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`. + /// + /// For a safe alternative see [`downcast_mut`]. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let mut x: Box = Box::new(1_usize); + /// + /// unsafe { + /// *x.downcast_mut_unchecked::() += 1; + /// } + /// + /// assert_eq!(*x.downcast_ref::().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 = "none")] + #[inline] + pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + debug_assert!(self.is::()); + // 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 +351,7 @@ impl dyn Any + Send { ::is::(self) } - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Any`. /// /// # Examples /// @@ -313,7 +375,7 @@ impl dyn Any + Send { ::downcast_ref::(self) } - /// Forwards to the method defined on the type `Any`. + /// Forwards to the method defined on the type `dyn Any`. /// /// # Examples /// @@ -340,6 +402,60 @@ impl dyn Any + Send { pub fn downcast_mut(&mut self) -> Option<&mut T> { ::downcast_mut::(self) } + + /// Forwards to the method defined on the type `dyn Any`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_ref_unchecked::(), 1); + /// } + /// ``` + /// + /// # Safety + /// + /// Same as the method on the type `dyn Any`. + #[unstable(feature = "downcast_unchecked", issue = "none")] + #[inline] + pub unsafe fn downcast_ref_unchecked(&self) -> &T { + // SAFETY: guaranteed by caller + unsafe { ::downcast_ref_unchecked::(self) } + } + + /// Forwards to the method defined on the type `dyn Any`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let mut x: Box = Box::new(1_usize); + /// + /// unsafe { + /// *x.downcast_mut_unchecked::() += 1; + /// } + /// + /// assert_eq!(*x.downcast_ref::().unwrap(), 2); + /// ``` + /// + /// # Safety + /// + /// Same as the method on the type `dyn Any`. + #[unstable(feature = "downcast_unchecked", issue = "none")] + #[inline] + pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + // SAFETY: guaranteed by caller + unsafe { ::downcast_mut_unchecked::(self) } + } } impl dyn Any + Send + Sync { @@ -418,6 +534,52 @@ impl dyn Any + Send + Sync { pub fn downcast_mut(&mut self) -> Option<&mut T> { ::downcast_mut::(self) } + + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let x: Box = Box::new(1_usize); + /// + /// unsafe { + /// assert_eq!(*x.downcast_ref_unchecked::(), 1); + /// } + /// ``` + #[unstable(feature = "downcast_unchecked", issue = "none")] + #[inline] + pub unsafe fn downcast_ref_unchecked(&self) -> &T { + // SAFETY: guaranteed by caller + unsafe { ::downcast_ref_unchecked::(self) } + } + + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// #![feature(downcast_unchecked)] + /// + /// use std::any::Any; + /// + /// let mut x: Box = Box::new(1_usize); + /// + /// unsafe { + /// *x.downcast_mut_unchecked::() += 1; + /// } + /// + /// assert_eq!(*x.downcast_ref::().unwrap(), 2); + /// ``` + #[unstable(feature = "downcast_unchecked", issue = "none")] + #[inline] + pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { + // SAFETY: guaranteed by caller + unsafe { ::downcast_mut_unchecked::(self) } + } } /////////////////////////////////////////////////////////////////////////////// From 6f982930ba2da1ee99c3c4378179bcfe6f615db6 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Fri, 12 Nov 2021 22:55:11 -0500 Subject: [PATCH 2/4] add tracking issue for `downcast_unchecked` --- library/alloc/src/boxed.rs | 6 +++--- library/core/src/any.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 81ac37a306b44..1e2c1b2eee67a 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1528,7 +1528,7 @@ impl Box { /// The contained value must be of type `T`. Calling this method /// with the incorrect type is *undefined behavior*. #[inline] - #[unstable(feature = "downcast_unchecked", issue = "none")] + #[unstable(feature = "downcast_unchecked", issue = "90850")] pub unsafe fn downcast_unchecked(self) -> Box { debug_assert!(self.is::()); unsafe { @@ -1585,7 +1585,7 @@ impl Box { /// The contained value must be of type `T`. Calling this method /// with the incorrect type is *undefined behavior*. #[inline] - #[unstable(feature = "downcast_unchecked", issue = "none")] + #[unstable(feature = "downcast_unchecked", issue = "90850")] pub unsafe fn downcast_unchecked(self) -> Box { debug_assert!(self.is::()); unsafe { @@ -1642,7 +1642,7 @@ impl Box { /// The contained value must be of type `T`. Calling this method /// with the incorrect type is *undefined behavior*. #[inline] - #[unstable(feature = "downcast_unchecked", issue = "none")] + #[unstable(feature = "downcast_unchecked", issue = "90850")] pub unsafe fn downcast_unchecked(self) -> Box { debug_assert!(self.is::()); unsafe { diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 8ff38e52a6f8e..3e306b1333a1e 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -285,7 +285,7 @@ impl dyn Any { /// /// The contained value must be of type `T`. Calling this method /// with the incorrect type is *undefined behavior*. - #[unstable(feature = "downcast_unchecked", issue = "none")] + #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &T { debug_assert!(self.is::()); @@ -317,7 +317,7 @@ impl dyn Any { /// /// The contained value must be of type `T`. Calling this method /// with the incorrect type is *undefined behavior*. - #[unstable(feature = "downcast_unchecked", issue = "none")] + #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { debug_assert!(self.is::()); @@ -422,7 +422,7 @@ impl dyn Any + Send { /// # Safety /// /// Same as the method on the type `dyn Any`. - #[unstable(feature = "downcast_unchecked", issue = "none")] + #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &T { // SAFETY: guaranteed by caller @@ -450,7 +450,7 @@ impl dyn Any + Send { /// # Safety /// /// Same as the method on the type `dyn Any`. - #[unstable(feature = "downcast_unchecked", issue = "none")] + #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { // SAFETY: guaranteed by caller @@ -550,7 +550,7 @@ impl dyn Any + Send + Sync { /// assert_eq!(*x.downcast_ref_unchecked::(), 1); /// } /// ``` - #[unstable(feature = "downcast_unchecked", issue = "none")] + #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_ref_unchecked(&self) -> &T { // SAFETY: guaranteed by caller @@ -574,7 +574,7 @@ impl dyn Any + Send + Sync { /// /// assert_eq!(*x.downcast_ref::().unwrap(), 2); /// ``` - #[unstable(feature = "downcast_unchecked", issue = "none")] + #[unstable(feature = "downcast_unchecked", issue = "90850")] #[inline] pub unsafe fn downcast_mut_unchecked(&mut self) -> &mut T { // SAFETY: guaranteed by caller From 25271a5a98e362fa118672c33e4861cd42e111e9 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Sat, 20 Nov 2021 18:21:52 -0500 Subject: [PATCH 3/4] fix doc links for `downcast_unchecked` --- library/alloc/src/boxed.rs | 6 ++++++ library/core/src/any.rs | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 1e2c1b2eee67a..e6f687ddf9633 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1527,6 +1527,8 @@ impl Box { /// /// 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(self) -> Box { @@ -1584,6 +1586,8 @@ impl Box { /// /// 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(self) -> Box { @@ -1641,6 +1645,8 @@ impl Box { /// /// 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(self) -> Box { diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 3e306b1333a1e..72528185707a6 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -265,8 +265,6 @@ impl dyn Any { /// Returns a reference to the inner value as type `dyn T`. /// - /// For a safe alternative see [`downcast_ref`]. - /// /// # Examples /// /// ``` @@ -295,8 +293,6 @@ impl dyn Any { /// Returns a mutable reference to the inner value as type `dyn T`. /// - /// For a safe alternative see [`downcast_mut`]. - /// /// # Examples /// /// ``` From 4ec5cdc94b83e1a37c628033597c17c4d7645128 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Fri, 3 Dec 2021 16:06:13 -0500 Subject: [PATCH 4/4] fix stability annotations for `Box::downcast` --- library/alloc/src/boxed.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index e6f687ddf9633..4898b9ca8fc35 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1500,7 +1500,7 @@ impl Box { /// print_if_string(Box::new(0i8)); /// ``` #[inline] - #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")] + #[stable(feature = "rust1", since = "1.0.0")] pub fn downcast(self) -> Result, Self> { if self.is::() { unsafe { Ok(self.downcast_unchecked::()) } } else { Err(self) } } @@ -1559,7 +1559,7 @@ impl Box { /// print_if_string(Box::new(0i8)); /// ``` #[inline] - #[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")] + #[stable(feature = "rust1", since = "1.0.0")] pub fn downcast(self) -> Result, Self> { if self.is::() { unsafe { Ok(self.downcast_unchecked::()) } } else { Err(self) } }