Refactor `Error::CallbackError` reporting and include source to
fmt::Display implementation. This fixes #71.
This commit is contained in:
parent
ef8c1556e6
commit
2ea2b1f4fb
30
src/error.rs
30
src/error.rs
|
@ -247,8 +247,28 @@ impl fmt::Display for Error {
|
||||||
Error::MismatchedRegistryKey => {
|
Error::MismatchedRegistryKey => {
|
||||||
write!(fmt, "RegistryKey used from different Lua state")
|
write!(fmt, "RegistryKey used from different Lua state")
|
||||||
}
|
}
|
||||||
Error::CallbackError { ref traceback, .. } => {
|
Error::CallbackError { ref cause, ref traceback } => {
|
||||||
write!(fmt, "callback error\n{}", traceback)
|
writeln!(fmt, "callback error")?;
|
||||||
|
// Trace errors down to the root
|
||||||
|
let (mut cause, mut full_traceback) = (cause, None);
|
||||||
|
while let Error::CallbackError { cause: ref cause2, traceback: ref traceback2 } = **cause {
|
||||||
|
cause = cause2;
|
||||||
|
full_traceback = Some(traceback2);
|
||||||
|
}
|
||||||
|
if let Some(full_traceback) = full_traceback {
|
||||||
|
let traceback = traceback.trim_start_matches("stack traceback:");
|
||||||
|
let traceback = traceback.trim_start().trim_end();
|
||||||
|
// Try to find local traceback within the full traceback
|
||||||
|
if let Some(pos) = full_traceback.find(traceback) {
|
||||||
|
write!(fmt, "{}", &full_traceback[..pos])?;
|
||||||
|
writeln!(fmt, ">{}", &full_traceback[pos..].trim_end())?;
|
||||||
|
} else {
|
||||||
|
writeln!(fmt, "{}", full_traceback.trim_end())?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeln!(fmt, "{}", traceback.trim_end())?;
|
||||||
|
}
|
||||||
|
write!(fmt, "caused by: {}", cause)
|
||||||
}
|
}
|
||||||
Error::PreviouslyResumedPanic => {
|
Error::PreviouslyResumedPanic => {
|
||||||
write!(fmt, "previously resumed panic returned again")
|
write!(fmt, "previously resumed panic returned again")
|
||||||
|
@ -269,7 +289,11 @@ impl fmt::Display for Error {
|
||||||
impl StdError for Error {
|
impl StdError for Error {
|
||||||
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
fn source(&self) -> Option<&(dyn StdError + 'static)> {
|
||||||
match *self {
|
match *self {
|
||||||
Error::CallbackError { ref cause, .. } => Some(cause.as_ref()),
|
// An error type with a source error should either return that error via source or
|
||||||
|
// include that source's error message in its own Display output, but never both.
|
||||||
|
// https://blog.rust-lang.org/inside-rust/2021/07/01/What-the-error-handling-project-group-is-working-towards.html
|
||||||
|
// Given that we include source to fmt::Display implementation for `CallbackError`, this call returns nothing.
|
||||||
|
Error::CallbackError { .. } => None,
|
||||||
Error::ExternalError(ref err) => err.source(),
|
Error::ExternalError(ref err) => err.source(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
28
src/util.rs
28
src/util.rs
|
@ -1,5 +1,4 @@
|
||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
use std::error::Error as StdError;
|
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::os::raw::{c_char, c_int, c_void};
|
use std::os::raw::{c_char, c_int, c_void};
|
||||||
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
|
||||||
|
@ -736,32 +735,6 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
// be possible to make this consume arbitrary amounts of memory (for example, some
|
// be possible to make this consume arbitrary amounts of memory (for example, some
|
||||||
// kind of recursive error structure?)
|
// kind of recursive error structure?)
|
||||||
let _ = write!(&mut (*err_buf), "{}", error);
|
let _ = write!(&mut (*err_buf), "{}", error);
|
||||||
// Find first two sources that caused the error
|
|
||||||
let mut source1 = error.source();
|
|
||||||
let mut source0 = source1.and_then(|s| s.source());
|
|
||||||
while let Some(source) = source0.and_then(|s| s.source()) {
|
|
||||||
source1 = source0;
|
|
||||||
source0 = Some(source);
|
|
||||||
}
|
|
||||||
match (source1, source0) {
|
|
||||||
(_, Some(error0))
|
|
||||||
if error0.to_string().contains("\nstack traceback:\n") =>
|
|
||||||
{
|
|
||||||
let _ = write!(&mut (*err_buf), "\ncaused by: {}", error0);
|
|
||||||
}
|
|
||||||
(Some(error1), Some(error0)) => {
|
|
||||||
let _ = write!(&mut (*err_buf), "\ncaused by: {}", error0);
|
|
||||||
let s = error1.to_string();
|
|
||||||
if let Some(traceback) = s.split_once("\nstack traceback:\n") {
|
|
||||||
let _ =
|
|
||||||
write!(&mut (*err_buf), "\nstack traceback:\n{}", traceback.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(Some(error1), None) => {
|
|
||||||
let _ = write!(&mut (*err_buf), "\ncaused by: {}", error1);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
Ok(err_buf)
|
Ok(err_buf)
|
||||||
}
|
}
|
||||||
Some(WrappedFailure::Panic(Some(ref panic))) => {
|
Some(WrappedFailure::Panic(Some(ref panic))) => {
|
||||||
|
@ -805,7 +778,6 @@ pub unsafe fn init_error_registry(state: *mut ffi::lua_State) -> Result<()> {
|
||||||
// Create destructed userdata metatable
|
// Create destructed userdata metatable
|
||||||
|
|
||||||
unsafe extern "C" fn destructed_error(state: *mut ffi::lua_State) -> c_int {
|
unsafe extern "C" fn destructed_error(state: *mut ffi::lua_State) -> c_int {
|
||||||
// TODO: Consider changing error to UserDataDestructed in v0.7
|
|
||||||
callback_error(state, |_| Err(Error::CallbackDestructed))
|
callback_error(state, |_| Err(Error::CallbackDestructed))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue