Minor doc fixes to the vtable crate

This commit is contained in:
Simon Hausmann 2020-08-25 16:22:07 +02:00
parent b80182ce00
commit 46911f60ee
2 changed files with 51 additions and 49 deletions

View file

@ -54,13 +54,13 @@ fn is_pin<'a>(ty: &'a Type) -> Option<&'a Type> {
} }
/** /**
This macro need to be applied to a VTable structure This macro needs to be applied to a VTable structure
The desing choice is that it is applied to a VTable and not to a trait so that cbindgen 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. can see the actual vtable struct.
This macro need to be applied to a struct whose name ends with "VTable", and which This macro needs to be applied to a struct whose name ends with "VTable", and which
contains member which are function pointers. contains members which are function pointers.
For example, if it is applied to `struct MyTraitVTable`, it will create: For example, if it is applied to `struct MyTraitVTable`, it will create:
- The `MyTrait` trait with all the functions. - The `MyTrait` trait with all the functions.
@ -70,23 +70,23 @@ For example, if it is applied to `struct MyTraitVTable`, it will create:
It will also implement the `VTableMeta` and `VTableMetaDrop` traits so that VRef and so on can work, 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. allowing to access methods from the trait directly from VRef.
This macro does the following transformation. This macro does the following transformation:
For fields whose type is a function: For function type fields:
- The ABI of each functions is changed to `extern "C"` - The ABI of each functions is changed to `extern "C"`
- `unsafe` is added to the signature of each, since it is unsafe to call these function directly from - `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 the vtable without having a valid pointer to the actual object. But if the original function was
marked unsafe, the unsafety is forwared to the trait. marked unsafe, the unsafety is forwarded to the trait.
- If a field is called `drop` it is understood that this is the destructor for a VBox - If a field is called `drop`, then it is understood that this is the destructor for a VBox.
- If the first argument of the function is `VRef<MyVTable>` or `VRefMut<MyVTable>` this is - 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. understood as a `&self` or `&mut self` argument in the trait.
- Similarily, if it is a `Pin<VRef<MyVTable>>` or `Pin<VRefMut<MyVTable>>`, self is mapped - Similarly, if it is a `Pin<VRef<MyVTable>>` or `Pin<VRefMut<MyVTable>>`, self is mapped
to `Pin<&Self>` or `Pin<&mut Self>` to `Pin<&Self>` or `Pin<&mut Self>`
For the other fields For the other fields:
- They are considered assotiated const of the MyTraitConsts - 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`, - 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 accessor to 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 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 VRef/VRefMut/VBox structure will dereference to a type which has the following associated items:

View file

@ -9,16 +9,16 @@
LICENSE END */ LICENSE END */
/*! /*!
This crate allow to create ffi-friendly virtual tables. This crate allows you to create ffi-friendly virtual tables.
## Features ## Features
- A `#[vtable]` macro to annotate a VTable struct to generate the traits and structure - A `#[vtable]` macro to annotate a VTable struct to generate the traits and structure
to safely work with it. to safely work with it.
- `VRef`/`VRefMut`/`VBox` types which are fat reference/box which wrap a pointer to - `VRef`/`VRefMut`/`VBox` types. They are fat reference/box types which wrap a pointer to
the vtable, and a pointer to the object the vtable, and a pointer to the object.
- Ability to store constant in a vtable. - Ability to store constants in a vtable.
- These constant can even be field offset - These constants can even be a field offset.
## Example of use: ## Example of use:
@ -28,13 +28,13 @@ use vtable::*;
#[vtable] #[vtable]
#[repr(C)] #[repr(C)]
struct AnimalVTable { struct AnimalVTable {
/// pointer to a function that make a noise. The `VRef<AnimalVTable>` is the type of /// pointer to a function that makes a noise. The `VRef<AnimalVTable>` is the type of
/// the self object. /// the self object.
/// ///
/// Note: the #[vtable] macro will automatically add `extern "C"` if that is missing /// Note: the #[vtable] macro will automatically add `extern "C"` if that is missing.
make_noise: fn(VRef<AnimalVTable>, i32) -> i32, make_noise: fn(VRef<AnimalVTable>, i32) -> i32,
/// if there is a 'drop' member, it is considered as the destrutor /// if there is a 'drop' member, it is considered as the destructor.
drop: fn(VRefMut<AnimalVTable>), drop: fn(VRefMut<AnimalVTable>),
} }
@ -74,11 +74,12 @@ pub use vtable_macro::*;
/// Internal trait that is implemented by the `#[vtable]` macro. /// Internal trait that is implemented by the `#[vtable]` macro.
/// ///
/// Safety: The Target object need to be implemented correctly. /// Safety: The Target object needs to be implemented correctly.
/// And there should be a VTable::VTable::new<T> funciton that returns a /// And there should be a VTable::VTable::new<T> function that returns a
/// VTable suitable for the type T /// VTable suitable for the type T.
pub unsafe trait VTableMeta { pub unsafe trait VTableMeta {
/// That's the trait object that implements the functions /// That's the trait object that implements the functions
///
/// NOTE: the size must be `2*size_of::<usize>` /// NOTE: the size must be `2*size_of::<usize>`
/// and a `repr(C)` with `(vtable, ptr)` so it has the same layout as /// and a `repr(C)` with `(vtable, ptr)` so it has the same layout as
/// the inner and VBox/VRef/VRefMut /// the inner and VBox/VRef/VRefMut
@ -90,14 +91,14 @@ pub unsafe trait VTableMeta {
/// This trait is implemented by the `#[vtable]` macro. /// This trait is implemented by the `#[vtable]` macro.
/// ///
/// It is implemented if the macro has a "drop" function /// It is implemented if the macro has a "drop" function.
pub trait VTableMetaDrop: VTableMeta { pub trait VTableMetaDrop: VTableMeta {
/// Safety: the Target need to be pointing to a valid allocated pointer /// Safety: the Target needs to be pointing to a valid allocated pointer
unsafe fn drop(ptr: *mut Self::Target); unsafe fn drop(ptr: *mut Self::Target);
fn new_box<X: HasStaticVTable<Self>>(value: X) -> VBox<Self>; fn new_box<X: HasStaticVTable<Self>>(value: X) -> VBox<Self>;
} }
/// Allow to associate a VTable to a type. /// Allow to associate a VTable with a type.
/// ///
/// Safety: the VTABLE and STATIC_VTABLE need to be a a valid virtual table /// Safety: the VTABLE and STATIC_VTABLE need to be a a valid virtual table
/// corresponding to pointer to Self instance. /// corresponding to pointer to Self instance.
@ -129,14 +130,14 @@ impl Inner {
} }
} }
/// An equivalent of a Box that holds a pointer to a VTable and a pointer to an instance /// An equivalent of a Box that holds a pointer to a VTable and a pointer to an instance.
/// which frees the instance when droped. /// A VBox frees the instance when dropped.
/// ///
/// The type parameter is supposed to be the VTable type. /// The type parameter is supposed to be the VTable type.
/// ///
/// The VBox implemtns Deref so one can access all the member of the vtable. /// The VBox implements Deref so one can access all the members of the vtable.
/// ///
/// This is only valid of the VTable has a `drop` type (so that the `#[vtable]` macro /// This is only valid if the VTable has a `drop` type (so that the `#[vtable]` macro
/// implements the `VTableMetaDrop` trait for it) /// implements the `VTableMetaDrop` trait for it)
#[repr(transparent)] #[repr(transparent)]
pub struct VBox<T: ?Sized + VTableMetaDrop> { pub struct VBox<T: ?Sized + VTableMetaDrop> {
@ -165,7 +166,7 @@ impl<T: ?Sized + VTableMetaDrop> Drop for VBox<T> {
} }
impl<T: ?Sized + VTableMetaDrop> VBox<T> { impl<T: ?Sized + VTableMetaDrop> VBox<T> {
/// Create a new VBox from an instance of a type that can be assosiated with a VTable. /// Create a new VBox from an instance of a type that can be associated with a VTable.
/// ///
/// Will move the instance on the heap. /// Will move the instance on the heap.
/// ///
@ -203,7 +204,7 @@ impl<T: ?Sized + VTableMetaDrop> VBox<T> {
/// `VRef<'a MyTraitVTable>` can be thought as a `&'a dyn MyTrait` /// `VRef<'a MyTraitVTable>` can be thought as a `&'a dyn MyTrait`
/// ///
/// It will dereference to a structure that has the same member as MyTrait /// It will dereference to a structure that has the same members as MyTrait.
#[repr(transparent)] #[repr(transparent)]
pub struct VRef<'a, T: ?Sized + VTableMeta> { pub struct VRef<'a, T: ?Sized + VTableMeta> {
inner: Inner, inner: Inner,
@ -227,7 +228,7 @@ impl<'a, T: ?Sized + VTableMeta> Deref for VRef<'a, T> {
} }
impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> { impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {
/// Create a new VRef from an reference of a type that can be assosiated with a VTable. /// Create a new VRef from an reference of a type that can be associated with a VTable.
/// ///
/// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by /// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by
/// the #[vtable] macro) /// the #[vtable] macro)
@ -241,7 +242,7 @@ impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {
} }
} }
/// Create a new Pin<VRef<_>> from a pinned reference. This is similar to `VRef::new` /// Create a new Pin<VRef<_>> from a pinned reference. This is similar to `VRef::new`.
pub fn new_pin<X: HasStaticVTable<T>>(value: core::pin::Pin<&'a X>) -> Pin<Self> { pub fn new_pin<X: HasStaticVTable<T>>(value: core::pin::Pin<&'a X>) -> Pin<Self> {
// Since Value is pinned, this means it is safe to construct a Pin // Since Value is pinned, this means it is safe to construct a Pin
unsafe { unsafe {
@ -267,7 +268,7 @@ impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {
} }
} }
/// Return to a reference of the given type if the type is actually matching /// Return a reference of the given type if the type is matching.
pub fn downcast<X: HasStaticVTable<T>>(&self) -> Option<&X> { pub fn downcast<X: HasStaticVTable<T>>(&self) -> Option<&X> {
if self.inner.vtable == X::static_vtable() as *const _ as *const u8 { if self.inner.vtable == X::static_vtable() as *const _ as *const u8 {
// Safety: We just checked that the vtable fits // Safety: We just checked that the vtable fits
@ -277,7 +278,7 @@ impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {
} }
} }
/// Return to a reference of the given type if the type is actually matching /// Return a reference of the given type if the type is matching
pub fn downcast_pin<X: HasStaticVTable<T>>(this: Pin<Self>) -> Option<Pin<&'a X>> { pub fn downcast_pin<X: HasStaticVTable<T>>(this: Pin<Self>) -> Option<Pin<&'a X>> {
let inner = unsafe { Pin::into_inner_unchecked(this).inner }; let inner = unsafe { Pin::into_inner_unchecked(this).inner };
if inner.vtable == X::static_vtable() as *const _ as *const u8 { if inner.vtable == X::static_vtable() as *const _ as *const u8 {
@ -291,7 +292,7 @@ impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {
/// `VRefMut<'a MyTraitVTable>` can be thought as a `&'a mut dyn MyTrait` /// `VRefMut<'a MyTraitVTable>` can be thought as a `&'a mut dyn MyTrait`
/// ///
/// It will dereference to a structure that has the same member as MyTrait /// It will dereference to a structure that has the same members as MyTrait.
#[repr(transparent)] #[repr(transparent)]
pub struct VRefMut<'a, T: ?Sized + VTableMeta> { pub struct VRefMut<'a, T: ?Sized + VTableMeta> {
inner: Inner, inner: Inner,
@ -312,7 +313,7 @@ impl<'a, T: ?Sized + VTableMeta> DerefMut for VRefMut<'a, T> {
} }
impl<'a, T: ?Sized + VTableMeta> VRefMut<'a, T> { impl<'a, T: ?Sized + VTableMeta> VRefMut<'a, T> {
/// Create a new VRef from a mutable reference of a type that can be assosiated with a VTable. /// Create a new VRef from a mutable reference of a type that can be associated with a VTable.
/// ///
/// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by /// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by
/// the #[vtable] macro) /// the #[vtable] macro)
@ -338,22 +339,22 @@ impl<'a, T: ?Sized + VTableMeta> VRefMut<'a, T> {
} }
} }
/// Borrow this to obtain a VRef /// Borrow this to obtain a VRef.
pub fn borrow<'b>(&'b self) -> VRef<'b, T> { pub fn borrow<'b>(&'b self) -> VRef<'b, T> {
unsafe { VRef::from_inner(self.inner) } unsafe { VRef::from_inner(self.inner) }
} }
/// Borrow this to obtain a new VRefMut /// Borrow this to obtain a new VRefMut.
pub fn borrow_mut<'b>(&'b mut self) -> VRefMut<'b, T> { pub fn borrow_mut<'b>(&'b mut self) -> VRefMut<'b, T> {
unsafe { VRefMut::from_inner(self.inner) } unsafe { VRefMut::from_inner(self.inner) }
} }
/// Create a VRef with the same lifetime as the original lifetime /// Create a VRef with the same lifetime as the original lifetime.
pub fn into_ref(self) -> VRef<'a, T> { pub fn into_ref(self) -> VRef<'a, T> {
unsafe { VRef::from_inner(self.inner) } unsafe { VRef::from_inner(self.inner) }
} }
/// Return to a reference of the given type if the type is actually matching /// Return a reference of the given type if the type is matching.
pub fn downcast<X: HasStaticVTable<T>>(&mut self) -> Option<&mut X> { pub fn downcast<X: HasStaticVTable<T>>(&mut self) -> Option<&mut X> {
if self.inner.vtable == X::static_vtable() as *const _ as *const u8 { if self.inner.vtable == X::static_vtable() as *const _ as *const u8 {
// Safety: We just checked that the vtable fits // Safety: We just checked that the vtable fits
@ -364,11 +365,12 @@ impl<'a, T: ?Sized + VTableMeta> VRefMut<'a, T> {
} }
} }
/** Create a `VRef` or a `VRefMut` suitable for an instance that implements the trait /** Creates a `VRef` or a `VRefMut` suitable for an instance that implements the trait
When possible, `VRef::new` or `VRefMut::new` should be preferred, as they use a static vtable. When possible, `VRef::new` or `VRefMut::new` should be preferred, as they use a static vtable.
But when using the generated `XxxVTable_static!` macro is not possible, this can be used. But when using the generated `XxxVTable_static!` macro that is not possible and this macro can be
Note that the `downcast` will not work with references created with this macro used instead.
Note that the `downcast` will not work with references created with this macro.
``` ```
use vtable::*; use vtable::*;
@ -438,7 +440,7 @@ macro_rules! new_vref {
}; };
} }
/// Represent an offset to a field of type mathcing the vtable, within the Base container structure. /// Represents an offset to a field of type matching the vtable, within the Base container structure.
#[repr(C)] #[repr(C)]
pub struct VOffset<Base, T: ?Sized + VTableMeta, PinFlag = NotPinned> { pub struct VOffset<Base, T: ?Sized + VTableMeta, PinFlag = NotPinned> {
vtable: &'static T::VTable, vtable: &'static T::VTable,
@ -484,7 +486,7 @@ impl<Base, T: ?Sized + VTableMeta, Flag> VOffset<Base, T, Flag> {
/// Create a new VOffset from raw data /// Create a new VOffset from raw data
/// ///
/// Safety: there must be a field that matches the vtable at offset T in base /// Safety: there must be a field that matches the vtable at offset T in base.
#[inline] #[inline]
pub unsafe fn from_raw(vtable: &'static T::VTable, offset: usize) -> Self { pub unsafe fn from_raw(vtable: &'static T::VTable, offset: usize) -> Self {
Self { vtable, offset, phantom: PhantomData } Self { vtable, offset, phantom: PhantomData }