Added argument overloading (#8)

* Added argument overloading

If a double is requested but a long is available, we can cast the
long into a double. This is required if the user gives an integer
into a double field.

As well as this, if a string is requested but a long or double is
available, we can cast both of these into a string.

* Check if zval is present before setting in arg

* Added optional argument example

* Updated documentation for ZendLong

* WIP: added null checks
This commit is contained in:
David 2021-03-10 21:09:18 +13:00 committed by GitHub
parent 9fbe186098
commit 0dd1a3f80f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 7 deletions

View File

@ -36,16 +36,23 @@ pub extern "C" fn get_module() -> *mut php_rs::php::module::ModuleEntry {
pub extern "C" fn skeleton_version(execute_data: *mut ExecutionData, _retval: *mut Zval) {
let mut x = Arg::new("x", DataType::Long);
let mut y = Arg::new("y", DataType::Double);
let mut z = Arg::new("z", DataType::Double);
let result = ArgParser::new(execute_data).arg(&mut x).arg(&mut y).parse();
let result = ArgParser::new(execute_data)
.arg(&mut x)
.arg(&mut y)
.not_required()
.arg(&mut z)
.parse();
if let Err(_) = result {
return;
}
println!(
"x: {}, y: {}",
"x: {}, y: {}, z: {}",
x.val::<ZendLong>().unwrap_or_default(),
y.val::<f64>().unwrap_or_default()
y.val::<f64>().unwrap_or_default(),
z.val::<f64>().unwrap_or_default()
);
}

View File

@ -1,8 +1,18 @@
use std::convert::{TryFrom, TryInto};
use std::{
borrow::Borrow,
convert::{TryFrom, TryInto},
};
use super::{enums::DataType, execution_data::ExecutionData, zval::Zval};
use crate::bindings::{zend_internal_arg_info, zend_wrong_parameters_count_error};
use crate::bindings::{
_zend_expected_type, _zend_expected_type_Z_EXPECTED_ARRAY, _zend_expected_type_Z_EXPECTED_BOOL,
_zend_expected_type_Z_EXPECTED_DOUBLE, _zend_expected_type_Z_EXPECTED_LONG,
_zend_expected_type_Z_EXPECTED_OBJECT, _zend_expected_type_Z_EXPECTED_RESOURCE,
_zend_expected_type_Z_EXPECTED_STRING, zend_internal_arg_info, zend_wrong_parameter_error,
zend_wrong_parameters_count_error, ZPP_ERROR_WRONG_CLASS_OR_NULL,
};
use crate::functions::c_str;
/// Represents an argument to a function.
pub struct Arg<'a> {
@ -73,6 +83,27 @@ impl<'a> Arg<'a> {
}
}
impl From<Arg<'_>> for _zend_expected_type {
fn from(arg: Arg) -> Self {
let err = match arg._type {
DataType::False | DataType::True => _zend_expected_type_Z_EXPECTED_BOOL,
DataType::Long => _zend_expected_type_Z_EXPECTED_LONG,
DataType::Double => _zend_expected_type_Z_EXPECTED_DOUBLE,
DataType::String => _zend_expected_type_Z_EXPECTED_STRING,
DataType::Array => _zend_expected_type_Z_EXPECTED_ARRAY,
DataType::Object => _zend_expected_type_Z_EXPECTED_OBJECT,
DataType::Resource => _zend_expected_type_Z_EXPECTED_RESOURCE,
_ => unreachable!(),
};
if arg.allow_null {
err + 1
} else {
err
}
}
}
/// Internal argument information used by Zend.
pub type ArgInfo = zend_internal_arg_info;
@ -142,7 +173,26 @@ impl<'a, 'b> ArgParser<'a, 'b> {
for (i, arg) in self.args.iter_mut().enumerate() {
let zval = unsafe { execute_data.zend_call_arg(i) };
arg.zval = Some(zval.unwrap());
if let Some(zval) = zval {
// if !arg.allow_null && zval.is_null() {
// unsafe {
// zend_wrong_parameter_error(
// ZPP_ERROR_WRONG_CLASS_OR_NULL as i32,
// i as u32,
// c_str(arg.name) as *mut i8,
// _zend_expected_type::from(**arg),
// &mut *zval,
// );
// }
// return Err(format!(
// "Argument at index {} was null but is non-nullable.",
// i
// ));
// }
arg.zval = Some(zval);
}
}
Ok(())

View File

@ -9,6 +9,7 @@ use super::types::ZendLong;
#[derive(Clone, Copy)]
pub enum DataType {
Undef = IS_UNDEF as isize,
Null = IS_NULL as isize,
False = IS_FALSE as isize,
True = IS_TRUE as isize,
@ -19,8 +20,8 @@ pub enum DataType {
Object = IS_OBJECT as isize,
Resource = IS_RESOURCE as isize,
Reference = IS_REFERENCE as isize,
ConstantExpression = IS_CONSTANT_AST as isize,
ConstantExpression = IS_CONSTANT_AST as isize,
Void = IS_VOID as isize,
}

View File

@ -86,4 +86,6 @@ impl ZendType {
}
/// Internal identifier used for a long.
/// The size depends on the system architecture. On 32-bit systems,
/// a ZendLong is 32-bits, while on a 64-bit system it is 64-bits.
pub type ZendLong = zend_long;

View File

@ -33,6 +33,8 @@ impl Zval {
pub fn double(&self) -> Option<f64> {
if self.is_double() {
Some(unsafe { self.value.dval })
} else if let Some(long) = self.long() {
Some(long as f64)
} else {
None
}
@ -53,6 +55,8 @@ impl Zval {
Some(_str.to_string())
}
} else if let Some(double) = self.double() {
Some(double.to_string())
} else {
None
}