use crate::error::{Error, ParseError};
use std::io::{Read, Write};
pub const MAGIC: &[u8; 4] = b"MThd";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Midi {
pub data: Vec<u8>,
}
impl Midi {
pub fn read_from(reader: &mut impl Read) -> Result<Midi, Error> {
let mut data = Vec::new();
reader.read_to_end(&mut data)?;
if data.len() < 4 || &data[0..4] != MAGIC {
return Err(ParseError::UnknownFileType("not a MIDI file".to_string()).into());
}
Ok(Midi { data })
}
pub fn write_to(&self, writer: &mut impl Write) -> Result<(), Error> {
writer.write_all(&self.data)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_file_is_kept_verbatim() {
let bytes = [b"MThd".as_slice(), &[0, 0, 0, 6, 0, 0, 0, 1, 0, 96]].concat();
let midi = Midi::read_from(&mut bytes.as_slice()).unwrap();
assert_eq!(midi.data, bytes);
let mut out = Vec::new();
midi.write_to(&mut out).unwrap();
assert_eq!(out, bytes);
}
#[test]
fn anything_else_is_refused() {
assert!(Midi::read_from(&mut b"MTrk....".as_slice()).is_err());
assert!(
Midi::read_from(&mut b"MT".as_slice()).is_err(),
"shorter than the magic"
);
}
}