diff options
| author | Jeremy Fitzhardinge <jsgf@fb.com> | 2018-05-17 08:17:35 -0700 |
|---|---|---|
| committer | Jeremy Fitzhardinge <jsgf@fb.com> | 2018-05-31 13:27:08 -0700 |
| commit | 37f5cf563c2c039503e8e50e252f2c1b31d69268 (patch) | |
| tree | 77eef669544c42a7876ffa3c5d7f529c528c86d8 | |
| parent | 72433e179d203431c85164555e651c7d65bd93c7 (diff) | |
| download | rust-37f5cf563c2c039503e8e50e252f2c1b31d69268.tar.gz rust-37f5cf563c2c039503e8e50e252f2c1b31d69268.zip | |
Implement `downcast` for `Arc<Any + Send + Sync>`
We only need to implement it for `Any + Send + Sync` because in practice that's the only useful combination for `Arc` and `Any`. Implementation for #44608 under the `rc_downcast` feature.
| -rw-r--r-- | src/liballoc/arc.rs | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index f7513248784..0795498f87f 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -16,6 +16,7 @@ //! //! [arc]: struct.Arc.html +use core::any::Any; use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; use core::borrow; @@ -971,6 +972,49 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc<T> { } } +impl Arc<Any + Send + Sync> { + #[inline] + #[unstable(feature = "rc_downcast", issue = "44608")] + /// Attempt to downcast the `Arc<Any + Send + Sync>` to a concrete type. + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_downcast)] + /// use std::any::Any; + /// use std::sync::Arc; + /// + /// fn print_if_string(value: Arc<Any + Send + Sync>) { + /// if let Ok(string) = value.downcast::<String>() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// fn main() { + /// let my_string = "Hello World".to_string(); + /// print_if_string(Arc::new(my_string)); + /// print_if_string(Arc::new(0i8)); + /// } + /// ``` + pub fn downcast<T>(self) -> Result<Arc<T>, Self> + where + T: Any + Send + Sync + 'static, + { + if (*self).is::<T>() { + unsafe { + let raw: *const ArcInner<Any + Send + Sync> = self.ptr.as_ptr(); + mem::forget(self); + Ok(Arc { + ptr: NonNull::new_unchecked(raw as *const ArcInner<T> as *mut _), + phantom: PhantomData, + }) + } + } else { + Err(self) + } + } +} + impl<T> Weak<T> { /// Constructs a new `Weak<T>`, allocating memory for `T` without initializing /// it. Calling [`upgrade`] on the return value always gives [`None`]. @@ -1844,6 +1888,26 @@ mod tests { assert_eq!(&r[..], [1, 2, 3]); } + + #[test] + fn test_downcast() { + use std::any::Any; + + let r1: Arc<Any + Send + Sync> = Arc::new(i32::max_value()); + let r2: Arc<Any + Send + Sync> = Arc::new("abc"); + + assert!(r1.clone().downcast::<u32>().is_err()); + + let r1i32 = r1.downcast::<i32>(); + assert!(r1i32.is_ok()); + assert_eq!(r1i32.unwrap(), Arc::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(), Arc::new("abc")); + } } #[stable(feature = "rust1", since = "1.0.0")] |
