use std::fmt;
pub trait ErrorInfo: fmt::Display + fmt::Debug + Send + Sync {
fn type_id(&self) -> std::any::TypeId;
fn into_error(self) -> Error
where
Self: Sized + 'static,
{
Error {
inner: Some(Box::new(self)),
}
}
}
#[allow(dead_code)]
struct ErrorWrapper<E: ErrorInfo + 'static>(E);
impl<E: ErrorInfo + 'static> fmt::Display for ErrorWrapper<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl<E: ErrorInfo + 'static> fmt::Debug for ErrorWrapper<E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl<E: ErrorInfo + 'static> ErrorInfo for ErrorWrapper<E> {
fn type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<E>()
}
}
pub fn is_error_a<E: ErrorInfo + 'static>(err: &dyn ErrorInfo) -> bool {
std::any::TypeId::of::<E>() == err.type_id()
}
#[must_use]
pub struct Error {
inner: Option<Box<dyn ErrorInfo>>,
}
impl Error {
pub fn success() -> Self {
Self { inner: None }
}
pub fn is_success(&self) -> bool {
self.inner.is_none()
}
pub fn is_failure(&self) -> bool {
self.inner.is_some()
}
pub fn from_string(msg: impl Into<String>) -> Self {
#[derive(Debug)]
struct StringError(String);
impl fmt::Display for StringError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl ErrorInfo for StringError {
fn type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<StringError>()
}
}
StringError(msg.into()).into_error()
}
pub fn into_result(&self) -> Result<(), String> {
match &self.inner {
None => Ok(()),
Some(err) => Err(err.to_string()),
}
}
pub fn join(self, other: Error) -> Error {
if self.is_success() {
return other;
}
if other.is_success() {
return self;
}
let msg = format!(
"{}; {}",
self.inner.as_ref().unwrap(),
other.inner.as_ref().unwrap()
);
std::mem::forget(other);
Error::from_string(msg)
}
pub fn join_errors(errors: Vec<Error>) -> Error {
errors
.into_iter()
.fold(Error::success(), |acc, e| acc.join(e))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
None => write!(f, "success"),
Some(err) => write!(f, "{}", err),
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.inner {
None => write!(f, "Error::success()"),
Some(err) => write!(f, "Error({})", err),
}
}
}
pub fn consume_error(err: Error) {
if err.is_failure() {
eprintln!("Warning: consuming unchecked error: {}", err);
}
drop(err);
}
pub struct Success;
impl From<Success> for Error {
fn from(_: Success) -> Self {
Error::success()
}
}
#[must_use]
pub struct Expected<T> {
value: Option<T>,
error: Error,
}
impl<T> Expected<T> {
pub fn from_value(value: T) -> Self {
Self {
value: Some(value),
error: Error::success(),
}
}
pub fn from_error(error: Error) -> Self {
Self { value: None, error }
}
pub fn is_valid(&self) -> bool {
self.value.is_some()
}
pub fn get(&self) -> Option<&T> {
self.value.as_ref()
}
pub fn take(self) -> T {
match self.value {
Some(v) => {
drop(self.error);
v
}
None => panic!("Expected::take() called on error: {}", self.error),
}
}
pub fn take_error(self) -> Error {
self.error
}
pub fn into_result(self) -> Result<T, Error> {
match self.value {
Some(v) => Ok(v),
None => Err(self.error),
}
}
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Expected<U> {
match self.value {
Some(v) => Expected::from_value(f(v)),
None => Expected::from_error(self.error),
}
}
}
impl<T: fmt::Debug> fmt::Debug for Expected<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.value {
Some(v) => write!(f, "Expected({:?})", v),
None => write!(f, "Expected(error: {})", self.error),
}
}
}
impl<T> From<Result<T, Error>> for Expected<T> {
fn from(result: Result<T, Error>) -> Self {
match result {
Ok(v) => Expected::from_value(v),
Err(e) => Expected::from_error(e),
}
}
}
impl Drop for Error {
fn drop(&mut self) {
if cfg!(debug_assertions) {
if let Some(err) = &self.inner {
eprintln!("WARNING: Unchecked LLVM Error dropped: {:?}", err);
}
}
}
}
#[derive(Debug, Clone)]
pub struct GenericError {
pub message: String,
}
impl GenericError {
pub fn new(msg: impl Into<String>) -> Self {
Self {
message: msg.into(),
}
}
}
impl fmt::Display for GenericError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.message)
}
}
impl ErrorInfo for GenericError {
fn type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<GenericError>()
}
}