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