args relfection

This commit is contained in:
Robin Appelman 2019-03-20 00:54:34 +01:00
commit 1e6e05c135
4 changed files with 54 additions and 21 deletions

View file

@ -2,6 +2,11 @@ use ivory::*;
use ivory::externs::printf;
use ivory::zend::{ExecuteData, Value};
#[ivory_export]
fn hello_other(_other: String) {
printf(format!("Hello ",));
}
#[ivory_export]
fn hello_world() {
printf("Hello world, Rust!");
@ -10,6 +15,6 @@ fn hello_world() {
ivory_module!({
name: "demo",
version: "0.0.1",
functions: &[hello_world],
functions: &[hello_world, hello_other],
info: &[("demo extension", "enabled")]
});

View file

@ -2,17 +2,14 @@
extern crate proc_macro;
use core::fmt::Debug;
use std::collections::HashMap;
use std::process::Command;
use core::fmt::Debug;
use proc_macro2::{Span, TokenStream, TokenTree};
use proc_macro2::token_stream::IntoIter;
use quote::{quote, quote_spanned};
use syn::{
Attribute, AttributeArgs, Data, Expr, ExprStruct, Fields, FieldValue, Ident, Item, ItemFn, Lit, LitStr,
Meta, parse2, parse_macro_input, parse_quote, parse_str, Pat, Path,
};
use syn::{Attribute, AttributeArgs, Data, Expr, ExprStruct, Fields, FieldValue, FnArg, Ident, Item, ItemFn, Lit, LitStr, Meta, parse2, parse_macro_input, parse_quote, parse_str, Pat, Path, Type};
use syn::parse_quote::parse;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
@ -48,6 +45,12 @@ fn export_fn(item: ItemFn) -> TokenStream {
unimplemented!("generics are not supported for exported functions");
}
let arg_defs = decl.inputs.into_iter()
.map(get_arg_info)
.map(|(name, _type, is_ref)| {
quote!(::ivory::zend::ArgInfo::new(::ivory::c_str!(#name), false, false, #is_ref))
});
quote! {
#[no_mangle]
pub extern "C" fn #name(data: &ExecuteData, retval: &Value) {
@ -55,11 +58,29 @@ fn export_fn(item: ItemFn) -> TokenStream {
}
const #meta_name: ::ivory::zend::FunctionMeta = ::ivory::zend::FunctionMeta{
name: {concat!(#name_str, "\0").as_ptr() as *const ::libc::c_char}
name: {concat!(#name_str, "\0").as_ptr() as *const ::libc::c_char},
func: #name,
args: &[ #(#arg_defs),*]
};
}
}
fn get_arg_info(arg: FnArg) -> (String, Type, bool) {
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())
},
Pat::Ref(ref_pat) => unimplemented!(),
_ => panic!()
}
},
_ => panic!("only normal function arguments are supported")
}
}
/// See the [crate documentation](index.html) for details
#[proc_macro]
pub fn ivory_module(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
@ -162,7 +183,7 @@ fn get_function_names(struct_def: TokenStream) -> Vec<String> {
match tree {
TokenTree::Ident(ident) => {
ident.to_string()
},
}
_ => panic!()
}
}).collect()
@ -192,11 +213,9 @@ fn get_field_expr(expr: Expr, field_name: &str) -> Option<Expr> {
fn get_funcs(names: Vec<String>, span: Span) -> TokenStream {
let definitions = names.into_iter().map(|name| {
// TODO: args
//let meta_name = Ident::new(&format!("FUNCTION_META_{}", name.to_uppercase()), span);
let func_ident = Ident::new(&name, span);
let meta_name = Ident::new(&format!("FUNCTION_META_{}", name.to_uppercase()), span);
quote! {
::ivory::zend::Function::new(::ivory::c_str!(#name), #func_ident),
#meta_name.as_function()
}
});

View file

@ -1,8 +1,10 @@
use std;
use libc::*;
use crate::zend::HandlerFunc;
#[derive(Clone)]
#[repr(C)]
pub struct ArgInfo {
name: *const c_char,
@ -14,7 +16,7 @@ pub struct ArgInfo {
}
impl ArgInfo {
pub fn new(
pub const fn new(
name: *const c_char,
allow_null: bool,
is_variadic: bool,
@ -31,6 +33,7 @@ impl ArgInfo {
}
}
#[derive(Clone)]
#[repr(C)]
pub struct Function {
fname: *const c_char,
@ -54,14 +57,16 @@ impl Function {
pub fn new_with_args(
name: *const c_char,
handler: HandlerFunc,
mut args: Vec<ArgInfo>,
mut args: &'static [ArgInfo],
) -> 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.insert(0, arg_count);
args_vec.push(arg_count);
args_vec.extend_from_slice(args);
let arg_ptr = Box::into_raw(args.into_boxed_slice()) as *const ArgInfo;
let arg_ptr = Box::into_raw(args_vec.into_boxed_slice()) as *const ArgInfo;
Function {
fname: name,

View file

@ -3,8 +3,7 @@ use std::mem;
use libc::*;
use crate::zend::function::Function;
use std::ffi::{CString, CStr};
use crate::zend::function::{Function, ArgInfo};
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;
@ -100,12 +99,17 @@ impl ModuleInternal {
pub struct FunctionMeta {
pub name: *const c_char,
pub arg_names: &'static [*const c_char]
pub func: HandlerFunc,
pub args: &'static [ArgInfo]
}
impl FunctionMeta {
pub fn into_function(self, func: HandlerFunc) -> Function {
Function::new(self.name, func)
pub fn as_function(&self) -> Function {
if self.args.len() == 0 {
Function::new(self.name, self.func)
} else {
Function::new_with_args(self.name, self.func, self.args)
}
}
}