vtable: add safe way to construct references

This commit is contained in:
Olivier Goffart 2020-05-16 10:14:11 +02:00
parent 810a3905a7
commit aff3d7e14b
6 changed files with 48 additions and 17 deletions

View file

@ -5,7 +5,8 @@ pub mod re_exports {
pub use const_field_offset::FieldOffsets;
pub use corelib::abi::datastructures::{Component, ComponentTO, ComponentVTable, ItemTreeNode};
pub use corelib::abi::primitives::{Image, ImageVTable, Rectangle, RectangleVTable};
pub use corelib::ComponentVTable_static;
pub use gl::sixtyfps_runtime_run_component_with_gl_renderer;
pub use once_cell::sync::Lazy;
pub use vtable::*;
pub use vtable::{self, *};
}

View file

@ -146,6 +146,7 @@ pub fn sixtyfps(stream: TokenStream) -> TokenStream {
struct #component_id {
#(#item_names : sixtyfps::re_exports::#item_types,)*
}
impl core::default::Default for #component_id {
fn default() -> Self {
let mut self_ = Self {
@ -168,19 +169,13 @@ pub fn sixtyfps(stream: TokenStream) -> TokenStream {
}
impl #component_id{
fn run(&mut self) {
// FIXME: we need a static lifetime for winit run, so this takes the component by value and put it in a leaked box
// Ideally we would not need a static lifetime to run the engine. (eg: use run_return function of winit)
fn run(self) {
use sixtyfps::re_exports::*;
// Would be nice if ComponentVTable::new was const.
static COMPONENT_VTABLE : Lazy<ComponentVTable> = Lazy::new(|| {
ComponentVTable::new::<#component_id>()
});
sixtyfps_runtime_run_component_with_gl_renderer(
unsafe { VRefMut::from_raw(
core::ptr::NonNull::from(&*COMPONENT_VTABLE),
core::ptr::NonNull::from(self).cast()
)}
);
sixtyfps::re_exports::ComponentVTable_static!(#component_id);
let static_self = Box::leak(Box::new(self));
sixtyfps_runtime_run_component_with_gl_renderer(VRefMut::new(static_self));
}
}
)

View file

@ -280,7 +280,7 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
fn new_box<X: HasStaticVTable<#vtable_name>>(value: X) -> VBox<#vtable_name> {
// Put the object on the heap and get a pointer to it
let ptr = core::ptr::NonNull::from(Box::leak(Box::new(value)));
unsafe { VBox::from_raw(core::ptr::NonNull::from(&X::VTABLE), ptr.cast()) }
unsafe { VBox::from_raw(core::ptr::NonNull::from(X::STATIC_VTABLE), ptr.cast()) }
}
}
pub type #box_name = VBox<#vtable_name>;
@ -457,13 +457,15 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
/// Implements HasStaticVTable<XXXVTable> for the given type
macro_rules! #static_vtable_macro_name {
($ty:ty) => {
unsafe impl ::vtable::HasStaticVTable<#vtable_name> for $ty {
unsafe impl vtable::HasStaticVTable<#vtable_name> for $ty {
const VTABLE: #vtable_name = {
use vtable::*;
type T = $ty;
#vtable_name {
#(#vtable_ctor)*
}
};
const STATIC_VTABLE : &'static #vtable_name = &Self::VTABLE;
}
}
}

View file

@ -27,6 +27,7 @@ where
{
/// Savety: must be a valid VTable for Self
const VTABLE: VT::VTable;
const STATIC_VTABLE: &'static VT::VTable;
}
#[derive(Copy, Clone)]
@ -115,6 +116,16 @@ impl<'a, T: ?Sized + VTableMeta> Deref for VRef<'a, T> {
}
impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {
pub fn new<X: HasStaticVTable<T>>(value: &'a X) -> Self {
Self {
inner: Inner {
vtable: X::STATIC_VTABLE as *const T::VTable as *const u8,
ptr: value as *const X as *const u8,
},
phantom: PhantomData,
}
}
unsafe fn from_inner(inner: Inner) -> Self {
Self { inner, phantom: PhantomData }
}
@ -145,6 +156,16 @@ impl<'a, T: ?Sized + VTableMeta> DerefMut for VRefMut<'a, T> {
}
impl<'a, T: ?Sized + VTableMeta> VRefMut<'a, T> {
pub fn new<X: HasStaticVTable<T>>(value: &'a mut X) -> Self {
Self {
inner: Inner {
vtable: X::STATIC_VTABLE as *const T::VTable as *const u8,
ptr: value as *mut X as *const u8,
},
phantom: PhantomData,
}
}
unsafe fn from_inner(inner: Inner) -> Self {
Self { inner, phantom: PhantomData }
}

View file

@ -56,4 +56,16 @@ fn test() {
let bx2 = VBox::<HelloVTable>::new(SomeStruct(23));
assert_eq!(bx2.foo(3), 26);
assert_eq!(bx2.get_vtable().CONSTANT, 88);
let mut hello = SomeStruct(44);
{
let xref = VRef::<HelloVTable>::new(&hello);
assert_eq!(xref.foo(0), 44);
}
{
let mut xref = VRefMut::<HelloVTable>::new(&mut hello);
assert_eq!(xref.foo_mut(2), 46);
let xref2 = xref.borrow();
assert_eq!(xref2.foo(1), 47);
}
}

View file

@ -84,7 +84,7 @@ impl ItemConsts for Image {
}
#[no_mangle]
pub static RectangleVTable: ItemVTable = Image::VTABLE;
pub static RectangleVTable: ItemVTable = Rectangle::VTABLE;
#[no_mangle]
pub static ImageVTable: ItemVTable = Rectangle::VTABLE;
pub static ImageVTable: ItemVTable = Image::VTABLE;