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        /// Undefined
38        const Undef = IS_UNDEF;
39        /// Null
40        const Null = IS_NULL;
41        /// `false`
42        const False = IS_FALSE;
43        /// `true`
44        const True = IS_TRUE;
45        /// Integer
46        const Long = IS_LONG;
47        /// Floating point number
48        const Double = IS_DOUBLE;
49        /// String
50        const String = IS_STRING;
51        /// Array
52        const Array = IS_ARRAY;
53        /// Object
54        const Object = IS_OBJECT;
55        /// Resource
56        const Resource = IS_RESOURCE;
57        /// Reference
58        const Reference = IS_REFERENCE;
59        /// Callable
60        const Callable = IS_CALLABLE;
61        /// Constant expression
62        const ConstantExpression = IS_CONSTANT_AST;
63        /// Void
64        const Void = IS_VOID;
65        /// Pointer
66        const Ptr = IS_PTR;
67        /// Iterable
68        const Iterable = IS_ITERABLE;
69
70        /// Interned string extended
71        const InternedStringEx = Self::String.bits();
72        /// String extended
73        const StringEx = Self::String.bits() | Self::RefCounted.bits();
74        /// Array extended
75        const ArrayEx = Self::Array.bits() | Self::RefCounted.bits() | Self::Collectable.bits();
76        /// Object extended
77        const ObjectEx = Self::Object.bits() | Self::RefCounted.bits() | Self::Collectable.bits();
78        /// Resource extended
79        const ResourceEx = Self::Resource.bits() | Self::RefCounted.bits();
80        /// Reference extended
81        const ReferenceEx = Self::Reference.bits() | Self::RefCounted.bits();
82        /// Constant ast extended
83        const ConstantAstEx = Self::ConstantExpression.bits() | Self::RefCounted.bits();
84
85        /// Reference counted
86        const RefCounted = (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT);
87        /// Collectable
88        const Collectable = (IS_TYPE_COLLECTABLE << Z_TYPE_FLAGS_SHIFT);
89    }
90}
91
92bitflags! {
93    /// Flags for building classes.
94    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
95    pub struct ClassFlags: u32 {
96        /// Final class or method
97        const Final = ZEND_ACC_FINAL;
98        /// Abstract method
99        const Abstract = ZEND_ACC_ABSTRACT;
100        /// Immutable `op_array` and class_entries
101        /// (implemented only for lazy loading of `op_array`s)
102        const Immutable = ZEND_ACC_IMMUTABLE;
103        /// Function has typed arguments / class has typed props
104        const HasTypeHints = ZEND_ACC_HAS_TYPE_HINTS;
105        /// Top-level class or function declaration
106        const TopLevel = ZEND_ACC_TOP_LEVEL;
107        /// op_array or class is preloaded
108        const Preloaded = ZEND_ACC_PRELOADED;
109
110        /// Class entry is an interface
111        const Interface = ZEND_ACC_INTERFACE;
112        /// Class entry is a trait
113        const Trait = ZEND_ACC_TRAIT;
114        /// Anonymous class
115        const AnonymousClass = ZEND_ACC_ANON_CLASS;
116        /// Class linked with parent, interfaces and traits
117        const Linked = ZEND_ACC_LINKED;
118        /// Class is abstract, since it is set by any abstract method
119        const ImplicitAbstractClass = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
120        /// Class has magic methods `__get`/`__set`/`__unset`/`__isset` that use guards
121        const UseGuards = ZEND_ACC_USE_GUARDS;
122
123        /// Class constants updated
124        const ConstantsUpdated = ZEND_ACC_CONSTANTS_UPDATED;
125        /// Objects of this class may not have dynamic properties
126        const NoDynamicProperties = ZEND_ACC_NO_DYNAMIC_PROPERTIES;
127        /// User class has methods with static variables
128        const HasStaticInMethods = ZEND_HAS_STATIC_IN_METHODS;
129        /// Children must reuse parent `get_iterator()`
130        #[cfg(not(php82))]
131        const ReuseGetIterator = ZEND_ACC_REUSE_GET_ITERATOR;
132        /// Parent class is resolved (CE)
133        const ResolvedParent = ZEND_ACC_RESOLVED_PARENT;
134        /// Interfaces are resolved (CE)
135        const ResolvedInterfaces = ZEND_ACC_RESOLVED_INTERFACES;
136        /// Class has unresolved variance obligations
137        const UnresolvedVariance = ZEND_ACC_UNRESOLVED_VARIANCE;
138        /// Class is linked apart from variance obligations
139        const NearlyLinked = ZEND_ACC_NEARLY_LINKED;
140
141        /// Class cannot be serialized or unserialized
142        #[cfg(php81)]
143        const NotSerializable = crate::ffi::ZEND_ACC_NOT_SERIALIZABLE;
144    }
145}
146
147bitflags! {
148    /// Flags for building methods.
149    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
150    pub struct MethodFlags: u32 {
151        /// Visibility public
152        const Public = ZEND_ACC_PUBLIC;
153        /// Visibility protected
154        const Protected = ZEND_ACC_PROTECTED;
155        /// Visibility private
156        const Private = ZEND_ACC_PRIVATE;
157        /// Method or property overrides private one
158        const Changed = ZEND_ACC_CHANGED;
159        /// Static method
160        const Static = ZEND_ACC_STATIC;
161        /// Final method
162        const Final = ZEND_ACC_FINAL;
163        /// Abstract method
164        const Abstract = ZEND_ACC_ABSTRACT;
165        /// Immutable `op_array` and class_entries
166        /// (implemented only for lazy loading of op_arrays)
167        const Immutable = ZEND_ACC_IMMUTABLE;
168        /// Function has typed arguments / class has typed props
169        const HasTypeHints = ZEND_ACC_HAS_TYPE_HINTS;
170        /// Top-level class or function declaration
171        const TopLevel = ZEND_ACC_TOP_LEVEL;
172        /// `op_array` or class is preloaded
173        const Preloaded = ZEND_ACC_PRELOADED;
174
175        /// Deprecation flag
176        const Deprecated = ZEND_ACC_DEPRECATED;
177        /// Function returning by reference
178        const ReturnReference = ZEND_ACC_RETURN_REFERENCE;
179        /// Function has a return type
180        const HasReturnType = ZEND_ACC_HAS_RETURN_TYPE;
181        /// Function with variable number of arguments
182        const Variadic = ZEND_ACC_VARIADIC;
183        /// `op_array` has finally blocks (user only)
184        const HasFinallyBlock = ZEND_ACC_HAS_FINALLY_BLOCK;
185        /// "main" `op_array` with `ZEND_DECLARE_CLASS_DELAYED` opcodes
186        const EarlyBinding = ZEND_ACC_EARLY_BINDING;
187        /// Closure uses `$this`
188        const UsesThis = ZEND_ACC_USES_THIS;
189        /// Call through user function trampoline
190        ///
191        /// # Example
192        /// - `__call`
193        /// - `__callStatic`
194        const CallViaTrampoline = ZEND_ACC_CALL_VIA_TRAMPOLINE;
195        /// Disable inline caching
196        const NeverCache = ZEND_ACC_NEVER_CACHE;
197        /// `op_array` is a clone of trait method
198        const TraitClone = ZEND_ACC_TRAIT_CLONE;
199        /// Function is a constructor
200        const IsConstructor = ZEND_ACC_CTOR;
201        /// Function is a closure
202        const Closure = ZEND_ACC_CLOSURE;
203        /// Function is a fake closure
204        const FakeClosure = ZEND_ACC_FAKE_CLOSURE;
205        /// Function is a generator
206        const Generator = ZEND_ACC_GENERATOR;
207        /// Function was processed by pass two (user only)
208        const DonePassTwo = ZEND_ACC_DONE_PASS_TWO;
209        /// `run_time_cache` allocated on heap (user only)
210        const HeapRTCache = ZEND_ACC_HEAP_RT_CACHE;
211        /// `op_array` uses strict mode types
212        const StrictTypes = ZEND_ACC_STRICT_TYPES;
213    }
214}
215
216bitflags! {
217    /// Flags for building properties.
218    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
219    pub struct PropertyFlags: u32 {
220        /// Visibility public
221        const Public = ZEND_ACC_PUBLIC;
222        /// Visibility protected
223        const Protected = ZEND_ACC_PROTECTED;
224        /// Visibility private
225        const Private = ZEND_ACC_PRIVATE;
226        /// Property or method overrides private one
227        const Changed = ZEND_ACC_CHANGED;
228        /// Static property
229        const Static = ZEND_ACC_STATIC;
230        /// Promoted property
231        const Promoted = ZEND_ACC_PROMOTED;
232    }
233}
234
235bitflags! {
236    /// Flags for building constants.
237    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
238    pub struct ConstantFlags: u32 {
239        /// Visibility public
240        const Public = ZEND_ACC_PUBLIC;
241        /// Visibility protected
242        const Protected = ZEND_ACC_PROTECTED;
243        /// Visibility private
244        const Private = ZEND_ACC_PRIVATE;
245        /// Promoted constant
246        const Promoted = ZEND_ACC_PROMOTED;
247    }
248}
249
250bitflags! {
251    /// Flags for building module global constants.
252    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
253    pub struct GlobalConstantFlags: u32 {
254        /// No longer used -- always case-sensitive
255        #[deprecated(note = "No longer used -- always case-sensitive")]
256        const CaseSensitive = CONST_CS;
257        /// Persistent
258        const Persistent = CONST_PERSISTENT;
259        /// Can't be saved in file cache
260        const NoFileCache = CONST_NO_FILE_CACHE;
261        /// Deprecated (this flag is not deprecated, it literally means the constant is deprecated)
262        const Deprecated = CONST_DEPRECATED;
263    }
264}
265
266bitflags! {
267    /// Represents the result of a function.
268    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
269    pub struct ZendResult: i32 {
270        /// Function call was successful.
271        const Success = 0;
272        /// Function call failed.
273        const Failure = -1;
274    }
275}
276
277bitflags! {
278    /// Represents permissions for where a configuration setting may be set.
279    pub struct IniEntryPermission: u32 {
280        /// User
281        const User = PHP_INI_USER;
282        /// Per directory
283        const PerDir = PHP_INI_PERDIR;
284        /// System
285        const System = PHP_INI_SYSTEM;
286        /// All
287        const All = PHP_INI_ALL;
288    }
289}
290
291bitflags! {
292    /// Represents error types when used via php_error_docref for example.
293    pub struct ErrorType: u32 {
294        /// Error
295        const Error = E_ERROR;
296        /// Warning
297        const Warning = E_WARNING;
298        /// Parse
299        const Parse = E_PARSE;
300        /// Notice
301        const Notice = E_NOTICE;
302        /// Core error
303        const CoreError = E_CORE_ERROR;
304        /// Core warning
305        const CoreWarning = E_CORE_WARNING;
306        /// Compile error
307        const CompileError = E_COMPILE_ERROR;
308        /// Compile warning
309        const CompileWarning = E_COMPILE_WARNING;
310        /// User error
311        const UserError = E_USER_ERROR;
312        /// User warning
313        const UserWarning = E_USER_WARNING;
314        /// User notice
315        const UserNotice = E_USER_NOTICE;
316        /// Strict
317        const Strict = E_STRICT;
318        /// Recoverable error
319        const RecoverableError = E_RECOVERABLE_ERROR;
320        /// Deprecated
321        const Deprecated = E_DEPRECATED;
322        /// User deprecated
323        const UserDeprecated = E_USER_DEPRECATED;
324    }
325}
326
327/// Represents the type of a function.
328#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
329pub enum FunctionType {
330    /// Internal function
331    Internal,
332    /// User function
333    User,
334    /// Eval code
335    Eval,
336}
337
338impl From<u8> for FunctionType {
339    #[allow(clippy::bad_bit_mask)]
340    fn from(value: u8) -> Self {
341        match value.into() {
342            ZEND_INTERNAL_FUNCTION => Self::Internal,
343            ZEND_USER_FUNCTION => Self::User,
344            ZEND_EVAL_CODE => Self::Eval,
345            _ => panic!("Unknown function type: {value}"),
346        }
347    }
348}
349
350/// Valid data types for PHP.
351#[repr(C, u8)]
352#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
353pub enum DataType {
354    /// Undefined
355    Undef,
356    /// `null`
357    Null,
358    /// `false`
359    False,
360    /// `true`
361    True,
362    /// Integer (the irony)
363    Long,
364    /// Floating point number
365    Double,
366    /// String
367    String,
368    /// Array
369    Array,
370    /// Iterable
371    Iterable,
372    /// Object
373    Object(Option<&'static str>),
374    /// Resource
375    Resource,
376    /// Reference
377    Reference,
378    /// Callable
379    Callable,
380    /// Constant expression
381    ConstantExpression,
382    /// Void
383    Void,
384    /// Mixed
385    Mixed,
386    /// Boolean
387    Bool,
388    /// Pointer
389    Ptr,
390    /// Indirect (internal)
391    Indirect,
392}
393
394impl Default for DataType {
395    fn default() -> Self {
396        Self::Void
397    }
398}
399
400impl DataType {
401    /// Returns the integer representation of the data type.
402    #[must_use]
403    pub const fn as_u32(&self) -> u32 {
404        match self {
405            DataType::Undef => IS_UNDEF,
406            DataType::Null => IS_NULL,
407            DataType::False => IS_FALSE,
408            DataType::True => IS_TRUE,
409            DataType::Long => IS_LONG,
410            DataType::Double => IS_DOUBLE,
411            DataType::String => IS_STRING,
412            DataType::Array => IS_ARRAY,
413            DataType::Object(_) => IS_OBJECT,
414            DataType::Resource | DataType::Reference => IS_RESOURCE,
415            DataType::Indirect => IS_INDIRECT,
416            DataType::Callable => IS_CALLABLE,
417            DataType::ConstantExpression => IS_CONSTANT_AST,
418            DataType::Void => IS_VOID,
419            DataType::Mixed => IS_MIXED,
420            DataType::Bool => _IS_BOOL,
421            DataType::Ptr => IS_PTR,
422            DataType::Iterable => IS_ITERABLE,
423        }
424    }
425}
426
427// TODO: Ideally want something like this
428// pub struct Type {
429//     data_type: DataType,
430//     is_refcounted: bool,
431//     is_collectable: bool,
432//     is_immutable: bool,
433//     is_persistent: bool,
434// }
435//
436// impl From<u32> for Type { ... }
437
438impl TryFrom<ZvalTypeFlags> for DataType {
439    type Error = Error;
440
441    fn try_from(value: ZvalTypeFlags) -> Result<Self> {
442        macro_rules! contains {
443            ($t: ident) => {
444                if value.contains(ZvalTypeFlags::$t) {
445                    return Ok(DataType::$t);
446                }
447            };
448        }
449
450        contains!(Undef);
451        contains!(Null);
452        contains!(False);
453        contains!(True);
454        contains!(False);
455        contains!(Long);
456        contains!(Double);
457        contains!(String);
458        contains!(Array);
459        contains!(Resource);
460        contains!(Callable);
461        contains!(ConstantExpression);
462        contains!(Void);
463
464        if value.contains(ZvalTypeFlags::Object) {
465            return Ok(DataType::Object(None));
466        }
467
468        Err(Error::UnknownDatatype(0))
469    }
470}
471
472impl From<u32> for DataType {
473    #[allow(clippy::bad_bit_mask)]
474    fn from(value: u32) -> Self {
475        macro_rules! contains {
476            ($c: ident, $t: ident) => {
477                if (value & $c) == $c {
478                    return DataType::$t;
479                }
480            };
481        }
482
483        contains!(IS_VOID, Void);
484        contains!(IS_PTR, Ptr);
485        contains!(IS_INDIRECT, Indirect);
486        contains!(IS_CALLABLE, Callable);
487        contains!(IS_CONSTANT_AST, ConstantExpression);
488        contains!(IS_REFERENCE, Reference);
489        contains!(IS_RESOURCE, Resource);
490        contains!(IS_ARRAY, Array);
491        contains!(IS_STRING, String);
492        contains!(IS_DOUBLE, Double);
493        contains!(IS_LONG, Long);
494        contains!(IS_TRUE, True);
495        contains!(IS_FALSE, False);
496        contains!(IS_NULL, Null);
497
498        if (value & IS_OBJECT) == IS_OBJECT {
499            return DataType::Object(None);
500        }
501
502        contains!(IS_UNDEF, Undef);
503
504        DataType::Mixed
505    }
506}
507
508impl Display for DataType {
509    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
510        match self {
511            DataType::Undef => write!(f, "Undefined"),
512            DataType::Null => write!(f, "Null"),
513            DataType::False => write!(f, "False"),
514            DataType::True => write!(f, "True"),
515            DataType::Long => write!(f, "Long"),
516            DataType::Double => write!(f, "Double"),
517            DataType::String => write!(f, "String"),
518            DataType::Array => write!(f, "Array"),
519            DataType::Object(obj) => write!(f, "{}", obj.as_deref().unwrap_or("Object")),
520            DataType::Resource => write!(f, "Resource"),
521            DataType::Reference => write!(f, "Reference"),
522            DataType::Callable => write!(f, "Callable"),
523            DataType::ConstantExpression => write!(f, "Constant Expression"),
524            DataType::Void => write!(f, "Void"),
525            DataType::Bool => write!(f, "Bool"),
526            DataType::Mixed => write!(f, "Mixed"),
527            DataType::Ptr => write!(f, "Pointer"),
528            DataType::Indirect => write!(f, "Indirect"),
529            DataType::Iterable => write!(f, "Iterable"),
530        }
531    }
532}
533
534#[cfg(test)]
535mod tests {
536    #![allow(clippy::unnecessary_fallible_conversions)]
537    use super::DataType;
538    use crate::ffi::{
539        IS_ARRAY, IS_ARRAY_EX, IS_CONSTANT_AST, IS_CONSTANT_AST_EX, IS_DOUBLE, IS_FALSE,
540        IS_INDIRECT, IS_INTERNED_STRING_EX, IS_LONG, IS_NULL, IS_OBJECT, IS_OBJECT_EX, IS_PTR,
541        IS_REFERENCE, IS_REFERENCE_EX, IS_RESOURCE, IS_RESOURCE_EX, IS_STRING, IS_STRING_EX,
542        IS_TRUE, IS_UNDEF, IS_VOID,
543    };
544    use std::convert::TryFrom;
545
546    #[test]
547    fn test_datatype() {
548        macro_rules! test {
549            ($c: ident, $t: ident) => {
550                assert_eq!(DataType::try_from($c), Ok(DataType::$t));
551            };
552        }
553
554        test!(IS_UNDEF, Undef);
555        test!(IS_NULL, Null);
556        test!(IS_FALSE, False);
557        test!(IS_TRUE, True);
558        test!(IS_LONG, Long);
559        test!(IS_DOUBLE, Double);
560        test!(IS_STRING, String);
561        test!(IS_ARRAY, Array);
562        assert_eq!(DataType::try_from(IS_OBJECT), Ok(DataType::Object(None)));
563        test!(IS_RESOURCE, Resource);
564        test!(IS_REFERENCE, Reference);
565        test!(IS_CONSTANT_AST, ConstantExpression);
566        test!(IS_INDIRECT, Indirect);
567        test!(IS_VOID, Void);
568        test!(IS_PTR, Ptr);
569
570        test!(IS_INTERNED_STRING_EX, String);
571        test!(IS_STRING_EX, String);
572        test!(IS_ARRAY_EX, Array);
573        assert_eq!(DataType::try_from(IS_OBJECT_EX), Ok(DataType::Object(None)));
574        test!(IS_RESOURCE_EX, Resource);
575        test!(IS_REFERENCE_EX, Reference);
576        test!(IS_CONSTANT_AST_EX, ConstantExpression);
577    }
578}