Skip to main content

mago_codex/flags/
attribute.rs

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