phper/
types.rs

1// Copyright (c) 2022 PHPER Framework Team
2// PHPER is licensed under Mulan PSL v2.
3// You can use this software according to the terms and conditions of the Mulan
4// PSL v2. You may obtain a copy of Mulan PSL v2 at:
5//          http://license.coscl.org.cn/MulanPSL2
6// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
7// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
8// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9// See the Mulan PSL v2 for more details.
10
11//! Apis relate to PHP types.
12
13use crate::sys::*;
14use derive_more::From;
15use std::{
16    ffi::CStr,
17    fmt::{self, Debug, Display},
18    os::raw::c_int,
19};
20
21/// Wrapper of PHP type.
22#[derive(Clone, Copy, PartialEq, Eq)]
23pub struct TypeInfo {
24    t: u32,
25}
26
27impl TypeInfo {
28    /// Array type info.
29    pub const ARRAY: TypeInfo = TypeInfo::from_raw(IS_ARRAY);
30    /// Boolean type info.
31    pub const BOOL: TypeInfo = TypeInfo::from_raw(_IS_BOOL);
32    /// Double number type info.
33    pub const DOUBLE: TypeInfo = TypeInfo::from_raw(IS_DOUBLE);
34    /// Long number type info.
35    pub const LONG: TypeInfo = TypeInfo::from_raw(IS_LONG);
36    /// Null type info.
37    pub const NULL: TypeInfo = TypeInfo::from_raw(IS_NULL);
38    /// Object type info.
39    pub const OBJECT: TypeInfo = TypeInfo::from_raw(IS_OBJECT);
40    /// Reference type info.
41    pub const REFERENCE: TypeInfo = TypeInfo::from_raw(IS_REFERENCE);
42    /// Resource type info.
43    pub const RESOURCE: TypeInfo = TypeInfo::from_raw(IS_RESOURCE);
44    /// String type info.
45    pub const STRING: TypeInfo = TypeInfo::from_raw(IS_STRING);
46    /// Undefined type info.
47    pub const UNDEF: TypeInfo = TypeInfo::from_raw(IS_UNDEF);
48}
49
50impl TypeInfo {
51    /// Construct [`TypeInfo`] from raw number.
52    pub const fn from_raw(t: u32) -> Self {
53        Self { t }
54    }
55
56    /// Transfers [`TypeInfo`] to raw number.
57    pub const fn into_raw(self) -> u32 {
58        self.t
59    }
60
61    /// Detects if the [`TypeInfo`] is undefined.
62    pub const fn is_undef(self) -> bool {
63        self.t == IS_UNDEF
64    }
65
66    /// Detects if the [`TypeInfo`] is null.
67    pub const fn is_null(self) -> bool {
68        self.t == IS_NULL
69    }
70
71    /// Detects if the [`TypeInfo`] is boolean.
72    pub const fn is_bool(self) -> bool {
73        self.is_true() || self.is_false()
74    }
75
76    /// Detects if the [`TypeInfo`] is true.
77    pub const fn is_true(self) -> bool {
78        get_base_type_by_raw(self.t) == IS_TRUE
79    }
80
81    /// Detects if the [`TypeInfo`] is false.
82    pub const fn is_false(self) -> bool {
83        get_base_type_by_raw(self.t) == IS_FALSE
84    }
85
86    /// Detects if the [`TypeInfo`] is long.
87    pub const fn is_long(self) -> bool {
88        get_base_type_by_raw(self.t) == IS_LONG
89    }
90
91    /// Detects if the [`TypeInfo`] is double.
92    pub const fn is_double(self) -> bool {
93        get_base_type_by_raw(self.t) == IS_DOUBLE
94    }
95
96    /// Detects if the [`TypeInfo`] is string.
97    pub const fn is_string(self) -> bool {
98        get_base_type_by_raw(self.t) == IS_STRING
99    }
100
101    /// Detects if the [`TypeInfo`] is array.
102    pub const fn is_array(self) -> bool {
103        get_base_type_by_raw(self.t) == IS_ARRAY
104    }
105
106    /// Detects if the [`TypeInfo`] is object.
107    pub const fn is_object(self) -> bool {
108        get_base_type_by_raw(self.t) == IS_OBJECT
109    }
110
111    /// Detects if the [`TypeInfo`] is resource.
112    pub const fn is_resource(self) -> bool {
113        get_base_type_by_raw(self.t) == IS_RESOURCE
114    }
115
116    /// Detects if the [`TypeInfo`] is reference.
117    pub const fn is_reference(self) -> bool {
118        get_base_type_by_raw(self.t) == IS_REFERENCE
119    }
120
121    /// Transfers [`TypeInfo`] to the base type info.
122    pub const fn get_base_type(self) -> TypeInfo {
123        Self::from_raw(get_base_type_by_raw(self.t))
124    }
125
126    /// Gets the name of base type.
127    ///
128    /// Can be sure, `zend_get_type_by_const` returns the const string, So this
129    /// method returns `&'static CStr`.
130    #[inline]
131    pub fn get_base_type_name(self) -> &'static CStr {
132        unsafe {
133            let t = get_base_type_by_raw(self.t);
134
135            if t == IS_UNDEF {
136                return c"undef";
137            }
138            if t == IS_REFERENCE {
139                return c"reference";
140            }
141
142            let s = zend_get_type_by_const(t as c_int);
143            let s = CStr::from_ptr(s);
144
145            // Compact with PHP7.
146            let bs = s.to_bytes();
147            if bs == b"boolean" {
148                return c"bool";
149            }
150            if bs == b"integer" {
151                return c"int";
152            }
153
154            s
155        }
156    }
157}
158
159impl Debug for TypeInfo {
160    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161        f.debug_struct("TypeInfo")
162            .field("base_name", &self.get_base_type_name())
163            .field("base", &self.get_base_type().t)
164            .field("raw", &self.t)
165            .finish()
166    }
167}
168
169impl From<u32> for TypeInfo {
170    fn from(n: u32) -> Self {
171        Self::from_raw(n)
172    }
173}
174
175impl Display for TypeInfo {
176    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177        let t = self.get_base_type_name().to_str().unwrap_or("unknown");
178        Display::fmt(t, f)
179    }
180}
181
182const fn get_base_type_by_raw(t: u32) -> u32 {
183    t & !(!0 << Z_TYPE_FLAGS_SHIFT)
184}
185
186/// Copyable value, used in constant and class property.
187#[derive(From)]
188pub enum Scalar {
189    /// Null.
190    Null,
191    /// Boolean.
192    Bool(bool),
193    /// Long.
194    I64(i64),
195    /// Double.
196    F64(f64),
197    /// String
198    String(String),
199    /// Binary string.
200    Bytes(Vec<u8>),
201}
202
203impl From<()> for Scalar {
204    fn from(_: ()) -> Self {
205        Self::Null
206    }
207}
208
209impl From<&str> for Scalar {
210    fn from(s: &str) -> Self {
211        Self::String(s.to_owned())
212    }
213}
214
215impl From<&[u8]> for Scalar {
216    fn from(b: &[u8]) -> Self {
217        Self::Bytes(b.to_owned())
218    }
219}
220
221/// PHP argument typehints
222#[derive(Debug, Clone, PartialEq, Eq)]
223pub enum ArgumentTypeHint {
224    /// null typehint
225    Null,
226    /// bool typehint
227    Bool,
228    /// int typehint
229    Int,
230    /// float typehint
231    Float,
232    /// string typehint
233    String,
234    /// array typehint
235    Array,
236    /// object typehint
237    Object,
238    /// callable typehint
239    Callable,
240    /// iterable typehint
241    Iterable,
242    /// mixed typehint (php 8.0+)
243    Mixed,
244    /// ClassEntry typehint (class, interface)
245    ClassEntry(String),
246}
247
248/// PHP return typehints
249#[derive(Debug, Clone, PartialEq, Eq)]
250pub enum ReturnTypeHint {
251    /// null typehint
252    Null,
253    /// bool typehint
254    Bool,
255    /// int typehint
256    Int,
257    /// float typehint
258    Float,
259    /// string typehint
260    String,
261    /// array typehint
262    Array,
263    /// object typehint
264    Object,
265    /// callable typehint
266    Callable,
267    /// iterable typehint
268    Iterable,
269    /// mixed typehint (php 8.0+)
270    Mixed,
271    /// ClassEntry typehint (class, interface)
272    ClassEntry(String),
273    /// never typehint (8.1+)
274    Never,
275    /// void typehint
276    Void,
277}