Skip to content

Commit 0a204fe

Browse files
committed
Renamed "downcast_trait" to "try_as_dyn", added documentation, including recursion limit docs
1 parent c38ca5b commit 0a204fe

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
@@ -897,10 +897,45 @@ pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
897897
type_name::<T>()
898898
}
899899

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

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

library/core/src/intrinsics/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2660,6 +2660,11 @@ pub unsafe fn vtable_align(ptr: *const ()) -> usize;
26602660
/// FIXME: write actual docs (ivarflakstad)
26612661
/// The intrinsic will return the vtable of `t` through the lens of `U`.
26622662
///
2663+
/// # Compile-time failures
2664+
/// Determining whether `T` implements `U` requires trait resolution by the compiler.
2665+
/// In some cases, that resolution can exceed the recursion limit,
2666+
/// and compilation will fail *instead of* this function returning `None`.
2667+
///
26632668
/// # Safety
26642669
///
26652670
/// `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)