intuicio_core/types/
mod.rs

1#![allow(unpredictable_function_pointer_comparisons)]
2
3pub mod enum_type;
4pub mod struct_type;
5
6use crate::{
7    Visibility,
8    meta::Meta,
9    types::{
10        enum_type::{Enum, EnumVariant},
11        struct_type::{Struct, StructField},
12    },
13};
14use intuicio_data::type_hash::TypeHash;
15use rustc_hash::FxHasher;
16use std::{
17    alloc::Layout,
18    borrow::Cow,
19    hash::{Hash, Hasher},
20    sync::Arc,
21};
22
23pub type TypeHandle = Arc<Type>;
24pub type MetaQuery = fn(&Meta) -> bool;
25
26#[derive(Debug, PartialEq)]
27pub enum Type {
28    Struct(Struct),
29    Enum(Enum),
30}
31
32impl Type {
33    pub fn is_struct(&self) -> bool {
34        matches!(self, Self::Struct(_))
35    }
36
37    pub fn is_enum(&self) -> bool {
38        matches!(self, Self::Enum(_))
39    }
40
41    pub fn as_struct(&self) -> Option<&Struct> {
42        if let Self::Struct(value) = self {
43            Some(value)
44        } else {
45            None
46        }
47    }
48
49    pub fn as_enum(&self) -> Option<&Enum> {
50        if let Self::Enum(value) = self {
51            Some(value)
52        } else {
53            None
54        }
55    }
56
57    pub fn meta(&self) -> Option<&Meta> {
58        match self {
59            Self::Struct(value) => value.meta.as_ref(),
60            Self::Enum(value) => value.meta.as_ref(),
61        }
62    }
63
64    pub fn name(&self) -> &str {
65        match self {
66            Self::Struct(value) => &value.name,
67            Self::Enum(value) => &value.name,
68        }
69    }
70
71    pub fn module_name(&self) -> Option<&str> {
72        match self {
73            Self::Struct(value) => value.module_name.as_deref(),
74            Self::Enum(value) => value.module_name.as_deref(),
75        }
76    }
77
78    pub fn visibility(&self) -> Visibility {
79        match self {
80            Self::Struct(value) => value.visibility,
81            Self::Enum(value) => value.visibility,
82        }
83    }
84
85    pub fn is_runtime(&self) -> bool {
86        match self {
87            Self::Struct(value) => value.is_runtime(),
88            Self::Enum(value) => value.is_runtime(),
89        }
90    }
91
92    pub fn is_native(&self) -> bool {
93        match self {
94            Self::Struct(value) => value.is_native(),
95            Self::Enum(value) => value.is_native(),
96        }
97    }
98
99    pub fn is_send(&self) -> bool {
100        match self {
101            Self::Struct(value) => value.is_send(),
102            Self::Enum(value) => value.is_send(),
103        }
104    }
105
106    pub fn is_sync(&self) -> bool {
107        match self {
108            Self::Struct(value) => value.is_sync(),
109            Self::Enum(value) => value.is_sync(),
110        }
111    }
112
113    pub fn is_copy(&self) -> bool {
114        match self {
115            Self::Struct(value) => value.is_copy(),
116            Self::Enum(value) => value.is_copy(),
117        }
118    }
119
120    pub fn can_initialize(&self) -> bool {
121        match self {
122            Self::Struct(value) => value.can_initialize(),
123            Self::Enum(value) => value.can_initialize(),
124        }
125    }
126
127    pub fn type_hash(&self) -> TypeHash {
128        match self {
129            Self::Struct(value) => value.type_hash(),
130            Self::Enum(value) => value.type_hash(),
131        }
132    }
133
134    pub fn type_name(&self) -> &str {
135        match self {
136            Self::Struct(value) => value.type_name(),
137            Self::Enum(value) => value.type_name(),
138        }
139    }
140
141    pub fn layout(&self) -> &Layout {
142        match self {
143            Self::Struct(value) => value.layout(),
144            Self::Enum(value) => value.layout(),
145        }
146    }
147
148    pub fn struct_fields(&self) -> Option<&[StructField]> {
149        if let Self::Struct(value) = self {
150            Some(value.fields())
151        } else {
152            None
153        }
154    }
155
156    pub fn enum_variants(&self) -> Option<&[EnumVariant]> {
157        if let Self::Enum(value) = self {
158            Some(value.variants())
159        } else {
160            None
161        }
162    }
163
164    pub fn is_compatible(&self, other: &Self) -> bool {
165        match (self, other) {
166            (Self::Struct(a), Self::Struct(b)) => a.is_compatible(b),
167            (Self::Enum(a), Self::Enum(b)) => a.is_compatible(b),
168            _ => false,
169        }
170    }
171
172    pub fn find_struct_fields<'a>(
173        &'a self,
174        query: StructFieldQuery<'a>,
175    ) -> Option<impl Iterator<Item = &'a StructField> + 'a> {
176        if let Self::Struct(value) = self {
177            Some(value.find_fields(query))
178        } else {
179            None
180        }
181    }
182
183    pub fn find_struct_field<'a>(&'a self, query: StructFieldQuery<'a>) -> Option<&'a StructField> {
184        if let Self::Struct(value) = self {
185            value.find_field(query)
186        } else {
187            None
188        }
189    }
190
191    pub fn find_enum_variants<'a>(
192        &'a self,
193        query: EnumVariantQuery<'a>,
194    ) -> Option<impl Iterator<Item = &'a EnumVariant> + 'a> {
195        if let Self::Enum(value) = self {
196            Some(value.find_variants(query))
197        } else {
198            None
199        }
200    }
201
202    pub fn find_enum_variant<'a>(&'a self, query: EnumVariantQuery<'a>) -> Option<&'a EnumVariant> {
203        if let Self::Enum(value) = self {
204            value.find_variant(query)
205        } else {
206            None
207        }
208    }
209
210    /// # Safety
211    pub unsafe fn try_copy(&self, from: *const u8, to: *mut u8) -> bool {
212        match self {
213            Self::Struct(value) => unsafe { value.try_copy(from, to) },
214            Self::Enum(value) => unsafe { value.try_copy(from, to) },
215        }
216    }
217
218    /// # Safety
219    pub unsafe fn find_enum_variant_by_value<T: 'static>(&self, value: &T) -> Option<&EnumVariant> {
220        if let Self::Enum(enum_type) = self {
221            unsafe { enum_type.find_variant_by_value(value) }
222        } else {
223            None
224        }
225    }
226
227    /// # Safety
228    pub unsafe fn initialize(&self, pointer: *mut ()) -> bool {
229        match self {
230            Self::Struct(value) => unsafe { value.initialize(pointer) },
231            Self::Enum(value) => unsafe { value.initialize(pointer) },
232        }
233    }
234
235    /// # Safety
236    pub unsafe fn finalize(&self, pointer: *mut ()) {
237        match self {
238            Self::Struct(value) => unsafe { value.finalize(pointer) },
239            Self::Enum(value) => unsafe { value.finalize(pointer) },
240        }
241    }
242
243    /// # Safety
244    pub unsafe fn initializer(&self) -> Option<unsafe fn(*mut ())> {
245        match self {
246            Self::Struct(value) => unsafe { value.initializer() },
247            Self::Enum(value) => unsafe { value.initializer() },
248        }
249    }
250
251    /// # Safety
252    pub unsafe fn finalizer(&self) -> unsafe fn(*mut ()) {
253        match self {
254            Self::Struct(value) => unsafe { value.finalizer() },
255            Self::Enum(value) => unsafe { value.finalizer() },
256        }
257    }
258
259    pub fn into_handle(self) -> TypeHandle {
260        self.into()
261    }
262}
263
264impl From<Struct> for Type {
265    fn from(value: Struct) -> Self {
266        Self::Struct(value)
267    }
268}
269
270impl From<Enum> for Type {
271    fn from(value: Enum) -> Self {
272        Self::Enum(value)
273    }
274}
275
276#[derive(Debug, Default, Clone, PartialEq, Hash)]
277pub struct StructFieldQuery<'a> {
278    pub name: Option<Cow<'a, str>>,
279    pub type_query: Option<TypeQuery<'a>>,
280    pub visibility: Option<Visibility>,
281    pub meta: Option<MetaQuery>,
282}
283
284impl StructFieldQuery<'_> {
285    pub fn is_valid(&self, field: &StructField) -> bool {
286        self.name
287            .as_ref()
288            .map(|name| name.as_ref() == field.name)
289            .unwrap_or(true)
290            && self
291                .type_query
292                .as_ref()
293                .map(|query| query.is_valid(&field.type_handle))
294                .unwrap_or(true)
295            && self
296                .visibility
297                .map(|visibility| field.visibility.is_visible(visibility))
298                .unwrap_or(true)
299            && self
300                .meta
301                .as_ref()
302                .map(|query| field.meta.as_ref().map(query).unwrap_or(false))
303                .unwrap_or(true)
304    }
305
306    pub fn to_static(&self) -> StructFieldQuery<'static> {
307        StructFieldQuery {
308            name: self
309                .name
310                .as_ref()
311                .map(|name| name.as_ref().to_owned().into()),
312            type_query: self.type_query.as_ref().map(|query| query.to_static()),
313            visibility: self.visibility,
314            meta: self.meta,
315        }
316    }
317}
318
319#[derive(Debug, Default, Clone, PartialEq, Hash)]
320pub struct EnumVariantQuery<'a> {
321    pub name: Option<Cow<'a, str>>,
322    pub fields: Cow<'a, [StructFieldQuery<'a>]>,
323    pub meta: Option<MetaQuery>,
324}
325
326impl EnumVariantQuery<'_> {
327    pub fn is_valid(&self, variant: &EnumVariant) -> bool {
328        self.name
329            .as_ref()
330            .map(|name| name.as_ref() == variant.name)
331            .unwrap_or(true)
332            && self
333                .fields
334                .iter()
335                .zip(variant.fields.iter())
336                .all(|(query, field)| query.is_valid(field))
337            && self
338                .meta
339                .as_ref()
340                .map(|query| variant.meta.as_ref().map(query).unwrap_or(false))
341                .unwrap_or(true)
342    }
343
344    pub fn to_static(&self) -> EnumVariantQuery<'static> {
345        EnumVariantQuery {
346            name: self
347                .name
348                .as_ref()
349                .map(|name| name.as_ref().to_owned().into()),
350            fields: self
351                .fields
352                .as_ref()
353                .iter()
354                .map(|query| query.to_static())
355                .collect(),
356            meta: self.meta,
357        }
358    }
359}
360
361#[derive(Debug, Default, Clone, PartialEq, Hash)]
362pub enum TypeKindQuery<'a> {
363    #[default]
364    None,
365    Struct {
366        fields: Cow<'a, [StructFieldQuery<'a>]>,
367    },
368    Enum {
369        variants: Cow<'a, [EnumVariantQuery<'a>]>,
370    },
371}
372
373impl TypeKindQuery<'_> {
374    pub fn is_valid(&self, type_: &Type) -> bool {
375        match (self, type_) {
376            (Self::None, _) => true,
377            (Self::Struct { fields }, Type::Struct(type_)) => fields
378                .iter()
379                .zip(type_.fields().iter())
380                .all(|(query, field)| query.is_valid(field)),
381            (Self::Struct { .. }, _) => false,
382            (Self::Enum { variants }, Type::Enum(type_)) => variants
383                .iter()
384                .zip(type_.variants().iter())
385                .all(|(query, variant)| query.is_valid(variant)),
386            (Self::Enum { .. }, _) => false,
387        }
388    }
389
390    pub fn to_static(&self) -> TypeKindQuery<'static> {
391        match self {
392            Self::None => TypeKindQuery::None,
393            Self::Struct { fields } => TypeKindQuery::Struct {
394                fields: fields
395                    .as_ref()
396                    .iter()
397                    .map(|query| query.to_static())
398                    .collect(),
399            },
400            Self::Enum { variants } => TypeKindQuery::Enum {
401                variants: variants
402                    .as_ref()
403                    .iter()
404                    .map(|query| query.to_static())
405                    .collect(),
406            },
407        }
408    }
409}
410
411#[derive(Debug, Default, Clone, PartialEq, Hash)]
412pub struct TypeQuery<'a> {
413    pub name: Option<Cow<'a, str>>,
414    pub module_name: Option<Cow<'a, str>>,
415    pub type_hash: Option<TypeHash>,
416    pub type_name: Option<Cow<'a, str>>,
417    pub visibility: Option<Visibility>,
418    pub kind: TypeKindQuery<'a>,
419    pub meta: Option<MetaQuery>,
420}
421
422impl<'a> TypeQuery<'a> {
423    pub fn of_type_name<T: 'static>() -> Self {
424        Self {
425            type_name: Some(std::any::type_name::<T>().into()),
426            ..Default::default()
427        }
428    }
429
430    pub fn of<T: 'static>() -> Self {
431        Self {
432            type_hash: Some(TypeHash::of::<T>()),
433            ..Default::default()
434        }
435    }
436
437    pub fn of_named<T: 'static>(name: &'a str) -> Self {
438        Self {
439            name: Some(name.into()),
440            type_hash: Some(TypeHash::of::<T>()),
441            ..Default::default()
442        }
443    }
444
445    pub fn is_valid(&self, type_: &Type) -> bool {
446        self.name
447            .as_ref()
448            .map(|name| name.as_ref() == type_.name())
449            .unwrap_or(true)
450            && self
451                .module_name
452                .as_ref()
453                .map(|name| {
454                    type_
455                        .module_name()
456                        .as_ref()
457                        .map(|module_name| name.as_ref() == *module_name)
458                        .unwrap_or(false)
459                })
460                .unwrap_or(true)
461            && self
462                .type_hash
463                .map(|type_hash| type_.type_hash() == type_hash)
464                .unwrap_or(true)
465            && self
466                .type_name
467                .as_ref()
468                .map(|type_name| type_.type_name() == type_name.as_ref())
469                .unwrap_or(true)
470            && self
471                .visibility
472                .map(|visibility| type_.visibility().is_visible(visibility))
473                .unwrap_or(true)
474            && self.kind.is_valid(type_)
475            && self
476                .meta
477                .as_ref()
478                .map(|query| {
479                    type_
480                        .meta()
481                        .as_ref()
482                        .map(|meta| query(meta))
483                        .unwrap_or(false)
484                })
485                .unwrap_or(true)
486    }
487
488    pub fn as_hash(&self) -> u64 {
489        let mut hasher = FxHasher::default();
490        self.hash(&mut hasher);
491        hasher.finish()
492    }
493
494    pub fn to_static(&self) -> TypeQuery<'static> {
495        TypeQuery {
496            name: self
497                .name
498                .as_ref()
499                .map(|name| name.as_ref().to_owned().into()),
500            module_name: self
501                .module_name
502                .as_ref()
503                .map(|name| name.as_ref().to_owned().into()),
504            type_hash: self.type_hash,
505            type_name: self
506                .type_name
507                .as_ref()
508                .map(|name| name.as_ref().to_owned().into()),
509            visibility: self.visibility,
510            kind: self.kind.to_static(),
511            meta: self.meta,
512        }
513    }
514}