mirror of
https://github.com/icewind1991/ivory.git
synced 2026-06-03 18:54:07 +02:00
function gen wip
This commit is contained in:
parent
56cd9d6968
commit
224c648852
17 changed files with 495 additions and 277 deletions
|
|
@ -1,12 +1,12 @@
|
||||||
[package]
|
[package]
|
||||||
name = "helloworld"
|
name = "ivory-helloworld"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Jin Hu <bixuehujin@gmail.com>"]
|
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.50"
|
libc = "0.2.50"
|
||||||
php-rs = { path = "../..", version = "0.1.0" }
|
ivory = { path = "../../ivory", version = "0.1.0" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "helloworld"
|
name = "helloworld"
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,15 @@
|
||||||
use libc::*;
|
use ivory::*;
|
||||||
use php_rs::info::{print_table_start, print_table_row, print_table_end};
|
use ivory::externs::printf;
|
||||||
use php_rs::zend::*;
|
use ivory::zend::{ExecuteData, Value};
|
||||||
use php_rs::*;
|
|
||||||
|
|
||||||
extern "C" {
|
#[ivory_export]
|
||||||
pub fn php_printf(format: *const c_char, ...) -> size_t;
|
fn hello_world() {
|
||||||
|
printf("Hello world, Rust!");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
ivory_module!({
|
||||||
pub extern "C" fn php_module_startup(_type: c_int, _module_number: c_int) -> c_int {
|
name: "demo",
|
||||||
0
|
version: "0.0.1",
|
||||||
}
|
functions: &[hello_world],
|
||||||
|
info: &[("demo extension", "enabled")]
|
||||||
#[no_mangle]
|
});
|
||||||
pub extern "C" fn php_module_shutdown(_type: c_int, _module_number: c_int) -> c_int {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn php_module_info() {
|
|
||||||
print_table_start();
|
|
||||||
print_table_row(&["A demo PHP extension written in Rust", "enabled"]);
|
|
||||||
print_table_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn helloworld(_data: &ExecuteData, _retval: &Value) {
|
|
||||||
unsafe { php_printf(c_str!("Hello world, Rust!")) };
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn get_module() -> *mut zend::Module {
|
|
||||||
let mut entry = Box::new(zend::Module::new(c_str!("demo"), c_str!("0.1.0-dev")));
|
|
||||||
|
|
||||||
entry.set_info_func(php_module_info);
|
|
||||||
|
|
||||||
let args = vec![
|
|
||||||
ArgInfo::new(c_str!("name"), false, false, false),
|
|
||||||
ArgInfo::new(c_str!("foo"), false, false, false),
|
|
||||||
];
|
|
||||||
|
|
||||||
let funcs = vec![
|
|
||||||
Function::new(c_str!("helloworld"), helloworld),
|
|
||||||
Function::new_with_args(c_str!("helloworld2"), helloworld, args),
|
|
||||||
];
|
|
||||||
|
|
||||||
entry.set_functions(funcs);
|
|
||||||
|
|
||||||
Box::into_raw(entry)
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "php-rs"
|
name = "ivory"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Jin Hu <bixuehujin@gmail.com>"]
|
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||||
keywords = ["php", "php-extension"]
|
keywords = ["php", "php-extension"]
|
||||||
description = "A library to build PHP extensions in Rust."
|
description = "A library to build PHP extensions in Rust."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
@ -10,7 +10,9 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.50"
|
libc = "0.2.50"
|
||||||
|
ivory-macro = { version = "0.1", path = "macro" }
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "php_rs"
|
name = "ivory"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
21
ivory/macro/Cargo.toml
Normal file
21
ivory/macro/Cargo.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
[package]
|
||||||
|
name = "ivory-macro"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||||
|
keywords = ["php", "php-extension"]
|
||||||
|
description = "A library to build PHP extensions in Rust."
|
||||||
|
license = "MIT"
|
||||||
|
repository = "https://github.com/rethinkphp/php-rs"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
syn = { version = "0.15", features = ["full"] }
|
||||||
|
quote = "0.6"
|
||||||
|
proc-macro2 = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
ivory = { version = "0.1", path = ".." }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "ivory_macro"
|
||||||
|
proc-macro = true
|
||||||
208
ivory/macro/src/lib.rs
Normal file
208
ivory/macro/src/lib.rs
Normal file
|
|
@ -0,0 +1,208 @@
|
||||||
|
#![recursion_limit = "128"]
|
||||||
|
|
||||||
|
extern crate proc_macro;
|
||||||
|
|
||||||
|
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::parse_quote::parse;
|
||||||
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
use syn::token::Comma;
|
||||||
|
|
||||||
|
/// See the [crate documentation](index.html) for details
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn ivory_export(attr: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let input: TokenStream = input.into();
|
||||||
|
let item = syn::parse2::<Item>(input).unwrap();
|
||||||
|
let attr = parse_macro_input!(attr as AttributeArgs);
|
||||||
|
|
||||||
|
let output = match item {
|
||||||
|
Item::Fn(itemFn) => {
|
||||||
|
export_fn(itemFn).into()
|
||||||
|
}
|
||||||
|
_ => unimplemented!()
|
||||||
|
};
|
||||||
|
|
||||||
|
// panic!("{}", output);
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn export_fn(item: ItemFn) -> TokenStream {
|
||||||
|
let span = item.span();
|
||||||
|
let name = item.ident;
|
||||||
|
let name_str = name.to_string();
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn #name(data: &ExecuteData, retval: &Value) {
|
||||||
|
let result = #body;
|
||||||
|
}
|
||||||
|
|
||||||
|
const #meta_name: ::ivory::zend::FunctionMeta = ::ivory::zend::FunctionMeta{
|
||||||
|
name: {concat!(#name_str, "\0").as_ptr() as *const ::libc::c_char}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See the [crate documentation](index.html) for details
|
||||||
|
#[proc_macro]
|
||||||
|
pub fn ivory_module(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
|
let input: TokenStream = input.into();
|
||||||
|
let span = input.span();
|
||||||
|
|
||||||
|
let mut tokens = input.into_iter();
|
||||||
|
let token = tokens.next().unwrap();
|
||||||
|
let group = match token {
|
||||||
|
TokenTree::Group(group) => {
|
||||||
|
group
|
||||||
|
}
|
||||||
|
_ => panic!("macro input must be a group")
|
||||||
|
};
|
||||||
|
|
||||||
|
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 fields = into_c_str(fields);
|
||||||
|
|
||||||
|
let result = quote! {
|
||||||
|
const MODULE_INFO: ::ivory::zend::PhpModule = ::ivory::zend::PhpModule {
|
||||||
|
#fields
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" fn php_module_info() {
|
||||||
|
::ivory::info::php_print_module_info(&MODULE_INFO.info);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
|
||||||
|
Box::into_raw(entry)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// panic!("{}", result);
|
||||||
|
|
||||||
|
result.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_c_str(input: TokenStream) -> TokenStream {
|
||||||
|
let tokens: Vec<TokenTree> = input.into_iter().map(|token| {
|
||||||
|
match token.clone() {
|
||||||
|
TokenTree::Literal(lit) => {
|
||||||
|
let mut tokens = TokenStream::new();
|
||||||
|
tokens.extend(vec![token.clone()]);
|
||||||
|
match syn::parse2::<LitStr>(tokens) {
|
||||||
|
Ok(litStr) => {
|
||||||
|
let val = litStr.value();
|
||||||
|
let tokens = quote! {
|
||||||
|
{ concat!(#val, "\0").as_ptr() as *const ::libc::c_char }
|
||||||
|
};
|
||||||
|
if let Some(tree) = tokens.into_iter().next() {
|
||||||
|
tree
|
||||||
|
} else {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => token
|
||||||
|
}
|
||||||
|
}).collect();
|
||||||
|
let mut output = TokenStream::new();
|
||||||
|
output.extend(tokens.into_iter());
|
||||||
|
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| {
|
||||||
|
// TODO: args
|
||||||
|
//let meta_name = Ident::new(&format!("FUNCTION_META_{}", name.to_uppercase()), span);
|
||||||
|
let func_ident = Ident::new(&name, span);
|
||||||
|
quote! {
|
||||||
|
::ivory::zend::Function::new(::ivory::c_str!(#name), #func_ident),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
let funcs = vec![
|
||||||
|
#(#definitions),*
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
12
ivory/src/externs/mod.rs
Normal file
12
ivory/src/externs/mod.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
use std::ffi::{CString};
|
||||||
|
|
||||||
|
use libc::*;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn php_printf(format: *const c_char, ...) -> size_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn printf<T: Into<Vec<u8>>>(string: T) {
|
||||||
|
let cstr = CString::new(string).unwrap();
|
||||||
|
unsafe { php_printf(cstr.as_ptr()); }
|
||||||
|
}
|
||||||
20
ivory/src/info.rs
Normal file
20
ivory/src/info.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use libc::*;
|
||||||
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn php_info_print_table_start();
|
||||||
|
pub fn php_info_print_table_row(num_cols: c_int, ...) -> c_void;
|
||||||
|
pub fn php_info_print_table_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn php_print_module_info(info: &[(&'static str, &'static str)]) {
|
||||||
|
unsafe {
|
||||||
|
php_info_print_table_start();
|
||||||
|
for (key, value) in info {
|
||||||
|
let v1 = CString::new(key.to_string()).unwrap();
|
||||||
|
let v2 = CString::new(value.to_string()).unwrap();
|
||||||
|
php_info_print_table_row(2, v1, v2);
|
||||||
|
}
|
||||||
|
php_info_print_table_end();
|
||||||
|
}
|
||||||
|
}
|
||||||
7
ivory/src/lib.rs
Normal file
7
ivory/src/lib.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#[macro_use]
|
||||||
|
pub mod macros;
|
||||||
|
|
||||||
|
pub mod externs;
|
||||||
|
pub mod info;
|
||||||
|
pub mod zend;
|
||||||
|
pub use ivory_macro::{ivory_export, ivory_module};
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! c_str {
|
macro_rules! c_str {
|
||||||
($s:expr) => {{
|
($s:expr) => {{
|
||||||
concat!($s, "\0").as_ptr() as *const c_char
|
concat!($s, "\0").as_ptr() as *const ::libc::c_char
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
84
ivory/src/zend/function.rs
Normal file
84
ivory/src/zend/function.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
use std;
|
||||||
|
|
||||||
|
use libc::*;
|
||||||
|
use crate::zend::HandlerFunc;
|
||||||
|
|
||||||
|
#[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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArgInfo {
|
||||||
|
pub fn new(
|
||||||
|
name: *const c_char,
|
||||||
|
allow_null: bool,
|
||||||
|
is_variadic: bool,
|
||||||
|
by_reference: bool,
|
||||||
|
) -> ArgInfo {
|
||||||
|
ArgInfo {
|
||||||
|
name,
|
||||||
|
class_name: std::ptr::null(),
|
||||||
|
type_hint: 0,
|
||||||
|
pass_by_reference: by_reference as c_uchar,
|
||||||
|
allow_null: allow_null as c_uchar,
|
||||||
|
is_variadic: is_variadic as c_uchar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct Function {
|
||||||
|
fname: *const c_char,
|
||||||
|
handler: Option<HandlerFunc>,
|
||||||
|
arg_info: *const ArgInfo,
|
||||||
|
num_args: u32,
|
||||||
|
flags: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Function {
|
||||||
|
pub fn new(name: *const c_char, handler: HandlerFunc) -> Function {
|
||||||
|
Function {
|
||||||
|
fname: name,
|
||||||
|
handler: Some(handler),
|
||||||
|
arg_info: std::ptr::null(),
|
||||||
|
num_args: 0,
|
||||||
|
flags: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_args(
|
||||||
|
name: *const c_char,
|
||||||
|
handler: HandlerFunc,
|
||||||
|
mut args: Vec<ArgInfo>,
|
||||||
|
) -> Function {
|
||||||
|
let num_args = args.len() as u32;
|
||||||
|
|
||||||
|
let arg_count = ArgInfo::new(num_args as *const c_char, false, false, false);
|
||||||
|
args.insert(0, arg_count);
|
||||||
|
|
||||||
|
let arg_ptr = Box::into_raw(args.into_boxed_slice()) as *const ArgInfo;
|
||||||
|
|
||||||
|
Function {
|
||||||
|
fname: name,
|
||||||
|
handler: Some(handler),
|
||||||
|
arg_info: arg_ptr,
|
||||||
|
num_args,
|
||||||
|
flags: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn end() -> Function {
|
||||||
|
Function {
|
||||||
|
fname: std::ptr::null(),
|
||||||
|
handler: None,
|
||||||
|
arg_info: std::ptr::null(),
|
||||||
|
num_args: 0,
|
||||||
|
flags: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
ivory/src/zend/mod.rs
Normal file
5
ivory/src/zend/mod.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
pub use self::module::*;
|
||||||
|
pub use self::function::*;
|
||||||
|
|
||||||
|
mod module;
|
||||||
|
mod function;
|
||||||
117
ivory/src/zend/module.rs
Normal file
117
ivory/src/zend/module.rs
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
use std;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
use libc::*;
|
||||||
|
|
||||||
|
use crate::zend::function::Function;
|
||||||
|
use std::ffi::{CString, CStr};
|
||||||
|
|
||||||
|
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;
|
||||||
|
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: &ExecuteData, retval: &Value);
|
||||||
|
|
||||||
|
pub struct ExecuteData {}
|
||||||
|
|
||||||
|
pub struct Value {}
|
||||||
|
|
||||||
|
pub struct ModuleDep {}
|
||||||
|
|
||||||
|
pub struct INI {}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ModuleInternal {
|
||||||
|
size: c_ushort,
|
||||||
|
zend_api: c_uint,
|
||||||
|
zend_debug: c_uchar,
|
||||||
|
zts: c_uchar,
|
||||||
|
ini_entry: *const INI,
|
||||||
|
deps: *const ModuleDep,
|
||||||
|
name: *const c_char,
|
||||||
|
functions: *const Function,
|
||||||
|
module_startup_func: Option<StartupFunc>,
|
||||||
|
module_shutdown_func: Option<ShutdownFunc>,
|
||||||
|
request_startup_func: Option<StartupFunc>,
|
||||||
|
request_shutdown_func: Option<ShutdownFunc>,
|
||||||
|
info_func: Option<InfoFunc>,
|
||||||
|
version: *const c_char,
|
||||||
|
globals_size: size_t,
|
||||||
|
globals_ptr: *const c_void,
|
||||||
|
globals_ctor: Option<GlobalsCtorFunc>,
|
||||||
|
globals_dtor: Option<GlobalsDtorFunc>,
|
||||||
|
post_deactivate_func: Option<PostDeactivateFunc>,
|
||||||
|
module_started: c_int,
|
||||||
|
type_: c_uchar,
|
||||||
|
handle: *const c_void,
|
||||||
|
module_number: c_int,
|
||||||
|
build_id: *const c_char,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleInternal {
|
||||||
|
pub fn new(name: *const c_char, version: *const c_char) -> ModuleInternal {
|
||||||
|
ModuleInternal {
|
||||||
|
size: mem::size_of::<ModuleInternal>() as u16,
|
||||||
|
zend_api: 20180731,
|
||||||
|
zend_debug: 0,
|
||||||
|
zts: 0,
|
||||||
|
ini_entry: std::ptr::null(),
|
||||||
|
deps: std::ptr::null(),
|
||||||
|
name,
|
||||||
|
functions: std::ptr::null(),
|
||||||
|
module_startup_func: None,
|
||||||
|
module_shutdown_func: None,
|
||||||
|
request_startup_func: None,
|
||||||
|
request_shutdown_func: None,
|
||||||
|
info_func: None,
|
||||||
|
version,
|
||||||
|
globals_size: 0,
|
||||||
|
globals_ptr: std::ptr::null(),
|
||||||
|
globals_ctor: None,
|
||||||
|
globals_dtor: None,
|
||||||
|
post_deactivate_func: None,
|
||||||
|
module_started: 0,
|
||||||
|
type_: 0,
|
||||||
|
handle: std::ptr::null(),
|
||||||
|
module_number: 0,
|
||||||
|
build_id: c_str!("API20180731,NTS"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_startup_func(&mut self, func: StartupFunc) {
|
||||||
|
self.module_startup_func = Some(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_shutdown_func(&mut self, func: ShutdownFunc) {
|
||||||
|
self.module_shutdown_func = Some(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_info_func(&mut self, func: InfoFunc) {
|
||||||
|
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 struct FunctionMeta {
|
||||||
|
pub name: *const c_char,
|
||||||
|
pub arg_names: &'static [*const c_char]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FunctionMeta {
|
||||||
|
pub fn into_function(self, func: HandlerFunc) -> Function {
|
||||||
|
Function::new(self.name, func)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PhpModule {
|
||||||
|
pub name: *const c_char,
|
||||||
|
pub version: *const c_char,
|
||||||
|
pub functions: &'static [HandlerFunc],
|
||||||
|
pub info: &'static [(&'static str, &'static str)]
|
||||||
|
}
|
||||||
31
src/info.rs
31
src/info.rs
|
|
@ -1,31 +0,0 @@
|
||||||
use libc::*;
|
|
||||||
use std::ffi::CString;
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
pub fn php_info_print_table_start();
|
|
||||||
pub fn php_info_print_table_row(num_cols: c_int, ...) -> c_void;
|
|
||||||
pub fn php_info_print_table_end();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print_table_row(values: &[&str]) {
|
|
||||||
let nargs = values.len() as i32;
|
|
||||||
|
|
||||||
if nargs != 2 {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
|
|
||||||
let v1 = CString::new(values[0]).unwrap();
|
|
||||||
let v2 = CString::new(values[1]).unwrap();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
php_info_print_table_row(nargs, v1.as_ptr(), v2.as_ptr());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print_table_start() {
|
|
||||||
unsafe { php_info_print_table_start() };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn print_table_end() {
|
|
||||||
unsafe { php_info_print_table_end() }
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
extern crate libc;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
pub mod macros;
|
|
||||||
|
|
||||||
pub mod info;
|
|
||||||
pub mod zend;
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
pub use self::module::*;
|
|
||||||
|
|
||||||
mod module;
|
|
||||||
|
|
@ -1,181 +0,0 @@
|
||||||
use std;
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use libc::*;
|
|
||||||
use std::ffi::{CString, CStr};
|
|
||||||
|
|
||||||
type StartupFunc = extern "C" fn(type_: c_int, module_number: c_int) -> c_int;
|
|
||||||
type ShutdownFunc = extern "C" fn(type_: c_int, module_number: c_int) -> c_int;
|
|
||||||
type InfoFunc = extern "C" fn();
|
|
||||||
type GlobalsCtorFunc = extern "C" fn(global: *const c_void) -> c_void;
|
|
||||||
type GlobalsDtorFunc = extern "C" fn(global: *const c_void) -> c_void;
|
|
||||||
type PostDeactivateFunc = extern "C" fn() -> c_int;
|
|
||||||
type HandlerFunc = extern "C" fn(execute_data: &ExecuteData, retval: &Value);
|
|
||||||
|
|
||||||
pub struct ExecuteData {}
|
|
||||||
|
|
||||||
pub struct Value {}
|
|
||||||
|
|
||||||
pub struct ModuleDep {}
|
|
||||||
|
|
||||||
#[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,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArgInfo {
|
|
||||||
pub fn new(
|
|
||||||
name: *const c_char,
|
|
||||||
allow_null: bool,
|
|
||||||
is_variadic: bool,
|
|
||||||
by_reference: bool,
|
|
||||||
) -> ArgInfo {
|
|
||||||
ArgInfo {
|
|
||||||
name,
|
|
||||||
class_name: std::ptr::null(),
|
|
||||||
type_hint: 0,
|
|
||||||
pass_by_reference: by_reference as c_uchar,
|
|
||||||
allow_null: allow_null as c_uchar,
|
|
||||||
is_variadic: is_variadic as c_uchar,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Function {
|
|
||||||
fname: *const c_char,
|
|
||||||
handler: Option<HandlerFunc>,
|
|
||||||
arg_info: *const ArgInfo,
|
|
||||||
num_args: u32,
|
|
||||||
flags: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Function {
|
|
||||||
pub fn new(name: *const c_char, handler: HandlerFunc) -> Function {
|
|
||||||
Function {
|
|
||||||
fname: name,
|
|
||||||
handler: Some(handler),
|
|
||||||
arg_info: std::ptr::null(),
|
|
||||||
num_args: 0,
|
|
||||||
flags: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_args(
|
|
||||||
name: *const c_char,
|
|
||||||
handler: HandlerFunc,
|
|
||||||
mut args: Vec<ArgInfo>,
|
|
||||||
) -> Function {
|
|
||||||
let num_args = args.len() as u32;
|
|
||||||
|
|
||||||
let arg_count = ArgInfo::new(num_args as *const c_char, false, false, false);
|
|
||||||
args.insert(0, arg_count);
|
|
||||||
|
|
||||||
let arg_ptr = args.as_ptr();
|
|
||||||
mem::forget(args);
|
|
||||||
|
|
||||||
Function {
|
|
||||||
fname: name,
|
|
||||||
handler: Some(handler),
|
|
||||||
arg_info: arg_ptr,
|
|
||||||
num_args,
|
|
||||||
flags: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end() -> Function {
|
|
||||||
Function {
|
|
||||||
fname: std::ptr::null(),
|
|
||||||
handler: None,
|
|
||||||
arg_info: std::ptr::null(),
|
|
||||||
num_args: 0,
|
|
||||||
flags: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct INI {}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Module {
|
|
||||||
size: c_ushort,
|
|
||||||
zend_api: c_uint,
|
|
||||||
zend_debug: c_uchar,
|
|
||||||
zts: c_uchar,
|
|
||||||
ini_entry: *const INI,
|
|
||||||
deps: *const ModuleDep,
|
|
||||||
name: *const c_char,
|
|
||||||
functions: *const Function,
|
|
||||||
module_startup_func: Option<StartupFunc>,
|
|
||||||
module_shutdown_func: Option<ShutdownFunc>,
|
|
||||||
request_startup_func: Option<StartupFunc>,
|
|
||||||
request_shutdown_func: Option<ShutdownFunc>,
|
|
||||||
info_func: Option<InfoFunc>,
|
|
||||||
version: *const c_char,
|
|
||||||
globals_size: size_t,
|
|
||||||
globals_ptr: *const c_void,
|
|
||||||
globals_ctor: Option<GlobalsCtorFunc>,
|
|
||||||
globals_dtor: Option<GlobalsDtorFunc>,
|
|
||||||
post_deactivate_func: Option<PostDeactivateFunc>,
|
|
||||||
module_started: c_int,
|
|
||||||
type_: c_uchar,
|
|
||||||
handle: *const c_void,
|
|
||||||
module_number: c_int,
|
|
||||||
build_id: *const c_char,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Module {
|
|
||||||
pub fn new(name: *const c_char, version: *const c_char) -> Module {
|
|
||||||
Module {
|
|
||||||
size: mem::size_of::<Module>() as u16,
|
|
||||||
zend_api: 20180731,
|
|
||||||
zend_debug: 0,
|
|
||||||
zts: 0,
|
|
||||||
ini_entry: std::ptr::null(),
|
|
||||||
deps: std::ptr::null(),
|
|
||||||
name,
|
|
||||||
functions: std::ptr::null(),
|
|
||||||
module_startup_func: None,
|
|
||||||
module_shutdown_func: None,
|
|
||||||
request_startup_func: None,
|
|
||||||
request_shutdown_func: None,
|
|
||||||
info_func: None,
|
|
||||||
version,
|
|
||||||
globals_size: 0,
|
|
||||||
globals_ptr: std::ptr::null(),
|
|
||||||
globals_ctor: None,
|
|
||||||
globals_dtor: None,
|
|
||||||
post_deactivate_func: None,
|
|
||||||
module_started: 0,
|
|
||||||
type_: 0,
|
|
||||||
handle: std::ptr::null(),
|
|
||||||
module_number: 0,
|
|
||||||
build_id: c_str!("API20180731,NTS"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_startup_func(&mut self, func: StartupFunc) {
|
|
||||||
self.module_startup_func = Some(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_shutdown_func(&mut self, func: ShutdownFunc) {
|
|
||||||
self.module_shutdown_func = Some(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_info_func(&mut self, func: InfoFunc) {
|
|
||||||
self.info_func = Some(func);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_functions(&mut self, mut funcs: Vec<Function>) {
|
|
||||||
funcs.push(Function::end());
|
|
||||||
self.functions = funcs.as_ptr();
|
|
||||||
mem::forget(funcs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Sync for Module {}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue