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::Any => {
51                flags = flags
52                    .union(Self::IS_BLITTABLE)
53                    .union(Self::IS_STORAGE)
54                    .union(Self::IS_ALLOWED_RETURN);
55            }
56            TypeKind::Codepoint => {
57                flags = flags
58                    .union(Self::IS_BLITTABLE)
59                    .union(Self::IS_STORAGE)
60                    .union(Self::IS_ALLOWED_RETURN)
61                    .union(Self::IS_SCALAR);
62            }
63            TypeKind::Byte => {
64                flags = flags
65                    .union(Self::IS_BLITTABLE)
66                    .union(Self::IS_STORAGE)
67                    .union(Self::IS_ALLOWED_RETURN)
68                    .union(Self::IS_SCALAR);
69            }
70            TypeKind::Int => {
71                flags = flags
72                    .union(Self::IS_BLITTABLE)
73                    .union(Self::IS_STORAGE)
74                    .union(Self::IS_ALLOWED_RETURN)
75                    .union(Self::IS_SCALAR);
76            }
77            TypeKind::String(..) => {
78                flags = flags
79                    .union(Self::IS_BLITTABLE)
80                    .union(Self::IS_ALLOWED_RETURN)
81                    .union(Self::IS_SCALAR);
82            }
83            TypeKind::StringStorage(_, _, _) => {
84                flags = flags
85                    .union(Self::IS_BLITTABLE)
86                    .union(Self::IS_STORAGE)
87                    .union(Self::IS_SCALAR);
88            }
89
90            TypeKind::Float => {
91                flags = flags
92                    .union(Self::IS_BLITTABLE)
93                    .union(Self::IS_STORAGE)
94                    .union(Self::IS_ALLOWED_RETURN)
95                    .union(Self::IS_SCALAR);
96            }
97            TypeKind::Bool => {
98                flags = flags
99                    .union(Self::IS_BLITTABLE)
100                    .union(Self::IS_STORAGE)
101                    .union(Self::IS_ALLOWED_RETURN)
102                    .union(Self::IS_SCALAR);
103            }
104            TypeKind::Unit => {
105                flags = flags
106                    .union(Self::IS_BLITTABLE)
107                    .union(Self::IS_STORAGE)
108                    .union(Self::IS_ALLOWED_RETURN)
109                    .union(Self::IS_SCALAR);
110            }
111            TypeKind::Function(_) => {}
112            TypeKind::Enum(enum_type) => {
113                if enum_type.are_all_variants_with_blittable_payload() {
114                    flags = flags
115                        .union(Self::IS_BLITTABLE)
116                        .union(Self::IS_ALLOWED_RETURN);
117                } else {
118                    panic!("enums should be blittable")
119                }
120                if enum_type.are_all_variants_with_storage_payload() {
121                    flags = flags.union(Self::IS_STORAGE);
122                }
123            }
124            TypeKind::Tuple(types) => {
125                // A tuple is blittable if all its component types are blittable
126                if types.iter().all(|t| t.flags.contains(Self::IS_BLITTABLE)) {
127                    flags = flags
128                        .union(Self::IS_BLITTABLE)
129                        .union(Self::IS_ALLOWED_RETURN);
130                }
131                if types.iter().all(|t| t.flags.contains(Self::IS_STORAGE)) {
132                    flags = flags.union(Self::IS_STORAGE);
133                }
134            }
135            TypeKind::Optional(inner) => {
136                // An optional is blittable if its inner type is blittable
137                if inner.flags.contains(Self::IS_BLITTABLE) {
138                    flags = flags
139                        .union(Self::IS_BLITTABLE);
140                }
141                // TODO: check this
142                if inner.flags.contains(Self::IS_ALLOWED_RETURN) {
143                    flags = flags
144                        .union(Self::IS_ALLOWED_RETURN);
145                }
146                if inner.flags.contains(Self::IS_STORAGE) {
147                    flags = flags.union(Self::IS_STORAGE);
148                }
149            }
150            TypeKind::NamedStruct(named) => {
151                if named.anon_struct_type.flags.contains(Self::IS_BLITTABLE) {
152                    flags = flags
153                        .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.anon_struct_type.flags.contains(Self::IS_ALLOWED_RETURN) {
159                    flags = flags
160                        .union(Self::IS_ALLOWED_RETURN);
161                }
162            }
163            TypeKind::AnonymousStruct(anon) => {
164                if anon
165                    .field_name_sorted_fields
166                    .iter()
167                    .all(|(_name, field)| field.field_type.flags.contains(Self::IS_BLITTABLE))
168                {
169                    flags = flags
170                        .union(Self::IS_BLITTABLE);
171                }
172
173                anon
174                    .field_name_sorted_fields
175                    .iter()
176                    .all(|(_name, field)| field.field_type.flags.contains(Self::IS_ALLOWED_RETURN));
177                flags = flags
178                    .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}