1#![no_std]
4#![allow(non_snake_case)]
5
6use core::{marker::PhantomData, ops::{Deref, DerefMut}};
7pub use dynamic_object_derive::*;
8extern crate alloc;
9use alloc::boxed::Box;
10pub mod typing;
11pub use typing::*;
12
13pub trait Dyn {
14
15}
16
17impl<T> Dyn for T {
18
19}
20
21pub trait Class {
23 type Parent: Sized + Class;
24 const NAME: &'static str;
25
26 fn id() -> usize;
27 fn offset() -> isize;
28 fn isa(id: usize) -> bool;
29}
30
31pub struct Object<T: Class, ContainerT = Box<dyn Dyn>> {
35 object: ContainerT,
38 isa: fn(id: usize) -> bool,
39 offset: i16,
40 _marker: PhantomData<T>
41}
42
43impl<T: Class, ContainerT> Object<T, ContainerT> {
44 pub fn new(object: ContainerT) -> Self {
54 Self {
55 object,
56 isa: T::isa,
57 offset: 0,
58 _marker: PhantomData
59 }
60 }
61
62 pub fn isa<Other: Class>(&self) -> bool {
73 (self.isa)(Other::id())
74 }
75
76 pub fn cast<Cast: Class>(self) -> Object<Cast, ContainerT> {
116 if isSubclassOf::<Cast, T>() {
117 assert!(self.isa::<Cast>());
118 }
119 let offset = if isSubclassOf::<Cast, T>() {
120 -typing::offsetOf::<T, Cast>()
121 }
122 else {
123 typing::offsetOf::<Cast, T>()
124 } as i16;
125 Object {
126 object: self.object,
127 isa: self.isa,
128 _marker: PhantomData,
129 offset: self.offset + offset
130 }
131 }
132
133 pub fn vtable(&self) -> &ContainerT {
134 &self.object
135 }
136
137 pub fn vtable_mut(&mut self) -> &mut ContainerT {
138 &mut self.object
139 }
140
141 pub fn try_cast<Cast: Class>(self) -> Option<Object<Cast, ContainerT>> {
143 if isSubclassOf::<Cast, T>() {
144 if !self.isa::<Cast>() {
145 return None
146 }
147 }
148
149 let offset = if isSubclassOf::<Cast, T>() {
150 -typing::offsetOf::<T, Cast>()
151 }
152 else {
153 typing::offsetOf::<Cast, T>()
154 } as i16;
155 Some(Object {
156 object: self.object,
157 isa: self.isa,
158 _marker: PhantomData,
159 offset: self.offset + offset
160 })
161 }
162}
163
164impl<T: Class, Container: Deref> Deref for Object<T, Container> {
165 type Target = T;
166
167 fn deref(&self) -> &Self::Target {
168 let inner = &*self.object as *const Container::Target as *const ();
169 let inner = inner as usize;
170 let inner = inner.wrapping_add(self.offset as usize);
171 let inner = inner as *const T;
172 unsafe {
173 &*inner
174 }
175 }
176}
177
178impl<T: Class, Container: DerefMut> DerefMut for Object<T, Container> {
179 fn deref_mut(&mut self) -> &mut Self::Target {
180 let inner = &mut *self.object as *mut Container::Target as *mut ();
181 let inner = inner as usize;
182 let inner = inner.wrapping_add(self.offset as usize);
183 let inner = inner as *mut T;
184 unsafe {
185 &mut *inner
186 }
187 }
188}
189
190impl<T: Class, Container: Clone> Clone for Object<T, Container> {
191 fn clone(&self) -> Self {
192 Self {
193 object: self.object.clone(),
194 isa: self.isa,
195 offset: self.offset,
196 _marker: PhantomData
197 }
198 }
199}
200
201impl<T: Class, Container: Copy> Copy for Object<T, Container> {
202
203}
204
205pub struct DynamicObjectBase;
214
215impl Class for DynamicObjectBase {
216 type Parent = Self;
217 const NAME: &'static str = "dynamic::ObjectBase";
218
219 fn isa(id: usize) -> bool {
220 id == Self::id()
221 }
222
223 fn offset() -> isize {
224 0
225 }
226
227 fn id() -> usize {
228 Self::id as *const u8 as usize
229 }
230}
231
232#[cfg(test)]
233mod test {
234 #![allow(unused_imports)]
235 #![allow(dead_code)]
236
237 extern crate std;
238 use dynamic_object_derive::*;
239 use crate as dynamic_object;
241 use crate::*;
242 use std::{println, prelude::*};
244
245 trait A {
246
247 }
248
249 #[subclass(DynamicObjectBase)]
250 struct Class {
251 value: u32,
252 foo: u32
253 }
254
255 #[subclass(Class, parent)]
256 struct Derived {
257 field: u32,
258 parent: Class,
259 }
260
261 #[subclass(DynamicObjectBase)]
262 struct BarObject {
263
264 }
265
266 #[subclass(DynamicObjectBase)]
267 struct AnotherObject {
268
269 }
270
271 #[test]
272 fn isa() {
273 let object = Derived {
274 parent: Class {
275 value: 0,
276 foo: 0
277 },
278 field: 0
279 };
280 let object = Object::<Derived>::new(Box::new(object));
281 assert!(object.isa::<DynamicObjectBase>());
282 assert!(!object.isa::<BarObject>());
283 }
284
285 #[test]
286 fn casting() {
287 let object = Derived {
288 parent: Class {
289 value: 548389,
290 foo: 72840548
291 },
292 field: 2153746,
293 };
294
295 let object = Object::<Derived>::new(Box::new(object));
296 assert!(object.field == 2153746);
297 assert!(object.parent.value == 548389);
298 assert!(object.parent.foo == 72840548);
299
300 let object = object.cast::<Class>();
301 println!("Parent offset: {}", object.offset);
302 println!("After cast: {}", object.value);
303 assert!(object.value == 548389);
304 assert!(object.foo == 72840548);
305
306 let object = object.cast::<Derived>();
307 assert!(object.field == 2153746);
308 assert!(object.parent.value == 548389);
309 assert!(object.parent.foo == 72840548);
310 }
311}