mirror of
https://github.com/icewind1991/ivory.git
synced 2026-06-03 10:44:09 +02:00
argument unpacking
This commit is contained in:
parent
e4874998f9
commit
d1f2500b31
3 changed files with 79 additions and 41 deletions
|
|
@ -2,11 +2,11 @@ use std::intrinsics::transmute;
|
|||
|
||||
use ivory::*;
|
||||
use ivory::externs::printf;
|
||||
use ivory::zend::{ExecuteData, ZVal, PhpVal};
|
||||
use ivory::zend::{ExecuteData, PhpVal, ZVal};
|
||||
|
||||
#[ivory_export]
|
||||
fn hello_other(_other: String) {
|
||||
printf(format!("Hello ", ));
|
||||
fn hello_other(other: String) {
|
||||
printf(format!("Hello {}", other));
|
||||
}
|
||||
|
||||
#[ivory_export]
|
||||
|
|
@ -14,24 +14,9 @@ fn hello_world() {
|
|||
printf("Hello world, Rust2!");
|
||||
}
|
||||
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn dump(data: *const ExecuteData, retval: *mut ZVal) {
|
||||
let data: &ExecuteData = unsafe { data.as_ref() }.unwrap();
|
||||
for arg in data.args() {
|
||||
printf(format!("{:?}\n", arg));
|
||||
}
|
||||
}
|
||||
|
||||
const FUNCTION_META_DUMP: ::ivory::zend::FunctionMeta = ::ivory::zend::FunctionMeta {
|
||||
name: { concat!("dump", "\0").as_ptr() as *const ::libc::c_char },
|
||||
func: dump,
|
||||
args: &[],
|
||||
};
|
||||
|
||||
ivory_module!({
|
||||
name: "demo",
|
||||
version: "0.0.1",
|
||||
functions: &[hello_world, hello_other, dump],
|
||||
functions: &[hello_world, hello_other],
|
||||
info: &[("demo extension", "enabled")]
|
||||
});
|
||||
|
|
@ -45,15 +45,41 @@ fn export_fn(item: ItemFn) -> TokenStream {
|
|||
unimplemented!("generics are not supported for exported functions");
|
||||
}
|
||||
|
||||
let arg_defs = decl.inputs.into_iter()
|
||||
let args: Vec<(String, Type, bool, Span)> = decl.inputs.into_iter()
|
||||
.map(get_arg_info)
|
||||
.map(|(name, _type, is_ref)| {
|
||||
.collect();
|
||||
let arg_count = args.len() as u32;
|
||||
|
||||
let arg_defs = args.iter().map(|(name, _type, is_ref, _)| {
|
||||
quote!(::ivory::zend::ArgInfo::new(::ivory::c_str!(#name), false, false, #is_ref))
|
||||
});
|
||||
|
||||
let arg_cast = args.iter().enumerate().map(|(index, (name, ty, _is_ref, span))| {
|
||||
let arg_ident = Ident::new(name, span.clone());
|
||||
quote!(
|
||||
let #arg_ident: #ty = {
|
||||
let opt: Option<#ty> = args.remove(0).into();
|
||||
match opt {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
::ivory::externs::printf("invalid argument type");
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
)
|
||||
});
|
||||
|
||||
quote! {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn #name(data: *const ::ivory::zend::ExecuteData, retval: *mut ::ivory::zend::ZVal) {
|
||||
let data: &::ivory::zend::ExecuteData = unsafe { data.as_ref() }.unwrap();
|
||||
if data.num_args() != #arg_count {
|
||||
::ivory::externs::printf("unexpected number of arguments");
|
||||
return;
|
||||
}
|
||||
let mut args: Vec<PhpVal> = data.args().collect();
|
||||
#(#arg_cast);*
|
||||
let result = #body;
|
||||
}
|
||||
|
||||
|
|
@ -65,13 +91,13 @@ fn export_fn(item: ItemFn) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_arg_info(arg: FnArg) -> (String, Type, bool) {
|
||||
fn get_arg_info(arg: FnArg) -> (String, Type, bool, Span) {
|
||||
match arg {
|
||||
FnArg::Captured(cap) => {
|
||||
let arg_type = cap.ty;
|
||||
match cap.pat {
|
||||
Pat::Ident(ident_pat) => {
|
||||
(ident_pat.ident.to_string(), arg_type, ident_pat.by_ref.is_some())
|
||||
(ident_pat.ident.to_string(), arg_type, ident_pat.by_ref.is_some(), ident_pat.span())
|
||||
},
|
||||
Pat::Ref(ref_pat) => unimplemented!(),
|
||||
_ => panic!()
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ impl Iterator for IntoArgIterator {
|
|||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.item < self.count {
|
||||
let val = unsafe { (self.base.add(self.item as usize)).into() };
|
||||
let val = unsafe { (*self.base.add(self.item as usize)).as_php_val() };
|
||||
self.item += 1;
|
||||
Some(val)
|
||||
} else {
|
||||
|
|
@ -101,7 +101,7 @@ impl ZVal {
|
|||
} else {
|
||||
ArrayKey::String(zend_str_as_string(&*elem.key))
|
||||
};
|
||||
let val: PhpVal = (&ZVal(elem.val)).into();
|
||||
let val: PhpVal = ZVal(elem.val).as_php_val();
|
||||
match val {
|
||||
PhpVal::Undef => {}
|
||||
_ => result.push((key, val))
|
||||
|
|
@ -109,6 +109,20 @@ impl ZVal {
|
|||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn as_php_val(&self) -> PhpVal {
|
||||
match self.get_type() {
|
||||
ZValType::Undef => PhpVal::Undef,
|
||||
ZValType::Null => PhpVal::Null,
|
||||
ZValType::False => PhpVal::Bool(false),
|
||||
ZValType::True => PhpVal::Bool(true),
|
||||
ZValType::Long => PhpVal::Long(unsafe { self.as_i64() }),
|
||||
ZValType::Double => PhpVal::Double(unsafe { self.as_f64() }),
|
||||
ZValType::String => PhpVal::String(unsafe { self.as_str() }),
|
||||
ZValType::Array => PhpVal::Array(unsafe { self.as_array() }),
|
||||
_ => PhpVal::Undef
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -162,25 +176,38 @@ impl Default for PhpVal {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<*const ZVal> for PhpVal {
|
||||
fn from(val: *const ZVal) -> Self {
|
||||
let val = unsafe { &*val };
|
||||
val.into()
|
||||
impl From<PhpVal> for Option<i64> {
|
||||
fn from(val: PhpVal) -> Self {
|
||||
match val {
|
||||
PhpVal::Long(val) => Some(val),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ZVal> for PhpVal {
|
||||
fn from(val: &ZVal) -> Self {
|
||||
match val.get_type() {
|
||||
ZValType::Undef => PhpVal::Undef,
|
||||
ZValType::Null => PhpVal::Null,
|
||||
ZValType::False => PhpVal::Bool(false),
|
||||
ZValType::True => PhpVal::Bool(true),
|
||||
ZValType::Long => PhpVal::Long(unsafe { val.as_i64() }),
|
||||
ZValType::Double => PhpVal::Double(unsafe { val.as_f64() }),
|
||||
ZValType::String => PhpVal::String(unsafe { val.as_str() }),
|
||||
ZValType::Array => PhpVal::Array(unsafe { val.as_array() }),
|
||||
_ => PhpVal::Undef
|
||||
impl From<PhpVal> for Option<f64> {
|
||||
fn from(val: PhpVal) -> Self {
|
||||
match val {
|
||||
PhpVal::Double(val) => Some(val),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PhpVal> for Option<bool> {
|
||||
fn from(val: PhpVal) -> Self {
|
||||
match val {
|
||||
PhpVal::Bool(val) => Some(val),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PhpVal> for Option<String> {
|
||||
fn from(val: PhpVal) -> Self {
|
||||
match val {
|
||||
PhpVal::String(val) => Some(val),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue