1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4#![no_std]
5extern crate alloc;
6use crate::alloc::borrow::ToOwned;
7use alloc::boxed::Box;
8use alloc::string::String;
9
10use core::pin::Pin;
11use vtable::*;
12#[vtable]
13/// This is the actual doc
14struct HelloVTable {
15 foo: fn(VRef<'_, HelloVTable>, u32) -> u32,
16 foo_mut: fn(VRefMut<'_, HelloVTable>, u32) -> u32,
17 construct: fn(*const HelloVTable, u32) -> VBox<HelloVTable>,
18 assoc: fn(*const HelloVTable) -> isize,
19 with_lifetime: fn(VRef<'_, HelloVTable>) -> &'_ u32,
20
21 drop: fn(VRefMut<'_, HelloVTable>),
22
23 CONSTANT: usize,
24
25 #[field_offset(u32)]
26 SOME_OFFSET: usize,
27}
28
29#[derive(Debug, const_field_offset::FieldOffsets)]
30#[repr(C)]
31struct SomeStruct {
32 e: u8,
33 x: u32,
34}
35impl Hello for SomeStruct {
36 fn foo(&self, xx: u32) -> u32 {
37 self.x + xx
38 }
39
40 fn foo_mut(&mut self, xx: u32) -> u32 {
41 self.x += xx;
42 self.x
43 }
44
45 fn construct(init: u32) -> Self {
46 Self { e: 3, x: init }
47 }
48
49 fn assoc() -> isize {
50 32
51 }
52
53 fn with_lifetime(&self) -> &u32 {
54 &self.x
55 }
56}
57impl HelloConsts for SomeStruct {
58 const CONSTANT: usize = 88;
59 const SOME_OFFSET: const_field_offset::FieldOffset<SomeStruct, u32> =
60 SomeStruct::FIELD_OFFSETS.x;
61}
62
63HelloVTable_static!(static SOME_STRUCT_TYPE for SomeStruct);
64
65#[repr(C)]
66#[derive(const_field_offset::FieldOffsets)]
67struct SomeStructContainer {
68 e: u8,
69 s: SomeStruct,
70}
71
72#[derive(Debug, const_field_offset::FieldOffsets, Default)]
73#[repr(C)]
74struct AnotherStruct {
75 s: String,
76 foo: u32,
77}
78impl Hello for AnotherStruct {
79 fn foo(&self, xx: u32) -> u32 {
80 self.s.len() as u32 + xx
81 }
82
83 fn foo_mut(&mut self, xx: u32) -> u32 {
84 self.foo(xx)
85 }
86
87 fn construct(init: u32) -> Self {
88 Self { s: "123".into(), foo: init }
89 }
90
91 fn assoc() -> isize {
92 999
93 }
94
95 fn with_lifetime(&self) -> &u32 {
96 &self.foo
97 }
98}
99impl HelloConsts for AnotherStruct {
100 const CONSTANT: usize = 99;
101 const SOME_OFFSET: const_field_offset::FieldOffset<AnotherStruct, u32> =
102 AnotherStruct::FIELD_OFFSETS.foo;
103}
104
105HelloVTable_static!(static ANOTHERSTRUCT_VTABLE for AnotherStruct);
106
107#[test]
108fn test() {
109 let vt = &SOME_STRUCT_TYPE;
110 assert_eq!(vt.assoc(), 32);
111 assert_eq!(vt.CONSTANT, 88);
112 let mut bx = vt.construct(89);
113 assert_eq!(bx.foo(1), 90);
114 assert_eq!(bx.foo_mut(6), 95);
115 assert_eq!(bx.foo(2), 97);
116 assert_eq!(bx.get_vtable().CONSTANT, 88);
117
118 let bx2 = VBox::<HelloVTable>::new(SomeStruct { e: 4, x: 23 });
119 assert_eq!(bx2.foo(3), 26);
120 assert_eq!(bx2.get_vtable().CONSTANT, 88);
121 assert_eq!(*bx2.SOME_OFFSET(), 23);
122
123 let mut hello = SomeStruct { e: 4, x: 44 };
124 {
125 let xref = VRef::<HelloVTable>::new(&hello);
126 assert_eq!(xref.foo(0), 44);
127 }
128 {
129 let mut xref = VRefMut::<HelloVTable>::new(&mut hello);
130 assert_eq!(xref.foo_mut(2), 46);
131 assert_eq!(*xref.SOME_OFFSET(), 46);
132 *xref.SOME_OFFSET_mut() = 3;
133 let xref2 = xref.borrow();
134 assert_eq!(xref2.foo(1), 4);
135 }
136
137 let vo = VOffset::<SomeStructContainer, HelloVTable>::new(SomeStructContainer::FIELD_OFFSETS.s);
138 let mut ssc = SomeStructContainer { e: 4, s: SomeStruct { e: 5, x: 32 } };
139 assert_eq!(vo.apply(&ssc).foo(4), 32 + 4);
140 assert_eq!(vo.apply_mut(&mut ssc).foo_mut(4), 32 + 4);
141 assert_eq!(*vo.apply(&ssc).SOME_OFFSET(), 32 + 4);
142}
143
144#[test]
145fn test2() {
146 let mut ss = SomeStruct::construct(44);
147 let mut vrss = VRefMut::<HelloVTable>::new(&mut ss);
148 assert_eq!(vrss.downcast::<SomeStruct>().unwrap().foo_mut(4), 44 + 4);
149 assert!(vrss.downcast::<AnotherStruct>().is_none());
150
151 let as_ = AnotherStruct::default();
152 let vras = VRef::<HelloVTable>::new(&as_);
153 assert_eq!(vras.downcast::<AnotherStruct>().unwrap().foo(4), 4);
154 assert!(vras.downcast::<SomeStruct>().is_none());
155}
156
157#[test]
158fn test3() {
159 #[vtable]
160 struct XxxVTable {
161 ret_int: fn(VRef<XxxVTable>) -> i32,
162 }
163 struct Plop(i32);
164 impl Xxx for Plop {
165 fn ret_int(&self) -> i32 {
166 self.0
167 }
168 }
169
170 let p = Plop(11);
171 new_vref!(let re : VRef<XxxVTable> for Xxx = &p);
172 assert_eq!(re.ret_int(), 11);
173
174 let mut p = Plop(55);
175 new_vref!(let mut re_mut : VRefMut<XxxVTable> for Xxx = &mut p);
176 assert_eq!(re_mut.ret_int(), 55);
177}
178
179#[test]
180fn pin() {
181 #[vtable]
182 struct PinnedVTable {
183 my_func: fn(core::pin::Pin<VRef<PinnedVTable>>, u32) -> u32,
184 my_func2: fn(::core::pin::Pin<VRef<'_, PinnedVTable>>) -> u32,
185 my_func3: fn(Pin<VRefMut<PinnedVTable>>, u32) -> u32,
186 }
187
188 struct P(String, core::marker::PhantomPinned);
189 impl Pinned for P {
190 fn my_func(self: Pin<&Self>, p: u32) -> u32 {
191 self.0.len() as u32 + p
192 }
193 fn my_func2(self: Pin<&Self>) -> u32 {
194 self.0.len() as u32
195 }
196 fn my_func3(self: Pin<&mut Self>, _p: u32) -> u32 {
197 self.0.len() as u32
198 }
199 }
200 PinnedVTable_static!(static PVT for P);
201
202 let b = Box::pin(P("hello".to_owned(), core::marker::PhantomPinned));
203 let r = VRef::new_pin(b.as_ref());
204 assert_eq!(r.as_ref().my_func(44), 44 + 5);
205 assert_eq!(r.as_ref().my_func2(), 5);
206}
207