| 1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
| 2 | // SPDX-License-Identifier: MIT OR Apache-2.0 |
| 3 | |
| 4 | #![no_std ] |
| 5 | extern crate alloc; |
| 6 | use crate::alloc::borrow::ToOwned; |
| 7 | use alloc::boxed::Box; |
| 8 | use alloc::string::String; |
| 9 | |
| 10 | use core::pin::Pin; |
| 11 | use vtable::*; |
| 12 | #[vtable ] |
| 13 | /// This is the actual doc |
| 14 | struct 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)] |
| 31 | struct SomeStruct { |
| 32 | e: u8, |
| 33 | x: u32, |
| 34 | } |
| 35 | impl 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 | } |
| 57 | impl 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 | |
| 63 | HelloVTable_static!(static SOME_STRUCT_TYPE for SomeStruct); |
| 64 | |
| 65 | #[repr (C)] |
| 66 | #[derive (const_field_offset::FieldOffsets)] |
| 67 | struct SomeStructContainer { |
| 68 | e: u8, |
| 69 | s: SomeStruct, |
| 70 | } |
| 71 | |
| 72 | #[derive (Debug, const_field_offset::FieldOffsets, Default)] |
| 73 | #[repr (C)] |
| 74 | struct AnotherStruct { |
| 75 | s: String, |
| 76 | foo: u32, |
| 77 | } |
| 78 | impl 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 | } |
| 99 | impl 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 | |
| 105 | HelloVTable_static!(static ANOTHERSTRUCT_VTABLE for AnotherStruct); |
| 106 | |
| 107 | #[test ] |
| 108 | fn 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 ] |
| 145 | fn 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 ] |
| 158 | fn 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 ] |
| 180 | fn 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 | |