1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use std::sync::{Arc, Mutex};
use ringbuf::Consumer;
use thiserror::Error;
use crate::{
command::{
producer::{CommandError, CommandProducer},
MetronomeCommand,
},
Tempo, Value,
};
use super::MetronomeId;
#[derive(Debug, Error)]
pub enum PopMetronomeEventError {
#[error("The event consumer cannot be used because a thread panicked while borrowing it.")]
MutexPoisoned,
}
#[derive(Clone)]
pub struct MetronomeHandle {
id: MetronomeId,
command_producer: CommandProducer,
event_consumer: Arc<Mutex<Consumer<f64>>>,
}
impl MetronomeHandle {
pub(crate) fn new(
id: MetronomeId,
command_producer: CommandProducer,
event_consumer: Consumer<f64>,
) -> Self {
Self {
id,
command_producer,
event_consumer: Arc::new(Mutex::new(event_consumer)),
}
}
pub fn id(&self) -> MetronomeId {
self.id
}
pub fn set_tempo(&mut self, tempo: impl Into<Value<Tempo>>) -> Result<(), CommandError> {
self.command_producer
.push(MetronomeCommand::SetMetronomeTempo(self.id(), tempo.into()).into())
}
pub fn start(&mut self) -> Result<(), CommandError> {
self.command_producer
.push(MetronomeCommand::StartMetronome(self.id()).into())
}
pub fn pause(&mut self) -> Result<(), CommandError> {
self.command_producer
.push(MetronomeCommand::PauseMetronome(self.id()).into())
}
pub fn stop(&mut self) -> Result<(), CommandError> {
self.command_producer
.push(MetronomeCommand::StopMetronome(self.id()).into())
}
pub fn pop_event(&mut self) -> Result<Option<f64>, PopMetronomeEventError> {
Ok(self
.event_consumer
.lock()
.map_err(|_| PopMetronomeEventError::MutexPoisoned)?
.pop())
}
}
impl std::fmt::Debug for MetronomeHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
#[derive(Debug)]
struct EventConsumer;
f.debug_struct("MetronomeHandle")
.field("id", &self.id)
.field("command_producer", &self.command_producer)
.field("event_consumer", &EventConsumer)
.finish()
}
}