1use seq_map::SeqMap;
8use std::cmp::max;
9use std::rc::Rc;
10use swamp_symbol::TopLevelSymbolId;
11use swamp_types::prelude::{AnonymousStructType, EnumType, EnumVariantType, NamedStructType};
12use swamp_types::{TypeId, TypeKind, TypeRef};
13use swamp_vm_isa::{
14 ANY_HEADER_ALIGNMENT, ANY_HEADER_SIZE, GRID_HEADER_ALIGNMENT, GRID_HEADER_SIZE,
15 MAP_HEADER_ALIGNMENT, MemoryAlignment, MemoryOffset, MemorySize, PTR_ALIGNMENT, PTR_SIZE,
16 STRING_PTR_ALIGNMENT, STRING_PTR_SIZE, VEC_HEADER_ALIGNMENT, VEC_HEADER_SIZE,
17};
18use swamp_vm_types::types::{
19 BasicType, BasicTypeId, BasicTypeKind, BasicTypeRef, OffsetMemoryItem, StructType, TaggedUnion,
20 TaggedUnionVariant, TupleType,
21};
22use swamp_vm_types::{CountU16, adjust_size_to_alignment, align_to};
23
24#[derive(Clone)]
25pub struct LayoutCache {
26 pub id_to_layout: SeqMap<TypeId, BasicTypeRef>,
27 pub kind_to_layout: SeqMap<TypeKind, BasicTypeRef>,
28 pub universal_id_to_layout: SeqMap<u64, BasicTypeRef>,
29 pub universal_short_id_to_layout: SeqMap<u32, BasicTypeRef>,
30}
31
32impl LayoutCache {}
33
34impl Default for LayoutCache {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl LayoutCache {
41 #[must_use]
42 pub fn new() -> Self {
43 Self {
44 id_to_layout: SeqMap::default(),
45 kind_to_layout: SeqMap::default(),
46 universal_id_to_layout: SeqMap::default(),
47 universal_short_id_to_layout: SeqMap::default(),
48 }
49 }
50
51 #[must_use]
52 pub fn layout(&mut self, analyzed_type: &TypeRef) -> BasicTypeRef {
53 if let Some(x) = self.id_to_layout.get(&analyzed_type.id) {
55 return x.clone();
56 }
57
58 if let Some(existing_layout) = self.kind_to_layout.get(&analyzed_type.kind).cloned() {
60 self.insert_layout(analyzed_type.id, existing_layout.clone());
63 return existing_layout;
64 }
65
66 let basic_type = self.layout_type(analyzed_type);
67
68 self.insert_layout(analyzed_type.id, basic_type.clone());
69
70 let _ = self
72 .kind_to_layout
73 .insert((*analyzed_type.kind).clone(), basic_type.clone());
74
75 basic_type
76 }
77
78 #[must_use]
79 fn layout_tagged_union(variants: &[TaggedUnionVariant], name: &str) -> TaggedUnion {
80 let num_variants = variants.len();
81 let (tag_size, tag_alignment) = if num_variants <= 0xFF {
82 (MemorySize(1), MemoryAlignment::U8)
83 } else if num_variants <= 0xFFFF {
84 (MemorySize(2), MemoryAlignment::U16)
85 } else {
86 (MemorySize(4), MemoryAlignment::U32)
87 };
88
89 let max_payload_size = variants
91 .iter()
92 .map(|v| v.ty.total_size)
93 .max()
94 .unwrap_or(MemorySize(0));
95 let max_payload_alignment = variants
96 .iter()
97 .map(|v| v.ty.max_alignment)
98 .max()
99 .unwrap_or(MemoryAlignment::U8);
100
101 let max_alignment = max(tag_alignment, max_payload_alignment);
103 let payload_offset = align_to(MemoryOffset(tag_size.0), max_payload_alignment);
104
105 let complete_size_before_alignment = MemorySize(payload_offset.0 + max_payload_size.0);
106 let total_size = adjust_size_to_alignment(complete_size_before_alignment, max_alignment);
107
108 TaggedUnion {
109 name: name.to_string(),
110 tag_offset: MemoryOffset(0),
111 tag_size,
112 tag_alignment,
113 payload_offset,
114 payload_max_size: max_payload_size,
115 max_payload_alignment,
116 total_size,
117 max_alignment,
118 variants: variants.to_vec(),
119 }
120 }
121
122 #[allow(clippy::too_many_lines)]
123 #[must_use]
124 pub fn layout_enum_into_tagged_union(
125 &mut self,
126 name: &str,
127 v: &[EnumVariantType],
128 ) -> TaggedUnion {
129 let variant_layouts: Vec<_> = v
130 .iter()
131 .map(|variant| {
132 let gen_payload_type = self.layout_type(&variant.payload_type);
133
134 TaggedUnionVariant {
135 name: variant.common.assigned_name.clone(),
136 ty: gen_payload_type,
137 }
138 })
139 .collect();
140
141 Self::layout_tagged_union(&variant_layouts, name)
142 }
143
144 #[must_use]
145 pub fn layout_enum(
146 &mut self,
147 name: &str,
148 variants: &[EnumVariantType],
149 type_id: TypeId,
150 symbol_id: TopLevelSymbolId,
151 ) -> BasicTypeRef {
152 let enum_kind = TypeKind::Enum(EnumType::new(
154 source_map_node::Node::default(),
155 name,
156 symbol_id,
157 vec![String::new()],
158 ));
159 if let Some(existing_layout) = self.kind_to_layout.get(&enum_kind) {
160 return existing_layout.clone();
161 }
162
163 let tagged_union = self.layout_enum_into_tagged_union(name, variants);
164
165 let basic_type = Rc::new(BasicType {
166 id: BasicTypeId(type_id.inner()),
167 total_size: tagged_union.total_size,
168 max_alignment: tagged_union.max_alignment,
169 kind: BasicTypeKind::TaggedUnion(tagged_union),
170 });
171
172 let _ = self.kind_to_layout.insert(enum_kind, basic_type.clone());
174
175 basic_type
176 }
177
178 #[must_use]
179 fn layout_vec_like(
180 &mut self,
181 element_type: &TypeRef,
182 capacity: usize,
183 ) -> (BasicTypeRef, MemorySize, MemoryAlignment) {
184 let element_type_basic = self.layout_type(element_type);
185 let (mem_size, mem_alignment) =
186 self.layout_vec_like_from_basic(&element_type_basic, capacity);
187
188 (element_type_basic, mem_size, mem_alignment)
189 }
190
191 #[must_use]
192 fn layout_vec_like_from_basic(
193 &mut self,
194 element_type_basic: &BasicTypeRef,
195 capacity: usize,
196 ) -> (MemorySize, MemoryAlignment) {
197 let total_size =
198 element_type_basic.total_size.0 as usize * capacity + VEC_HEADER_SIZE.0 as usize;
199 let max_alignment = max(element_type_basic.max_alignment, MemoryAlignment::U32);
200
201 (MemorySize(total_size as u32), max_alignment)
202 }
203
204 #[allow(clippy::too_many_lines)]
230 #[must_use]
231 fn layout_type(&mut self, ty: &TypeRef) -> BasicTypeRef {
232 if let Some(x) = self.id_to_layout.get(&ty.id) {
234 return x.clone();
235 }
236
237 if let Some(existing_layout) = self.kind_to_layout.get(&ty.kind) {
239 let new_basic_type = Rc::new(BasicType {
243 id: BasicTypeId(ty.id.inner()),
244 total_size: existing_layout.total_size,
245 max_alignment: existing_layout.max_alignment,
246 kind: existing_layout.kind.clone(),
247 });
248
249 self.insert_layout(ty.id, new_basic_type.clone());
251
252 match &*ty.kind {
255 TypeKind::AnonymousStruct(struct_type) => {
256 for field in struct_type.field_name_sorted_fields.values() {
258 let field_type = &field.field_type;
259 let field_layout = self.layout(field_type);
260 let _ = self.id_to_layout.insert(field_type.id, field_layout);
261 }
262 }
263
264 TypeKind::NamedStruct(named_struct) => {
265 if let TypeKind::AnonymousStruct(anon_struct) =
267 &*named_struct.anon_struct_type.kind
268 {
269 for field in anon_struct.field_name_sorted_fields.values() {
270 let field_type = &field.field_type;
271 let field_layout = self.layout(field_type);
272 self.insert_layout(field_type.id, field_layout);
273 }
274 }
275 }
276
277 TypeKind::Tuple(tuple_types) => {
278 for elem_type in tuple_types {
280 let elem_layout = self.layout(elem_type);
281 self.insert_layout(elem_type.id, elem_layout);
282 }
283 }
284 _ => {}
285 }
286
287 return new_basic_type;
288 }
289
290 let basic_type = match &*ty.kind {
291 TypeKind::Never => {
292 create_basic_type(ty.id, BasicTypeKind::U8, MemorySize(0), MemoryAlignment::U8)
293 }
294 TypeKind::Pointer(_) => create_basic_type(
295 ty.id,
296 BasicTypeKind::Pointer,
297 MemorySize(4),
298 MemoryAlignment::U32,
299 ),
300 TypeKind::Byte => {
301 create_basic_type(ty.id, BasicTypeKind::U8, MemorySize(1), MemoryAlignment::U8)
302 }
303 TypeKind::Short => create_basic_type(
304 ty.id,
305 BasicTypeKind::U16,
306 MemorySize(2),
307 MemoryAlignment::U16,
308 ),
309 TypeKind::Codepoint => create_basic_type(
310 ty.id,
311 BasicTypeKind::U32,
312 MemorySize(4),
313 MemoryAlignment::U32,
314 ),
315 TypeKind::Int => create_basic_type(
316 ty.id,
317 BasicTypeKind::S32,
318 MemorySize(4),
319 MemoryAlignment::U32,
320 ),
321
322 TypeKind::Float => create_basic_type(
323 ty.id,
324 BasicTypeKind::Fixed32,
325 MemorySize(4),
326 MemoryAlignment::U32,
327 ),
328
329 TypeKind::Bool => {
330 create_basic_type(ty.id, BasicTypeKind::B8, MemorySize(1), MemoryAlignment::U8)
331 }
332
333 TypeKind::StringView(byte, char) => create_basic_type(
334 ty.id,
335 BasicTypeKind::StringView {
336 byte: self.layout(byte),
337 char: self.layout(char),
338 },
339 STRING_PTR_SIZE,
340 STRING_PTR_ALIGNMENT,
341 ),
342
343 TypeKind::AnonymousStruct(struct_type) => {
344 self.layout_struct(struct_type, "anonymous", ty.id)
345 }
346
347 TypeKind::NamedStruct(named_struct) => self.layout_named_struct(named_struct, ty.id),
348
349 TypeKind::Tuple(tuple_types) => self.layout_tuple(tuple_types, ty.id),
350
351 TypeKind::Optional(inner_type) => self.layout_optional_type(inner_type, ty.id),
352
353 TypeKind::Enum(enum_type) => {
354 let variants = enum_type.variants.values().cloned().collect::<Vec<_>>();
355 self.layout_enum(
356 &enum_type.assigned_name,
357 &variants,
358 ty.id,
359 enum_type.symbol_id,
360 )
361 }
362
363 TypeKind::FixedCapacityAndLengthArray(element_type, capacity) => {
364 let (element_layout, total_size, max_alignment) =
365 self.layout_vec_like(element_type, *capacity);
366
367 let array_type = Rc::new(BasicType {
368 id: BasicTypeId(ty.id.inner()),
369 kind: BasicTypeKind::FixedCapacityArray(element_layout.clone(), *capacity),
370 total_size,
371 max_alignment,
372 });
373
374 self.insert_layout(element_type.id, element_layout);
376
377 array_type
378 }
379
380 TypeKind::StringStorage(byte_type, char_type, capacity) => {
381 let (element_layout, total_size, max_alignment) =
382 self.layout_vec_like(byte_type, *capacity);
383
384 let array_type = Rc::new(BasicType {
385 id: BasicTypeId(ty.id.inner()),
386 kind: BasicTypeKind::StringStorage {
387 element_type: element_layout.clone(),
388 char: self.layout(char_type),
389 capacity: *capacity,
390 },
391 total_size,
392 max_alignment,
393 });
394
395 self.insert_layout(byte_type.id, element_layout);
397
398 array_type
399 }
400
401 TypeKind::Any => create_basic_type(
402 ty.id,
403 BasicTypeKind::Any,
404 ANY_HEADER_SIZE,
405 ANY_HEADER_ALIGNMENT,
406 ),
407
408 TypeKind::DynamicLengthVecView(element_type) => {
409 let (element_layout, _, _) = self.layout_vec_like(element_type, 0);
410
411 let vec_type = Rc::new(BasicType {
412 id: BasicTypeId(ty.id.inner()),
413 kind: BasicTypeKind::DynamicLengthVecView(element_layout.clone()),
414 total_size: PTR_SIZE,
415 max_alignment: PTR_ALIGNMENT,
416 });
417
418 self.insert_layout(element_type.id, element_layout);
419
420 vec_type
421 }
422
423 TypeKind::VecStorage(element_type, capacity) => {
424 let (element_layout, total_size, element_alignment) =
425 self.layout_vec_like(element_type, *capacity);
426
427 let storage_type = Rc::new(BasicType {
428 id: BasicTypeId(ty.id.inner()),
429 kind: BasicTypeKind::VecStorage(element_layout.clone(), *capacity),
430 total_size,
431 max_alignment: max(VEC_HEADER_ALIGNMENT, element_alignment),
432 });
433
434 self.insert_layout(element_type.id, element_layout);
435
436 storage_type
437 }
438
439 TypeKind::DynamicLengthMapView(key_type, value_type) => {
440 let key_layout = self.layout(key_type);
442 self.insert_layout(key_type.id, key_layout.clone());
443
444 let value_layout = self.layout(value_type);
446 self.insert_layout(value_type.id, value_layout.clone());
447
448 let key_item = OffsetMemoryItem {
449 offset: MemoryOffset(0),
450 size: key_layout.total_size,
451 name: "key".to_string(),
452 ty: key_layout.clone(),
453 };
454
455 let value_offset = align_to(
456 MemoryOffset(key_layout.total_size.0),
457 value_layout.max_alignment,
458 );
459
460 let value_item = OffsetMemoryItem {
461 offset: value_offset,
462 size: value_layout.total_size,
463 name: "value".to_string(),
464 ty: value_layout.clone(),
465 };
466
467 Rc::new(BasicType {
468 id: BasicTypeId(ty.id.inner()),
469 kind: BasicTypeKind::DynamicLengthMapView(
470 Box::new(key_item),
471 Box::new(value_item),
472 ),
473 total_size: PTR_SIZE,
474 max_alignment: PTR_ALIGNMENT,
475 })
476 }
477
478 TypeKind::MapStorage(key_type, value_type, logical_limit) => {
479 let key_layout = self.layout(key_type);
481 self.insert_layout(key_type.id, key_layout.clone());
482
483 let value_layout = self.layout(value_type);
485 self.insert_layout(value_type.id, value_layout.clone());
486
487 let logical_limit = *logical_limit;
488
489 let (_bucket_layout, map_init) = hashmap_mem::layout(
490 key_layout.total_size.0,
491 key_layout.max_alignment.into(),
492 value_layout.total_size.0,
493 value_layout.max_alignment.into(),
494 logical_limit as u16,
495 );
496 let total_size = MemorySize(map_init.total_size);
497
498 Rc::new(BasicType {
499 id: BasicTypeId(ty.id.inner()),
500 kind: BasicTypeKind::MapStorage {
501 key_type: key_layout,
502 logical_limit,
503 capacity: CountU16(map_init.capacity),
504 value_type: value_layout,
505 },
506 total_size,
507 max_alignment: MAP_HEADER_ALIGNMENT,
508 })
509 }
510
511 TypeKind::Range(_range_struct) => create_basic_type(
512 ty.id,
513 BasicTypeKind::InternalRangeHeader,
514 MemorySize(12),
515 MemoryAlignment::U32,
516 ),
517
518 TypeKind::GridView(element_type) => {
519 let element_layout = self.layout(element_type);
520 self.insert_layout(element_type.id, element_layout.clone());
521
522 Rc::new(BasicType {
523 id: BasicTypeId(ty.id.inner()),
524 kind: BasicTypeKind::GridView(element_layout),
525 total_size: PTR_SIZE,
526 max_alignment: PTR_ALIGNMENT,
527 })
528 }
529
530 TypeKind::GridStorage(element_type, width, height) => {
531 let element_layout = self.layout(element_type);
532 self.insert_layout(element_type.id, element_layout.clone());
533
534 let element_size = element_layout.total_size;
535 let element_alignment = element_layout.max_alignment;
536
537 Rc::new(BasicType {
538 id: BasicTypeId(ty.id.inner()),
539 kind: BasicTypeKind::GridStorage(element_layout, *width, *height),
540 total_size: MemorySize(
541 GRID_HEADER_SIZE.0 + element_size.0 * (*width as u32) * (*height as u32),
542 ),
543 max_alignment: max(GRID_HEADER_ALIGNMENT, element_alignment),
544 })
545 }
546
547 TypeKind::SliceView(element_type) => {
548 let element_layout = self.layout(element_type);
549 self.insert_layout(element_type.id, element_layout.clone());
550
551 Rc::new(BasicType {
552 id: BasicTypeId(ty.id.inner()),
553 kind: BasicTypeKind::SliceView(element_layout),
554 total_size: PTR_SIZE,
555 max_alignment: PTR_ALIGNMENT,
556 })
557 }
558
559 TypeKind::SparseStorage(element_type, capacity) => {
560 let element_layout = self.layout(element_type);
561 let size = sparse_mem::layout_size(*capacity as u16, element_layout.total_size.0);
562
563 Rc::new(BasicType {
564 id: BasicTypeId(ty.id.inner()),
565 kind: BasicTypeKind::SparseStorage(element_layout, *capacity),
566 total_size: MemorySize(size as u32),
567 max_alignment: MemoryAlignment::U64,
568 })
569 }
570
571 TypeKind::SparseView(element_type) => {
572 let element_layout = self.layout(element_type);
573 self.insert_layout(element_type.id, element_layout.clone());
574
575 Rc::new(BasicType {
576 id: BasicTypeId(ty.id.inner()),
577 kind: BasicTypeKind::SparseView(element_layout),
578 total_size: PTR_SIZE,
579 max_alignment: PTR_ALIGNMENT,
580 })
581 }
582
583 TypeKind::StackStorage(element_type, capacity) => {
584 let (element_layout, total_size, _max_alignment) =
585 self.layout_vec_like(element_type, *capacity);
586
587 let storage_type = Rc::new(BasicType {
588 id: BasicTypeId(ty.id.inner()),
589 kind: BasicTypeKind::StackStorage(element_layout.clone(), *capacity),
590 total_size,
591 max_alignment: VEC_HEADER_ALIGNMENT,
592 });
593
594 self.insert_layout(element_type.id, element_layout);
595
596 storage_type
597 }
598
599 TypeKind::StackView(element_type) => {
600 let element_layout = self.layout(element_type);
601 self.insert_layout(element_type.id, element_layout.clone());
602
603 Rc::new(BasicType {
604 id: BasicTypeId(ty.id.inner()),
605 kind: BasicTypeKind::DynamicLengthVecView(element_layout),
606 total_size: PTR_SIZE,
607 max_alignment: PTR_ALIGNMENT,
608 })
609 }
610
611 TypeKind::QueueStorage(element_type, capacity) => {
612 let (element_layout, total_size, _max_alignment) =
613 self.layout_vec_like(element_type, *capacity);
614
615 let storage_type = Rc::new(BasicType {
616 id: BasicTypeId(ty.id.inner()),
617 kind: BasicTypeKind::QueueStorage(element_layout.clone(), *capacity),
618 total_size,
619 max_alignment: VEC_HEADER_ALIGNMENT,
620 });
621
622 self.insert_layout(element_type.id, element_layout);
623
624 storage_type
625 }
626
627 TypeKind::QueueView(element_type) => {
628 let element_layout = self.layout(element_type);
629 self.insert_layout(element_type.id, element_layout.clone());
630
631 Rc::new(BasicType {
632 id: BasicTypeId(ty.id.inner()),
633 kind: BasicTypeKind::DynamicLengthVecView(element_layout),
634 total_size: PTR_SIZE,
635 max_alignment: PTR_ALIGNMENT,
636 })
637 }
638
639 TypeKind::Function(_) => {
640 panic!("function types can not be laid out")
641 }
642
643 TypeKind::Unit => create_basic_type(
644 ty.id,
645 BasicTypeKind::Empty,
646 MemorySize(0),
647 MemoryAlignment::U8,
648 ),
649 };
650
651 self.insert_layout(ty.id, basic_type.clone());
653 let _ = self
654 .kind_to_layout
655 .insert((*ty.kind).clone(), basic_type.clone());
656
657 basic_type
658 }
659
660 fn layout_named_struct(
661 &mut self,
662 named_struct_type: &NamedStructType,
663 type_id: TypeId,
664 ) -> BasicTypeRef {
665 let struct_kind = TypeKind::NamedStruct(named_struct_type.clone());
667 if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind) {
668 return existing_layout.clone();
669 }
670
671 let anon_struct = match &*named_struct_type.anon_struct_type.kind {
673 TypeKind::AnonymousStruct(anon_struct) => anon_struct,
674 _ => panic!("Expected AnonymousStruct in NamedStructType"),
675 };
676
677 let inner_struct = self.layout_struct_type(anon_struct, &named_struct_type.assigned_name);
678
679 let basic_type = Rc::new(BasicType {
681 id: BasicTypeId(type_id.inner()), total_size: inner_struct.total_size,
683 max_alignment: inner_struct.max_alignment,
684 kind: BasicTypeKind::Struct(inner_struct),
685 });
686
687 let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
689
690 basic_type
691 }
692
693 #[must_use]
694 pub fn layout_struct_type(
695 &mut self,
696 struct_type: &AnonymousStructType,
697 name: &str,
698 ) -> StructType {
699 let mut field_layouts = Vec::with_capacity(struct_type.field_name_sorted_fields.len());
701 let mut max_alignment = MemoryAlignment::U8;
702
703 for (field_name, field_type) in &struct_type.field_name_sorted_fields {
704 let field_layout = self.layout(&field_type.field_type);
706 check_type_size(&field_layout, &format!("field {name}::{field_name}"));
707
708 self.insert_layout(field_type.field_type.id, field_layout.clone());
710
711 if field_layout.max_alignment > max_alignment {
712 max_alignment = field_layout.max_alignment;
713 }
714
715 field_layouts.push((field_name.clone(), field_layout));
716 }
717
718 let mut offset = MemoryOffset(0);
720 let mut items = Vec::with_capacity(field_layouts.len());
721
722 for (field_name, field_layout) in field_layouts {
723 offset = align_to(offset, field_layout.max_alignment);
724
725 items.push(OffsetMemoryItem {
726 offset,
727 size: field_layout.total_size,
728 name: field_name,
729 ty: field_layout.clone(),
730 });
731
732 offset = offset + field_layout.total_size;
733 }
734
735 let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
736
737 StructType {
738 name: name.to_string(),
739 fields: items,
740 total_size,
741 max_alignment,
742 }
743 }
744
745 pub fn layout_struct(
746 &mut self,
747 struct_type: &AnonymousStructType,
748 name: &str,
749 type_id: TypeId,
750 ) -> BasicTypeRef {
751 for (_field_name, struct_field) in &struct_type.field_name_sorted_fields {
753 let field_type = &struct_field.field_type;
754 let _field_layout = self.layout(field_type);
755
756 }
758
759 let struct_kind = TypeKind::AnonymousStruct(struct_type.clone());
761 if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind).cloned() {
762 self.insert_layout(type_id, existing_layout.clone());
764 return existing_layout;
765 }
766
767 let struct_layout = self.layout_struct_type(struct_type, name);
768
769 let struct_id = type_id;
771
772 let basic_type = Rc::new(BasicType {
773 id: BasicTypeId(struct_id.inner()),
774 total_size: struct_layout.total_size,
775 max_alignment: struct_layout.max_alignment,
776 kind: BasicTypeKind::Struct(struct_layout),
777 });
778
779 self.insert_layout(struct_id, basic_type.clone());
781 let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
782
783 basic_type
784 }
785
786 #[must_use]
787 pub fn layout_optional_type(&mut self, inner_type: &TypeRef, type_id: TypeId) -> BasicTypeRef {
788 let optional_kind = TypeKind::Optional(inner_type.clone());
790 if let Some(existing_layout) = self.kind_to_layout.get(&optional_kind) {
791 assert!(matches!(&existing_layout.kind, BasicTypeKind::Optional(_)));
792 return existing_layout.clone();
793 }
794
795 let inner_layout = self.layout(inner_type);
797
798 self.insert_layout(inner_type.id, inner_layout.clone());
800 let _ = self
801 .kind_to_layout
802 .insert((*inner_type.kind).clone(), inner_layout);
803
804 let optional_union = self.layout_optional_type_items(inner_type);
806
807 let optional_id = type_id;
809
810 let basic_type = Rc::new(BasicType {
811 id: BasicTypeId(optional_id.inner()),
812 total_size: optional_union.total_size,
813 max_alignment: optional_union.max_alignment,
814 kind: BasicTypeKind::Optional(optional_union),
815 });
816
817 self.insert_layout(optional_id, basic_type.clone());
819 let _ = self
820 .kind_to_layout
821 .insert(optional_kind, basic_type.clone());
822
823 basic_type
824 }
825
826 #[must_use]
827 pub fn layout_optional_type_items(&mut self, inner_type: &TypeRef) -> TaggedUnion {
828 let gen_type = self.layout_type(inner_type);
829
830 let payload_tagged_variant = TaggedUnionVariant {
831 name: "Some".to_string(),
832 ty: gen_type,
833 };
834
835 let none_tagged_variant = TaggedUnionVariant {
836 name: "None".to_string(),
837 ty: Rc::new(BasicType {
838 id: BasicTypeId(0),
839 kind: BasicTypeKind::Empty,
840 total_size: MemorySize(0),
841 max_alignment: MemoryAlignment::U8,
842 }),
843 };
844
845 Self::layout_tagged_union(&[none_tagged_variant, payload_tagged_variant], "Maybe")
846 }
847
848 #[must_use]
849 pub fn layout_tuple_items(&mut self, types: &[TypeRef]) -> TupleType {
850 let mut max_alignment = MemoryAlignment::U8;
852 for ty in types {
853 let elem_layout = self.layout(ty);
855
856 self.insert_layout(ty.id, elem_layout.clone());
858
859 if elem_layout.max_alignment > max_alignment {
860 max_alignment = elem_layout.max_alignment;
861 }
862 }
863
864 let mut offset = MemoryOffset(0);
866 let mut items = Vec::with_capacity(types.len());
867
868 for (i, ty) in types.iter().enumerate() {
869 let elem_layout = self.layout(ty);
871
872 offset = align_to(offset, elem_layout.max_alignment);
873
874 items.push(OffsetMemoryItem {
875 offset,
876 size: elem_layout.total_size,
877 name: i.to_string(),
878 ty: elem_layout.clone(),
879 });
880
881 offset = offset + elem_layout.total_size;
882 }
883
884 let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
886
887 TupleType {
888 fields: items,
889 total_size,
890 max_alignment,
891 }
892 }
893
894 #[must_use]
895 pub fn layout_tuple(&mut self, types: &[TypeRef], tuple_id: TypeId) -> BasicTypeRef {
896 for ty in types {
898 let inner_layout = self.layout(ty);
899 self.insert_layout(ty.id, inner_layout.clone());
900 let _ = self
901 .kind_to_layout
902 .insert((*ty.kind).clone(), inner_layout.clone());
903 }
904
905 let tuple_kind = TypeKind::Tuple(types.to_vec());
907 if let Some(existing_layout) = self.kind_to_layout.get(&tuple_kind).cloned() {
908 self.insert_layout(tuple_id, existing_layout.clone());
910 return existing_layout;
911 }
912
913 let tuple_layout = self.layout_tuple_items(types);
914
915 let basic_type = Rc::new(BasicType {
916 id: BasicTypeId(tuple_id.inner()),
917 total_size: tuple_layout.total_size,
918 max_alignment: tuple_layout.max_alignment,
919 kind: BasicTypeKind::Tuple(tuple_layout),
920 });
921
922 self.insert_layout(tuple_id, basic_type.clone());
924 let _ = self.kind_to_layout.insert(tuple_kind, basic_type.clone());
925
926 basic_type
927 }
928
929 fn insert_layout(&mut self, type_id: TypeId, layout: BasicTypeRef) {
931 let _ = self.id_to_layout.insert(type_id, layout.clone());
932
933 let universal_hash = layout.universal_hash_u64();
935 let _ = self
936 .universal_id_to_layout
937 .insert(universal_hash, layout.clone());
938 let _ = self
939 .universal_short_id_to_layout
940 .insert(universal_hash as u32, layout);
941 }
942
943 #[must_use]
944 pub fn universal_short_id(&self, short_id: u32) -> &BasicTypeRef {
945 if let Some(x) = self.universal_short_id_to_layout.get(&short_id) {
946 x
947 } else {
948 for (hash, ty) in &self.universal_short_id_to_layout {
949 eprintln!("{hash:X} ({hash}) {}", ty.kind);
950 }
951 panic!("not found")
952 }
953 }
954}
955
956fn create_basic_type(
957 type_id: TypeId,
958 kind: BasicTypeKind,
959 size: MemorySize,
960 alignment: MemoryAlignment,
961) -> BasicTypeRef {
962 let basic_type_id = BasicTypeId(type_id.inner());
963
964 Rc::new(BasicType {
965 id: basic_type_id,
966 kind,
967 total_size: size,
968 max_alignment: alignment,
969 })
970}
971
972pub const fn check_type_size(ty: &BasicType, _comment: &str) {
973 if ty.total_size.0 > 1024 * 1024 {
974 }
976}