mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 22:54:36 +00:00
Add documentation for the vtable crate
This commit is contained in:
parent
33dd2d765d
commit
bf3a0878b5
2 changed files with 160 additions and 5 deletions
|
@ -1,9 +1,69 @@
|
|||
/*!
|
||||
This crate allow to create ffi-friendly virtual tables.
|
||||
|
||||
## Features
|
||||
|
||||
- A `#[vtable]` macro to annotate a VTable struct to generate the traits and structure
|
||||
to safely work with it.
|
||||
- `VRef`/`VRefMut`/`VBox` types which are fat reference/box which wrap a pointer to
|
||||
the vtable, and a pointer to the object
|
||||
- Ability to store constant in a vtable.
|
||||
- These constant can even be field offset
|
||||
|
||||
## Example of use:
|
||||
|
||||
```
|
||||
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 a noise. The `VRef<AnimalVTable>` is the type of
|
||||
/// the self object.
|
||||
///
|
||||
/// Note: the #[vtable] macro will automatically add `extern "C"` if that is missing
|
||||
make_noise: fn(VRef<AnimalVTable>, i32) -> i32,
|
||||
|
||||
/// if there is a 'drop' member, it is considered as the destrutor
|
||||
drop: fn(VRefMut<AnimalVTable>),
|
||||
}
|
||||
|
||||
struct Dog(i32);
|
||||
|
||||
// The #[vtable] macro created the Animal Trait
|
||||
impl Animal for Dog {
|
||||
fn make_noise(&self, intensity: i32) -> i32 {
|
||||
println!("Wof!");
|
||||
return self.0 * intensity;
|
||||
}
|
||||
}
|
||||
|
||||
// the vtable macro also exposed a macro to create a vtable
|
||||
AnimalVTable_static!(Dog);
|
||||
|
||||
// with that, it is possible to instentiate a VBox
|
||||
let animal_box = VBox::<AnimalVTable>::new(Dog(42));
|
||||
assert_eq!(animal_box.make_noise(2), 42 * 2);
|
||||
```
|
||||
|
||||
The `#[vtable]` macro created the "Animal" trait.
|
||||
|
||||
Note that the `#[vtable]` macro is applied to the VTable struct so
|
||||
that `cbindgen` can see the actual vtable.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
pub use const_field_offset::FieldOffset;
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Deref, DerefMut, Drop};
|
||||
use core::ptr::NonNull;
|
||||
#[doc(inline)]
|
||||
pub use vtable_macro::*;
|
||||
|
||||
/// Internal trait that is implemented by the `#[vtable]` macro.
|
||||
///
|
||||
/// Safety: The Target object need to be implemented correctly.
|
||||
pub unsafe trait VTableMeta {
|
||||
/// That's the trait object that implements the functions
|
||||
/// NOTE: the size must be 2*size_of::<usize>
|
||||
|
@ -15,6 +75,9 @@ pub unsafe trait VTableMeta {
|
|||
type VTable: 'static;
|
||||
}
|
||||
|
||||
/// This trait is implemented by the `#[vtable]` macro.
|
||||
///
|
||||
/// It is implemented if the macro has a "drop" function
|
||||
pub trait VTableMetaDrop: VTableMeta {
|
||||
/// Safety: the Target need to be pointing to a valid allocated pointer
|
||||
unsafe fn drop(ptr: *mut Self::Target);
|
||||
|
@ -22,12 +85,16 @@ pub trait VTableMetaDrop: VTableMeta {
|
|||
}
|
||||
|
||||
/// Allow to associate a VTable to a type.
|
||||
///
|
||||
/// Safety: the VTABLE and STATIC_VTABLE need to be a a valid virtual table
|
||||
/// corresponding to pointer to Self instance.
|
||||
pub unsafe trait HasStaticVTable<VT>
|
||||
where
|
||||
VT: ?Sized + VTableMeta,
|
||||
{
|
||||
/// Savety: must be a valid VTable for Self
|
||||
/// Safety: must be a valid VTable for Self
|
||||
const VTABLE: VT::VTable;
|
||||
/// Reference to Self::VTABLE
|
||||
const STATIC_VTABLE: &'static VT::VTable;
|
||||
}
|
||||
|
||||
|
@ -51,6 +118,15 @@ impl Inner {
|
|||
}
|
||||
}
|
||||
|
||||
/// An equivalent of a Box that holds a pointer to a VTable and a pointer to an instance
|
||||
/// which frees the instance when droped.
|
||||
///
|
||||
/// The type parameter is supposed to be the VTable type.
|
||||
///
|
||||
/// The VBox implemtns Deref so one can access all the member of the vtable.
|
||||
///
|
||||
/// This is only valid of the VTable has a `drop` type (so that the `#[vtable]` macro
|
||||
/// implements the `VTableMetaDrop` trait for it)
|
||||
#[repr(transparent)]
|
||||
pub struct VBox<T: ?Sized + VTableMetaDrop> {
|
||||
inner: Inner,
|
||||
|
@ -78,24 +154,38 @@ impl<T: ?Sized + VTableMetaDrop> Drop for 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.
|
||||
///
|
||||
/// Will move the instance on the heap.
|
||||
///
|
||||
/// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by
|
||||
/// the #[vtable] macro)
|
||||
pub fn new<X: HasStaticVTable<T>>(value: X) -> Self {
|
||||
T::new_box(value)
|
||||
}
|
||||
|
||||
/// Safety: the `ptr` needs to be a valid for the `vtable`, and properly allocated so it can be dropped
|
||||
pub unsafe fn from_raw(vtable: NonNull<T::VTable>, ptr: NonNull<u8>) -> Self {
|
||||
Self {
|
||||
inner: Inner { vtable: vtable.cast().as_ptr(), ptr: ptr.cast().as_ptr() },
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a VRef pointing to this box
|
||||
pub fn borrow<'b>(&'b self) -> VRef<'b, T> {
|
||||
unsafe { VRef::from_inner(self.inner) }
|
||||
}
|
||||
|
||||
/// Gets a VRefMut pointing to this box
|
||||
pub fn borrow_mut<'b>(&'b mut self) -> VRefMut<'b, T> {
|
||||
unsafe { VRefMut::from_inner(self.inner) }
|
||||
}
|
||||
}
|
||||
|
||||
/// `VRef<'a MyTraitVTable>` can be thought as a `&'a dyn MyTrait`
|
||||
///
|
||||
/// It will dereference to a structure that has the same member as MyTrait
|
||||
#[repr(transparent)]
|
||||
pub struct VRef<'a, T: ?Sized + VTableMeta> {
|
||||
inner: Inner,
|
||||
|
@ -119,6 +209,10 @@ impl<'a, T: ?Sized + VTableMeta> Deref for 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.
|
||||
///
|
||||
/// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by
|
||||
/// the #[vtable] macro)
|
||||
pub fn new<X: HasStaticVTable<T>>(value: &'a X) -> Self {
|
||||
Self {
|
||||
inner: Inner {
|
||||
|
@ -132,6 +226,8 @@ impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {
|
|||
unsafe fn from_inner(inner: Inner) -> Self {
|
||||
Self { inner, phantom: PhantomData }
|
||||
}
|
||||
|
||||
/// Safety: the `ptr` needs to be a valid for the `vtable`, and properly allocated so it can be dropped
|
||||
pub unsafe fn from_raw(vtable: NonNull<T::VTable>, ptr: NonNull<u8>) -> Self {
|
||||
Self {
|
||||
inner: Inner { vtable: vtable.cast().as_ptr(), ptr: ptr.cast().as_ptr() },
|
||||
|
@ -140,6 +236,9 @@ impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// `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
|
||||
#[repr(transparent)]
|
||||
pub struct VRefMut<'a, T: ?Sized + VTableMeta> {
|
||||
inner: Inner,
|
||||
|
@ -160,6 +259,10 @@ impl<'a, T: ?Sized + VTableMeta> DerefMut for 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.
|
||||
///
|
||||
/// (the `HasStaticVTable` is implemented by the `“MyTrait”VTable_static!` macro generated by
|
||||
/// the #[vtable] macro)
|
||||
pub fn new<X: HasStaticVTable<T>>(value: &'a mut X) -> Self {
|
||||
Self {
|
||||
inner: Inner {
|
||||
|
@ -173,18 +276,26 @@ impl<'a, T: ?Sized + VTableMeta> VRefMut<'a, T> {
|
|||
unsafe fn from_inner(inner: Inner) -> Self {
|
||||
Self { inner, phantom: PhantomData }
|
||||
}
|
||||
|
||||
/// Safety: the `ptr` needs to be a valid for the `vtable`, and properly allocated so it can be dropped
|
||||
pub unsafe fn from_raw(vtable: NonNull<T::VTable>, ptr: NonNull<u8>) -> Self {
|
||||
Self {
|
||||
inner: Inner { vtable: vtable.cast().as_ptr(), ptr: ptr.cast().as_ptr() },
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrow this to obtain a VRef
|
||||
pub fn borrow<'b>(&'b self) -> VRef<'b, T> {
|
||||
unsafe { VRef::from_inner(self.inner) }
|
||||
}
|
||||
|
||||
/// Borrow this to obtain a new VRefMut
|
||||
pub fn borrow_mut<'b>(&'b mut self) -> VRefMut<'b, T> {
|
||||
unsafe { VRefMut::from_inner(self.inner) }
|
||||
}
|
||||
|
||||
/// Create a VRef with the same lifetime as the original lifetime
|
||||
pub fn into_ref(self) -> VRef<'a, T> {
|
||||
unsafe { VRef::from_inner(self.inner) }
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue