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_types::types::{
14 BasicType, BasicTypeId, BasicTypeKind, BasicTypeRef, OffsetMemoryItem, StructType, TaggedUnion,
15 TaggedUnionVariant, TupleType,
16};
17use swamp_vm_types::{
18 adjust_size_to_alignment, align_to, CountU16, MemoryAlignment, MemoryOffset,
19 MemorySize, ANY_HEADER_ALIGNMENT, ANY_HEADER_SIZE, GRID_HEADER_ALIGNMENT, GRID_HEADER_SIZE, MAP_HEADER_ALIGNMENT,
20 PTR_ALIGNMENT, PTR_SIZE, STRING_PTR_ALIGNMENT, STRING_PTR_SIZE,
21 VEC_HEADER_ALIGNMENT, VEC_HEADER_SIZE,
22};
23
24#[derive(Clone)]
25pub struct LayoutCache {
26 pub id_to_layout: SeqMap<TypeId, BasicTypeRef>,
27 pub kind_to_layout: SeqMap<TypeKind, BasicTypeRef>,
28}
29
30impl LayoutCache {}
31
32impl Default for LayoutCache {
33 fn default() -> Self {
34 Self::new()
35 }
36}
37
38impl LayoutCache {
39 #[must_use]
40 pub fn new() -> Self {
41 Self {
42 id_to_layout: SeqMap::default(),
43 kind_to_layout: SeqMap::default(),
44 }
45 }
46
47 #[must_use]
48 pub fn layout(&mut self, analyzed_type: &TypeRef) -> BasicTypeRef {
49 if let Some(x) = self.id_to_layout.get(&analyzed_type.id) {
51 return x.clone();
52 }
53
54 if let Some(existing_layout) = self.kind_to_layout.get(&analyzed_type.kind) {
56 let _ = self
59 .id_to_layout
60 .insert(analyzed_type.id, existing_layout.clone());
61 return existing_layout.clone();
62 }
63
64 let basic_type = self.layout_type(analyzed_type);
65
66 let _ = self
67 .id_to_layout
68 .insert(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 let _ = self.id_to_layout.insert(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 let _ = self.id_to_layout.insert(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 let _ = self.id_to_layout.insert(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::Byte => {
295 create_basic_type(ty.id, BasicTypeKind::U8, MemorySize(1), MemoryAlignment::U8)
296 }
297 TypeKind::Codepoint => create_basic_type(
298 ty.id,
299 BasicTypeKind::U32,
300 MemorySize(4),
301 MemoryAlignment::U32,
302 ),
303 TypeKind::Int => create_basic_type(
304 ty.id,
305 BasicTypeKind::S32,
306 MemorySize(4),
307 MemoryAlignment::U32,
308 ),
309
310 TypeKind::Float => create_basic_type(
311 ty.id,
312 BasicTypeKind::Fixed32,
313 MemorySize(4),
314 MemoryAlignment::U32,
315 ),
316
317 TypeKind::Bool => {
318 create_basic_type(ty.id, BasicTypeKind::B8, MemorySize(1), MemoryAlignment::U8)
319 }
320
321 TypeKind::String(byte, char) => create_basic_type(
322 ty.id,
323 BasicTypeKind::StringView {
324 byte: self.layout(byte),
325 char: self.layout(char),
326 },
327 STRING_PTR_SIZE,
328 STRING_PTR_ALIGNMENT,
329 ),
330
331 TypeKind::AnonymousStruct(struct_type) => {
332 self.layout_struct(struct_type, "anonymous", ty.id)
333 }
334
335 TypeKind::NamedStruct(named_struct) => self.layout_named_struct(named_struct, ty.id),
336
337 TypeKind::Tuple(tuple_types) => self.layout_tuple(tuple_types, ty.id),
338
339 TypeKind::Optional(inner_type) => self.layout_optional_type(inner_type, ty.id),
340
341 TypeKind::Enum(enum_type) => {
342 let variants = enum_type.variants.values().cloned().collect::<Vec<_>>();
343 self.layout_enum(&enum_type.assigned_name, &variants, ty.id, enum_type.symbol_id)
344 }
345
346 TypeKind::FixedCapacityAndLengthArray(element_type, capacity) => {
347 let (element_layout, total_size, max_alignment) =
348 self.layout_vec_like(element_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(element_type.id, element_layout);
359
360 array_type
361 }
362
363 TypeKind::StringStorage(byte_type, char_type, capacity) => {
364 let (element_layout, total_size, max_alignment) =
365 self.layout_vec_like(byte_type, *capacity);
366
367 let array_type = Rc::new(BasicType {
368 id: BasicTypeId(ty.id.inner()),
369 kind: BasicTypeKind::StringStorage {
370 element_type: element_layout.clone(),
371 char: self.layout(char_type),
372 capacity: *capacity,
373 },
374 total_size,
375 max_alignment,
376 });
377
378 let _ = self.id_to_layout.insert(byte_type.id, element_layout);
380
381 array_type
382 }
383
384 TypeKind::Any => create_basic_type(
385 ty.id,
386 BasicTypeKind::Any,
387 ANY_HEADER_SIZE,
388 ANY_HEADER_ALIGNMENT,
389 ),
390
391 TypeKind::DynamicLengthVecView(element_type) => {
392 let (element_layout, _, _) = self.layout_vec_like(element_type, 0);
393
394 let vec_type = Rc::new(BasicType {
395 id: BasicTypeId(ty.id.inner()),
396 kind: BasicTypeKind::DynamicLengthVecView(element_layout.clone()),
397 total_size: PTR_SIZE,
398 max_alignment: PTR_ALIGNMENT,
399 });
400
401 let _ = self.id_to_layout.insert(element_type.id, element_layout);
402
403 vec_type
404 }
405
406 TypeKind::VecStorage(element_type, capacity) => {
407 let (element_layout, total_size, element_alignment) =
408 self.layout_vec_like(element_type, *capacity);
409
410 let storage_type = Rc::new(BasicType {
411 id: BasicTypeId(ty.id.inner()),
412 kind: BasicTypeKind::VecStorage(element_layout.clone(), *capacity),
413 total_size,
414 max_alignment: max(VEC_HEADER_ALIGNMENT, element_alignment),
415 });
416
417 let _ = self.id_to_layout.insert(element_type.id, element_layout);
418
419 storage_type
420 }
421
422 TypeKind::DynamicLengthMapView(key_type, value_type) => {
423 let key_layout = self.layout(key_type);
425 let _ = self.id_to_layout.insert(key_type.id, key_layout.clone());
426
427 let value_layout = self.layout(value_type);
429 let _ = self
430 .id_to_layout
431 .insert(value_type.id, value_layout.clone());
432
433 let key_item = OffsetMemoryItem {
434 offset: MemoryOffset(0),
435 size: key_layout.total_size,
436 name: "key".to_string(),
437 ty: key_layout.clone(),
438 };
439
440 let value_offset = align_to(
441 MemoryOffset(key_layout.total_size.0),
442 value_layout.max_alignment,
443 );
444
445 let value_item = OffsetMemoryItem {
446 offset: value_offset,
447 size: value_layout.total_size,
448 name: "value".to_string(),
449 ty: value_layout.clone(),
450 };
451
452 Rc::new(BasicType {
453 id: BasicTypeId(ty.id.inner()),
454 kind: BasicTypeKind::DynamicLengthMapView(
455 Box::new(key_item),
456 Box::new(value_item),
457 ),
458 total_size: PTR_SIZE,
459 max_alignment: PTR_ALIGNMENT,
460 })
461 }
462
463 TypeKind::MapStorage(key_type, value_type, logical_limit) => {
464 let key_layout = self.layout(key_type);
466 let _ = self.id_to_layout.insert(key_type.id, key_layout.clone());
467
468 let value_layout = self.layout(value_type);
470 let _ = self
471 .id_to_layout
472 .insert(value_type.id, value_layout.clone());
473
474 let logical_limit = *logical_limit;
475
476 let (_bucket_layout, map_init) = hashmap_mem::layout(
477 key_layout.total_size.0,
478 key_layout.max_alignment.into(),
479 value_layout.total_size.0,
480 value_layout.max_alignment.into(),
481 logical_limit as u16,
482 );
483 let total_size = MemorySize(map_init.total_size);
484
485 Rc::new(BasicType {
486 id: BasicTypeId(ty.id.inner()),
487 kind: BasicTypeKind::MapStorage {
488 key_type: key_layout,
489 logical_limit,
490 capacity: CountU16(map_init.capacity),
491 value_type: value_layout,
492 },
493 total_size,
494 max_alignment: MAP_HEADER_ALIGNMENT,
495 })
496 }
497
498 TypeKind::Range(_range_struct) => create_basic_type(
499 ty.id,
500 BasicTypeKind::InternalRangeHeader,
501 MemorySize(12),
502 MemoryAlignment::U32,
503 ),
504
505 TypeKind::GridView(element_type) => {
506 let element_layout = self.layout(element_type);
507 let _ = self
508 .id_to_layout
509 .insert(element_type.id, element_layout.clone());
510
511 Rc::new(BasicType {
512 id: BasicTypeId(ty.id.inner()),
513 kind: BasicTypeKind::GridView(element_layout),
514 total_size: PTR_SIZE,
515 max_alignment: PTR_ALIGNMENT,
516 })
517 }
518
519 TypeKind::GridStorage(element_type, width, height) => {
520 let element_layout = self.layout(element_type);
521 let _ = self
522 .id_to_layout
523 .insert(element_type.id, element_layout.clone());
524
525 let element_size = element_layout.total_size;
526 let element_alignment = element_layout.max_alignment;
527
528 Rc::new(BasicType {
529 id: BasicTypeId(ty.id.inner()),
530 kind: BasicTypeKind::GridStorage(element_layout, *width, *height),
531 total_size: MemorySize(
532 GRID_HEADER_SIZE.0 + element_size.0 * (*width as u32) * (*height as u32),
533 ),
534 max_alignment: max(GRID_HEADER_ALIGNMENT, element_alignment),
535 })
536 }
537
538 TypeKind::SliceView(element_type) => {
539 let element_layout = self.layout(element_type);
540 let _ = self
541 .id_to_layout
542 .insert(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 let _ = self
567 .id_to_layout
568 .insert(element_type.id, element_layout.clone());
569
570 Rc::new(BasicType {
571 id: BasicTypeId(ty.id.inner()),
572 kind: BasicTypeKind::SparseView(element_layout),
573 total_size: PTR_SIZE,
574 max_alignment: PTR_ALIGNMENT,
575 })
576 }
577
578 TypeKind::StackStorage(element_type, capacity) => {
579 let (element_layout, total_size, _max_alignment) =
580 self.layout_vec_like(element_type, *capacity);
581
582 let storage_type = Rc::new(BasicType {
583 id: BasicTypeId(ty.id.inner()),
584 kind: BasicTypeKind::StackStorage(element_layout.clone(), *capacity),
585 total_size,
586 max_alignment: VEC_HEADER_ALIGNMENT,
587 });
588
589 let _ = self.id_to_layout.insert(element_type.id, element_layout);
590
591 storage_type
592 }
593
594 TypeKind::StackView(element_type) => {
595 let element_layout = self.layout(element_type);
596 let _ = self
597 .id_to_layout
598 .insert(element_type.id, element_layout.clone());
599
600 Rc::new(BasicType {
601 id: BasicTypeId(ty.id.inner()),
602 kind: BasicTypeKind::DynamicLengthVecView(element_layout),
603 total_size: PTR_SIZE,
604 max_alignment: PTR_ALIGNMENT,
605 })
606 }
607
608 TypeKind::QueueStorage(element_type, capacity) => {
609 let (element_layout, total_size, _max_alignment) =
610 self.layout_vec_like(element_type, *capacity);
611
612 let storage_type = Rc::new(BasicType {
613 id: BasicTypeId(ty.id.inner()),
614 kind: BasicTypeKind::QueueStorage(element_layout.clone(), *capacity),
615 total_size,
616 max_alignment: VEC_HEADER_ALIGNMENT,
617 });
618
619 let _ = self.id_to_layout.insert(element_type.id, element_layout);
620
621 storage_type
622 }
623
624 TypeKind::QueueView(element_type) => {
625 let element_layout = self.layout(element_type);
626 let _ = self
627 .id_to_layout
628 .insert(element_type.id, element_layout.clone());
629
630 Rc::new(BasicType {
631 id: BasicTypeId(ty.id.inner()),
632 kind: BasicTypeKind::DynamicLengthVecView(element_layout),
633 total_size: PTR_SIZE,
634 max_alignment: PTR_ALIGNMENT,
635 })
636 }
637
638 TypeKind::Function(_) => {
639 panic!("function types can not be laid out")
640 }
641
642 TypeKind::Unit => create_basic_type(
643 ty.id,
644 BasicTypeKind::Empty,
645 MemorySize(0),
646 MemoryAlignment::U8,
647 ),
648 };
649
650 let _ = self.id_to_layout.insert(ty.id, basic_type.clone());
652 let _ = self
653 .kind_to_layout
654 .insert((*ty.kind).clone(), basic_type.clone());
655
656 basic_type
657 }
658
659 fn layout_named_struct(
660 &mut self,
661 named_struct_type: &NamedStructType,
662 type_id: TypeId,
663 ) -> BasicTypeRef {
664 let struct_kind = TypeKind::NamedStruct(named_struct_type.clone());
666 if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind) {
667 return existing_layout.clone();
668 }
669
670 let anon_struct = match &*named_struct_type.anon_struct_type.kind {
672 TypeKind::AnonymousStruct(anon_struct) => anon_struct,
673 _ => panic!("Expected AnonymousStruct in NamedStructType"),
674 };
675
676 let inner_struct = self.layout_struct_type(anon_struct, &named_struct_type.assigned_name);
677
678 let basic_type = Rc::new(BasicType {
680 id: BasicTypeId(type_id.inner()), total_size: inner_struct.total_size,
682 max_alignment: inner_struct.max_alignment,
683 kind: BasicTypeKind::Struct(inner_struct),
684 });
685
686 let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
688
689 basic_type
690 }
691
692 #[must_use]
693 pub fn layout_struct_type(
694 &mut self,
695 struct_type: &AnonymousStructType,
696 name: &str,
697 ) -> StructType {
698 let mut field_layouts = Vec::with_capacity(struct_type.field_name_sorted_fields.len());
700 let mut max_alignment = MemoryAlignment::U8;
701
702 for (field_name, field_type) in &struct_type.field_name_sorted_fields {
703 let field_layout = self.layout(&field_type.field_type);
705 check_type_size(&field_layout, &format!("field {name}::{field_name}"));
706
707 let _ = self
709 .id_to_layout
710 .insert(field_type.field_type.id, field_layout.clone());
711
712 if field_layout.max_alignment > max_alignment {
713 max_alignment = field_layout.max_alignment;
714 }
715
716 field_layouts.push((field_name.clone(), field_layout));
717 }
718
719 let mut offset = MemoryOffset(0);
721 let mut items = Vec::with_capacity(field_layouts.len());
722
723 for (field_name, field_layout) in field_layouts {
724 offset = align_to(offset, field_layout.max_alignment);
725
726 items.push(OffsetMemoryItem {
727 offset,
728 size: field_layout.total_size,
729 name: field_name,
730 ty: field_layout.clone(),
731 });
732
733 offset = offset + field_layout.total_size;
734 }
735
736 let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
737
738 StructType {
739 name: name.to_string(),
740 fields: items,
741 total_size,
742 max_alignment,
743 }
744 }
745
746 pub fn layout_struct(
747 &mut self,
748 struct_type: &AnonymousStructType,
749 name: &str,
750 type_id: TypeId,
751 ) -> BasicTypeRef {
752 for (_field_name, struct_field) in &struct_type.field_name_sorted_fields {
754 let field_type = &struct_field.field_type;
755 let _field_layout = self.layout(field_type);
756
757 }
759
760 let struct_kind = TypeKind::AnonymousStruct(struct_type.clone());
762 if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind) {
763 let _ = self.id_to_layout.insert(type_id, existing_layout.clone());
765 return existing_layout.clone();
766 }
767
768 let struct_layout = self.layout_struct_type(struct_type, name);
769
770 let struct_id = type_id;
772
773 let basic_type = Rc::new(BasicType {
774 id: BasicTypeId(struct_id.inner()),
775 total_size: struct_layout.total_size,
776 max_alignment: struct_layout.max_alignment,
777 kind: BasicTypeKind::Struct(struct_layout),
778 });
779
780 let _ = self.id_to_layout.insert(struct_id, basic_type.clone());
782 let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
783
784 basic_type
785 }
786
787 #[must_use]
788 pub fn layout_optional_type(&mut self, inner_type: &TypeRef, type_id: TypeId) -> BasicTypeRef {
789 let optional_kind = TypeKind::Optional(inner_type.clone());
791 if let Some(existing_layout) = self.kind_to_layout.get(&optional_kind) {
792 assert!(matches!(&existing_layout.kind, BasicTypeKind::Optional(_)));
793 return existing_layout.clone();
794 }
795
796 let inner_layout = self.layout(inner_type);
798
799 let _ = self
801 .id_to_layout
802 .insert(inner_type.id, inner_layout.clone());
803 let _ = self
804 .kind_to_layout
805 .insert((*inner_type.kind).clone(), inner_layout);
806
807 let optional_union = self.layout_optional_type_items(inner_type);
809
810 let optional_id = type_id;
812
813 let basic_type = Rc::new(BasicType {
814 id: BasicTypeId(optional_id.inner()),
815 total_size: optional_union.total_size,
816 max_alignment: optional_union.max_alignment,
817 kind: BasicTypeKind::Optional(optional_union),
818 });
819
820 let _ = self.id_to_layout.insert(optional_id, basic_type.clone());
822 let _ = self
823 .kind_to_layout
824 .insert(optional_kind, basic_type.clone());
825
826 basic_type
827 }
828
829 #[must_use]
830 pub fn layout_optional_type_items(&mut self, inner_type: &TypeRef) -> TaggedUnion {
831 let gen_type = self.layout_type(inner_type);
832
833 let payload_tagged_variant = TaggedUnionVariant {
834 name: "Some".to_string(),
835 ty: gen_type,
836 };
837
838 let none_tagged_variant = TaggedUnionVariant {
839 name: "None".to_string(),
840 ty: Rc::new(BasicType {
841 id: BasicTypeId(0),
842 kind: BasicTypeKind::Empty,
843 total_size: MemorySize(0),
844 max_alignment: MemoryAlignment::U8,
845 }),
846 };
847
848 Self::layout_tagged_union(&[none_tagged_variant, payload_tagged_variant], "Maybe")
849 }
850
851 #[must_use]
852 pub fn layout_tuple_items(&mut self, types: &[TypeRef]) -> TupleType {
853 let mut max_alignment = MemoryAlignment::U8;
855 for ty in types {
856 let elem_layout = self.layout(ty);
858
859 let _ = self.id_to_layout.insert(ty.id, elem_layout.clone());
861
862 if elem_layout.max_alignment > max_alignment {
863 max_alignment = elem_layout.max_alignment;
864 }
865 }
866
867 let mut offset = MemoryOffset(0);
869 let mut items = Vec::with_capacity(types.len());
870
871 for (i, ty) in types.iter().enumerate() {
872 let elem_layout = self.layout(ty);
874
875 offset = align_to(offset, elem_layout.max_alignment);
876
877 items.push(OffsetMemoryItem {
878 offset,
879 size: elem_layout.total_size,
880 name: i.to_string(),
881 ty: elem_layout.clone(),
882 });
883
884 offset = offset + elem_layout.total_size;
885 }
886
887 let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
889
890 TupleType {
891 fields: items,
892 total_size,
893 max_alignment,
894 }
895 }
896
897 #[must_use]
898 pub fn layout_tuple(&mut self, types: &[TypeRef], tuple_id: TypeId) -> BasicTypeRef {
899 for ty in types {
901 let inner_layout = self.layout(ty);
902 let _ = self.id_to_layout.insert(ty.id, inner_layout.clone());
903 let _ = self
904 .kind_to_layout
905 .insert((*ty.kind).clone(), inner_layout.clone());
906 }
907
908 let tuple_kind = TypeKind::Tuple(types.to_vec());
910 if let Some(existing_layout) = self.kind_to_layout.get(&tuple_kind) {
911 let _ = self.id_to_layout.insert(tuple_id, existing_layout.clone());
913 return existing_layout.clone();
914 }
915
916 let tuple_layout = self.layout_tuple_items(types);
917
918 let basic_type = Rc::new(BasicType {
919 id: BasicTypeId(tuple_id.inner()),
920 total_size: tuple_layout.total_size,
921 max_alignment: tuple_layout.max_alignment,
922 kind: BasicTypeKind::Tuple(tuple_layout),
923 });
924
925 let _ = self.id_to_layout.insert(tuple_id, basic_type.clone());
927 let _ = self.kind_to_layout.insert(tuple_kind, basic_type.clone());
928
929 basic_type
930 }
931}
932
933fn create_basic_type(
934 type_id: TypeId,
935 kind: BasicTypeKind,
936 size: MemorySize,
937 alignment: MemoryAlignment,
938) -> BasicTypeRef {
939 let basic_type_id = BasicTypeId(type_id.inner());
940
941 Rc::new(BasicType {
942 id: basic_type_id,
943 kind,
944 total_size: size,
945 max_alignment: alignment,
946 })
947}
948
949pub const fn check_type_size(ty: &BasicType, _comment: &str) {
950 if ty.total_size.0 > 1024 * 1024 {
951 }
953}