From 61b15f290d4aeccba4f402cc77b289ba9caa70c9 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Mon, 27 Oct 2025 22:47:59 +0100 Subject: [PATCH] Refactoring pmoflac - factorisation des erreurs --- pmoflac/src/aiff.rs | 32 ++++------------------------ pmoflac/src/autodetect.rs | 40 +++++++++++++++++++++-------------- pmoflac/src/decoder_common.rs | 35 ++++++++++++++++++++++++++++++ pmoflac/src/mp3.rs | 34 ++++------------------------- pmoflac/src/ogg_common.rs | 39 ++-------------------------------- pmoflac/src/wav.rs | 32 ++++------------------------ 6 files changed, 73 insertions(+), 139 deletions(-) diff --git a/pmoflac/src/aiff.rs b/pmoflac/src/aiff.rs index cafbd183..189e843a 100644 --- a/pmoflac/src/aiff.rs +++ b/pmoflac/src/aiff.rs @@ -20,39 +20,15 @@ use tokio::{ use crate::{ common::ChannelReader, - decoder_common::{spawn_ingest_task, spawn_writer_task, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE}, + decoder_common::{ + spawn_ingest_task, spawn_writer_task, DecoderError, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE, + }, pcm::StreamInfo, stream::ManagedAsyncReader, }; /// Errors that can occur while decoding AIFF data. -#[derive(thiserror::Error, Debug, Clone)] -pub enum AiffError { - #[error("I/O error ({kind:?}): {message}")] - Io { - kind: io::ErrorKind, - message: String, - }, - #[error("AIFF decode error: {0}")] - Decode(String), - #[error("internal channel closed unexpectedly")] - ChannelClosed, -} - -impl From for AiffError { - fn from(err: io::Error) -> Self { - AiffError::Io { - kind: err.kind(), - message: err.to_string(), - } - } -} - -impl From for AiffError { - fn from(value: String) -> Self { - AiffError::Decode(value) - } -} +pub type AiffError = DecoderError; /// Streaming reader that buffers bytes as they arrive and exposes convenience helpers. struct StreamingAiffReader diff --git a/pmoflac/src/autodetect.rs b/pmoflac/src/autodetect.rs index cd27242b..2bda9060 100644 --- a/pmoflac/src/autodetect.rs +++ b/pmoflac/src/autodetect.rs @@ -23,17 +23,17 @@ pub enum DecodeAudioError { #[error("unknown or unsupported audio format")] UnknownFormat, #[error("FLAC decode error: {0}")] - Flac(#[from] FlacError), + Flac(FlacError), #[error("MP3 decode error: {0}")] - Mp3(#[from] Mp3Error), + Mp3(Mp3Error), #[error("Ogg/Vorbis decode error: {0}")] Vorbis(OggError), #[error("Ogg/Opus decode error: {0}")] Opus(OggOpusError), #[error("WAV decode error: {0}")] - Wav(#[from] WavError), + Wav(WavError), #[error("AIFF decode error: {0}")] - Aiff(#[from] AiffError), + Aiff(AiffError), } pub async fn decode_audio_stream(reader: R) -> Result @@ -59,11 +59,15 @@ where let stream = match format { DetectedFormat::Flac => { - let stream = decode_flac_stream(prefixed).await?; + let stream = decode_flac_stream(prefixed) + .await + .map_err(DecodeAudioError::Flac)?; DecodedAudioStream::Flac(stream) } DetectedFormat::Mp3 => { - let stream = decode_mp3_stream(prefixed).await?; + let stream = decode_mp3_stream(prefixed) + .await + .map_err(DecodeAudioError::Mp3)?; DecodedAudioStream::Mp3(stream) } DetectedFormat::OggVorbis => { @@ -79,11 +83,15 @@ where DecodedAudioStream::OggOpus(stream) } DetectedFormat::Wav => { - let stream = decode_wav_stream(prefixed).await?; + let stream = decode_wav_stream(prefixed) + .await + .map_err(DecodeAudioError::Wav)?; DecodedAudioStream::Wav(stream) } DetectedFormat::Aiff => { - let stream = decode_aiff_stream(prefixed).await?; + let stream = decode_aiff_stream(prefixed) + .await + .map_err(DecodeAudioError::Aiff)?; DecodedAudioStream::Aiff(stream) } }; @@ -114,16 +122,16 @@ impl DecodedAudioStream { pub async fn wait(self) -> Result<(), DecodeAudioError> { match self { - DecodedAudioStream::Flac(inner) => inner.wait().await.map_err(DecodeAudioError::from), - DecodedAudioStream::Mp3(inner) => inner.wait().await.map_err(DecodeAudioError::from), + DecodedAudioStream::Flac(inner) => inner.wait().await.map_err(DecodeAudioError::Flac), + DecodedAudioStream::Mp3(inner) => inner.wait().await.map_err(DecodeAudioError::Mp3), DecodedAudioStream::OggVorbis(inner) => { inner.wait().await.map_err(DecodeAudioError::Vorbis) } DecodedAudioStream::OggOpus(inner) => { inner.wait().await.map_err(DecodeAudioError::Opus) } - DecodedAudioStream::Wav(inner) => inner.wait().await.map_err(DecodeAudioError::from), - DecodedAudioStream::Aiff(inner) => inner.wait().await.map_err(DecodeAudioError::from), + DecodedAudioStream::Wav(inner) => inner.wait().await.map_err(DecodeAudioError::Wav), + DecodedAudioStream::Aiff(inner) => inner.wait().await.map_err(DecodeAudioError::Aiff), } } @@ -186,12 +194,12 @@ pub enum DecodedReader { impl DecodedReader { pub async fn wait(self) -> Result<(), DecodeAudioError> { match self { - DecodedReader::Flac(inner) => inner.wait().await.map_err(DecodeAudioError::from), - DecodedReader::Mp3(inner) => inner.wait().await.map_err(DecodeAudioError::from), + DecodedReader::Flac(inner) => inner.wait().await.map_err(DecodeAudioError::Flac), + DecodedReader::Mp3(inner) => inner.wait().await.map_err(DecodeAudioError::Mp3), DecodedReader::OggVorbis(inner) => inner.wait().await.map_err(DecodeAudioError::Vorbis), DecodedReader::OggOpus(inner) => inner.wait().await.map_err(DecodeAudioError::Opus), - DecodedReader::Wav(inner) => inner.wait().await.map_err(DecodeAudioError::from), - DecodedReader::Aiff(inner) => inner.wait().await.map_err(DecodeAudioError::from), + DecodedReader::Wav(inner) => inner.wait().await.map_err(DecodeAudioError::Wav), + DecodedReader::Aiff(inner) => inner.wait().await.map_err(DecodeAudioError::Aiff), } } } diff --git a/pmoflac/src/decoder_common.rs b/pmoflac/src/decoder_common.rs index a228949c..c8da6437 100644 --- a/pmoflac/src/decoder_common.rs +++ b/pmoflac/src/decoder_common.rs @@ -12,6 +12,41 @@ use tokio::{ task::JoinHandle, }; +/// Generic error type shared by the streaming decoders. +#[derive(thiserror::Error, Debug, Clone)] +pub enum DecoderError { + #[error("I/O error ({kind:?}): {message}")] + Io { + kind: io::ErrorKind, + message: String, + }, + #[error("{0}")] + Decode(String), + #[error("internal channel closed unexpectedly")] + ChannelClosed, +} + +impl From for DecoderError { + fn from(err: io::Error) -> Self { + DecoderError::Io { + kind: err.kind(), + message: err.to_string(), + } + } +} + +impl From for DecoderError { + fn from(value: String) -> Self { + DecoderError::Decode(value) + } +} + +impl From<&str> for DecoderError { + fn from(value: &str) -> Self { + DecoderError::Decode(value.to_owned()) + } +} + /// Size of chunks when reading input data. /// /// This size balances between efficient I/O operations and memory usage. diff --git a/pmoflac/src/mp3.rs b/pmoflac/src/mp3.rs index fb388ce7..2488cd73 100644 --- a/pmoflac/src/mp3.rs +++ b/pmoflac/src/mp3.rs @@ -101,41 +101,15 @@ use tokio::{ use crate::{ common::ChannelReader, - decoder_common::{spawn_ingest_task, spawn_writer_task, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE}, + decoder_common::{ + spawn_ingest_task, spawn_writer_task, DecoderError, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE, + }, pcm::StreamInfo, stream::ManagedAsyncReader, }; /// Errors that can occur while decoding MP3 data. -#[derive(thiserror::Error, Debug, Clone)] -pub enum Mp3Error { - #[error("I/O error ({kind:?}): {message}")] - Io { - kind: io::ErrorKind, - message: String, - }, - #[error("MP3 decode error: {0}")] - Decode(String), - #[error("internal channel closed unexpectedly")] - ChannelClosed, - #[error("{role} task failed: {details}")] - TaskJoin { role: &'static str, details: String }, -} - -impl From for Mp3Error { - fn from(err: io::Error) -> Self { - Mp3Error::Io { - kind: err.kind(), - message: err.to_string(), - } - } -} - -impl From for Mp3Error { - fn from(msg: String) -> Self { - Mp3Error::Decode(msg) - } -} +pub type Mp3Error = DecoderError; /// An async stream that decodes MP3 audio into PCM samples. /// diff --git a/pmoflac/src/ogg_common.rs b/pmoflac/src/ogg_common.rs index bd1463e0..331caf28 100644 --- a/pmoflac/src/ogg_common.rs +++ b/pmoflac/src/ogg_common.rs @@ -25,7 +25,7 @@ use std::{ io::{self, Read}, }; -use crate::common::ChannelReader; +use crate::{common::ChannelReader, decoder_common::DecoderError}; /// Maximum number of bytes to scan when searching for Ogg sync pattern. /// @@ -60,42 +60,7 @@ impl Default for OggReaderOptions { } } -/// Shared error type for Ogg container parsing. -#[derive(thiserror::Error, Debug, Clone)] -pub enum OggContainerError { - #[error("I/O error ({kind:?}): {message}")] - Io { - kind: io::ErrorKind, - message: String, - }, - #[error("ogg container error: {0}")] - Decode(String), - #[error("internal channel closed unexpectedly")] - ChannelClosed, - #[error("{role} task failed: {details}")] - TaskJoin { role: &'static str, details: String }, -} - -impl From for OggContainerError { - fn from(err: io::Error) -> Self { - OggContainerError::Io { - kind: err.kind(), - message: err.to_string(), - } - } -} - -impl From for OggContainerError { - fn from(value: String) -> Self { - OggContainerError::Decode(value) - } -} - -impl From<&str> for OggContainerError { - fn from(value: &str) -> Self { - OggContainerError::Decode(value.into()) - } -} +pub type OggContainerError = DecoderError; /// Streaming Ogg packet reader that assembles packets from Ogg pages. /// diff --git a/pmoflac/src/wav.rs b/pmoflac/src/wav.rs index f539dd45..541c5a3d 100644 --- a/pmoflac/src/wav.rs +++ b/pmoflac/src/wav.rs @@ -18,39 +18,15 @@ use tokio::{ use crate::{ common::ChannelReader, - decoder_common::{spawn_ingest_task, spawn_writer_task, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE}, + decoder_common::{ + spawn_ingest_task, spawn_writer_task, DecoderError, CHANNEL_CAPACITY, DUPLEX_BUFFER_SIZE, + }, pcm::StreamInfo, stream::ManagedAsyncReader, }; /// Errors that can occur while decoding WAV data. -#[derive(thiserror::Error, Debug, Clone)] -pub enum WavError { - #[error("I/O error ({kind:?}): {message}")] - Io { - kind: io::ErrorKind, - message: String, - }, - #[error("WAV decode error: {0}")] - Decode(String), - #[error("internal channel closed unexpectedly")] - ChannelClosed, -} - -impl From for WavError { - fn from(err: io::Error) -> Self { - WavError::Io { - kind: err.kind(), - message: err.to_string(), - } - } -} - -impl From for WavError { - fn from(value: String) -> Self { - WavError::Decode(value) - } -} +pub type WavError = DecoderError; /// Streaming WAV reader state. struct StreamingWavReader