Skip to content

Commit b7a9d4e

Browse files
committed
Auto merge of #50836 - jsgf:arc-downcast, r=SimonSapin
Arc downcast Implement `downcast` for `Arc<Any + Send + Sync>` as part of #44608, and gated by the same `rc_downcast` feature. This PR is mostly lightly-edited cut'n'paste. This has two additional changes: - The `downcast` implementation needs `Any + Send + Sync` implementations for `is` and `Debug`, and I added `downcast_ref` and `downcast_mut` for completeness/consistency. (Can these be insta-stabilized?) - At @SimonSapin's suggestion, I converted `Arc` and `Rc` to use `NonNull::cast` to avoid an `unsafe` block in each which tidied things up nicely.
2 parents efc508b + 87c3d7b commit b7a9d4e

File tree

3 files changed

+153
-10
lines changed

3 files changed

+153
-10
lines changed

Diff for: src/liballoc/arc.rs

+59
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,44 @@ 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+
let ptr = self.ptr.cast::<ArcInner<T>>();
1005+
mem::forget(self);
1006+
Ok(Arc { ptr, phantom: PhantomData })
1007+
} else {
1008+
Err(self)
1009+
}
1010+
}
1011+
}
1012+
9741013
impl<T> Weak<T> {
9751014
/// Constructs a new `Weak<T>`, allocating memory for `T` without initializing
9761015
/// it. Calling [`upgrade`] on the return value always gives [`None`].
@@ -1844,6 +1883,26 @@ mod tests {
18441883

18451884
assert_eq!(&r[..], [1, 2, 3]);
18461885
}
1886+
1887+
#[test]
1888+
fn test_downcast() {
1889+
use std::any::Any;
1890+
1891+
let r1: Arc<Any + Send + Sync> = Arc::new(i32::max_value());
1892+
let r2: Arc<Any + Send + Sync> = Arc::new("abc");
1893+
1894+
assert!(r1.clone().downcast::<u32>().is_err());
1895+
1896+
let r1i32 = r1.downcast::<i32>();
1897+
assert!(r1i32.is_ok());
1898+
assert_eq!(r1i32.unwrap(), Arc::new(i32::max_value()));
1899+
1900+
assert!(r2.clone().downcast::<i32>().is_err());
1901+
1902+
let r2str = r2.downcast::<&'static str>();
1903+
assert!(r2str.is_ok());
1904+
assert_eq!(r2str.unwrap(), Arc::new("abc"));
1905+
}
18471906
}
18481907

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

Diff for: src/liballoc/rc.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -644,15 +644,9 @@ impl Rc<Any> {
644644
/// ```
645645
pub fn downcast<T: Any>(self) -> Result<Rc<T>, Rc<Any>> {
646646
if (*self).is::<T>() {
647-
// avoid the pointer arithmetic in from_raw
648-
unsafe {
649-
let raw: *const RcBox<Any> = self.ptr.as_ptr();
650-
forget(self);
651-
Ok(Rc {
652-
ptr: NonNull::new_unchecked(raw as *const RcBox<T> as *mut _),
653-
phantom: PhantomData,
654-
})
655-
}
647+
let ptr = self.ptr.cast::<RcBox<T>>();
648+
forget(self);
649+
Ok(Rc { ptr, phantom: PhantomData })
656650
} else {
657651
Err(self)
658652
}

Diff for: src/libcore/any.rs

+91-1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,13 @@ impl fmt::Debug for Any + Send {
136136
}
137137
}
138138

139+
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
140+
impl fmt::Debug for Any + Send + Sync {
141+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142+
f.pad("Any")
143+
}
144+
}
145+
139146
impl Any {
140147
/// Returns `true` if the boxed type is the same as `T`.
141148
///
@@ -301,7 +308,7 @@ impl Any+Send {
301308
/// ```
302309
/// use std::any::Any;
303310
///
304-
/// fn modify_if_u32(s: &mut (Any+ Send)) {
311+
/// fn modify_if_u32(s: &mut (Any + Send)) {
305312
/// if let Some(num) = s.downcast_mut::<u32>() {
306313
/// *num = 42;
307314
/// }
@@ -325,6 +332,89 @@ impl Any+Send {
325332
}
326333
}
327334

335+
impl Any+Send+Sync {
336+
/// Forwards to the method defined on the type `Any`.
337+
///
338+
/// # Examples
339+
///
340+
/// ```
341+
/// use std::any::Any;
342+
///
343+
/// fn is_string(s: &(Any + Send + Sync)) {
344+
/// if s.is::<String>() {
345+
/// println!("It's a string!");
346+
/// } else {
347+
/// println!("Not a string...");
348+
/// }
349+
/// }
350+
///
351+
/// fn main() {
352+
/// is_string(&0);
353+
/// is_string(&"cookie monster".to_string());
354+
/// }
355+
/// ```
356+
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
357+
#[inline]
358+
pub fn is<T: Any>(&self) -> bool {
359+
Any::is::<T>(self)
360+
}
361+
362+
/// Forwards to the method defined on the type `Any`.
363+
///
364+
/// # Examples
365+
///
366+
/// ```
367+
/// use std::any::Any;
368+
///
369+
/// fn print_if_string(s: &(Any + Send + Sync)) {
370+
/// if let Some(string) = s.downcast_ref::<String>() {
371+
/// println!("It's a string({}): '{}'", string.len(), string);
372+
/// } else {
373+
/// println!("Not a string...");
374+
/// }
375+
/// }
376+
///
377+
/// fn main() {
378+
/// print_if_string(&0);
379+
/// print_if_string(&"cookie monster".to_string());
380+
/// }
381+
/// ```
382+
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
383+
#[inline]
384+
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
385+
Any::downcast_ref::<T>(self)
386+
}
387+
388+
/// Forwards to the method defined on the type `Any`.
389+
///
390+
/// # Examples
391+
///
392+
/// ```
393+
/// use std::any::Any;
394+
///
395+
/// fn modify_if_u32(s: &mut (Any + Send + Sync)) {
396+
/// if let Some(num) = s.downcast_mut::<u32>() {
397+
/// *num = 42;
398+
/// }
399+
/// }
400+
///
401+
/// fn main() {
402+
/// let mut x = 10u32;
403+
/// let mut s = "starlord".to_string();
404+
///
405+
/// modify_if_u32(&mut x);
406+
/// modify_if_u32(&mut s);
407+
///
408+
/// assert_eq!(x, 42);
409+
/// assert_eq!(&s, "starlord");
410+
/// }
411+
/// ```
412+
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
413+
#[inline]
414+
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
415+
Any::downcast_mut::<T>(self)
416+
}
417+
}
328418

329419
///////////////////////////////////////////////////////////////////////////////
330420
// TypeID and its methods

0 commit comments

Comments
 (0)