Skip to content

Commit

Permalink
Implement downcast for Arc<Any + Send + Sync>
Browse files Browse the repository at this point in the history
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 rust-lang#44608 under the `rc_downcast` feature.
  • Loading branch information
jsgf committed May 31, 2018
1 parent 72433e1 commit 37f5cf5
Showing 1 changed file with 64 additions and 0 deletions.
64 changes: 64 additions & 0 deletions src/liballoc/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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`].
Expand Down Expand Up @@ -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")]
Expand Down

0 comments on commit 37f5cf5

Please sign in to comment.