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 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(&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 self.insert_layout(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 self.insert_layout(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 self.insert_layout(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 self.insert_layout(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 self.insert_layout(key_type.id, key_layout.clone());
426
427 let value_layout = self.layout(value_type);
429 self.insert_layout(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 self.insert_layout(key_type.id, key_layout.clone());
465
466 let value_layout = self.layout(value_type);
468 self.insert_layout(value_type.id, value_layout.clone());
469
470 let logical_limit = *logical_limit;
471
472 let (_bucket_layout, map_init) = hashmap_mem::layout(
473 key_layout.total_size.0,
474 key_layout.max_alignment.into(),
475 value_layout.total_size.0,
476 value_layout.max_alignment.into(),
477 logical_limit as u16,
478 );
479 let total_size = MemorySize(map_init.total_size);
480
481 Rc::new(BasicType {
482 id: BasicTypeId(ty.id.inner()),
483 kind: BasicTypeKind::MapStorage {
484 key_type: key_layout,
485 logical_limit,
486 capacity: CountU16(map_init.capacity),
487 value_type: value_layout,
488 },
489 total_size,
490 max_alignment: MAP_HEADER_ALIGNMENT,
491 })
492 }
493
494 TypeKind::Range(_range_struct) => create_basic_type(
495 ty.id,
496 BasicTypeKind::InternalRangeHeader,
497 MemorySize(12),
498 MemoryAlignment::U32,
499 ),
500
501 TypeKind::GridView(element_type) => {
502 let element_layout = self.layout(element_type);
503 self.insert_layout(element_type.id, element_layout.clone());
504
505 Rc::new(BasicType {
506 id: BasicTypeId(ty.id.inner()),
507 kind: BasicTypeKind::GridView(element_layout),
508 total_size: PTR_SIZE,
509 max_alignment: PTR_ALIGNMENT,
510 })
511 }
512
513 TypeKind::GridStorage(element_type, width, height) => {
514 let element_layout = self.layout(element_type);
515 self.insert_layout(element_type.id, element_layout.clone());
516
517 let element_size = element_layout.total_size;
518 let element_alignment = element_layout.max_alignment;
519
520 Rc::new(BasicType {
521 id: BasicTypeId(ty.id.inner()),
522 kind: BasicTypeKind::GridStorage(element_layout, *width, *height),
523 total_size: MemorySize(
524 GRID_HEADER_SIZE.0 + element_size.0 * (*width as u32) * (*height as u32),
525 ),
526 max_alignment: max(GRID_HEADER_ALIGNMENT, element_alignment),
527 })
528 }
529
530 TypeKind::SliceView(element_type) => {
531 let element_layout = self.layout(element_type);
532 self.insert_layout(element_type.id, element_layout.clone());
533
534 Rc::new(BasicType {
535 id: BasicTypeId(ty.id.inner()),
536 kind: BasicTypeKind::SliceView(element_layout),
537 total_size: PTR_SIZE,
538 max_alignment: PTR_ALIGNMENT,
539 })
540 }
541
542 TypeKind::SparseStorage(element_type, capacity) => {
543 let element_layout = self.layout(element_type);
544 let size = sparse_mem::layout_size(*capacity as u16, element_layout.total_size.0);
545
546 Rc::new(BasicType {
547 id: BasicTypeId(ty.id.inner()),
548 kind: BasicTypeKind::SparseStorage(element_layout, *capacity),
549 total_size: MemorySize(size as u32),
550 max_alignment: MemoryAlignment::U64,
551 })
552 }
553
554 TypeKind::SparseView(element_type) => {
555 let element_layout = self.layout(element_type);
556 self.insert_layout(element_type.id, element_layout.clone());
557
558 Rc::new(BasicType {
559 id: BasicTypeId(ty.id.inner()),
560 kind: BasicTypeKind::SparseView(element_layout),
561 total_size: PTR_SIZE,
562 max_alignment: PTR_ALIGNMENT,
563 })
564 }
565
566 TypeKind::StackStorage(element_type, capacity) => {
567 let (element_layout, total_size, _max_alignment) =
568 self.layout_vec_like(element_type, *capacity);
569
570 let storage_type = Rc::new(BasicType {
571 id: BasicTypeId(ty.id.inner()),
572 kind: BasicTypeKind::StackStorage(element_layout.clone(), *capacity),
573 total_size,
574 max_alignment: VEC_HEADER_ALIGNMENT,
575 });
576
577 self.insert_layout(element_type.id, element_layout);
578
579 storage_type
580 }
581
582 TypeKind::StackView(element_type) => {
583 let element_layout = self.layout(element_type);
584 self.insert_layout(element_type.id, element_layout.clone());
585
586 Rc::new(BasicType {
587 id: BasicTypeId(ty.id.inner()),
588 kind: BasicTypeKind::DynamicLengthVecView(element_layout),
589 total_size: PTR_SIZE,
590 max_alignment: PTR_ALIGNMENT,
591 })
592 }
593
594 TypeKind::QueueStorage(element_type, capacity) => {
595 let (element_layout, total_size, _max_alignment) =
596 self.layout_vec_like(element_type, *capacity);
597
598 let storage_type = Rc::new(BasicType {
599 id: BasicTypeId(ty.id.inner()),
600 kind: BasicTypeKind::QueueStorage(element_layout.clone(), *capacity),
601 total_size,
602 max_alignment: VEC_HEADER_ALIGNMENT,
603 });
604
605 self.insert_layout(element_type.id, element_layout);
606
607 storage_type
608 }
609
610 TypeKind::QueueView(element_type) => {
611 let element_layout = self.layout(element_type);
612 self.insert_layout(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 self.insert_layout(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 field_layouts = Vec::with_capacity(struct_type.field_name_sorted_fields.len());
684 let mut max_alignment = MemoryAlignment::U8;
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 self.insert_layout(field_type.field_type.id, field_layout.clone());
693
694 if field_layout.max_alignment > max_alignment {
695 max_alignment = field_layout.max_alignment;
696 }
697
698 field_layouts.push((field_name.clone(), field_layout));
699 }
700
701 let mut offset = MemoryOffset(0);
703 let mut items = Vec::with_capacity(field_layouts.len());
704
705 for (field_name, field_layout) in field_layouts {
706 offset = align_to(offset, field_layout.max_alignment);
707
708 items.push(OffsetMemoryItem {
709 offset,
710 size: field_layout.total_size,
711 name: field_name,
712 ty: field_layout.clone(),
713 });
714
715 offset = offset + field_layout.total_size;
716 }
717
718 let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
719
720 StructType {
721 name: name.to_string(),
722 fields: items,
723 total_size,
724 max_alignment,
725 }
726 }
727
728 pub fn layout_struct(
729 &mut self,
730 struct_type: &AnonymousStructType,
731 name: &str,
732 type_id: TypeId,
733 ) -> BasicTypeRef {
734 for (_field_name, struct_field) in &struct_type.field_name_sorted_fields {
736 let field_type = &struct_field.field_type;
737 let _field_layout = self.layout(field_type);
738
739 }
741
742 let struct_kind = TypeKind::AnonymousStruct(struct_type.clone());
744 if let Some(existing_layout) = self.kind_to_layout.get(&struct_kind).cloned() {
745 self.insert_layout(type_id, existing_layout.clone());
747 return existing_layout;
748 }
749
750 let struct_layout = self.layout_struct_type(struct_type, name);
751
752 let struct_id = type_id;
754
755 let basic_type = Rc::new(BasicType {
756 id: BasicTypeId(struct_id.inner()),
757 total_size: struct_layout.total_size,
758 max_alignment: struct_layout.max_alignment,
759 kind: BasicTypeKind::Struct(struct_layout),
760 });
761
762 self.insert_layout(struct_id, basic_type.clone());
764 let _ = self.kind_to_layout.insert(struct_kind, basic_type.clone());
765
766 basic_type
767 }
768
769 #[must_use]
770 pub fn layout_optional_type(&mut self, inner_type: &TypeRef, type_id: TypeId) -> BasicTypeRef {
771 let optional_kind = TypeKind::Optional(inner_type.clone());
773 if let Some(existing_layout) = self.kind_to_layout.get(&optional_kind) {
774 assert!(matches!(&existing_layout.kind, BasicTypeKind::Optional(_)));
775 return existing_layout.clone();
776 }
777
778 let inner_layout = self.layout(inner_type);
780
781 self.insert_layout(inner_type.id, inner_layout.clone());
783 let _ = self
784 .kind_to_layout
785 .insert((*inner_type.kind).clone(), inner_layout);
786
787 let optional_union = self.layout_optional_type_items(inner_type);
789
790 let optional_id = type_id;
792
793 let basic_type = Rc::new(BasicType {
794 id: BasicTypeId(optional_id.inner()),
795 total_size: optional_union.total_size,
796 max_alignment: optional_union.max_alignment,
797 kind: BasicTypeKind::Optional(optional_union),
798 });
799
800 self.insert_layout(optional_id, basic_type.clone());
802 let _ = self
803 .kind_to_layout
804 .insert(optional_kind, basic_type.clone());
805
806 basic_type
807 }
808
809 #[must_use]
810 pub fn layout_optional_type_items(&mut self, inner_type: &TypeRef) -> TaggedUnion {
811 let gen_type = self.layout_type(inner_type);
812
813 let payload_tagged_variant = TaggedUnionVariant {
814 name: "Some".to_string(),
815 ty: gen_type,
816 };
817
818 let none_tagged_variant = TaggedUnionVariant {
819 name: "None".to_string(),
820 ty: Rc::new(BasicType {
821 id: BasicTypeId(0),
822 kind: BasicTypeKind::Empty,
823 total_size: MemorySize(0),
824 max_alignment: MemoryAlignment::U8,
825 }),
826 };
827
828 Self::layout_tagged_union(&[none_tagged_variant, payload_tagged_variant], "Maybe")
829 }
830
831 #[must_use]
832 pub fn layout_tuple_items(&mut self, types: &[TypeRef]) -> TupleType {
833 let mut max_alignment = MemoryAlignment::U8;
835 for ty in types {
836 let elem_layout = self.layout(ty);
838
839 self.insert_layout(ty.id, elem_layout.clone());
841
842 if elem_layout.max_alignment > max_alignment {
843 max_alignment = elem_layout.max_alignment;
844 }
845 }
846
847 let mut offset = MemoryOffset(0);
849 let mut items = Vec::with_capacity(types.len());
850
851 for (i, ty) in types.iter().enumerate() {
852 let elem_layout = self.layout(ty);
854
855 offset = align_to(offset, elem_layout.max_alignment);
856
857 items.push(OffsetMemoryItem {
858 offset,
859 size: elem_layout.total_size,
860 name: i.to_string(),
861 ty: elem_layout.clone(),
862 });
863
864 offset = offset + elem_layout.total_size;
865 }
866
867 let total_size = adjust_size_to_alignment(offset.as_size(), max_alignment);
869
870 TupleType {
871 fields: items,
872 total_size,
873 max_alignment,
874 }
875 }
876
877 #[must_use]
878 pub fn layout_tuple(&mut self, types: &[TypeRef], tuple_id: TypeId) -> BasicTypeRef {
879 for ty in types {
881 let inner_layout = self.layout(ty);
882 self.insert_layout(ty.id, inner_layout.clone());
883 let _ = self
884 .kind_to_layout
885 .insert((*ty.kind).clone(), inner_layout.clone());
886 }
887
888 let tuple_kind = TypeKind::Tuple(types.to_vec());
890 if let Some(existing_layout) = self.kind_to_layout.get(&tuple_kind).cloned() {
891 self.insert_layout(tuple_id, existing_layout.clone());
893 return existing_layout;
894 }
895
896 let tuple_layout = self.layout_tuple_items(types);
897
898 let basic_type = Rc::new(BasicType {
899 id: BasicTypeId(tuple_id.inner()),
900 total_size: tuple_layout.total_size,
901 max_alignment: tuple_layout.max_alignment,
902 kind: BasicTypeKind::Tuple(tuple_layout),
903 });
904
905 self.insert_layout(tuple_id, basic_type.clone());
907 let _ = self.kind_to_layout.insert(tuple_kind, basic_type.clone());
908
909 basic_type
910 }
911
912 fn insert_layout(&mut self, type_id: TypeId, layout: BasicTypeRef) {
914 let _ = self.id_to_layout.insert(type_id, layout.clone());
915
916 let universal_hash = layout.universal_hash_u64();
918 let _ = self.universal_id_to_layout.insert(universal_hash, layout.clone());
919 let _ = self.universal_short_id_to_layout.insert(universal_hash as u32, layout);
920 }
921
922 #[must_use] pub fn universal_short_id(&self, short_id: u32) -> &BasicTypeRef {
923 if let Some(x) = self.universal_short_id_to_layout.get(&short_id) {
924 x
925 } else {
926 for (hash, ty) in &self.universal_short_id_to_layout {
927 eprintln!("{hash:X} ({hash}) {}", ty.kind);
928 }
929 panic!("not found")
930 }
931 }
932}
933
934fn create_basic_type(
935 type_id: TypeId,
936 kind: BasicTypeKind,
937 size: MemorySize,
938 alignment: MemoryAlignment,
939) -> BasicTypeRef {
940 let basic_type_id = BasicTypeId(type_id.inner());
941
942 Rc::new(BasicType {
943 id: basic_type_id,
944 kind,
945 total_size: size,
946 max_alignment: alignment,
947 })
948}
949
950pub const fn check_type_size(ty: &BasicType, _comment: &str) {
951 if ty.total_size.0 > 1024 * 1024 {
952 }
954}