Attribute Macro vtable::vtable[][src]

#[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 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 type fn(VRefMut<MyVTable>)
  • If two fields called drop_in_place and dealloc are present, then they are understood to be in-place destructors and deallocation functions. drop_in_place must have the signature fn(VRefMut<MyVTable> -> Layout, and dealloc must have the signature fn(&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 to dealloc, which is responsible for releasing the memory. These two functions are used to enable the use of VRc and VWeak.
  • If the first argument of the function is VRef<MyVTable> or VRefMut<MyVTable>, then it is understood as a &self or &mut self argument in the trait.
  • Similarly, if it is a Pin<VRef<MyVTable>> or Pin<VRefMut<MyVTable>>, self is mapped to Pin<&Self> or Pin<&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 be usize, and the associated const in the trait will be of type FieldOffset<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 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);