1#![deny(missing_docs)]
2#![allow(missing_docs)]
3
4#[derive(Clone, PartialEq, Eq, Debug)]
6pub enum Fields {
7 Named(&'static [Field]),
9
10 Indexed(&'static [Field]),
13
14 Unit,
16}
17
18#[derive(Clone, PartialEq, Eq, Debug)]
23pub enum Data {
24 Primitive,
26 Struct(Fields),
28
29 Enum(Variants),
31
32 Unit,
36}
37
38#[derive(Clone, PartialEq, Eq, Debug)]
40pub enum FieldId {
41 Index(usize),
43 Named(&'static str),
45}
46
47#[derive(Clone, PartialEq, Eq, Debug)]
51pub struct Field {
52 pub id: FieldId,
56 pub ty: &'static Type,
58}
59impl From<&'static str> for FieldId {
60 fn from(s: &'static str) -> Self {
61 FieldId::Named(s)
62 }
63}
64
65impl From<usize> for FieldId {
66 fn from(i: usize) -> Self {
67 FieldId::Index(i)
68 }
69}
70
71
72#[derive(Clone, PartialEq, Eq, Debug)]
74pub struct Variant {
75 #[allow(missing_docs)]
76 pub ident: &'static str,
77 #[allow(missing_docs)]
78 pub fields: Fields,
79}
80#[allow(missing_docs)]
81#[derive(Clone, PartialEq, Eq, Debug)]
82pub struct Variants {
83 #[allow(missing_docs)]
84 pub variants: &'static [Variant],
85}
86
87#[derive(Clone, PartialEq, Eq, Debug)]
91pub struct Type {
92 pub ident: &'static str,
94 pub data: Data,
96}
97
98#[derive(thiserror::Error, Debug)]
100pub enum FieldAccessError {
101 #[error("Requested type doesn't match actual type")]
103 UnmatchingType,
104
105 #[error("Attempt to access field in unit type/variant")]
107 Unit,
108
109 #[error("Field not found")]
111 NotFound,
112}
113
114#[derive(thiserror::Error, Debug)]
116pub enum RuntimeConstructError {
117 #[error("Can't construct primitive type")]
119 Primitive,
120
121 #[error("Invalid type at {index} was passed to runtime constructor")]
123 UnexpectedType {
124 #[allow(missing_docs)]
125 index: usize,
126 expected: &'static str,
128 },
129
130 #[error("Requested variant doesn't exist")]
132 InvalidVariant,
133
134 #[error("Some fields of this type are not public")]
135 #[allow(missing_docs)]
136 PrivateFields,
137
138 #[error("Called `construct_struct` on enum type")]
139 #[allow(missing_docs)]
140 NotStruct,
141
142 #[error("Called `construct_enum` on a struct type")]
143 #[allow(missing_docs)]
144 NotEnum,
145
146 #[error("Not enough arguments were passed")]
147 #[allow(missing_docs)]
148 NotEnoughArgs,
149}
150
151pub trait TypeInfoDynamic: std::any::Any {
156 fn get_dynamic(&self) -> &'static Type;
160
161 fn construct_struct(
170 &self,
171 args: Vec<Box<dyn Any>>,
172 ) -> Result<Box<dyn Any>, RuntimeConstructError>;
173
174 fn construct_enum(
183 &self,
184 variant: &'static str, args: Vec<Box<dyn Any>>,
186 ) -> Result<Box<dyn Any>, RuntimeConstructError>;
187
188 fn field<'s>(&'s self, id: FieldId) -> Result<Unsizeable<'s>, FieldAccessError>;
194
195 fn field_mut<'s>(&'s mut self, id: FieldId) -> Result<UnsizeableMut<'s>, FieldAccessError>;
199}
200
201pub trait TypeInfo: TypeInfoDynamic + Sized {
203 #[allow(missing_docs)]
204 const INFO: &'static Type;
205}
206
207pub struct Unsizeable<'a> {
211 ptr: *const (),
212 target_id: std::any::TypeId,
213 _lt: std::marker::PhantomData<&'a ()>,
214}
215
216impl<'a> Unsizeable<'a> {
217 #[doc(hidden)]
218 pub fn new(ptr: *const (), target_id: std::any::TypeId) -> Self {
219 Self {
220 ptr,
221 target_id,
222 _lt: std::marker::PhantomData,
223 }
224 }
225
226 pub fn downcast_ref<T>(&self) -> Option<&'a T>
232 where
233 T: 'static,
234 {
235 if std::any::TypeId::of::<T>() != self.target_id {
236 return None;
237 }
238
239 unsafe {
240 let target_ptr = self.ptr as *const T;
241 target_ptr.as_ref()
242 }
243 }
244}
245
246pub struct UnsizeableMut<'a> {
251 ptr: *mut (),
252 target_id: std::any::TypeId,
253 _lt: std::marker::PhantomData<&'a ()>,
254}
255impl<'a> UnsizeableMut<'a> {
256 #[doc(hidden)]
257 pub fn new(ptr: *mut (), target_id: std::any::TypeId) -> Self {
258 Self {
259 ptr,
260 target_id,
261 _lt: std::marker::PhantomData,
262 }
263 }
264
265 pub fn downcast_mut<T>(&self) -> Option<&'a mut T>
270 where
271 T: 'static,
272 {
273 if std::any::TypeId::of::<T>() != self.target_id {
274 return None;
275 }
276
277 unsafe {
278 let target_ptr = self.ptr as *mut T;
279 target_ptr.as_mut()
280 }
281 }
282}
283
284use std::any::Any;
285
286use paste::paste;
287macro_rules! impl_primitive {
288 ($name:ty ) => {
289 paste! {
290 #[allow(unused)]
291 const [<$name:upper _INFO>]: Type = Type {
292 ident: std::stringify!($name),
293 data: Data::Primitive,
294 };
297
298 #[automatically_derived]
299 impl TypeInfoDynamic for $name {
300 fn get_dynamic(&self) -> &'static Type {
301 &[<$name:upper _INFO>]
302
303 }
304 fn construct_struct(&self, _args: Vec<Box<dyn Any>>) -> Result<Box<dyn Any>, RuntimeConstructError> {
305 Err(RuntimeConstructError::Primitive)
306 }
307
308 fn construct_enum(
309 &self,
310 _variant: &'static str,
311 _args: Vec<Box<dyn Any>>,
312 ) -> Result<Box<dyn Any>, RuntimeConstructError> {
313 Err(RuntimeConstructError::Primitive)
314
315 }
316
317 fn field<'s>(&'s self, id: FieldId) -> Result<Unsizeable<'s>, FieldAccessError> {
318 Err(FieldAccessError::Unit)
319 }
320 fn field_mut<'s>(&'s mut self, id: FieldId) -> Result<UnsizeableMut<'s>, FieldAccessError> {
321 Err(FieldAccessError::Unit)
322
323 }
324
325 }
326 #[automatically_derived]
327 impl TypeInfo for $name {
328 const INFO: &'static Type = &[<$name:upper _INFO>];
329 }
330 }
331 };
332}
333
334impl_primitive!(u8);
335impl_primitive!(u16);
336impl_primitive!(u32);
337impl_primitive!(u64);
338impl_primitive!(u128);
339
340impl_primitive!(i8);
341impl_primitive!(i16);
342impl_primitive!(i32);
343impl_primitive!(i64);
344impl_primitive!(i128);
345
346impl_primitive!(usize);
347impl_primitive!(isize);
348
349impl_primitive!(String);
350
351impl_primitive!(f32);
352impl_primitive!(f64);
353
354mod __object_safety_check {
355 use super::TypeInfoDynamic;
356
357 fn __check_is_object_safe() -> Box<dyn TypeInfoDynamic> {
358 Box::new(100u32)
359 }
360}