use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive]
pub enum Error {
UnsupportedSampleRate {
hz: u32,
},
InvalidFrequency {
hz: f32,
max_hz: f32,
},
InvalidConfig {
field: &'static str,
problem: ConfigProblem,
},
BufferLength {
expected: usize,
actual: usize,
},
BlockTooLarge {
frames: usize,
max: usize,
},
InvalidEvent {
index: usize,
problem: EventProblem,
},
InvalidMidi,
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive]
pub enum ConfigProblem {
OutOfRange {
min: f64,
max: f64,
},
NotFinite,
Unordered {
other: &'static str,
},
}
#[derive(Clone, Copy, Debug, PartialEq)]
#[non_exhaustive]
pub enum EventProblem {
OffsetOutsideBlock,
OffsetDecreasing,
Config {
field: &'static str,
problem: ConfigProblem,
},
Midi,
}
impl Error {
pub(crate) fn config(field: &'static str, problem: ConfigProblem) -> Self {
Self::InvalidConfig { field, problem }
}
pub(crate) fn check_length(expected: usize, actual: usize) -> Result<(), Self> {
if expected == actual {
Ok(())
} else {
Err(Self::BufferLength { expected, actual })
}
}
}
pub(crate) fn check_range(
field: &'static str,
value: f32,
min: f32,
max: f32,
) -> Result<(), Error> {
if !value.is_finite() {
return Err(Error::config(field, ConfigProblem::NotFinite));
}
if !(min..=max).contains(&value) {
let (min, max) = (f64::from(min), f64::from(max));
return Err(Error::config(field, ConfigProblem::OutOfRange { min, max }));
}
Ok(())
}
pub(crate) fn check_count(
field: &'static str,
value: i64,
min: i64,
max: i64,
) -> Result<(), Error> {
if !(min..=max).contains(&value) {
let (min, max) = (min as f64, max as f64);
return Err(Error::config(field, ConfigProblem::OutOfRange { min, max }));
}
Ok(())
}
impl fmt::Display for ConfigProblem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OutOfRange { min, max } => write!(f, "must be in {min}..={max}"),
Self::NotFinite => f.write_str("must be finite"),
Self::Unordered { other } => write!(f, "must be below {other}"),
}
}
}
impl fmt::Display for EventProblem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OffsetOutsideBlock => f.write_str("offset is outside the block"),
Self::OffsetDecreasing => f.write_str("offset is below the previous event's offset"),
Self::Config { field, problem } => write!(f, "{field} {problem}"),
Self::Midi => f.write_str("MIDI message is not valid"),
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnsupportedSampleRate { hz } => write!(f, "unsupported sample rate: {hz} Hz"),
Self::InvalidFrequency { hz, max_hz } => {
write!(
f,
"frequency {hz} Hz must be finite and in 0 < hz <= {max_hz}"
)
}
Self::InvalidConfig { field, problem } => {
write!(f, "invalid config: {field} {problem}")
}
Self::BufferLength { expected, actual } => {
write!(f, "buffer length is {actual}, expected {expected}")
}
Self::BlockTooLarge { frames, max } => {
write!(
f,
"block of {frames} frames is larger than the prepared {max}"
)
}
Self::InvalidEvent { index, problem } => write!(f, "event {index}: {problem}"),
Self::InvalidMidi => f.write_str("MIDI message is not valid"),
}
}
}
impl std::error::Error for Error {}