mirror of
https://github.com/danog/ext-php-rs.git
synced 2025-01-22 13:01:24 +01:00
Automatically check for optional parameters
No longer need to annotate the optional parameter
This commit is contained in:
parent
b1787ebd0a
commit
07e8d32538
@ -55,8 +55,9 @@ pub fn parser(args: AttributeArgs, input: ItemFn) -> Result<(TokenStream, Functi
|
||||
Span::call_site(),
|
||||
);
|
||||
let args = build_args(inputs, &attr_args.defaults)?;
|
||||
let optional = find_optional_parameter(args.iter(), attr_args.optional);
|
||||
let arg_definitions = build_arg_definitions(&args);
|
||||
let arg_parser = build_arg_parser(args.iter(), &attr_args.optional)?;
|
||||
let arg_parser = build_arg_parser(args.iter(), &optional)?;
|
||||
let arg_accessors = build_arg_accessors(&args);
|
||||
|
||||
let return_handler = build_return_handler(output);
|
||||
@ -88,7 +89,7 @@ pub fn parser(args: AttributeArgs, input: ItemFn) -> Result<(TokenStream, Functi
|
||||
name: ident.to_string(),
|
||||
ident: internal_ident.to_string(),
|
||||
args,
|
||||
optional: attr_args.optional,
|
||||
optional,
|
||||
output: return_type,
|
||||
};
|
||||
|
||||
@ -131,6 +132,27 @@ fn build_arg_definitions(args: &[Arg]) -> Vec<TokenStream> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn find_optional_parameter<'a>(
|
||||
args: impl DoubleEndedIterator<Item = &'a Arg>,
|
||||
optional: Option<String>,
|
||||
) -> Option<String> {
|
||||
if optional.is_some() {
|
||||
return optional;
|
||||
}
|
||||
|
||||
let mut optional = None;
|
||||
|
||||
for arg in args.rev() {
|
||||
if arg.nullable {
|
||||
optional.replace(arg.name.clone());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
optional
|
||||
}
|
||||
|
||||
pub fn build_arg_parser<'a>(
|
||||
args: impl Iterator<Item = &'a Arg>,
|
||||
optional: &Option<String>,
|
||||
@ -284,7 +306,12 @@ impl Arg {
|
||||
_ => path.to_token_stream().to_string(),
|
||||
};
|
||||
|
||||
Some(Arg::new(name, &stringified, seg.ident == "Option", default))
|
||||
Some(Arg::new(
|
||||
name,
|
||||
&stringified,
|
||||
seg.ident == "Option" || default.is_some(),
|
||||
default,
|
||||
))
|
||||
}
|
||||
Type::Reference(ref_) => {
|
||||
// Returning references is invalid, so let's just create our arg
|
||||
|
@ -59,6 +59,13 @@ pub fn parser(input: &mut ImplItemMethod) -> Result<(TokenStream, Method)> {
|
||||
|
||||
let internal_ident = Ident::new(&format!("_internal_php_{}", ident), Span::call_site());
|
||||
let args = build_args(inputs, &defaults)?;
|
||||
let optional = function::find_optional_parameter(
|
||||
args.iter().filter_map(|arg| match arg {
|
||||
Arg::Typed(arg) => Some(arg),
|
||||
_ => None,
|
||||
}),
|
||||
optional,
|
||||
);
|
||||
let (arg_definitions, is_static) = build_arg_definitions(&args);
|
||||
let arg_parser = build_arg_parser(args.iter(), &optional)?;
|
||||
let arg_accessors = build_arg_accessors(&args);
|
||||
|
@ -8,15 +8,15 @@ return types.
|
||||
|
||||
## Optional parameters
|
||||
|
||||
Optional parameters can be used by setting the Rust parameter type to
|
||||
`Option<T>` and then passing the name of the first optional parameter into the
|
||||
macro options. Note that all parameters after the given parameter will be
|
||||
optional as well, and therefore must be of the type `Option<T>`.
|
||||
Optional parameters can be used by setting the Rust parameter type to a variant
|
||||
of `Option<T>`. The macro will then figure out which parameters are optional by
|
||||
using the last consecutive arguments that are a variant of `Option<T>` or have a
|
||||
default value.
|
||||
|
||||
```rust
|
||||
# extern crate ext_php_rs;
|
||||
# use ext_php_rs::prelude::*;
|
||||
#[php_function(optional = "age")]
|
||||
#[php_function]
|
||||
pub fn greet(name: String, age: Option<i32>) -> String {
|
||||
let mut greeting = format!("Hello, {}!", name);
|
||||
|
||||
@ -35,13 +35,59 @@ default, it does not need to be a variant of `Option`:
|
||||
```rust
|
||||
# extern crate ext_php_rs;
|
||||
# use ext_php_rs::prelude::*;
|
||||
#[php_function(optional = "offset", defaults(offset = 0))]
|
||||
#[php_function(defaults(offset = 0))]
|
||||
pub fn rusty_strpos(haystack: &str, needle: &str, offset: i64) -> Option<usize> {
|
||||
let haystack: String = haystack.chars().skip(offset as usize).collect();
|
||||
haystack.find(needle)
|
||||
}
|
||||
```
|
||||
|
||||
Note that if there is a non-optional argument after an argument that is a
|
||||
variant of `Option<T>`, the `Option<T>` argument will be deemed a nullable
|
||||
argument rather than an optional argument.
|
||||
|
||||
```rust
|
||||
# extern crate ext_php_rs;
|
||||
# use ext_php_rs::prelude::*;
|
||||
/// `age` will be deemed required and nullable rather than optional.
|
||||
#[php_function]
|
||||
pub fn greet(name: String, age: Option<i32>, description: String) -> String {
|
||||
let mut greeting = format!("Hello, {}!", name);
|
||||
|
||||
if let Some(age) = age {
|
||||
greeting += &format!(" You are {} years old.", age);
|
||||
}
|
||||
|
||||
greeting += &format!(" {}.", description);
|
||||
greeting
|
||||
}
|
||||
```
|
||||
|
||||
You can also specify the optional arguments if you want to have nullable
|
||||
arguments before optional arguments. This is done through an attribute
|
||||
parameter:
|
||||
|
||||
```rust
|
||||
# extern crate ext_php_rs;
|
||||
# use ext_php_rs::prelude::*;
|
||||
/// `age` will be deemed required and nullable rather than optional,
|
||||
/// while description will be optional.
|
||||
#[php_function(optional = "description")]
|
||||
pub fn greet(name: String, age: Option<i32>, description: Option<String>) -> String {
|
||||
let mut greeting = format!("Hello, {}!", name);
|
||||
|
||||
if let Some(age) = age {
|
||||
greeting += &format!(" You are {} years old.", age);
|
||||
}
|
||||
|
||||
if let Some(description) = description {
|
||||
greeting += &format!(" {}.", description);
|
||||
}
|
||||
|
||||
greeting
|
||||
}
|
||||
```
|
||||
|
||||
## Throwing exceptions
|
||||
|
||||
Exceptions can be thrown from inside a function which returns a `Result<T, E>`,
|
||||
|
@ -27,6 +27,9 @@ attributes:
|
||||
- `#[public]`, `#[protected]` and `#[private]` - Sets the visibility of the
|
||||
method.
|
||||
|
||||
The `#[defaults]` and `#[optional]` attributes operate the same as the
|
||||
equivalent function attribute parameters.
|
||||
|
||||
## Constants
|
||||
|
||||
Constants are defined as regular Rust `impl` constants. Any type that implements
|
||||
|
Loading…
x
Reference in New Issue
Block a user