ext_php_rs/builders/
function.rs1use crate::{
2 args::{Arg, ArgInfo},
3 error::{Error, Result},
4 flags::{DataType, MethodFlags},
5 types::Zval,
6 zend::{ExecuteData, FunctionEntry, ZendType},
7};
8use std::{ffi::CString, mem, ptr};
9
10#[cfg(not(windows))]
12pub type FunctionHandler = extern "C" fn(execute_data: &mut ExecuteData, retval: &mut Zval);
13#[cfg(windows)]
14pub type FunctionHandler =
15 extern "vectorcall" fn(execute_data: &mut ExecuteData, retval: &mut Zval);
16
17#[cfg(not(windows))]
19type FunctionPointerHandler = extern "C" fn(execute_data: *mut ExecuteData, retval: *mut Zval);
20#[cfg(windows)]
21type FunctionPointerHandler =
22 extern "vectorcall" fn(execute_data: *mut ExecuteData, retval: *mut Zval);
23
24#[derive(Debug)]
26pub struct FunctionBuilder<'a> {
27 name: String,
28 function: FunctionEntry,
29 args: Vec<Arg<'a>>,
30 n_req: Option<usize>,
31 retval: Option<DataType>,
32 ret_as_ref: bool,
33 ret_as_null: bool,
34}
35
36impl<'a> FunctionBuilder<'a> {
37 pub fn new<T: Into<String>>(name: T, handler: FunctionHandler) -> Self {
46 Self {
47 name: name.into(),
48 function: FunctionEntry {
49 fname: ptr::null(),
50 handler: Some(unsafe {
53 mem::transmute::<FunctionHandler, FunctionPointerHandler>(handler)
54 }),
55 arg_info: ptr::null(),
56 num_args: 0,
57 flags: 0, #[cfg(php84)]
59 doc_comment: ptr::null(),
60 #[cfg(php84)]
61 frameless_function_infos: ptr::null(),
62 },
63 args: vec![],
64 n_req: None,
65 retval: None,
66 ret_as_ref: false,
67 ret_as_null: false,
68 }
69 }
70
71 pub fn new_abstract<T: Into<String>>(name: T) -> Self {
78 Self {
79 name: name.into(),
80 function: FunctionEntry {
81 fname: ptr::null(),
82 handler: None,
83 arg_info: ptr::null(),
84 num_args: 0,
85 flags: MethodFlags::Abstract.bits(),
86 #[cfg(php84)]
87 doc_comment: ptr::null(),
88 #[cfg(php84)]
89 frameless_function_infos: ptr::null(),
90 },
91 args: vec![],
92 n_req: None,
93 retval: None,
94 ret_as_ref: false,
95 ret_as_null: false,
96 }
97 }
98
99 pub fn constructor(handler: FunctionHandler) -> Self {
107 Self::new("__construct", handler)
108 }
109
110 pub fn arg(mut self, arg: Arg<'a>) -> Self {
116 self.args.push(arg);
117 self
118 }
119
120 pub fn not_required(mut self) -> Self {
122 self.n_req = Some(self.args.len());
123 self
124 }
125
126 pub fn variadic(mut self) -> Self {
127 self.function.flags |= MethodFlags::Variadic.bits();
128 self
129 }
130
131 pub fn returns(mut self, type_: DataType, as_ref: bool, allow_null: bool) -> Self {
139 self.retval = Some(type_);
140 self.ret_as_ref = as_ref;
141 self.ret_as_null = allow_null;
142 self
143 }
144
145 pub fn build(mut self) -> Result<FunctionEntry> {
149 let mut args = Vec::with_capacity(self.args.len() + 1);
150
151 args.push(ArgInfo {
153 name: self.n_req.unwrap_or(self.args.len()) as *const _,
154 type_: match self.retval {
155 Some(retval) => {
156 ZendType::empty_from_type(retval, self.ret_as_ref, false, self.ret_as_null)
157 .ok_or(Error::InvalidCString)?
158 }
159 None => ZendType::empty(false, false),
160 },
161 default_value: ptr::null(),
162 });
163
164 args.extend(
166 self.args
167 .iter()
168 .map(|arg| arg.as_arg_info())
169 .collect::<Result<Vec<_>>>()?,
170 );
171
172 self.function.fname = CString::new(self.name)?.into_raw();
173 self.function.num_args = (args.len() - 1) as u32;
174 self.function.arg_info = Box::into_raw(args.into_boxed_slice()) as *const ArgInfo;
175
176 Ok(self.function)
177 }
178}