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    #[must_use]
78    pub const fn contains(self, other: AttributeFlags) -> bool {
79        (self.0 & other.0) == other.0
80    }
81
82    #[inline]
83    pub const fn remove(&mut self, other: AttributeFlags) {
84        self.0 &= !other.0;
85    }
86
87    #[inline]
88    #[must_use]
89    pub const fn intersects(self, other: AttributeFlags) -> bool {
90        (self.0 & other.0) != 0
91    }
92
93    #[inline]
94    #[must_use]
95    pub const fn union(&self, other: AttributeFlags) -> AttributeFlags {
96        AttributeFlags(self.0 | other.0)
97    }
98
99    #[inline]
100    #[must_use]
101    pub const fn intersection(&self, other: AttributeFlags) -> AttributeFlags {
102        AttributeFlags(self.0 & other.0)
103    }
104
105    #[inline]
106    #[must_use]
107    pub const fn bits(self) -> u8 {
108        self.0
109    }
110
111    #[inline]
112    #[must_use]
113    pub const fn all() -> Self {
114        Self(Self::TARGET_ALL.0 | Self::IS_REPEATABLE.0)
115    }
116}
117
118impl AttributeFlags {
119    /// Checks if the `IS_REPEATABLE` flag is set, meaning the attribute
120    /// can be declared multiple times on the same target.
121    #[must_use]
122    pub const fn is_repeatable(&self) -> bool {
123        self.contains(Self::IS_REPEATABLE)
124    }
125
126    /// Checks if the `TARGET_CLASS` flag is set, indicating the attribute
127    /// can be applied to classes, interfaces, traits, or enums.
128    #[must_use]
129    pub const fn targets_class(&self) -> bool {
130        self.contains(Self::TARGET_CLASS)
131    }
132
133    /// Checks if the `TARGET_FUNCTION` flag is set, indicating the attribute
134    /// can be applied to functions or closures.
135    #[must_use]
136    pub const fn targets_function(&self) -> bool {
137        self.contains(Self::TARGET_FUNCTION)
138    }
139
140    /// Checks if the `TARGET_METHOD` flag is set, indicating the attribute
141    /// can be applied to class or interface methods.
142    #[must_use]
143    pub const fn targets_method(&self) -> bool {
144        self.contains(Self::TARGET_METHOD)
145    }
146
147    /// Checks if the `TARGET_PROPERTY` flag is set, indicating the attribute
148    /// can be applied to class properties.
149    #[must_use]
150    pub const fn targets_property(&self) -> bool {
151        self.contains(Self::TARGET_PROPERTY)
152    }
153
154    /// Checks if the `TARGET_CLASS_CONSTANT` flag is set, indicating the attribute
155    /// can be applied to class constants.
156    #[must_use]
157    pub const fn targets_class_constant(&self) -> bool {
158        self.contains(Self::TARGET_CLASS_CONSTANT)
159    }
160
161    /// Checks if the `TARGET_PARAMETER` flag is set, indicating the attribute
162    /// can be applied to function or method parameters.
163    #[must_use]
164    pub const fn targets_parameter(&self) -> bool {
165        self.contains(Self::TARGET_PARAMETER)
166    }
167
168    /// Checks if the `TARGET_CONSTANT` flag is set, indicating the attribute
169    /// can be applied to global constants.
170    #[must_use]
171    pub const fn targets_constant(&self) -> bool {
172        self.contains(Self::TARGET_CONSTANT)
173    }
174
175    /// Returns a list of human-readable strings for each target flag set.
176    #[must_use]
177    pub fn get_target_names(&self) -> Vec<&'static str> {
178        let mut targets = Vec::with_capacity(7);
179
180        if self.targets_class() {
181            targets.push("classes");
182        }
183
184        if self.targets_function() {
185            targets.push("functions");
186        }
187
188        if self.targets_method() {
189            targets.push("methods");
190        }
191
192        if self.targets_property() {
193            targets.push("properties");
194        }
195
196        if self.targets_class_constant() {
197            targets.push("class constants");
198        }
199
200        if self.targets_parameter() {
201            targets.push("parameters");
202        }
203
204        if self.targets_constant() {
205            targets.push("global constants");
206        }
207
208        targets
209    }
210}
211
212impl std::ops::BitOr for AttributeFlags {
213    type Output = Self;
214
215    #[inline]
216    fn bitor(self, rhs: Self) -> Self::Output {
217        AttributeFlags(self.0 | rhs.0)
218    }
219}
220
221impl std::ops::BitAnd for AttributeFlags {
222    type Output = Self;
223
224    #[inline]
225    fn bitand(self, rhs: Self) -> Self::Output {
226        AttributeFlags(self.0 & rhs.0)
227    }
228}
229
230impl std::ops::BitXor for AttributeFlags {
231    type Output = Self;
232
233    #[inline]
234    fn bitxor(self, rhs: Self) -> Self::Output {
235        AttributeFlags(self.0 ^ rhs.0)
236    }
237}
238
239impl std::ops::Not for AttributeFlags {
240    type Output = Self;
241
242    #[inline]
243    fn not(self) -> Self::Output {
244        AttributeFlags(!self.0)
245    }
246}
247
248impl std::ops::BitOrAssign for AttributeFlags {
249    #[inline]
250    fn bitor_assign(&mut self, rhs: Self) {
251        self.0 |= rhs.0;
252    }
253}
254
255impl std::ops::BitAndAssign for AttributeFlags {
256    #[inline]
257    fn bitand_assign(&mut self, rhs: Self) {
258        self.0 &= rhs.0;
259    }
260}
261
262impl std::ops::BitXorAssign for AttributeFlags {
263    #[inline]
264    fn bitxor_assign(&mut self, rhs: Self) {
265        self.0 ^= rhs.0;
266    }
267}