Skip to content

Commit 758a0ce

Browse files
committed
alloc: Implement downcast Rc<Any> -> Rc<T>
Implement downcast the like it exists for Box. The implementation avoids using into_raw/from_raw, because the pointer arithmetic which should cancel does not seem to optimize out at the moment. Since Rc<T> is never Send, only Rc<Any> and not Rc<Any + Send> implements downcast.
1 parent efceda2 commit 758a0ce

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

src/liballoc/rc.rs

+61
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ use boxed::Box;
244244
#[cfg(test)]
245245
use std::boxed::Box;
246246

247+
use core::any::Any;
247248
use core::borrow;
248249
use core::cell::Cell;
249250
use core::cmp::Ordering;
@@ -608,6 +609,46 @@ impl<T: Clone> Rc<T> {
608609
}
609610
}
610611

612+
impl Rc<Any> {
613+
#[inline]
614+
#[unstable(feature = "rc_downcast", issue = "0")]
615+
/// Attempt to downcast the `Rc<Any>` to a concrete type.
616+
///
617+
/// # Examples
618+
///
619+
/// ```
620+
/// #![feature(rc_downcast)]
621+
/// use std::any::Any;
622+
/// use std::rc::Rc;
623+
///
624+
/// fn print_if_string(value: Rc<Any>) {
625+
/// if let Ok(string) = value.downcast::<String>() {
626+
/// println!("String ({}): {}", string.len(), string);
627+
/// }
628+
/// }
629+
///
630+
/// fn main() {
631+
/// let my_string = "Hello World".to_string();
632+
/// print_if_string(Rc::new(my_string));
633+
/// print_if_string(Rc::new(0i8));
634+
/// }
635+
/// ```
636+
pub fn downcast<T: Any>(self) -> Result<Rc<T>, Rc<Any>> {
637+
if (*self).is::<T>() {
638+
// avoid the pointer arithmetic in from_raw
639+
unsafe {
640+
let raw: *const RcBox<Any> = self.ptr.as_ptr();
641+
forget(self);
642+
Ok(Rc {
643+
ptr: Shared::new_unchecked(raw as *const RcBox<T> as *mut _),
644+
})
645+
}
646+
} else {
647+
Err(self)
648+
}
649+
}
650+
}
651+
611652
impl<T: ?Sized> Rc<T> {
612653
// Allocates an `RcBox<T>` with sufficient space for an unsized value
613654
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
@@ -1696,6 +1737,26 @@ mod tests {
16961737

16971738
assert_eq!(&r[..], [1, 2, 3]);
16981739
}
1740+
1741+
#[test]
1742+
fn test_downcast() {
1743+
use std::any::Any;
1744+
1745+
let r1: Rc<Any> = Rc::new(i32::max_value());
1746+
let r2: Rc<Any> = Rc::new("abc");
1747+
1748+
assert!(r1.clone().downcast::<u32>().is_err());
1749+
1750+
let r1i32 = r1.downcast::<i32>();
1751+
assert!(r1i32.is_ok());
1752+
assert_eq!(r1i32.unwrap(), Rc::new(i32::max_value()));
1753+
1754+
assert!(r2.clone().downcast::<i32>().is_err());
1755+
1756+
let r2str = r2.downcast::<&'static str>();
1757+
assert!(r2str.is_ok());
1758+
assert_eq!(r2str.unwrap(), Rc::new("abc"));
1759+
}
16991760
}
17001761

17011762
#[stable(feature = "rust1", since = "1.0.0")]

0 commit comments

Comments
 (0)