mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 14:51:15 +00:00
vtable: support associated consts
This commit is contained in:
parent
544cb1a198
commit
62010be72e
3 changed files with 86 additions and 27 deletions
|
@ -81,15 +81,15 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
brace_token: Default::default(),
|
||||
items: Default::default(),
|
||||
};
|
||||
let mut generated_trait_assoc_const = None;
|
||||
|
||||
let mut generated_to_fn_trait = vec![];
|
||||
let mut generated_type_assoc_fn = vec![];
|
||||
let mut vtable_ctor = vec![];
|
||||
|
||||
for field in &mut fields.named {
|
||||
if let Type::BareFn(f) = &mut field.ty {
|
||||
let ident = field.ident.as_ref().unwrap();
|
||||
|
||||
if let Type::BareFn(f) = &mut field.ty {
|
||||
let mut sig = Signature {
|
||||
constness: None,
|
||||
asyncness: None,
|
||||
|
@ -264,8 +264,7 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
vis: Visibility::Inherited,
|
||||
defaultness: None,
|
||||
sig: sig.clone(),
|
||||
block: parse(
|
||||
if has_self {
|
||||
block: parse2(if has_self {
|
||||
quote!({
|
||||
// Safety: this rely on the vtable being valid, and the ptr being a valid instance for this vtable
|
||||
unsafe { (self.vtable.as_ref().#ident)(#call_code) }
|
||||
|
@ -273,9 +272,7 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
} else {
|
||||
// This should never happen: nobody should be able to access the Trait Object directly.
|
||||
quote!({ panic!("Calling Sized method on a Trait Object") })
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
})
|
||||
.unwrap(),
|
||||
});
|
||||
|
||||
|
@ -295,13 +292,10 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
vis: generated_trait.vis.clone(),
|
||||
defaultness: None,
|
||||
sig,
|
||||
block: parse(
|
||||
quote!({
|
||||
block: parse2(quote!({
|
||||
// Safety: this rely on the vtable being valid, and the ptr being a valid instance for this vtable
|
||||
unsafe { (self.vtable.as_ref().#ident)(#call_code) }
|
||||
})
|
||||
.into(),
|
||||
)
|
||||
}))
|
||||
.unwrap(),
|
||||
});
|
||||
|
||||
|
@ -327,17 +321,47 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
},));
|
||||
}
|
||||
} else {
|
||||
return Error::new(field.span(), "member must only be functions")
|
||||
.to_compile_error()
|
||||
.into();
|
||||
// associated constant
|
||||
let ty = &field.ty;
|
||||
|
||||
let generated_trait_assoc_const =
|
||||
generated_trait_assoc_const.get_or_insert_with(|| ItemTrait {
|
||||
attrs: vec![],
|
||||
ident: quote::format_ident!("{}Consts", trait_name),
|
||||
items: vec![],
|
||||
..generated_trait.clone()
|
||||
});
|
||||
generated_trait_assoc_const.items.push(TraitItem::Const(TraitItemConst {
|
||||
attrs: field.attrs.clone(),
|
||||
const_token: Default::default(),
|
||||
ident: ident.clone(),
|
||||
colon_token: Default::default(),
|
||||
ty: ty.clone(),
|
||||
default: None,
|
||||
semi_token: Default::default(),
|
||||
}));
|
||||
|
||||
vtable_ctor.push(quote!(#ident: T::#ident,));
|
||||
|
||||
generated_type_assoc_fn.push(
|
||||
parse2(quote! {
|
||||
pub fn #ident(&self) -> #ty {
|
||||
// Safety: this rely on the vtable being valid, and the ptr being a valid instance for this vtable
|
||||
unsafe { self.vtable.as_ref().#ident }
|
||||
}
|
||||
})
|
||||
.unwrap(),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let vis = input.vis;
|
||||
input.vis = Visibility::Public(VisPublic { pub_token: Default::default() });
|
||||
|
||||
/*let (fields_name, fields_type): (Vec<_>, Vec<_>) =
|
||||
fields.named.iter().map(|f| (f.ident.clone().unwrap(), f.ty.clone())).unzip();*/
|
||||
let new_trait_extra = generated_trait_assoc_const.as_ref().map(|x| {
|
||||
let i = &x.ident;
|
||||
quote!(+ #i)
|
||||
});
|
||||
|
||||
let result = quote!(
|
||||
#[allow(non_snake_case)]
|
||||
|
@ -350,7 +374,7 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
|
||||
impl #vtable_name {
|
||||
// unfortunately cannot be const in stable rust because of the bounds (depends on rfc 2632)
|
||||
pub /*const*/ fn new<T: #trait_name>() -> Self {
|
||||
pub /*const*/ fn new<T: #trait_name #new_trait_extra>() -> Self {
|
||||
Self {
|
||||
#(#vtable_ctor)*
|
||||
}
|
||||
|
@ -358,6 +382,8 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
#generated_trait
|
||||
#generated_trait_assoc_const
|
||||
|
||||
struct #impl_name { _private: [u8; 0] }
|
||||
|
||||
/// This structure is highly unsafe, as it just has pointers. One could call trait functions
|
||||
|
@ -388,12 +414,20 @@ pub fn vtable(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
|||
type Trait = dyn #trait_name;
|
||||
type VTable = #vtable_name;
|
||||
type TraitObject = #to_name;
|
||||
type Type = #type_name;
|
||||
#[inline]
|
||||
unsafe fn map_to(from: &Self::TraitObject) -> &Self::Trait { from }
|
||||
#[inline]
|
||||
unsafe fn map_to_mut(from: &mut Self::TraitObject) -> &mut Self::Trait { from }
|
||||
#[inline]
|
||||
unsafe fn get_ptr(from: &Self::TraitObject) -> core::ptr::NonNull<u8> { from.ptr.cast() }
|
||||
#[inline]
|
||||
unsafe fn get_vtable(from: &Self::TraitObject) -> core::ptr::NonNull<Self::VTable> { from.vtable }
|
||||
#[inline]
|
||||
unsafe fn from_raw(vtable: core::ptr::NonNull<Self::VTable>, ptr: core::ptr::NonNull<u8>) -> Self::TraitObject
|
||||
{ #to_name { vtable, ptr : ptr.cast() } }
|
||||
#[inline]
|
||||
unsafe fn get_type(from: &Self::TraitObject) -> Self::Type { #type_name::from_raw(from.vtable) }
|
||||
}
|
||||
|
||||
#drop_impl
|
||||
|
|
|
@ -9,10 +9,14 @@ pub unsafe trait VTableMeta {
|
|||
/// that's the vtable struct `HelloVTable`
|
||||
type VTable;
|
||||
|
||||
/// That's the safe wrapper around a vtable pointer (`HelloType`)
|
||||
type Type;
|
||||
|
||||
/// That's the trait object that implements the trait.
|
||||
/// NOTE: the size must be 2*size_of<usize>
|
||||
type TraitObject: Copy;
|
||||
|
||||
|
||||
/// That maps from the tait object from the trait iteself
|
||||
/// (In other word, return 'to' since 'to' implements trait,
|
||||
/// but we can't represent that in rust right now, hence these helper)
|
||||
|
@ -29,6 +33,11 @@ pub unsafe trait VTableMeta {
|
|||
|
||||
/// Create a trait object from its raw parts
|
||||
unsafe fn from_raw(vtable: NonNull<Self::VTable>, ptr: NonNull<u8>) -> Self::TraitObject;
|
||||
|
||||
/// return a safe pointer around the vtable
|
||||
unsafe fn get_type(from: &Self::TraitObject) -> Self::Type;
|
||||
|
||||
|
||||
}
|
||||
|
||||
pub trait VTableMetaDrop: VTableMeta {
|
||||
|
@ -84,6 +93,9 @@ impl<T: ?Sized + VTableMetaDrop> VBox<T> {
|
|||
pub unsafe fn from_raw(vtable: NonNull<T::VTable>, ptr: NonNull<u8>) -> Self {
|
||||
Self {inner : T::from_raw(vtable, ptr)}
|
||||
}
|
||||
pub fn get_type(&self) -> T::Type {
|
||||
unsafe { T::get_type(&self.inner) }
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -144,6 +156,9 @@ impl<'a, T: ?Sized + VTableMeta> VRef<'a, T> {
|
|||
pub unsafe fn from_raw(vtable: NonNull<T::VTable>, ptr: NonNull<u8>) -> Self {
|
||||
Self {inner : T::from_raw(vtable, ptr), _phantom: PhantomData }
|
||||
}
|
||||
pub fn get_type(&self) -> T::Type {
|
||||
unsafe { T::get_type(&self.inner) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VRefMut<'a, T: ?Sized + VTableMeta> {
|
||||
|
@ -191,4 +206,7 @@ impl<'a, T: ?Sized + VTableMeta> VRefMut<'a, T> {
|
|||
pub fn into_ref(self) -> VRef<'a, T> {
|
||||
unsafe { VRef::from_inner(VRefMut::inner(&self)) }
|
||||
}
|
||||
pub fn get_type(&self) -> T::Type {
|
||||
unsafe { T::get_type(&self.inner) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@ struct HelloVTable {
|
|||
assoc: fn(*const HelloVTable) -> isize,
|
||||
|
||||
drop: fn(VRefMut<'_, HelloVTable>),
|
||||
|
||||
CONSTANT: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -34,6 +36,9 @@ impl Hello for SomeStruct {
|
|||
32
|
||||
}
|
||||
}
|
||||
impl HelloConsts for SomeStruct {
|
||||
const CONSTANT: usize = 88;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
|
@ -41,10 +46,12 @@ fn test() {
|
|||
let mut vt = HelloVTable::new::<SomeStruct>();
|
||||
let vt = unsafe { HelloType::from_raw(std::ptr::NonNull::from(&mut vt)) };
|
||||
assert_eq!(vt.assoc(), 32);
|
||||
assert_eq!(vt.CONSTANT(), 88);
|
||||
let mut bx = vt.construct(89);
|
||||
assert_eq!(bx.foo(1), 90);
|
||||
assert_eq!(bx.foo_mut(6), 95);
|
||||
assert_eq!(bx.foo(2), 97);
|
||||
assert_eq!(bx.get_type().CONSTANT(), 88);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue