diff --git a/examples/http-client/src/response.rs b/examples/http-client/src/response.rs index 0164a2cc..9e6650e1 100644 --- a/examples/http-client/src/response.rs +++ b/examples/http-client/src/response.rs @@ -31,7 +31,7 @@ pub fn make_response_class() -> StatefulClass> { .ok_or(HttpClientError::ResponseHadRead) .and_then(|response| response.bytes().map_err(Into::into)) })?; - Ok::<_, HttpClientError>((&body).to_vec()) + Ok::<_, HttpClientError>(body.to_vec()) }, vec![], ); diff --git a/phper/src/classes.rs b/phper/src/classes.rs index 35e09520..54f60738 100644 --- a/phper/src/classes.rs +++ b/phper/src/classes.rs @@ -57,23 +57,23 @@ pub struct StatefulClass { } impl StatefulClass<()> { - pub fn new(class_name: impl ToString) -> Self { + pub fn new(class_name: impl Into) -> Self { Self::new_with_state_constructor(class_name, || ()) } } impl StatefulClass { - pub fn new_with_default_state(class_name: impl ToString) -> Self { + pub fn new_with_default_state(class_name: impl Into) -> Self { Self::new_with_state_constructor(class_name, Default::default) } } impl StatefulClass { pub fn new_with_state_constructor( - class_name: impl ToString, state_constructor: impl Fn() -> T + Send + Sync + 'static, + class_name: impl Into, state_constructor: impl Fn() -> T + Send + Sync + 'static, ) -> Self { Self { - class_name: class_name.to_string(), + class_name: class_name.into(), state_constructor: Arc::new(state_constructor), method_entities: Vec::new(), property_entities: Vec::new(), @@ -86,7 +86,7 @@ impl StatefulClass { } pub fn add_method( - &mut self, name: impl ToString, vis: Visibility, handler: F, arguments: Vec, + &mut self, name: impl Into, vis: Visibility, handler: F, arguments: Vec, ) where F: Fn(&mut StatefulObj, &mut [ZVal]) -> R + Send + Sync + 'static, R: Into + 'static, @@ -101,7 +101,7 @@ impl StatefulClass { } pub fn add_static_method( - &mut self, name: impl ToString, vis: Visibility, handler: F, arguments: Vec, + &mut self, name: impl Into, vis: Visibility, handler: F, arguments: Vec, ) where F: Fn(&mut [ZVal]) -> R + Send + Sync + 'static, R: Into + 'static, @@ -121,14 +121,14 @@ impl StatefulClass { /// receive only scalar zval , otherwise will report fatal error: /// "Internal zvals cannot be refcounted". pub fn add_property( - &mut self, name: impl ToString, visibility: Visibility, value: impl Into, + &mut self, name: impl Into, visibility: Visibility, value: impl Into, ) { self.property_entities .push(PropertyEntity::new(name, visibility, value)); } - pub fn extends(&mut self, name: impl ToString) { - let name = name.to_string(); + pub fn extends(&mut self, name: impl Into) { + let name = name.into(); self.parent = Some(name); } } @@ -351,9 +351,9 @@ pub struct PropertyEntity { } impl PropertyEntity { - pub fn new(name: impl ToString, visibility: Visibility, value: impl Into) -> Self { + pub fn new(name: impl Into, visibility: Visibility, value: impl Into) -> Self { Self { - name: name.to_string(), + name: name.into(), visibility, value: value.into(), } diff --git a/phper/src/constants.rs b/phper/src/constants.rs index c22f0f7f..ed9c93bb 100644 --- a/phper/src/constants.rs +++ b/phper/src/constants.rs @@ -8,4 +8,64 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -// TODO Add constant. +//! Apis relate to [crate::sys::zend_constant]. + +use std::ffi::{c_char, c_int}; + +use crate::{modules::ModuleContext, sys::*, types::Scalar}; + +pub(crate) struct Constant { + name: String, + value: Scalar, +} + +impl Constant { + pub fn new(name: impl Into, value: impl Into) -> Self { + Self { + name: name.into(), + value: value.into(), + } + } + + pub(crate) fn register(&self, module_context: &ModuleContext) { + let name_ptr = self.name.as_ptr() as *const c_char; + let name_len = self.name.len() as size_t; + let flags = (CONST_PERSISTENT | CONST_CS) as c_int; + let num = module_context.module_number; + + unsafe { + match &self.value { + Scalar::Null => zend_register_null_constant(name_ptr, name_len, flags, num), + Scalar::Bool(b) => { + zend_register_bool_constant(name_ptr, name_len, *b as zend_bool, flags, num) + } + Scalar::I64(i) => { + zend_register_long_constant(name_ptr, name_len, *i as zend_long, flags, num) + } + Scalar::F64(f) => zend_register_double_constant(name_ptr, name_len, *f, flags, num), + Scalar::String(s) => { + let s_ptr = s.as_ptr() as *mut u8; + zend_register_stringl_constant( + name_ptr, + name_len, + s_ptr.cast(), + s.len() as size_t, + flags, + num, + ) + } + Scalar::Bytes(s) => { + let s_ptr = s.as_ptr() as *mut u8; + zend_register_stringl_constant( + name_ptr, + name_len, + s_ptr.cast(), + s.len() as size_t, + flags, + num, + ) + } + } + } + } +} diff --git a/phper/src/errors.rs b/phper/src/errors.rs index 7ac41165..125102c7 100644 --- a/phper/src/errors.rs +++ b/phper/src/errors.rs @@ -106,9 +106,9 @@ pub enum Error { } impl Error { - /// An essy way to cause an [anyhow::Error]. - pub fn other(message: impl ToString) -> Self { - let message = message.to_string(); + /// An easy way to cause an [anyhow::Error]. + pub fn other(message: impl Into) -> Self { + let message = message.into(); Other(anyhow!(message)) } } diff --git a/phper/src/functions.rs b/phper/src/functions.rs index 1cfedff0..6b4790b4 100644 --- a/phper/src/functions.rs +++ b/phper/src/functions.rs @@ -117,7 +117,7 @@ pub struct FunctionEntity { impl FunctionEntity { pub(crate) fn new( - name: impl ToString, handler: Box, arguments: Vec, + name: impl Into, handler: Box, arguments: Vec, visibility: Option, r#static: Option, ) -> Self { let name = ensure_end_with_zero(name); @@ -178,7 +178,7 @@ pub struct Argument { } impl Argument { - pub fn by_val(name: impl ToString) -> Self { + pub fn by_val(name: impl Into) -> Self { let name = ensure_end_with_zero(name); Self { name, @@ -187,7 +187,7 @@ impl Argument { } } - pub fn by_ref(name: impl ToString) -> Self { + pub fn by_ref(name: impl Into) -> Self { let name = ensure_end_with_zero(name); Self { name, @@ -196,7 +196,7 @@ impl Argument { } } - pub fn by_val_optional(name: impl ToString) -> Self { + pub fn by_val_optional(name: impl Into) -> Self { let name = ensure_end_with_zero(name); Self { name, @@ -205,7 +205,7 @@ impl Argument { } } - pub fn by_ref_optional(name: impl ToString) -> Self { + pub fn by_ref_optional(name: impl Into) -> Self { let name = ensure_end_with_zero(name); Self { name, diff --git a/phper/src/ini.rs b/phper/src/ini.rs index 224eaf8c..0ffd56cf 100644 --- a/phper/src/ini.rs +++ b/phper/src/ini.rs @@ -34,17 +34,16 @@ thread_local! { pub struct Ini; impl Ini { - pub fn add(name: impl ToString, default_value: impl TransformIniValue, policy: Policy) { + pub fn add(name: impl Into, default_value: impl TransformIniValue, policy: Policy) { assert!( !REGISTERED.load(Ordering::SeqCst), "shouldn't add ini after registered" ); + let name = name.into(); + INI_ENTITIES.with(|ini_entities| { - ini_entities.insert( - name.to_string(), - IniEntity::new(name, default_value, policy), - ); + ini_entities.insert(name.clone(), IniEntity::new(name, default_value, policy)); }); } @@ -194,11 +193,11 @@ pub(crate) struct IniEntity { impl IniEntity { pub(crate) fn new( - name: impl ToString, default_value: T, policy: Policy, + name: impl Into, default_value: T, policy: Policy, ) -> Self { assert!(::arg2_size() <= size_of::()); Self { - name: name.to_string(), + name: name.into(), value: 0, value_type_id: ::arg2_type(), default_value: default_value.to_text(), diff --git a/phper/src/lib.rs b/phper/src/lib.rs index aa00f7f5..990b4728 100644 --- a/phper/src/lib.rs +++ b/phper/src/lib.rs @@ -17,7 +17,7 @@ mod macros; pub mod arrays; pub mod classes; pub mod cmd; -pub mod constants; +pub(crate) mod constants; pub mod errors; pub mod exceptions; pub mod functions; diff --git a/phper/src/modules.rs b/phper/src/modules.rs index 5b7b168a..140d4d27 100644 --- a/phper/src/modules.rs +++ b/phper/src/modules.rs @@ -13,9 +13,11 @@ use crate::{ c_str_ptr, classes::{ClassEntity, Classifiable}, + constants::Constant, functions::{Argument, Function, FunctionEntity}, ini::Ini, sys::*, + types::Scalar, utils::ensure_end_with_zero, values::ZVal, }; @@ -42,6 +44,9 @@ unsafe extern "C" fn module_startup(r#type: c_int, module_number: c_int) -> c_in let args = ModuleContext::new(r#type, module_number); write_global_module(|module| { args.register_ini_entries(Ini::entries()); + for constant in &module.constants { + constant.register(&args); + } for class_entity in &mut module.class_entities { class_entity.init(); class_entity.declare_properties(); @@ -106,10 +111,13 @@ pub struct Module { request_shutdown: Option bool + Send + Sync>>, function_entities: Vec, class_entities: Vec, + constants: Vec, } impl Module { - pub fn new(name: impl ToString, version: impl ToString, author: impl ToString) -> Self { + pub fn new( + name: impl Into, version: impl Into, author: impl Into, + ) -> Self { Self { name: ensure_end_with_zero(name), version: ensure_end_with_zero(version), @@ -120,6 +128,7 @@ impl Module { request_shutdown: None, function_entities: vec![], class_entities: Default::default(), + constants: Default::default(), } } @@ -147,8 +156,9 @@ impl Module { self.request_shutdown = Some(Box::new(func)); } - pub fn add_function(&mut self, name: impl ToString, handler: F, arguments: Vec) - where + pub fn add_function( + &mut self, name: impl Into, handler: F, arguments: Vec, + ) where F: Fn(&mut [ZVal]) -> R + Send + Sync + 'static, R: Into + 'static, { @@ -165,6 +175,10 @@ impl Module { self.class_entities.push(unsafe { ClassEntity::new(class) }); } + pub fn add_constant(&mut self, name: impl Into, value: impl Into) { + self.constants.push(Constant::new(name, value)); + } + /// Leak memory to generate `zend_module_entry` pointer. #[doc(hidden)] pub unsafe fn module_entry(self) -> *const zend_module_entry { @@ -223,8 +237,8 @@ impl Module { pub struct ModuleContext { #[allow(dead_code)] - r#type: c_int, - module_number: c_int, + pub(crate) r#type: c_int, + pub(crate) module_number: c_int, } impl ModuleContext { diff --git a/phper/src/output.rs b/phper/src/output.rs index 2ff173b3..fa964d86 100644 --- a/phper/src/output.rs +++ b/phper/src/output.rs @@ -22,7 +22,7 @@ pub enum LogLevel { Deprecated = E_DEPRECATED, } -pub fn log(level: LogLevel, message: impl ToString) { +pub fn log(level: LogLevel, message: impl Into) { let message = ensure_end_with_zero(message); unsafe { php_error_docref1( @@ -34,7 +34,7 @@ pub fn log(level: LogLevel, message: impl ToString) { } } -pub fn echo(message: impl ToString) { +pub fn echo(message: impl Into) { let message = ensure_end_with_zero(message); unsafe { zend_write.expect("function zend_write can't be null")( diff --git a/phper/src/utils.rs b/phper/src/utils.rs index a0edaec1..b77a5c95 100644 --- a/phper/src/utils.rs +++ b/phper/src/utils.rs @@ -10,8 +10,8 @@ //! Internal useful utils. -pub(crate) fn ensure_end_with_zero(s: impl ToString) -> String { - let mut s = s.to_string(); +pub(crate) fn ensure_end_with_zero(s: impl Into) -> String { + let mut s = s.into(); if !s.ends_with('\0') { s.push('\0'); } diff --git a/tests/integration/src/constant.rs b/tests/integration/src/constant.rs new file mode 100644 index 00000000..fdf40e05 --- /dev/null +++ b/tests/integration/src/constant.rs @@ -0,0 +1,21 @@ +// Copyright (c) 2022 PHPER Framework Team +// PHPER is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use phper::modules::Module; + +pub fn integrate(module: &mut Module) { + module.add_constant("INTEGRATE_CONST_NULL", ()); + module.add_constant("INTEGRATE_CONST_TRUE", true); + module.add_constant("INTEGRATE_CONST_FALSE", false); + module.add_constant("INTEGRATE_CONST_LONG", 100i64); + module.add_constant("INTEGRATE_CONST_DOUBLE", 200.); + module.add_constant("INTEGRATE_CONST_STRING", "something"); + module.add_constant("INTEGRATE_CONST_BYTES", "something".as_bytes().to_owned()); +} diff --git a/tests/integration/src/lib.rs b/tests/integration/src/lib.rs index f6a6bf00..45611595 100644 --- a/tests/integration/src/lib.rs +++ b/tests/integration/src/lib.rs @@ -13,6 +13,7 @@ mod arguments; mod arrays; mod classes; +mod constant; mod functions; mod objects; mod strings; @@ -35,6 +36,7 @@ pub fn get_module() -> Module { objects::integrate(&mut module); strings::integrate(&mut module); values::integrate(&mut module); + constant::integrate(&mut module); module } diff --git a/tests/integration/tests/integration.rs b/tests/integration/tests/integration.rs index 4623e4e2..2572d3ec 100644 --- a/tests/integration/tests/integration.rs +++ b/tests/integration/tests/integration.rs @@ -29,6 +29,7 @@ fn test_cli() { &tests_php_dir.join("objects.php"), &tests_php_dir.join("strings.php"), &tests_php_dir.join("values.php"), + &tests_php_dir.join("constant.php"), ], ); } @@ -48,4 +49,5 @@ fn test_fpm() { test_fpm_request("GET", &tests_php_dir, "/objects.php", None, None); test_fpm_request("GET", &tests_php_dir, "/strings.php", None, None); test_fpm_request("GET", &tests_php_dir, "/values.php", None, None); + test_fpm_request("GET", &tests_php_dir, "/constant.php", None, None); } diff --git a/tests/integration/tests/php/constant.php b/tests/integration/tests/php/constant.php new file mode 100644 index 00000000..56a46219 --- /dev/null +++ b/tests/integration/tests/php/constant.php @@ -0,0 +1,22 @@ +