Skip to content

Commit 29403ee

Browse files
committed
add unchecked downcast methods
1 parent e90c5fb commit 29403ee

File tree

2 files changed

+273
-36
lines changed

2 files changed

+273
-36
lines changed

library/alloc/src/boxed.rs

+103-28
Original file line numberDiff line numberDiff line change
@@ -1482,8 +1482,6 @@ impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
14821482
}
14831483

14841484
impl<A: Allocator> Box<dyn Any, A> {
1485-
#[inline]
1486-
#[stable(feature = "rust1", since = "1.0.0")]
14871485
/// Attempt to downcast the box to a concrete type.
14881486
///
14891487
/// # Examples
@@ -1501,21 +1499,46 @@ impl<A: Allocator> Box<dyn Any, A> {
15011499
/// print_if_string(Box::new(my_string));
15021500
/// print_if_string(Box::new(0i8));
15031501
/// ```
1502+
#[inline]
1503+
#[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
15041504
pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
1505-
if self.is::<T>() {
1506-
unsafe {
1507-
let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
1508-
Ok(Box::from_raw_in(raw as *mut T, alloc))
1509-
}
1510-
} else {
1511-
Err(self)
1505+
if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
1506+
}
1507+
1508+
/// Downcasts the box to a concrete type.
1509+
///
1510+
/// For a safe alternative see [`downcast`].
1511+
///
1512+
/// # Examples
1513+
///
1514+
/// ```
1515+
/// #![feature(downcast_unchecked)]
1516+
///
1517+
/// use std::any::Any;
1518+
///
1519+
/// let x: Box<dyn Any> = Box::new(1_usize);
1520+
///
1521+
/// unsafe {
1522+
/// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
1523+
/// }
1524+
/// ```
1525+
///
1526+
/// # Safety
1527+
///
1528+
/// The contained value must be of type `T`. Calling this method
1529+
/// with the incorrect type is *undefined behavior*.
1530+
#[inline]
1531+
#[unstable(feature = "downcast_unchecked", issue = "none")]
1532+
pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
1533+
debug_assert!(self.is::<T>());
1534+
unsafe {
1535+
let (raw, alloc): (*mut dyn Any, _) = Box::into_raw_with_allocator(self);
1536+
Box::from_raw_in(raw as *mut T, alloc)
15121537
}
15131538
}
15141539
}
15151540

15161541
impl<A: Allocator> Box<dyn Any + Send, A> {
1517-
#[inline]
1518-
#[stable(feature = "rust1", since = "1.0.0")]
15191542
/// Attempt to downcast the box to a concrete type.
15201543
///
15211544
/// # Examples
@@ -1533,21 +1556,46 @@ impl<A: Allocator> Box<dyn Any + Send, A> {
15331556
/// print_if_string(Box::new(my_string));
15341557
/// print_if_string(Box::new(0i8));
15351558
/// ```
1559+
#[inline]
1560+
#[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
15361561
pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
1537-
if self.is::<T>() {
1538-
unsafe {
1539-
let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
1540-
Ok(Box::from_raw_in(raw as *mut T, alloc))
1541-
}
1542-
} else {
1543-
Err(self)
1562+
if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
1563+
}
1564+
1565+
/// Downcasts the box to a concrete type.
1566+
///
1567+
/// For a safe alternative see [`downcast`].
1568+
///
1569+
/// # Examples
1570+
///
1571+
/// ```
1572+
/// #![feature(downcast_unchecked)]
1573+
///
1574+
/// use std::any::Any;
1575+
///
1576+
/// let x: Box<dyn Any + Send> = Box::new(1_usize);
1577+
///
1578+
/// unsafe {
1579+
/// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
1580+
/// }
1581+
/// ```
1582+
///
1583+
/// # Safety
1584+
///
1585+
/// The contained value must be of type `T`. Calling this method
1586+
/// with the incorrect type is *undefined behavior*.
1587+
#[inline]
1588+
#[unstable(feature = "downcast_unchecked", issue = "none")]
1589+
pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
1590+
debug_assert!(self.is::<T>());
1591+
unsafe {
1592+
let (raw, alloc): (*mut (dyn Any + Send), _) = Box::into_raw_with_allocator(self);
1593+
Box::from_raw_in(raw as *mut T, alloc)
15441594
}
15451595
}
15461596
}
15471597

15481598
impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
1549-
#[inline]
1550-
#[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
15511599
/// Attempt to downcast the box to a concrete type.
15521600
///
15531601
/// # Examples
@@ -1565,15 +1613,42 @@ impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
15651613
/// print_if_string(Box::new(my_string));
15661614
/// print_if_string(Box::new(0i8));
15671615
/// ```
1616+
#[inline]
1617+
#[stable(feature = "box_send_sync_any_downcast", since = "1.51.0")]
15681618
pub fn downcast<T: Any>(self) -> Result<Box<T, A>, Self> {
1569-
if self.is::<T>() {
1570-
unsafe {
1571-
let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
1572-
Box::into_raw_with_allocator(self);
1573-
Ok(Box::from_raw_in(raw as *mut T, alloc))
1574-
}
1575-
} else {
1576-
Err(self)
1619+
if self.is::<T>() { unsafe { Ok(self.downcast_unchecked::<T>()) } } else { Err(self) }
1620+
}
1621+
1622+
/// Downcasts the box to a concrete type.
1623+
///
1624+
/// For a safe alternative see [`downcast`].
1625+
///
1626+
/// # Examples
1627+
///
1628+
/// ```
1629+
/// #![feature(downcast_unchecked)]
1630+
///
1631+
/// use std::any::Any;
1632+
///
1633+
/// let x: Box<dyn Any + Send + Sync> = Box::new(1_usize);
1634+
///
1635+
/// unsafe {
1636+
/// assert_eq!(*x.downcast_unchecked::<usize>(), 1);
1637+
/// }
1638+
/// ```
1639+
///
1640+
/// # Safety
1641+
///
1642+
/// The contained value must be of type `T`. Calling this method
1643+
/// with the incorrect type is *undefined behavior*.
1644+
#[inline]
1645+
#[unstable(feature = "downcast_unchecked", issue = "none")]
1646+
pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
1647+
debug_assert!(self.is::<T>());
1648+
unsafe {
1649+
let (raw, alloc): (*mut (dyn Any + Send + Sync), _) =
1650+
Box::into_raw_with_allocator(self);
1651+
Box::from_raw_in(raw as *mut T, alloc)
15771652
}
15781653
}
15791654
}

0 commit comments

Comments
 (0)