#[vtable]Expand description
This macro needs to be applied to a VTable structure
The design choice is that it is applied to a VTable and not to a trait so that cbindgen can see the actual vtable struct.
This macro needs to be applied to a struct whose name ends with “VTable”, and which contains members which are function pointers.
For example, if it is applied to struct MyTraitVTable, it will create:
- The
MyTraittrait with all the functions. - The
MyTraitConststrait for the associated constants, if any MyTraitVTable_static!macro.
It will also implement the VTableMeta and VTableMetaDrop traits so that VRef and so on can work,
allowing to access methods from the trait directly from VRef.
This macro does the following transformation:
For function type fields:
unsafeis added to the signature, since it is unsafe to call these functions directly from the vtable without having a valid pointer to the actual object. But if the original function was marked unsafe, the unsafety is forwarded to the trait.- If a field is called
drop, then it is understood that this is the destructor for a VBox. It must have the typefn(VRefMut<MyVTable>) - If two fields called
drop_in_placeanddeallocare present, then they are understood to be in-place destructors and deallocation functions.drop_in_placemust have the signaturefn(VRefMut<MyVTable> -> Layout, anddeallocmust have the signaturefn(&MyVTable, ptr: *mut u8, layout: Layout).drop_in_placeis responsible for destructing the object and returning the memory layout that was used for the initial allocation. It will be passed todealloc, which is responsible for releasing the memory. These two functions are used to enable the use ofVRcandVWeak. - If the first argument of the function is
VRef<MyVTable>orVRefMut<MyVTable>, then it is understood as a&selfor&mut selfargument in the trait. - Similarly, if it is a
Pin<VRef<MyVTable>>orPin<VRefMut<MyVTable>>, self is mapped toPin<&Self>orPin<&mut Self>
For the other fields:
- They are considered associated constants of the MyTraitConsts trait.
- If they are annotated with the
#[field_offset(FieldType)]attribute, the type of the field must beusize, and the associated const in the trait will be of typeFieldOffset<Self, FieldType>, and an accessor to the field reference and reference mut will be added to the Target of VRef and VRefMut.
The VRef/VRefMut/VBox structure will dereference to a type which has the following associated items:
- The functions from the vtable that have a VRef or VRefMut first parameter for self.
- For each
#[field_offset]attributes, a corresponding getter returns a reference to that field, and mutable accessor that ends with_mutreturns a mutable reference. as_ptrreturns a*mut u8get_vtableReturn a reference to the VTable so one can access the associated consts.
The VTable struct gets a new associated function that creates a vtable for any type
that implements the generated traits.
§Example
use vtable::*;
// we are going to declare a VTable structure for an Animal trait
#[vtable]
#[repr(C)]
struct AnimalVTable {
/// Pointer to a function that make noise.
/// `unsafe` will automatically be added
make_noise: fn(VRef<AnimalVTable>, i32) -> i32,
/// if there is a 'drop' member, it is considered as the destructor
drop: fn(VRefMut<AnimalVTable>),
/// Associated constant.
LEG_NUMBER: i8,
/// There exist a `bool` field in the structure and this is an offset
#[field_offset(bool)]
IS_HUNGRY: usize,
}
#[repr(C)]
struct Dog{ strength: i32, is_hungry: bool };
// The #[vtable] macro created the Animal Trait
impl Animal for Dog {
fn make_noise(&self, intensity: i32) -> i32 {
println!("Wof!");
return self.strength * intensity;
}
}
// The #[vtable] macro created the AnimalConsts Trait
impl AnimalConsts for Dog {
const LEG_NUMBER: i8 = 4;
const IS_HUNGRY: vtable::FieldOffset<Self, bool> = unsafe { vtable::FieldOffset::new_from_offset(4) };
}
// The #[vtable] macro also exposed a macro to create a vtable
AnimalVTable_static!(static DOG_VT for Dog);
// with that, it is possible to instantiate a vtable::VRefMut
let mut dog = Dog { strength: 100, is_hungry: false };
{
let mut animal_vref = VRefMut::<AnimalVTable>::new(&mut dog);
// access to the vtable through the get_vtable() function
assert_eq!(animal_vref.get_vtable().LEG_NUMBER, 4);
// functions are also added for the #[field_offset] member
assert_eq!(*animal_vref.IS_HUNGRY(), false);
*animal_vref.IS_HUNGRY_mut() = true;
}
assert_eq!(dog.is_hungry, true);