mirror of
https://github.com/danog/ext-php-rs.git
synced 2024-11-27 04:24:54 +01:00
Returning from functions (#9)
* Added ability to set value of zval This allows the return value to now be set. See the example in `example/skel/src.lib`. * Added PHP internals book to resources * Pass self as pointer to keep consistency
This commit is contained in:
parent
0dd1a3f80f
commit
8f108a61c3
@ -14,6 +14,10 @@ See the [example project](example/skel). There is inline documentation. Starting
|
||||
|
||||
Contributions are very much welcome. I am a novice Rust developer and any suggestions are wanted and welcome. Feel free to file issues and PRs through Github.
|
||||
|
||||
## Resources
|
||||
|
||||
- [PHP Internals Book](https://www.phpinternalsbook.com/)
|
||||
|
||||
## License
|
||||
|
||||
```
|
||||
|
@ -7,7 +7,7 @@ use php_rs::{
|
||||
function::FunctionBuilder,
|
||||
module::{ModuleBuilder, ModuleEntry},
|
||||
types::ZendLong,
|
||||
zval::Zval,
|
||||
zval::{SetZval, Zval},
|
||||
},
|
||||
};
|
||||
|
||||
@ -49,10 +49,12 @@ pub extern "C" fn skeleton_version(execute_data: *mut ExecutionData, _retval: *m
|
||||
return;
|
||||
}
|
||||
|
||||
println!(
|
||||
let result = format!(
|
||||
"x: {}, y: {}, z: {}",
|
||||
x.val::<ZendLong>().unwrap_or_default(),
|
||||
y.val::<f64>().unwrap_or_default(),
|
||||
z.val::<f64>().unwrap_or_default()
|
||||
);
|
||||
|
||||
_retval.set_string(result).unwrap();
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
use std::{ffi::c_void, ptr};
|
||||
|
||||
use crate::bindings::{
|
||||
zend_long, zend_type, IS_MIXED, MAY_BE_ANY, MAY_BE_BOOL, _IS_BOOL, _ZEND_IS_VARIADIC_BIT,
|
||||
_ZEND_SEND_MODE_SHIFT, _ZEND_TYPE_NULLABLE_BIT,
|
||||
use crate::{
|
||||
bindings::{
|
||||
zend_long, zend_string, zend_strpprintf, zend_type, GC_FLAGS_MASK, GC_FLAGS_SHIFT,
|
||||
GC_INFO_SHIFT, IS_MIXED, IS_STR_INTERNED, MAY_BE_ANY, MAY_BE_BOOL, _IS_BOOL,
|
||||
_ZEND_IS_VARIADIC_BIT, _ZEND_SEND_MODE_SHIFT, _ZEND_TYPE_NULLABLE_BIT,
|
||||
},
|
||||
functions::c_str,
|
||||
};
|
||||
|
||||
use super::enums::DataType;
|
||||
@ -89,3 +93,35 @@ impl ZendType {
|
||||
/// 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;
|
||||
|
||||
/// String type used in the Zend internals.
|
||||
/// The actual size of the 'string' differs, as the
|
||||
/// end of this struct is only 1 char long, but the length
|
||||
/// inside the struct defines how many characters are in the string.
|
||||
pub type ZendString = zend_string;
|
||||
|
||||
impl ZendString {
|
||||
/// Creates a new Zend string.
|
||||
///
|
||||
/// Note that this returns a raw pointer, and will not be freed by
|
||||
/// Rust.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `str_` - The string to create a Zend string from.
|
||||
pub fn new<S>(str_: S) -> *mut Self
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
let str_ = str_.as_ref();
|
||||
unsafe { zend_strpprintf(str_.len() as u64, c_str(str_)) }
|
||||
}
|
||||
|
||||
/// Translation of the `ZSTR_IS_INTERNED` macro.
|
||||
/// zend_string.h:76
|
||||
pub(crate) unsafe fn is_interned(&self) -> bool {
|
||||
(((self.gc.u.type_info >> GC_INFO_SHIFT) & (GC_FLAGS_MASK >> GC_FLAGS_SHIFT))
|
||||
& IS_STR_INTERNED)
|
||||
!= 0
|
||||
}
|
||||
}
|
||||
|
186
src/php/zval.rs
186
src/php/zval.rs
@ -1,9 +1,12 @@
|
||||
use core::slice;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::bindings::{zend_object, zend_resource, zval};
|
||||
use crate::bindings::{zend_object, zend_resource, zval, IS_INTERNED_STRING_EX, IS_STRING_EX};
|
||||
|
||||
use super::{enums::DataType, types::ZendLong};
|
||||
use super::{
|
||||
enums::DataType,
|
||||
types::{ZendLong, ZendString},
|
||||
};
|
||||
|
||||
/// Zend value. Represents most data types that are in the Zend engine.
|
||||
pub type Zval = zval;
|
||||
@ -149,6 +152,185 @@ impl Zval {
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to set the value of the zval.
|
||||
///
|
||||
/// This needs to be a trait to be implemented on a pointer that
|
||||
/// points to a zval.
|
||||
pub trait SetZval {
|
||||
/// Sets the value of the zval as a string.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `val` - The value to set the zval as.
|
||||
fn set_string<S>(&self, val: S) -> Result<(), String>
|
||||
where
|
||||
S: AsRef<str>;
|
||||
|
||||
/// Sets the value of the zval as a long.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `val` - The value to set the zval as.
|
||||
fn set_long(&self, val: ZendLong) -> Result<(), String>;
|
||||
|
||||
/// Sets the value of the zval as a double.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `val` - The value to set the zval as.
|
||||
fn set_double(&self, val: f64) -> Result<(), String>;
|
||||
|
||||
/// Sets the value of the zval as a boolean.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `val` - The value to set the zval as.
|
||||
fn set_bool(&self, val: bool) -> Result<(), String>;
|
||||
|
||||
/// Sets the value of the zval as null.
|
||||
/// This is the default of a zval.
|
||||
fn set_null(&self) -> Result<(), String>;
|
||||
|
||||
/// Sets the value of the zval as a resource.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `val` - The value to set the zval as.
|
||||
fn set_resource(&self, val: *mut zend_resource) -> Result<(), String>;
|
||||
|
||||
/// Sets the value of the zval as an object.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// * `val` - The value to set the zval as.
|
||||
/// * `copy` - Whether to copy the object or pass as a reference.
|
||||
fn set_object(&self, val: *mut zend_object, copy: bool) -> Result<(), String>;
|
||||
}
|
||||
|
||||
impl SetZval for *mut Zval {
|
||||
fn set_string<S>(&self, val: S) -> Result<(), String>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
{
|
||||
let _self = match unsafe { self.as_mut() } {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Err(String::from(
|
||||
"Could not retrieve mutable reference of zend value.",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let zend_str = ZendString::new(val);
|
||||
_self.value.str = zend_str;
|
||||
_self.u1.type_info = if unsafe { zend_str.as_ref().unwrap().is_interned() } {
|
||||
IS_INTERNED_STRING_EX
|
||||
} else {
|
||||
IS_STRING_EX
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_long(&self, val: ZendLong) -> Result<(), String> {
|
||||
let _self = match unsafe { self.as_mut() } {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Err(String::from(
|
||||
"Could not retrieve mutable reference of zend value.",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
_self.value.lval = val;
|
||||
_self.u1.type_info = DataType::Long as u32;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_double(&self, val: f64) -> Result<(), String> {
|
||||
let _self = match unsafe { self.as_mut() } {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Err(String::from(
|
||||
"Could not retrieve mutable reference of zend value.",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
_self.value.dval = val;
|
||||
_self.u1.type_info = DataType::Double as u32;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_bool(&self, val: bool) -> Result<(), String> {
|
||||
let _self = match unsafe { self.as_mut() } {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Err(String::from(
|
||||
"Could not retrieve mutable reference of zend value.",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
_self.u1.type_info = if val {
|
||||
DataType::True as u32
|
||||
} else {
|
||||
DataType::False as u32
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_null(&self) -> Result<(), String> {
|
||||
let _self = match unsafe { self.as_mut() } {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Err(String::from(
|
||||
"Could not retrieve mutable reference of zend value.",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
_self.u1.type_info = DataType::Null as u32;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_resource(&self, val: *mut zend_resource) -> Result<(), String> {
|
||||
let _self = match unsafe { self.as_mut() } {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Err(String::from(
|
||||
"Could not retrieve mutable reference of zend value.",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
_self.u1.type_info = DataType::Resource as u32;
|
||||
_self.value.res = val;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_object(&self, val: *mut zend_object, _copy: bool) -> Result<(), String> {
|
||||
let _self = match unsafe { self.as_mut() } {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return Err(String::from(
|
||||
"Could not retrieve mutable reference of zend value.",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
_self.u1.type_info = DataType::Object as u32;
|
||||
_self.value.obj = val;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&Zval> for ZendLong {
|
||||
type Error = ();
|
||||
fn try_from(value: &Zval) -> Result<Self, Self::Error> {
|
||||
|
Loading…
Reference in New Issue
Block a user