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.
This commit is contained in:
commit
b7a9d4ea74
@ -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,44 @@ 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>() {
|
||||
let ptr = self.ptr.cast::<ArcInner<T>>();
|
||||
mem::forget(self);
|
||||
Ok(Arc { ptr, 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 +1883,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")]
|
||||
|
@ -644,15 +644,9 @@ impl Rc<Any> {
|
||||
/// ```
|
||||
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: NonNull::new_unchecked(raw as *const RcBox<T> as *mut _),
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
let ptr = self.ptr.cast::<RcBox<T>>();
|
||||
forget(self);
|
||||
Ok(Rc { ptr, phantom: PhantomData })
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
|
@ -136,6 +136,13 @@ impl fmt::Debug for Any + Send {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
|
||||
impl fmt::Debug for Any + Send + Sync {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.pad("Any")
|
||||
}
|
||||
}
|
||||
|
||||
impl Any {
|
||||
/// Returns `true` if the boxed type is the same as `T`.
|
||||
///
|
||||
@ -301,7 +308,7 @@ impl Any+Send {
|
||||
/// ```
|
||||
/// use std::any::Any;
|
||||
///
|
||||
/// fn modify_if_u32(s: &mut (Any+ Send)) {
|
||||
/// fn modify_if_u32(s: &mut (Any + Send)) {
|
||||
/// if let Some(num) = s.downcast_mut::<u32>() {
|
||||
/// *num = 42;
|
||||
/// }
|
||||
@ -325,6 +332,89 @@ impl Any+Send {
|
||||
}
|
||||
}
|
||||
|
||||
impl Any+Send+Sync {
|
||||
/// Forwards to the method defined on the type `Any`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::any::Any;
|
||||
///
|
||||
/// fn is_string(s: &(Any + Send + Sync)) {
|
||||
/// if s.is::<String>() {
|
||||
/// println!("It's a string!");
|
||||
/// } else {
|
||||
/// println!("Not a string...");
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// is_string(&0);
|
||||
/// is_string(&"cookie monster".to_string());
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub fn is<T: Any>(&self) -> bool {
|
||||
Any::is::<T>(self)
|
||||
}
|
||||
|
||||
/// Forwards to the method defined on the type `Any`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::any::Any;
|
||||
///
|
||||
/// fn print_if_string(s: &(Any + Send + Sync)) {
|
||||
/// if let Some(string) = s.downcast_ref::<String>() {
|
||||
/// println!("It's a string({}): '{}'", string.len(), string);
|
||||
/// } else {
|
||||
/// println!("Not a string...");
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// print_if_string(&0);
|
||||
/// print_if_string(&"cookie monster".to_string());
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
|
||||
Any::downcast_ref::<T>(self)
|
||||
}
|
||||
|
||||
/// Forwards to the method defined on the type `Any`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::any::Any;
|
||||
///
|
||||
/// fn modify_if_u32(s: &mut (Any + Send + Sync)) {
|
||||
/// if let Some(num) = s.downcast_mut::<u32>() {
|
||||
/// *num = 42;
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let mut x = 10u32;
|
||||
/// let mut s = "starlord".to_string();
|
||||
///
|
||||
/// modify_if_u32(&mut x);
|
||||
/// modify_if_u32(&mut s);
|
||||
///
|
||||
/// assert_eq!(x, 42);
|
||||
/// assert_eq!(&s, "starlord");
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "any_send_sync_methods", since = "1.28.0")]
|
||||
#[inline]
|
||||
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
|
||||
Any::downcast_mut::<T>(self)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TypeID and its methods
|
||||
|
Loading…
Reference in New Issue
Block a user