1use crate::alloc::{FrameMemoryRegion, ScopeAllocator};
7use seq_map::SeqMap;
8use swamp_types::{AnonymousStructType, EnumVariantType, Type};
9use swamp_vm_types::{
10 FLOAT_SIZE, INT_SIZE, MAP_REFERENCE_SIZE, MAP_SIZE, MemoryAlignment, MemoryOffset, MemorySize,
11 STR_SIZE, VEC_REFERENCE_SIZE,
12};
13use tracing::{error, info};
14
15pub fn layout_struct(anon_struct: &AnonymousStructType) -> (MemorySize, MemoryAlignment) {
16 let mut calculated_offset = MemoryOffset(0);
17 let mut largest_alignment = MemoryAlignment::U8;
18 for (_name, field) in &anon_struct.field_name_sorted_fields {
19 let (field_size, field_alignment) = type_size_and_alignment(&field.field_type);
20 if field_alignment.greater_than(largest_alignment) {
21 largest_alignment = field_alignment;
22 }
23 calculated_offset.space(field_size, field_alignment);
24 }
25
26 let total_offset = calculated_offset.space(MemorySize(0), largest_alignment);
27
28 (total_offset.as_size(), largest_alignment)
29}
30
31#[must_use]
32pub fn layout_tuple(types: &Vec<Type>) -> (MemorySize, MemoryAlignment) {
33 let mut calculated_offset = MemoryOffset(0);
34 let mut largest_alignment = MemoryAlignment::U8;
35 for ty in types {
36 let (field_size, field_alignment) = type_size_and_alignment(&ty);
37 if field_alignment.greater_than(largest_alignment) {
38 largest_alignment = field_alignment;
39 }
40 calculated_offset.space(field_size, field_alignment);
41 }
42 let total_offset = calculated_offset.space(MemorySize(0), largest_alignment);
43 (total_offset.as_size(), largest_alignment)
44}
45
46#[must_use]
47pub fn layout_tuple_elements(
48 types: &Vec<Type>,
49) -> (MemorySize, MemoryAlignment, Vec<(MemoryOffset, MemorySize)>) {
50 let mut calculated_offset = MemoryOffset(0);
51 let mut largest_alignment = MemoryAlignment::U8;
52
53 let mut elements = Vec::new();
54 for ty in types {
55 let (field_size, field_alignment) = type_size_and_alignment(&ty);
56 if field_alignment.greater_than(largest_alignment) {
57 largest_alignment = field_alignment;
58 }
59 elements.push((calculated_offset, field_size));
60 calculated_offset.space(field_size, field_alignment);
61 }
62 let total_offset = calculated_offset.space(MemorySize(0), largest_alignment);
63 (total_offset.as_size(), largest_alignment, elements)
64}
65
66pub fn layout_union(variants: &SeqMap<String, EnumVariantType>) -> (MemorySize, MemoryAlignment) {
67 let mut max_variant_alignment = MemoryAlignment::U8;
68 let mut max_variant_size = MemorySize(0);
69 let mut calculated_offset = MemoryOffset(0);
70 for (_name, variant) in variants {
71 let (variant_size, variant_alignment) = match variant {
72 EnumVariantType::Struct(anon_struct) => layout_struct(&anon_struct.anon_struct),
73 EnumVariantType::Tuple(types) => layout_tuple(&types.fields_in_order),
74 EnumVariantType::Nothing(_) => (MemorySize(0), MemoryAlignment::U8),
75 };
76
77 if variant_alignment.greater_than(max_variant_alignment) {
78 max_variant_alignment = variant_alignment;
79 }
80
81 if variant_size.0 > max_variant_size.0 {
82 max_variant_size = variant_size;
83 }
84 }
85
86 (max_variant_size, max_variant_alignment)
87}
88
89pub fn is_vec(ty: &Type) -> Option<(MemorySize, MemoryAlignment)> {
90 match ty {
91 Type::NamedStruct(named_struct) => {
92 if named_struct.module_path == vec!["core-0.0.0".to_string()]
93 && named_struct.assigned_name.starts_with("Vec<")
94 {
95 Some((MemorySize(VEC_REFERENCE_SIZE), MemoryAlignment::U16))
96 } else {
97 None
98 }
99 }
100 _ => None,
101 }
102}
103
104pub fn is_map(ty: &Type) -> Option<(MemorySize, MemoryAlignment)> {
105 match ty {
106 Type::NamedStruct(named_struct) => {
107 if named_struct.module_path == vec!["core-0.0.0".to_string()]
108 && named_struct.assigned_name.starts_with("Map<")
109 {
110 Some((MemorySize(MAP_SIZE), MemoryAlignment::U16))
111 } else {
112 None
113 }
114 }
115 _ => None,
116 }
117}
118
119pub fn type_size_and_alignment(ty: &Type) -> (MemorySize, MemoryAlignment) {
120 match ty {
121 Type::Int => (MemorySize(INT_SIZE), MemoryAlignment::U32),
122 Type::Float => (MemorySize(FLOAT_SIZE), MemoryAlignment::U32),
123 Type::String => (MemorySize(STR_SIZE), MemoryAlignment::U16),
124 Type::Bool => (MemorySize(1), MemoryAlignment::U8),
125 Type::Unit => (MemorySize(0), MemoryAlignment::U8),
126 Type::Never => (MemorySize(0), MemoryAlignment::U8),
127 Type::Tuple(types) => layout_tuple(types),
128 Type::NamedStruct(named_struct) => {
129 if named_struct.module_path == vec!["core-0.0.0".to_string()]
130 && named_struct.assigned_name.starts_with("Vec<")
131 {
132 (MemorySize(VEC_REFERENCE_SIZE), MemoryAlignment::U16)
133 } else if named_struct.module_path == vec!["core-0.0.0".to_string()]
134 && named_struct.assigned_name.starts_with("Map<")
135 {
136 (MemorySize(MAP_REFERENCE_SIZE), MemoryAlignment::U16)
137 } else {
138 type_size_and_alignment(&Type::AnonymousStruct(
139 named_struct.anon_struct_type.clone(),
140 ))
141 }
142 }
143 Type::Slice(value_type) => type_size_and_alignment(value_type),
144 Type::SlicePair(key_type, value_type) => {
145 layout_tuple(&vec![*key_type.clone(), *value_type.clone()])
146 }
147 Type::AnonymousStruct(anon_struct) => layout_struct(anon_struct),
148 Type::Enum(enum_type) => {
149 let (offset, alignment) = layout_union(&enum_type.variants);
150
151 let alignment_octets: usize = alignment.into();
152
153 (MemorySize(offset.0 + alignment_octets as u16), alignment)
154 }
155 Type::Function(_) => (MemorySize(2), MemoryAlignment::U16),
156 Type::Optional(inner_type) => {
157 let (offset, alignment) = type_size_and_alignment(inner_type);
158
159 let alignment_octets: usize = alignment.into();
160
161 (MemorySize(offset.0 + alignment_octets as u16), alignment)
162 }
163 Type::Generic(a, b) => {
164 error!(?a, ?b, "generic can not be generated");
165 panic!("generic is not supported")
166 }
167 Type::MutableReference(referenced_type) => type_size_and_alignment(referenced_type),
168 Type::Blueprint(_) => panic!("not supported"),
169 Type::Variable(_) => panic!("not supported"),
170 Type::External(_) => todo!(),
171 }
172}
173
174pub fn reserve_space_for_type(ty: &Type, allocator: &mut ScopeAllocator) -> FrameMemoryRegion {
175 let (size, alignment) = type_size_and_alignment(ty);
176
177 allocator.reserve(size, alignment)
178}