1use bitflags::bitflags;
4
5#[cfg(php81)]
6use crate::ffi::ZEND_ACC_ENUM;
7#[cfg(not(php82))]
8use crate::ffi::ZEND_ACC_REUSE_GET_ITERATOR;
9use crate::ffi::{
10 _IS_BOOL, CONST_CS, CONST_DEPRECATED, CONST_NO_FILE_CACHE, CONST_PERSISTENT, E_COMPILE_ERROR,
11 E_COMPILE_WARNING, E_CORE_ERROR, E_CORE_WARNING, E_DEPRECATED, E_ERROR, E_NOTICE, E_PARSE,
12 E_RECOVERABLE_ERROR, E_STRICT, E_USER_DEPRECATED, E_USER_ERROR, E_USER_NOTICE, E_USER_WARNING,
13 E_WARNING, GC_IMMUTABLE, IS_ARRAY, IS_CALLABLE, IS_CONSTANT_AST, IS_DOUBLE, IS_FALSE,
14 IS_INDIRECT, IS_ITERABLE, IS_LONG, IS_MIXED, IS_NULL, IS_OBJECT, IS_PTR, IS_REFERENCE,
15 IS_RESOURCE, IS_STRING, IS_TRUE, IS_TYPE_COLLECTABLE, IS_TYPE_REFCOUNTED, IS_UNDEF, IS_VOID,
16 PHP_INI_ALL, PHP_INI_PERDIR, PHP_INI_SYSTEM, PHP_INI_USER, Z_TYPE_FLAGS_SHIFT,
17 ZEND_ACC_ABSTRACT, ZEND_ACC_ANON_CLASS, ZEND_ACC_CALL_VIA_TRAMPOLINE, ZEND_ACC_CHANGED,
18 ZEND_ACC_CLOSURE, ZEND_ACC_CONSTANTS_UPDATED, ZEND_ACC_CTOR, ZEND_ACC_DEPRECATED,
19 ZEND_ACC_DONE_PASS_TWO, ZEND_ACC_EARLY_BINDING, ZEND_ACC_FAKE_CLOSURE, ZEND_ACC_FINAL,
20 ZEND_ACC_GENERATOR, ZEND_ACC_HAS_FINALLY_BLOCK, ZEND_ACC_HAS_RETURN_TYPE,
21 ZEND_ACC_HAS_TYPE_HINTS, ZEND_ACC_HEAP_RT_CACHE, ZEND_ACC_IMMUTABLE,
22 ZEND_ACC_IMPLICIT_ABSTRACT_CLASS, ZEND_ACC_INTERFACE, ZEND_ACC_LINKED, ZEND_ACC_NEARLY_LINKED,
23 ZEND_ACC_NEVER_CACHE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PRELOADED, ZEND_ACC_PRIVATE,
24 ZEND_ACC_PROMOTED, ZEND_ACC_PROTECTED, ZEND_ACC_PUBLIC, ZEND_ACC_RESOLVED_INTERFACES,
25 ZEND_ACC_RESOLVED_PARENT, ZEND_ACC_RETURN_REFERENCE, ZEND_ACC_STATIC, ZEND_ACC_STRICT_TYPES,
26 ZEND_ACC_TOP_LEVEL, ZEND_ACC_TRAIT, ZEND_ACC_TRAIT_CLONE, ZEND_ACC_UNRESOLVED_VARIANCE,
27 ZEND_ACC_USE_GUARDS, ZEND_ACC_USES_THIS, ZEND_ACC_VARIADIC, ZEND_EVAL_CODE,
28 ZEND_HAS_STATIC_IN_METHODS, ZEND_INTERNAL_FUNCTION, ZEND_USER_FUNCTION,
29};
30
31use std::{convert::TryFrom, fmt::Display};
32
33use crate::error::{Error, Result};
34
35bitflags! {
36 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
38 pub struct ZvalTypeFlags: u32 {
39 const Undef = IS_UNDEF;
41 const Null = IS_NULL;
43 const False = IS_FALSE;
45 const True = IS_TRUE;
47 const Long = IS_LONG;
49 const Double = IS_DOUBLE;
51 const String = IS_STRING;
53 const Array = IS_ARRAY;
55 const Object = IS_OBJECT;
57 const Resource = IS_RESOURCE;
59 const Reference = IS_REFERENCE;
61 const Callable = IS_CALLABLE;
63 const ConstantExpression = IS_CONSTANT_AST;
65 const Void = IS_VOID;
67 const Ptr = IS_PTR;
69 const Iterable = IS_ITERABLE;
71
72 const InternedStringEx = Self::String.bits();
74 const StringEx = Self::String.bits() | Self::RefCounted.bits();
76 const ArrayEx = Self::Array.bits() | Self::RefCounted.bits() | Self::Collectable.bits();
78 const ObjectEx = Self::Object.bits() | Self::RefCounted.bits() | Self::Collectable.bits();
80 const ResourceEx = Self::Resource.bits() | Self::RefCounted.bits();
82 const ReferenceEx = Self::Reference.bits() | Self::RefCounted.bits();
84 const ConstantAstEx = Self::ConstantExpression.bits() | Self::RefCounted.bits();
86
87 const RefCounted = (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT);
89 const Collectable = (IS_TYPE_COLLECTABLE << Z_TYPE_FLAGS_SHIFT);
91
92 const Immutable = GC_IMMUTABLE;
94 }
95}
96
97bitflags! {
98 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
100 pub struct ClassFlags: u32 {
101 const Final = ZEND_ACC_FINAL;
103 const Abstract = ZEND_ACC_ABSTRACT;
105 const Immutable = ZEND_ACC_IMMUTABLE;
108 const HasTypeHints = ZEND_ACC_HAS_TYPE_HINTS;
110 const TopLevel = ZEND_ACC_TOP_LEVEL;
112 const Preloaded = ZEND_ACC_PRELOADED;
114
115 const Interface = ZEND_ACC_INTERFACE;
117 const Trait = ZEND_ACC_TRAIT;
119 const AnonymousClass = ZEND_ACC_ANON_CLASS;
121 #[cfg(php81)]
123 const Enum = ZEND_ACC_ENUM;
124 const Linked = ZEND_ACC_LINKED;
126 const ImplicitAbstractClass = ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
128 const UseGuards = ZEND_ACC_USE_GUARDS;
130
131 const ConstantsUpdated = ZEND_ACC_CONSTANTS_UPDATED;
133 const NoDynamicProperties = ZEND_ACC_NO_DYNAMIC_PROPERTIES;
135 const HasStaticInMethods = ZEND_HAS_STATIC_IN_METHODS;
137 #[cfg(not(php82))]
139 const ReuseGetIterator = ZEND_ACC_REUSE_GET_ITERATOR;
140 const ResolvedParent = ZEND_ACC_RESOLVED_PARENT;
142 const ResolvedInterfaces = ZEND_ACC_RESOLVED_INTERFACES;
144 const UnresolvedVariance = ZEND_ACC_UNRESOLVED_VARIANCE;
146 const NearlyLinked = ZEND_ACC_NEARLY_LINKED;
148
149 #[cfg(php81)]
151 const NotSerializable = crate::ffi::ZEND_ACC_NOT_SERIALIZABLE;
152 }
153}
154
155bitflags! {
156 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
158 pub struct MethodFlags: u32 {
159 const Public = ZEND_ACC_PUBLIC;
161 const Protected = ZEND_ACC_PROTECTED;
163 const Private = ZEND_ACC_PRIVATE;
165 const Changed = ZEND_ACC_CHANGED;
167 const Static = ZEND_ACC_STATIC;
169 const Final = ZEND_ACC_FINAL;
171 const Abstract = ZEND_ACC_ABSTRACT;
173 const Immutable = ZEND_ACC_IMMUTABLE;
176 const HasTypeHints = ZEND_ACC_HAS_TYPE_HINTS;
178 const TopLevel = ZEND_ACC_TOP_LEVEL;
180 const Preloaded = ZEND_ACC_PRELOADED;
182
183 const Deprecated = ZEND_ACC_DEPRECATED;
185 const ReturnReference = ZEND_ACC_RETURN_REFERENCE;
187 const HasReturnType = ZEND_ACC_HAS_RETURN_TYPE;
189 const Variadic = ZEND_ACC_VARIADIC;
191 const HasFinallyBlock = ZEND_ACC_HAS_FINALLY_BLOCK;
193 const EarlyBinding = ZEND_ACC_EARLY_BINDING;
195 const UsesThis = ZEND_ACC_USES_THIS;
197 const CallViaTrampoline = ZEND_ACC_CALL_VIA_TRAMPOLINE;
203 const NeverCache = ZEND_ACC_NEVER_CACHE;
205 const TraitClone = ZEND_ACC_TRAIT_CLONE;
207 const IsConstructor = ZEND_ACC_CTOR;
209 const Closure = ZEND_ACC_CLOSURE;
211 const FakeClosure = ZEND_ACC_FAKE_CLOSURE;
213 const Generator = ZEND_ACC_GENERATOR;
215 const DonePassTwo = ZEND_ACC_DONE_PASS_TWO;
217 const HeapRTCache = ZEND_ACC_HEAP_RT_CACHE;
219 const StrictTypes = ZEND_ACC_STRICT_TYPES;
221 }
222}
223
224bitflags! {
225 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
227 pub struct PropertyFlags: u32 {
228 const Public = ZEND_ACC_PUBLIC;
230 const Protected = ZEND_ACC_PROTECTED;
232 const Private = ZEND_ACC_PRIVATE;
234 const Changed = ZEND_ACC_CHANGED;
236 const Static = ZEND_ACC_STATIC;
238 const Promoted = ZEND_ACC_PROMOTED;
240 }
241}
242
243bitflags! {
244 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
246 pub struct ConstantFlags: u32 {
247 const Public = ZEND_ACC_PUBLIC;
249 const Protected = ZEND_ACC_PROTECTED;
251 const Private = ZEND_ACC_PRIVATE;
253 const Promoted = ZEND_ACC_PROMOTED;
255 }
256}
257
258bitflags! {
259 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
261 pub struct GlobalConstantFlags: u32 {
262 #[deprecated(note = "No longer used -- always case-sensitive")]
264 const CaseSensitive = CONST_CS;
265 const Persistent = CONST_PERSISTENT;
267 const NoFileCache = CONST_NO_FILE_CACHE;
269 const Deprecated = CONST_DEPRECATED;
271 }
272}
273
274bitflags! {
275 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
277 pub struct ZendResult: i32 {
278 const Success = 0;
280 const Failure = -1;
282 }
283}
284
285bitflags! {
286 pub struct IniEntryPermission: u32 {
288 const User = PHP_INI_USER;
290 const PerDir = PHP_INI_PERDIR;
292 const System = PHP_INI_SYSTEM;
294 const All = PHP_INI_ALL;
296 }
297}
298
299bitflags! {
300 pub struct ErrorType: u32 {
302 const Error = E_ERROR;
304 const Warning = E_WARNING;
306 const Parse = E_PARSE;
308 const Notice = E_NOTICE;
310 const CoreError = E_CORE_ERROR;
312 const CoreWarning = E_CORE_WARNING;
314 const CompileError = E_COMPILE_ERROR;
316 const CompileWarning = E_COMPILE_WARNING;
318 #[cfg_attr(php84, deprecated = "`E_USER_ERROR` is deprecated since PHP 8.4. Throw an exception instead.")]
320 const UserError = E_USER_ERROR;
321 const UserWarning = E_USER_WARNING;
323 const UserNotice = E_USER_NOTICE;
325 const Strict = E_STRICT;
327 const RecoverableError = E_RECOVERABLE_ERROR;
329 const Deprecated = E_DEPRECATED;
331 const UserDeprecated = E_USER_DEPRECATED;
333 }
334}
335
336#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
338pub enum FunctionType {
339 Internal,
341 User,
343 Eval,
345}
346
347impl From<u8> for FunctionType {
348 #[allow(clippy::bad_bit_mask)]
349 fn from(value: u8) -> Self {
350 match value.into() {
351 ZEND_INTERNAL_FUNCTION => Self::Internal,
352 ZEND_USER_FUNCTION => Self::User,
353 ZEND_EVAL_CODE => Self::Eval,
354 _ => panic!("Unknown function type: {value}"),
355 }
356 }
357}
358
359#[repr(C, u8)]
361#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
362pub enum DataType {
363 Undef,
365 Null,
367 False,
369 True,
371 Long,
373 Double,
375 String,
377 Array,
379 Iterable,
381 Object(Option<&'static str>),
383 Resource,
385 Reference,
387 Callable,
389 ConstantExpression,
391 #[default]
393 Void,
394 Mixed,
396 Bool,
398 Ptr,
400 Indirect,
402}
403
404impl DataType {
405 #[must_use]
407 pub const fn as_u32(&self) -> u32 {
408 match self {
409 DataType::Undef => IS_UNDEF,
410 DataType::Null => IS_NULL,
411 DataType::False => IS_FALSE,
412 DataType::True => IS_TRUE,
413 DataType::Long => IS_LONG,
414 DataType::Double => IS_DOUBLE,
415 DataType::String => IS_STRING,
416 DataType::Array => IS_ARRAY,
417 DataType::Object(_) => IS_OBJECT,
418 DataType::Resource | DataType::Reference => IS_RESOURCE,
419 DataType::Indirect => IS_INDIRECT,
420 DataType::Callable => IS_CALLABLE,
421 DataType::ConstantExpression => IS_CONSTANT_AST,
422 DataType::Void => IS_VOID,
423 DataType::Mixed => IS_MIXED,
424 DataType::Bool => _IS_BOOL,
425 DataType::Ptr => IS_PTR,
426 DataType::Iterable => IS_ITERABLE,
427 }
428 }
429}
430
431impl TryFrom<ZvalTypeFlags> for DataType {
443 type Error = Error;
444
445 fn try_from(value: ZvalTypeFlags) -> Result<Self> {
446 macro_rules! contains {
447 ($t: ident) => {
448 if value.contains(ZvalTypeFlags::$t) {
449 return Ok(DataType::$t);
450 }
451 };
452 }
453
454 contains!(Undef);
455 contains!(Null);
456 contains!(False);
457 contains!(True);
458 contains!(False);
459 contains!(Long);
460 contains!(Double);
461 contains!(String);
462 contains!(Array);
463 contains!(Resource);
464 contains!(Callable);
465 contains!(ConstantExpression);
466 contains!(Void);
467
468 if value.contains(ZvalTypeFlags::Object) {
469 return Ok(DataType::Object(None));
470 }
471
472 Err(Error::UnknownDatatype(0))
473 }
474}
475
476impl From<u32> for DataType {
477 #[allow(clippy::bad_bit_mask)]
478 fn from(value: u32) -> Self {
479 macro_rules! contains {
480 ($c: ident, $t: ident) => {
481 if (value & $c) == $c {
482 return DataType::$t;
483 }
484 };
485 }
486
487 contains!(IS_VOID, Void);
488 contains!(IS_PTR, Ptr);
489 contains!(IS_INDIRECT, Indirect);
490 contains!(IS_CALLABLE, Callable);
491 contains!(IS_CONSTANT_AST, ConstantExpression);
492 contains!(IS_REFERENCE, Reference);
493 contains!(IS_RESOURCE, Resource);
494 contains!(IS_ARRAY, Array);
495 contains!(IS_STRING, String);
496 contains!(IS_DOUBLE, Double);
497 contains!(IS_LONG, Long);
498 contains!(IS_TRUE, True);
499 contains!(IS_FALSE, False);
500 contains!(IS_NULL, Null);
501
502 if (value & IS_OBJECT) == IS_OBJECT {
503 return DataType::Object(None);
504 }
505
506 contains!(IS_UNDEF, Undef);
507
508 DataType::Mixed
509 }
510}
511
512impl Display for DataType {
513 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
514 match self {
515 DataType::Undef => write!(f, "Undefined"),
516 DataType::Null => write!(f, "Null"),
517 DataType::False => write!(f, "False"),
518 DataType::True => write!(f, "True"),
519 DataType::Long => write!(f, "Long"),
520 DataType::Double => write!(f, "Double"),
521 DataType::String => write!(f, "String"),
522 DataType::Array => write!(f, "Array"),
523 DataType::Object(obj) => write!(f, "{}", obj.as_deref().unwrap_or("Object")),
524 DataType::Resource => write!(f, "Resource"),
525 DataType::Reference => write!(f, "Reference"),
526 DataType::Callable => write!(f, "Callable"),
527 DataType::ConstantExpression => write!(f, "Constant Expression"),
528 DataType::Void => write!(f, "Void"),
529 DataType::Bool => write!(f, "Bool"),
530 DataType::Mixed => write!(f, "Mixed"),
531 DataType::Ptr => write!(f, "Pointer"),
532 DataType::Indirect => write!(f, "Indirect"),
533 DataType::Iterable => write!(f, "Iterable"),
534 }
535 }
536}
537
538#[cfg(test)]
539mod tests {
540 #![allow(clippy::unnecessary_fallible_conversions)]
541 use super::DataType;
542 use crate::ffi::{
543 IS_ARRAY, IS_ARRAY_EX, IS_CONSTANT_AST, IS_CONSTANT_AST_EX, IS_DOUBLE, IS_FALSE,
544 IS_INDIRECT, IS_INTERNED_STRING_EX, IS_LONG, IS_NULL, IS_OBJECT, IS_OBJECT_EX, IS_PTR,
545 IS_REFERENCE, IS_REFERENCE_EX, IS_RESOURCE, IS_RESOURCE_EX, IS_STRING, IS_STRING_EX,
546 IS_TRUE, IS_UNDEF, IS_VOID,
547 };
548 use std::convert::TryFrom;
549
550 #[test]
551 fn test_datatype() {
552 macro_rules! test {
553 ($c: ident, $t: ident) => {
554 assert_eq!(DataType::try_from($c), Ok(DataType::$t));
555 };
556 }
557
558 test!(IS_UNDEF, Undef);
559 test!(IS_NULL, Null);
560 test!(IS_FALSE, False);
561 test!(IS_TRUE, True);
562 test!(IS_LONG, Long);
563 test!(IS_DOUBLE, Double);
564 test!(IS_STRING, String);
565 test!(IS_ARRAY, Array);
566 assert_eq!(DataType::try_from(IS_OBJECT), Ok(DataType::Object(None)));
567 test!(IS_RESOURCE, Resource);
568 test!(IS_REFERENCE, Reference);
569 test!(IS_CONSTANT_AST, ConstantExpression);
570 test!(IS_INDIRECT, Indirect);
571 test!(IS_VOID, Void);
572 test!(IS_PTR, Ptr);
573
574 test!(IS_INTERNED_STRING_EX, String);
575 test!(IS_STRING_EX, String);
576 test!(IS_ARRAY_EX, Array);
577 assert_eq!(DataType::try_from(IS_OBJECT_EX), Ok(DataType::Object(None)));
578 test!(IS_RESOURCE_EX, Resource);
579 test!(IS_REFERENCE_EX, Reference);
580 test!(IS_CONSTANT_AST_EX, ConstantExpression);
581 }
582}