work towards type hints in function exports

once const traits are a thing the zvaltype can be determined
This commit is contained in:
Robin Appelman 2019-06-04 20:18:26 +02:00
commit 5eb8082d86
3 changed files with 70 additions and 10 deletions

View file

@ -7,9 +7,7 @@ mod cache;
use proc_macro2::{Span, TokenStream, TokenTree};
use quote::quote;
use syn::spanned::Spanned;
use syn::{
parse_macro_input, AttributeArgs, FnArg, Ident, Item, ItemFn, LitStr, Pat, ReturnType, Type,
};
use syn::{parse_macro_input, AttributeArgs, FnArg, Ident, Item, ItemFn, LitStr, Pat, ReturnType, Type, parse_str};
/// See the [crate documentation](index.html) for details
#[proc_macro_attribute]
@ -34,6 +32,7 @@ pub fn ivory_export(
#[derive(Clone)]
pub(crate) struct ArgumentDefinition {
name: String,
ty: String,
is_ref: bool,
}
@ -115,6 +114,7 @@ fn get_arg_info(arg: FnArg) -> (ArgumentDefinition, Type) {
Pat::Ident(ident_pat) => (
ArgumentDefinition {
name: ident_pat.ident.to_string(),
ty: format!("{}", quote!(#arg_type)),
is_ref: ident_pat.by_ref.is_some(),
},
arg_type,
@ -164,7 +164,7 @@ pub fn ivory_module(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
entry.set_info_func(php_module_info);
entry.set_functions(&IVORY_FUCTIONS);
entry.set_functions(&IVORY_FUNCTIONS);
Box::into_raw(entry)
}
@ -215,7 +215,8 @@ fn get_funcs(funcs: Vec<FunctionDefinition>, span: Span) -> TokenStream {
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))
let ty = parse_str::<Type>(&arg.ty).unwrap();
quote!(::ivory::zend::ArgInfo::from_type::<#ty>(::ivory::c_str!(#name), #is_ref))
});
if num_args > 0 {
@ -223,7 +224,7 @@ fn get_funcs(funcs: Vec<FunctionDefinition>, span: Span) -> TokenStream {
::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),
&[::ivory::zend::ArgInfo::arg_count(#num_args),
#(#arg_defs),*
],
#num_args as u32
@ -240,7 +241,7 @@ fn get_funcs(funcs: Vec<FunctionDefinition>, span: Span) -> TokenStream {
});
quote! {
const IVORY_FUCTIONS: [::ivory::zend::Function; #func_count] = [
const IVORY_FUNCTIONS: [::ivory::zend::Function; #func_count] = [
#(#definitions),*,
::ivory::zend::Function::end()
];

View file

@ -1,3 +1,5 @@
use crate::zend::zval::GetTypeHint;
use crate::zend::ZValType;
use std;
use std::os::raw::{c_char, c_uchar, c_void};
@ -6,7 +8,9 @@ use std::os::raw::{c_char, c_uchar, c_void};
pub struct ArgInfo {
pub name: *const c_char,
pub class_name: *const c_char,
pub type_hint: c_uchar,
// *const c_char
pub type_hint: ZValType,
// *const c_char
pub pass_by_reference: c_uchar,
pub allow_null: c_uchar,
pub is_variadic: c_uchar,
@ -15,6 +19,7 @@ pub struct ArgInfo {
impl ArgInfo {
pub const fn new(
name: *const c_char,
ty: ZValType,
allow_null: bool,
is_variadic: bool,
by_reference: bool,
@ -22,12 +27,36 @@ impl ArgInfo {
ArgInfo {
name,
class_name: std::ptr::null(),
type_hint: 0,
type_hint: ty,
pass_by_reference: by_reference as c_uchar,
allow_null: allow_null as c_uchar,
is_variadic: is_variadic as c_uchar,
}
}
pub const fn arg_count(count: usize) -> Self {
ArgInfo::new(count as *const c_char, ZValType::Undef, false, false, false)
}
pub const fn from_type<T>(name: *const c_char, is_ref: bool) -> Self {
ArgInfo::new(name, ZValType::Undef, false, false, false)
}
}
pub trait GetArgInfo {
fn get_arg_info(name: *const c_char, is_ref: bool) -> ArgInfo;
}
impl<T: GetTypeHint> GetArgInfo for T {
fn get_arg_info(name: *const c_char, is_ref: bool) -> ArgInfo {
ArgInfo::new(name, Self::get_type_hint(), false, false, is_ref)
}
}
impl<T: GetTypeHint> GetArgInfo for Option<T> {
fn get_arg_info(name: *const c_char, is_ref: bool) -> ArgInfo {
ArgInfo::new(name, T::get_type_hint(), true, false, is_ref)
}
}
#[repr(C)]

View file

@ -103,7 +103,7 @@ impl ZVal {
}
}
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[repr(u8)]
pub enum ZValType {
Undef = 0,
@ -159,6 +159,36 @@ impl Display for ZValType {
}
}
pub trait GetTypeHint {
fn get_type_hint() -> ZValType;
}
macro_rules! impl_get_type_hint {
($type:ty, $hint:expr) => {
impl GetTypeHint for $type {
#[inline]
fn get_type_hint() -> ZValType {
$hint
}
}
};
}
impl_get_type_hint!(String, ZValType::String);
impl_get_type_hint!(bool, ZValType::Bool);
impl_get_type_hint!(f64, ZValType::Double);
impl_get_type_hint!(f32, ZValType::Double);
impl_get_type_hint!(u8, ZValType::Long);
impl_get_type_hint!(u16, ZValType::Long);
impl_get_type_hint!(u32, ZValType::Long);
impl_get_type_hint!(u64, ZValType::Long);
impl_get_type_hint!(usize, ZValType::Long);
impl_get_type_hint!(i8, ZValType::Long);
impl_get_type_hint!(i16, ZValType::Long);
impl_get_type_hint!(i32, ZValType::Long);
impl_get_type_hint!(i64, ZValType::Long);
impl_get_type_hint!(isize, ZValType::Long);
impl From<ZValType> for u8 {
fn from(val: ZValType) -> Self {
unsafe { transmute(val) }