swamp_types/
flags.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5
6use crate::type_kind::TypeKind;
7
8/// Flags describing properties of a type
9#[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    /// Can be held on to for a short while
21    pub const ALLOWED_FOR_SCOPED_BORROW: Self = Self(1 << 0);
22    /// Is the type self-contained in a register
23    pub const IS_SCALAR: Self = Self(1 << 1);
24    /// Can it be stored in a sum or product type
25    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    /// Compute type flags based on the `TypeKind`
45    #[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) // is this true?
116                    .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                // A tuple is blittable if all its component types are blittable
136                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                // An optional is blittable if its inner type is blittable
151                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                // TODO: check this
159                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}