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
//! Code is based on <https://github.com/chris-morgan/mopa>
//! with the macro inlined for `Resource`. License files can be found in the
//! directory of this source file, see COPYRIGHT, LICENSE-APACHE and
//! LICENSE-MIT.
#[cfg(test)]
mod tests;
use std::any::TypeId;
use crate::Resource;
impl dyn Resource {
/// Returns the boxed value if it is of type `T`, or `Err(Self)` if it
/// isn't.
#[inline]
pub fn downcast<T: Resource>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
if self.is::<T>() {
// SAFETY: We just checked that the type is `T`.
unsafe { Ok(self.downcast_unchecked()) }
} else {
Err(self)
}
}
/// Returns the boxed value, blindly assuming it to be of type `T`.
///
/// # Safety
///
/// If you are not *absolutely certain* of `T`, you *must not* call this.
/// Using anything other than the correct type `T` for this `Resource`
/// will result in UB.
#[inline]
pub unsafe fn downcast_unchecked<T: Resource>(self: Box<Self>) -> Box<T> {
// SAFETY: Caller promises the concrete type is `T`.
unsafe { Box::from_raw(Box::into_raw(self) as *mut T) }
}
/// Returns true if the boxed type is the same as `T`
#[inline]
pub fn is<T: Resource>(&self) -> bool {
TypeId::of::<T>() == self.type_id()
}
/// Returns some reference to the boxed value if it is of type `T`, or
/// `None` if it isn't.
#[inline]
pub fn downcast_ref<T: Resource>(&self) -> Option<&T> {
if self.is::<T>() {
// SAFETY: We just checked that the type is `T`.
unsafe { Some(self.downcast_ref_unchecked()) }
} else {
Option::None
}
}
/// Returns a reference to the boxed value, blindly assuming it to be of
/// type `T`.
///
/// # Safety
///
/// If you are not *absolutely certain* of `T`, you *must not* call this.
/// Using anything other than the correct type `T` for this `Resource`
/// will result in UB.
#[inline]
pub unsafe fn downcast_ref_unchecked<T: Resource>(&self) -> &T {
// SAFETY: Caller promises the concrete type is `T`.
unsafe { &*(self as *const Self as *const T) }
}
/// Returns some mutable reference to the boxed value if it is of type `T`,
/// or `None` if it isn't.
#[inline]
pub fn downcast_mut<T: Resource>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
// SAFETY: We just checked that the type is `T`.
unsafe { Some(self.downcast_mut_unchecked()) }
} else {
Option::None
}
}
/// Returns a mutable reference to the boxed value, blindly assuming it to
/// be of type `T`.
///
/// # Safety
///
/// If you are not *absolutely certain* of `T`, you *must not* call this.
/// Using anything other than the correct type `T` for this `Resource`
/// will result in UB.
#[inline]
pub unsafe fn downcast_mut_unchecked<T: Resource>(&mut self) -> &mut T {
// SAFETY: Caller promises the concrete type is `T`.
unsafe { &mut *(self as *mut Self as *mut T) }
}
}