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