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