-
Notifications
You must be signed in to change notification settings - Fork 331
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
Translating between Result ⟷ exceptions #53
Comments
I started putting together a design for the exception-to-Result direction of this. I'm trying to leave open the possibility of different codebases having different try-catch logic for extracting messages from exceptions, while still providing a reasonable default conversion. I think there will be a way for us to accommodate this with an expression SFINAE that looks like the following: struct trycatch {
template <typename T> trycatch(T);
static char use_default;
};
template <typename Try, typename Fail,
typename = decltype(trycatch(std::declval<Try>()).use_default)>
static void trycatch(Try &&func, Fail &&fail) noexcept try {
func();
} catch (const std::exception &e) {
fail(e.what());
} which we invoke in generated code roughly as: // union with the same layout as std::result::Result<T, cxx::Exception>
rust::Result<T> result;
trycatch(
[&] {
new (&result) rust::Result<T>(the_function(args...));
},
[&](rust::Exception e) noexcept {
new (&result) rust::Result<T>(std::move(e));
});
return result; In this implementation, CXX provides a default try-catch based on template <typename Try, typename Fail>
void trycatch(Try &&func, Fail &&fail) noexcept; Since our generated code includes the user's header before our default provided trycatch implementation, according to https://timsong-cpp.github.io/cppwp/basic.scope.hiding their trycatch function hides the dummy trycatch struct and the expression SFINAE makes our default provided one not exist. As an example in Folly's case the codebase might use this which provides more type information: template <typename Try, typename Fail>
static void trycatch(Try &&func, Fail &&fail) noexcept try {
func();
} catch (const std::exception &e) {
fail(folly::toStdString(folly::exceptionStr(e)));
} catch (...) {
fail("<unknown exception>");
} |
Currently we catch and abort on unwinding across the FFI boundary in either direction; it's left to the user to communicate all failures via ordinary return values or out-parameters.
It would be nice if C++ exceptions were exposed to Rust as an idiomatic
Result
error value. For C++ functions that are declared in the bridge as returning a Result, we would not abort on exceptions but instead marshal them across as some kind ofcxx::Exception
object.Conversely, Rust functions that are declared as returning a Result could transmit failures as an exception on the C++ side.
In both cases, long term we would want the translation to be customizable because not all codebases use exceptions; some would prefer a mapping of Rust
Result
to Leaf or Outcome. Some thoughts in #16.The text was updated successfully, but these errors were encountered: