[−][src]Attribute Macro vtable_macro::vtable
#[vtable]
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
MyTrait
trait with all the functions. - The
MyTraitConsts
trait 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:
- The ABI of each functions is changed to
extern "C"
unsafe
is 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_place
anddealloc
are present, then they are understood to be in-place destructors and deallocation functions.drop_in_place
must have the signaturefn(VRefMut<MyVTable> -> Layout
, anddealloc
must have the signaturefn(&MyVTable, ptr: *mut u8, layout: Layout)
.drop_in_place
is 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 ofVRc
andVWeak
. - If the first argument of the function is
VRef<MyVTable>
orVRefMut<MyVTable>
, then it is understood as a&self
or&mut self
argument 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
_mut` returns a mutable reference. as_ptr
returns a*mut u8
get_vtable
Return 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` and `extern "C"` will automatically be added make_noise: fn(VRef<AnimalVTable>, i32) -> i32, /// if there is a 'drop' member, it is considered as the destrutor 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{ strenght: 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.strenght * 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 { strenght: 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);