Skip to content

Design for custom exceptions #1186

Open
@schreter

Description

@schreter

In our project, we need to control which exceptions get thrown into C++ code from our Rust callbacks (i.e., it can't be rust::Error, not even std::exception, it has to be one of the project-specific exception types).

The PR #1180 already provides some basics to be able to handle custom errors using a callback into C++ to construct the exception (via ToCxxException trait). However, this is not sufficient, since we need to handle also "standard" exceptions like AllocError or std::io::Error to throw respective C++ exceptions.

One possible way would be to add ToCxxException for some standard Rust errors (which is probably desirable on its own), but due to the Rust type system, such implementations must reside in cxx crate. Adding the possibility to register callbacks to generate different exceptions for all these types would bloat the cxx crate unnecessarily.

The proposal is thus to simply leave this to the implementor of the higher layer functionality (i.e., our team in this case) to actually convert errors to C++ exceptions in an application-specific way.

In #1180, the default mapping is done using cxx::map_rust_error_to_cxx_exception macro. This currently only handles CxxException specially to allow for transparent passing of C++ exceptions through Rust frames. As mentioned, this could be extended for some standard exceptions.

However, to make this fully flexible, we can simply add an attribute with the path to the macro on the bridge/extern block/function (typically only on the bridge) to specify this mapping macro explicitly. Then, the bridge will generate the code to map the error to the exception in a user-specific way, avoiding bloat in the cxx crate.

The current working proposal is:

#[cxx::bridge(namespace = "my_crate")]
#[error_mapper = ::my_crate::map_rust_error_to_cxx_exception]
pub mod ffi {
   ...
}

where my_crate::map_rust_error_to_cxx_exception is a macro taking one ident or expr with the value of the Rust error and returning a cxx::CxxException object built for it. Since it's a macro, it can implement the semi-specialization trick via multiple trait impls shadowing each other in a deterministic way to handle some errors explicitly and some by a common fallback path, much like already done in the cxx crate.

We have the implementation already done in mere ~60 LOCs on top of #1180, but cannot publish it yet, since that PR is still pending.

Any further ideas/opinions/suggestions for the attribute name?

Thanks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions