Skip to content

Commit

Permalink
Rollup merge of rust-lang#44273 - bluss:rc-downcast, r=alexcrichton
Browse files Browse the repository at this point in the history
Implement <Rc<Any>>::downcast

* Implement `<Rc<Any>>::downcast::<T>`
  * New unstable method. Works just like Box\<Any\>, but for Rc.
  * Any has two cases for its methods: Any and Any + Send; Rc is never Send, so that case is skipped for Rc.
  * Motivation for being a method with self is to match Box and there is no user-supplied type; the inner type is Any and downcast does not conflict with any method of Any.
* Arc was skipped because Any itself has no downcast for the case that makes most sense: Any + Send + Sync
  • Loading branch information
alexcrichton committed Sep 17, 2017
2 parents 277476c + 3a39d95 commit 2a844b3
Showing 1 changed file with 61 additions and 0 deletions.
61 changes: 61 additions & 0 deletions src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ use boxed::Box;
#[cfg(test)]
use std::boxed::Box;

use core::any::Any;
use core::borrow;
use core::cell::Cell;
use core::cmp::Ordering;
Expand Down Expand Up @@ -608,6 +609,46 @@ impl<T: Clone> Rc<T> {
}
}

impl Rc<Any> {
#[inline]
#[unstable(feature = "rc_downcast", issue = "44608")]
/// Attempt to downcast the `Rc<Any>` to a concrete type.
///
/// # Examples
///
/// ```
/// #![feature(rc_downcast)]
/// use std::any::Any;
/// use std::rc::Rc;
///
/// fn print_if_string(value: Rc<Any>) {
/// if let Ok(string) = value.downcast::<String>() {
/// println!("String ({}): {}", string.len(), string);
/// }
/// }
///
/// fn main() {
/// let my_string = "Hello World".to_string();
/// print_if_string(Rc::new(my_string));
/// print_if_string(Rc::new(0i8));
/// }
/// ```
pub fn downcast<T: Any>(self) -> Result<Rc<T>, Rc<Any>> {
if (*self).is::<T>() {
// avoid the pointer arithmetic in from_raw
unsafe {
let raw: *const RcBox<Any> = self.ptr.as_ptr();
forget(self);
Ok(Rc {
ptr: Shared::new_unchecked(raw as *const RcBox<T> as *mut _),
})
}
} else {
Err(self)
}
}
}

impl<T: ?Sized> Rc<T> {
// Allocates an `RcBox<T>` with sufficient space for an unsized value
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
Expand Down Expand Up @@ -1696,6 +1737,26 @@ mod tests {

assert_eq!(&r[..], [1, 2, 3]);
}

#[test]
fn test_downcast() {
use std::any::Any;

let r1: Rc<Any> = Rc::new(i32::max_value());
let r2: Rc<Any> = Rc::new("abc");

assert!(r1.clone().downcast::<u32>().is_err());

let r1i32 = r1.downcast::<i32>();
assert!(r1i32.is_ok());
assert_eq!(r1i32.unwrap(), Rc::new(i32::max_value()));

assert!(r2.clone().downcast::<i32>().is_err());

let r2str = r2.downcast::<&'static str>();
assert!(r2str.is_ok());
assert_eq!(r2str.unwrap(), Rc::new("abc"));
}
}

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

0 comments on commit 2a844b3

Please sign in to comment.