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