|
86 | 86 |
|
87 | 87 | #![stable(feature = "rust1", since = "1.0.0")] |
88 | 88 |
|
89 | | -use crate::{fmt, hash, intrinsics}; |
| 89 | +use crate::{fmt, hash, intrinsics, ptr}; |
90 | 90 |
|
91 | 91 | /////////////////////////////////////////////////////////////////////////////// |
92 | 92 | // Any trait |
@@ -906,3 +906,109 @@ pub const fn type_name<T: ?Sized>() -> &'static str { |
906 | 906 | pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str { |
907 | 907 | type_name::<T>() |
908 | 908 | } |
| 909 | + |
| 910 | +/// Returns `Some(&U)` if `T` can be coerced to the trait object type `U`. Otherwise, it returns `None`. |
| 911 | +/// |
| 912 | +/// # Compile-time failures |
| 913 | +/// Determining whether `T` can be coerced to the trait object type `U` requires compiler trait resolution. |
| 914 | +/// In some cases, that resolution can exceed the recursion limit, |
| 915 | +/// and compilation will fail instead of this function returning `None`. |
| 916 | +/// # Examples |
| 917 | +/// |
| 918 | +/// ```rust |
| 919 | +/// #![feature(try_as_dyn)] |
| 920 | +/// |
| 921 | +/// use core::any::try_as_dyn; |
| 922 | +/// |
| 923 | +/// trait Animal { |
| 924 | +/// fn speak(&self) -> &'static str; |
| 925 | +/// } |
| 926 | +/// |
| 927 | +/// struct Dog; |
| 928 | +/// impl Animal for Dog { |
| 929 | +/// fn speak(&self) -> &'static str { "woof" } |
| 930 | +/// } |
| 931 | +/// |
| 932 | +/// struct Rock; // does not implement Animal |
| 933 | +/// |
| 934 | +/// let dog = Dog; |
| 935 | +/// let rock = Rock; |
| 936 | +/// |
| 937 | +/// let as_animal: Option<&dyn Animal> = try_as_dyn::<Dog, dyn Animal>(&dog); |
| 938 | +/// assert_eq!(as_animal.unwrap().speak(), "woof"); |
| 939 | +/// |
| 940 | +/// let not_an_animal: Option<&dyn Animal> = try_as_dyn::<Rock, dyn Animal>(&rock); |
| 941 | +/// assert!(not_an_animal.is_none()); |
| 942 | +/// ``` |
| 943 | +#[must_use] |
| 944 | +#[unstable(feature = "try_as_dyn", issue = "144361")] |
| 945 | +pub const fn try_as_dyn< |
| 946 | + T: Any + 'static, |
| 947 | + U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized + 'static, |
| 948 | +>( |
| 949 | + t: &T, |
| 950 | +) -> Option<&U> { |
| 951 | + let vtable: Option<ptr::DynMetadata<U>> = const { intrinsics::vtable_for::<T, U>() }; |
| 952 | + match vtable { |
| 953 | + Some(dyn_metadata) => { |
| 954 | + let pointer = ptr::from_raw_parts(t, dyn_metadata); |
| 955 | + // SAFETY: `t` is a reference to a type, so we know it is valid. |
| 956 | + // `dyn_metadata` is a vtable for T, implementing the trait of `U`. |
| 957 | + Some(unsafe { &*pointer }) |
| 958 | + } |
| 959 | + None => None, |
| 960 | + } |
| 961 | +} |
| 962 | + |
| 963 | +/// Returns `Some(&mut U)` if `T` can be coerced to the trait object type `U`. Otherwise, it returns `None`. |
| 964 | +/// |
| 965 | +/// # Compile-time failures |
| 966 | +/// Determining whether `T` can be coerced to the trait object type `U` requires compiler trait resolution. |
| 967 | +/// In some cases, that resolution can exceed the recursion limit, |
| 968 | +/// and compilation will fail instead of this function returning `None`. |
| 969 | +/// # Examples |
| 970 | +/// |
| 971 | +/// ```rust |
| 972 | +/// #![feature(try_as_dyn)] |
| 973 | +/// |
| 974 | +/// use core::any::try_as_dyn_mut; |
| 975 | +/// |
| 976 | +/// trait Animal { |
| 977 | +/// fn speak(&self) -> &'static str; |
| 978 | +/// } |
| 979 | +/// |
| 980 | +/// struct Dog; |
| 981 | +/// impl Animal for Dog { |
| 982 | +/// fn speak(&self) -> &'static str { "woof" } |
| 983 | +/// } |
| 984 | +/// |
| 985 | +/// struct Rock; // does not implement Animal |
| 986 | +/// |
| 987 | +/// let mut dog = Dog; |
| 988 | +/// let mut rock = Rock; |
| 989 | +/// |
| 990 | +/// let as_animal: Option<&mut dyn Animal> = try_as_dyn_mut::<Dog, dyn Animal>(&mut dog); |
| 991 | +/// assert_eq!(as_animal.unwrap().speak(), "woof"); |
| 992 | +/// |
| 993 | +/// let not_an_animal: Option<&mut dyn Animal> = try_as_dyn_mut::<Rock, dyn Animal>(&mut rock); |
| 994 | +/// assert!(not_an_animal.is_none()); |
| 995 | +/// ``` |
| 996 | +#[must_use] |
| 997 | +#[unstable(feature = "try_as_dyn", issue = "144361")] |
| 998 | +pub const fn try_as_dyn_mut< |
| 999 | + T: Any + 'static, |
| 1000 | + U: ptr::Pointee<Metadata = ptr::DynMetadata<U>> + ?Sized + 'static, |
| 1001 | +>( |
| 1002 | + t: &mut T, |
| 1003 | +) -> Option<&mut U> { |
| 1004 | + let vtable: Option<ptr::DynMetadata<U>> = const { intrinsics::vtable_for::<T, U>() }; |
| 1005 | + match vtable { |
| 1006 | + Some(dyn_metadata) => { |
| 1007 | + let pointer = ptr::from_raw_parts_mut(t, dyn_metadata); |
| 1008 | + // SAFETY: `t` is a reference to a type, so we know it is valid. |
| 1009 | + // `dyn_metadata` is a vtable for T, implementing the trait of `U`. |
| 1010 | + Some(unsafe { &mut *pointer }) |
| 1011 | + } |
| 1012 | + None => None, |
| 1013 | + } |
| 1014 | +} |
0 commit comments