Created
July 9, 2021 00:38
-
-
Save thomcc/79b607fd12712d64d099f9f32238c647 to your computer and use it in GitHub Desktop.
Extracting the message from a `std::thread::Result::Err` (e.g. a `Box<dyn Any + Send>`).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::any::Any; | |
pub fn extract_message(err: &(dyn Any + Send)) -> String { | |
fn extract(err: &(dyn Any + Send), max_tries: usize) -> String { | |
if let Some(&s) = err.downcast_ref::<&'static str>() { | |
return s.into(); | |
} | |
if let Some(s) = err.downcast_ref::<String>() { | |
return s.into(); | |
} | |
if max_tries != 0 { | |
let wrapped: Option<&Box<dyn Any + Send>> = err.downcast_ref::<Box<dyn Any + Send>>(); | |
if let Some(v) = wrapped { | |
// This is very subtle! Without `&**` the &Box will itself | |
// coersce to &dyn Any, which will ofc cause us to recurse | |
// infinitely. See the caveat in the [official docs][dynanyptr] | |
// for some discussion of the related issue. (Note: the | |
// max_tries param exists largely because I got this wrong | |
// the first time...). | |
// | |
// [dynanyptr]: https://doc.rust-lang.org/std/any/index.html#smart-pointers-and-dyn-any | |
return extract(&**v, max_tries - 1); | |
} | |
} | |
return format!("#<unknown error {:?}>", err.type_id()); | |
} | |
// Bound recursion to 10. Shouldn't be needed anymore, but you never know... | |
extract(err, 10) | |
} | |
#[cfg(test)] | |
mod test { | |
use super::*; | |
#[test] | |
fn test_extract_message() { | |
assert_eq!(extract_message(&boxstr("foo")), "foo"); | |
assert_eq!(extract_message(&boxstring("foo".to_string())), "foo"); | |
assert_eq!(extract_message(&boxbox(boxstr("foo"))), "foo"); | |
} | |
fn boxstr(s: &'static str) -> Box<dyn Any + Send> { | |
Box::new(s) | |
} | |
fn boxstring(s: String) -> Box<dyn Any + Send> { | |
Box::new(s) | |
} | |
fn boxbox(b: Box<dyn Any + Send>) -> Box<dyn Any + Send> { | |
Box::new(b) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment