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!({
|
ivory_module!({
|
||||||
name: "demo",
|
name: "demo",
|
||||||
version: "0.0.1",
|
version: "0.0.1",
|
||||||
functions: &[hello_world, hello_other],
|
|
||||||
info: &[("demo extension", "enabled")]
|
info: &[("demo extension", "enabled")]
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use ivory::{ivory_export, ivory_module};
|
|
||||||
use ivory::externs::printf;
|
use ivory::externs::printf;
|
||||||
|
use ivory::{ivory_export, ivory_module};
|
||||||
|
|
||||||
#[ivory_export]
|
#[ivory_export]
|
||||||
fn hello_other(other: String) {
|
fn hello_other(other: String) {
|
||||||
|
|
@ -14,6 +14,5 @@ fn hello_world() {
|
||||||
ivory_module!({
|
ivory_module!({
|
||||||
name: "demo",
|
name: "demo",
|
||||||
version: "0.0.1",
|
version: "0.0.1",
|
||||||
functions: &[hello_world, hello_other],
|
|
||||||
info: &[("demo extension", "enabled")]
|
info: &[("demo extension", "enabled")]
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ edition = "2018"
|
||||||
syn = { version = "0.15", features = ["full"] }
|
syn = { version = "0.15", features = ["full"] }
|
||||||
quote = "0.6"
|
quote = "0.6"
|
||||||
proc-macro2 = "0.4"
|
proc-macro2 = "0.4"
|
||||||
|
lazy_static = "1.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ivory = { version = "0.1", path = ".." }
|
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;
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
mod cache;
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream, TokenTree};
|
use proc_macro2::{Span, TokenStream, TokenTree};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::punctuated::Punctuated;
|
|
||||||
use syn::spanned::Spanned;
|
use syn::spanned::Spanned;
|
||||||
use syn::{
|
use syn::{parse_macro_input, AttributeArgs, FnArg, Ident, Item, ItemFn, LitStr, Pat, Type};
|
||||||
parse2, parse_macro_input, AttributeArgs, Expr, FieldValue, FnArg, Ident, Item, ItemFn, LitStr,
|
|
||||||
Pat, Type,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// See the [crate documentation](index.html) for details
|
/// See the [crate documentation](index.html) for details
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
|
|
@ -35,6 +33,7 @@ fn export_fn(item: ItemFn) -> TokenStream {
|
||||||
let span = item.span();
|
let span = item.span();
|
||||||
let name = item.ident;
|
let name = item.ident;
|
||||||
let name_str = name.to_string();
|
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 meta_name = Ident::new(&format!("FUNCTION_META_{}", name_str.to_uppercase()), span);
|
||||||
let body = item.block;
|
let body = item.block;
|
||||||
let decl = item.decl;
|
let decl = item.decl;
|
||||||
|
|
@ -122,13 +121,7 @@ pub fn ivory_module(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
|
||||||
let fields = group.stream();
|
let fields = group.stream();
|
||||||
|
|
||||||
let struct_def = quote! {
|
let funcs = get_funcs(cache::get_functions(), span);
|
||||||
::ivory::zend::PhpModule {
|
|
||||||
#fields
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let function_names = get_function_names(struct_def);
|
|
||||||
let funcs = get_funcs(function_names, span);
|
|
||||||
|
|
||||||
let fields = into_c_str(fields);
|
let fields = into_c_str(fields);
|
||||||
|
|
||||||
|
|
@ -195,45 +188,6 @@ fn into_c_str(input: TokenStream) -> TokenStream {
|
||||||
output
|
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 {
|
fn get_funcs(names: Vec<String>, span: Span) -> TokenStream {
|
||||||
let definitions = names.into_iter().map(|name| {
|
let definitions = names.into_iter().map(|name| {
|
||||||
let meta_name = Ident::new(&format!("FUNCTION_META_{}", name.to_uppercase()), span);
|
let meta_name = Ident::new(&format!("FUNCTION_META_{}", name.to_uppercase()), span);
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,5 @@ impl FunctionMeta {
|
||||||
pub struct PhpModule {
|
pub struct PhpModule {
|
||||||
pub name: *const c_char,
|
pub name: *const c_char,
|
||||||
pub version: *const c_char,
|
pub version: *const c_char,
|
||||||
pub functions: &'static [HandlerFunc],
|
|
||||||
pub info: &'static [(&'static str, &'static str)],
|
pub info: &'static [(&'static str, &'static str)],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,13 +41,5 @@ fn expect_option_bool(arg: Option<bool>) {
|
||||||
ivory_module!({
|
ivory_module!({
|
||||||
name: "tests",
|
name: "tests",
|
||||||
version: "0.0.1",
|
version: "0.0.1",
|
||||||
functions: &[
|
|
||||||
dump_arg,
|
|
||||||
expect_long,
|
|
||||||
expect_double,
|
|
||||||
expect_string,
|
|
||||||
expect_bool,
|
|
||||||
expect_option_bool
|
|
||||||
],
|
|
||||||
info: &[("test extension", "enabled")]
|
info: &[("test extension", "enabled")]
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue