Skip to main content

mago_codex/ttype/
flags.rs

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