-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to handle mutable arguments? #95
Comments
Yes, this is the "out parameter" / "out reference" pattern, which thus involve the optional support for them that
The main API to write through an #[ffi_export]
fn api_func(error: Option<Out<'_, Error>>) {
if let Some(out_err) = err {
out_err.write(Error {
error_code: 0,
error_str: char_p::new("error"),
});
}
} Remark regarding
|
I'm going to close the issue since I consider that the usage of the optional |
Thanks for the detailed response, and sorry it took me so long to come up with a feedback. This was indeed very helpful — I did not notice To illustrate, I have a bunch of methods that may return #[ffi_export]
fn api_func(error: Option<Out<'_, Error>>) -> Option<usize> {
let x = returns_option().report_error("returns_option() failed", error)?;
let y = returns_result().report_error("returns_result() failed", error)?;
Some(x + y)
} and impl<T, E: Display> Reportable<T> for Result<T, E> {
fn report_error<'a>(self, message: &'a str, error: Option<Out<'a, Error>>) -> Option<T> {
match self {
Ok(value) => Some(value),
Err(err) => {
write_error(format!("{}: {}", message, err), error);
None
}
}
}
} where The way I see two ways out of this, both are not completely satisfactory. Explicit: make #[ffi_export]
fn api_func(error: Option<Out<'_, Error>>) -> Option<usize> {
let (x, error) = returns_option().report_error("returns_option() failed", error)?;
let (y, error) = returns_result().report_error("returns_result() failed", error)?;
Some(x + y)
} This adds visual noise to the users of Macro: inline #[ffi_export]
fn api_func(error: Option<Out<'_, Error>>) -> Option<usize> {
let x = report_option!(returns_option(), "returns_option() failed", error);
let y = report_result!(returns_result(), "returns_result() failed", error);
Some(x + y)
} I consider macros the absolute last resort because they're hard to maintain and debug. And it makes the code too vague. Any ideas? |
ContextSo, the way to see With an fn example<T> (mut o: Option<&mut T>)
{
fn consumes_option<T> (_: Option<&mut T>)
{}
- consumes_option(o); /* would cause a `move` error on the next `consumes_option` */
+ consumes_option(o.as_deref_mut());
consumes_option(o);
} Obviously writing - fn consumes_option<T> (o: Option<&mut T>)
+ fn consumes_option_not<T> (o: &mut Option<&mut T>)
Well, in the case of All this thus yields: The fix #[ffi_export]
fn api_func(mut error: Option<Out<'_, Error>>) -> Option<usize> {
+ ^^^
let x = returns_option().report_error("returns_option() failed", &mut error)?;
+ ^^^^
let y = returns_result().report_error("returns_result() failed", &mut error)?;
+ ^^^^
Some(x + y)
}
impl<T, E: Display> Reportable<T> for Result<T, E> {
fn report_error<'a>(self, message: &'a str, error: &mut Option<Out<'a, Error>>) -> Option<T> {
+ ^^^^
match self {
Ok(value) => Some(value),
Err(err) => {
write_error(format!("{}: {}", message, err), error.as_mut().map(Out::reborrow));
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
None
}
}
}
}
AsideI don't think you should be repeating the lifetime parameter - fn report_error<'a>(self, message: &'a str, error: &'_ mut Option<Out<'a, Error>>) -> Option<T> {
+ fn report_error (self, message: &'_ str, error: &'_ mut Option<Out<'_, Error>>) -> Option<T> { |
Thanks for the explanation, this makes sense. There's one problem though, a declaration like
does not compile - I'm getting Edit: this can be avoided by having a Edit2: I've tried this solution, and it seems like it doesn't protect from reusing let x = returns_option().report_error("returns_option() failed", &mut error);
let y = returns_result().report_error("returns_result() failed", &mut error); (note the lack of question mark operators), and the compiler will not complain, even though the second call may rewrite the error and leak memory. |
The |
I want to add error reporting in my API along the lines of
(just an example,
api_func()
returns a result value too)I tried various approaches on the Rust side, but I cannot make it work; at best it compiles, but in runtime I get a
malloc: *** error for object <...>: pointer being freed was not allocated
error. For example, for this code:or for the example in #30. What is the correct way of doing it in
safer_ffi
? It seems that my problem is that I cannot figure out how to tell the compiler not to drop the newly created string.(Ideally I'd want the reference to be nullable, so that one could call
api_func(NULL)
in C, and the error reporting would be skipped, but I'll probably be able to deduce it)The text was updated successfully, but these errors were encountered: