1use crate::raw;
7
8#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
9pub struct MidiDeltaMicros(u32);
10
11impl MidiDeltaMicros {
12 pub const fn new(micros: u32) -> Self {
13 Self(micros)
14 }
15
16 pub const fn as_micros(self) -> u32 {
17 self.0
18 }
19}
20
21impl From<u32> for MidiDeltaMicros {
22 fn from(micros: u32) -> Self {
23 Self::new(micros)
24 }
25}
26
27#[derive(Clone, Copy, Debug, Default)]
28pub struct MidiInterface {
29 raw: raw::retro_midi_interface,
30}
31
32impl MidiInterface {
33 pub(crate) const fn from_raw(raw: raw::retro_midi_interface) -> Self {
34 Self { raw }
35 }
36
37 pub const fn is_available(self) -> bool {
38 self.raw.input_enabled.is_some()
39 && self.raw.output_enabled.is_some()
40 && self.raw.read.is_some()
41 && self.raw.write.is_some()
42 && self.raw.flush.is_some()
43 }
44
45 pub fn input_enabled(self) -> bool {
46 self.raw
47 .input_enabled
48 .map(|input_enabled| unsafe { input_enabled() })
49 .unwrap_or(false)
50 }
51
52 pub fn output_enabled(self) -> bool {
53 self.raw
54 .output_enabled
55 .map(|output_enabled| unsafe { output_enabled() })
56 .unwrap_or(false)
57 }
58
59 pub fn read_byte(self) -> Option<u8> {
60 let read = self.raw.read?;
61 let mut byte = 0u8;
62 if unsafe { read(&mut byte as *mut u8) } {
63 Some(byte)
64 } else {
65 None
66 }
67 }
68
69 pub fn write_byte(self, byte: u8, delta_time: impl Into<MidiDeltaMicros>) -> bool {
70 self.raw
71 .write
72 .map(|write| unsafe { write(byte, delta_time.into().as_micros()) })
73 .unwrap_or(false)
74 }
75
76 pub fn flush(self) -> bool {
77 self.raw
78 .flush
79 .map(|flush| unsafe { flush() })
80 .unwrap_or(false)
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::{MidiDeltaMicros, MidiInterface};
87
88 #[test]
89 fn midi_delta_micros_preserves_raw_value() {
90 assert_eq!(MidiDeltaMicros::new(240).as_micros(), 240);
91 }
92
93 #[test]
94 fn empty_midi_interface_reports_unavailable() {
95 let midi = MidiInterface::default();
96
97 assert!(!midi.is_available());
98 assert!(!midi.input_enabled());
99 assert!(!midi.output_enabled());
100 assert_eq!(midi.read_byte(), None);
101 assert!(!midi.write_byte(0x90, MidiDeltaMicros::new(0)));
102 assert!(!midi.flush());
103 }
104}