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 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 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 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 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 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 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}