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