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