devela/code/any/ext.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
// devela::code::any::ext
//
//!
//
// - WAIT: (const) [type_name](https://github.com/rust-lang/rust/issues/63084)
// - WAIT: [trait_upcasting](https://github.com/rust-lang/rust/issues/65991)
use core::any::{type_name_of_val, Any, TypeId};
#[cfg(feature = "alloc")]
use crate::Box;
/// Marker trait to prevent downstream implementations of the [`ExtAny`] trait.
trait Sealed {}
impl<T: ?Sized + Any> Sealed for T {}
impl<T: ?Sized + Any> ExtAny for T {}
/// Extension trait providing convenience methods for `T:`[`Any`].
///
/// This trait is sealed and cannot be implemented manually.
#[rustfmt::skip]
#[expect(private_bounds, reason = "Sealed")]
pub trait ExtAny: Any + Sealed {
/* type */
/// Returns the `TypeId` of `Self`.
///
/// # Example
/// ```
/// use devela::ExtAny;
///
/// let x = 5;
/// assert_eq!(x.type_of(), i32::type_id());
/// ```
#[must_use]
fn type_id() -> TypeId { TypeId::of::<Self>() }
/// Returns the `TypeId` of `self`.
///
/// # Example
/// ```
/// use devela::ExtAny;
///
/// let x = 5;
/// assert_eq!(x.type_of(), i32::type_id());
/// ```
#[must_use]
fn type_of(&self) -> TypeId { TypeId::of::<Self>() }
/// Returns the type name of `self`.
///
/// # Example
/// ```
/// use devela::code::ExtAny;
///
/// let x = 5;
/// assert_eq!(x.type_name(), "i32");
/// ```
#[must_use]
fn type_name(&self) -> &'static str { type_name_of_val(self) }
/// Returns `true` if `Self` is of type `T`.
///
/// # Example
/// ```
/// use devela::ExtAny;
///
/// let val = 5;
/// assert!(val.type_is::<i32>());
/// assert!(!val.type_is::<u32>());
///
/// // Compared to Any::is():
/// let any = val.as_any_ref();
/// // assert!(any.type_is::<i32>()); // doesn't work for &dyn Any
/// // assert!(val.is::<i32>()); // doesn't work for T: Any
/// assert!(any.is::<i32>()); // does work for &dyn Any
/// ```
#[must_use]
fn type_is<T: 'static>(&self) -> bool { self.type_id() == TypeId::of::<T>() }
/* upcasts */
/// Upcasts `&self` as `&dyn Any`.
///
/// # Example
/// ```
/// use devela::{Any, ExtAny};
///
/// let val = 5;
/// let any: &dyn Any = &val as &dyn Any;
/// assert!(any.is::<i32>()); // works direcly for dyn Any
/// ```
#[must_use]
fn as_any_ref(&self) -> &dyn Any where Self: Sized { self }
/// Upcasts `&mut self` as `&mut dyn Any`.
///
/// # Example
/// ```
/// use devela::{Any, ExtAny};
///
/// let mut x = 5;
/// let any: &mut dyn Any = x.as_any_mut();
/// assert!(any.is::<i32>());
/// ```
#[must_use]
fn as_any_mut(&mut self) -> &mut dyn Any where Self: Sized { self }
/// Upcasts `Box<self>` as `Box<dyn Any>`.
///
/// # Example
/// ```
/// use devela::{Any, ExtAny};
///
/// let x = Box::new(5);
/// let any: Box<dyn Any> = x.as_any_box();
/// assert!(any.is::<i32>());
/// ```
#[must_use]
#[cfg(feature = "alloc")]
fn as_any_box(self: Box<Self>) -> Box<dyn Any> where Self: Sized { self }
/* downcasts */
/// Returns some shared reference to the inner value if it is of type `T`.
///
/// This method is only needed when not dealing directly with `dyn Any` trait objects,
/// since it's [already implemented for `dyn Any`](Any#method.downcast_ref).
///
/// # Example
/// ```
/// use core::fmt::Display;
/// use devela::{Any, ExtAny};
///
/// trait Trait: Any + Display {}
/// impl Trait for i32 {}
/// impl Trait for char {}
/// impl Trait for bool {}
///
/// # #[cfg(feature = "alloc")]
/// // in the heap:
/// {
/// # use devela::{Box, Vec};
/// let b: Box<dyn Trait> = Box::new(5);
/// if let Some(n) = (*b).downcast_ref::<i32>() {
/// assert_eq![n, &5_i32];
/// }
///
/// let bb: Vec<Box<dyn Trait>> = vec![Box::new(true), Box::new(6), Box::new('c')];
/// for b in bb {
/// if let Some(n) = (*b).downcast_ref::<i32>() {
/// assert_eq![n, &6_i32];
/// }
/// }
/// }
/// // in the stack:
/// # #[cfg_attr(not(feature = "__force_miri_dst"), cfg(not(miri)))] // FIX
/// {
/// use devela::{Any, DstArray, DstStack, DstValue, ExtAny};
/// let v = DstValue::<dyn Trait, DstArray<usize, 2>>::new(7, |v| v as _).unwrap();
/// if let Some(n) = (*v).downcast_ref::<i32>() {
/// assert_eq![n, &7_i32];
/// }
///
/// let mut vv = DstStack::<dyn Trait, DstArray<u32, 12>>::new();
/// vv.push(true, |v| v).unwrap();
/// vv.push(8_i32, |v| v).unwrap();
/// vv.push('c', |v| v).unwrap();
/// for v in vv.iter() {
/// if let Some(n) = (*v).downcast_ref::<i32>() {
/// assert_eq![n, &8_i32];
/// }
/// }
/// }
/// ```
#[must_use]
#[cfg(feature = "unsafe_layout")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "unsafe_layout")))]
fn downcast_ref<T: 'static>(&self) -> Option<&T> {
// SAFETY: We verify T is of the right type before downcasting
unsafe { (*self).type_is::<T>().then(|| &*<*const _>::cast(self)) }
}
/// Returns some exclusive reference to the inner value if it is of type `T`.
///
/// This method is only needed when not dealing directly with `dyn Any` trait objects,
/// since it's [already implemented for `dyn Any`][Any#method.downcast_mut].
#[must_use]
#[cfg(feature = "unsafe_layout")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "unsafe_layout")))]
fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
// SAFETY: We verify T is of the right type before downcasting
unsafe { (*self).type_is::<T>().then(|| &mut *<*mut _>::cast(self)) }
}
}