use std::{
convert::Infallible,
fs::File,
io::{BufReader, Read},
path::Path,
};
use crate::Chunk;
pub trait Yieldable<T> {
fn get(&mut self, n: usize) -> Vec<T>;
}
impl<ITER> Yieldable<ITER::Item> for ITER
where
ITER: Iterator,
{
#[allow(if_let_rescope)]
fn get(&mut self, n: usize) -> Vec<ITER::Item> {
let mut elements = Vec::with_capacity(n);
for _ in 0..n {
if let Some(item) = self.next() {
elements.push(item);
} else {
break; }
}
elements
}
}
pub trait MidiStream {
fn read_chunk_data_pair(&mut self) -> Option<(Chunk, Vec<u8>)>;
}
impl<MIDI> MidiStream for MIDI
where
MIDI: Iterator<Item = u8>,
{
fn read_chunk_data_pair(&mut self) -> Option<(Chunk, Vec<u8>)> {
let chunk_packet = self.get(8);
if chunk_packet.len() != 8 {
return None;
}
let chunk = u64::from_be_bytes(chunk_packet.try_into().unwrap());
let chunk: Chunk = chunk.into();
let data = self.get(chunk.len());
if data.len() != chunk.len() {
return None;
}
Some((chunk, data))
}
}
pub trait MidiReadable {
type Error;
fn get_midi_bytes(self) -> Result<impl Iterator<Item = u8>, Self::Error>;
}
pub struct MidiData(Vec<u8>);
impl MidiReadable for MidiData {
type Error = Infallible;
fn get_midi_bytes(self) -> Result<impl Iterator<Item = u8>, Self::Error> {
Ok(self.0.into_iter())
}
}
impl<PATH> MidiReadable for PATH
where
PATH: AsRef<Path>,
{
type Error = std::io::Error;
fn get_midi_bytes(self) -> Result<impl Iterator<Item = u8>, Self::Error> {
let path = self.as_ref();
let file = File::open(path)?;
let reader = BufReader::new(file);
Ok(reader.bytes().filter_map(Result::ok))
}
}
#[cfg(test)]
mod tests {
use super::MidiReadable;
#[test]
fn midi_files_stream() {
let path = "test/run.mid";
let data = path.get_midi_bytes();
assert!(data.is_ok())
}
}