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