1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
use crate::events::DebugError;
use crate::{ConversionError, Host, HostError, RawVal, Status};
impl Host {
/// Records a debug-event from its input in as much detail as possible, then
/// converts its input to a (often coarser-granularity) [Status] code, and then
/// forms a [HostError] with it (which also captures a [backtrace::Backtrace]).
/// This is the method you want to call any time there's a finer-granularity error
/// type that you want to log the details of and then downgrade fail with.
pub fn err<T>(&self, src: T) -> HostError
where
DebugError: From<T>,
{
let ds: DebugError = src.into();
if let Err(e) = self.record_debug_event(ds.event) {
e
} else {
let mut he: HostError = ds.status.into();
// If `get_events` causes an out-of-budget err, the events will not be recorded.
he.events = self.get_events().ok();
he
}
}
/// Helper for the simplest status-only error path.
pub fn err_status<T>(&self, status: T) -> HostError
where
Status: From<T>,
{
self.err(DebugError::new(status))
}
/// Helper for the simplest string + general-error path.
pub fn err_general(&self, msg: &'static str) -> HostError {
self.err(DebugError::general().msg(msg))
}
/// Helper for the next-simplest status-and-extended-debug-message error path.
pub fn err_status_msg<T>(&self, status: T, msg: &'static str) -> HostError
where
Status: From<T>,
{
self.err(DebugError::new(status).msg(msg))
}
/// Helper for the error message with status and an arbitrary number of args.
pub fn err_status_msg_with_args<T>(
&self,
status: T,
msg: &'static str,
args: &[RawVal],
) -> HostError
where
Status: From<T>,
{
let mut e = DebugError::new(status).msg(msg);
for arg in args {
e = e.arg(*arg)
}
self.err(e)
}
// Helper for a conversion error from any type into a rawval
pub fn err_conversion_into_rawval<T>(&self, rv: RawVal) -> HostError {
self.err(
DebugError::new(ConversionError)
.msg("error converting {} into {}")
.arg(rv)
.arg(std::any::type_name::<T>()),
)
}
// Helper for a simplest conversion error with a provided msg
pub fn err_conversion_general(&self, msg: &'static str) -> HostError {
self.err(DebugError::new(ConversionError).msg(msg))
}
/// Given a result carrying some error type that can be converted to a
/// DebugError, calls self.err with it when there's an error. Returns a
/// result over HostError.
///
/// If you have an error type T you want to record as a detailed debug event
/// and a less-detailed Status code embedded in a HostError, add an `impl
/// From<T> for DebugError` over in the [events](crate::events) module and call this
/// where the error is generated.
///
/// Note: we do _not_ want to `impl From<T> for HostError` for such types,
/// as doing so will avoid routing them through the host in order to record
/// their extended diagnostic information into the debug buffer. This means
/// you will wind up writing `host.map_err(...)?` a bunch in code that you
/// used to be able to get away with just writing `...?`, there's no way
/// around this if we want to record the diagnostic information.
pub fn map_err<T, E>(&self, res: Result<T, E>) -> Result<T, HostError>
where
DebugError: From<E>,
{
res.map_err(|e| self.err(e.into()))
}
}
// Helper for building multi-argument errors.
// For example:
// ```
// err!(host, status, "{}: foo {}", arg1, arg2);
// ```
// All arguments must be convertible to `RawVal` with `try_into_val`. This is
// expected to be called from within a function that returns
// `Result<_, HostError>`. If these requirements can't be fulfilled, use
// `err_status_msg_with_args` function directly.
#[macro_export]
macro_rules! err {
($host:expr, $status:expr, $msg:expr, $($args:expr),+) => {
$host.err_status_msg_with_args($status, $msg, &[$($args.try_into_val($host)?,)+])
};
}