ext_php_rs/
constant.rs

1//! Types and traits for registering constants in PHP.
2
3use cfg_if::cfg_if;
4use std::ffi::CString;
5use std::fmt::Debug;
6
7use super::flags::GlobalConstantFlags;
8use crate::error::Result;
9use crate::ffi::{
10    zend_register_bool_constant, zend_register_double_constant, zend_register_long_constant,
11    zend_register_string_constant,
12};
13
14/// Implemented on types which can be registered as a constant in PHP.
15pub trait IntoConst: Debug {
16    /// Registers a global module constant in PHP, with the value as the content
17    /// of self. This function _must_ be called in the module startup
18    /// function, which is called after the module is initialized. The
19    /// second parameter of the startup function will be the module number.
20    /// By default, the case-insensitive and persistent flags are set when
21    /// registering the constant.
22    ///
23    /// Returns a result containing nothing if the constant was successfully
24    /// registered.
25    ///
26    /// # Parameters
27    ///
28    /// * `name` - The name of the constant.
29    /// * `module_number` - The module number that we are registering the
30    ///   constant under.
31    ///
32    /// # Errors
33    ///
34    /// Returns an error if the constant could not be registered.
35    ///
36    /// # Examples
37    ///
38    /// ```no_run
39    /// use ext_php_rs::constant::IntoConst;
40    ///
41    /// pub extern "C" fn startup_function(_type: i32, module_number: i32) -> i32 {
42    ///     5.register_constant("MY_CONST_NAME", module_number); // MY_CONST_NAME == 5
43    ///     "Hello, world!".register_constant("STRING_CONSTANT", module_number); // STRING_CONSTANT == "Hello, world!"
44    ///     0
45    /// }
46    /// ```
47    fn register_constant(&self, name: &str, module_number: i32) -> Result<()> {
48        self.register_constant_flags(name, module_number, GlobalConstantFlags::Persistent)
49    }
50
51    /// Registers a global module constant in PHP, with the value as the content
52    /// of self. This function _must_ be called in the module startup
53    /// function, which is called after the module is initialized. The
54    /// second parameter of the startup function will be the module number.
55    /// This function allows you to pass any extra flags in if you require.
56    /// Note that the case-sensitive and persistent flags *are not* set when you
57    /// use this function, you must set these yourself.
58    ///
59    /// Returns a result containing nothing if the constant was successfully
60    /// registered.
61    ///
62    /// # Parameters
63    ///
64    /// * `name` - The name of the constant.
65    /// * `module_number` - The module number that we are registering the
66    ///   constant under.
67    /// * `flags` - Flags to register the constant with.
68    ///
69    /// # Errors
70    ///
71    /// Returns an error if the constant flags could not be registered.
72    ///
73    /// # Examples
74    ///
75    /// ```no_run
76    /// use ext_php_rs::{constant::IntoConst, flags::GlobalConstantFlags};
77    ///
78    /// pub extern "C" fn startup_function(_type: i32, module_number: i32) -> i32 {
79    ///     42.register_constant_flags("MY_CONST_NAME", module_number, GlobalConstantFlags::Persistent | GlobalConstantFlags::Deprecated);
80    ///     0
81    /// }
82    /// ```
83    fn register_constant_flags(
84        &self,
85        name: &str,
86        module_number: i32,
87        flags: GlobalConstantFlags,
88    ) -> Result<()>;
89}
90
91impl IntoConst for String {
92    fn register_constant_flags(
93        &self,
94        name: &str,
95        module_number: i32,
96        flags: GlobalConstantFlags,
97    ) -> Result<()> {
98        self.as_str()
99            .register_constant_flags(name, module_number, flags)
100    }
101}
102
103impl IntoConst for &str {
104    fn register_constant_flags(
105        &self,
106        name: &str,
107        module_number: i32,
108        flags: GlobalConstantFlags,
109    ) -> Result<()> {
110        unsafe {
111            cfg_if! {
112                if #[cfg(php85)] {
113                    let _ = zend_register_string_constant(
114                        CString::new(name)?.as_ptr(),
115                        name.len() as _,
116                        CString::new(*self)?.as_ptr(),
117                        flags.bits().try_into()?,
118                        module_number,
119                    );
120                } else {
121                    zend_register_string_constant(
122                        CString::new(name)?.as_ptr(),
123                        name.len() as _,
124                        CString::new(*self)?.as_ptr(),
125                        flags.bits().try_into()?,
126                        module_number,
127                    );
128                }
129            }
130        };
131        Ok(())
132    }
133}
134
135impl IntoConst for bool {
136    fn register_constant_flags(
137        &self,
138        name: &str,
139        module_number: i32,
140        flags: GlobalConstantFlags,
141    ) -> Result<()> {
142        unsafe {
143            cfg_if! {
144                if #[cfg(php85)] {
145                    let _ = zend_register_bool_constant(
146                        CString::new(name)?.as_ptr(),
147                        name.len() as _,
148                        *self,
149                        flags.bits().try_into()?,
150                        module_number,
151                    );
152                } else {
153                    zend_register_bool_constant(
154                        CString::new(name)?.as_ptr(),
155                        name.len() as _,
156                        *self,
157                        flags.bits().try_into()?,
158                        module_number,
159                    );
160                }
161            }
162        };
163        Ok(())
164    }
165}
166
167/// Implements the `IntoConst` trait for a given number type using a given
168/// function.
169macro_rules! into_const_num {
170    ($type: ty, $fn: expr) => {
171        impl IntoConst for $type {
172            fn register_constant_flags(
173                &self,
174                name: &str,
175                module_number: i32,
176                flags: GlobalConstantFlags,
177            ) -> Result<()> {
178                unsafe {
179                    cfg_if! {
180                        if #[cfg(php85)] {
181                            let _ = $fn(
182                                CString::new(name)?.as_ptr(),
183                                name.len() as _,
184                                (*self).into(),
185                                flags.bits().try_into()?,
186                                module_number,
187                            );
188                        } else {
189                            $fn(
190                                CString::new(name)?.as_ptr(),
191                                name.len() as _,
192                                (*self).into(),
193                                flags.bits().try_into()?,
194                                module_number,
195                            );
196                        }
197                    }
198                };
199                Ok(())
200            }
201        }
202    };
203}
204
205into_const_num!(i8, zend_register_long_constant);
206into_const_num!(i16, zend_register_long_constant);
207into_const_num!(i32, zend_register_long_constant);
208into_const_num!(i64, zend_register_long_constant);
209into_const_num!(f32, zend_register_double_constant);
210into_const_num!(f64, zend_register_double_constant);