Skip to content

Commit 41da55a

Browse files
committed
Renamed "downcast_trait" to "try_as_dyn", added documentation, including recursion limit docs
1 parent e248522 commit 41da55a

File tree

6 files changed

+95
-21
lines changed

6 files changed

+95
-21
lines changed

library/core/src/any.rs

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -907,10 +907,45 @@ pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
907907
type_name::<T>()
908908
}
909909

910-
#[allow(missing_docs)]
910+
911+
/// Attempts to view `T` as a reference to the trait object `U`.
912+
///
913+
/// Returns `Some(&U)` if the type `T` implements `U`, and `None` otherwise.
914+
///
915+
/// # Compile-time failures
916+
/// Determining whether `T` implements `U` requires trait resolution by the compiler.
917+
/// In some cases, that resolution can exceed the recursion limit,
918+
/// and compilation will fail *instead of* this function returning `None`.
919+
/// # Examples
920+
///
921+
/// ```rust
922+
/// #![feature(try_as_dyn)]
923+
///
924+
/// use core::any::try_as_dyn;
925+
///
926+
/// trait Animal {
927+
/// fn speak(&self) -> &'static str;
928+
/// }
929+
///
930+
/// struct Dog;
931+
/// impl Animal for Dog {
932+
/// fn speak(&self) -> &'static str { "woof" }
933+
/// }
934+
///
935+
/// struct Rock; // does not implement Animal
936+
///
937+
/// let dog = Dog;
938+
/// let rock = Rock;
939+
///
940+
/// let as_animal: Option<&dyn Animal> = try_as_dyn::<Dog, dyn Animal>(&dog);
941+
/// assert_eq!(as_animal.unwrap().speak(), "woof");
942+
///
943+
/// let not_an_animal: Option<&dyn Animal> = try_as_dyn::<Rock, dyn Animal>(&rock);
944+
/// assert!(not_an_animal.is_none());
945+
/// ```
911946
#[must_use]
912-
#[unstable(feature = "downcast_trait", issue = "144361")]
913-
pub const fn downcast_trait<
947+
#[unstable(feature = "try_as_dyn", issue = "144361")]
948+
pub const fn try_as_dyn<
914949
T: Any + 'static,
915950
U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized + 'static,
916951
>(
@@ -928,10 +963,44 @@ pub const fn downcast_trait<
928963
}
929964
}
930965

931-
#[allow(missing_docs)]
966+
/// Attempts to view `T` as a reference to the trait object `U`.
967+
///
968+
/// Returns `Some(&mut U)` if the type `T` implements `U`, and `None` otherwise.
969+
///
970+
/// # Compile-time failures
971+
/// Determining whether `T` implements `U` requires trait resolution by the compiler.
972+
/// In some cases, that resolution can exceed the recursion limit,
973+
/// and compilation will fail *instead of* this function returning `None`.
974+
/// # Examples
975+
///
976+
/// ```rust
977+
/// #![feature(try_as_dyn)]
978+
///
979+
/// use core::any::try_as_dyn;
980+
///
981+
/// trait Animal {
982+
/// fn speak(&self) -> &'static str;
983+
/// }
984+
///
985+
/// struct Dog;
986+
/// impl Animal for Dog {
987+
/// fn speak(&self) -> &'static str { "woof" }
988+
/// }
989+
///
990+
/// struct Rock; // does not implement Animal
991+
///
992+
/// let mut dog = Dog;
993+
/// let mut rock = Rock;
994+
///
995+
/// let as_animal: Option<&mut dyn Animal> = try_as_dyn_mut::<Dog, dyn Animal>(&mut dog);
996+
/// assert_eq!(as_animal.unwrap().speak(), "woof");
997+
///
998+
/// let not_an_animal: Option<&mut dyn Animal> = try_as_dyn_mut::<Rock, dyn Animal>(&mut rock);
999+
/// assert!(not_an_animal.is_none());
1000+
/// ```
9321001
#[must_use]
933-
#[unstable(feature = "downcast_trait", issue = "144361")]
934-
pub const fn downcast_trait_mut<
1002+
#[unstable(feature = "try_as_dyn", issue = "144361")]
1003+
pub const fn try_as_dyn_mut<
9351004
T: Any + 'static,
9361005
U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized + 'static,
9371006
>(

library/core/src/intrinsics/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2757,6 +2757,11 @@ pub unsafe fn vtable_align(ptr: *const ()) -> usize;
27572757
/// FIXME: write actual docs (ivarflakstad)
27582758
/// The intrinsic will return the vtable of `t` through the lens of `U`.
27592759
///
2760+
/// # Compile-time failures
2761+
/// Determining whether `T` implements `U` requires trait resolution by the compiler.
2762+
/// In some cases, that resolution can exceed the recursion limit,
2763+
/// and compilation will fail *instead of* this function returning `None`.
2764+
///
27602765
/// # Safety
27612766
///
27622767
/// `ptr` must point to a vtable.
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//@ run-pass
2-
#![feature(downcast_trait)]
2+
#![feature(try_as_dyn)]
33

44
use std::fmt::Debug;
55

66
// Look ma, no `T: Debug`
7-
fn downcast_debug_format<T: 'static>(t: &T) -> String {
8-
match std::any::downcast_trait::<_, dyn Debug>(t) {
7+
fn debug_format_with_try_as_dyn<T: 'static>(t: &T) -> String {
8+
match std::any::try_as_dyn::<_, dyn Debug>(t) {
99
Some(d) => format!("{d:?}"),
1010
None => "default".to_string()
1111
}
@@ -19,11 +19,11 @@ fn main() {
1919
index: usize
2020
}
2121
let a = A { index: 42 };
22-
let result = downcast_debug_format(&a);
22+
let result = debug_format_with_try_as_dyn(&a);
2323
assert_eq!("A { index: 42 }", result);
2424

2525
struct B {}
2626
let b = B {};
27-
let result = downcast_debug_format(&b);
27+
let result = debug_format_with_try_as_dyn(&b);
2828
assert_eq!("default", result);
2929
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@ run-pass
2-
#![feature(downcast_trait)]
2+
#![feature(try_as_dyn)]
33

4-
use std::{any::downcast_trait, sync::OnceLock};
4+
use std::{any::try_as_dyn, sync::OnceLock};
55

66
trait Trait {
77
fn call(&self, x: &Box<i32>);
@@ -22,7 +22,7 @@ fn store(x: &'static Box<i32>) {
2222
fn main() {
2323
let data = Box::new(Box::new(1i32));
2424
let fn_ptr: fn(&'static Box<i32>) = store;
25-
let dt = downcast_trait::<_, dyn Trait>(&fn_ptr);
25+
let dt = try_as_dyn::<_, dyn Trait>(&fn_ptr);
2626
if let Some(dt) = dt {
2727
// unsound path
2828
dt.call(&*data);
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//@ run-pass
2-
#![feature(downcast_trait)]
3-
use std::{any::downcast_trait, sync::OnceLock};
2+
#![feature(try_as_dyn)]
3+
use std::{any::try_as_dyn, sync::OnceLock};
44

55
trait Trait<T> {
66
fn call(&self, t: T, x: &Box<i32>);
@@ -20,7 +20,7 @@ fn store(x: &'static Box<i32>) {
2020

2121
fn main() {
2222
let data = Box::new(Box::new(1i32));
23-
let dt = downcast_trait::<_, dyn Trait<fn(&'static Box<i32>)>>(&());
23+
let dt = try_as_dyn::<_, dyn Trait<fn(&'static Box<i32>)>>(&());
2424
if let Some(dt) = dt {
2525
// unsound path
2626
dt.call(store, &*data);
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//@ run-pass
2-
#![feature(downcast_trait)]
2+
#![feature(try_as_dyn)]
33

44
use std::fmt::{Error, Write};
55

66
// Look ma, no `T: Write`
7-
fn downcast_mut_write<T: 'static>(t: &mut T, s: &str) -> Result<(), Error> {
8-
match std::any::downcast_trait_mut::<_, dyn Write>(t) {
7+
fn try_as_dyn_mut_write<T: 'static>(t: &mut T, s: &str) -> Result<(), Error> {
8+
match std::any::try_as_dyn_mut::<_, dyn Write>(t) {
99
Some(w) => w.write_str(s),
1010
None => Ok(())
1111
}
@@ -15,6 +15,6 @@ fn downcast_mut_write<T: 'static>(t: &mut T, s: &str) -> Result<(), Error> {
1515
fn main() {
1616
let mut buf = "Hello".to_string();
1717

18-
downcast_mut_write(&mut buf, " world!").unwrap();
18+
try_as_dyn_mut_write(&mut buf, " world!").unwrap();
1919
assert_eq!(buf, "Hello world!");
2020
}

0 commit comments

Comments
 (0)