Skip to main content

mago_codex/ttype/
flags.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4/// Flags representing various properties of a type union.
5///
6/// This replaces 9 individual boolean fields with a compact 16-bit representation,
7/// reducing memory usage from 9 bytes to 2 bytes per TUnion instance.
8#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
9pub struct UnionFlags(u16);
10
11impl UnionFlags {
12    /// Indicates the union had a template type at some point.
13    pub const HAD_TEMPLATE: UnionFlags = UnionFlags(1 << 0);
14    /// Indicates the value is passed by reference.
15    pub const BY_REFERENCE: UnionFlags = UnionFlags(1 << 1);
16    /// Indicates no references exist to this type.
17    pub const REFERENCE_FREE: UnionFlags = UnionFlags(1 << 2);
18    /// Indicates the type may be undefined due to a try block.
19    pub const POSSIBLY_UNDEFINED_FROM_TRY: UnionFlags = UnionFlags(1 << 3);
20    /// Indicates the type may be undefined.
21    pub const POSSIBLY_UNDEFINED: UnionFlags = UnionFlags(1 << 4);
22    /// Indicates nullable issues should be ignored for this type.
23    pub const IGNORE_NULLABLE_ISSUES: UnionFlags = UnionFlags(1 << 5);
24    /// Indicates falsable issues should be ignored for this type.
25    pub const IGNORE_FALSABLE_ISSUES: UnionFlags = UnionFlags(1 << 6);
26    /// Indicates the type came from a template default value.
27    pub const FROM_TEMPLATE_DEFAULT: UnionFlags = UnionFlags(1 << 7);
28    /// Indicates the type has been populated with codebase information.
29    pub const POPULATED: UnionFlags = UnionFlags(1 << 8);
30    /// Indicates the null in this union came from nullsafe short-circuit.
31    pub const NULLSAFE_NULL: UnionFlags = UnionFlags(1 << 9);
32}
33
34impl UnionFlags {
35    #[inline]
36    #[must_use]
37    pub const fn empty() -> Self {
38        UnionFlags(0)
39    }
40
41    #[inline]
42    pub const fn insert(&mut self, flag: UnionFlags) {
43        self.0 |= flag.0;
44    }
45
46    #[inline]
47    pub const fn set(&mut self, flag: UnionFlags, value: bool) {
48        if value {
49            self.insert(flag);
50        } else {
51            self.0 &= !flag.0;
52        }
53    }
54
55    #[inline]
56    #[must_use]
57    pub const fn contains(self, flag: UnionFlags) -> bool {
58        (self.0 & flag.0) == flag.0
59    }
60
61    #[inline]
62    #[must_use]
63    pub const fn intersects(self, other: UnionFlags) -> bool {
64        (self.0 & other.0) != 0
65    }
66
67    #[inline]
68    #[must_use]
69    pub const fn union(&self, other: UnionFlags) -> UnionFlags {
70        UnionFlags(self.0 | other.0)
71    }
72
73    #[inline]
74    #[must_use]
75    pub const fn intersection(&self, other: UnionFlags) -> UnionFlags {
76        UnionFlags(self.0 & other.0)
77    }
78}
79
80impl std::ops::BitOr for UnionFlags {
81    type Output = Self;
82
83    #[inline]
84    fn bitor(self, rhs: Self) -> Self::Output {
85        UnionFlags(self.0 | rhs.0)
86    }
87}
88
89impl std::ops::BitOrAssign for UnionFlags {
90    #[inline]
91    fn bitor_assign(&mut self, rhs: Self) {
92        self.0 |= rhs.0;
93    }
94}
95
96impl std::ops::BitAnd for UnionFlags {
97    type Output = Self;
98
99    #[inline]
100    fn bitand(self, rhs: Self) -> Self::Output {
101        UnionFlags(self.0 & rhs.0)
102    }
103}
104
105impl std::ops::BitAndAssign for UnionFlags {
106    #[inline]
107    fn bitand_assign(&mut self, rhs: Self) {
108        self.0 &= rhs.0;
109    }
110}
111
112impl std::ops::Not for UnionFlags {
113    type Output = Self;
114
115    #[inline]
116    fn not(self) -> Self::Output {
117        UnionFlags(!self.0)
118    }
119}