Cex author here.
The cex crate simulates of checked exceptions in Rust, which can do this in the following way.
In Cargo.toml:
enumx = "0.4"
cex = "0.5"
use enumx::export::*;
use enumx::predefined::*;
use cex::*;
#[cex]
fn do_stuff() -> Result!( () throws Err1, Err2 ) {
ret!(());
}
#[cex]
fn do_other_stuff() -> Result!( () throws Err1, Err2, Err3 ) {
do_stuff()?;
ret!(());
}
The polyerror
crate chooses the "error-per-function" strategy, which is adopted by some previous version of cex. The code above could be written as:
cex! {
fn do_stuff() -> ()
throws Foo(Err1)
, Bar(Err2)
{
Ok(())
}
}
cex! {
fn do_other_stuff() -> ()
throws Foo(Err1)
, Bar(Err2)
, Baz(Err3)
{
do_stuff()?;
Ok(())
}
}
The cex!{}
macro will produce enum do_stuff::Err
and enum do_other_stuff::Err
for do_stuff()
and do_other_stuff()
.
But I changed my mind and gave up the "one-error-per-function" strategy in newer versions of cex. Because I noticed a fact that in a library, series of functions may throw the same set of errors, so "one-error-per-function" strategy is only used to track the source of errors which can be done by cex's "logging" mechanism.
Now, the cex
library supports even more functionality.
-
You can call
do_other_stuff()
insidedo_stuff()
while propagating errors is still convenient. Notice that the former throws less errors than the latter.#[cex] fn do_stuff() -> Result!( () throws Err1, Err2 ) { do_other_stuff() .or_else( |err| #[ty_pat(gen_throws)] match err { Err3(_) => /* deal with this error */, }) } #[cex] fn do_other_stuff() -> Result!( () throws Err1, Err2, Err3 ) { ret!(()); }
-
Checked exceptions can fallback as
impl std::error::Error
or any other traits.#[cex] fn do_stuff() -> Result!( () throws Err1, Err2 ) { ret!(()); } fn downstream_api() -> Result<(), impl std::error::Error> { Ok( do_stuff()? ) }
@john01dav I'm sorry to introduce cex
in your crate's announcement, but many people seems to hate checked exceptions and did not want to discuss in my previous post.