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
//! Virtual method tables.
//!
//! [`dungeon_cell`][crate] uses custom vtables to track what types are stored and
//! provide methods for those stored types.
use ::core::any::TypeId;
use std::mem::MaybeUninit;
mod coerce;
mod core;
pub use self::core::*;
pub use coerce::*;
/// Basic vtable trait.
///
/// A vtable that implements this trait can act like the vtable generated for `dyn Any`.
/// All dungeon types use this trait as the basis for their type erasure.
///
/// # Safety
/// The [`TypeId`][std::any::TypeId] value returned by [`Self::type_id()`] must be
/// for the type the vtable instance represents. The following safety requirements
/// are derived from that type.
///
/// - [`Self::type_name()`] has no safety requirements. It can return any value.
/// However, it is recommended to return a string representing the type.
///
/// - [`Self::size()`] must return the size in bytes the type takes in memory.
/// This is the value returned by [`std::mem::size_of()`] for the type.
///
/// - [`Self::alignment()`] must return the alignment in bytes the type requires.
/// This is the value returned by [`std::mem::align_of()`] for the type.
///
/// - [`Self::drop_in_place()`] must drop a value of the type in place.
/// The [`std::ptr::drop_in_place()`] function is recommended to implement this.
/// Alternatively, the implementation may forget the value (aka do nothing)
/// instead of dropping.
///
/// All methods, except [`Self::drop_in_place()`], defined by this trait must not
/// panic in any situation. [`Self::drop_in_place()`] is allowed to panic as it may
/// call user defined code.
pub unsafe trait VTable: Clone {
/// Returns the type's ID.
fn type_id(&self) -> TypeId;
/// Returns name of the type.
///
/// This should only be used for diagnostic purposes. See the
/// [`std` docs](https://doc.rust-lang.org/std/any/fn.type_name.html#note)
/// for more information.
fn type_name(&self) -> &'static str;
/// Returns type's size in bytes.
fn size(&self) -> usize;
/// Returns type's required alignment in bytes.
fn alignment(&self) -> usize;
/// Drops the value in the given aligned buffer.
///
/// # Safety
/// The given `buffer` must follow the safety requirements given in the
/// [`std` docs](https://doc.rust-lang.org/std/ptr/fn.drop_in_place.html#safety)
/// for [`std::ptr::drop_in_place()`]. Additionally, the value stored in `buffer`
/// must be a value of the type reported by [`Self::type_id()`].
unsafe fn drop_in_place(&self, buffer: *mut MaybeUninit<u8>);
}
// Automatically implement for borrows of a vtable.
// This allows for borrows to static vtable instances to be valid.
unsafe impl<T: VTable> VTable for &T {
fn type_id(&self) -> TypeId {
T::type_id(self)
}
fn type_name(&self) -> &'static str {
T::type_name(self)
}
fn size(&self) -> usize {
T::size(self)
}
fn alignment(&self) -> usize {
T::alignment(self)
}
unsafe fn drop_in_place(&self, buffer: *mut MaybeUninit<u8>) {
T::drop_in_place(self, buffer)
}
}
/// Generate vtable for type.
///
/// # Safety
/// The vtable instance [`Self::instance()`] returns must report as being for type `T`
/// when the [`VTable::type_id()`] method is called on it.
pub unsafe trait VTableOf<T>: VTable {
/// Get an instance of the vtable for the type `T`.
fn instance() -> Self;
}
/// Generate vtable for type in a const context.
///
/// # Safety
/// The vtable instance [`Self::INSTANCE`] must report as being for type `T`
/// when the [`VTable::type_id()`] method is called on it.
pub unsafe trait ConstVTableOf<T>: VTableOf<T> {
/// Instance of the vtable for the type `T`.
const INSTANCE: Self;
}