mirror of
https://github.com/icewind1991/ivory.git
synced 2026-06-03 18:54:07 +02:00
make imported functions work
This commit is contained in:
parent
34fb187384
commit
56d69458a8
6 changed files with 102 additions and 71 deletions
|
|
@ -1,14 +1,16 @@
|
|||
use lazy_static::lazy_static;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::FunctionDefinition;
|
||||
|
||||
lazy_static! {
|
||||
static ref FUNCTION_NAMES: Mutex<Vec<String>> = Mutex::new(Vec::new());
|
||||
static ref FUNCTION_NAMES: Mutex<Vec<FunctionDefinition>> = Mutex::new(Vec::new());
|
||||
}
|
||||
|
||||
pub fn cache_function(name: String) {
|
||||
FUNCTION_NAMES.lock().unwrap().push(name);
|
||||
pub(crate) fn cache_function(func: FunctionDefinition) {
|
||||
FUNCTION_NAMES.lock().unwrap().push(func);
|
||||
}
|
||||
|
||||
pub fn get_functions() -> Vec<String> {
|
||||
pub(crate) fn get_functions() -> Vec<FunctionDefinition> {
|
||||
FUNCTION_NAMES.lock().unwrap().clone()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,27 +29,39 @@ pub fn ivory_export(
|
|||
output
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ArgumentDefinition {
|
||||
name: String,
|
||||
is_ref: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct FunctionDefinition {
|
||||
name: String,
|
||||
args: Vec<ArgumentDefinition>,
|
||||
}
|
||||
|
||||
fn export_fn(item: ItemFn) -> TokenStream {
|
||||
let span = item.span();
|
||||
let name = item.ident;
|
||||
let name_str = name.to_string();
|
||||
cache::cache_function(name_str.clone());
|
||||
let meta_name = Ident::new(&format!("FUNCTION_META_{}", name_str.to_uppercase()), span);
|
||||
let body = item.block;
|
||||
let decl = item.decl;
|
||||
if decl.generics.gt_token.is_some() {
|
||||
unimplemented!("generics are not supported for exported functions");
|
||||
}
|
||||
|
||||
let args: Vec<(String, Type, bool, Span)> = decl.inputs.into_iter().map(get_arg_info).collect();
|
||||
let args: Vec<(ArgumentDefinition, Type)> = decl.inputs.into_iter().map(get_arg_info).collect();
|
||||
let arg_defs: Vec<ArgumentDefinition> = args.clone().into_iter().map(|(def, _)| def).collect();
|
||||
let func_def = FunctionDefinition {
|
||||
name: name_str.clone(),
|
||||
args: arg_defs,
|
||||
};
|
||||
cache::cache_function(func_def);
|
||||
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());
|
||||
let arg_cast = args.iter().enumerate().map(|(_index, (arg, ty))| {
|
||||
let arg_ident = Ident::new(&arg.name, span);
|
||||
quote!(
|
||||
let #arg_ident: #ty = {
|
||||
let result: Result<#ty, ::ivory::CastError> = args.next().unwrap().into();
|
||||
|
|
@ -78,25 +90,20 @@ fn export_fn(item: ItemFn) -> TokenStream {
|
|||
#(#arg_cast);*
|
||||
let result = #body;
|
||||
}
|
||||
|
||||
const #meta_name: ::ivory::zend::FunctionMeta = ::ivory::zend::FunctionMeta{
|
||||
name: {concat!(#name_str, "\0").as_ptr() as *const ::std::os::raw::c_char},
|
||||
func: #name,
|
||||
args: &[ #(#arg_defs),*]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn get_arg_info(arg: FnArg) -> (String, Type, bool, Span) {
|
||||
fn get_arg_info(arg: FnArg) -> (ArgumentDefinition, Type) {
|
||||
match arg {
|
||||
FnArg::Captured(cap) => {
|
||||
let arg_type = cap.ty;
|
||||
match cap.pat {
|
||||
Pat::Ident(ident_pat) => (
|
||||
ident_pat.ident.to_string(),
|
||||
ArgumentDefinition {
|
||||
name: ident_pat.ident.to_string(),
|
||||
is_ref: ident_pat.by_ref.is_some(),
|
||||
},
|
||||
arg_type,
|
||||
ident_pat.by_ref.is_some(),
|
||||
ident_pat.span(),
|
||||
),
|
||||
Pat::Ref(_ref_pat) => unimplemented!(),
|
||||
_ => panic!(),
|
||||
|
|
@ -134,20 +141,16 @@ pub fn ivory_module(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|||
::ivory::info::php_print_module_info(&MODULE_INFO.info);
|
||||
}
|
||||
|
||||
#funcs
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_module() -> *mut ::ivory::zend::ModuleInternal {
|
||||
let mut entry = Box::new(::ivory::zend::ModuleInternal::new(MODULE_INFO.name, MODULE_INFO.version));
|
||||
|
||||
entry.set_info_func(php_module_info);
|
||||
|
||||
let args = vec![
|
||||
::ivory::zend::ArgInfo::new(::ivory::c_str!("name"), false, false, false),
|
||||
::ivory::zend::ArgInfo::new(::ivory::c_str!("foo"), false, false, false),
|
||||
];
|
||||
|
||||
#funcs;
|
||||
|
||||
entry.set_functions(funcs);
|
||||
entry.set_functions(&IVORY_FUCTIONS);
|
||||
|
||||
Box::into_raw(entry)
|
||||
}
|
||||
|
|
@ -188,17 +191,44 @@ fn into_c_str(input: TokenStream) -> TokenStream {
|
|||
output
|
||||
}
|
||||
|
||||
fn get_funcs(names: Vec<String>, span: Span) -> TokenStream {
|
||||
let definitions = names.into_iter().map(|name| {
|
||||
let meta_name = Ident::new(&format!("FUNCTION_META_{}", name.to_uppercase()), span);
|
||||
quote! {
|
||||
#meta_name.as_function()
|
||||
fn get_funcs(funcs: Vec<FunctionDefinition>, span: Span) -> TokenStream {
|
||||
let func_count = funcs.len() + 1;
|
||||
|
||||
let definitions = funcs.into_iter().map(|func| {
|
||||
let name = func.name;
|
||||
let name_ident = Ident::new(&name, span.clone());
|
||||
let num_args = func.args.len();
|
||||
let arg_defs = func.args.iter().map(|arg| {
|
||||
let name = &arg.name;
|
||||
let is_ref = &arg.is_ref;
|
||||
quote!(::ivory::zend::ArgInfo::new(::ivory::c_str!(#name), false, false, #is_ref))
|
||||
});
|
||||
|
||||
if num_args > 0 {
|
||||
quote! {
|
||||
::ivory::zend::Function::new_with_args(
|
||||
{concat!(#name, "\0").as_ptr() as *const ::std::os::raw::c_char},
|
||||
#name_ident as *const ::std::os::raw::c_void,
|
||||
&[::ivory::zend::ArgInfo::new(#num_args as *const ::std::os::raw::c_char, false, false, false),
|
||||
#(#arg_defs),*
|
||||
],
|
||||
#num_args as u32
|
||||
)
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
::ivory::zend::Function::new(
|
||||
{concat!(#name, "\0").as_ptr() as *const ::std::os::raw::c_char},
|
||||
#name_ident as *const ::std::os::raw::c_void,
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
let funcs = vec![
|
||||
#(#definitions),*
|
||||
const IVORY_FUCTIONS: [::ivory::zend::Function; #func_count] = [
|
||||
#(#definitions),*,
|
||||
::ivory::zend::Function::end()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
use std;
|
||||
use std::os::raw::{c_char, c_uchar};
|
||||
|
||||
use crate::zend::HandlerFunc;
|
||||
use std::os::raw::{c_char, c_uchar, c_void};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct ArgInfo {
|
||||
name: *const c_char,
|
||||
class_name: *const c_char,
|
||||
type_hint: c_uchar,
|
||||
pass_by_reference: c_uchar,
|
||||
allow_null: c_uchar,
|
||||
is_variadic: c_uchar,
|
||||
pub name: *const c_char,
|
||||
pub class_name: *const c_char,
|
||||
pub type_hint: c_uchar,
|
||||
pub pass_by_reference: c_uchar,
|
||||
pub allow_null: c_uchar,
|
||||
pub is_variadic: c_uchar,
|
||||
}
|
||||
|
||||
impl ArgInfo {
|
||||
|
|
@ -35,50 +33,44 @@ impl ArgInfo {
|
|||
#[repr(C)]
|
||||
pub struct Function {
|
||||
fname: *const c_char,
|
||||
handler: Option<HandlerFunc>,
|
||||
handler: *const c_void,
|
||||
arg_info: *const ArgInfo,
|
||||
num_args: u32,
|
||||
flags: u32,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
pub fn new(name: *const c_char, handler: HandlerFunc) -> Function {
|
||||
pub const fn new(name: *const c_char, handler: *const c_void) -> Function {
|
||||
Function {
|
||||
fname: name,
|
||||
handler: Some(handler),
|
||||
handler,
|
||||
arg_info: std::ptr::null(),
|
||||
num_args: 0,
|
||||
flags: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_args(
|
||||
pub const fn new_with_args(
|
||||
name: *const c_char,
|
||||
handler: HandlerFunc,
|
||||
handler: *const c_void,
|
||||
args: &'static [ArgInfo],
|
||||
num_args: u32,
|
||||
) -> Function {
|
||||
let num_args = args.len() as u32;
|
||||
let mut args_vec = Vec::new();
|
||||
|
||||
let arg_count = ArgInfo::new(num_args as *const c_char, false, false, false);
|
||||
args_vec.push(arg_count);
|
||||
args_vec.extend_from_slice(args);
|
||||
|
||||
let arg_ptr = Box::into_raw(args_vec.into_boxed_slice()) as *const ArgInfo;
|
||||
let arg_ptr = args.as_ptr();
|
||||
|
||||
Function {
|
||||
fname: name,
|
||||
handler: Some(handler),
|
||||
handler,
|
||||
arg_info: arg_ptr,
|
||||
num_args,
|
||||
flags: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn end() -> Function {
|
||||
pub const fn end() -> Function {
|
||||
Function {
|
||||
fname: std::ptr::null(),
|
||||
handler: None,
|
||||
handler: std::ptr::null(),
|
||||
arg_info: std::ptr::null(),
|
||||
num_args: 0,
|
||||
flags: 0,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use std::mem;
|
|||
use std::os::raw::{c_char, c_int, c_uchar, c_uint, c_ushort, c_void};
|
||||
|
||||
use crate::zend::function::{ArgInfo, Function};
|
||||
use crate::zend::{ExecuteData, ZVal};
|
||||
|
||||
pub(crate) type StartupFunc = extern "C" fn(type_: c_int, module_number: c_int) -> c_int;
|
||||
pub(crate) type ShutdownFunc = extern "C" fn(type_: c_int, module_number: c_int) -> c_int;
|
||||
|
|
@ -11,7 +10,6 @@ pub(crate) type InfoFunc = extern "C" fn();
|
|||
pub(crate) type GlobalsCtorFunc = extern "C" fn(global: *const c_void) -> c_void;
|
||||
pub(crate) type GlobalsDtorFunc = extern "C" fn(global: *const c_void) -> c_void;
|
||||
pub(crate) type PostDeactivateFunc = extern "C" fn() -> c_int;
|
||||
pub(crate) type HandlerFunc = extern "C" fn(execute_data: *const ExecuteData, retval: *mut ZVal);
|
||||
|
||||
pub struct ModuleDep {}
|
||||
|
||||
|
|
@ -87,24 +85,24 @@ impl ModuleInternal {
|
|||
self.info_func = Some(func);
|
||||
}
|
||||
|
||||
pub fn set_functions(&mut self, mut funcs: Vec<Function>) {
|
||||
funcs.push(Function::end());
|
||||
self.functions = Box::into_raw(funcs.into_boxed_slice()) as *const Function;
|
||||
pub fn set_functions(&mut self, funcs: &'static [Function]) {
|
||||
self.functions = funcs.as_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FunctionMeta {
|
||||
pub name: *const c_char,
|
||||
pub func: HandlerFunc,
|
||||
pub func: *const c_void,
|
||||
pub args: &'static [ArgInfo],
|
||||
}
|
||||
|
||||
impl FunctionMeta {
|
||||
pub fn as_function(&self) -> Function {
|
||||
if self.args.len() == 0 {
|
||||
if self.args.len() == 1 {
|
||||
// first arg is argument count which is always added
|
||||
Function::new(self.name, self.func)
|
||||
} else {
|
||||
Function::new_with_args(self.name, self.func, self.args)
|
||||
Function::new_with_args(self.name, self.func, self.args, self.args.len() as u32 - 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
7
tests/src/imported.rs
Normal file
7
tests/src/imported.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
use ivory::externs::printf;
|
||||
use ivory::ivory_export;
|
||||
|
||||
#[ivory_export]
|
||||
fn imported_fn() {
|
||||
printf("imported");
|
||||
}
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
use crate::imported::imported_fn;
|
||||
use ivory::externs::printf;
|
||||
use ivory::PhpVal;
|
||||
use ivory::{ivory_export, ivory_module};
|
||||
|
||||
mod imported;
|
||||
|
||||
fn dump<T: Debug>(arg: T) {
|
||||
printf(format!("{:?}", arg));
|
||||
}
|
||||
|
|
@ -37,7 +40,6 @@ fn expect_bool(arg: bool) {
|
|||
fn expect_option_bool(arg: Option<bool>) {
|
||||
dump(arg);
|
||||
}
|
||||
|
||||
ivory_module!({
|
||||
name: "tests",
|
||||
version: "0.0.1",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue