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
43#[allow(dead_code)]
45pub type TimeResult<T> = Result<T, TimeError>;
46
47impl TimeError {
48 pub fn hardware(msg: impl Into<String>) -> Self {
50 Self::Hardware(msg.into())
51 }
52
53 pub fn invalid_sample_rate(rate: f32) -> Self {
55 Self::InvalidSampleRate(rate)
56 }
57
58 pub fn invalid_tempo(tempo: f32) -> Self {
60 Self::InvalidTempo(tempo)
61 }
62
63 pub fn is_recoverable(&self) -> bool {
65 match self {
66 Self::Underflow | Self::Overflow => true,
67 _ => false,
68 }
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn test_time_error_creation() {
78 let err = TimeError::hardware("ALSA error");
79 assert!(matches!(err, TimeError::Hardware(_)));
80
81 let err = TimeError::invalid_sample_rate(96000.0);
82 assert!(matches!(err, TimeError::InvalidSampleRate(_)));
83 }
84
85 #[test]
86 fn test_time_error_recoverable() {
87 assert!(TimeError::Underflow.is_recoverable());
88 assert!(TimeError::Overflow.is_recoverable());
89 assert!(!TimeError::NotStarted.is_recoverable());
90 }
91}