#[cfg(feature = "alloc")]
use alloc::{boxed::Box, string::String};
pub type Result<T = ()> = core::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("Attempted to use an invalid accidental")]
InvalidAccidental,
#[error("Attempted to name an invalid pitch class: {0}")]
InvalidPitchClass(isize),
#[error("Mismatched pitch classes, received {0} while expecting {1}")]
MismatchedPitchClasses(isize, isize),
#[error("Unable to parse the string into the configured type")]
FromStrParseError,
#[error("Unable to parse the string into the desired pitch class: {0}")]
InvalidPitchClassParse(&'static str),
#[error("Mismatched symbols")]
MismatchedSymbols,
#[error("Invalid Chord")]
InvalidChord,
#[cfg(feature = "alloc")]
#[error("Invalid Intervals: {0}")]
IncompatibleIntervals(String),
#[error("Invalid Note")]
InvalidNote,
#[error(transparent)]
AnyError(#[from] anyhow::Error),
#[error(transparent)]
#[cfg(feature = "serde_json")]
JsonError(#[from] serde_json::Error),
#[error(transparent)]
AddrParseError(#[from] core::net::AddrParseError),
#[error("The impossible has occurred")]
Infallible(#[from] core::convert::Infallible),
#[error(transparent)]
FmtError(#[from] core::fmt::Error),
#[error(transparent)]
Utf8Error(#[from] core::str::Utf8Error),
#[cfg(feature = "std")]
#[error(transparent)]
IOError(#[from] std::io::Error),
#[cfg(feature = "alloc")]
#[error(transparent)]
BoxError(#[from] Box<dyn core::error::Error + Send + Sync>),
#[cfg(feature = "alloc")]
#[error("Unknown Error: {0}")]
Unknown(String),
}
impl Error {
#[cfg(feature = "alloc")]
pub fn boxed<E>(err: E) -> Self
where
E: core::error::Error + Send + Sync + 'static,
{
Error::BoxError(Box::new(err))
}
#[cfg(feature = "alloc")]
pub fn unknown<E>(err: E) -> Self
where
E: alloc::string::ToString,
{
Error::Unknown(err.to_string())
}
}
#[cfg(feature = "alloc")]
impl From<&str> for Error {
fn from(s: &str) -> Self {
Error::unknown(s)
}
}
#[cfg(feature = "alloc")]
impl From<String> for Error {
fn from(s: String) -> Self {
Error::Unknown(s)
}
}
#[doc(hidden)]
pub mod custom {
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[derive(
Clone,
Copy,
Debug,
Default,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
strum::AsRefStr,
strum::Display,
strum::EnumCount,
strum::EnumString,
strum::VariantNames,
)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(rename_all = "snake_case")
)]
#[non_exhaustive]
pub enum ErrorKind {
InvalidAccidental,
ChordError,
NoteError,
PitchError,
InvalidPitchClass,
MismatchedPitchClasses,
FromStrParseError,
InvalidPitchClassParse,
MismatchedSymbols,
InvalidChord,
IncompatibleIntervals,
InvalidNote,
Utf8Error,
AnyError,
JsonError,
AddrParseError,
Infallible,
FmtError,
None,
IOError,
#[default]
Unknown,
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ErrorBase<E = Box<dyn core::error::Error + 'static>> {
pub(crate) kind: ErrorKind,
pub(crate) source: Option<E>,
}
impl<E> ErrorBase<E>
where
E: core::error::Error,
{
pub const fn new(kind: ErrorKind, source: Option<E>) -> Self {
Self { kind, source }
}
pub const fn unknown(source: E) -> Self {
Self {
kind: ErrorKind::Unknown,
source: Some(source),
}
}
pub fn with_kind(self, kind: ErrorKind) -> ErrorBase<E> {
ErrorBase {
kind,
source: self.source,
}
}
pub fn with_source<E2>(self, source: E2) -> ErrorBase<E2>
where
E2: core::error::Error,
{
ErrorBase {
kind: self.kind,
source: Some(source),
}
}
}
impl<E> core::fmt::Display for ErrorBase<E>
where
E: 'static + core::error::Error,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if let Some(source) = &self.source {
write!(f, "{}: {}", self.kind, source)
} else {
write!(f, "{}", self.kind)
}
}
}
impl<E> core::error::Error for ErrorBase<E>
where
E: 'static + core::error::Error,
{
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
self.source
.as_ref()
.map(|e| e as &(dyn core::error::Error + 'static))
}
}
impl<T> From<Option<T>> for ErrorBase
where
T: core::error::Error + 'static,
{
fn from(opt: Option<T>) -> Self {
match opt {
Some(err) => Self {
kind: ErrorKind::Unknown,
source: Some(Box::new(err)),
},
None => Self {
kind: ErrorKind::None,
source: None,
},
}
}
}
impl From<core::str::Utf8Error> for ErrorBase {
fn from(err: core::str::Utf8Error) -> Self {
Self {
kind: ErrorKind::Utf8Error,
#[cfg(feature = "alloc")]
source: Some(Box::new(err)),
}
}
}
#[cfg(feature = "serde_json")]
impl From<serde_json::Error> for ErrorBase {
fn from(err: serde_json::Error) -> Self {
Self {
kind: ErrorKind::JsonError,
source: Some(Box::new(err)),
}
}
}
}