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 it be copied without any extra logic
21    pub const IS_BLITTABLE: 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
28    #[must_use]
29    pub const fn new() -> Self {
30        Self::NONE
31    }
32
33    #[must_use]
34    pub const fn contains(self, flag: Self) -> bool {
35        (self.0 & flag.0) != 0
36    }
37
38    #[must_use]
39    pub const fn union(self, other: Self) -> Self {
40        Self(self.0 | other.0)
41    }
42
43    /// Compute type flags based on the `TypeKind`
44    #[allow(clippy::too_many_lines)]
45    #[must_use]
46    pub fn compute_for_type_kind(kind: &TypeKind) -> Self {
47        let mut flags = Self::NONE;
48
49        match kind {
50            TypeKind::Never => {
51                flags = flags.union(Self::IS_ALLOWED_RETURN);
52            }
53            TypeKind::Any => {
54                flags = flags
55                    .union(Self::IS_BLITTABLE)
56                    .union(Self::IS_STORAGE)
57                    .union(Self::IS_ALLOWED_RETURN);
58            }
59            TypeKind::Codepoint => {
60                flags = flags
61                    .union(Self::IS_BLITTABLE)
62                    .union(Self::IS_STORAGE)
63                    .union(Self::IS_ALLOWED_RETURN)
64                    .union(Self::IS_SCALAR);
65            }
66            TypeKind::Byte => {
67                flags = flags
68                    .union(Self::IS_BLITTABLE)
69                    .union(Self::IS_STORAGE)
70                    .union(Self::IS_ALLOWED_RETURN)
71                    .union(Self::IS_SCALAR);
72            }
73            TypeKind::Int => {
74                flags = flags
75                    .union(Self::IS_BLITTABLE)
76                    .union(Self::IS_STORAGE)
77                    .union(Self::IS_ALLOWED_RETURN)
78                    .union(Self::IS_SCALAR);
79            }
80            TypeKind::String(..) => {
81                flags = flags
82                    .union(Self::IS_BLITTABLE)
83                    .union(Self::IS_ALLOWED_RETURN)
84                    .union(Self::IS_SCALAR);
85            }
86            TypeKind::StringStorage(_, _, _) => {
87                flags = flags
88                    .union(Self::IS_BLITTABLE)
89                    .union(Self::IS_STORAGE)
90                    .union(Self::IS_SCALAR);
91            }
92
93            TypeKind::Float => {
94                flags = flags
95                    .union(Self::IS_BLITTABLE)
96                    .union(Self::IS_STORAGE)
97                    .union(Self::IS_ALLOWED_RETURN)
98                    .union(Self::IS_SCALAR);
99            }
100            TypeKind::Bool => {
101                flags = flags
102                    .union(Self::IS_BLITTABLE)
103                    .union(Self::IS_STORAGE)
104                    .union(Self::IS_ALLOWED_RETURN)
105                    .union(Self::IS_SCALAR);
106            }
107            TypeKind::Unit => {
108                flags = flags
109                    .union(Self::IS_BLITTABLE)
110                    .union(Self::IS_STORAGE)
111                    .union(Self::IS_ALLOWED_RETURN)
112                    .union(Self::IS_SCALAR);
113            }
114            TypeKind::Function(_) => {}
115            TypeKind::Enum(enum_type) => {
116                if enum_type.are_all_variants_with_blittable_payload() {
117                    flags = flags
118                        .union(Self::IS_BLITTABLE)
119                        .union(Self::IS_ALLOWED_RETURN);
120                } else {
121                    panic!("enums should be blittable")
122                }
123                if enum_type.are_all_variants_with_storage_payload() {
124                    flags = flags.union(Self::IS_STORAGE);
125                }
126            }
127            TypeKind::Tuple(types) => {
128                // A tuple is blittable if all its component types are blittable
129                if types.iter().all(|t| t.flags.contains(Self::IS_BLITTABLE)) {
130                    flags = flags
131                        .union(Self::IS_BLITTABLE)
132                        .union(Self::IS_ALLOWED_RETURN);
133                }
134                if types.iter().all(|t| t.flags.contains(Self::IS_STORAGE)) {
135                    flags = flags.union(Self::IS_STORAGE);
136                }
137            }
138            TypeKind::Optional(inner) => {
139                // An optional is blittable if its inner type is blittable
140                if inner.flags.contains(Self::IS_BLITTABLE) {
141                    flags = flags.union(Self::IS_BLITTABLE);
142                }
143                // TODO: check this
144                if inner.flags.contains(Self::IS_ALLOWED_RETURN) {
145                    flags = flags.union(Self::IS_ALLOWED_RETURN);
146                }
147                if inner.flags.contains(Self::IS_STORAGE) {
148                    flags = flags.union(Self::IS_STORAGE);
149                }
150            }
151            TypeKind::NamedStruct(named) => {
152                if named.anon_struct_type.flags.contains(Self::IS_BLITTABLE) {
153                    flags = flags.union(Self::IS_BLITTABLE);
154                }
155                if named.anon_struct_type.flags.contains(Self::IS_STORAGE) {
156                    flags = flags.union(Self::IS_STORAGE);
157                }
158                if named
159                    .anon_struct_type
160                    .flags
161                    .contains(Self::IS_ALLOWED_RETURN)
162                {
163                    flags = flags.union(Self::IS_ALLOWED_RETURN);
164                }
165            }
166            TypeKind::AnonymousStruct(anon) => {
167                if anon
168                    .field_name_sorted_fields
169                    .iter()
170                    .all(|(_name, field)| field.field_type.flags.contains(Self::IS_BLITTABLE))
171                {
172                    flags = flags.union(Self::IS_BLITTABLE);
173                }
174
175                anon.field_name_sorted_fields
176                    .iter()
177                    .all(|(_name, field)| field.field_type.flags.contains(Self::IS_ALLOWED_RETURN));
178                flags = flags.union(Self::IS_ALLOWED_RETURN);
179
180                if anon
181                    .field_name_sorted_fields
182                    .iter()
183                    .all(|(_name, field)| field.field_type.flags.contains(Self::IS_STORAGE))
184                {
185                    flags = flags.union(Self::IS_STORAGE);
186                }
187            }
188            TypeKind::MapStorage(key, value, _) => {
189                if key.is_blittable() && value.is_blittable() {
190                    flags = flags.union(Self::IS_BLITTABLE);
191                }
192
193                if key.is_storage() && value.is_storage() {
194                    flags = flags.union(Self::IS_STORAGE);
195                }
196            }
197            TypeKind::DynamicLengthMapView(_, _) => {
198                flags = flags.union(Self::IS_ALLOWED_RETURN);
199            }
200            TypeKind::FixedCapacityAndLengthArray(inner, _) => {
201                if inner.is_blittable() {
202                    flags = flags.union(Self::IS_BLITTABLE);
203                }
204                if inner.is_storage() {
205                    flags = flags.union(Self::IS_STORAGE);
206                }
207            }
208            TypeKind::SliceView(_) => {
209                flags = flags.union(Self::IS_ALLOWED_RETURN);
210            }
211            TypeKind::VecStorage(inner, _) => {
212                if inner.is_blittable() {
213                    flags = flags.union(Self::IS_BLITTABLE);
214                }
215                if inner.is_storage() {
216                    flags = flags.union(Self::IS_STORAGE);
217                }
218            }
219            TypeKind::DynamicLengthVecView(_) => {
220                flags = flags.union(Self::IS_ALLOWED_RETURN);
221            }
222
223            TypeKind::StackStorage(inner, _) => {
224                if inner.is_blittable() {
225                    flags = flags.union(Self::IS_BLITTABLE);
226                }
227                if inner.is_storage() {
228                    flags = flags.union(Self::IS_STORAGE);
229                }
230            }
231            TypeKind::StackView(_) => {
232                flags = flags.union(Self::IS_ALLOWED_RETURN);
233            }
234
235            TypeKind::QueueStorage(inner, _) => {
236                if inner.is_blittable() {
237                    flags = flags.union(Self::IS_BLITTABLE);
238                }
239                if inner.is_storage() {
240                    flags = flags.union(Self::IS_STORAGE);
241                }
242            }
243            TypeKind::QueueView(_) => {
244                flags = flags.union(Self::IS_ALLOWED_RETURN);
245            }
246            TypeKind::GridStorage(inner, _, _) => {
247                if inner.is_blittable() {
248                    flags = flags.union(Self::IS_BLITTABLE);
249                }
250                if inner.is_storage() {
251                    flags = flags.union(Self::IS_STORAGE);
252                }
253            }
254            TypeKind::GridView(_) => {
255                flags = flags.union(Self::IS_ALLOWED_RETURN);
256            }
257            TypeKind::SparseStorage(inner, _) => {
258                if inner.is_blittable() {
259                    flags = flags.union(Self::IS_BLITTABLE);
260                }
261                if inner.is_storage() {
262                    flags = flags.union(Self::IS_STORAGE);
263                }
264            }
265            TypeKind::SparseView(_) => {
266                flags = flags.union(Self::IS_ALLOWED_RETURN);
267            }
268            TypeKind::Range(_inner) => {
269                flags = flags
270                    .union(Self::IS_BLITTABLE)
271                    .union(Self::IS_ALLOWED_RETURN);
272                flags = flags.union(Self::IS_STORAGE);
273            }
274        }
275
276        flags
277    }
278}