use alloc::boxed::Box;
use alloc::string::{String, ToString};
use core::fmt;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FloErrorKind {
InvalidData,
UnsupportedFeature,
Io,
Codec,
Metadata,
Lossy,
Lossless,
Wasm,
Internal,
}
pub struct FloError {
kind: FloErrorKind,
message: String,
source: Option<Box<dyn core::error::Error + Send + Sync + 'static>>,
}
impl Clone for FloError {
fn clone(&self) -> Self {
Self {
kind: self.kind,
message: self.message.clone(),
source: None,
}
}
}
impl FloError {
pub fn new<T: Into<String>>(kind: FloErrorKind, message: T) -> Self {
Self {
kind,
message: message.into(),
source: None,
}
}
pub fn kind(&self) -> FloErrorKind {
self.kind
}
pub fn message(&self) -> &str {
&self.message
}
pub fn with_context<T: Into<String>>(mut self, ctx: T) -> Self {
let ctx = ctx.into();
if self.message.is_empty() {
self.message = ctx;
} else {
self.message = alloc::format!("{ctx}: {}", self.message);
}
self
}
pub fn with_source(mut self, source: impl core::error::Error + Send + Sync + 'static) -> Self {
self.source = Some(Box::new(source));
self
}
pub fn into_boxed(self) -> Box<FloError> {
Box::new(self)
}
}
impl fmt::Display for FloError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.message, f)
}
}
impl fmt::Debug for FloError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("FloError");
d.field("kind", &format_args!("{:?}", self.kind));
d.field("message", &self.message);
d.finish()
}
}
impl core::error::Error for FloError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
self.source
.as_deref()
.map(|e| e as &(dyn core::error::Error + 'static))
}
}
impl From<fmt::Error> for FloError {
fn from(e: fmt::Error) -> Self {
Self::new(FloErrorKind::Codec, e.to_string())
}
}
impl From<String> for FloError {
fn from(s: String) -> Self {
Self::new(FloErrorKind::Internal, s)
}
}
impl From<&str> for FloError {
fn from(s: &str) -> Self {
Self::new(FloErrorKind::Internal, s.to_string())
}
}
pub trait FloErrorExt<T> {
fn context(self, ctx: impl Into<String>) -> Result<T, FloError>;
}
impl<T> FloErrorExt<T> for Result<T, FloError> {
fn context(self, ctx: impl Into<String>) -> Result<T, FloError> {
self.map_err(|e| e.with_context(ctx))
}
}
pub type FloResult<T> = Result<T, FloError>;