From faffe0db88d429a1c6540bf7dfa1070e0bea7108 Mon Sep 17 00:00:00 2001 From: Eric Buehler Date: Tue, 10 Sep 2024 19:29:28 -0400 Subject: [PATCH 1/4] Make Error::msg more in line with anyhow::Error::msg --- candle-core/src/error.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/candle-core/src/error.rs b/candle-core/src/error.rs index e7112e2e61..a517295c42 100644 --- a/candle-core/src/error.rs +++ b/candle-core/src/error.rs @@ -1,3 +1,5 @@ +use std::fmt::{Debug, Display}; + use crate::{DType, DeviceLocation, Layout, MetalError, Shape}; #[derive(Debug, Clone)] @@ -215,14 +217,21 @@ pub enum Error { pub type Result = std::result::Result; impl Error { + /// Create a new error by wrapping another. pub fn wrap(err: impl std::error::Error + Send + Sync + 'static) -> Self { Self::Wrapped(Box::new(err)).bt() } - pub fn msg(err: impl std::error::Error) -> Self { - Self::Msg(err.to_string()).bt() + /// Create a new error based on a printable error message. + /// + /// If the message implements `std::error::Error`, prefer using [`Error::wrap`] instead. + pub fn msg(msg: M) -> Self { + Self::Msg(msg.to_string()).bt() } + /// Create a new error based on a debuggable error message. + /// + /// If the message implements `std::error::Error`, prefer using [`Error::wrap`] instead. pub fn debug(err: impl std::fmt::Debug) -> Self { Self::Msg(format!("{err:?}")).bt() } From d8fa3e14b89a94278302d5266124ed0529c594df Mon Sep 17 00:00:00 2001 From: Eric Buehler Date: Tue, 10 Sep 2024 19:44:16 -0400 Subject: [PATCH 2/4] Add context trait --- candle-core/src/error.rs | 97 +++++++++++++++++++++++++++++++++++++++- candle-core/src/lib.rs | 2 +- 2 files changed, 96 insertions(+), 3 deletions(-) diff --git a/candle-core/src/error.rs b/candle-core/src/error.rs index a517295c42..44f6c206d7 100644 --- a/candle-core/src/error.rs +++ b/candle-core/src/error.rs @@ -1,4 +1,7 @@ -use std::fmt::{Debug, Display}; +use std::{ + convert::Infallible, + fmt::{Debug, Display}, +}; use crate::{DType, DeviceLocation, Layout, MetalError, Shape}; @@ -196,6 +199,13 @@ pub enum Error { #[error(transparent)] Wrapped(Box), + /// Arbitrary errors wrapping with context. + #[error("{wrapped:?}\n{context:?}")] + WrappedContext { + wrapped: Box, + context: String, + }, + /// Adding path information to an error. #[error("path: {path:?} {inner}")] WithPath { @@ -225,7 +235,7 @@ impl Error { /// Create a new error based on a printable error message. /// /// If the message implements `std::error::Error`, prefer using [`Error::wrap`] instead. - pub fn msg(msg: M) -> Self { + pub fn msg(msg: M) -> Self { Self::Msg(msg.to_string()).bt() } @@ -276,3 +286,86 @@ pub fn zip(r1: Result, r2: Result) -> Result<(T, U)> { (_, Err(e)) => Err(e), } } + +pub(crate) mod private { + pub trait Sealed {} + + impl Sealed for std::result::Result where E: std::error::Error {} + impl Sealed for Option {} +} + +/// Attach more context to an error. +/// +/// Inspired by [`anyhow::Context`]. +pub trait Context: private::Sealed { + /// Wrap the error value with additional context. + fn context(self, context: C) -> std::result::Result + where + C: Display + Send + Sync + 'static; + + /// Wrap the error value with additional context that is evaluated lazily + /// only once an error does occur. + fn with_context(self, f: F) -> std::result::Result + where + C: Display + Send + Sync + 'static, + F: FnOnce() -> C; +} + +impl Context for std::result::Result +where + E: std::error::Error + Send + Sync + 'static, +{ + fn context(self, context: C) -> std::result::Result + where + C: Display + Send + Sync + 'static, + { + // Not using map_err to save 2 useless frames off the captured backtrace + // in ext_context. + match self { + Ok(ok) => Ok(ok), + Err(error) => Err(Error::WrappedContext { + wrapped: Box::new(error), + context: context.to_string(), + }), + } + } + + fn with_context(self, context: F) -> std::result::Result + where + C: Display + Send + Sync + 'static, + F: FnOnce() -> C, + { + match self { + Ok(ok) => Ok(ok), + Err(error) => Err(Error::WrappedContext { + wrapped: Box::new(error), + context: context().to_string(), + }), + } + } +} + +impl Context for Option { + fn context(self, context: C) -> std::result::Result + where + C: Display + Send + Sync + 'static, + { + // Not using ok_or_else to save 2 useless frames off the captured + // backtrace. + match self { + Some(ok) => Ok(ok), + None => Err(Error::msg(context)), + } + } + + fn with_context(self, context: F) -> std::result::Result + where + C: Display + Send + Sync + 'static, + F: FnOnce() -> C, + { + match self { + Some(ok) => Ok(ok), + None => Err(Error::msg(context())), + } + } +} diff --git a/candle-core/src/lib.rs b/candle-core/src/lib.rs index 2a36cebd34..4af605b6eb 100644 --- a/candle-core/src/lib.rs +++ b/candle-core/src/lib.rs @@ -80,7 +80,7 @@ pub use cpu_backend::{CpuStorage, CpuStorageRef}; pub use custom_op::{CustomOp1, CustomOp2, CustomOp3, InplaceOp1, InplaceOp2, InplaceOp3}; pub use device::{Device, DeviceLocation, NdArray}; pub use dtype::{DType, DTypeParseError, FloatDType, IntDType, WithDType}; -pub use error::{Error, Result}; +pub use error::{Error, Result, Context}; pub use indexer::IndexOp; pub use layout::Layout; pub use shape::{Shape, D}; From acd1afd53a277cfd5314e1bb1742d2e7193b4dcd Mon Sep 17 00:00:00 2001 From: Eric Buehler Date: Tue, 10 Sep 2024 19:46:36 -0400 Subject: [PATCH 3/4] Even more flexible --- candle-core/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/candle-core/src/error.rs b/candle-core/src/error.rs index 44f6c206d7..80050d0822 100644 --- a/candle-core/src/error.rs +++ b/candle-core/src/error.rs @@ -235,7 +235,7 @@ impl Error { /// Create a new error based on a printable error message. /// /// If the message implements `std::error::Error`, prefer using [`Error::wrap`] instead. - pub fn msg(msg: M) -> Self { + pub fn msg(msg: M) -> Self { Self::Msg(msg.to_string()).bt() } From bbd7127d4a7b80a68697454f3dd9093eeea066bb Mon Sep 17 00:00:00 2001 From: Eric Buehler Date: Tue, 10 Sep 2024 20:35:41 -0400 Subject: [PATCH 4/4] Format --- candle-core/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/candle-core/src/lib.rs b/candle-core/src/lib.rs index 4af605b6eb..a38ed4790b 100644 --- a/candle-core/src/lib.rs +++ b/candle-core/src/lib.rs @@ -80,7 +80,7 @@ pub use cpu_backend::{CpuStorage, CpuStorageRef}; pub use custom_op::{CustomOp1, CustomOp2, CustomOp3, InplaceOp1, InplaceOp2, InplaceOp3}; pub use device::{Device, DeviceLocation, NdArray}; pub use dtype::{DType, DTypeParseError, FloatDType, IntDType, WithDType}; -pub use error::{Error, Result, Context}; +pub use error::{Context, Error, Result}; pub use indexer::IndexOp; pub use layout::Layout; pub use shape::{Shape, D};