1use crate::type_kind::TypeKind;
7
8#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
10pub struct TypeFlags(u32);
11
12impl Default for TypeFlags {
13 fn default() -> Self {
14 Self::new()
15 }
16}
17
18impl TypeFlags {
19 pub const NONE: Self = Self(0);
20 pub const ALLOWED_FOR_SCOPED_BORROW: Self = Self(1 << 0);
22 pub const IS_SCALAR: Self = Self(1 << 1);
24 pub const IS_STORAGE: Self = Self(1 << 2);
26 pub const IS_ALLOWED_RETURN: Self = Self(1 << 3);
27 pub const ALLOWED_FOR_VARIABLE: Self = Self(1 << 4);
28
29 #[must_use]
30 pub const fn new() -> Self {
31 Self::NONE
32 }
33
34 #[must_use]
35 pub const fn contains(self, flag: Self) -> bool {
36 (self.0 & flag.0) != 0
37 }
38
39 #[must_use]
40 pub const fn union(self, other: Self) -> Self {
41 Self(self.0 | other.0)
42 }
43
44 #[allow(clippy::too_many_lines)]
46 #[must_use]
47 pub fn compute_for_type_kind(kind: &TypeKind) -> Self {
48 let mut flags = Self::NONE;
49
50 match kind {
51 TypeKind::Never => {
52 flags = flags.union(Self::IS_ALLOWED_RETURN);
53 }
54 TypeKind::Any => {
55 flags = flags
56 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
57 .union(Self::IS_ALLOWED_RETURN);
58 }
59 TypeKind::Pointer(_) => {
60 flags = flags
61 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
62 .union(Self::IS_ALLOWED_RETURN);
63 }
64 TypeKind::Codepoint => {
65 flags = flags
66 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
67 .union(Self::ALLOWED_FOR_VARIABLE)
68 .union(Self::IS_STORAGE)
69 .union(Self::IS_ALLOWED_RETURN)
70 .union(Self::IS_SCALAR);
71 }
72 TypeKind::Byte => {
73 flags = flags
74 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
75 .union(Self::ALLOWED_FOR_VARIABLE)
76 .union(Self::IS_STORAGE)
77 .union(Self::IS_ALLOWED_RETURN)
78 .union(Self::IS_SCALAR);
79 }
80 TypeKind::Short => {
81 flags = flags
82 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
83 .union(Self::ALLOWED_FOR_VARIABLE)
84 .union(Self::IS_STORAGE)
85 .union(Self::IS_ALLOWED_RETURN)
86 .union(Self::IS_SCALAR);
87 }
88 TypeKind::Int => {
89 flags = flags
90 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
91 .union(Self::ALLOWED_FOR_VARIABLE)
92 .union(Self::IS_STORAGE)
93 .union(Self::IS_ALLOWED_RETURN)
94 .union(Self::IS_SCALAR);
95 }
96
97 TypeKind::Float => {
98 flags = flags
99 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
100 .union(Self::ALLOWED_FOR_VARIABLE)
101 .union(Self::IS_STORAGE)
102 .union(Self::IS_ALLOWED_RETURN)
103 .union(Self::IS_SCALAR);
104 }
105 TypeKind::Bool => {
106 flags = flags
107 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
108 .union(Self::ALLOWED_FOR_VARIABLE)
109 .union(Self::IS_STORAGE)
110 .union(Self::IS_ALLOWED_RETURN)
111 .union(Self::IS_SCALAR);
112 }
113 TypeKind::Unit => {
114 flags = flags
115 .union(Self::ALLOWED_FOR_SCOPED_BORROW) .union(Self::IS_STORAGE)
117 .union(Self::IS_ALLOWED_RETURN)
118 .union(Self::IS_SCALAR);
119 }
120 TypeKind::Function(_) => {}
121 TypeKind::Enum(enum_type) => {
122 if enum_type.are_all_variants_with_blittable_payload() {
123 flags = flags
124 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
125 .union(Self::ALLOWED_FOR_VARIABLE)
126 .union(Self::IS_ALLOWED_RETURN);
127 } else {
128 panic!("enums should be blittable")
129 }
130 if enum_type.are_all_variants_with_storage_payload() {
131 flags = flags.union(Self::IS_STORAGE);
132 }
133 }
134 TypeKind::Tuple(types) => {
135 if types
137 .iter()
138 .all(|t| t.flags.contains(Self::ALLOWED_FOR_SCOPED_BORROW))
139 {
140 flags = flags
141 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
142 .union(Self::ALLOWED_FOR_VARIABLE)
143 .union(Self::IS_ALLOWED_RETURN);
144 }
145 if types.iter().all(|t| t.flags.contains(Self::IS_STORAGE)) {
146 flags = flags.union(Self::IS_STORAGE);
147 }
148 }
149 TypeKind::Optional(inner) => {
150 if inner.flags.contains(Self::ALLOWED_FOR_SCOPED_BORROW) {
152 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
153 }
154 if inner.flags.contains(Self::ALLOWED_FOR_VARIABLE) {
155 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
156 }
157
158 if inner.flags.contains(Self::IS_ALLOWED_RETURN) {
160 flags = flags.union(Self::IS_ALLOWED_RETURN);
161 }
162 if inner.flags.contains(Self::IS_STORAGE) {
163 flags = flags.union(Self::IS_STORAGE);
164 }
165 }
166 TypeKind::NamedStruct(named) => {
167 if named
168 .anon_struct_type
169 .flags
170 .contains(Self::ALLOWED_FOR_SCOPED_BORROW)
171 {
172 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
173 }
174 if named
175 .anon_struct_type
176 .flags
177 .contains(Self::ALLOWED_FOR_VARIABLE)
178 {
179 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
180 }
181 if named.anon_struct_type.flags.contains(Self::IS_STORAGE) {
182 flags = flags.union(Self::IS_STORAGE);
183 }
184 if named
185 .anon_struct_type
186 .flags
187 .contains(Self::IS_ALLOWED_RETURN)
188 {
189 flags = flags.union(Self::IS_ALLOWED_RETURN);
190 }
191 }
192 TypeKind::AnonymousStruct(anon) => {
193 if anon.field_name_sorted_fields.iter().all(|(_name, field)| {
194 field
195 .field_type
196 .flags
197 .contains(Self::ALLOWED_FOR_SCOPED_BORROW)
198 }) {
199 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
200 }
201
202 if anon.field_name_sorted_fields.iter().all(|(_name, field)| {
203 field.field_type.flags.contains(Self::ALLOWED_FOR_VARIABLE)
204 }) {
205 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
206 }
207
208 anon.field_name_sorted_fields
209 .iter()
210 .all(|(_name, field)| field.field_type.flags.contains(Self::IS_ALLOWED_RETURN));
211 flags = flags.union(Self::IS_ALLOWED_RETURN);
212
213 if anon
214 .field_name_sorted_fields
215 .iter()
216 .all(|(_name, field)| field.field_type.flags.contains(Self::IS_STORAGE))
217 {
218 flags = flags.union(Self::IS_STORAGE);
219 }
220 }
221 TypeKind::MapStorage(key, value, _) => {
222 if key.allowed_for_scoped_borrow() && value.allowed_for_scoped_borrow() {
223 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
224 }
225
226 if key.can_be_stored_in_variable() && value.can_be_stored_in_variable() {
227 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
228 }
229
230 if key.is_storage() && value.is_storage() {
231 flags = flags.union(Self::IS_STORAGE);
232 }
233 }
234
235 TypeKind::DynamicLengthMapView(_, _) => {
236 flags = flags.union(Self::IS_ALLOWED_RETURN);
237 }
238
239 TypeKind::FixedCapacityAndLengthArray(inner, _) => {
240 if inner.allowed_for_scoped_borrow() {
241 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
242 }
243 if inner.can_be_stored_in_variable() {
244 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
245 }
246 if inner.is_storage() {
247 flags = flags.union(Self::IS_STORAGE);
248 }
249 }
250 TypeKind::SliceView(_) => {
251 flags = flags.union(Self::IS_ALLOWED_RETURN);
252 }
253 TypeKind::VecStorage(inner, _) => {
254 if inner.allowed_for_scoped_borrow() {
255 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
256 }
257 if inner.can_be_stored_in_variable() {
258 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
259 }
260 if inner.is_storage() {
261 flags = flags.union(Self::IS_STORAGE);
262 }
263 }
264 TypeKind::DynamicLengthVecView(_) => {
265 flags = flags.union(Self::IS_ALLOWED_RETURN);
266 }
267
268 TypeKind::StringStorage(_, _, _) => {
269 flags = flags
270 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
271 .union(Self::ALLOWED_FOR_VARIABLE)
272 .union(Self::IS_STORAGE);
273 }
274
275 TypeKind::StringView(..) => {
276 flags = flags
277 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
278 .union(Self::ALLOWED_FOR_VARIABLE)
279 .union(Self::IS_ALLOWED_RETURN);
280 }
281
282 TypeKind::StackStorage(inner, _) => {
283 if inner.allowed_for_scoped_borrow() {
284 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
285 }
286 if inner.can_be_stored_in_variable() {
287 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
288 }
289 if inner.is_storage() {
290 flags = flags.union(Self::IS_STORAGE);
291 }
292 }
293 TypeKind::StackView(_) => {
294 flags = flags.union(Self::IS_ALLOWED_RETURN);
295 }
296
297 TypeKind::QueueStorage(inner, _) => {
298 if inner.allowed_for_scoped_borrow() {
299 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
300 }
301 if inner.can_be_stored_in_variable() {
302 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
303 }
304 if inner.is_storage() {
305 flags = flags.union(Self::IS_STORAGE);
306 }
307 }
308 TypeKind::QueueView(_) => {
309 flags = flags.union(Self::IS_ALLOWED_RETURN);
310 }
311 TypeKind::GridStorage(inner, _, _) => {
312 if inner.allowed_for_scoped_borrow() {
313 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
314 }
315 if inner.can_be_stored_in_variable() {
316 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
317 }
318 if inner.is_storage() {
319 flags = flags.union(Self::IS_STORAGE);
320 }
321 }
322 TypeKind::GridView(_) => {
323 flags = flags.union(Self::IS_ALLOWED_RETURN);
324 }
325 TypeKind::SparseStorage(inner, _) => {
326 if inner.allowed_for_scoped_borrow() {
327 flags = flags.union(Self::ALLOWED_FOR_SCOPED_BORROW);
328 }
329 if inner.can_be_stored_in_variable() {
330 flags = flags.union(Self::ALLOWED_FOR_VARIABLE);
331 }
332 if inner.is_storage() {
333 flags = flags.union(Self::IS_STORAGE);
334 }
335 }
336 TypeKind::SparseView(_) => {
337 flags = flags.union(Self::IS_ALLOWED_RETURN);
338 }
339 TypeKind::Range(_inner) => {
340 flags = flags
341 .union(Self::ALLOWED_FOR_SCOPED_BORROW)
342 .union(Self::ALLOWED_FOR_VARIABLE)
343 .union(Self::IS_ALLOWED_RETURN);
344 flags = flags.union(Self::IS_STORAGE);
345 }
346 }
347
348 flags
349 }
350}