mirror of
https://github.com/danog/ext-php-rs.git
synced 2024-11-26 12:04:53 +01:00
Merge pull request #230 from davidcole1340/function-arg-pass-by-ref
Support function args being passed by reference
This commit is contained in:
commit
4dd7b8ded5
@ -26,6 +26,7 @@ pub struct Arg {
|
||||
pub ty: String,
|
||||
pub nullable: bool,
|
||||
pub default: Option<String>,
|
||||
pub as_ref: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -249,12 +250,19 @@ pub fn get_return_type(output_type: &ReturnType) -> Result<Option<(String, bool)
|
||||
}
|
||||
|
||||
impl Arg {
|
||||
pub fn new(name: String, ty: String, nullable: bool, default: Option<String>) -> Self {
|
||||
pub fn new(
|
||||
name: String,
|
||||
ty: String,
|
||||
nullable: bool,
|
||||
default: Option<String>,
|
||||
as_ref: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
ty,
|
||||
nullable,
|
||||
default,
|
||||
as_ref,
|
||||
}
|
||||
}
|
||||
|
||||
@ -268,6 +276,7 @@ impl Arg {
|
||||
match ty {
|
||||
Type::Path(TypePath { path, .. }) => {
|
||||
let mut path = path.clone();
|
||||
let mut pass_by_ref = false;
|
||||
path.drop_lifetimes();
|
||||
|
||||
let seg = path.segments.last()?;
|
||||
@ -283,9 +292,45 @@ impl Arg {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
// For for types that are `Option<&mut T>` to turn them into `Option<&T>`,
|
||||
// marking the Arg as as "passed by reference".
|
||||
let option = Some(seg)
|
||||
.filter(|seg| seg.ident == "Option")
|
||||
.and_then(|seg| {
|
||||
if let PathArguments::AngleBracketed(args) = &seg.arguments {
|
||||
args.args
|
||||
.iter()
|
||||
.find(|arg| matches!(arg, GenericArgument::Type(_)))
|
||||
.map(|ga| {
|
||||
let new_ga = match ga {
|
||||
GenericArgument::Type(ty) => {
|
||||
let _rtype = match ty {
|
||||
Type::Reference(r) => {
|
||||
let mut new_ref = r.clone();
|
||||
new_ref.mutability = None;
|
||||
pass_by_ref = true;
|
||||
Type::Reference(new_ref)
|
||||
}
|
||||
_ => ty.clone(),
|
||||
};
|
||||
GenericArgument::Type(_rtype)
|
||||
}
|
||||
_ => ga.clone(),
|
||||
};
|
||||
new_ga.to_token_stream().to_string()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let stringified = match result {
|
||||
Some(result) if is_return => result,
|
||||
_ => path.to_token_stream().to_string(),
|
||||
_ => match option {
|
||||
Some(result) => result,
|
||||
None => path.to_token_stream().to_string(),
|
||||
},
|
||||
};
|
||||
|
||||
Some(Arg::new(
|
||||
@ -293,6 +338,7 @@ impl Arg {
|
||||
stringified,
|
||||
seg.ident == "Option" || default.is_some(),
|
||||
default,
|
||||
pass_by_ref,
|
||||
))
|
||||
}
|
||||
Type::Reference(ref_) => {
|
||||
@ -302,6 +348,7 @@ impl Arg {
|
||||
ref_.to_token_stream().to_string(),
|
||||
false,
|
||||
default,
|
||||
ref_.mutability.is_some(),
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
@ -361,6 +408,7 @@ impl Arg {
|
||||
let ty = self.get_type_ident();
|
||||
|
||||
let null = self.nullable.then(|| quote! { .allow_null() });
|
||||
let passed_by_ref = self.as_ref.then(|| quote! { .as_ref() });
|
||||
let default = self.default.as_ref().map(|val| {
|
||||
quote! {
|
||||
.default(#val)
|
||||
@ -368,7 +416,7 @@ impl Arg {
|
||||
});
|
||||
|
||||
quote! {
|
||||
::ext_php_rs::args::Arg::new(#name, #ty) #null #default
|
||||
::ext_php_rs::args::Arg::new(#name, #ty) #null #passed_by_ref #default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,3 +45,17 @@ pub fn test_bool(input: bool) -> String {
|
||||
var_dump(test_bool(true)); // string(4) "Yes!"
|
||||
var_dump(test_bool(false)); // string(3) "No!"
|
||||
```
|
||||
|
||||
## Rust example, taking by reference
|
||||
|
||||
```rust,no_run
|
||||
# #![cfg_attr(windows, feature(abi_vectorcall))]
|
||||
# extern crate ext_php_rs;
|
||||
# use ext_php_rs::prelude::*;
|
||||
# use ext_php_rs::types;
|
||||
#[php_function]
|
||||
pub fn test_bool(input: &mut types::Zval) {
|
||||
input.reference_mut().unwrap().set_bool(false);
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
Loading…
Reference in New Issue
Block a user