mirror of
https://github.com/icewind1991/ivory.git
synced 2026-06-03 18:54:07 +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::*;
|
||||||
use ivory::externs::printf;
|
use ivory::externs::printf;
|
||||||
use ivory::zend::{ExecuteData, ZVal, PhpVal};
|
use ivory::zend::{ExecuteData, PhpVal, ZVal};
|
||||||
|
|
||||||
#[ivory_export]
|
#[ivory_export]
|
||||||
fn hello_other(_other: String) {
|
fn hello_other(other: String) {
|
||||||
printf(format!("Hello ", ));
|
printf(format!("Hello {}", other));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ivory_export]
|
#[ivory_export]
|
||||||
|
|
@ -14,24 +14,9 @@ fn hello_world() {
|
||||||
printf("Hello world, Rust2!");
|
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!({
|
ivory_module!({
|
||||||
name: "demo",
|
name: "demo",
|
||||||
version: "0.0.1",
|
version: "0.0.1",
|
||||||
functions: &[hello_world, hello_other, dump],
|
functions: &[hello_world, hello_other],
|
||||||
info: &[("demo extension", "enabled")]
|
info: &[("demo extension", "enabled")]
|
||||||
});
|
});
|
||||||
|
|
@ -45,15 +45,41 @@ fn export_fn(item: ItemFn) -> TokenStream {
|
||||||
unimplemented!("generics are not supported for exported functions");
|
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(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))
|
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! {
|
quote! {
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn #name(data: *const ::ivory::zend::ExecuteData, retval: *mut ::ivory::zend::ZVal) {
|
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;
|
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 {
|
match arg {
|
||||||
FnArg::Captured(cap) => {
|
FnArg::Captured(cap) => {
|
||||||
let arg_type = cap.ty;
|
let arg_type = cap.ty;
|
||||||
match cap.pat {
|
match cap.pat {
|
||||||
Pat::Ident(ident_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!(),
|
Pat::Ref(ref_pat) => unimplemented!(),
|
||||||
_ => panic!()
|
_ => panic!()
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ impl Iterator for IntoArgIterator {
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
if self.item < self.count {
|
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;
|
self.item += 1;
|
||||||
Some(val)
|
Some(val)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -101,7 +101,7 @@ impl ZVal {
|
||||||
} else {
|
} else {
|
||||||
ArrayKey::String(zend_str_as_string(&*elem.key))
|
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 {
|
match val {
|
||||||
PhpVal::Undef => {}
|
PhpVal::Undef => {}
|
||||||
_ => result.push((key, val))
|
_ => result.push((key, val))
|
||||||
|
|
@ -109,6 +109,20 @@ impl ZVal {
|
||||||
}
|
}
|
||||||
result
|
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)]
|
#[derive(Debug)]
|
||||||
|
|
@ -162,25 +176,38 @@ impl Default for PhpVal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<*const ZVal> for PhpVal {
|
impl From<PhpVal> for Option<i64> {
|
||||||
fn from(val: *const ZVal) -> Self {
|
fn from(val: PhpVal) -> Self {
|
||||||
let val = unsafe { &*val };
|
match val {
|
||||||
val.into()
|
PhpVal::Long(val) => Some(val),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ZVal> for PhpVal {
|
impl From<PhpVal> for Option<f64> {
|
||||||
fn from(val: &ZVal) -> Self {
|
fn from(val: PhpVal) -> Self {
|
||||||
match val.get_type() {
|
match val {
|
||||||
ZValType::Undef => PhpVal::Undef,
|
PhpVal::Double(val) => Some(val),
|
||||||
ZValType::Null => PhpVal::Null,
|
_ => None
|
||||||
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() }),
|
impl From<PhpVal> for Option<bool> {
|
||||||
ZValType::Array => PhpVal::Array(unsafe { val.as_array() }),
|
fn from(val: PhpVal) -> Self {
|
||||||
_ => PhpVal::Undef
|
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