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);