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 ANY_HEADER_ALIGNMENT, ANY_HEADER_SIZE, CountU16, GRID_HEADER_ALIGNMENT, GRID_HEADER_SIZE,
19 MAP_HEADER_ALIGNMENT, MemoryAlignment, MemoryOffset, MemorySize, PTR_ALIGNMENT, PTR_SIZE,
20 STRING_PTR_ALIGNMENT, STRING_PTR_SIZE, VEC_HEADER_ALIGNMENT, VEC_HEADER_SIZE,
21 adjust_size_to_alignment, align_to,
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 pub universal_id_to_layout: SeqMap<u64, BasicTypeRef>,
29 pub universal_short_id_to_layout: SeqMap<u32, BasicTypeRef>,
30}
31
32impl LayoutCache {}
33
34impl Default for LayoutCache {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl LayoutCache {
41 #[must_use]
42 pub fn new() -> Self {
43 Self {
44 id_to_layout: SeqMap::default(),
45 kind_to_layout: SeqMap::default(),
46 universal_id_to_layout: SeqMap::default(),
47 universal_short_id_to_layout: SeqMap::default(),
48 }
49 }
50
51 #[must_use]
52 pub fn layout(&mut self, analyzed_type: &TypeRef) -> BasicTypeRef {
53 if let Some(x) = self.id_to_layout.get(&analyzed_type.id) {
55 return x.clone();
56 }
57
58 if let Some(existing_layout) = self.kind_to_layout.get(&analyzed_type.kind).cloned() {
60 self.insert_layout(analyzed_type.id, existing_layout.clone());
63 return existing_layout;
64 }
65
66 let basic_type = self.layout_type(analyzed_type);
67
68 self.insert_layout(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 self.insert_layout(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 self.insert_layout(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 self.insert_layout(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(
344 &enum_type.assigned_name,
345 &variants,
346 ty.id,
347 enum_type.symbol_id,
348 )
349 }
350
351 TypeKind::FixedCapacityAndLengthArray(element_type, capacity) => {
352 let (element_layout, total_size, max_alignment) =
353 self.layout_vec_like(element_type, *capacity);
354
355 let array_type = Rc::new(BasicType {
356 id: BasicTypeId(ty.id.inner()),
357 kind: BasicTypeKind::FixedCapacityArray(element_layout.clone(), *capacity),
358 total_size,
359 max_alignment,
360 });
361
362 self.insert_layout(element_type.id, element_layout);
364
365 array_type
366 }
367
368 TypeKind::StringStorage(byte_type, char_type, capacity) => {
369 let (element_layout, total_size, max_alignment) =
370 self.layout_vec_like(byte_type, *capacity);
371
372 let array_type = Rc::new(BasicType {
373 id: BasicTypeId(ty.id.inner()),
374 kind: BasicTypeKind::StringStorage {
375 element_type: element_layout.clone(),
376 char: self.layout(char_type),
377 capacity: *capacity,
378 },
379 total_size,
380 max_alignment,
381 });
382
383 self.insert_layout(byte_type.id, element_layout);
385
386 array_type
387 }
388
389 TypeKind::Any => create_basic_type(
390 ty.id,
391 BasicTypeKind::Any,
392 ANY_HEADER_SIZE,
393 ANY_HEADER_ALIGNMENT,
394 ),
395
396 TypeKind::DynamicLengthVecView(element_type) => {
397 let (element_layout, _, _) = self.layout_vec_like(element_type, 0);
398
399 let vec_type = Rc::new(BasicType {
400 id: BasicTypeId(ty.id.inner()),
401 kind: BasicTypeKind::DynamicLengthVecView(element_layout.clone()),
402 total_size: PTR_SIZE,
403 max_alignment: PTR_ALIGNMENT,
404 });
405
406 self.insert_layout(element_type.id, element_layout);
407
408 vec_type
409 }
410
411 TypeKind::VecStorage(element_type, capacity) => {
412 let (element_layout, total_size, element_alignment) =
413 self.layout_vec_like(element_type, *capacity);
414
415 let storage_type = Rc::new(BasicType {
416 id: BasicTypeId(ty.id.inner()),
417 kind: BasicTypeKind::VecStorage(element_layout.clone(), *capacity),
418 total_size,
419 max_alignment: max(VEC_HEADER_ALIGNMENT, element_alignment),
420 });
421
422 self.insert_layout(element_type.id, element_layout);
423
424 storage_type
425 }
426
427 TypeKind::DynamicLengthMapView(key_type, value_type) => {
428 let key_layout = self.layout(key_type);
430 self.insert_layout(key_type.id, key_layout.clone());
431
432 let value_layout = self.layout(value_type);
434 self.insert_layout(value_type.id, value_layout.clone());
435
436 let key_item = OffsetMemoryItem {
437 offset: MemoryOffset(0),
438 size: key_layout.total_size,
439 name: "key".to_string(),
440 ty: key_layout.clone(),
441 };
442
443 let value_offset = align_to(
444 MemoryOffset(key_layout.total_size.0),
445 value_layout.max_alignment,
446 );
447
448 let value_item = OffsetMemoryItem {
449 offset: value_offset,
450 size: value_layout.total_size,
451 name: "value".to_string(),
452 ty: value_layout.clone(),
453 };
454
455 Rc::new(BasicType {
456 id: BasicTypeId(ty.id.inner()),
457 kind: BasicTypeKind::DynamicLengthMapView(
458 Box::new(key_item),
459 Box::new(value_item),
460 ),
461 total_size: PTR_SIZE,
462 max_alignment: PTR_ALIGNMENT,
463 })
464 }
465
466 TypeKind::MapStorage(key_type, value_type, logical_limit) => {
467 let key_layout = self.layout(key_type);
469 self.insert_layout(key_type.id, key_layout.clone());
470
471 let value_layout = self.layout(value_type);
473 self.insert_layout(value_type.id, value_layout.clone());
474
475 let logical_limit = *logical_limit;
476
477 let (_bucket_layout, map_init) = hashmap_mem::layout(
478 key_layout.total_size.0,
479 key_layout.max_alignment.into(),
480 value_layout.total_size.0,
481 value_layout.max_alignment.into(),
482 logical_limit as u16,
483 );
484 let total_size = MemorySize(map_init.total_size);
485
486 Rc::new(BasicType {
487 id: BasicTypeId(ty.id.inner()),
488 kind: BasicTypeKind::MapStorage {
489 key_type: key_layout,
490 logical_limit,
491 capacity: CountU16(map_init.capacity),
492 value_type: value_layout,
493 },
494 total_size,
495 max_alignment: MAP_HEADER_ALIGNMENT,
496 })
497 }
498
499 TypeKind::Range(_range_struct) => create_basic_type(
500 ty.id,
501 BasicTypeKind::InternalRangeHeader,
502 MemorySize(12),
503 MemoryAlignment::U32,
504 ),
505
506 TypeKind::GridView(element_type) => {
507 let element_layout = self.layout(element_type);
508 self.insert_layout(element_type.id, element_layout.clone());
509
510 Rc::new(BasicType {
511 id: BasicTypeId(ty.id.inner()),
512 kind: BasicTypeKind::GridView(element_layout),
513 total_size: PTR_SIZE,
514 max_alignment: PTR_ALIGNMENT,
515 })
516 }
517
518 TypeKind::GridStorage(element_type, width, height) => {
519 let element_layout = self.layout(element_type);
520 self.insert_layout(element_type.id, element_layout.clone());
521
522 let element_size = element_layout.total_size;
523 let element_alignment = element_layout.max_alignment;
524
525 Rc::new(BasicType {
526 id: BasicTypeId(ty.id.inner()),
527 kind: BasicTypeKind::GridStorage(element_layout, *width, *height),
528 total_size: MemorySize(
529 GRID_HEADER_SIZE.0 + element_size.0 * (*width as u32) * (*height as u32),
530 ),
531 max_alignment: max(GRID_HEADER_ALIGNMENT, element_alignment),
532 })
533 }
534
535 TypeKind::SliceView(element_type) => {
536 let element_layout = self.layout(element_type);
537 self.insert_layout(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 self.insert_layout(element_type.id, element_layout.clone());
562
563 Rc::new(BasicType {
564 id: BasicTypeId(ty.id.inner()),
565 kind: BasicTypeKind::SparseView(element_layout),
566 total_size: PTR_SIZE,
567 max_alignment: PTR_ALIGNMENT,
568 })
569 }
570
571 TypeKind::StackStorage(element_type, capacity) => {
572 let (element_layout, total_size, _max_alignment) =
573 self.layout_vec_like(element_type, *capacity);
574
575 let storage_type = Rc::new(BasicType {
576 id: BasicTypeId(ty.id.inner()),
577 kind: BasicTypeKind::StackStorage(element_layout.clone(), *capacity),
578 total_size,
579 max_alignment: VEC_HEADER_ALIGNMENT,
580 });
581
582 self.insert_layout(element_type.id, element_layout);
583
584 storage_type
585 }
586
587 TypeKind::StackView(element_type) => {
588 let element_layout = self.layout(element_type);
589 self.insert_layout(element_type.id, element_layout.clone());
590
591 Rc::new(BasicType {
592 id: BasicTypeId(ty.id.inner()),
593 kind: BasicTypeKind::DynamicLengthVecView(element_layout),
594 total_size: PTR_SIZE,
595 max_alignment: PTR_ALIGNMENT,
596 })
597 }
598
599 TypeKind::QueueStorage(element_type, capacity) => {
600 let (element_layout, total_size, _max_alignment) =
601 self.layout_vec_like(element_type, *capacity);
602
603 let storage_type = Rc::new(BasicType {
604 id: BasicTypeId(ty.id.inner()),
605 kind: BasicTypeKind::QueueStorage(element_layout.clone(), *capacity),
606 total_size,
607 max_alignment: VEC_HEADER_ALIGNMENT,
608 });
609
610 self.insert_layout(element_type.id, element_layout);
611
612 storage_type
613 }
614
615 TypeKind::QueueView(element_type) => {
616 let element_layout = self.layout(element_type);
617 self.insert_layout(element_type.id, element_layout.clone());
618
619 Rc::new(BasicType {
620 id: BasicTypeId(ty.id.inner()),
621 kind: BasicTypeKind::DynamicLengthVecView(element_layout),
622 total_size: PTR_SIZE,
623 max_alignment: PTR_ALIGNMENT,
624 })
625 }
626
627 TypeKind::Function(_) => {
628 panic!("function types can not be laid out")
629 }
630
631 TypeKind::Unit => create_basic_type(
632 ty.id,
633 BasicTypeKind::Empty,
634 MemorySize(0),
635 MemoryAlignment::U8,
636 ),
637 };
638
639 self.insert_layout(ty.id, basic_type.clone());
641 let _ = self
642 .kind_to_layout
643 .insert((*ty.kind).clone(), basic_type.clone());
644
645 basic_type
646 }
647
648 fn layout_named_struct(
649 &mut self,
650 named_struct_type: &NamedStructType,
651 type_id: TypeId,
652 ) -> BasicTypeRef {
653 let struct_kind = TypeKind::NamedStruct(named_struct_type.clone());
655 if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind) {
656 return existing_layout.clone();
657 }
658
659 let anon_struct = match &*named_struct_type.anon_struct_type.kind {
661 TypeKind::AnonymousStruct(anon_struct) => anon_struct,
662 _ => panic!("Expected AnonymousStruct in NamedStructType"),
663 };
664
665 let inner_struct = self.layout_struct_type(anon_struct, &named_struct_type.assigned_name);
666
667 let basic_type = Rc::new(BasicType {
669 id: BasicTypeId(type_id.inner()), total_size: inner_struct.total_size,
671 max_alignment: inner_struct.max_alignment,
672 kind: BasicTypeKind::Struct(inner_struct),
673 });
674
675 let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
677
678 basic_type
679 }
680
681 #[must_use]
682 pub fn layout_struct_type(
683 &mut self,
684 struct_type: &AnonymousStructType,
685 name: &str,
686 ) -> StructType {
687 let mut field_layouts = Vec::with_capacity(struct_type.field_name_sorted_fields.len());
689 let mut max_alignment = MemoryAlignment::U8;
690
691 for (field_name, field_type) in &struct_type.field_name_sorted_fields {
692 let field_layout = self.layout(&field_type.field_type);
694 check_type_size(&field_layout, &format!("field {name}::{field_name}"));
695
696 self.insert_layout(field_type.field_type.id, field_layout.clone());
698
699 if field_layout.max_alignment > max_alignment {
700 max_alignment = field_layout.max_alignment;
701 }
702
703 field_layouts.push((field_name.clone(), field_layout));
704 }
705
706 let mut offset = MemoryOffset(0);
708 let mut items = Vec::with_capacity(field_layouts.len());
709
710 for (field_name, field_layout) in field_layouts {
711 offset = align_to(offset, field_layout.max_alignment);
712
713 items.push(OffsetMemoryItem {
714 offset,
715 size: field_layout.total_size,
716 name: field_name,
717 ty: field_layout.clone(),
718 });
719
720 offset = offset + field_layout.total_size;
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).cloned() {
750 self.insert_layout(type_id, existing_layout.clone());
752 return existing_layout;
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 self.insert_layout(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 self.insert_layout(inner_type.id, inner_layout.clone());
788 let _ = self
789 .kind_to_layout
790 .insert((*inner_type.kind).clone(), inner_layout);
791
792 let optional_union = self.layout_optional_type_items(inner_type);
794
795 let optional_id = type_id;
797
798 let basic_type = Rc::new(BasicType {
799 id: BasicTypeId(optional_id.inner()),
800 total_size: optional_union.total_size,
801 max_alignment: optional_union.max_alignment,
802 kind: BasicTypeKind::Optional(optional_union),
803 });
804
805 self.insert_layout(optional_id, basic_type.clone());
807 let _ = self
808 .kind_to_layout
809 .insert(optional_kind, basic_type.clone());
810
811 basic_type
812 }
813
814 #[must_use]
815 pub fn layout_optional_type_items(&mut self, inner_type: &TypeRef) -> TaggedUnion {
816 let gen_type = self.layout_type(inner_type);
817
818 let payload_tagged_variant = TaggedUnionVariant {
819 name: "Some".to_string(),
820 ty: gen_type,
821 };
822
823 let none_tagged_variant = TaggedUnionVariant {
824 name: "None".to_string(),
825 ty: Rc::new(BasicType {
826 id: BasicTypeId(0),
827 kind: BasicTypeKind::Empty,
828 total_size: MemorySize(0),
829 max_alignment: MemoryAlignment::U8,
830 }),
831 };
832
833 Self::layout_tagged_union(&[none_tagged_variant, payload_tagged_variant], "Maybe")
834 }
835
836 #[must_use]
837 pub fn layout_tuple_items(&mut self, types: &[TypeRef]) -> TupleType {
838 let mut max_alignment = MemoryAlignment::U8;
840 for ty in types {
841 let elem_layout = self.layout(ty);
843
844 self.insert_layout(ty.id, elem_layout.clone());
846
847 if elem_layout.max_alignment > max_alignment {
848 max_alignment = elem_layout.max_alignment;
849 }
850 }
851
852 let mut offset = MemoryOffset(0);
854 let mut items = Vec::with_capacity(types.len());
855
856 for (i, ty) in types.iter().enumerate() {
857 let elem_layout = self.layout(ty);
859
860 offset = align_to(offset, elem_layout.max_alignment);
861
862 items.push(OffsetMemoryItem {
863 offset,
864 size: elem_layout.total_size,
865 name: i.to_string(),
866 ty: elem_layout.clone(),
867 });
868
869 offset = offset + elem_layout.total_size;
870 }
871
872 let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
874
875 TupleType {
876 fields: items,
877 total_size,
878 max_alignment,
879 }
880 }
881
882 #[must_use]
883 pub fn layout_tuple(&mut self, types: &[TypeRef], tuple_id: TypeId) -> BasicTypeRef {
884 for ty in types {
886 let inner_layout = self.layout(ty);
887 self.insert_layout(ty.id, inner_layout.clone());
888 let _ = self
889 .kind_to_layout
890 .insert((*ty.kind).clone(), inner_layout.clone());
891 }
892
893 let tuple_kind = TypeKind::Tuple(types.to_vec());
895 if let Some(existing_layout) = self.kind_to_layout.get(&tuple_kind).cloned() {
896 self.insert_layout(tuple_id, existing_layout.clone());
898 return existing_layout;
899 }
900
901 let tuple_layout = self.layout_tuple_items(types);
902
903 let basic_type = Rc::new(BasicType {
904 id: BasicTypeId(tuple_id.inner()),
905 total_size: tuple_layout.total_size,
906 max_alignment: tuple_layout.max_alignment,
907 kind: BasicTypeKind::Tuple(tuple_layout),
908 });
909
910 self.insert_layout(tuple_id, basic_type.clone());
912 let _ = self.kind_to_layout.insert(tuple_kind, basic_type.clone());
913
914 basic_type
915 }
916
917 fn insert_layout(&mut self, type_id: TypeId, layout: BasicTypeRef) {
919 let _ = self.id_to_layout.insert(type_id, layout.clone());
920
921 let universal_hash = layout.universal_hash_u64();
923 let _ = self
924 .universal_id_to_layout
925 .insert(universal_hash, layout.clone());
926 let _ = self
927 .universal_short_id_to_layout
928 .insert(universal_hash as u32, layout);
929 }
930
931 #[must_use]
932 pub fn universal_short_id(&self, short_id: u32) -> &BasicTypeRef {
933 if let Some(x) = self.universal_short_id_to_layout.get(&short_id) {
934 x
935 } else {
936 for (hash, ty) in &self.universal_short_id_to_layout {
937 eprintln!("{hash:X} ({hash}) {}", ty.kind);
938 }
939 panic!("not found")
940 }
941 }
942}
943
944fn create_basic_type(
945 type_id: TypeId,
946 kind: BasicTypeKind,
947 size: MemorySize,
948 alignment: MemoryAlignment,
949) -> BasicTypeRef {
950 let basic_type_id = BasicTypeId(type_id.inner());
951
952 Rc::new(BasicType {
953 id: basic_type_id,
954 kind,
955 total_size: size,
956 max_alignment: alignment,
957 })
958}
959
960pub const fn check_type_size(ty: &BasicType, _comment: &str) {
961 if ty.total_size.0 > 1024 * 1024 {
962 }
964}