Expand description
Defines an ABI safe interface for trait objects, by emulating the vtable and fat pointer
ABI Safe Trait Objects
This module provides the low and mid-level api for ABI-Safe Trait objects
Most user code will interact with the DynRef
, DynMut
, and DynBox
types.
The rest of the api is to support those types and the #[abi_safe]
attribute defined by the xlang_abi_macro
crate
Defining an ABI Safe Trait
Any trait can be defined as ABI Safe if it meets the following requirements:
- The trait must be Object Safe
- All trait methods that are not bound by Self: Sized must have an abi-safe receiver (Either &Self, &mut Self, Box
, or Pin where P is one of the preceeding types)
- Every trait method not bound by Self: Sized must be declared with an explicit abi, which should not be extern“Rust“, extern“rust-call“, or extern“rust-intrinsic“
- Every trait method bound by Self: Sized must have a default impl (this is required as the
#[abi_safe]
macro produces code that implements the trait, and can’t implement Self: Sized methods) - Unsafe traits may have additional requirements on the Preconditions of implementors, as the macro produces implementations of the trait that forward to the vtable
Every trait that satisfies the above requirements can use the #[abi_safe]
attribute macro to be used with ABI-Safe Trait Object types defined by this library
Example
#[abi_safe]
pub trait Foo{
fn bar(&self);
fn baz(&mut self);
}
Using an ABI Safe Trait
Abi safe traits can be used with the DynRef
, DynMut
, DynBox
, and DynPtr
types in this module,
by calling the unsize_*
methods of those types on concrete pointers/references to types implementing the trait (note, this does not work if you have already unsize the type to a language trait object, like &dyn Foo
).
You can then use these types with the methods of the trait
Manually Implementing AbiSafeTrait
While it is recommend to use the attribute to implement the various AbiSafe
traits, it is possible to implement them manually.
All of these traits are unsafe and impose numerous preconditions on implmenetors, any of which will result in very unsound code if violated.
That being said, if you accept the Nasal Demons you are invoking, it can be fairly simple, and, in some cases, advantageous to implement the traits manually.
For example, manual implementations can use additional recievers (usually combined with the arbitrary_self_types
feature) or to provide custom implementations of
some trait methods for abi-safe trait objects (for example, if the trait is unsafe, and forwarding to the vtable would violate the safety invariant).
Manual implementations can also provide custom vtables, including for types that don’t implement the trait, allowing special types to be unsized into references.
Before attempting this, you must ensure the trait in use is object safe, and it is recommended that each method have an explicit abi other than extern“Rust“, extern“rust-call“, or extern“rust-intrinsic“.
Vtables
The first requirement is to create a trait’s abi safe VTable
. This must be a #[repr(C)]
type,
and the first four (non 1-ZST) members must be the members of the AbiSafeVTableHead
type (size, alignment, destructor, reserved dellocation function)
The remainder of the members should typically be the virtual functions of the trait (the methods not bound on Self: Sized). Each member should be public
Structs
VTable
produced by this module, containing fields common to the vtables of all traitsBox
to a trait object.Traits
T
when using #[xlang_abi::abi_safe_trait]
VTables
forVTable<T>
defined by the LCRust v0 ABI