risingwave_common::error::thiserror_ext

Derive Macro Box

#[derive(Box)]
{
    // Attributes available to this derive:
    #[thiserror_ext]
}
Expand description

Generates a new type that wraps the original error type in a [struct@Box].

Specify the name of the new type with #[thiserror_ext(newtype(name = ..))].

§Reduce size

The most common motivation for using this macro is to reduce the size of the original error type. As a sum-type, a [Result] is at least as large as its largest variant. Large error type may hurt the performance of a function call returning a [Result]. With this macro, the new type always has the same size as a [struct@Box].

On the other hand, returning an error should be an exceptional case in most cases. Therefore, even though boxing the error type may lead to extra allocation, it’s usually acceptable.

§Example

#[derive(Debug, thiserror::Error, thiserror_ext::Box)]
#[thiserror_ext(newtype(name = Error))]
enum ErrorKind {
    #[error("foo")]
    Foo,
    #[error("io")]
    Io(#[from] std::io::Error),
}

// The size of `Error` is one pointer.
assert_eq!(std::mem::size_of::<Error>(), std::mem::size_of::<usize>());

// Convert to `Error`, from `ErrorKind` or other types that can be converted
// to `ErrorKind`.
let error: Error = ErrorKind::Foo.into();
let error: Error = io_error().into();

// Get the reference or the value of the inner error.
let _: &ErrorKind = error.inner();
let _: ErrorKind = error.into_inner();

§Backtrace

Another use case is to capture backtrace when the error is created. Without a new type, one has to manually add a Backtrace field to each variant of the error type. The new type allows one to capture backtrace in a single place.

Specify #[thiserror_ext(newtype(.., backtrace))] to enable capturing backtrace. The extra backtrace is captured only if the original error type does not provide one. Typically, this should be maintained by the #[backtrace] attribute from thiserror.

§Example

#[derive(Debug, thiserror::Error, thiserror_ext::Box)]
#[thiserror_ext(newtype(name = Error, backtrace))]
enum ErrorKind {
    #[error("foo")]
    Foo,
}

let error: Error = ErrorKind::Foo.into();
let backtrace: &Backtrace = std::error::request_ref(&error).unwrap();