diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2017-09-16 09:16:46 -0500 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2017-09-16 17:09:36 -0700 |
| commit | 2a844b3d0d3e3db70d44ad1127f4d37b26211383 (patch) | |
| tree | 516583f05131d30307cfd8ce436722f64aff38ae | |
| parent | 277476c4fb9e967ca28a7b529dbcf6b348cb787d (diff) | |
| parent | 3a39d95330623d47bcfcd5cac2d6b3c30e12ae5a (diff) | |
| download | rust-2a844b3d0d3e3db70d44ad1127f4d37b26211383.tar.gz rust-2a844b3d0d3e3db70d44ad1127f4d37b26211383.zip | |
Rollup merge of #44273 - bluss:rc-downcast, r=alexcrichton
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
| -rw-r--r-- | src/liballoc/rc.rs | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 47f537caf31..58c589697f4 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -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; @@ -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> { @@ -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")] |
