mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-26 21:34:08 +00:00

When using rust, allow panics to cross the boundaries of our vtable traits. This avoids panic producing two backtrace with panic=unwind This patch doesn't touch the ABI of out FFI interface, they stay extern "C", because if a panic or exception crosses these boundaries, we are in trouble. (Also, we have a panic=abort in our Cargo.toml anyway)
206 lines
5.3 KiB
Rust
206 lines
5.3 KiB
Rust
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
|
// SPDX-License-Identifier: MIT OR Apache-2.0
|
|
|
|
#![no_std]
|
|
extern crate alloc;
|
|
use crate::alloc::borrow::ToOwned;
|
|
use alloc::boxed::Box;
|
|
use alloc::string::String;
|
|
|
|
use core::pin::Pin;
|
|
use vtable::*;
|
|
#[vtable]
|
|
/// This is the actual doc
|
|
struct HelloVTable {
|
|
foo: fn(VRef<'_, HelloVTable>, u32) -> u32,
|
|
foo_mut: extern "C" fn(VRefMut<'_, HelloVTable>, u32) -> u32,
|
|
construct: fn(*const HelloVTable, u32) -> VBox<HelloVTable>,
|
|
assoc: fn(*const HelloVTable) -> isize,
|
|
with_lifetime: extern "C-unwind" fn(VRef<'_, HelloVTable>) -> &'_ u32,
|
|
|
|
drop: fn(VRefMut<'_, HelloVTable>),
|
|
|
|
CONSTANT: usize,
|
|
|
|
#[field_offset(u32)]
|
|
SOME_OFFSET: usize,
|
|
}
|
|
|
|
#[derive(Debug, const_field_offset::FieldOffsets)]
|
|
#[repr(C)]
|
|
struct SomeStruct {
|
|
e: u8,
|
|
x: u32,
|
|
}
|
|
impl Hello for SomeStruct {
|
|
fn foo(&self, xx: u32) -> u32 {
|
|
self.x + xx
|
|
}
|
|
|
|
fn foo_mut(&mut self, xx: u32) -> u32 {
|
|
self.x += xx;
|
|
self.x
|
|
}
|
|
|
|
fn construct(init: u32) -> Self {
|
|
Self { e: 3, x: init }
|
|
}
|
|
|
|
fn assoc() -> isize {
|
|
32
|
|
}
|
|
|
|
fn with_lifetime(&self) -> &u32 {
|
|
&self.x
|
|
}
|
|
}
|
|
impl HelloConsts for SomeStruct {
|
|
const CONSTANT: usize = 88;
|
|
const SOME_OFFSET: const_field_offset::FieldOffset<SomeStruct, u32> =
|
|
SomeStruct::FIELD_OFFSETS.x;
|
|
}
|
|
|
|
HelloVTable_static!(static SOME_STRUCT_TYPE for SomeStruct);
|
|
|
|
#[repr(C)]
|
|
#[derive(const_field_offset::FieldOffsets)]
|
|
struct SomeStructContainer {
|
|
e: u8,
|
|
s: SomeStruct,
|
|
}
|
|
|
|
#[derive(Debug, const_field_offset::FieldOffsets, Default)]
|
|
#[repr(C)]
|
|
struct AnotherStruct {
|
|
s: String,
|
|
foo: u32,
|
|
}
|
|
impl Hello for AnotherStruct {
|
|
fn foo(&self, xx: u32) -> u32 {
|
|
self.s.len() as u32 + xx
|
|
}
|
|
|
|
fn foo_mut(&mut self, xx: u32) -> u32 {
|
|
self.foo(xx)
|
|
}
|
|
|
|
fn construct(init: u32) -> Self {
|
|
Self { s: "123".into(), foo: init }
|
|
}
|
|
|
|
fn assoc() -> isize {
|
|
999
|
|
}
|
|
|
|
fn with_lifetime(&self) -> &u32 {
|
|
&self.foo
|
|
}
|
|
}
|
|
impl HelloConsts for AnotherStruct {
|
|
const CONSTANT: usize = 99;
|
|
const SOME_OFFSET: const_field_offset::FieldOffset<AnotherStruct, u32> =
|
|
AnotherStruct::FIELD_OFFSETS.foo;
|
|
}
|
|
|
|
HelloVTable_static!(static ANOTHERSTRUCT_VTABLE for AnotherStruct);
|
|
|
|
#[test]
|
|
fn test() {
|
|
let vt = &SOME_STRUCT_TYPE;
|
|
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_vtable().CONSTANT, 88);
|
|
|
|
let bx2 = VBox::<HelloVTable>::new(SomeStruct { e: 4, x: 23 });
|
|
assert_eq!(bx2.foo(3), 26);
|
|
assert_eq!(bx2.get_vtable().CONSTANT, 88);
|
|
assert_eq!(*bx2.SOME_OFFSET(), 23);
|
|
|
|
let mut hello = SomeStruct { e: 4, x: 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);
|
|
assert_eq!(*xref.SOME_OFFSET(), 46);
|
|
*xref.SOME_OFFSET_mut() = 3;
|
|
let xref2 = xref.borrow();
|
|
assert_eq!(xref2.foo(1), 4);
|
|
}
|
|
|
|
let vo = VOffset::<SomeStructContainer, HelloVTable>::new(SomeStructContainer::FIELD_OFFSETS.s);
|
|
let mut ssc = SomeStructContainer { e: 4, s: SomeStruct { e: 5, x: 32 } };
|
|
assert_eq!(vo.apply(&ssc).foo(4), 32 + 4);
|
|
assert_eq!(vo.apply_mut(&mut ssc).foo_mut(4), 32 + 4);
|
|
assert_eq!(*vo.apply(&ssc).SOME_OFFSET(), 32 + 4);
|
|
}
|
|
|
|
#[test]
|
|
fn test2() {
|
|
let mut ss = SomeStruct::construct(44);
|
|
let mut vrss = VRefMut::<HelloVTable>::new(&mut ss);
|
|
assert_eq!(vrss.downcast::<SomeStruct>().unwrap().foo_mut(4), 44 + 4);
|
|
assert!(vrss.downcast::<AnotherStruct>().is_none());
|
|
|
|
let as_ = AnotherStruct::default();
|
|
let vras = VRef::<HelloVTable>::new(&as_);
|
|
assert_eq!(vras.downcast::<AnotherStruct>().unwrap().foo(4), 4);
|
|
assert!(vras.downcast::<SomeStruct>().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn test3() {
|
|
#[vtable]
|
|
struct XxxVTable {
|
|
ret_int: fn(VRef<XxxVTable>) -> i32,
|
|
}
|
|
struct Plop(i32);
|
|
impl Xxx for Plop {
|
|
fn ret_int(&self) -> i32 {
|
|
self.0
|
|
}
|
|
}
|
|
|
|
let p = Plop(11);
|
|
new_vref!(let re : VRef<XxxVTable> for Xxx = &p);
|
|
assert_eq!(re.ret_int(), 11);
|
|
|
|
let mut p = Plop(55);
|
|
new_vref!(let mut re_mut : VRefMut<XxxVTable> for Xxx = &mut p);
|
|
assert_eq!(re_mut.ret_int(), 55);
|
|
}
|
|
|
|
#[test]
|
|
fn pin() {
|
|
#[vtable]
|
|
struct PinnedVTable {
|
|
my_func: fn(core::pin::Pin<VRef<PinnedVTable>>, u32) -> u32,
|
|
my_func2: fn(::core::pin::Pin<VRef<'_, PinnedVTable>>) -> u32,
|
|
my_func3: fn(Pin<VRefMut<PinnedVTable>>, u32) -> u32,
|
|
}
|
|
|
|
struct P(String, core::marker::PhantomPinned);
|
|
impl Pinned for P {
|
|
fn my_func(self: Pin<&Self>, p: u32) -> u32 {
|
|
self.0.len() as u32 + p
|
|
}
|
|
fn my_func2(self: Pin<&Self>) -> u32 {
|
|
self.0.len() as u32
|
|
}
|
|
fn my_func3(self: Pin<&mut Self>, _p: u32) -> u32 {
|
|
self.0.len() as u32
|
|
}
|
|
}
|
|
PinnedVTable_static!(static PVT for P);
|
|
|
|
let b = Box::pin(P("hello".to_owned(), core::marker::PhantomPinned));
|
|
let r = VRef::new_pin(b.as_ref());
|
|
assert_eq!(r.as_ref().my_func(44), 44 + 5);
|
|
assert_eq!(r.as_ref().my_func2(), 5);
|
|
}
|