1use thiserror::Error;
6
7#[derive(Error, Debug, Clone, PartialEq)]
9pub enum TimeError {
10 #[error("Hardware error: {0}")]
12 Hardware(String),
13
14 #[error("Invalid sample rate: {0}")]
16 InvalidSampleRate(f32),
17
18 #[error("Clock not started")]
20 NotStarted,
21
22 #[error("Clock already started")]
24 AlreadyStarted,
25
26 #[error("Clock underflow")]
28 Underflow,
29
30 #[error("Clock overflow")]
32 Overflow,
33
34 #[error("Invalid tempo: {0}")]
36 InvalidTempo(f32),
37
38 #[error("Timing error: {0}")]
40 Timing(String),
41}
42
43impl TimeError {
44 pub fn hardware(msg: impl Into<String>) -> Self {
46 Self::Hardware(msg.into())
47 }
48
49 pub fn invalid_sample_rate(rate: f32) -> Self {
51 Self::InvalidSampleRate(rate)
52 }
53
54 pub fn invalid_tempo(tempo: f32) -> Self {
56 Self::InvalidTempo(tempo)
57 }
58
59 pub fn is_recoverable(&self) -> bool {
61 matches!(self, Self::Underflow | Self::Overflow)
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_time_error_creation() {
71 let err = TimeError::hardware("ALSA error");
72 assert!(matches!(err, TimeError::Hardware(_)));
73
74 let err = TimeError::invalid_sample_rate(96000.0);
75 assert!(matches!(err, TimeError::InvalidSampleRate(_)));
76 }
77
78 #[test]
79 fn test_time_error_recoverable() {
80 assert!(TimeError::Underflow.is_recoverable());
81 assert!(TimeError::Overflow.is_recoverable());
82 assert!(!TimeError::NotStarted.is_recoverable());
83 }
84}