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