Skip to main content

mago_codex/flags/
attribute.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4/// Represents the flags defined in a PHP `#[Attribute]` declaration,
5/// specifying the targets where the attribute can be applied and whether it's repeatable.
6#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
7#[repr(transparent)]
8pub struct AttributeFlags(u8);
9
10impl AttributeFlags {
11    /// Flag indicating the attribute can be applied to classes, interfaces, traits, and enums.
12    /// Corresponds to `Attribute::TARGET_CLASS`.
13    pub const TARGET_CLASS: AttributeFlags = AttributeFlags(1 << 0);
14
15    /// Flag indicating the attribute can be applied to functions (including closures and arrow functions).
16    /// Corresponds to `Attribute::TARGET_FUNCTION`.
17    pub const TARGET_FUNCTION: AttributeFlags = AttributeFlags(1 << 1);
18
19    /// Flag indicating the attribute can be applied to methods.
20    /// Corresponds to `Attribute::TARGET_METHOD`.
21    pub const TARGET_METHOD: AttributeFlags = AttributeFlags(1 << 2);
22
23    /// Flag indicating the attribute can be applied to properties.
24    /// Corresponds to `Attribute::TARGET_PROPERTY`.
25    pub const TARGET_PROPERTY: AttributeFlags = AttributeFlags(1 << 3);
26
27    /// Flag indicating the attribute can be applied to class constants.
28    /// Corresponds to `Attribute::TARGET_CLASS_CONSTANT`.
29    pub const TARGET_CLASS_CONSTANT: AttributeFlags = AttributeFlags(1 << 4);
30
31    /// Flag indicating the attribute can be applied to function or method parameters.
32    /// Corresponds to `Attribute::TARGET_PARAMETER`.
33    pub const TARGET_PARAMETER: AttributeFlags = AttributeFlags(1 << 5);
34
35    /// Flag indicating the attribute can be applied to global constants (defined with `const`).
36    /// Corresponds to `Attribute::TARGET_CONSTANT`.
37    pub const TARGET_CONSTANT: AttributeFlags = AttributeFlags(1 << 6);
38
39    /// A combination of all `TARGET_*` flags, indicating the attribute can be applied anywhere.
40    /// Corresponds to `Attribute::TARGET_ALL`.
41    pub const TARGET_ALL: AttributeFlags =
42        AttributeFlags((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6));
43
44    /// Flag indicating the attribute can be repeated on the same declaration.
45    /// Corresponds to `Attribute::IS_REPEATABLE`.
46    pub const IS_REPEATABLE: AttributeFlags = AttributeFlags(1 << 7);
47}
48
49impl AttributeFlags {
50    #[inline]
51    #[must_use]
52    pub const fn empty() -> Self {
53        AttributeFlags(0)
54    }
55
56    #[inline]
57    #[must_use]
58    pub const fn from_bits(bits: u8) -> Self {
59        AttributeFlags(bits)
60    }
61
62    #[inline]
63    pub const fn insert(&mut self, other: AttributeFlags) {
64        self.0 |= other.0;
65    }
66
67    #[inline]
68    pub const fn set(&mut self, other: AttributeFlags, value: bool) {
69        if value {
70            self.insert(other);
71        } else {
72            self.0 &= !other.0;
73        }
74    }
75
76    #[inline]
77    pub const fn contains(self, other: AttributeFlags) -> bool {
78        (self.0 & other.0) == other.0
79    }
80
81    #[inline]
82    pub const fn remove(&mut self, other: AttributeFlags) {
83        self.0 &= !other.0;
84    }
85
86    #[inline]
87    pub const fn intersects(self, other: AttributeFlags) -> bool {
88        (self.0 & other.0) != 0
89    }
90
91    #[inline]
92    #[must_use]
93    pub const fn union(&self, other: AttributeFlags) -> AttributeFlags {
94        AttributeFlags(self.0 | other.0)
95    }
96
97    #[inline]
98    #[must_use]
99    pub const fn intersection(&self, other: AttributeFlags) -> AttributeFlags {
100        AttributeFlags(self.0 & other.0)
101    }
102
103    #[inline]
104    pub const fn bits(self) -> u8 {
105        self.0
106    }
107
108    #[inline]
109    #[must_use]
110    pub const fn all() -> Self {
111        Self(Self::TARGET_ALL.0 | Self::IS_REPEATABLE.0)
112    }
113}
114
115impl AttributeFlags {
116    /// Checks if the `IS_REPEATABLE` flag is set, meaning the attribute
117    /// can be declared multiple times on the same target.
118    #[must_use]
119    pub const fn is_repeatable(&self) -> bool {
120        self.contains(Self::IS_REPEATABLE)
121    }
122
123    /// Checks if the `TARGET_CLASS` flag is set, indicating the attribute
124    /// can be applied to classes, interfaces, traits, or enums.
125    #[must_use]
126    pub const fn targets_class(&self) -> bool {
127        self.contains(Self::TARGET_CLASS)
128    }
129
130    /// Checks if the `TARGET_FUNCTION` flag is set, indicating the attribute
131    /// can be applied to functions or closures.
132    #[must_use]
133    pub const fn targets_function(&self) -> bool {
134        self.contains(Self::TARGET_FUNCTION)
135    }
136
137    /// Checks if the `TARGET_METHOD` flag is set, indicating the attribute
138    /// can be applied to class or interface methods.
139    #[must_use]
140    pub const fn targets_method(&self) -> bool {
141        self.contains(Self::TARGET_METHOD)
142    }
143
144    /// Checks if the `TARGET_PROPERTY` flag is set, indicating the attribute
145    /// can be applied to class properties.
146    #[must_use]
147    pub const fn targets_property(&self) -> bool {
148        self.contains(Self::TARGET_PROPERTY)
149    }
150
151    /// Checks if the `TARGET_CLASS_CONSTANT` flag is set, indicating the attribute
152    /// can be applied to class constants.
153    #[must_use]
154    pub const fn targets_class_constant(&self) -> bool {
155        self.contains(Self::TARGET_CLASS_CONSTANT)
156    }
157
158    /// Checks if the `TARGET_PARAMETER` flag is set, indicating the attribute
159    /// can be applied to function or method parameters.
160    #[must_use]
161    pub const fn targets_parameter(&self) -> bool {
162        self.contains(Self::TARGET_PARAMETER)
163    }
164
165    /// Checks if the `TARGET_CONSTANT` flag is set, indicating the attribute
166    /// can be applied to global constants.
167    #[must_use]
168    pub const fn targets_constant(&self) -> bool {
169        self.contains(Self::TARGET_CONSTANT)
170    }
171
172    /// Returns a list of human-readable strings for each target flag set.
173    #[must_use]
174    pub fn get_target_names(&self) -> Vec<&'static str> {
175        let mut targets = Vec::with_capacity(7);
176
177        if self.targets_class() {
178            targets.push("classes");
179        }
180
181        if self.targets_function() {
182            targets.push("functions");
183        }
184
185        if self.targets_method() {
186            targets.push("methods");
187        }
188
189        if self.targets_property() {
190            targets.push("properties");
191        }
192
193        if self.targets_class_constant() {
194            targets.push("class constants");
195        }
196
197        if self.targets_parameter() {
198            targets.push("parameters");
199        }
200
201        if self.targets_constant() {
202            targets.push("global constants");
203        }
204
205        targets
206    }
207}
208
209impl std::ops::BitOr for AttributeFlags {
210    type Output = Self;
211
212    #[inline]
213    fn bitor(self, rhs: Self) -> Self::Output {
214        AttributeFlags(self.0 | rhs.0)
215    }
216}
217
218impl std::ops::BitAnd for AttributeFlags {
219    type Output = Self;
220
221    #[inline]
222    fn bitand(self, rhs: Self) -> Self::Output {
223        AttributeFlags(self.0 & rhs.0)
224    }
225}
226
227impl std::ops::BitXor for AttributeFlags {
228    type Output = Self;
229
230    #[inline]
231    fn bitxor(self, rhs: Self) -> Self::Output {
232        AttributeFlags(self.0 ^ rhs.0)
233    }
234}
235
236impl std::ops::Not for AttributeFlags {
237    type Output = Self;
238
239    #[inline]
240    fn not(self) -> Self::Output {
241        AttributeFlags(!self.0)
242    }
243}
244
245impl std::ops::BitOrAssign for AttributeFlags {
246    #[inline]
247    fn bitor_assign(&mut self, rhs: Self) {
248        self.0 |= rhs.0;
249    }
250}
251
252impl std::ops::BitAndAssign for AttributeFlags {
253    #[inline]
254    fn bitand_assign(&mut self, rhs: Self) {
255        self.0 &= rhs.0;
256    }
257}
258
259impl std::ops::BitXorAssign for AttributeFlags {
260    #[inline]
261    fn bitxor_assign(&mut self, rhs: Self) {
262        self.0 ^= rhs.0;
263    }
264}