Skip to content

Commit 37f5cf5

Browse files
committed
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 rust-lang#44608 under the `rc_downcast` feature.
1 parent 72433e1 commit 37f5cf5

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

Diff for: src/liballoc/arc.rs

+64
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//!
1717
//! [arc]: struct.Arc.html
1818
19+
use core::any::Any;
1920
use core::sync::atomic;
2021
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
2122
use core::borrow;
@@ -971,6 +972,49 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc<T> {
971972
}
972973
}
973974

975+
impl Arc<Any + Send + Sync> {
976+
#[inline]
977+
#[unstable(feature = "rc_downcast", issue = "44608")]
978+
/// Attempt to downcast the `Arc<Any + Send + Sync>` to a concrete type.
979+
///
980+
/// # Examples
981+
///
982+
/// ```
983+
/// #![feature(rc_downcast)]
984+
/// use std::any::Any;
985+
/// use std::sync::Arc;
986+
///
987+
/// fn print_if_string(value: Arc<Any + Send + Sync>) {
988+
/// if let Ok(string) = value.downcast::<String>() {
989+
/// println!("String ({}): {}", string.len(), string);
990+
/// }
991+
/// }
992+
///
993+
/// fn main() {
994+
/// let my_string = "Hello World".to_string();
995+
/// print_if_string(Arc::new(my_string));
996+
/// print_if_string(Arc::new(0i8));
997+
/// }
998+
/// ```
999+
pub fn downcast<T>(self) -> Result<Arc<T>, Self>
1000+
where
1001+
T: Any + Send + Sync + 'static,
1002+
{
1003+
if (*self).is::<T>() {
1004+
unsafe {
1005+
let raw: *const ArcInner<Any + Send + Sync> = self.ptr.as_ptr();
1006+
mem::forget(self);
1007+
Ok(Arc {
1008+
ptr: NonNull::new_unchecked(raw as *const ArcInner<T> as *mut _),
1009+
phantom: PhantomData,
1010+
})
1011+
}
1012+
} else {
1013+
Err(self)
1014+
}
1015+
}
1016+
}
1017+
9741018
impl<T> Weak<T> {
9751019
/// Constructs a new `Weak<T>`, allocating memory for `T` without initializing
9761020
/// it. Calling [`upgrade`] on the return value always gives [`None`].
@@ -1844,6 +1888,26 @@ mod tests {
18441888

18451889
assert_eq!(&r[..], [1, 2, 3]);
18461890
}
1891+
1892+
#[test]
1893+
fn test_downcast() {
1894+
use std::any::Any;
1895+
1896+
let r1: Arc<Any + Send + Sync> = Arc::new(i32::max_value());
1897+
let r2: Arc<Any + Send + Sync> = Arc::new("abc");
1898+
1899+
assert!(r1.clone().downcast::<u32>().is_err());
1900+
1901+
let r1i32 = r1.downcast::<i32>();
1902+
assert!(r1i32.is_ok());
1903+
assert_eq!(r1i32.unwrap(), Arc::new(i32::max_value()));
1904+
1905+
assert!(r2.clone().downcast::<i32>().is_err());
1906+
1907+
let r2str = r2.downcast::<&'static str>();
1908+
assert!(r2str.is_ok());
1909+
assert_eq!(r2str.unwrap(), Arc::new("abc"));
1910+
}
18471911
}
18481912

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

0 commit comments

Comments
 (0)