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::Int => {
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::Float => {
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_SCALAR)
68                    .union(Self::IS_ALLOWED_RETURN); // Strings are "sort of" self-contained in a register
69            }
70            TypeKind::Bool => {
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::Unit => {
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::Function(_) => {}
85            TypeKind::Enum(enum_type) => {
86                if enum_type.are_all_variants_with_blittable_payload() {
87                    flags = flags
88                        .union(Self::IS_BLITTABLE)
89                        .union(Self::IS_ALLOWED_RETURN);
90                } else {
91                    panic!("enums should be blittable")
92                }
93                if enum_type.are_all_variants_with_storage_payload() {
94                    flags = flags.union(Self::IS_STORAGE);
95                }
96            }
97            TypeKind::Tuple(types) => {
98                // A tuple is blittable if all its component types are blittable
99                if types.iter().all(|t| t.flags.contains(Self::IS_BLITTABLE)) {
100                    flags = flags
101                        .union(Self::IS_BLITTABLE)
102                        .union(Self::IS_ALLOWED_RETURN);
103                }
104                if types.iter().all(|t| t.flags.contains(Self::IS_STORAGE)) {
105                    flags = flags.union(Self::IS_STORAGE);
106                }
107            }
108            TypeKind::Optional(inner) => {
109                // An optional is blittable if its inner type is blittable
110                if inner.flags.contains(Self::IS_BLITTABLE) {
111                    flags = flags
112                        .union(Self::IS_BLITTABLE)
113                        .union(Self::IS_ALLOWED_RETURN);
114                }
115                if inner.flags.contains(Self::IS_STORAGE) {
116                    flags = flags.union(Self::IS_STORAGE);
117                }
118            }
119            TypeKind::NamedStruct(named) => {
120                if named.anon_struct_type.flags.contains(Self::IS_BLITTABLE) {
121                    flags = flags
122                        .union(Self::IS_BLITTABLE)
123                        .union(Self::IS_ALLOWED_RETURN);
124                }
125                if named.anon_struct_type.flags.contains(Self::IS_STORAGE) {
126                    flags = flags.union(Self::IS_STORAGE);
127                }
128            }
129            TypeKind::AnonymousStruct(anon) => {
130                if anon.field_name_sorted_fields.iter().all(|(_name, field)| {
131                    assert!(
132                        field.field_type.is_blittable(),
133                        "what is wrong with field: {field}"
134                    );
135                    field.field_type.flags.contains(Self::IS_BLITTABLE)
136                }) {
137                    flags = flags
138                        .union(Self::IS_BLITTABLE)
139                        .union(Self::IS_ALLOWED_RETURN);
140                }
141
142                if anon
143                    .field_name_sorted_fields
144                    .iter()
145                    .all(|(name, field)| field.field_type.flags.contains(Self::IS_STORAGE))
146                {
147                    flags = flags.union(Self::IS_STORAGE);
148                }
149            }
150            TypeKind::MapStorage(key, value, _) => {
151                if key.is_blittable() && value.is_blittable() {
152                    flags = flags.union(Self::IS_BLITTABLE);
153                }
154
155                if key.is_storage() && value.is_storage() {
156                    flags = flags.union(Self::IS_STORAGE);
157                }
158            }
159            TypeKind::DynamicLengthMapView(_, _) => {
160                flags = flags.union(Self::IS_ALLOWED_RETURN);
161            }
162            TypeKind::FixedCapacityAndLengthArray(inner, _) => {
163                if inner.is_blittable() {
164                    flags = flags.union(Self::IS_BLITTABLE);
165                }
166                if inner.is_storage() {
167                    flags = flags.union(Self::IS_STORAGE);
168                }
169            }
170            TypeKind::SliceView(_) => {
171                flags = flags.union(Self::IS_ALLOWED_RETURN);
172            }
173            TypeKind::VecStorage(inner, _) => {
174                if inner.is_blittable() {
175                    flags = flags.union(Self::IS_BLITTABLE);
176                }
177                if inner.is_storage() {
178                    flags = flags.union(Self::IS_STORAGE);
179                }
180            }
181            TypeKind::DynamicLengthVecView(_) => {
182                flags = flags.union(Self::IS_ALLOWED_RETURN);
183            }
184
185            TypeKind::StackStorage(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::StackView(_) => {
194                flags = flags.union(Self::IS_ALLOWED_RETURN);
195            }
196
197            TypeKind::QueueStorage(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::QueueView(_) => {
206                flags = flags.union(Self::IS_ALLOWED_RETURN);
207            }
208            TypeKind::GridStorage(inner, _, _) => {
209                if inner.is_blittable() {
210                    flags = flags.union(Self::IS_BLITTABLE);
211                }
212                if inner.is_storage() {
213                    flags = flags.union(Self::IS_STORAGE);
214                }
215            }
216            TypeKind::GridView(_) => {
217                flags = flags.union(Self::IS_ALLOWED_RETURN);
218            }
219            TypeKind::SparseStorage(inner, _) => {
220                if inner.is_blittable() {
221                    flags = flags.union(Self::IS_BLITTABLE);
222                }
223                if inner.is_storage() {
224                    flags = flags.union(Self::IS_STORAGE);
225                }
226            }
227            TypeKind::SparseView(_) => {
228                flags = flags.union(Self::IS_ALLOWED_RETURN);
229            }
230            TypeKind::Range(inner) => {
231                flags = flags
232                    .union(Self::IS_BLITTABLE)
233                    .union(Self::IS_ALLOWED_RETURN);
234                flags = flags.union(Self::IS_STORAGE);
235            }
236
237            _ => {}
238        }
239
240        flags
241    }
242}