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::GridView(element_type) => {
512 let element_layout = self.layout(element_type);
513 self.insert_layout(element_type.id, element_layout.clone());
514
515 Rc::new(BasicType {
516 id: BasicTypeId(ty.id.inner()),
517 kind: BasicTypeKind::GridView(element_layout),
518 total_size: PTR_SIZE,
519 max_alignment: PTR_ALIGNMENT,
520 })
521 }
522
523 TypeKind::GridStorage(element_type, width, height) => {
524 let element_layout = self.layout(element_type);
525 self.insert_layout(element_type.id, element_layout.clone());
526
527 let element_size = element_layout.total_size;
528 let element_alignment = element_layout.max_alignment;
529
530 Rc::new(BasicType {
531 id: BasicTypeId(ty.id.inner()),
532 kind: BasicTypeKind::GridStorage(element_layout, *width, *height),
533 total_size: MemorySize(
534 GRID_HEADER_SIZE.0 + element_size.0 * (*width as u32) * (*height as u32),
535 ),
536 max_alignment: max(GRID_HEADER_ALIGNMENT, element_alignment),
537 })
538 }
539
540 TypeKind::SliceView(element_type) => {
541 let element_layout = self.layout(element_type);
542 self.insert_layout(element_type.id, element_layout.clone());
543
544 Rc::new(BasicType {
545 id: BasicTypeId(ty.id.inner()),
546 kind: BasicTypeKind::SliceView(element_layout),
547 total_size: PTR_SIZE,
548 max_alignment: PTR_ALIGNMENT,
549 })
550 }
551
552 TypeKind::SparseStorage(element_type, capacity) => {
553 let element_layout = self.layout(element_type);
554 let size = sparse_mem::layout_size(*capacity as u16, element_layout.total_size.0);
555
556 Rc::new(BasicType {
557 id: BasicTypeId(ty.id.inner()),
558 kind: BasicTypeKind::SparseStorage(element_layout, *capacity),
559 total_size: MemorySize(size as u32),
560 max_alignment: MemoryAlignment::U64,
561 })
562 }
563
564 TypeKind::SparseView(element_type) => {
565 let element_layout = self.layout(element_type);
566 self.insert_layout(element_type.id, element_layout.clone());
567
568 Rc::new(BasicType {
569 id: BasicTypeId(ty.id.inner()),
570 kind: BasicTypeKind::SparseView(element_layout),
571 total_size: PTR_SIZE,
572 max_alignment: PTR_ALIGNMENT,
573 })
574 }
575
576 TypeKind::StackStorage(element_type, capacity) => {
577 let (element_layout, total_size, _max_alignment) =
578 self.layout_vec_like(element_type, *capacity);
579
580 let storage_type = Rc::new(BasicType {
581 id: BasicTypeId(ty.id.inner()),
582 kind: BasicTypeKind::StackStorage(element_layout.clone(), *capacity),
583 total_size,
584 max_alignment: VEC_HEADER_ALIGNMENT,
585 });
586
587 self.insert_layout(element_type.id, element_layout);
588
589 storage_type
590 }
591
592 TypeKind::StackView(element_type) => {
593 let element_layout = self.layout(element_type);
594 self.insert_layout(element_type.id, element_layout.clone());
595
596 Rc::new(BasicType {
597 id: BasicTypeId(ty.id.inner()),
598 kind: BasicTypeKind::DynamicLengthVecView(element_layout),
599 total_size: PTR_SIZE,
600 max_alignment: PTR_ALIGNMENT,
601 })
602 }
603
604 TypeKind::QueueStorage(element_type, capacity) => {
605 let (element_layout, total_size, _max_alignment) =
606 self.layout_vec_like(element_type, *capacity);
607
608 let storage_type = Rc::new(BasicType {
609 id: BasicTypeId(ty.id.inner()),
610 kind: BasicTypeKind::QueueStorage(element_layout.clone(), *capacity),
611 total_size,
612 max_alignment: VEC_HEADER_ALIGNMENT,
613 });
614
615 self.insert_layout(element_type.id, element_layout);
616
617 storage_type
618 }
619
620 TypeKind::QueueView(element_type) => {
621 let element_layout = self.layout(element_type);
622 self.insert_layout(element_type.id, element_layout.clone());
623
624 Rc::new(BasicType {
625 id: BasicTypeId(ty.id.inner()),
626 kind: BasicTypeKind::DynamicLengthVecView(element_layout),
627 total_size: PTR_SIZE,
628 max_alignment: PTR_ALIGNMENT,
629 })
630 }
631
632 TypeKind::Function(_) => {
633 panic!("function types can not be laid out")
634 }
635
636 TypeKind::Unit => create_basic_type(
637 ty.id,
638 BasicTypeKind::Empty,
639 MemorySize(0),
640 MemoryAlignment::U8,
641 ),
642 };
643
644 self.insert_layout(ty.id, basic_type.clone());
646 let _ = self
647 .kind_to_layout
648 .insert((*ty.kind).clone(), basic_type.clone());
649
650 basic_type
651 }
652
653 fn layout_named_struct(
654 &mut self,
655 named_struct_type: &NamedStructType,
656 type_id: TypeId,
657 ) -> BasicTypeRef {
658 let struct_kind = TypeKind::NamedStruct(named_struct_type.clone());
660 if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind) {
661 return existing_layout.clone();
662 }
663
664 let anon_struct = match &*named_struct_type.anon_struct_type.kind {
666 TypeKind::AnonymousStruct(anon_struct) => anon_struct,
667 _ => panic!("Expected AnonymousStruct in NamedStructType"),
668 };
669
670 let inner_struct = self.layout_struct_type(anon_struct, &named_struct_type.assigned_name);
671
672 let basic_type = Rc::new(BasicType {
674 id: BasicTypeId(type_id.inner()), total_size: inner_struct.total_size,
676 max_alignment: inner_struct.max_alignment,
677 kind: BasicTypeKind::Struct(inner_struct),
678 });
679
680 let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
682
683 basic_type
684 }
685
686 #[must_use]
687 pub fn layout_struct_type(
688 &mut self,
689 struct_type: &AnonymousStructType,
690 name: &str,
691 ) -> StructType {
692 let mut field_layouts = Vec::with_capacity(struct_type.field_name_sorted_fields.len());
694 let mut max_alignment = MemoryAlignment::U8;
695
696 for (field_name, field_type) in &struct_type.field_name_sorted_fields {
697 let field_layout = self.layout(&field_type.field_type);
699 check_type_size(&field_layout, &format!("field {name}::{field_name}"));
700
701 self.insert_layout(field_type.field_type.id, field_layout.clone());
703
704 if field_layout.max_alignment > max_alignment {
705 max_alignment = field_layout.max_alignment;
706 }
707
708 field_layouts.push((field_name.clone(), field_layout));
709 }
710
711 let mut offset = MemoryOffset(0);
713 let mut items = Vec::with_capacity(field_layouts.len());
714
715 for (field_name, field_layout) in field_layouts {
716 offset = align_to(offset, field_layout.max_alignment);
717
718 items.push(OffsetMemoryItem {
719 offset,
720 size: field_layout.total_size,
721 name: field_name,
722 ty: field_layout.clone(),
723 });
724
725 offset = offset + field_layout.total_size;
726 }
727
728 let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
729
730 StructType {
731 name: name.to_string(),
732 fields: items,
733 total_size,
734 max_alignment,
735 }
736 }
737
738 pub fn layout_struct(
739 &mut self,
740 struct_type: &AnonymousStructType,
741 name: &str,
742 type_id: TypeId,
743 ) -> BasicTypeRef {
744 for (_field_name, struct_field) in &struct_type.field_name_sorted_fields {
746 let field_type = &struct_field.field_type;
747 let _field_layout = self.layout(field_type);
748
749 }
751
752 let struct_kind = TypeKind::AnonymousStruct(struct_type.clone());
754 if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind).cloned() {
755 self.insert_layout(type_id, existing_layout.clone());
757 return existing_layout;
758 }
759
760 let struct_layout = self.layout_struct_type(struct_type, name);
761
762 let struct_id = type_id;
764
765 let basic_type = Rc::new(BasicType {
766 id: BasicTypeId(struct_id.inner()),
767 total_size: struct_layout.total_size,
768 max_alignment: struct_layout.max_alignment,
769 kind: BasicTypeKind::Struct(struct_layout),
770 });
771
772 self.insert_layout(struct_id, basic_type.clone());
774 let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
775
776 basic_type
777 }
778
779 #[must_use]
780 pub fn layout_optional_type(&mut self, inner_type: &TypeRef, type_id: TypeId) -> BasicTypeRef {
781 let optional_kind = TypeKind::Optional(inner_type.clone());
783 if let Some(existing_layout) = self.kind_to_layout.get(&optional_kind) {
784 assert!(matches!(&existing_layout.kind, BasicTypeKind::Optional(_)));
785 return existing_layout.clone();
786 }
787
788 let inner_layout = self.layout(inner_type);
790
791 self.insert_layout(inner_type.id, inner_layout.clone());
793 let _ = self
794 .kind_to_layout
795 .insert((*inner_type.kind).clone(), inner_layout);
796
797 let optional_union = self.layout_optional_type_items(inner_type);
799
800 let optional_id = type_id;
802
803 let basic_type = Rc::new(BasicType {
804 id: BasicTypeId(optional_id.inner()),
805 total_size: optional_union.total_size,
806 max_alignment: optional_union.max_alignment,
807 kind: BasicTypeKind::Optional(optional_union),
808 });
809
810 self.insert_layout(optional_id, basic_type.clone());
812 let _ = self
813 .kind_to_layout
814 .insert(optional_kind, basic_type.clone());
815
816 basic_type
817 }
818
819 #[must_use]
820 pub fn layout_optional_type_items(&mut self, inner_type: &TypeRef) -> TaggedUnion {
821 let gen_type = self.layout_type(inner_type);
822
823 let payload_tagged_variant = TaggedUnionVariant {
824 name: "Some".to_string(),
825 ty: gen_type,
826 };
827
828 let none_tagged_variant = TaggedUnionVariant {
829 name: "None".to_string(),
830 ty: Rc::new(BasicType {
831 id: BasicTypeId(0),
832 kind: BasicTypeKind::Empty,
833 total_size: MemorySize(0),
834 max_alignment: MemoryAlignment::U8,
835 }),
836 };
837
838 Self::layout_tagged_union(&[none_tagged_variant, payload_tagged_variant], "Maybe")
839 }
840
841 #[must_use]
842 pub fn layout_tuple_items(&mut self, types: &[TypeRef]) -> TupleType {
843 let mut max_alignment = MemoryAlignment::U8;
845 for ty in types {
846 let elem_layout = self.layout(ty);
848
849 self.insert_layout(ty.id, elem_layout.clone());
851
852 if elem_layout.max_alignment > max_alignment {
853 max_alignment = elem_layout.max_alignment;
854 }
855 }
856
857 let mut offset = MemoryOffset(0);
859 let mut items = Vec::with_capacity(types.len());
860
861 for (i, ty) in types.iter().enumerate() {
862 let elem_layout = self.layout(ty);
864
865 offset = align_to(offset, elem_layout.max_alignment);
866
867 items.push(OffsetMemoryItem {
868 offset,
869 size: elem_layout.total_size,
870 name: i.to_string(),
871 ty: elem_layout.clone(),
872 });
873
874 offset = offset + elem_layout.total_size;
875 }
876
877 let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
879
880 TupleType {
881 fields: items,
882 total_size,
883 max_alignment,
884 }
885 }
886
887 #[must_use]
888 pub fn layout_tuple(&mut self, types: &[TypeRef], tuple_id: TypeId) -> BasicTypeRef {
889 for ty in types {
891 let inner_layout = self.layout(ty);
892 self.insert_layout(ty.id, inner_layout.clone());
893 let _ = self
894 .kind_to_layout
895 .insert((*ty.kind).clone(), inner_layout.clone());
896 }
897
898 let tuple_kind = TypeKind::Tuple(types.to_vec());
900 if let Some(existing_layout) = self.kind_to_layout.get(&tuple_kind).cloned() {
901 self.insert_layout(tuple_id, existing_layout.clone());
903 return existing_layout;
904 }
905
906 let tuple_layout = self.layout_tuple_items(types);
907
908 let basic_type = Rc::new(BasicType {
909 id: BasicTypeId(tuple_id.inner()),
910 total_size: tuple_layout.total_size,
911 max_alignment: tuple_layout.max_alignment,
912 kind: BasicTypeKind::Tuple(tuple_layout),
913 });
914
915 self.insert_layout(tuple_id, basic_type.clone());
917 let _ = self.kind_to_layout.insert(tuple_kind, basic_type.clone());
918
919 basic_type
920 }
921
922 fn insert_layout(&mut self, type_id: TypeId, layout: BasicTypeRef) {
924 let _ = self.id_to_layout.insert(type_id, layout.clone());
925
926 let universal_hash = layout.universal_hash_u64();
928 let _ = self
929 .universal_id_to_layout
930 .insert(universal_hash, layout.clone());
931 let _ = self
932 .universal_short_id_to_layout
933 .insert(universal_hash as u32, layout);
934 }
935
936 #[must_use]
937 pub fn universal_short_id(&self, short_id: u32) -> &BasicTypeRef {
938 if let Some(x) = self.universal_short_id_to_layout.get(&short_id) {
939 x
940 } else {
941 for (hash, ty) in &self.universal_short_id_to_layout {
942 eprintln!("{hash:X} ({hash}) {}", ty.kind);
943 }
944 panic!("not found")
945 }
946 }
947}
948
949fn create_basic_type(
950 type_id: TypeId,
951 kind: BasicTypeKind,
952 size: MemorySize,
953 alignment: MemoryAlignment,
954) -> BasicTypeRef {
955 let basic_type_id = BasicTypeId(type_id.inner());
956
957 Rc::new(BasicType {
958 id: basic_type_id,
959 kind,
960 total_size: size,
961 max_alignment: alignment,
962 })
963}
964
965pub const fn check_type_size(ty: &BasicType, _comment: &str) {
966 if ty.total_size.0 > 1024 * 1024 {
967 }
969}