diff options
-rw-r--r-- | src/error.rs | 49 | ||||
-rw-r--r-- | src/lib.rs | 11 | ||||
-rw-r--r-- | src/prelude.rs | 8 |
3 files changed, 63 insertions, 5 deletions
diff --git a/src/error.rs b/src/error.rs index de22dc7..7e74d69 100644 --- a/src/error.rs +++ b/src/error.rs @@ -7,6 +7,8 @@ use std::str::Utf8Error; use std::string::String as StdString; use std::sync::Arc; +use crate::private::Sealed; + /// Error type returned by `mlua` methods. #[derive(Debug, Clone)] #[non_exhaustive] @@ -190,6 +192,11 @@ pub enum Error { /// error. The Rust code that originally invoked the Lua code then receives a `CallbackError`, /// from which the original error (and a stack traceback) can be recovered. ExternalError(Arc<dyn StdError + Send + Sync>), + /// An error with additional context. + WithContext { + context: StdString, + cause: Arc<Error>, + }, } /// A specialized `Result` type used by `mlua`'s API. @@ -306,6 +313,10 @@ impl fmt::Display for Error { write!(fmt, "deserialize error: {err}") }, Error::ExternalError(ref err) => write!(fmt, "{err}"), + Error::WithContext { ref context, ref cause } => { + writeln!(fmt, "{context}")?; + write!(fmt, "{cause}") + } } } } @@ -374,6 +385,44 @@ where } } +/// Provides the `context` method for [`Error`] and `Result<T, Error>`. +pub trait ErrorContext: Sealed { + fn context<C: fmt::Display>(self, context: C) -> Self; + fn with_context<C: fmt::Display>(self, f: impl FnOnce(&Error) -> C) -> Self; +} + +impl ErrorContext for Error { + fn context<C: fmt::Display>(self, context: C) -> Self { + Error::WithContext { + context: context.to_string(), + cause: Arc::new(self), + } + } + + fn with_context<C: fmt::Display>(self, f: impl FnOnce(&Error) -> C) -> Self { + Error::WithContext { + context: f(&self).to_string(), + cause: Arc::new(self), + } + } +} + +impl<T> ErrorContext for StdResult<T, Error> { + fn context<C: fmt::Display>(self, context: C) -> Self { + self.map_err(|err| Error::WithContext { + context: context.to_string(), + cause: Arc::new(err), + }) + } + + fn with_context<C: fmt::Display>(self, f: impl FnOnce(&Error) -> C) -> Self { + self.map_err(|err| Error::WithContext { + context: f(&err).to_string(), + cause: Arc::new(err), + }) + } +} + impl std::convert::From<AddrParseError> for Error { fn from(err: AddrParseError) -> Self { Error::external(err) @@ -108,7 +108,7 @@ pub mod prelude; pub use crate::{ffi::lua_CFunction, ffi::lua_State}; pub use crate::chunk::{AsChunk, Chunk, ChunkMode}; -pub use crate::error::{Error, ExternalError, ExternalResult, Result}; +pub use crate::error::{Error, ErrorContext, ExternalError, ExternalResult, Result}; pub use crate::function::{Function, FunctionInfo}; pub use crate::hook::{Debug, DebugEvent, DebugNames, DebugSource, DebugStack}; pub use crate::lua::{GCMode, Lua, LuaOptions}; @@ -232,3 +232,12 @@ pub use mlua_derive::chunk; #[cfg(any(feature = "module", docsrs))] #[cfg_attr(docsrs, doc(cfg(feature = "module")))] pub use mlua_derive::lua_module; + +pub(crate) mod private { + use super::*; + + pub trait Sealed {} + + impl Sealed for Error {} + impl<T> Sealed for std::result::Result<T, Error> {} +} diff --git a/src/prelude.rs b/src/prelude.rs index 20ca6b8..32eb440 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -3,10 +3,10 @@ #[doc(no_inline)] pub use crate::{ AnyUserData as LuaAnyUserData, AnyUserDataExt as LuaAnyUserDataExt, Chunk as LuaChunk, - Error as LuaError, ExternalError as LuaExternalError, ExternalResult as LuaExternalResult, - FromLua, FromLuaMulti, Function as LuaFunction, FunctionInfo as LuaFunctionInfo, - GCMode as LuaGCMode, Integer as LuaInteger, IntoLua, IntoLuaMulti, - LightUserData as LuaLightUserData, Lua, LuaOptions, MetaMethod as LuaMetaMethod, + Error as LuaError, ErrorContext as LuaErrorContext, ExternalError as LuaExternalError, + ExternalResult as LuaExternalResult, FromLua, FromLuaMulti, Function as LuaFunction, + FunctionInfo as LuaFunctionInfo, GCMode as LuaGCMode, Integer as LuaInteger, IntoLua, + IntoLuaMulti, LightUserData as LuaLightUserData, Lua, LuaOptions, MetaMethod as LuaMetaMethod, MultiValue as LuaMultiValue, Nil as LuaNil, Number as LuaNumber, RegistryKey as LuaRegistryKey, Result as LuaResult, StdLib as LuaStdLib, String as LuaString, Table as LuaTable, TableExt as LuaTableExt, TablePairs as LuaTablePairs, TableSequence as LuaTableSequence, |