1use std::{ffi::CString, ptr};
4
5use crate::{
6 convert::{FromZvalMut, IntoZvalDyn},
7 describe::{abi, Parameter},
8 error::{Error, Result},
9 ffi::{
10 _zend_expected_type, _zend_expected_type_Z_EXPECTED_ARRAY,
11 _zend_expected_type_Z_EXPECTED_BOOL, _zend_expected_type_Z_EXPECTED_DOUBLE,
12 _zend_expected_type_Z_EXPECTED_LONG, _zend_expected_type_Z_EXPECTED_OBJECT,
13 _zend_expected_type_Z_EXPECTED_RESOURCE, _zend_expected_type_Z_EXPECTED_STRING,
14 zend_internal_arg_info, zend_wrong_parameters_count_error,
15 },
16 flags::DataType,
17 types::Zval,
18 zend::ZendType,
19};
20
21#[must_use]
23#[derive(Debug)]
24pub struct Arg<'a> {
25 name: String,
26 r#type: DataType,
27 as_ref: bool,
28 allow_null: bool,
29 pub(crate) variadic: bool,
30 default_value: Option<String>,
31 zval: Option<&'a mut Zval>,
32 variadic_zvals: Vec<Option<&'a mut Zval>>,
33}
34
35impl<'a> Arg<'a> {
36 pub fn new<T: Into<String>>(name: T, r#type: DataType) -> Self {
43 Arg {
44 name: name.into(),
45 r#type,
46 as_ref: false,
47 allow_null: false,
48 variadic: false,
49 default_value: None,
50 zval: None,
51 variadic_zvals: vec![],
52 }
53 }
54
55 #[allow(clippy::wrong_self_convention)]
57 pub fn as_ref(mut self) -> Self {
58 self.as_ref = true;
59 self
60 }
61
62 pub fn is_variadic(mut self) -> Self {
64 self.variadic = true;
65 self
66 }
67
68 pub fn allow_null(mut self) -> Self {
70 self.allow_null = true;
71 self
72 }
73
74 pub fn default<T: Into<String>>(mut self, default: T) -> Self {
76 self.default_value = Some(default.into());
77 self
78 }
79
80 pub fn consume<T>(mut self) -> Result<T, Self>
91 where
92 for<'b> T: FromZvalMut<'b>,
93 {
94 self.zval
95 .as_mut()
96 .and_then(|zv| T::from_zval_mut(zv.dereference_mut()))
97 .ok_or(self)
98 }
99
100 pub fn val<T>(&'a mut self) -> Option<T>
104 where
105 T: FromZvalMut<'a>,
106 {
107 self.zval
108 .as_mut()
109 .and_then(|zv| T::from_zval_mut(zv.dereference_mut()))
110 }
111
112 pub fn variadic_vals<T>(&'a mut self) -> Vec<T>
114 where
115 T: FromZvalMut<'a>,
116 {
117 self.variadic_zvals
118 .iter_mut()
119 .filter_map(|zv| zv.as_mut())
120 .filter_map(|zv| T::from_zval_mut(zv.dereference_mut()))
121 .collect()
122 }
123
124 #[allow(clippy::mut_mut)]
132 pub fn zval(&mut self) -> Option<&mut &'a mut Zval> {
133 self.zval.as_mut()
134 }
135
136 #[allow(clippy::inline_always)]
154 #[inline(always)]
155 pub fn try_call(&self, params: Vec<&dyn IntoZvalDyn>) -> Result<Zval> {
156 self.zval.as_ref().ok_or(Error::Callable)?.try_call(params)
157 }
158
159 pub(crate) fn as_arg_info(&self) -> Result<ArgInfo> {
161 Ok(ArgInfo {
162 name: CString::new(self.name.as_str())?.into_raw(),
163 type_: ZendType::empty_from_type(
164 self.r#type,
165 self.as_ref,
166 self.variadic,
167 self.allow_null,
168 )
169 .ok_or(Error::InvalidCString)?,
170 default_value: match &self.default_value {
171 Some(val) if val.as_str() == "None" => CString::new("null")?.into_raw(),
172 Some(val) => CString::new(val.as_str())?.into_raw(),
173 None => ptr::null(),
174 },
175 })
176 }
177}
178
179impl From<Arg<'_>> for _zend_expected_type {
180 fn from(arg: Arg) -> Self {
181 let type_id = match arg.r#type {
182 DataType::False | DataType::True => _zend_expected_type_Z_EXPECTED_BOOL,
183 DataType::Long => _zend_expected_type_Z_EXPECTED_LONG,
184 DataType::Double => _zend_expected_type_Z_EXPECTED_DOUBLE,
185 DataType::String => _zend_expected_type_Z_EXPECTED_STRING,
186 DataType::Array => _zend_expected_type_Z_EXPECTED_ARRAY,
187 DataType::Object(_) => _zend_expected_type_Z_EXPECTED_OBJECT,
188 DataType::Resource => _zend_expected_type_Z_EXPECTED_RESOURCE,
189 _ => unreachable!(),
190 };
191
192 if arg.allow_null {
193 type_id + 1
194 } else {
195 type_id
196 }
197 }
198}
199
200impl From<Arg<'_>> for Parameter {
201 fn from(val: Arg<'_>) -> Self {
202 Parameter {
203 name: val.name.into(),
204 ty: Some(val.r#type).into(),
205 nullable: val.allow_null,
206 variadic: val.variadic,
207 default: val.default_value.map(abi::RString::from).into(),
208 }
209 }
210}
211
212pub type ArgInfo = zend_internal_arg_info;
214
215#[must_use]
217pub struct ArgParser<'a, 'b> {
218 args: Vec<&'b mut Arg<'a>>,
219 min_num_args: Option<usize>,
220 arg_zvals: Vec<Option<&'a mut Zval>>,
221}
222
223impl<'a, 'b> ArgParser<'a, 'b> {
224 pub fn new(arg_zvals: Vec<Option<&'a mut Zval>>) -> Self {
226 ArgParser {
227 args: vec![],
228 min_num_args: None,
229 arg_zvals,
230 }
231 }
232
233 pub fn arg(mut self, arg: &'b mut Arg<'a>) -> Self {
239 self.args.push(arg);
240 self
241 }
242
243 pub fn not_required(mut self) -> Self {
245 self.min_num_args = Some(self.args.len());
246 self
247 }
248
249 pub fn parse(mut self) -> Result<()> {
269 let max_num_args = self.args.len();
270 let mut min_num_args = self.min_num_args.unwrap_or(max_num_args);
271 let num_args = self.arg_zvals.len();
272 let has_variadic = self.args.last().is_some_and(|arg| arg.variadic);
273 if has_variadic {
274 min_num_args = min_num_args.saturating_sub(1);
275 }
276
277 if num_args < min_num_args || (!has_variadic && num_args > max_num_args) {
278 unsafe {
281 zend_wrong_parameters_count_error(
282 min_num_args.try_into()?,
283 max_num_args.try_into()?,
284 );
285 };
286 return Err(Error::IncorrectArguments(num_args, min_num_args));
287 }
288
289 for (i, arg_zval) in self.arg_zvals.into_iter().enumerate() {
290 let arg = match self.args.get_mut(i) {
291 Some(arg) => Some(arg),
292 None => self.args.last_mut().filter(|arg| arg.variadic),
294 };
295 if let Some(arg) = arg {
296 if arg.variadic {
297 arg.variadic_zvals.push(arg_zval);
298 } else {
299 arg.zval = arg_zval;
300 }
301 }
302 }
303
304 Ok(())
305 }
306}
307
308#[cfg(test)]
309mod tests {
310 #![allow(clippy::unwrap_used)]
311 #[cfg(feature = "embed")]
312 use crate::embed::Embed;
313
314 use super::*;
315
316 #[test]
317 fn test_new() {
318 let arg = Arg::new("test", DataType::Long);
319 assert_eq!(arg.name, "test");
320 assert_eq!(arg.r#type, DataType::Long);
321 assert!(!arg.as_ref);
322 assert!(!arg.allow_null);
323 assert!(!arg.variadic);
324 assert!(arg.default_value.is_none());
325 assert!(arg.zval.is_none());
326 assert!(arg.variadic_zvals.is_empty());
327 }
328
329 #[test]
330 fn test_as_ref() {
331 let arg = Arg::new("test", DataType::Long).as_ref();
332 assert!(arg.as_ref);
333 }
334
335 #[test]
336 fn test_is_variadic() {
337 let arg = Arg::new("test", DataType::Long).is_variadic();
338 assert!(arg.variadic);
339 }
340
341 #[test]
342 fn test_allow_null() {
343 let arg = Arg::new("test", DataType::Long).allow_null();
344 assert!(arg.allow_null);
345 }
346
347 #[test]
348 fn test_default() {
349 let arg = Arg::new("test", DataType::Long).default("default");
350 assert_eq!(arg.default_value, Some("default".to_string()));
351
352 }
354
355 #[test]
356 fn test_consume_no_value() {
357 let arg = Arg::new("test", DataType::Long);
358 let result: Result<i32, _> = arg.consume();
359 assert!(result.is_err());
360 assert_eq!(result.unwrap_err().name, "test");
361 }
362
363 #[test]
364 #[cfg(feature = "embed")]
365 fn test_consume() {
366 let mut arg = Arg::new("test", DataType::Long);
367 let mut zval = Zval::from(42);
368 arg.zval = Some(&mut zval);
369
370 let result: Result<i32, _> = arg.consume();
371 assert_eq!(result.unwrap(), 42);
372 }
373
374 #[test]
375 fn test_val_no_value() {
376 let mut arg = Arg::new("test", DataType::Long);
377 let result: Option<i32> = arg.val();
378 assert!(result.is_none());
379 }
380
381 #[test]
382 #[cfg(feature = "embed")]
383 fn test_val() {
384 let mut arg = Arg::new("test", DataType::Long);
385 let mut zval = Zval::from(42);
386 arg.zval = Some(&mut zval);
387
388 let result: Option<i32> = arg.val();
389 assert_eq!(result.unwrap(), 42);
390 }
391
392 #[test]
393 #[cfg(feature = "embed")]
394 fn test_variadic_vals() {
395 let mut arg = Arg::new("test", DataType::Long).is_variadic();
396 let mut zval1 = Zval::from(42);
397 let mut zval2 = Zval::from(43);
398 arg.variadic_zvals.push(Some(&mut zval1));
399 arg.variadic_zvals.push(Some(&mut zval2));
400
401 let result: Vec<i32> = arg.variadic_vals();
402 assert_eq!(result, vec![42, 43]);
403 }
404
405 #[test]
406 fn test_zval_no_value() {
407 let mut arg = Arg::new("test", DataType::Long);
408 let result = arg.zval();
409 assert!(result.is_none());
410 }
411
412 #[test]
413 #[cfg(feature = "embed")]
414 fn test_zval() {
415 let mut arg = Arg::new("test", DataType::Long);
416 let mut zval = Zval::from(42);
417 arg.zval = Some(&mut zval);
418
419 let result = arg.zval();
420 assert!(result.is_some());
421 assert_eq!(result.unwrap().dereference_mut().long(), Some(42));
422 }
423
424 #[cfg(feature = "embed")]
425 #[test]
426 fn test_try_call_no_value() {
427 let arg = Arg::new("test", DataType::Long);
428 let result = arg.try_call(vec![]);
429 assert!(result.is_err());
430 }
431
432 #[test]
433 #[cfg(feature = "embed")]
434 fn test_try_call_not_callable() {
435 Embed::run(|| {
436 let mut arg = Arg::new("test", DataType::Long);
437 let mut zval = Zval::from(42);
438 arg.zval = Some(&mut zval);
439
440 let result = arg.try_call(vec![]);
441 assert!(result.is_err());
442 });
443 }
444
445 #[test]
448 #[cfg(feature = "embed")]
449 fn test_as_arg_info() {
450 let arg = Arg::new("test", DataType::Long);
451 let arg_info = arg.as_arg_info();
452 assert!(arg_info.is_ok());
453
454 let arg_info = arg_info.unwrap();
455 assert!(arg_info.default_value.is_null());
456
457 let r#type = arg_info.type_;
458 assert_eq!(r#type.type_mask, 16);
459 }
460
461 #[test]
462 #[cfg(feature = "embed")]
463 fn test_as_arg_info_with_default() {
464 let arg = Arg::new("test", DataType::Long).default("default");
465 let arg_info = arg.as_arg_info();
466 assert!(arg_info.is_ok());
467
468 let arg_info = arg_info.unwrap();
469 assert!(!arg_info.default_value.is_null());
470
471 let r#type = arg_info.type_;
472 assert_eq!(r#type.type_mask, 16);
473 }
474
475 #[test]
476 fn test_type_from_arg() {
477 let arg = Arg::new("test", DataType::Long);
478 let actual: _zend_expected_type = arg.into();
479 assert_eq!(actual, 0);
480
481 let arg = Arg::new("test", DataType::Long).allow_null();
482 let actual: _zend_expected_type = arg.into();
483 assert_eq!(actual, 1);
484
485 let arg = Arg::new("test", DataType::False);
486 let actual: _zend_expected_type = arg.into();
487 assert_eq!(actual, 2);
488
489 let arg = Arg::new("test", DataType::False).allow_null();
490 let actual: _zend_expected_type = arg.into();
491 assert_eq!(actual, 3);
492
493 let arg = Arg::new("test", DataType::True);
494 let actual: _zend_expected_type = arg.into();
495 assert_eq!(actual, 2);
496
497 let arg = Arg::new("test", DataType::True).allow_null();
498 let actual: _zend_expected_type = arg.into();
499 assert_eq!(actual, 3);
500
501 let arg = Arg::new("test", DataType::String);
502 let actual: _zend_expected_type = arg.into();
503 assert_eq!(actual, 4);
504
505 let arg = Arg::new("test", DataType::String).allow_null();
506 let actual: _zend_expected_type = arg.into();
507 assert_eq!(actual, 5);
508
509 let arg = Arg::new("test", DataType::Array);
510 let actual: _zend_expected_type = arg.into();
511 assert_eq!(actual, 6);
512
513 let arg = Arg::new("test", DataType::Array).allow_null();
514 let actual: _zend_expected_type = arg.into();
515 assert_eq!(actual, 7);
516
517 let arg = Arg::new("test", DataType::Resource);
518 let actual: _zend_expected_type = arg.into();
519 assert_eq!(actual, 14);
520
521 let arg = Arg::new("test", DataType::Resource).allow_null();
522 let actual: _zend_expected_type = arg.into();
523 assert_eq!(actual, 15);
524
525 let arg = Arg::new("test", DataType::Object(None));
526 let actual: _zend_expected_type = arg.into();
527 assert_eq!(actual, 18);
528
529 let arg = Arg::new("test", DataType::Object(None)).allow_null();
530 let actual: _zend_expected_type = arg.into();
531 assert_eq!(actual, 19);
532
533 let arg = Arg::new("test", DataType::Double);
534 let actual: _zend_expected_type = arg.into();
535 assert_eq!(actual, 20);
536
537 let arg = Arg::new("test", DataType::Double).allow_null();
538 let actual: _zend_expected_type = arg.into();
539 assert_eq!(actual, 21);
540 }
541
542 #[test]
543 fn test_param_from_arg() {
544 let arg = Arg::new("test", DataType::Long)
545 .default("default")
546 .allow_null();
547 let param: Parameter = arg.into();
548 assert_eq!(param.name, "test".into());
549 assert_eq!(param.ty, abi::Option::Some(DataType::Long));
550 assert!(param.nullable);
551 assert_eq!(param.default, abi::Option::Some("default".into()));
552 }
553
554 #[test]
555 fn test_arg_parser_new() {
556 let arg_zvals = vec![None, None];
557 let parser = ArgParser::new(arg_zvals);
558 assert_eq!(parser.arg_zvals.len(), 2);
559 assert!(parser.args.is_empty());
560 assert!(parser.min_num_args.is_none());
561 }
562
563 #[test]
564 fn test_arg_parser_arg() {
565 let arg_zvals = vec![None, None];
566 let mut parser = ArgParser::new(arg_zvals);
567 let mut arg = Arg::new("test", DataType::Long);
568 parser = parser.arg(&mut arg);
569 assert_eq!(parser.args.len(), 1);
570 assert_eq!(parser.args[0].name, "test");
571 assert_eq!(parser.args[0].r#type, DataType::Long);
572 }
573
574 }