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