From 740cff65e28d109b26e7428840cff75968818ce0 Mon Sep 17 00:00:00 2001 From: Finomnis Date: Sun, 3 Apr 2022 12:42:38 +0200 Subject: [PATCH] Add conversion from Report to Box --- src/eyreish/error.rs | 38 ++++++++++++++++++++++++++++++++++++++ tests/test_convert.rs | 19 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/eyreish/error.rs b/src/eyreish/error.rs index e1a8593..3ae84b6 100644 --- a/src/eyreish/error.rs +++ b/src/eyreish/error.rs @@ -83,6 +83,7 @@ impl Report { object_mut: object_mut::, object_ref_stderr: object_ref_stderr::, object_boxed: object_boxed::, + object_boxed_stderr: object_boxed_stderr::, object_downcast: object_downcast::, object_drop_rest: object_drop_front::, }; @@ -106,6 +107,7 @@ impl Report { object_mut: object_mut::>, object_ref_stderr: object_ref_stderr::>, object_boxed: object_boxed::>, + object_boxed_stderr: object_boxed_stderr::>, object_downcast: object_downcast::, object_drop_rest: object_drop_front::, }; @@ -131,6 +133,7 @@ impl Report { object_mut: object_mut::>, object_ref_stderr: object_ref_stderr::>, object_boxed: object_boxed::>, + object_boxed_stderr: object_boxed_stderr::>, object_downcast: context_downcast::, object_drop_rest: context_drop_rest::, }; @@ -153,6 +156,7 @@ impl Report { object_mut: object_mut::, object_ref_stderr: object_ref_stderr::, object_boxed: object_boxed::, + object_boxed_stderr: object_boxed_stderr::, object_downcast: object_downcast::>, object_drop_rest: object_drop_front::>, }; @@ -213,6 +217,7 @@ impl Report { object_mut: object_mut::>, object_ref_stderr: object_ref_stderr::>, object_boxed: object_boxed::>, + object_boxed_stderr: object_boxed_stderr::>, object_downcast: context_chain_downcast::, object_drop_rest: context_chain_drop_rest::, }; @@ -455,6 +460,8 @@ struct ErrorVTable { object_ref_stderr: unsafe fn(&ErrorImpl<()>) -> &(dyn StdError + Send + Sync + 'static), #[allow(clippy::type_complexity)] object_boxed: unsafe fn(Box>) -> Box, + #[allow(clippy::type_complexity)] + object_boxed_stderr: unsafe fn(Box>) -> Box, object_downcast: unsafe fn(&ErrorImpl<()>, TypeId) -> Option>, object_drop_rest: unsafe fn(Box>, TypeId), } @@ -513,6 +520,15 @@ where mem::transmute::>, Box>>(e) } +// Safety: requires layout of *e to match ErrorImpl. +unsafe fn object_boxed_stderr(e: Box>) -> Box +where + E: StdError + Send + Sync + 'static, +{ + // Attach ErrorImpl's native StdError vtable. The StdError impl is below. + mem::transmute::>, Box>>(e) +} + // Safety: requires layout of *e to match ErrorImpl. unsafe fn object_downcast(e: &ErrorImpl<()>, target: TypeId) -> Option> where @@ -711,12 +727,34 @@ impl From for Box { } } +impl From for Box { + fn from(error: Report) -> Self { + let outer = ManuallyDrop::new(error); + unsafe { + // Read Box> from error. Can't move it out because + // Report has a Drop impl which we want to not run. + let inner = ptr::read(&outer.inner); + let erased = ManuallyDrop::into_inner(inner); + + // Use vtable to attach ErrorImpl's native StdError vtable for + // the right original type E. + (erased.vtable.object_boxed_stderr)(erased) + } + } +} + impl From for Box { fn from(error: Report) -> Self { Box::::from(error) } } +impl From for Box { + fn from(error: Report) -> Self { + Box::::from(error) + } +} + impl AsRef for Report { fn as_ref(&self) -> &(dyn Diagnostic + Send + Sync + 'static) { &**self diff --git a/tests/test_convert.rs b/tests/test_convert.rs index d43190b..fade2a8 100644 --- a/tests/test_convert.rs +++ b/tests/test_convert.rs @@ -21,3 +21,22 @@ fn test_question_mark() -> Result<(), Box> { f()?; Ok(()) } + +#[test] +fn test_convert_stderr() { + let has_dropped = Flag::new(); + let error: Report = Report::new(DetectDrop::new(&has_dropped)); + let box_dyn = Box::::from(error); + assert_eq!("oh no!", box_dyn.to_string()); + drop(box_dyn); + assert!(has_dropped.get()); +} + +#[test] +fn test_question_mark_stderr() -> Result<(), Box> { + fn f() -> Result<()> { + Ok(()) + } + f()?; + Ok(()) +}