alloc: Implement downcast Rc<Any> -> Rc<T>
Implement downcast the like it exists for Box. The implementation avoids using into_raw/from_raw, because the pointer arithmetic which should cancel does not seem to optimize out at the moment. Since Rc<T> is never Send, only Rc<Any> and not Rc<Any + Send> implements downcast.
This commit is contained in:
parent
efceda220e
commit
758a0ce934
1 changed files with 61 additions and 0 deletions
|
@ -244,6 +244,7 @@ use boxed::Box;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
|
|
||||||
|
use core::any::Any;
|
||||||
use core::borrow;
|
use core::borrow;
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
|
@ -608,6 +609,46 @@ impl<T: Clone> Rc<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Rc<Any> {
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "rc_downcast", issue = "0")]
|
||||||
|
/// Attempt to downcast the `Rc<Any>` to a concrete type.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(rc_downcast)]
|
||||||
|
/// use std::any::Any;
|
||||||
|
/// use std::rc::Rc;
|
||||||
|
///
|
||||||
|
/// fn print_if_string(value: Rc<Any>) {
|
||||||
|
/// if let Ok(string) = value.downcast::<String>() {
|
||||||
|
/// println!("String ({}): {}", string.len(), string);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let my_string = "Hello World".to_string();
|
||||||
|
/// print_if_string(Rc::new(my_string));
|
||||||
|
/// print_if_string(Rc::new(0i8));
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
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: Shared::new_unchecked(raw as *const RcBox<T> as *mut _),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: ?Sized> Rc<T> {
|
impl<T: ?Sized> Rc<T> {
|
||||||
// Allocates an `RcBox<T>` with sufficient space for an unsized value
|
// Allocates an `RcBox<T>` with sufficient space for an unsized value
|
||||||
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
|
unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> {
|
||||||
|
@ -1696,6 +1737,26 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(&r[..], [1, 2, 3]);
|
assert_eq!(&r[..], [1, 2, 3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_downcast() {
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
|
let r1: Rc<Any> = Rc::new(i32::max_value());
|
||||||
|
let r2: Rc<Any> = Rc::new("abc");
|
||||||
|
|
||||||
|
assert!(r1.clone().downcast::<u32>().is_err());
|
||||||
|
|
||||||
|
let r1i32 = r1.downcast::<i32>();
|
||||||
|
assert!(r1i32.is_ok());
|
||||||
|
assert_eq!(r1i32.unwrap(), Rc::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(), Rc::new("abc"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue