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                        .union(Self::IS_ALLOWED_RETURN);
135                }
136                if inner.flags.contains(Self::IS_STORAGE) {
137                    flags = flags.union(Self::IS_STORAGE);
138                }
139            }
140            TypeKind::NamedStruct(named) => {
141                if named.anon_struct_type.flags.contains(Self::IS_BLITTABLE) {
142                    flags = flags
143                        .union(Self::IS_BLITTABLE)
144                        .union(Self::IS_ALLOWED_RETURN);
145                }
146                if named.anon_struct_type.flags.contains(Self::IS_STORAGE) {
147                    flags = flags.union(Self::IS_STORAGE);
148                }
149            }
150            TypeKind::AnonymousStruct(anon) => {
151                if anon
152                    .field_name_sorted_fields
153                    .iter()
154                    .all(|(_name, field)| field.field_type.flags.contains(Self::IS_BLITTABLE))
155                {
156                    flags = flags
157                        .union(Self::IS_BLITTABLE)
158                        .union(Self::IS_ALLOWED_RETURN);
159                }
160
161                if anon
162                    .field_name_sorted_fields
163                    .iter()
164                    .all(|(_name, field)| field.field_type.flags.contains(Self::IS_STORAGE))
165                {
166                    flags = flags.union(Self::IS_STORAGE);
167                }
168            }
169            TypeKind::MapStorage(key, value, _) => {
170                if key.is_blittable() && value.is_blittable() {
171                    flags = flags.union(Self::IS_BLITTABLE);
172                }
173
174                if key.is_storage() && value.is_storage() {
175                    flags = flags.union(Self::IS_STORAGE);
176                }
177            }
178            TypeKind::DynamicLengthMapView(_, _) => {
179                flags = flags.union(Self::IS_ALLOWED_RETURN);
180            }
181            TypeKind::FixedCapacityAndLengthArray(inner, _) => {
182                if inner.is_blittable() {
183                    flags = flags.union(Self::IS_BLITTABLE);
184                }
185                if inner.is_storage() {
186                    flags = flags.union(Self::IS_STORAGE);
187                }
188            }
189            TypeKind::SliceView(_) => {
190                flags = flags.union(Self::IS_ALLOWED_RETURN);
191            }
192            TypeKind::VecStorage(inner, _) => {
193                if inner.is_blittable() {
194                    flags = flags.union(Self::IS_BLITTABLE);
195                }
196                if inner.is_storage() {
197                    flags = flags.union(Self::IS_STORAGE);
198                }
199            }
200            TypeKind::DynamicLengthVecView(_) => {
201                flags = flags.union(Self::IS_ALLOWED_RETURN);
202            }
203
204            TypeKind::StackStorage(inner, _) => {
205                if inner.is_blittable() {
206                    flags = flags.union(Self::IS_BLITTABLE);
207                }
208                if inner.is_storage() {
209                    flags = flags.union(Self::IS_STORAGE);
210                }
211            }
212            TypeKind::StackView(_) => {
213                flags = flags.union(Self::IS_ALLOWED_RETURN);
214            }
215
216            TypeKind::QueueStorage(inner, _) => {
217                if inner.is_blittable() {
218                    flags = flags.union(Self::IS_BLITTABLE);
219                }
220                if inner.is_storage() {
221                    flags = flags.union(Self::IS_STORAGE);
222                }
223            }
224            TypeKind::QueueView(_) => {
225                flags = flags.union(Self::IS_ALLOWED_RETURN);
226            }
227            TypeKind::GridStorage(inner, _, _) => {
228                if inner.is_blittable() {
229                    flags = flags.union(Self::IS_BLITTABLE);
230                }
231                if inner.is_storage() {
232                    flags = flags.union(Self::IS_STORAGE);
233                }
234            }
235            TypeKind::GridView(_) => {
236                flags = flags.union(Self::IS_ALLOWED_RETURN);
237            }
238            TypeKind::SparseStorage(inner, _) => {
239                if inner.is_blittable() {
240                    flags = flags.union(Self::IS_BLITTABLE);
241                }
242                if inner.is_storage() {
243                    flags = flags.union(Self::IS_STORAGE);
244                }
245            }
246            TypeKind::SparseView(_) => {
247                flags = flags.union(Self::IS_ALLOWED_RETURN);
248            }
249            TypeKind::Range(_inner) => {
250                flags = flags
251                    .union(Self::IS_BLITTABLE)
252                    .union(Self::IS_ALLOWED_RETURN);
253                flags = flags.union(Self::IS_STORAGE);
254            }
255        }
256
257        flags
258    }
259}