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