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