use crate::header::{error::HeaderError, AudioFormat, Header};
use crate::read::{ReadError, Reader};
use crate::stream::{LazyStream, Stream, StreamIntoIter};
use std::{
error::Error,
fmt::{Display, Formatter, Result as FmtResult},
io::Read,
num::NonZeroU32,
};
use tap::Pipe;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Bank<R: Read> {
header: Header,
read: Reader<R>,
}
impl<R: Read> Bank<R> {
pub fn new(source: R) -> Result<Self, DecodeError> {
let mut read = Reader::new(source);
let header = Header::parse(&mut read)?;
Ok(Self { header, read })
}
#[must_use]
pub fn format(&self) -> AudioFormat {
self.header.format
}
#[must_use]
pub fn num_streams(&self) -> NonZeroU32 {
self.header
.stream_info
.len()
.pipe(u32::try_from)
.expect("stream count was already validated to be NonZeroU32")
.try_into()
.expect("stream count was already validated to be NonZeroU32")
}
pub fn read_streams<F, E>(mut self, f: F) -> Result<(), LazyStreamError<E>>
where
F: Fn(LazyStream<'_, R>) -> Result<(), E>,
{
for (info, index) in self.header.stream_info.iter().zip(0..) {
let size = u32::from(info.size) as usize;
let start_pos = self.read.position();
f(LazyStream::new(
index,
self.header.format,
self.header.flags,
info,
&mut self.read,
))
.map_err(LazyStreamError::from_other(index))?;
self.read
.advance_to(start_pos + size)
.map_err(LazyStreamError::from_read(index))?;
}
Ok(())
}
}
impl<R: Read> From<Bank<R>> for StreamIntoIter<R> {
fn from(value: Bank<R>) -> Self {
Self::new(
value.header.format,
value.header.flags,
value.header.stream_info,
value.read,
)
}
}
impl<R: Read> IntoIterator for Bank<R> {
type IntoIter = StreamIntoIter<R>;
type Item = Stream;
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter::from(self)
}
}
#[derive(Debug)]
pub struct DecodeError {
inner: Box<HeaderError>,
}
impl From<HeaderError> for DecodeError {
fn from(value: HeaderError) -> Self {
Self {
inner: Box::new(value),
}
}
}
impl Display for DecodeError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
self.inner.fmt(f)
}
}
impl Error for DecodeError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.inner.source()
}
}
#[derive(Debug)]
pub struct LazyStreamError<E> {
index: u32,
source: LazyStreamErrorSource<E>,
}
#[derive(Debug)]
enum LazyStreamErrorSource<E> {
Read(ReadError),
Other(E),
}
impl<E> LazyStreamError<E> {
fn from_read(index: u32) -> impl FnOnce(ReadError) -> Self {
move |source| Self {
index,
source: LazyStreamErrorSource::Read(source),
}
}
fn from_other(index: u32) -> impl FnOnce(E) -> Self {
move |source| Self {
index,
source: LazyStreamErrorSource::Other(source),
}
}
pub fn index(&self) -> u32 {
self.index
}
}
impl<E> Display for LazyStreamError<E> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.write_fmt(format_args!("failed to process stream at index {}", self.index))
}
}
impl<E: Error + 'static> Error for LazyStreamError<E> {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match &self.source {
LazyStreamErrorSource::Read(e) => Some(e),
LazyStreamErrorSource::Other(e) => Some(e),
}
}
}