use std::fs;
use std::io;
pub mod plain;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum Format {
Header,
Aiff,
Wav,
}
impl Format {
pub fn magic(probe: impl AsRef<[u8]>) -> Option<Self> {
let probe = probe.as_ref();
if probe.len() < 12 {
return None;
}
match (&probe[..3], &probe[..4], &probe[8..12]) {
(b"ID3", _, _) => Some(Format::Header),
(_, b"FORM", _) => Some(Format::Aiff),
(_, b"RIFF", b"WAVE") => Some(Format::Wav),
_ => None,
}
}
}
pub trait Storage<'a> {
type Reader: io::Read + io::Seek + 'a;
type Writer: io::Write + io::Seek + 'a;
#[allow(unused)] fn reader(&'a mut self) -> io::Result<Self::Reader>;
fn writer(&'a mut self) -> io::Result<Self::Writer>;
}
pub trait StorageFile: io::Read + io::Write + io::Seek + private::Sealed {
fn set_len(&mut self, new_len: u64) -> io::Result<()>;
}
impl<T: StorageFile> StorageFile for &mut T {
fn set_len(&mut self, new_len: u64) -> io::Result<()> {
(*self).set_len(new_len)
}
}
impl StorageFile for fs::File {
fn set_len(&mut self, new_len: u64) -> io::Result<()> {
fs::File::set_len(self, new_len)
}
}
impl StorageFile for io::Cursor<Vec<u8>> {
fn set_len(&mut self, new_len: u64) -> io::Result<()> {
self.get_mut().resize(new_len as usize, 0);
Ok(())
}
}
mod private {
pub trait Sealed {}
impl<T: Sealed> Sealed for &mut T {}
impl Sealed for std::fs::File {}
impl Sealed for std::io::Cursor<Vec<u8>> {}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Read;
use std::path::Path;
fn probe(path: impl AsRef<Path>) -> [u8; 12] {
let mut f = fs::File::open(path).unwrap();
let mut b = [0u8; 12];
f.read(&mut b[..]).unwrap();
b
}
#[test]
fn test_format_magic() {
assert_eq!(
Format::magic(probe("testdata/aiff/padding.aiff")),
Some(Format::Aiff)
);
assert_eq!(
Format::magic(probe("testdata/aiff/quiet.aiff")),
Some(Format::Aiff)
);
assert_eq!(
Format::magic(probe("testdata/wav/tagged-end.wav")),
Some(Format::Wav)
);
assert_eq!(
Format::magic(probe("testdata/wav/tagless.wav")),
Some(Format::Wav)
);
assert_eq!(
Format::magic(probe("testdata/id3v22.id3")),
Some(Format::Header)
);
assert_eq!(Format::magic(probe("testdata/mpeg-header")), None);
}
}