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) => CString::new(val.as_str())?.into_raw(),
172 None => ptr::null(),
173 },
174 })
175 }
176}
177
178impl From<Arg<'_>> for _zend_expected_type {
179 fn from(arg: Arg) -> Self {
180 let type_id = match arg.r#type {
181 DataType::False | DataType::True => _zend_expected_type_Z_EXPECTED_BOOL,
182 DataType::Long => _zend_expected_type_Z_EXPECTED_LONG,
183 DataType::Double => _zend_expected_type_Z_EXPECTED_DOUBLE,
184 DataType::String => _zend_expected_type_Z_EXPECTED_STRING,
185 DataType::Array => _zend_expected_type_Z_EXPECTED_ARRAY,
186 DataType::Object(_) => _zend_expected_type_Z_EXPECTED_OBJECT,
187 DataType::Resource => _zend_expected_type_Z_EXPECTED_RESOURCE,
188 _ => unreachable!(),
189 };
190
191 if arg.allow_null {
192 type_id + 1
193 } else {
194 type_id
195 }
196 }
197}
198
199impl From<Arg<'_>> for Parameter {
200 fn from(val: Arg<'_>) -> Self {
201 Parameter {
202 name: val.name.into(),
203 ty: Some(val.r#type).into(),
204 nullable: val.allow_null,
205 default: val.default_value.map(abi::RString::from).into(),
206 }
207 }
208}
209
210pub type ArgInfo = zend_internal_arg_info;
212
213#[must_use]
215pub struct ArgParser<'a, 'b> {
216 args: Vec<&'b mut Arg<'a>>,
217 min_num_args: Option<usize>,
218 arg_zvals: Vec<Option<&'a mut Zval>>,
219}
220
221impl<'a, 'b> ArgParser<'a, 'b> {
222 pub fn new(arg_zvals: Vec<Option<&'a mut Zval>>) -> Self {
224 ArgParser {
225 args: vec![],
226 min_num_args: None,
227 arg_zvals,
228 }
229 }
230
231 pub fn arg(mut self, arg: &'b mut Arg<'a>) -> Self {
237 self.args.push(arg);
238 self
239 }
240
241 pub fn not_required(mut self) -> Self {
243 self.min_num_args = Some(self.args.len());
244 self
245 }
246
247 pub fn parse(mut self) -> Result<()> {
267 let max_num_args = self.args.len();
268 let mut min_num_args = self.min_num_args.unwrap_or(max_num_args);
269 let num_args = self.arg_zvals.len();
270 let has_variadic = self.args.last().is_some_and(|arg| arg.variadic);
271 if has_variadic {
272 min_num_args = min_num_args.saturating_sub(1);
273 }
274
275 if num_args < min_num_args || (!has_variadic && num_args > max_num_args) {
276 unsafe {
279 zend_wrong_parameters_count_error(
280 min_num_args.try_into()?,
281 max_num_args.try_into()?,
282 );
283 };
284 return Err(Error::IncorrectArguments(num_args, min_num_args));
285 }
286
287 for (i, arg_zval) in self.arg_zvals.into_iter().enumerate() {
288 let arg = match self.args.get_mut(i) {
289 Some(arg) => Some(arg),
290 None => self.args.last_mut().filter(|arg| arg.variadic),
292 };
293 if let Some(arg) = arg {
294 if arg.variadic {
295 arg.variadic_zvals.push(arg_zval);
296 } else {
297 arg.zval = arg_zval;
298 }
299 }
300 }
301
302 Ok(())
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 #![allow(clippy::unwrap_used)]
309 #[cfg(feature = "embed")]
310 use crate::embed::Embed;
311
312 use super::*;
313
314 #[test]
315 fn test_new() {
316 let arg = Arg::new("test", DataType::Long);
317 assert_eq!(arg.name, "test");
318 assert_eq!(arg.r#type, DataType::Long);
319 assert!(!arg.as_ref);
320 assert!(!arg.allow_null);
321 assert!(!arg.variadic);
322 assert!(arg.default_value.is_none());
323 assert!(arg.zval.is_none());
324 assert!(arg.variadic_zvals.is_empty());
325 }
326
327 #[test]
328 fn test_as_ref() {
329 let arg = Arg::new("test", DataType::Long).as_ref();
330 assert!(arg.as_ref);
331 }
332
333 #[test]
334 fn test_is_variadic() {
335 let arg = Arg::new("test", DataType::Long).is_variadic();
336 assert!(arg.variadic);
337 }
338
339 #[test]
340 fn test_allow_null() {
341 let arg = Arg::new("test", DataType::Long).allow_null();
342 assert!(arg.allow_null);
343 }
344
345 #[test]
346 fn test_default() {
347 let arg = Arg::new("test", DataType::Long).default("default");
348 assert_eq!(arg.default_value, Some("default".to_string()));
349
350 }
352
353 #[test]
354 fn test_consume_no_value() {
355 let arg = Arg::new("test", DataType::Long);
356 let result: Result<i32, _> = arg.consume();
357 assert!(result.is_err());
358 assert_eq!(result.unwrap_err().name, "test");
359 }
360
361 #[test]
362 #[cfg(feature = "embed")]
363 fn test_consume() {
364 let mut arg = Arg::new("test", DataType::Long);
365 let mut zval = Zval::from(42);
366 arg.zval = Some(&mut zval);
367
368 let result: Result<i32, _> = arg.consume();
369 assert_eq!(result.unwrap(), 42);
370 }
371
372 #[test]
373 fn test_val_no_value() {
374 let mut arg = Arg::new("test", DataType::Long);
375 let result: Option<i32> = arg.val();
376 assert!(result.is_none());
377 }
378
379 #[test]
380 #[cfg(feature = "embed")]
381 fn test_val() {
382 let mut arg = Arg::new("test", DataType::Long);
383 let mut zval = Zval::from(42);
384 arg.zval = Some(&mut zval);
385
386 let result: Option<i32> = arg.val();
387 assert_eq!(result.unwrap(), 42);
388 }
389
390 #[test]
391 #[cfg(feature = "embed")]
392 fn test_variadic_vals() {
393 let mut arg = Arg::new("test", DataType::Long).is_variadic();
394 let mut zval1 = Zval::from(42);
395 let mut zval2 = Zval::from(43);
396 arg.variadic_zvals.push(Some(&mut zval1));
397 arg.variadic_zvals.push(Some(&mut zval2));
398
399 let result: Vec<i32> = arg.variadic_vals();
400 assert_eq!(result, vec![42, 43]);
401 }
402
403 #[test]
404 fn test_zval_no_value() {
405 let mut arg = Arg::new("test", DataType::Long);
406 let result = arg.zval();
407 assert!(result.is_none());
408 }
409
410 #[test]
411 #[cfg(feature = "embed")]
412 fn test_zval() {
413 let mut arg = Arg::new("test", DataType::Long);
414 let mut zval = Zval::from(42);
415 arg.zval = Some(&mut zval);
416
417 let result = arg.zval();
418 assert!(result.is_some());
419 assert_eq!(result.unwrap().dereference_mut().long(), Some(42));
420 }
421
422 #[test]
423 fn test_try_call_no_value() {
424 let arg = Arg::new("test", DataType::Long);
425 let result = arg.try_call(vec![]);
426 assert!(result.is_err());
427 }
428
429 #[test]
430 #[cfg(feature = "embed")]
431 fn test_try_call_not_callable() {
432 Embed::run(|| {
433 let mut arg = Arg::new("test", DataType::Long);
434 let mut zval = Zval::from(42);
435 arg.zval = Some(&mut zval);
436
437 let result = arg.try_call(vec![]);
438 assert!(result.is_err());
439 });
440 }
441
442 #[test]
445 #[cfg(feature = "embed")]
446 fn test_as_arg_info() {
447 let arg = Arg::new("test", DataType::Long);
448 let arg_info = arg.as_arg_info();
449 assert!(arg_info.is_ok());
450
451 let arg_info = arg_info.unwrap();
452 assert!(arg_info.default_value.is_null());
453
454 let r#type = arg_info.type_;
455 assert_eq!(r#type.type_mask, 16);
456 }
457
458 #[test]
459 #[cfg(feature = "embed")]
460 fn test_as_arg_info_with_default() {
461 let arg = Arg::new("test", DataType::Long).default("default");
462 let arg_info = arg.as_arg_info();
463 assert!(arg_info.is_ok());
464
465 let arg_info = arg_info.unwrap();
466 assert!(!arg_info.default_value.is_null());
467
468 let r#type = arg_info.type_;
469 assert_eq!(r#type.type_mask, 16);
470 }
471
472 #[test]
473 fn test_type_from_arg() {
474 let arg = Arg::new("test", DataType::Long);
475 let actual: _zend_expected_type = arg.into();
476 assert_eq!(actual, 0);
477
478 let arg = Arg::new("test", DataType::Long).allow_null();
479 let actual: _zend_expected_type = arg.into();
480 assert_eq!(actual, 1);
481
482 let arg = Arg::new("test", DataType::False);
483 let actual: _zend_expected_type = arg.into();
484 assert_eq!(actual, 2);
485
486 let arg = Arg::new("test", DataType::False).allow_null();
487 let actual: _zend_expected_type = arg.into();
488 assert_eq!(actual, 3);
489
490 let arg = Arg::new("test", DataType::True);
491 let actual: _zend_expected_type = arg.into();
492 assert_eq!(actual, 2);
493
494 let arg = Arg::new("test", DataType::True).allow_null();
495 let actual: _zend_expected_type = arg.into();
496 assert_eq!(actual, 3);
497
498 let arg = Arg::new("test", DataType::String);
499 let actual: _zend_expected_type = arg.into();
500 assert_eq!(actual, 4);
501
502 let arg = Arg::new("test", DataType::String).allow_null();
503 let actual: _zend_expected_type = arg.into();
504 assert_eq!(actual, 5);
505
506 let arg = Arg::new("test", DataType::Array);
507 let actual: _zend_expected_type = arg.into();
508 assert_eq!(actual, 6);
509
510 let arg = Arg::new("test", DataType::Array).allow_null();
511 let actual: _zend_expected_type = arg.into();
512 assert_eq!(actual, 7);
513
514 let arg = Arg::new("test", DataType::Resource);
515 let actual: _zend_expected_type = arg.into();
516 assert_eq!(actual, 14);
517
518 let arg = Arg::new("test", DataType::Resource).allow_null();
519 let actual: _zend_expected_type = arg.into();
520 assert_eq!(actual, 15);
521
522 let arg = Arg::new("test", DataType::Object(None));
523 let actual: _zend_expected_type = arg.into();
524 assert_eq!(actual, 18);
525
526 let arg = Arg::new("test", DataType::Object(None)).allow_null();
527 let actual: _zend_expected_type = arg.into();
528 assert_eq!(actual, 19);
529
530 let arg = Arg::new("test", DataType::Double);
531 let actual: _zend_expected_type = arg.into();
532 assert_eq!(actual, 20);
533
534 let arg = Arg::new("test", DataType::Double).allow_null();
535 let actual: _zend_expected_type = arg.into();
536 assert_eq!(actual, 21);
537 }
538
539 #[test]
540 fn test_param_from_arg() {
541 let arg = Arg::new("test", DataType::Long)
542 .default("default")
543 .allow_null();
544 let param: Parameter = arg.into();
545 assert_eq!(param.name, "test".into());
546 assert_eq!(param.ty, abi::Option::Some(DataType::Long));
547 assert!(param.nullable);
548 assert_eq!(param.default, abi::Option::Some("default".into()));
549 }
550
551 #[test]
552 fn test_arg_parser_new() {
553 let arg_zvals = vec![None, None];
554 let parser = ArgParser::new(arg_zvals);
555 assert_eq!(parser.arg_zvals.len(), 2);
556 assert!(parser.args.is_empty());
557 assert!(parser.min_num_args.is_none());
558 }
559
560 #[test]
561 fn test_arg_parser_arg() {
562 let arg_zvals = vec![None, None];
563 let mut parser = ArgParser::new(arg_zvals);
564 let mut arg = Arg::new("test", DataType::Long);
565 parser = parser.arg(&mut arg);
566 assert_eq!(parser.args.len(), 1);
567 assert_eq!(parser.args[0].name, "test");
568 assert_eq!(parser.args[0].r#type, DataType::Long);
569 }
570
571 }