Replies: 1 comment
-
👋 That is a good question indeed, thanks for bringing it up 🙂 Our current usage at ditto actually stumbled upon this very question too: we do use the thread-local pattern with some error codes returned (and out parameters), following the old-school C idioms; but this has made some generation of the FFI glue in the other side of the language cumbersome. We are thus planning on, at the very least, start adding a That being said, we are allowed to do this since the C API we use to cross the FFI boundary is completely internal, so there may be other patterns that require something else (that is, I can imagine you or somebody else really requiring that thread-local pattern). In that case, another option would be to have fn unwrap_into<T, E> (into: Out<'_, T>, result: Result<T, E>)
-> c_int
{
match result {
Ok(it) => { into.write(it); 0 },
Err(err) => { update_last_error(err); -1 },
}
}
#[ffi_export(result_handler = |result| unwrap_into(out, result))]
fn get_thing (…, out: Out<'_, Thing>)
-> c_int
{
let mut thing = try_get_thing(…)?;
something_else(&mut thing, …)?;
Ok(thing)
} That being said, I wonder if such mechanic would not be too magical, and that maybe the callers ought to wrap the function body themselves 🤔: macro_rules! try_ {( $($body:tt)* ) => (
(|| Ok({ $($body)* }))()
)}
#[ffi_export]
fn get_thing (…, out: Out<'_, Thing>)
-> c_int
{
unwrap_into(out, try_! {
// <- the cost of this less magical approach: extra rightward drift
let mut thing = try_get_thing(…)?;
something_else(&mut thing, …)?;
thing
})
} If you yourself (or any other person seeing this discussion) have ideas or suggestions in that regard, I'm all 👂s |
Beta Was this translation helpful? Give feedback.
-
👋🏼 Before I found this project, I hand-wrote some FFI wrappers around a Rust library (Apache Arrow) to be able to use from a Swift app. It was tedious and painful; the whole nasty mess (which I intend to convert to safer_ffi if I have the occasion) can be seen at https://github.com/parquette/arcolyte/blob/main/src/ffi.rs
One nice feature, though, is the ability to make the Rust error available to the calling environment by simply setting a thread-local string. So a Rust error can be converted into an idiomatic Swift error with too much agony:
https://github.com/parquette/Parquette/blob/afe6bb02494ba379eb4347ef74f8f7c3c33715d8/SwiftArrow/SwiftArrow.swift#L61-L79
Has there been any discussion or consideration of how error propagation might work in this project? I didn't see anything in the docs, and I don't see any open issues or discussion on the topic. It could be the case that a naïve mechanism such as the above would provide sufficient utility in many scenarios.
Beta Was this translation helpful? Give feedback.
All reactions