mirror of
https://github.com/danog/ext-php-rs.git
synced 2024-11-30 04:39:04 +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 ty: String,
|
||||||
pub nullable: bool,
|
pub nullable: bool,
|
||||||
pub default: Option<String>,
|
pub default: Option<String>,
|
||||||
|
pub as_ref: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -249,12 +250,19 @@ pub fn get_return_type(output_type: &ReturnType) -> Result<Option<(String, bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Arg {
|
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 {
|
Self {
|
||||||
name,
|
name,
|
||||||
ty,
|
ty,
|
||||||
nullable,
|
nullable,
|
||||||
default,
|
default,
|
||||||
|
as_ref,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +276,7 @@ impl Arg {
|
|||||||
match ty {
|
match ty {
|
||||||
Type::Path(TypePath { path, .. }) => {
|
Type::Path(TypePath { path, .. }) => {
|
||||||
let mut path = path.clone();
|
let mut path = path.clone();
|
||||||
|
let mut pass_by_ref = false;
|
||||||
path.drop_lifetimes();
|
path.drop_lifetimes();
|
||||||
|
|
||||||
let seg = path.segments.last()?;
|
let seg = path.segments.last()?;
|
||||||
@ -283,9 +292,45 @@ impl Arg {
|
|||||||
None
|
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 {
|
let stringified = match result {
|
||||||
Some(result) if is_return => 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(
|
Some(Arg::new(
|
||||||
@ -293,6 +338,7 @@ impl Arg {
|
|||||||
stringified,
|
stringified,
|
||||||
seg.ident == "Option" || default.is_some(),
|
seg.ident == "Option" || default.is_some(),
|
||||||
default,
|
default,
|
||||||
|
pass_by_ref,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Type::Reference(ref_) => {
|
Type::Reference(ref_) => {
|
||||||
@ -302,6 +348,7 @@ impl Arg {
|
|||||||
ref_.to_token_stream().to_string(),
|
ref_.to_token_stream().to_string(),
|
||||||
false,
|
false,
|
||||||
default,
|
default,
|
||||||
|
ref_.mutability.is_some(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -361,6 +408,7 @@ impl Arg {
|
|||||||
let ty = self.get_type_ident();
|
let ty = self.get_type_ident();
|
||||||
|
|
||||||
let null = self.nullable.then(|| quote! { .allow_null() });
|
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| {
|
let default = self.default.as_ref().map(|val| {
|
||||||
quote! {
|
quote! {
|
||||||
.default(#val)
|
.default(#val)
|
||||||
@ -368,7 +416,7 @@ impl Arg {
|
|||||||
});
|
});
|
||||||
|
|
||||||
quote! {
|
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(true)); // string(4) "Yes!"
|
||||||
var_dump(test_bool(false)); // string(3) "No!"
|
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