use std::{fmt::Debug, sync::Arc};
use backtrace::Backtrace;
use thiserror::Error;
use super::{provider, Key};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Error, Debug, Clone)]
pub enum Error {
#[error("{0} has already been provided")]
Occupied(
Key,
),
#[error("{missing} was not found\n\nAvailable:{}\n{}", format_avail_lines(.available), format_backtrace(.backtrace))]
NotFound {
missing: Key,
available: Vec<Key>,
backtrace: Arc<Backtrace>,
},
#[error("provider failure")]
Provider(#[from] Box<provider::Error>),
#[error("{} was not able to be downcast to {}", .0, .0.type_name)]
TypeMismatch(
Key,
),
#[error("{key} cannot be consumed, {strong_count} strong pointers remain")]
CannotConsume {
key: Key,
strong_count: usize,
},
#[error("general failure")]
Any(#[from] Arc<anyhow::Error>),
}
fn format_avail_lines(available: &[Key]) -> String {
if !available.is_empty() {
format!(
"\n - {}",
available
.iter()
.map(|k| k.to_string())
.collect::<Vec<String>>()
.join("\n\n - ")
)
} else {
" (empty)".to_string()
}
}
fn format_backtrace(backtrace: &Arc<Backtrace>) -> String {
match std::env::var("RUST_LIB_BACKTRACE").or_else(|_| std::env::var("RUST_BACKTRACE")) {
Ok(should_disable) if should_disable != "0" => {
format!("\nstack backtrace:\n{:?}", backtrace)
}
_ => "".to_string(),
}
}
impl From<provider::Error> for Error {
fn from(e: provider::Error) -> Self {
Error::Provider(Box::new(e))
}
}
pub fn to_nakago_error<E>(e: E) -> Error
where
anyhow::Error: From<E>,
{
Error::Any(Arc::new(e.into()))
}