diff --git a/Cargo.lock b/Cargo.lock index 1c3e182..79000f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,6 +79,7 @@ version = "1.1.1" dependencies = [ "erasable 1.2.1", "slice-dst 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unsize", ] [[package]] @@ -104,3 +105,12 @@ dependencies = [ "autocfg", "erasable 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] + +[[package]] +name = "unsize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa7a7a734c1a5664a662ddcea0b6c9472a21da8888c957c7f1eaa09dba7a939" +dependencies = [ + "autocfg", +] diff --git a/crates/rc-box/Cargo.toml b/crates/rc-box/Cargo.toml index 7649e11..2c68d37 100644 --- a/crates/rc-box/Cargo.toml +++ b/crates/rc-box/Cargo.toml @@ -27,3 +27,10 @@ slice-dst = { version = "1.4.0", optional = true } version = "1.0.0" path = "../erasable" optional = true + +[dependencies.unsize] +version = "1.1" +optional = true + +[package.metadata.docs.rs] +all-features = true diff --git a/crates/rc-box/src/lib.rs b/crates/rc-box/src/lib.rs index b2878c6..0909f91 100644 --- a/crates/rc-box/src/lib.rs +++ b/crates/rc-box/src/lib.rs @@ -95,8 +95,6 @@ macro_rules! rc_box { // ~~~ $Rc and Box like inherent impls ~~~ // - // downcast is pretty useless without CoerceUnsized - impl $RcBox { doc_comment! { concat!("Attempt to downcast the box to a concrete type. @@ -122,7 +120,8 @@ print_if_string(my_number.try_into().unwrap()); ``` The unsizing as `", stringify!($Rc), "` is required until -[DST coercions](https://github.com/rust-lang/rust/issues/27732) are stabilized."), +[DST coercions](https://github.com/rust-lang/rust/issues/27732) are stabilized. Alternatively, +activate the `unsize` feature to convert the pointer via an explicit method call."), #[inline] pub fn downcast(self) -> Result<$RcBox, Self> where T: Any, @@ -164,7 +163,8 @@ print_if_string(my_number.try_into().unwrap()); ``` The unsizing as `", stringify!($Rc), "` is required until -[DST coercions](https://github.com/rust-lang/rust/issues/27732) are stabilized."), +[DST coercions](https://github.com/rust-lang/rust/issues/27732) are stabilized. Alternatively, +activate the `unsize` feature to convert the pointer via an explicit method call."), #[inline] pub fn downcast(self) -> Result<$RcBox, Self> where T: Any + Send @@ -206,7 +206,8 @@ print_if_string(my_number.try_into().unwrap()); ``` The unsizing as `", stringify!($Rc), "` is required until -[DST coercions](https://github.com/rust-lang/rust/issues/27732) are stabilized."), +[DST coercions](https://github.com/rust-lang/rust/issues/27732) are stabilized. Alternatively, +activate the `unsize` feature to convert the pointer via an explicit method call."), #[inline] pub fn downcast(self) -> Result<$RcBox, Self> where T: Any + Send + Sync @@ -634,6 +635,51 @@ then the data will be pinned in memory and unable to be moved."), #[cfg(feature = "std")] impl UnwindSafe for $RcBox where Box: UnwindSafe {} + + #[cfg(feature = "unsize")] + doc_comment! { + concat!("Unsizes a pointer using the `unsize` crate. + +# Usage + +``` +# use rc_box::*; +use unsize::{Coercion, CoerceUnsize}; + +let unique = ", stringify!($RcBox), "::new(|| 42u32); +let unique:", stringify!($RcBox), r" u32> = + unique.unsize(Coercion::<_, dyn Fn() -> u32>::to_fn()); + +let value = (*unique)(); +assert_eq!(value, 42); +``` + +Another common usage would be to create a `dyn Any`. + +fn print_if_string(value: ", stringify!($RcBox), r#") { + if let Ok(string) = value.downcast::() { + println!("String ({}): {}", string.len(), string); + } +} + +let my_string = "Hello World".to_string(); +let my_string: "#, stringify!($RcBox), " = ", stringify!($RcBox), "::new(my_string).unsize(Coercion::to_any()); +print_if_string(my_string); +let my_number: ", stringify!($RcBox), " = ", stringify!($RcBox), "::new(0i8).unsize(Coercion::to_any()); +print_if_string(my_number); +```"), + unsafe impl unsize::CoerciblePtr for $RcBox { + type Pointee = T; + type Output = $RcBox; + fn as_sized_ptr(&mut self) -> *mut T { + $RcBox::as_raw(self).as_ptr() + } + unsafe fn replace_ptr(self, new: *mut U) -> $RcBox { + let new = $RcBox::into_raw(self).replace_ptr(new); + $RcBox::from_raw(new.as_ptr() as *const U) + } + } + } )*}; }