ext_php_rs/
flags.rs

1//! Flags and enums used in PHP and the Zend engine.
2
3use bitflags::bitflags;
4
5#[cfg(not(php82))]
6use crate::ffi::ZEND_ACC_REUSE_GET_ITERATOR;
7use crate::ffi::{
8    CONST_CS, CONST_DEPRECATED, CONST_NO_FILE_CACHE, CONST_PERSISTENT, E_COMPILE_ERROR,
9    E_COMPILE_WARNING, E_CORE_ERROR, E_CORE_WARNING, E_DEPRECATED, E_ERROR, E_NOTICE, E_PARSE,
10    E_RECOVERABLE_ERROR, E_STRICT, E_USER_DEPRECATED, E_USER_ERROR, E_USER_NOTICE, E_USER_WARNING,
11    E_WARNING, IS_ARRAY, IS_CALLABLE, IS_CONSTANT_AST, IS_DOUBLE, IS_FALSE, IS_INDIRECT,
12    IS_ITERABLE, IS_LONG, IS_MIXED, IS_NULL, IS_OBJECT, IS_PTR, IS_REFERENCE, IS_RESOURCE,
13    IS_STRING, IS_TRUE, IS_TYPE_COLLECTABLE, IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID, PHP_INI_ALL,
14    PHP_INI_PERDIR, PHP_INI_SYSTEM, PHP_INI_USER, ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS,
15    ZEND_ACC_CALL_VIA_TRAMPOLINE, ZEND_ACC_CHANGED, ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED,
16    ZEND_ACC_CTOR, ZEND_ACC_DEPRECATED, ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING,
17    ZEND_ACC_FAKE_CLOSURE, ZEND_ACC_FINAL, ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK,
18    ZEND_ACC_HAS_RETURN_TYPE, ZEND_ACC_HAS_TYPE_HINTS, ZEND_ACC_HEAP_RT_CACHE, ZEND_ACC_IMMUTABLE,
19    ZEND_ACC_IMPLICIT_ABSTRACT_CLASS, ZEND_ACC_INTERFACE, ZEND_ACC_LINKED, ZEND_ACC_NEARLY_LINKED,
20    ZEND_ACC_NEVER_CACHE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PRELOADED, ZEND_ACC_PRIVATE,
21    ZEND_ACC_PROMOTED, ZEND_ACC_PROTECTED, ZEND_ACC_PUBLIC, ZEND_ACC_RESOLVED_INTERFACES,
22    ZEND_ACC_RESOLVED_PARENT, ZEND_ACC_RETURN_REFERENCE, ZEND_ACC_STATIC, ZEND_ACC_STRICT_TYPES,
23    ZEND_ACC_TOP_LEVEL, ZEND_ACC_TRAIT, ZEND_ACC_TRAIT_CLONE, ZEND_ACC_UNRESOLVED_VARIANCE,
24    ZEND_ACC_USES_THIS, ZEND_ACC_USE_GUARDS, ZEND_ACC_VARIADIC, ZEND_EVAL_CODE,
25    ZEND_HAS_STATIC_IN_METHODS, ZEND_INTERNAL_FUNCTION, ZEND_USER_FUNCTION, Z_TYPE_FLAGS_SHIFT,
26    _IS_BOOL,
27};
28
29use std::{convert::TryFrom, fmt::Display};
30
31use crate::error::{Error, Result};
32
33bitflags! {
34    /// Flags used for setting the type of Zval.
35    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
36    pub struct ZvalTypeFlags: u32 {
37        const Undef = IS_UNDEF;
38        const Null = IS_NULL;
39        const False = IS_FALSE;
40        const True = IS_TRUE;
41        const Long = IS_LONG;
42        const Double = IS_DOUBLE;
43        const String = IS_STRING;
44        const Array = IS_ARRAY;
45        const Object = IS_OBJECT;
46        const Resource = IS_RESOURCE;
47        const Reference = IS_REFERENCE;
48        const Callable = IS_CALLABLE;
49        const ConstantExpression = IS_CONSTANT_AST;
50        const Void = IS_VOID;
51        const Ptr = IS_PTR;
52        const Iterable = IS_ITERABLE;
53
54        const InternedStringEx = Self::String.bits();
55        const StringEx = Self::String.bits() | Self::RefCounted.bits();
56        const ArrayEx = Self::Array.bits() | Self::RefCounted.bits() | Self::Collectable.bits();
57        const ObjectEx = Self::Object.bits() | Self::RefCounted.bits() | Self::Collectable.bits();
58        const ResourceEx = Self::Resource.bits() | Self::RefCounted.bits();
59        const ReferenceEx = Self::Reference.bits() | Self::RefCounted.bits();
60        const ConstantAstEx = Self::ConstantExpression.bits() | Self::RefCounted.bits();
61
62        const RefCounted = (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT);
63        const Collectable = (IS_TYPE_COLLECTABLE << Z_TYPE_FLAGS_SHIFT);
64    }
65}
66
67bitflags! {
68    /// Flags for building classes.
69    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
70    pub struct ClassFlags: u32 {
71        const Final = ZEND_ACC_FINAL;
72        const Abstract = ZEND_ACC_ABSTRACT;
73        const Immutable = ZEND_ACC_IMMUTABLE;
74        const HasTypeHints = ZEND_ACC_HAS_TYPE_HINTS;
75        const TopLevel = ZEND_ACC_TOP_LEVEL;
76        const Preloaded = ZEND_ACC_PRELOADED;
77
78        const Interface = ZEND_ACC_INTERFACE;
79        const Trait = ZEND_ACC_TRAIT;
80        const AnonymousClass = ZEND_ACC_ANON_CLASS;
81        const Linked = ZEND_ACC_LINKED;
82        const ImplicitAbstractClass = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
83        const UseGuards = ZEND_ACC_USE_GUARDS;
84        const ConstantsUpdated = ZEND_ACC_CONSTANTS_UPDATED;
85        const NoDynamicProperties = ZEND_ACC_NO_DYNAMIC_PROPERTIES;
86        const HasStaticInMethods = ZEND_HAS_STATIC_IN_METHODS;
87        #[cfg(not(php82))]
88        const ReuseGetIterator = ZEND_ACC_REUSE_GET_ITERATOR;
89        const ResolvedParent = ZEND_ACC_RESOLVED_PARENT;
90        const ResolvedInterfaces = ZEND_ACC_RESOLVED_INTERFACES;
91        const UnresolvedVariance = ZEND_ACC_UNRESOLVED_VARIANCE;
92        const NearlyLinked = ZEND_ACC_NEARLY_LINKED;
93
94        #[cfg(php81)]
95        const NotSerializable = crate::ffi::ZEND_ACC_NOT_SERIALIZABLE;
96    }
97}
98
99bitflags! {
100    /// Flags for building methods.
101    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
102    pub struct MethodFlags: u32 {
103        const Public = ZEND_ACC_PUBLIC;
104        const Protected = ZEND_ACC_PROTECTED;
105        const Private = ZEND_ACC_PRIVATE;
106        const Changed = ZEND_ACC_CHANGED;
107        const Static = ZEND_ACC_STATIC;
108        const Final = ZEND_ACC_FINAL;
109        const Abstract = ZEND_ACC_ABSTRACT;
110        const Immutable = ZEND_ACC_IMMUTABLE;
111        const HasTypeHints = ZEND_ACC_HAS_TYPE_HINTS;
112        const TopLevel = ZEND_ACC_TOP_LEVEL;
113        const Preloaded = ZEND_ACC_PRELOADED;
114
115        const Deprecated = ZEND_ACC_DEPRECATED;
116        const ReturnReference = ZEND_ACC_RETURN_REFERENCE;
117        const HasReturnType = ZEND_ACC_HAS_RETURN_TYPE;
118        const Variadic = ZEND_ACC_VARIADIC;
119        const HasFinallyBlock = ZEND_ACC_HAS_FINALLY_BLOCK;
120        const EarlyBinding = ZEND_ACC_EARLY_BINDING;
121        const UsesThis = ZEND_ACC_USES_THIS;
122        const CallViaTrampoline = ZEND_ACC_CALL_VIA_TRAMPOLINE;
123        const NeverCache = ZEND_ACC_NEVER_CACHE;
124        const TraitClone = ZEND_ACC_TRAIT_CLONE;
125        const IsConstructor = ZEND_ACC_CTOR;
126        const Closure = ZEND_ACC_CLOSURE;
127        const FakeClosure = ZEND_ACC_FAKE_CLOSURE;
128        const Generator = ZEND_ACC_GENERATOR;
129        const DonePassTwo = ZEND_ACC_DONE_PASS_TWO;
130        const HeapRTCache = ZEND_ACC_HEAP_RT_CACHE;
131        const StrictTypes = ZEND_ACC_STRICT_TYPES;
132    }
133}
134
135bitflags! {
136    /// Flags for building properties.
137    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
138    pub struct PropertyFlags: u32 {
139        const Public = ZEND_ACC_PUBLIC;
140        const Protected = ZEND_ACC_PROTECTED;
141        const Private = ZEND_ACC_PRIVATE;
142        const Changed = ZEND_ACC_CHANGED;
143        const Static = ZEND_ACC_STATIC;
144        const Promoted = ZEND_ACC_PROMOTED;
145    }
146}
147
148bitflags! {
149    /// Flags for building constants.
150    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
151    pub struct ConstantFlags: u32 {
152        const Public = ZEND_ACC_PUBLIC;
153        const Protected = ZEND_ACC_PROTECTED;
154        const Private = ZEND_ACC_PRIVATE;
155        const Promoted = ZEND_ACC_PROMOTED;
156    }
157}
158
159bitflags! {
160    /// Flags for building module global constants.
161    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
162    pub struct GlobalConstantFlags: u32 {
163        const CaseSensitive = CONST_CS;
164        const Persistent = CONST_PERSISTENT;
165        const NoFileCache = CONST_NO_FILE_CACHE;
166        const Deprecated = CONST_DEPRECATED;
167    }
168}
169
170bitflags! {
171    /// Represents the result of a function.
172    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
173    pub struct ZendResult: i32 {
174        const Success = 0;
175        const Failure = -1;
176    }
177}
178
179bitflags! {
180    /// Represents permissions for where a configuration setting may be set.
181    pub struct IniEntryPermission: u32 {
182        const User = PHP_INI_USER;
183        const PerDir = PHP_INI_PERDIR;
184        const System = PHP_INI_SYSTEM;
185        const All = PHP_INI_ALL;
186    }
187}
188
189bitflags! {
190    /// Represents error types when used via php_error_docref for example.
191    pub struct ErrorType: u32 {
192        const Error = E_ERROR;
193        const Warning = E_WARNING;
194        const Parse = E_PARSE;
195        const Notice = E_NOTICE;
196        const CoreError = E_CORE_ERROR;
197        const CoreWarning = E_CORE_WARNING;
198        const CompileError = E_COMPILE_ERROR;
199        const CompileWarning = E_COMPILE_WARNING;
200        const UserError = E_USER_ERROR;
201        const UserWarning = E_USER_WARNING;
202        const UserNotice = E_USER_NOTICE;
203        const Strict = E_STRICT;
204        const RecoverableError = E_RECOVERABLE_ERROR;
205        const Deprecated = E_DEPRECATED;
206        const UserDeprecated = E_USER_DEPRECATED;
207    }
208}
209
210#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
211pub enum FunctionType {
212    Internal,
213    User,
214    Eval,
215}
216
217impl From<u8> for FunctionType {
218    #[allow(clippy::bad_bit_mask)]
219    fn from(value: u8) -> Self {
220        match value as _ {
221            ZEND_INTERNAL_FUNCTION => Self::Internal,
222            ZEND_USER_FUNCTION => Self::User,
223            ZEND_EVAL_CODE => Self::Eval,
224            _ => panic!("Unknown function type: {}", value),
225        }
226    }
227}
228
229/// Valid data types for PHP.
230#[repr(C, u8)]
231#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
232pub enum DataType {
233    Undef,
234    Null,
235    False,
236    True,
237    Long,
238    Double,
239    String,
240    Array,
241    Iterable,
242    Object(Option<&'static str>),
243    Resource,
244    Reference,
245    Callable,
246    ConstantExpression,
247    Void,
248    Mixed,
249    Bool,
250    Ptr,
251    Indirect,
252}
253
254impl Default for DataType {
255    fn default() -> Self {
256        Self::Void
257    }
258}
259
260impl DataType {
261    /// Returns the integer representation of the data type.
262    pub const fn as_u32(&self) -> u32 {
263        match self {
264            DataType::Undef => IS_UNDEF,
265            DataType::Null => IS_NULL,
266            DataType::False => IS_FALSE,
267            DataType::True => IS_TRUE,
268            DataType::Long => IS_LONG,
269            DataType::Double => IS_DOUBLE,
270            DataType::String => IS_STRING,
271            DataType::Array => IS_ARRAY,
272            DataType::Object(_) => IS_OBJECT,
273            DataType::Resource => IS_RESOURCE,
274            DataType::Reference => IS_RESOURCE,
275            DataType::Indirect => IS_INDIRECT,
276            DataType::Callable => IS_CALLABLE,
277            DataType::ConstantExpression => IS_CONSTANT_AST,
278            DataType::Void => IS_VOID,
279            DataType::Mixed => IS_MIXED,
280            DataType::Bool => _IS_BOOL,
281            DataType::Ptr => IS_PTR,
282            DataType::Iterable => IS_ITERABLE,
283        }
284    }
285}
286
287// TODO: Ideally want something like this
288// pub struct Type {
289//     data_type: DataType,
290//     is_refcounted: bool,
291//     is_collectable: bool,
292//     is_immutable: bool,
293//     is_persistent: bool,
294// }
295//
296// impl From<u32> for Type { ... }
297
298impl TryFrom<ZvalTypeFlags> for DataType {
299    type Error = Error;
300
301    fn try_from(value: ZvalTypeFlags) -> Result<Self> {
302        macro_rules! contains {
303            ($t: ident) => {
304                if value.contains(ZvalTypeFlags::$t) {
305                    return Ok(DataType::$t);
306                }
307            };
308        }
309
310        contains!(Undef);
311        contains!(Null);
312        contains!(False);
313        contains!(True);
314        contains!(False);
315        contains!(Long);
316        contains!(Double);
317        contains!(String);
318        contains!(Array);
319        contains!(Resource);
320        contains!(Callable);
321        contains!(ConstantExpression);
322        contains!(Void);
323
324        if value.contains(ZvalTypeFlags::Object) {
325            return Ok(DataType::Object(None));
326        }
327
328        Err(Error::UnknownDatatype(0))
329    }
330}
331
332impl From<u32> for DataType {
333    #[allow(clippy::bad_bit_mask)]
334    fn from(value: u32) -> Self {
335        macro_rules! contains {
336            ($c: ident, $t: ident) => {
337                if (value & $c) == $c {
338                    return DataType::$t;
339                }
340            };
341        }
342
343        contains!(IS_VOID, Void);
344        contains!(IS_PTR, Ptr);
345        contains!(IS_INDIRECT, Indirect);
346        contains!(IS_CALLABLE, Callable);
347        contains!(IS_CONSTANT_AST, ConstantExpression);
348        contains!(IS_REFERENCE, Reference);
349        contains!(IS_RESOURCE, Resource);
350        contains!(IS_ARRAY, Array);
351        contains!(IS_STRING, String);
352        contains!(IS_DOUBLE, Double);
353        contains!(IS_LONG, Long);
354        contains!(IS_TRUE, True);
355        contains!(IS_FALSE, False);
356        contains!(IS_NULL, Null);
357
358        if (value & IS_OBJECT) == IS_OBJECT {
359            return DataType::Object(None);
360        }
361
362        contains!(IS_UNDEF, Undef);
363
364        DataType::Mixed
365    }
366}
367
368impl Display for DataType {
369    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
370        match self {
371            DataType::Undef => write!(f, "Undefined"),
372            DataType::Null => write!(f, "Null"),
373            DataType::False => write!(f, "False"),
374            DataType::True => write!(f, "True"),
375            DataType::Long => write!(f, "Long"),
376            DataType::Double => write!(f, "Double"),
377            DataType::String => write!(f, "String"),
378            DataType::Array => write!(f, "Array"),
379            DataType::Object(obj) => write!(f, "{}", obj.as_deref().unwrap_or("Object")),
380            DataType::Resource => write!(f, "Resource"),
381            DataType::Reference => write!(f, "Reference"),
382            DataType::Callable => write!(f, "Callable"),
383            DataType::ConstantExpression => write!(f, "Constant Expression"),
384            DataType::Void => write!(f, "Void"),
385            DataType::Bool => write!(f, "Bool"),
386            DataType::Mixed => write!(f, "Mixed"),
387            DataType::Ptr => write!(f, "Pointer"),
388            DataType::Indirect => write!(f, "Indirect"),
389            DataType::Iterable => write!(f, "Iterable"),
390        }
391    }
392}
393
394#[cfg(test)]
395mod tests {
396    use super::DataType;
397    use crate::ffi::{
398        IS_ARRAY, IS_ARRAY_EX, IS_CONSTANT_AST, IS_CONSTANT_AST_EX, IS_DOUBLE, IS_FALSE,
399        IS_INDIRECT, IS_INTERNED_STRING_EX, IS_LONG, IS_NULL, IS_OBJECT, IS_OBJECT_EX, IS_PTR,
400        IS_REFERENCE, IS_REFERENCE_EX, IS_RESOURCE, IS_RESOURCE_EX, IS_STRING, IS_STRING_EX,
401        IS_TRUE, IS_UNDEF, IS_VOID,
402    };
403    use std::convert::TryFrom;
404
405    #[test]
406    fn test_datatype() {
407        macro_rules! test {
408            ($c: ident, $t: ident) => {
409                assert_eq!(DataType::try_from($c), Ok(DataType::$t));
410            };
411        }
412
413        test!(IS_UNDEF, Undef);
414        test!(IS_NULL, Null);
415        test!(IS_FALSE, False);
416        test!(IS_TRUE, True);
417        test!(IS_LONG, Long);
418        test!(IS_DOUBLE, Double);
419        test!(IS_STRING, String);
420        test!(IS_ARRAY, Array);
421        assert_eq!(DataType::try_from(IS_OBJECT), Ok(DataType::Object(None)));
422        test!(IS_RESOURCE, Resource);
423        test!(IS_REFERENCE, Reference);
424        test!(IS_CONSTANT_AST, ConstantExpression);
425        test!(IS_INDIRECT, Indirect);
426        test!(IS_VOID, Void);
427        test!(IS_PTR, Ptr);
428
429        test!(IS_INTERNED_STRING_EX, String);
430        test!(IS_STRING_EX, String);
431        test!(IS_ARRAY_EX, Array);
432        assert_eq!(DataType::try_from(IS_OBJECT_EX), Ok(DataType::Object(None)));
433        test!(IS_RESOURCE_EX, Resource);
434        test!(IS_REFERENCE_EX, Reference);
435        test!(IS_CONSTANT_AST_EX, ConstantExpression);
436    }
437}