1use 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 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 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#[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 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
287impl 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}