1use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub struct StructLayoutId(pub u32);
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19pub struct EnumLayoutId(pub u32);
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub struct ClosureTypeId(pub u32);
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
27pub struct FunctionTypeId(pub u32);
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
37pub enum ConcreteType {
38 F64,
40 F32,
45 Char,
50 I64,
52 I32,
54 I16,
56 I8,
58 U64,
60 U32,
62 U16,
64 U8,
66 Bool,
68 String,
70 Struct(StructLayoutId),
72 Array(Box<ConcreteType>),
75 HashMap(Box<ConcreteType>, Box<ConcreteType>),
77 Option(Box<ConcreteType>),
79 Result(Box<ConcreteType>, Box<ConcreteType>),
81 Enum(EnumLayoutId),
83 Closure(ClosureTypeId),
85 Function(FunctionTypeId),
87 Pointer(Box<ConcreteType>),
89 Tuple(Vec<ConcreteType>),
91 Void,
93 Decimal,
95 BigInt,
97 DateTime,
99 HashSet(Box<ConcreteType>),
126 Deque(Box<ConcreteType>),
133 PriorityQueue,
138 Channel(Box<ConcreteType>),
144 Mutex(Box<ConcreteType>),
151 Atomic,
157 Lazy(Box<ConcreteType>),
162}
163
164impl ConcreteType {
165 #[inline]
167 pub fn stack_size(&self) -> usize {
168 8 }
170
171 #[inline]
173 pub fn alignment(&self) -> usize {
174 match self {
175 ConcreteType::I8 | ConcreteType::U8 | ConcreteType::Bool => 1,
176 ConcreteType::I16 | ConcreteType::U16 => 2,
177 ConcreteType::I32
180 | ConcreteType::U32
181 | ConcreteType::F32
182 | ConcreteType::Char => 4,
183 _ => 8, }
185 }
186
187 #[inline]
189 pub fn field_size(&self) -> usize {
190 match self {
191 ConcreteType::I8 | ConcreteType::U8 | ConcreteType::Bool => 1,
192 ConcreteType::I16 | ConcreteType::U16 => 2,
193 ConcreteType::I32
196 | ConcreteType::U32
197 | ConcreteType::F32
198 | ConcreteType::Char => 4,
199 _ => 8,
200 }
201 }
202
203 #[inline]
205 pub fn is_numeric(&self) -> bool {
206 matches!(
207 self,
208 ConcreteType::F64
209 | ConcreteType::F32
210 | ConcreteType::I64
211 | ConcreteType::I32
212 | ConcreteType::I16
213 | ConcreteType::I8
214 | ConcreteType::U64
215 | ConcreteType::U32
216 | ConcreteType::U16
217 | ConcreteType::U8
218 | ConcreteType::Decimal
219 | ConcreteType::BigInt
220 )
221 }
222
223 #[inline]
225 pub fn is_integer(&self) -> bool {
226 matches!(
227 self,
228 ConcreteType::I64
229 | ConcreteType::I32
230 | ConcreteType::I16
231 | ConcreteType::I8
232 | ConcreteType::U64
233 | ConcreteType::U32
234 | ConcreteType::U16
235 | ConcreteType::U8
236 )
237 }
238
239 #[inline]
241 pub fn is_heap(&self) -> bool {
242 matches!(
243 self,
244 ConcreteType::String
245 | ConcreteType::Struct(_)
246 | ConcreteType::Array(_)
247 | ConcreteType::HashMap(_, _)
248 | ConcreteType::Enum(_)
249 | ConcreteType::Closure(_)
250 | ConcreteType::Pointer(_)
251 | ConcreteType::BigInt
252 | ConcreteType::Decimal
253 | ConcreteType::DateTime
254 | ConcreteType::HashSet(_)
260 | ConcreteType::Deque(_)
261 | ConcreteType::PriorityQueue
262 | ConcreteType::Channel(_)
263 | ConcreteType::Mutex(_)
264 | ConcreteType::Atomic
265 | ConcreteType::Lazy(_)
266 )
267 }
268
269 #[inline]
271 pub fn is_scalar(&self) -> bool {
272 matches!(
273 self,
274 ConcreteType::F64
275 | ConcreteType::F32
276 | ConcreteType::I64
277 | ConcreteType::I32
278 | ConcreteType::I16
279 | ConcreteType::I8
280 | ConcreteType::U64
281 | ConcreteType::U32
282 | ConcreteType::U16
283 | ConcreteType::U8
284 | ConcreteType::Bool
285 | ConcreteType::Char
286 )
287 }
288
289 pub fn to_field_kind(&self) -> super::struct_layout::FieldKind {
291 use super::struct_layout::FieldKind;
292 match self {
293 ConcreteType::F64 => FieldKind::F64,
294 ConcreteType::I64 => FieldKind::I64,
295 ConcreteType::I32 => FieldKind::I32,
296 ConcreteType::I16 => FieldKind::I16,
297 ConcreteType::I8 => FieldKind::I8,
298 ConcreteType::U64 => FieldKind::U64,
299 ConcreteType::U32 => FieldKind::U32,
300 ConcreteType::U16 => FieldKind::U16,
301 ConcreteType::U8 => FieldKind::U8,
302 ConcreteType::Bool => FieldKind::Bool,
303 ConcreteType::F32 | ConcreteType::Char => FieldKind::U32,
314 _ => FieldKind::Ptr,
316 }
317 }
318
319 pub fn mono_key(&self) -> String {
322 match self {
323 ConcreteType::F64 => "f64".into(),
324 ConcreteType::F32 => "f32".into(),
325 ConcreteType::Char => "char".into(),
326 ConcreteType::I64 => "i64".into(),
327 ConcreteType::I32 => "i32".into(),
328 ConcreteType::I16 => "i16".into(),
329 ConcreteType::I8 => "i8".into(),
330 ConcreteType::U64 => "u64".into(),
331 ConcreteType::U32 => "u32".into(),
332 ConcreteType::U16 => "u16".into(),
333 ConcreteType::U8 => "u8".into(),
334 ConcreteType::Bool => "bool".into(),
335 ConcreteType::String => "string".into(),
336 ConcreteType::Struct(id) => format!("struct_{}", id.0),
337 ConcreteType::Array(elem) => format!("array_{}", elem.mono_key()),
338 ConcreteType::HashMap(k, v) => {
339 format!("hashmap_{}_{}", k.mono_key(), v.mono_key())
340 }
341 ConcreteType::Option(inner) => format!("option_{}", inner.mono_key()),
342 ConcreteType::Result(ok, err) => {
343 format!("result_{}_{}", ok.mono_key(), err.mono_key())
344 }
345 ConcreteType::Enum(id) => format!("enum_{}", id.0),
346 ConcreteType::Closure(id) => format!("closure_{}", id.0),
347 ConcreteType::Function(id) => format!("fn_{}", id.0),
348 ConcreteType::Pointer(inner) => format!("ptr_{}", inner.mono_key()),
349 ConcreteType::Tuple(elems) => {
350 let parts: Vec<_> = elems.iter().map(|e| e.mono_key()).collect();
351 format!("tuple_{}", parts.join("_"))
352 }
353 ConcreteType::Void => "void".into(),
354 ConcreteType::Decimal => "decimal".into(),
355 ConcreteType::BigInt => "bigint".into(),
356 ConcreteType::DateTime => "datetime".into(),
357 ConcreteType::HashSet(elem) => format!("hashset_{}", elem.mono_key()),
359 ConcreteType::Deque(elem) => format!("deque_{}", elem.mono_key()),
360 ConcreteType::PriorityQueue => "priority_queue".into(),
361 ConcreteType::Channel(elem) => format!("channel_{}", elem.mono_key()),
362 ConcreteType::Mutex(inner) => format!("mutex_{}", inner.mono_key()),
363 ConcreteType::Atomic => "atomic".into(),
364 ConcreteType::Lazy(inner) => format!("lazy_{}", inner.mono_key()),
365 }
366 }
367
368 pub fn type_tag(&self) -> u8 {
370 match self {
371 ConcreteType::F64 => 0,
372 ConcreteType::I64 => 1,
373 ConcreteType::I32 => 2,
374 ConcreteType::I16 => 3,
375 ConcreteType::I8 => 4,
376 ConcreteType::U64 => 5,
377 ConcreteType::U32 => 6,
378 ConcreteType::U16 => 7,
379 ConcreteType::U8 => 8,
380 ConcreteType::Bool => 9,
381 ConcreteType::String => 10,
382 ConcreteType::Struct(_) => 11,
383 ConcreteType::Array(_) => 12,
384 ConcreteType::HashMap(_, _) => 13,
385 ConcreteType::Option(_) => 14,
386 ConcreteType::Result(_, _) => 15,
387 ConcreteType::Enum(_) => 16,
388 ConcreteType::Closure(_) => 17,
389 ConcreteType::Function(_) => 18,
390 ConcreteType::Pointer(_) => 19,
391 ConcreteType::Tuple(_) => 20,
392 ConcreteType::Void => 21,
393 ConcreteType::Decimal => 22,
394 ConcreteType::BigInt => 23,
395 ConcreteType::DateTime => 24,
396 ConcreteType::HashSet(_) => 25,
398 ConcreteType::Deque(_) => 26,
399 ConcreteType::PriorityQueue => 27,
400 ConcreteType::Channel(_) => 28,
401 ConcreteType::Mutex(_) => 29,
402 ConcreteType::Atomic => 30,
403 ConcreteType::Lazy(_) => 31,
404 ConcreteType::F32 => 32,
409 ConcreteType::Char => 33,
410 }
411 }
412}
413
414impl From<super::struct_layout::FieldKind> for ConcreteType {
416 fn from(fk: super::struct_layout::FieldKind) -> Self {
417 use super::struct_layout::FieldKind;
418 match fk {
419 FieldKind::F64 => ConcreteType::F64,
420 FieldKind::I64 => ConcreteType::I64,
421 FieldKind::I32 => ConcreteType::I32,
422 FieldKind::I16 => ConcreteType::I16,
423 FieldKind::I8 => ConcreteType::I8,
424 FieldKind::U64 => ConcreteType::U64,
425 FieldKind::U32 => ConcreteType::U32,
426 FieldKind::U16 => ConcreteType::U16,
427 FieldKind::U8 => ConcreteType::U8,
428 FieldKind::Bool => ConcreteType::Bool,
429 FieldKind::Ptr => ConcreteType::Pointer(Box::new(ConcreteType::Void)),
431 }
432 }
433}
434
435impl std::fmt::Display for ConcreteType {
436 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437 match self {
438 ConcreteType::F64 => write!(f, "number"),
439 ConcreteType::F32 => write!(f, "f32"),
440 ConcreteType::Char => write!(f, "char"),
441 ConcreteType::I64 => write!(f, "int"),
442 ConcreteType::I32 => write!(f, "i32"),
443 ConcreteType::I16 => write!(f, "i16"),
444 ConcreteType::I8 => write!(f, "i8"),
445 ConcreteType::U64 => write!(f, "u64"),
446 ConcreteType::U32 => write!(f, "u32"),
447 ConcreteType::U16 => write!(f, "u16"),
448 ConcreteType::U8 => write!(f, "u8"),
449 ConcreteType::Bool => write!(f, "bool"),
450 ConcreteType::String => write!(f, "string"),
451 ConcreteType::Struct(id) => write!(f, "Struct#{}", id.0),
452 ConcreteType::Array(elem) => write!(f, "Array<{elem}>"),
453 ConcreteType::HashMap(k, v) => write!(f, "HashMap<{k}, {v}>"),
454 ConcreteType::Option(inner) => write!(f, "{inner}?"),
455 ConcreteType::Result(ok, err) => write!(f, "Result<{ok}, {err}>"),
456 ConcreteType::Enum(id) => write!(f, "Enum#{}", id.0),
457 ConcreteType::Closure(id) => write!(f, "Closure#{}", id.0),
458 ConcreteType::Function(id) => write!(f, "Function#{}", id.0),
459 ConcreteType::Pointer(inner) => write!(f, "ptr<{inner}>"),
460 ConcreteType::Tuple(elems) => {
461 write!(f, "(")?;
462 for (i, e) in elems.iter().enumerate() {
463 if i > 0 {
464 write!(f, ", ")?;
465 }
466 write!(f, "{e}")?;
467 }
468 write!(f, ")")
469 }
470 ConcreteType::Void => write!(f, "void"),
471 ConcreteType::Decimal => write!(f, "decimal"),
472 ConcreteType::BigInt => write!(f, "bigint"),
473 ConcreteType::DateTime => write!(f, "DateTime"),
474 ConcreteType::HashSet(elem) => write!(f, "HashSet<{elem}>"),
476 ConcreteType::Deque(elem) => write!(f, "Deque<{elem}>"),
477 ConcreteType::PriorityQueue => write!(f, "PriorityQueue"),
478 ConcreteType::Channel(elem) => write!(f, "Channel<{elem}>"),
479 ConcreteType::Mutex(inner) => write!(f, "Mutex<{inner}>"),
480 ConcreteType::Atomic => write!(f, "Atomic"),
481 ConcreteType::Lazy(inner) => write!(f, "Lazy<{inner}>"),
482 }
483 }
484}
485
486#[cfg(test)]
487mod tests {
488 use super::*;
489
490 #[test]
491 fn test_mono_key_primitives() {
492 assert_eq!(ConcreteType::F64.mono_key(), "f64");
493 assert_eq!(ConcreteType::I64.mono_key(), "i64");
494 assert_eq!(ConcreteType::Bool.mono_key(), "bool");
495 assert_eq!(ConcreteType::String.mono_key(), "string");
496 }
497
498 #[test]
499 fn test_mono_key_composites() {
500 let arr_f64 = ConcreteType::Array(Box::new(ConcreteType::F64));
501 assert_eq!(arr_f64.mono_key(), "array_f64");
502
503 let map = ConcreteType::HashMap(
504 Box::new(ConcreteType::String),
505 Box::new(ConcreteType::I64),
506 );
507 assert_eq!(map.mono_key(), "hashmap_string_i64");
508
509 let nested = ConcreteType::Array(Box::new(ConcreteType::Array(Box::new(
510 ConcreteType::I32,
511 ))));
512 assert_eq!(nested.mono_key(), "array_array_i32");
513 }
514
515 #[test]
516 fn test_type_tags_unique() {
517 let types = vec![
518 ConcreteType::F64,
519 ConcreteType::I64,
520 ConcreteType::I32,
521 ConcreteType::I16,
522 ConcreteType::I8,
523 ConcreteType::U64,
524 ConcreteType::U32,
525 ConcreteType::U16,
526 ConcreteType::U8,
527 ConcreteType::Bool,
528 ConcreteType::String,
529 ConcreteType::Struct(StructLayoutId(0)),
530 ConcreteType::Array(Box::new(ConcreteType::F64)),
531 ConcreteType::HashMap(Box::new(ConcreteType::String), Box::new(ConcreteType::F64)),
532 ConcreteType::Option(Box::new(ConcreteType::I64)),
533 ConcreteType::Result(Box::new(ConcreteType::I64), Box::new(ConcreteType::String)),
534 ConcreteType::Enum(EnumLayoutId(0)),
535 ConcreteType::Closure(ClosureTypeId(0)),
536 ConcreteType::Function(FunctionTypeId(0)),
537 ConcreteType::Pointer(Box::new(ConcreteType::U8)),
538 ConcreteType::Tuple(vec![ConcreteType::I64, ConcreteType::F64]),
539 ConcreteType::Void,
540 ConcreteType::Decimal,
541 ConcreteType::BigInt,
542 ConcreteType::DateTime,
543 ConcreteType::HashSet(Box::new(ConcreteType::String)),
545 ConcreteType::Deque(Box::new(ConcreteType::I64)),
546 ConcreteType::PriorityQueue,
547 ConcreteType::Channel(Box::new(ConcreteType::I64)),
548 ConcreteType::Mutex(Box::new(ConcreteType::I64)),
549 ConcreteType::Atomic,
550 ConcreteType::Lazy(Box::new(ConcreteType::I64)),
551 ConcreteType::F32,
553 ConcreteType::Char,
554 ];
555 let tags: Vec<u8> = types.iter().map(|t| t.type_tag()).collect();
556 let unique: std::collections::HashSet<u8> = tags.iter().copied().collect();
557 assert_eq!(tags.len(), unique.len(), "type tags must be unique");
558 }
559
560 #[test]
563 fn test_round_19_f32_char_scalars() {
564 assert_eq!(ConcreteType::F32.mono_key(), "f32");
565 assert_eq!(ConcreteType::Char.mono_key(), "char");
566 assert_eq!(format!("{}", ConcreteType::F32), "f32");
567 assert_eq!(format!("{}", ConcreteType::Char), "char");
568 assert_eq!(ConcreteType::F32.alignment(), 4);
570 assert_eq!(ConcreteType::F32.field_size(), 4);
571 assert_eq!(ConcreteType::Char.alignment(), 4);
572 assert_eq!(ConcreteType::Char.field_size(), 4);
573 assert!(ConcreteType::F32.is_scalar());
576 assert!(ConcreteType::Char.is_scalar());
577 assert!(ConcreteType::F32.is_numeric());
578 assert!(!ConcreteType::Char.is_numeric());
579 assert!(!ConcreteType::F32.is_integer());
580 assert!(!ConcreteType::Char.is_integer());
581 assert!(!ConcreteType::F32.is_heap());
583 assert!(!ConcreteType::Char.is_heap());
584 }
585
586 #[test]
587 fn test_round_11_collection_concurrency_arms_mono_key_and_display() {
588 let hs = ConcreteType::HashSet(Box::new(ConcreteType::String));
591 assert_eq!(hs.mono_key(), "hashset_string");
592 assert_eq!(format!("{hs}"), "HashSet<string>");
593
594 let dq = ConcreteType::Deque(Box::new(ConcreteType::I64));
595 assert_eq!(dq.mono_key(), "deque_i64");
596 assert_eq!(format!("{dq}"), "Deque<int>");
597
598 let pq = ConcreteType::PriorityQueue;
599 assert_eq!(pq.mono_key(), "priority_queue");
600 assert_eq!(format!("{pq}"), "PriorityQueue");
601
602 let ch = ConcreteType::Channel(Box::new(ConcreteType::I64));
603 assert_eq!(ch.mono_key(), "channel_i64");
604 assert_eq!(format!("{ch}"), "Channel<int>");
605
606 let mx = ConcreteType::Mutex(Box::new(ConcreteType::I64));
607 assert_eq!(mx.mono_key(), "mutex_i64");
608 assert_eq!(format!("{mx}"), "Mutex<int>");
609
610 let at = ConcreteType::Atomic;
611 assert_eq!(at.mono_key(), "atomic");
612 assert_eq!(format!("{at}"), "Atomic");
613
614 let lz = ConcreteType::Lazy(Box::new(ConcreteType::Bool));
615 assert_eq!(lz.mono_key(), "lazy_bool");
616 assert_eq!(format!("{lz}"), "Lazy<bool>");
617 }
618
619 #[test]
620 fn test_round_11_arms_are_heap() {
621 assert!(ConcreteType::HashSet(Box::new(ConcreteType::String)).is_heap());
624 assert!(ConcreteType::Deque(Box::new(ConcreteType::I64)).is_heap());
625 assert!(ConcreteType::PriorityQueue.is_heap());
626 assert!(ConcreteType::Channel(Box::new(ConcreteType::I64)).is_heap());
627 assert!(ConcreteType::Mutex(Box::new(ConcreteType::I64)).is_heap());
628 assert!(ConcreteType::Atomic.is_heap());
629 assert!(ConcreteType::Lazy(Box::new(ConcreteType::I64)).is_heap());
630
631 assert!(!ConcreteType::HashSet(Box::new(ConcreteType::String)).is_scalar());
633 assert!(!ConcreteType::Mutex(Box::new(ConcreteType::I64)).is_numeric());
634 assert!(!ConcreteType::Atomic.is_integer());
635 }
636
637 #[test]
638 fn test_field_kind_roundtrip() {
639 use super::super::struct_layout::FieldKind;
640 let kinds = [
641 FieldKind::F64,
642 FieldKind::I64,
643 FieldKind::I32,
644 FieldKind::I16,
645 FieldKind::I8,
646 FieldKind::U64,
647 FieldKind::U32,
648 FieldKind::U16,
649 FieldKind::U8,
650 FieldKind::Bool,
651 ];
652 for kind in kinds {
653 let ct = ConcreteType::from(kind);
654 let back = ct.to_field_kind();
655 assert_eq!(kind, back);
656 }
657 }
658
659 #[test]
660 fn test_is_numeric() {
661 assert!(ConcreteType::F64.is_numeric());
662 assert!(ConcreteType::I64.is_numeric());
663 assert!(ConcreteType::U8.is_numeric());
664 assert!(ConcreteType::Decimal.is_numeric());
665 assert!(!ConcreteType::Bool.is_numeric());
666 assert!(!ConcreteType::String.is_numeric());
667 }
668
669 #[test]
670 fn test_is_heap() {
671 assert!(ConcreteType::String.is_heap());
672 assert!(ConcreteType::Array(Box::new(ConcreteType::F64)).is_heap());
673 assert!(!ConcreteType::F64.is_heap());
674 assert!(!ConcreteType::Bool.is_heap());
675 }
676
677 #[test]
678 fn test_display() {
679 assert_eq!(format!("{}", ConcreteType::F64), "number");
680 assert_eq!(format!("{}", ConcreteType::I64), "int");
681 assert_eq!(
682 format!("{}", ConcreteType::Array(Box::new(ConcreteType::F64))),
683 "Array<number>"
684 );
685 assert_eq!(
686 format!("{}", ConcreteType::Option(Box::new(ConcreteType::I64))),
687 "int?"
688 );
689 }
690}