mirror of
https://github.com/icewind1991/ivory.git
synced 2026-06-03 10:44:09 +02:00
remove the need to list all exported functions when declaring the module
This commit is contained in:
parent
a0af05508f
commit
34fb187384
7 changed files with 22 additions and 64 deletions
|
|
@ -21,7 +21,6 @@ fn hello_world() {
|
|||
ivory_module!({
|
||||
name: "demo",
|
||||
version: "0.0.1",
|
||||
functions: &[hello_world, hello_other],
|
||||
info: &[("demo extension", "enabled")]
|
||||
});
|
||||
```
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use ivory::{ivory_export, ivory_module};
|
||||
use ivory::externs::printf;
|
||||
use ivory::{ivory_export, ivory_module};
|
||||
|
||||
#[ivory_export]
|
||||
fn hello_other(other: String) {
|
||||
|
|
@ -14,6 +14,5 @@ fn hello_world() {
|
|||
ivory_module!({
|
||||
name: "demo",
|
||||
version: "0.0.1",
|
||||
functions: &[hello_world, hello_other],
|
||||
info: &[("demo extension", "enabled")]
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ edition = "2018"
|
|||
syn = { version = "0.15", features = ["full"] }
|
||||
quote = "0.6"
|
||||
proc-macro2 = "0.4"
|
||||
lazy_static = "1.3"
|
||||
|
||||
[dev-dependencies]
|
||||
ivory = { version = "0.1", path = ".." }
|
||||
|
|
|
|||
14
ivory/macro/src/cache.rs
Normal file
14
ivory/macro/src/cache.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use lazy_static::lazy_static;
|
||||
use std::sync::Mutex;
|
||||
|
||||
lazy_static! {
|
||||
static ref FUNCTION_NAMES: Mutex<Vec<String>> = Mutex::new(Vec::new());
|
||||
}
|
||||
|
||||
pub fn cache_function(name: String) {
|
||||
FUNCTION_NAMES.lock().unwrap().push(name);
|
||||
}
|
||||
|
||||
pub fn get_functions() -> Vec<String> {
|
||||
FUNCTION_NAMES.lock().unwrap().clone()
|
||||
}
|
||||
|
|
@ -2,14 +2,12 @@
|
|||
|
||||
extern crate proc_macro;
|
||||
|
||||
mod cache;
|
||||
|
||||
use proc_macro2::{Span, TokenStream, TokenTree};
|
||||
use quote::quote;
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{
|
||||
parse2, parse_macro_input, AttributeArgs, Expr, FieldValue, FnArg, Ident, Item, ItemFn, LitStr,
|
||||
Pat, Type,
|
||||
};
|
||||
use syn::{parse_macro_input, AttributeArgs, FnArg, Ident, Item, ItemFn, LitStr, Pat, Type};
|
||||
|
||||
/// See the [crate documentation](index.html) for details
|
||||
#[proc_macro_attribute]
|
||||
|
|
@ -35,6 +33,7 @@ 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;
|
||||
|
|
@ -122,13 +121,7 @@ pub fn ivory_module(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|||
|
||||
let fields = group.stream();
|
||||
|
||||
let struct_def = quote! {
|
||||
::ivory::zend::PhpModule {
|
||||
#fields
|
||||
}
|
||||
};
|
||||
let function_names = get_function_names(struct_def);
|
||||
let funcs = get_funcs(function_names, span);
|
||||
let funcs = get_funcs(cache::get_functions(), span);
|
||||
|
||||
let fields = into_c_str(fields);
|
||||
|
||||
|
|
@ -195,45 +188,6 @@ fn into_c_str(input: TokenStream) -> TokenStream {
|
|||
output
|
||||
}
|
||||
|
||||
fn get_function_names(struct_def: TokenStream) -> Vec<String> {
|
||||
let expr: Expr = parse2(struct_def).unwrap();
|
||||
let expr = get_field_expr(expr, "functions").unwrap();
|
||||
match expr {
|
||||
Expr::Reference(ref_expr) => match *ref_expr.expr {
|
||||
Expr::Array(arr) => arr
|
||||
.elems
|
||||
.into_iter()
|
||||
.map(|element: Expr| {
|
||||
let tokens: TokenStream = quote!(#element);
|
||||
let tree = tokens.into_iter().next().unwrap();
|
||||
match tree {
|
||||
TokenTree::Ident(ident) => ident.to_string(),
|
||||
_ => panic!(),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
_ => panic!(),
|
||||
},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_field_expr(expr: Expr, field_name: &str) -> Option<Expr> {
|
||||
let fields: Punctuated<FieldValue, syn::token::Comma> = match expr {
|
||||
Expr::Struct(expr) => expr.fields,
|
||||
_ => panic!("invalid struct"),
|
||||
};
|
||||
for field in fields {
|
||||
if let syn::Member::Named(ident) = &field.member {
|
||||
let name = ident.to_string();
|
||||
if &name == field_name {
|
||||
return Some(field.expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -112,6 +112,5 @@ impl FunctionMeta {
|
|||
pub struct PhpModule {
|
||||
pub name: *const c_char,
|
||||
pub version: *const c_char,
|
||||
pub functions: &'static [HandlerFunc],
|
||||
pub info: &'static [(&'static str, &'static str)],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,13 +41,5 @@ fn expect_option_bool(arg: Option<bool>) {
|
|||
ivory_module!({
|
||||
name: "tests",
|
||||
version: "0.0.1",
|
||||
functions: &[
|
||||
dump_arg,
|
||||
expect_long,
|
||||
expect_double,
|
||||
expect_string,
|
||||
expect_bool,
|
||||
expect_option_bool
|
||||
],
|
||||
info: &[("test extension", "enabled")]
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue