mirror of
https://github.com/icewind1991/ivory.git
synced 2026-06-03 10:44:09 +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]
|
||||
name = "helloworld"
|
||||
name = "ivory-helloworld"
|
||||
version = "0.1.0"
|
||||
authors = ["Jin Hu <bixuehujin@gmail.com>"]
|
||||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.50"
|
||||
php-rs = { path = "../..", version = "0.1.0" }
|
||||
ivory = { path = "../../ivory", version = "0.1.0" }
|
||||
|
||||
[lib]
|
||||
name = "helloworld"
|
||||
|
|
|
|||
|
|
@ -1,51 +1,15 @@
|
|||
use libc::*;
|
||||
use php_rs::info::{print_table_start, print_table_row, print_table_end};
|
||||
use php_rs::zend::*;
|
||||
use php_rs::*;
|
||||
use ivory::*;
|
||||
use ivory::externs::printf;
|
||||
use ivory::zend::{ExecuteData, Value};
|
||||
|
||||
extern "C" {
|
||||
pub fn php_printf(format: *const c_char, ...) -> size_t;
|
||||
#[ivory_export]
|
||||
fn hello_world() {
|
||||
printf("Hello world, Rust!");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn php_module_startup(_type: c_int, _module_number: c_int) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
ivory_module!({
|
||||
name: "demo",
|
||||
version: "0.0.1",
|
||||
functions: &[hello_world],
|
||||
info: &[("demo extension", "enabled")]
|
||||
});
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
[package]
|
||||
name = "php-rs"
|
||||
name = "ivory"
|
||||
version = "0.1.0"
|
||||
authors = ["Jin Hu <bixuehujin@gmail.com>"]
|
||||
authors = ["Robin Appelman <robin@icewind.nl>"]
|
||||
keywords = ["php", "php-extension"]
|
||||
description = "A library to build PHP extensions in Rust."
|
||||
license = "MIT"
|
||||
|
|
@ -10,7 +10,9 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
libc = "0.2.50"
|
||||
ivory-macro = { version = "0.1", path = "macro" }
|
||||
|
||||
[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_rules! c_str {
|
||||
($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