diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 8521175a..8efbc794 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -17,6 +17,7 @@ Thom Chiovoloni # Please keep this section sorted in ascending order. aschey [https://github.com/aschey] +atoktoto [https://github.com/atoktoto] BlackHoleFox [https://github.com/blackholefox] darksv [https://github.com/darksv] dedobbin [https://github.com/dedobbin] diff --git a/symphonia-bundle-flac/Cargo.toml b/symphonia-bundle-flac/Cargo.toml index 21ab2593..13e7ccb9 100644 --- a/symphonia-bundle-flac/Cargo.toml +++ b/symphonia-bundle-flac/Cargo.toml @@ -14,6 +14,10 @@ rust-version = "1.53" [dependencies] log = "0.4" -symphonia-core = { version = "0.5.2", path = "../symphonia-core" } -symphonia-metadata = { version = "0.5.2", path = "../symphonia-metadata" } -symphonia-utils-xiph = { version = "0.5.2", path = "../symphonia-utils-xiph" } \ No newline at end of file +symphonia-core = { version = "0.5.2", path = "../symphonia-core", default-features = false } +symphonia-metadata = { version = "0.5.2", path = "../symphonia-metadata", default-features = false } +symphonia-utils-xiph = { version = "0.5.2", path = "../symphonia-utils-xiph", default-features = false } + +[features] +std = ["symphonia-core/std", "symphonia-metadata/std", "symphonia-utils-xiph/std"] +default = ["std"] \ No newline at end of file diff --git a/symphonia-bundle-flac/src/decoder.rs b/symphonia-bundle-flac/src/decoder.rs index ce02fdda..658a628f 100644 --- a/symphonia-bundle-flac/src/decoder.rs +++ b/symphonia-bundle-flac/src/decoder.rs @@ -5,9 +5,10 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::cmp; -use std::convert::TryInto; -use std::num::Wrapping; +use alloc::string::String; +use core::cmp; +use core::convert::TryInto; +use core::num::Wrapping; use symphonia_core::audio::{AsAudioBufferRef, AudioBuffer, AudioBufferRef}; use symphonia_core::audio::{Signal, SignalSpec}; @@ -263,7 +264,7 @@ impl Decoder for FlacDecoder { // Only generate the expected and decoded MD5 checksum strings if logging is // enabled at the debug level. if log_enabled!(log::Level::Debug) { - use std::fmt::Write; + use core::fmt::Write; let mut expected_s = String::with_capacity(32); let mut decoded_s = String::with_capacity(32); diff --git a/symphonia-bundle-flac/src/demuxer.rs b/symphonia-bundle-flac/src/demuxer.rs index 2ae595f9..bcd125d4 100644 --- a/symphonia-bundle-flac/src/demuxer.rs +++ b/symphonia-bundle-flac/src/demuxer.rs @@ -5,8 +5,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::io::{Seek, SeekFrom}; - +use alloc::boxed::Box; +use alloc::vec::Vec; use symphonia_core::support_format; use symphonia_core::codecs::{CodecParameters, VerificationCheck, CODEC_TYPE_FLAC}; diff --git a/symphonia-bundle-flac/src/lib.rs b/symphonia-bundle-flac/src/lib.rs index c1ffec2c..d343fbe9 100644 --- a/symphonia-bundle-flac/src/lib.rs +++ b/symphonia-bundle-flac/src/lib.rs @@ -13,6 +13,9 @@ #![allow(clippy::excessive_precision)] #![allow(clippy::identity_op)] #![allow(clippy::manual_range_contains)] +#![no_std] + +extern crate alloc; mod decoder; mod demuxer; diff --git a/symphonia-bundle-flac/src/parser.rs b/symphonia-bundle-flac/src/parser.rs index cd389ccc..df2c5bb6 100644 --- a/symphonia-bundle-flac/src/parser.rs +++ b/symphonia-bundle-flac/src/parser.rs @@ -5,6 +5,9 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use alloc::boxed::Box; +use alloc::vec; +use alloc::vec::Vec; use symphonia_core::checksum::Crc16Ansi; use symphonia_core::errors::Result; use symphonia_core::formats::Packet; diff --git a/symphonia-bundle-flac/src/validate.rs b/symphonia-bundle-flac/src/validate.rs index e42a8d31..d58d87c8 100644 --- a/symphonia-bundle-flac/src/validate.rs +++ b/symphonia-bundle-flac/src/validate.rs @@ -5,8 +5,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::mem; -use std::vec::Vec; +use alloc::vec::Vec; +use core::mem; use symphonia_core::audio::{AudioBuffer, Signal}; use symphonia_core::checksum::Md5; diff --git a/symphonia-bundle-mp3/src/demuxer.rs b/symphonia-bundle-mp3/src/demuxer.rs index ee389ec2..f706c0fb 100644 --- a/symphonia-bundle-mp3/src/demuxer.rs +++ b/symphonia-bundle-mp3/src/demuxer.rs @@ -18,8 +18,6 @@ use symphonia_core::probe::{Descriptor, Instantiate, QueryDescriptor}; use crate::common::{FrameHeader, MpegLayer}; use crate::header::{self, MAX_MPEG_FRAME_SIZE, MPEG_HEADER_LEN}; -use std::io::{Seek, SeekFrom}; - use log::{debug, info, warn}; /// MPEG1 and MPEG2 audio elementary stream reader. diff --git a/symphonia-bundle-mp3/src/layer3/mod.rs b/symphonia-bundle-mp3/src/layer3/mod.rs index d1257486..6da0fbe9 100644 --- a/symphonia-bundle-mp3/src/layer3/mod.rs +++ b/symphonia-bundle-mp3/src/layer3/mod.rs @@ -8,7 +8,8 @@ use std::fmt; use symphonia_core::audio::{AudioBuffer, Signal}; -use symphonia_core::errors::{decode_error, Error, Result}; +use symphonia_core::errors::SymphoniaError as Error; +use symphonia_core::errors::{decode_error, Result}; use symphonia_core::io::{BitReaderLtr, BufReader, ReadBitsLtr, ReadBytes}; mod bitstream; @@ -356,7 +357,7 @@ impl Layer3 { // IO error to a decode error. frame_data.granules[gr].channels[ch].rzero = match huffman_result { Ok(rzero) => rzero, - Err(Error::IoError(e)) if e.kind() == std::io::ErrorKind::Other => { + Err(Error::IoError(_)) => { return decode_error("mpa: huffman decode overrun"); } Err(err) => return Err(err), diff --git a/symphonia-bundle-mp3/src/lib.rs b/symphonia-bundle-mp3/src/lib.rs index def350db..08ac92e0 100644 --- a/symphonia-bundle-mp3/src/lib.rs +++ b/symphonia-bundle-mp3/src/lib.rs @@ -14,6 +14,8 @@ #![allow(clippy::identity_op)] #![allow(clippy::manual_range_contains)] +extern crate alloc; + // Shared modules. mod common; mod header; diff --git a/symphonia-check/src/main.rs b/symphonia-check/src/main.rs index 1682074f..74153d6d 100644 --- a/symphonia-check/src/main.rs +++ b/symphonia-check/src/main.rs @@ -18,7 +18,8 @@ use std::process::{Command, Stdio}; use symphonia::core::audio::{AudioBufferRef, SampleBuffer}; use symphonia::core::codecs::{Decoder, DecoderOptions}; -use symphonia::core::errors::{Error, Result}; +use symphonia::core::errors::Result; +use symphonia::core::errors::SymphoniaError as Error; use symphonia::core::formats::{FormatOptions, FormatReader}; use symphonia::core::io::{MediaSourceStream, ReadOnlySource}; use symphonia::core::meta::MetadataOptions; @@ -396,7 +397,7 @@ fn main() { println!(); match run_test(path, &opts, &mut res) { - Err(Error::IoError(err)) if err.kind() == std::io::ErrorKind::UnexpectedEof => (), + Err(Error::EndOfFile) => (), Err(err) => { eprintln!("Test interrupted by error: {}", err); std::process::exit(2); diff --git a/symphonia-codec-aac/src/aac/codebooks.rs b/symphonia-codec-aac/src/aac/codebooks.rs index 88370aa1..f33eeb5a 100644 --- a/symphonia-codec-aac/src/aac/codebooks.rs +++ b/symphonia-codec-aac/src/aac/codebooks.rs @@ -5,6 +5,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. +use symphonia_core::errors::Result; use symphonia_core::io::{vlc::*, ReadBitsLtr}; use lazy_static::lazy_static; @@ -500,7 +501,7 @@ pub struct QuadsCodebook { impl QuadsCodebook { #[inline(always)] - pub fn read_quant(&self, bs: &mut B) -> std::io::Result<(u8, u8, u8, u8)> { + pub fn read_quant(&self, bs: &mut B) -> Result<(u8, u8, u8, u8)> { bs.read_codebook(&self.codebook).map(|(cw, _)| AAC_QUADS[cw as usize]) } } @@ -522,7 +523,7 @@ pub struct PairsCodebook { impl PairsCodebook { #[inline(always)] - pub fn read_dequant(&self, bs: &mut B) -> std::io::Result<(f32, f32)> { + pub fn read_dequant(&self, bs: &mut B) -> Result<(f32, f32)> { bs.read_codebook(&self.codebook).map(|(cw, _)| self.values[cw as usize]) } } @@ -543,7 +544,7 @@ pub struct EscapeCodebook { impl EscapeCodebook { #[inline(always)] - pub fn read_quant(&self, bs: &mut B) -> std::io::Result<(u16, u16)> { + pub fn read_quant(&self, bs: &mut B) -> Result<(u16, u16)> { bs.read_codebook(&self.codebook).map(|(cw, _)| self.values[cw as usize]) } } diff --git a/symphonia-codec-aac/src/adts.rs b/symphonia-codec-aac/src/adts.rs index 596c41dc..7ff60dca 100644 --- a/symphonia-codec-aac/src/adts.rs +++ b/symphonia-codec-aac/src/adts.rs @@ -16,11 +16,10 @@ use symphonia_core::io::*; use symphonia_core::meta::{Metadata, MetadataLog}; use symphonia_core::probe::{Descriptor, Instantiate, QueryDescriptor}; -use std::io::{Seek, SeekFrom}; - use super::common::{map_channels, M4AType, AAC_SAMPLE_RATES, M4A_TYPES}; use log::debug; +use symphonia_core::io::Seek; const SAMPLES_PER_AAC_PACKET: u64 = 1024; diff --git a/symphonia-codec-aac/src/lib.rs b/symphonia-codec-aac/src/lib.rs index 34c8c9f8..08ca8fad 100644 --- a/symphonia-codec-aac/src/lib.rs +++ b/symphonia-codec-aac/src/lib.rs @@ -16,6 +16,8 @@ // TODO: Remove this when refactoring AAC. #![allow(clippy::needless_range_loop)] +extern crate alloc; + mod aac; mod adts; mod common; diff --git a/symphonia-codec-aac/tests/tests.rs b/symphonia-codec-aac/tests/tests.rs index 6f2e3c89..7ba3d3ea 100644 --- a/symphonia-codec-aac/tests/tests.rs +++ b/symphonia-codec-aac/tests/tests.rs @@ -31,5 +31,5 @@ fn invalid_channels_aac() { let err = test_decode(file).unwrap_err(); - assert!(matches!(err, errors::Error::Unsupported(_))); + assert!(matches!(err, errors::SymphoniaError::Unsupported(_))); } diff --git a/symphonia-codec-adpcm/src/lib.rs b/symphonia-codec-adpcm/src/lib.rs index 4d69fe3e..079d8512 100644 --- a/symphonia-codec-adpcm/src/lib.rs +++ b/symphonia-codec-adpcm/src/lib.rs @@ -24,6 +24,8 @@ use symphonia_core::errors::{unsupported_error, Result}; use symphonia_core::formats::Packet; use symphonia_core::io::ReadBytes; +extern crate alloc; + mod codec_ima; mod codec_ms; mod common; diff --git a/symphonia-codec-alac/src/lib.rs b/symphonia-codec-alac/src/lib.rs index 1ada71ab..e43c2c72 100644 --- a/symphonia-codec-alac/src/lib.rs +++ b/symphonia-codec-alac/src/lib.rs @@ -29,6 +29,8 @@ use symphonia_core::formats::Packet; use symphonia_core::io::{BitReaderLtr, BufReader, FiniteStream, ReadBitsLtr, ReadBytes}; use symphonia_core::support_codec; +extern crate alloc; + /// Supported ALAC version. const ALAC_VERSION: u8 = 0; diff --git a/symphonia-codec-pcm/Cargo.toml b/symphonia-codec-pcm/Cargo.toml index c9c8a67c..dbf1e553 100644 --- a/symphonia-codec-pcm/Cargo.toml +++ b/symphonia-codec-pcm/Cargo.toml @@ -14,4 +14,4 @@ rust-version = "1.53" [dependencies] log = "0.4" -symphonia-core = { version = "0.5.2", path = "../symphonia-core" } \ No newline at end of file +symphonia-core = { version = "0.5.2", path = "../symphonia-core", default-features = false } \ No newline at end of file diff --git a/symphonia-codec-pcm/src/lib.rs b/symphonia-codec-pcm/src/lib.rs index 22f9a857..5e25bf5b 100644 --- a/symphonia-codec-pcm/src/lib.rs +++ b/symphonia-codec-pcm/src/lib.rs @@ -7,6 +7,7 @@ #![warn(rust_2018_idioms)] #![forbid(unsafe_code)] +#![no_std] // The following lints are allowed in all Symphonia crates. Please see clippy.toml for their // justification. #![allow(clippy::comparison_chain)] @@ -14,6 +15,8 @@ #![allow(clippy::identity_op)] #![allow(clippy::manual_range_contains)] +extern crate alloc; + use symphonia_core::support_codec; use symphonia_core::audio::{AsAudioBufferRef, AudioBuffer, AudioBufferRef, Signal, SignalSpec}; diff --git a/symphonia-codec-vorbis/src/floor.rs b/symphonia-codec-vorbis/src/floor.rs index 1e478a1f..b3c14c25 100644 --- a/symphonia-codec-vorbis/src/floor.rs +++ b/symphonia-codec-vorbis/src/floor.rs @@ -8,7 +8,8 @@ use std::cmp::min; use std::collections::HashSet; -use symphonia_core::errors::{decode_error, Error, Result}; +use symphonia_core::errors::SymphoniaError as Error; +use symphonia_core::errors::{decode_error, Result}; use symphonia_core::io::{BitReaderRtl, ReadBitsRtl}; use super::codebook::VorbisCodebook; @@ -92,7 +93,7 @@ macro_rules! io_try_or_ret { // An end-of-bitstream error is classified under ErrorKind::Other. This condition // should not be treated as an error, rather, it should return from the function // immediately without error. - Err(ref e) if e.kind() == std::io::ErrorKind::Other => return Ok(()), + Err(Error::EndOfFile) => return Ok(()), Err(e) => return Err(e.into()), } }; @@ -105,7 +106,7 @@ macro_rules! try_or_ret { // An end-of-bitstream error is classified under ErrorKind::Other. This condition // should not be treated as an error, rather, it should return from the function // immediately without error. - Err(Error::IoError(ref e)) if e.kind() == std::io::ErrorKind::Other => return Ok(()), + Err(Error::EndOfFile) => return Ok(()), Err(e) => return Err(e), } }; diff --git a/symphonia-codec-vorbis/src/lib.rs b/symphonia-codec-vorbis/src/lib.rs index 59b53455..7726fada 100644 --- a/symphonia-codec-vorbis/src/lib.rs +++ b/symphonia-codec-vorbis/src/lib.rs @@ -16,6 +16,8 @@ // Disable to better express the specification. #![allow(clippy::collapsible_else_if)] +extern crate alloc; + use symphonia_core::audio::{AsAudioBufferRef, AudioBuffer, AudioBufferRef}; use symphonia_core::audio::{Signal, SignalSpec}; use symphonia_core::codecs::{CodecDescriptor, CodecParameters, CODEC_TYPE_VORBIS}; diff --git a/symphonia-codec-vorbis/src/residue.rs b/symphonia-codec-vorbis/src/residue.rs index 0f66c69d..5531571b 100644 --- a/symphonia-codec-vorbis/src/residue.rs +++ b/symphonia-codec-vorbis/src/residue.rs @@ -7,9 +7,9 @@ use std::cmp::min; use std::convert::TryInto; -use std::io; -use symphonia_core::errors::{decode_error, Error, Result}; +use symphonia_core::errors::SymphoniaError as Error; +use symphonia_core::errors::{decode_error, Result}; use symphonia_core::io::{BitReaderRtl, ReadBitsRtl}; use super::codebook::VorbisCodebook; @@ -155,7 +155,7 @@ impl Residue { Ok(_) => (), // An end-of-bitstream error is classified under ErrorKind::Other. This condition // should not be treated as an error. - Err(Error::IoError(ref e)) if e.kind() == io::ErrorKind::Other => (), + Err(Error::EndOfFile) => (), Err(e) => return Err(e), }; diff --git a/symphonia-core/Cargo.toml b/symphonia-core/Cargo.toml index 4db81690..c5cbc3fc 100644 --- a/symphonia-core/Cargo.toml +++ b/symphonia-core/Cargo.toml @@ -13,7 +13,9 @@ edition = "2018" rust-version = "1.53" [features] -default = [] +std = ["arrayvec/std"] +fft = ["rustfft"] +default = ["std", "fft"] # SIMD support. opt-simd-sse = ["rustfft/sse"] @@ -28,11 +30,12 @@ opt-simd = [ ] [dependencies] -arrayvec = "0.7.1" +arrayvec = { version = "0.7.1", default-features = false } bitflags = "1.2.1" bytemuck = "1.7" lazy_static = "1.4.0" log = "0.4" +libm = { version = "0.2.8" } [dependencies.rustfft] version = "6.1.0" diff --git a/symphonia-core/src/audio.rs b/symphonia-core/src/audio.rs index 36f431d2..047cb360 100644 --- a/symphonia-core/src/audio.rs +++ b/symphonia-core/src/audio.rs @@ -8,11 +8,13 @@ //! The `audio` module provides primitives for working with multi-channel audio buffers of varying //! sample formats. -use std::borrow::Cow; -use std::fmt; -use std::marker::PhantomData; -use std::mem; -use std::vec::Vec; +use alloc::borrow::Cow; +use alloc::boxed::Box; +use alloc::vec; +use alloc::vec::Vec; +use core::fmt; +use core::marker::PhantomData; +use core::mem; use arrayvec::ArrayVec; use bitflags::bitflags; diff --git a/symphonia-core/src/checksum/md5.rs b/symphonia-core/src/checksum/md5.rs index 3f44a25b..1834eae0 100644 --- a/symphonia-core/src/checksum/md5.rs +++ b/symphonia-core/src/checksum/md5.rs @@ -5,7 +5,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::cmp; +use core::cmp; use crate::io::Monitor; diff --git a/symphonia-core/src/codecs.rs b/symphonia-core/src/codecs.rs index 31feb1de..281c95a9 100644 --- a/symphonia-core/src/codecs.rs +++ b/symphonia-core/src/codecs.rs @@ -8,9 +8,10 @@ //! The `codec` module provides the traits and support structures necessary to implement audio codec //! decoders. -use std::collections::HashMap; -use std::default::Default; -use std::fmt; +use alloc::boxed::Box; +use alloc::collections::BTreeMap; +use core::default::Default; +use core::fmt; use crate::audio::{AudioBufferRef, Channels, Layout}; use crate::errors::{unsupported_error, Result}; @@ -19,7 +20,7 @@ use crate::sample::SampleFormat; use crate::units::TimeBase; /// A `CodecType` is a unique identifier used to identify a specific codec. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct CodecType(u32); /// Declares a new `CodecType` given a character code. A character code is an ASCII string @@ -522,13 +523,13 @@ pub struct CodecDescriptor { /// A `CodecRegistry` allows the registration of codecs, and provides a method to instantiate a /// `Decoder` given a `CodecParameters` object. pub struct CodecRegistry { - codecs: HashMap, + codecs: BTreeMap, } impl CodecRegistry { /// Instantiate a new `CodecRegistry`. pub fn new() -> Self { - CodecRegistry { codecs: HashMap::new() } + CodecRegistry { codecs: BTreeMap::new() } } /// Gets the `CodecDescriptor` for a registered codec. @@ -582,7 +583,7 @@ macro_rules! support_codec { codec: $type, short_name: $short_name, long_name: $long_name, - inst_func: |params, opt| Ok(Box::new(Self::try_new(¶ms, &opt)?)), + inst_func: |params, opt| Ok(alloc::boxed::Box::new(Self::try_new(¶ms, &opt)?)), } }; } diff --git a/symphonia-core/src/conv.rs b/symphonia-core/src/conv.rs index c41fec3a..408de30b 100644 --- a/symphonia-core/src/conv.rs +++ b/symphonia-core/src/conv.rs @@ -28,7 +28,7 @@ pub mod dither { use super::FromSample; use crate::sample::Sample; use crate::sample::{i24, u24}; - use std::marker::PhantomData; + use core::marker::PhantomData; mod prng { #[inline] @@ -679,7 +679,7 @@ impl ConvertibleSample for S where mod tests { use super::FromSample; use crate::sample::{i24, u24, Sample}; - use std::{i16, i32, i8, u16, u32, u8}; + use core::{i16, i32, i8, u16, u32, u8}; #[test] fn verify_u8_from_sample() { diff --git a/symphonia-core/src/dsp/fft.rs b/symphonia-core/src/dsp/fft.rs index 350ce468..a8cbfe86 100644 --- a/symphonia-core/src/dsp/fft.rs +++ b/symphonia-core/src/dsp/fft.rs @@ -10,8 +10,9 @@ //! The complex (I)FFT in this module supports a size up-to 65536. The FFT is implemented using the //! radix-2 Cooley-Tukey algorithm. -use std::convert::TryInto; -use std::f32; +use alloc::boxed::Box; +use core::convert::TryInto; +use core::f32; use lazy_static::lazy_static; @@ -25,7 +26,7 @@ macro_rules! fft_twiddle_table { let mut table = [Default::default(); N >> 1]; - let theta = std::f64::consts::PI / (N >> 1) as f64; + let theta = core::f64::consts::PI / (N >> 1) as f64; for (k, t) in table.iter_mut().enumerate() { let angle = theta * k as f64; @@ -409,7 +410,8 @@ fn fft2(x: &mut [Complex; 2]) { #[cfg(test)] mod tests { use super::*; - use std::f64; + use alloc::vec::Vec; + use core::f64; /// Compute a naive DFT. fn dft_naive(x: &[Complex], y: &mut [Complex]) { diff --git a/symphonia-core/src/dsp/mdct/no_simd.rs b/symphonia-core/src/dsp/mdct/no_simd.rs index f2853ce8..d18b2755 100644 --- a/symphonia-core/src/dsp/mdct/no_simd.rs +++ b/symphonia-core/src/dsp/mdct/no_simd.rs @@ -9,6 +9,9 @@ use crate::dsp::complex::Complex; use crate::dsp::fft::*; +use alloc::boxed::Box; +use alloc::vec; +use alloc::vec::Vec; /// The Inverse Modified Discrete Transform (IMDCT). pub struct Imdct { diff --git a/symphonia-core/src/dsp/mdct/simd.rs b/symphonia-core/src/dsp/mdct/simd.rs index 502095d6..9ec4b07c 100644 --- a/symphonia-core/src/dsp/mdct/simd.rs +++ b/symphonia-core/src/dsp/mdct/simd.rs @@ -7,7 +7,10 @@ //! The Modified Discrete Cosine Transform (MDCT) implemented with SIMD optimizations. -use std::sync::Arc; +use alloc::boxed::Box; +use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; use rustfft::num_complex::Complex; @@ -42,7 +45,7 @@ impl Imdct { let mut twiddle = Vec::with_capacity(n2); let alpha = 1.0 / 8.0 + if scale.is_sign_positive() { 0.0 } else { n2 as f64 }; - let pi_n = std::f64::consts::PI / n as f64; + let pi_n = core::f64::consts::PI / n as f64; let sqrt_scale = scale.abs().sqrt(); for k in 0..n2 { diff --git a/symphonia-core/src/dsp/mod.rs b/symphonia-core/src/dsp/mod.rs index 8de8f0cc..243198fb 100644 --- a/symphonia-core/src/dsp/mod.rs +++ b/symphonia-core/src/dsp/mod.rs @@ -8,5 +8,7 @@ //! The `dsp` module provides efficient implementations of common signal processing algorithms. pub mod complex; +#[cfg(feature = "fft")] pub mod fft; +#[cfg(feature = "fft")] pub mod mdct; diff --git a/symphonia-core/src/errors.rs b/symphonia-core/src/errors.rs index 7959b3b9..42be564a 100644 --- a/symphonia-core/src/errors.rs +++ b/symphonia-core/src/errors.rs @@ -7,10 +7,17 @@ //! The `errors` module defines the common error type. -use std::error; -use std::fmt; -use std::io; -use std::result; +use alloc::boxed::Box; +use core::fmt; +use core::fmt::Display; +use core::result; + +#[cfg(not(feature = "std"))] +use core::error::Error as StdError; + +use core::ops::Deref; +#[cfg(feature = "std")] +use std::error::Error as StdError; /// `SeekErrorKind` is a list of generic reasons why a seek may fail. #[derive(Debug)] @@ -38,9 +45,11 @@ impl SeekErrorKind { /// `Error` provides an enumeration of all possible errors reported by Symphonia. #[derive(Debug)] -pub enum Error { - /// An IO error occured while reading, writing, or seeking the stream. - IoError(std::io::Error), +pub enum SymphoniaError { + /// An IO error occurred while reading, writing, or seeking the stream. + IoError(Box), + /// An IO error occurred while reading, writing, or seeking the stream that is retryable. + IoInterruptedError(Box), /// The stream contained malformed data and could not be decoded or demuxed. DecodeError(&'static str), /// The stream could not be seeked. @@ -52,78 +61,93 @@ pub enum Error { LimitError(&'static str), /// The demuxer or decoder needs to be reset before continuing. ResetRequired, + EndOfFile, + Other(&'static str), } -impl fmt::Display for Error { +impl Display for SymphoniaError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::IoError(ref err) => err.fmt(f), - Error::DecodeError(msg) => { + SymphoniaError::IoError(ref err) => { + write!(f, "io error {:?}", err) + } + SymphoniaError::IoInterruptedError(ref err) => { + write!(f, "io error {:?}", err) + } + SymphoniaError::DecodeError(msg) => { write!(f, "malformed stream: {}", msg) } - Error::SeekError(ref kind) => { + SymphoniaError::SeekError(ref kind) => { write!(f, "seek error: {}", kind.as_str()) } - Error::Unsupported(feature) => { + SymphoniaError::Unsupported(feature) => { write!(f, "unsupported feature: {}", feature) } - Error::LimitError(constraint) => { + SymphoniaError::LimitError(constraint) => { write!(f, "limit reached: {}", constraint) } - Error::ResetRequired => { + SymphoniaError::ResetRequired => { write!(f, "decoder needs to be reset") } + SymphoniaError::EndOfFile => { + write!(f, "unexpected end of file") + } + SymphoniaError::Other(msg) => { + write!(f, "other error: {}", msg) + } } } } -impl std::error::Error for Error { - fn cause(&self) -> Option<&dyn error::Error> { +impl StdError for SymphoniaError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { match *self { - Error::IoError(ref err) => Some(err), - Error::DecodeError(_) => None, - Error::SeekError(_) => None, - Error::Unsupported(_) => None, - Error::LimitError(_) => None, - Error::ResetRequired => None, + SymphoniaError::IoError(ref err) => Some(err.deref()), + SymphoniaError::IoInterruptedError(ref err) => Some(err.deref()), + _ => None, } } } -impl From for Error { - fn from(err: io::Error) -> Error { - Error::IoError(err) +#[cfg(feature = "std")] +impl From for SymphoniaError { + fn from(err: std::io::Error) -> SymphoniaError { + match err.kind() { + std::io::ErrorKind::Interrupted => SymphoniaError::IoInterruptedError(Box::new(err)), + std::io::ErrorKind::UnexpectedEof => SymphoniaError::EndOfFile, + _ => SymphoniaError::IoError(Box::new(err)), + } } } -pub type Result = result::Result; +pub type Result = result::Result; /// Convenience function to create a decode error. pub fn decode_error(desc: &'static str) -> Result { - Err(Error::DecodeError(desc)) + Err(SymphoniaError::DecodeError(desc)) } /// Convenience function to create a seek error. pub fn seek_error(kind: SeekErrorKind) -> Result { - Err(Error::SeekError(kind)) + Err(SymphoniaError::SeekError(kind)) } /// Convenience function to create an unsupport feature error. pub fn unsupported_error(feature: &'static str) -> Result { - Err(Error::Unsupported(feature)) + Err(SymphoniaError::Unsupported(feature)) } /// Convenience function to create a limit error. pub fn limit_error(constraint: &'static str) -> Result { - Err(Error::LimitError(constraint)) + Err(SymphoniaError::LimitError(constraint)) } /// Convenience function to create a reset required error. pub fn reset_error() -> Result { - Err(Error::ResetRequired) + Err(SymphoniaError::ResetRequired) } /// Convenience function to create an end-of-stream error. pub fn end_of_stream_error() -> Result { - Err(Error::IoError(io::Error::new(io::ErrorKind::UnexpectedEof, "end of stream"))) + Err(SymphoniaError::EndOfFile) } diff --git a/symphonia-core/src/formats.rs b/symphonia-core/src/formats.rs index 58158f31..ed6a99b5 100644 --- a/symphonia-core/src/formats.rs +++ b/symphonia-core/src/formats.rs @@ -13,6 +13,9 @@ use crate::errors::Result; use crate::io::{BufReader, MediaSourceStream}; use crate::meta::{Metadata, Tag}; use crate::units::{Time, TimeStamp}; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; pub mod prelude { //! The `formats` module prelude. @@ -165,7 +168,7 @@ impl Track { /// `FormatReader` provides an Iterator-like interface over packets for easy consumption and /// filtering. Seeking will invalidate the state of any `Decoder` processing packets from the /// `FormatReader` and should be reset after a successful seek operation. -pub trait FormatReader: Send + Sync { +pub trait FormatReader { /// Attempt to instantiate a `FormatReader` using the provided `FormatOptions` and /// `MediaSourceStream`. The reader will probe the container to verify format support, determine /// the number of tracks, and read any initial metadata. @@ -328,6 +331,7 @@ pub mod util { //! Helper utilities for implementing `FormatReader`s. use super::Packet; + use alloc::vec::Vec; /// A `SeekPoint` is a mapping between a sample or frame number to byte offset within a media /// stream. diff --git a/symphonia-core/src/io/bit.rs b/symphonia-core/src/io/bit.rs index 82cbe32e..8d274878 100644 --- a/symphonia-core/src/io/bit.rs +++ b/symphonia-core/src/io/bit.rs @@ -5,25 +5,28 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::cmp::min; -use std::io; +use core::cmp::min; +use crate::errors::Result; +use crate::errors::SymphoniaError as Error; use crate::io::ReadBytes; use crate::util::bits::*; -fn end_of_bitstream_error() -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, "unexpected end of bitstream")) +fn end_of_bitstream_error() -> Result { + Err(Error::Other("unexpected end of bitstream")) } pub mod vlc { //! The `vlc` module provides support for decoding variable-length codes (VLC). - use std::cmp::max; - use std::collections::{BTreeMap, VecDeque}; - use std::io; + use crate::errors::Result; + use crate::errors::SymphoniaError as Error; + use alloc::collections::{BTreeMap, VecDeque}; + use alloc::vec::Vec; + use core::cmp::max; - fn codebook_error(desc: &'static str) -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, desc)) + fn codebook_error(desc: &'static str) -> Result { + Err(Error::Other(desc)) } /// `BitOrder` describes the relationship between the order of bits in the provided codewords @@ -297,7 +300,7 @@ pub mod vlc { bit_order: BitOrder, is_sparse: bool, blocks: &[CodebookBlock], - ) -> io::Result> { + ) -> Result> { // The codebook table. let mut table = Vec::new(); @@ -434,7 +437,7 @@ pub mod vlc { code_words: &[u32], code_lens: &[u8], values: &[E::ValueType], - ) -> io::Result> { + ) -> Result> { assert!(code_words.len() == code_lens.len()); assert!(code_words.len() == values.len()); @@ -522,14 +525,14 @@ pub mod vlc { } mod private { - use std::io; + use crate::errors::Result; pub trait FetchBitsLtr { /// Discard any remaining bits in the source and fetch new bits. - fn fetch_bits(&mut self) -> io::Result<()>; + fn fetch_bits(&mut self) -> Result<()>; /// Fetch new bits, and append them after the remaining bits. - fn fetch_bits_partial(&mut self) -> io::Result<()>; + fn fetch_bits_partial(&mut self) -> Result<()>; /// Get all the bits in the source. fn get_bits(&self) -> u64; @@ -543,10 +546,10 @@ mod private { pub trait FetchBitsRtl { /// Discard any remaining bits in the source and fetch new bits. - fn fetch_bits(&mut self) -> io::Result<()>; + fn fetch_bits(&mut self) -> Result<()>; /// Fetch new bits, and append them after the remaining bits. - fn fetch_bits_partial(&mut self) -> io::Result<()>; + fn fetch_bits_partial(&mut self) -> Result<()>; /// Get all the bits in the source. fn get_bits(&self) -> u64; @@ -576,7 +579,7 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { /// Ignores the specified number of bits from the stream or returns an error. #[inline(always)] - fn ignore_bits(&mut self, mut num_bits: u32) -> io::Result<()> { + fn ignore_bits(&mut self, mut num_bits: u32) -> Result<()> { if num_bits <= self.num_bits_left() { self.consume_bits(num_bits); } @@ -599,13 +602,13 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { /// Ignores one bit from the stream or returns an error. #[inline(always)] - fn ignore_bit(&mut self) -> io::Result<()> { + fn ignore_bit(&mut self) -> Result<()> { self.ignore_bits(1) } /// Read a single bit as a boolean value or returns an error. #[inline(always)] - fn read_bool(&mut self) -> io::Result { + fn read_bool(&mut self) -> Result { if self.num_bits_left() < 1 { self.fetch_bits()?; } @@ -618,7 +621,7 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { /// Reads and returns a single bit or returns an error. #[inline(always)] - fn read_bit(&mut self) -> io::Result { + fn read_bit(&mut self) -> Result { if self.num_bits_left() < 1 { self.fetch_bits()?; } @@ -632,7 +635,7 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { /// Reads and returns up to 32-bits or returns an error. #[inline(always)] - fn read_bits_leq32(&mut self, mut bit_width: u32) -> io::Result { + fn read_bits_leq32(&mut self, mut bit_width: u32) -> Result { debug_assert!(bit_width <= u32::BITS); // Shift in two 32-bit operations instead of a single 64-bit operation to avoid panicing @@ -658,14 +661,14 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { /// Reads up to 32-bits and interprets them as a signed two's complement integer or returns an /// error. #[inline(always)] - fn read_bits_leq32_signed(&mut self, bit_width: u32) -> io::Result { + fn read_bits_leq32_signed(&mut self, bit_width: u32) -> Result { let value = self.read_bits_leq32(bit_width)?; Ok(sign_extend_leq32_to_i32(value, bit_width)) } /// Reads and returns up to 64-bits or returns an error. #[inline(always)] - fn read_bits_leq64(&mut self, mut bit_width: u32) -> io::Result { + fn read_bits_leq64(&mut self, mut bit_width: u32) -> Result { debug_assert!(bit_width <= u64::BITS); // Hard-code the bit_width == 0 case as it's not possible to handle both the bit_width == 0 @@ -699,14 +702,14 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { /// Reads up to 64-bits and interprets them as a signed two's complement integer or returns an /// error. #[inline(always)] - fn read_bits_leq64_signed(&mut self, bit_width: u32) -> io::Result { + fn read_bits_leq64_signed(&mut self, bit_width: u32) -> Result { let value = self.read_bits_leq64(bit_width)?; Ok(sign_extend_leq64_to_i64(value, bit_width)) } /// Reads and returns a unary zeros encoded integer or an error. #[inline(always)] - fn read_unary_zeros(&mut self) -> io::Result { + fn read_unary_zeros(&mut self) -> Result { let mut num = 0; loop { @@ -739,7 +742,7 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { /// Reads and returns a unary zeros encoded integer that is capped to a maximum value. #[inline(always)] - fn read_unary_zeros_capped(&mut self, mut limit: u32) -> io::Result { + fn read_unary_zeros_capped(&mut self, mut limit: u32) -> Result { let mut num = 0; loop { @@ -776,7 +779,7 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { /// Reads and returns a unary ones encoded integer or an error. #[inline(always)] - fn read_unary_ones(&mut self) -> io::Result { + fn read_unary_ones(&mut self) -> Result { // Note: This algorithm is identical to read_unary_zeros except flipped for 1s. let mut num = 0; @@ -802,7 +805,7 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { /// Reads and returns a unary ones encoded integer that is capped to a maximum value. #[inline(always)] - fn read_unary_ones_capped(&mut self, mut limit: u32) -> io::Result { + fn read_unary_ones_capped(&mut self, mut limit: u32) -> Result { // Note: This algorithm is identical to read_unary_zeros_capped except flipped for 1s. let mut num = 0; @@ -838,7 +841,7 @@ pub trait ReadBitsLtr: private::FetchBitsLtr { fn read_codebook( &mut self, codebook: &vlc::Codebook, - ) -> io::Result<(E::ValueType, u32)> { + ) -> Result<(E::ValueType, u32)> { // Attempt refill the bit buffer with enough bits for the longest codeword in the codebook. // However, this does not mean the bit buffer will have enough bits to decode a codeword. if self.num_bits_left() < codebook.max_code_len { @@ -907,14 +910,14 @@ impl<'a, B: ReadBytes> BitStreamLtr<'a, B> { impl<'a, B: ReadBytes> private::FetchBitsLtr for BitStreamLtr<'a, B> { #[inline(always)] - fn fetch_bits(&mut self) -> io::Result<()> { + fn fetch_bits(&mut self) -> Result<()> { self.bits = u64::from(self.reader.read_u8()?) << 56; self.n_bits_left = u8::BITS; Ok(()) } #[inline(always)] - fn fetch_bits_partial(&mut self) -> io::Result<()> { + fn fetch_bits_partial(&mut self) -> Result<()> { todo!() } @@ -956,8 +959,8 @@ impl<'a> BitReaderLtr<'a> { impl<'a> private::FetchBitsLtr for BitReaderLtr<'a> { #[inline] - fn fetch_bits_partial(&mut self) -> io::Result<()> { - let mut buf = [0u8; std::mem::size_of::()]; + fn fetch_bits_partial(&mut self) -> Result<()> { + let mut buf = [0u8; core::mem::size_of::()]; let read_len = min(self.buf.len(), (u64::BITS - self.n_bits_left) as usize >> 3); @@ -971,10 +974,10 @@ impl<'a> private::FetchBitsLtr for BitReaderLtr<'a> { Ok(()) } - fn fetch_bits(&mut self) -> io::Result<()> { - let mut buf = [0u8; std::mem::size_of::()]; + fn fetch_bits(&mut self) -> Result<()> { + let mut buf = [0u8; core::mem::size_of::()]; - let read_len = min(self.buf.len(), std::mem::size_of::()); + let read_len = min(self.buf.len(), core::mem::size_of::()); if read_len == 0 { return end_of_bitstream_error(); @@ -1026,7 +1029,7 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { /// Ignores the specified number of bits from the stream or returns an error. #[inline(always)] - fn ignore_bits(&mut self, mut num_bits: u32) -> io::Result<()> { + fn ignore_bits(&mut self, mut num_bits: u32) -> Result<()> { if num_bits <= self.num_bits_left() { self.consume_bits(num_bits); } @@ -1049,13 +1052,13 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { /// Ignores one bit from the stream or returns an error. #[inline(always)] - fn ignore_bit(&mut self) -> io::Result<()> { + fn ignore_bit(&mut self) -> Result<()> { self.ignore_bits(1) } /// Read a single bit as a boolean value or returns an error. #[inline(always)] - fn read_bool(&mut self) -> io::Result { + fn read_bool(&mut self) -> Result { if self.num_bits_left() < 1 { self.fetch_bits()?; } @@ -1068,7 +1071,7 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { /// Reads and returns a single bit or returns an error. #[inline(always)] - fn read_bit(&mut self) -> io::Result { + fn read_bit(&mut self) -> Result { if self.num_bits_left() < 1 { self.fetch_bits()?; } @@ -1082,7 +1085,7 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { /// Reads and returns up to 32-bits or returns an error. #[inline(always)] - fn read_bits_leq32(&mut self, bit_width: u32) -> io::Result { + fn read_bits_leq32(&mut self, bit_width: u32) -> Result { debug_assert!(bit_width <= u32::BITS); let mut bits = self.get_bits(); @@ -1107,14 +1110,14 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { /// Reads up to 32-bits and interprets them as a signed two's complement integer or returns an /// error. #[inline(always)] - fn read_bits_leq32_signed(&mut self, bit_width: u32) -> io::Result { + fn read_bits_leq32_signed(&mut self, bit_width: u32) -> Result { let value = self.read_bits_leq32(bit_width)?; Ok(sign_extend_leq32_to_i32(value, bit_width)) } /// Reads and returns up to 64-bits or returns an error. #[inline(always)] - fn read_bits_leq64(&mut self, bit_width: u32) -> io::Result { + fn read_bits_leq64(&mut self, bit_width: u32) -> Result { debug_assert!(bit_width <= u64::BITS); // Hard-code the bit_width == 0 case as it's not possible to handle both the bit_width == 0 @@ -1152,14 +1155,14 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { /// Reads up to 64-bits and interprets them as a signed two's complement integer or returns an /// error. #[inline(always)] - fn read_bits_leq64_signed(&mut self, bit_width: u32) -> io::Result { + fn read_bits_leq64_signed(&mut self, bit_width: u32) -> Result { let value = self.read_bits_leq64(bit_width)?; Ok(sign_extend_leq64_to_i64(value, bit_width)) } /// Reads and returns a unary zeros encoded integer or an error. #[inline(always)] - fn read_unary_zeros(&mut self) -> io::Result { + fn read_unary_zeros(&mut self) -> Result { let mut num = 0; loop { @@ -1192,7 +1195,7 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { /// Reads and returns a unary zeros encoded integer that is capped to a maximum value. #[inline(always)] - fn read_unary_zeros_capped(&mut self, mut limit: u32) -> io::Result { + fn read_unary_zeros_capped(&mut self, mut limit: u32) -> Result { let mut num = 0; loop { @@ -1229,7 +1232,7 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { /// Reads and returns a unary ones encoded integer or an error. #[inline(always)] - fn read_unary_ones(&mut self) -> io::Result { + fn read_unary_ones(&mut self) -> Result { // Note: This algorithm is identical to read_unary_zeros except flipped for 1s. let mut num = 0; @@ -1255,7 +1258,7 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { /// Reads and returns a unary ones encoded integer or an error. #[inline(always)] - fn read_unary_ones_capped(&mut self, mut limit: u32) -> io::Result { + fn read_unary_ones_capped(&mut self, mut limit: u32) -> Result { // Note: This algorithm is identical to read_unary_zeros_capped except flipped for 1s. let mut num = 0; @@ -1289,7 +1292,7 @@ pub trait ReadBitsRtl: private::FetchBitsRtl { fn read_codebook( &mut self, codebook: &vlc::Codebook, - ) -> io::Result<(E::ValueType, u32)> { + ) -> Result<(E::ValueType, u32)> { if self.num_bits_left() < codebook.max_code_len { self.fetch_bits_partial()?; } @@ -1356,14 +1359,14 @@ impl<'a, B: ReadBytes> BitStreamRtl<'a, B> { impl<'a, B: ReadBytes> private::FetchBitsRtl for BitStreamRtl<'a, B> { #[inline(always)] - fn fetch_bits(&mut self) -> io::Result<()> { + fn fetch_bits(&mut self) -> Result<()> { self.bits = u64::from(self.reader.read_u8()?); self.n_bits_left = u8::BITS; Ok(()) } #[inline(always)] - fn fetch_bits_partial(&mut self) -> io::Result<()> { + fn fetch_bits_partial(&mut self) -> Result<()> { todo!() } @@ -1405,8 +1408,8 @@ impl<'a> BitReaderRtl<'a> { impl<'a> private::FetchBitsRtl for BitReaderRtl<'a> { #[inline] - fn fetch_bits_partial(&mut self) -> io::Result<()> { - let mut buf = [0u8; std::mem::size_of::()]; + fn fetch_bits_partial(&mut self) -> Result<()> { + let mut buf = [0u8; core::mem::size_of::()]; let read_len = min(self.buf.len(), (u64::BITS - self.n_bits_left) as usize >> 3); @@ -1420,10 +1423,10 @@ impl<'a> private::FetchBitsRtl for BitReaderRtl<'a> { Ok(()) } - fn fetch_bits(&mut self) -> io::Result<()> { - let mut buf = [0u8; std::mem::size_of::()]; + fn fetch_bits(&mut self) -> Result<()> { + let mut buf = [0u8; core::mem::size_of::()]; - let read_len = min(self.buf.len(), std::mem::size_of::()); + let read_len = min(self.buf.len(), core::mem::size_of::()); if read_len == 0 { return end_of_bitstream_error(); @@ -1469,6 +1472,7 @@ mod tests { use super::vlc::{BitOrder, Codebook, CodebookBuilder, Entry8x8}; use super::{BitReaderLtr, ReadBitsLtr}; use super::{BitReaderRtl, ReadBitsRtl}; + use alloc::vec::Vec; #[test] #[allow(clippy::bool_assert_comparison)] @@ -1830,7 +1834,7 @@ mod tests { let decoded: Vec = (0..text.len()).into_iter().map(|_| bs.read_codebook(&codebook).unwrap().0).collect(); - assert_eq!(text, std::str::from_utf8(&decoded).unwrap()); + assert_eq!(text, core::str::from_utf8(&decoded).unwrap()); } // BitStreamRtl @@ -2126,6 +2130,6 @@ mod tests { let decoded: Vec = (0..text.len()).into_iter().map(|_| bs.read_codebook(&codebook).unwrap().0).collect(); - assert_eq!(text, std::str::from_utf8(&decoded).unwrap()); + assert_eq!(text, core::str::from_utf8(&decoded).unwrap()); } } diff --git a/symphonia-core/src/io/buf_reader.rs b/symphonia-core/src/io/buf_reader.rs index fbbf860b..233be022 100644 --- a/symphonia-core/src/io/buf_reader.rs +++ b/symphonia-core/src/io/buf_reader.rs @@ -5,14 +5,15 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::cmp; -use std::io; +use core::cmp; use super::{FiniteStream, ReadBytes}; +use crate::errors::Result; +use crate::errors::SymphoniaError as Error; #[inline(always)] -fn underrun_error() -> io::Result { - Err(io::Error::new(io::ErrorKind::UnexpectedEof, "buffer underrun")) +fn underrun_error() -> Result { + Err(Error::Other("buffer underrun")) } /// A `BufReader` reads bytes from a byte buffer. @@ -33,7 +34,7 @@ impl<'a> BufReader<'a> { /// if the underlying buffer is exhausted before matching the pattern, remainder of the buffer /// is returned. #[inline(always)] - pub fn scan_bytes_ref(&mut self, pattern: &[u8], scan_len: usize) -> io::Result<&'a [u8]> { + pub fn scan_bytes_ref(&mut self, pattern: &[u8], scan_len: usize) -> Result<&'a [u8]> { self.scan_bytes_aligned_ref(pattern, 1, scan_len) } @@ -44,7 +45,7 @@ impl<'a> BufReader<'a> { pattern: &[u8], align: usize, scan_len: usize, - ) -> io::Result<&'a [u8]> { + ) -> Result<&'a [u8]> { // The pattern must be atleast one byte. debug_assert!(!pattern.is_empty()); @@ -76,7 +77,7 @@ impl<'a> BufReader<'a> { } /// Returns a reference to the next `len` bytes in the buffer and advances the stream. - pub fn read_buf_bytes_ref(&mut self, len: usize) -> io::Result<&'a [u8]> { + pub fn read_buf_bytes_ref(&mut self, len: usize) -> Result<&'a [u8]> { if self.pos + len > self.buf.len() { return underrun_error(); } @@ -94,7 +95,7 @@ impl<'a> BufReader<'a> { impl<'a> ReadBytes for BufReader<'a> { #[inline(always)] - fn read_byte(&mut self) -> io::Result { + fn read_byte(&mut self) -> Result { if self.buf.len() - self.pos < 1 { return underrun_error(); } @@ -104,7 +105,7 @@ impl<'a> ReadBytes for BufReader<'a> { } #[inline(always)] - fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { + fn read_double_bytes(&mut self) -> Result<[u8; 2]> { if self.buf.len() - self.pos < 2 { return underrun_error(); } @@ -117,7 +118,7 @@ impl<'a> ReadBytes for BufReader<'a> { } #[inline(always)] - fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { + fn read_triple_bytes(&mut self) -> Result<[u8; 3]> { if self.buf.len() - self.pos < 3 { return underrun_error(); } @@ -130,7 +131,7 @@ impl<'a> ReadBytes for BufReader<'a> { } #[inline(always)] - fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { + fn read_quad_bytes(&mut self) -> Result<[u8; 4]> { if self.buf.len() - self.pos < 4 { return underrun_error(); } @@ -142,7 +143,7 @@ impl<'a> ReadBytes for BufReader<'a> { Ok(bytes) } - fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { + fn read_buf(&mut self, buf: &mut [u8]) -> Result { let len = cmp::min(self.buf.len() - self.pos, buf.len()); buf[..len].copy_from_slice(&self.buf[self.pos..self.pos + len]); self.pos += len; @@ -150,7 +151,7 @@ impl<'a> ReadBytes for BufReader<'a> { Ok(len) } - fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + fn read_buf_exact(&mut self, buf: &mut [u8]) -> Result<()> { let len = buf.len(); if self.buf.len() - self.pos < len { @@ -168,14 +169,14 @@ impl<'a> ReadBytes for BufReader<'a> { pattern: &[u8], align: usize, buf: &'b mut [u8], - ) -> io::Result<&'b mut [u8]> { + ) -> Result<&'b mut [u8]> { let scanned = self.scan_bytes_aligned_ref(pattern, align, buf.len())?; buf[..scanned.len()].copy_from_slice(scanned); Ok(&mut buf[..scanned.len()]) } - fn ignore_bytes(&mut self, count: u64) -> io::Result<()> { + fn ignore_bytes(&mut self, count: u64) -> Result<()> { if self.buf.len() - self.pos < count as usize { return underrun_error(); } diff --git a/symphonia-core/src/io/media_source_stream.rs b/symphonia-core/src/io/media_source_stream.rs index a5bbb234..f380b85d 100644 --- a/symphonia-core/src/io/media_source_stream.rs +++ b/symphonia-core/src/io/media_source_stream.rs @@ -5,17 +5,18 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::cmp; -use std::io; -use std::io::{IoSliceMut, Read, Seek}; -use std::ops::Sub; +use alloc::boxed::Box; +use alloc::vec; +use core::cmp; +use core::ops::Sub; -use super::SeekBuffered; +use super::{IoSliceMut, Read, Seek, SeekBuffered, SeekFrom}; use super::{MediaSource, ReadBytes}; +use crate::errors::{Result, SymphoniaError}; #[inline(always)] -fn end_of_stream_error() -> io::Result { - Err(io::Error::new(io::ErrorKind::UnexpectedEof, "end of stream")) +fn end_of_stream_error() -> Result { + Err(SymphoniaError::EndOfFile) } /// `MediaSourceStreamOptions` specifies the buffering behaviour of a `MediaSourceStream`. @@ -98,7 +99,7 @@ impl MediaSourceStream { } /// If the buffer has been exhausted, fetch a new block of data to replenish the buffer. - fn fetch(&mut self) -> io::Result<()> { + fn fetch(&mut self) -> Result<()> { // Only fetch when the ring buffer is empty. if self.is_buffer_exhausted() { // Split the vector at the write position to get slices of the two contiguous regions of @@ -137,7 +138,7 @@ impl MediaSourceStream { /// If the buffer has been exhausted, fetch a new block of data to replenish the buffer. If /// no more data could be fetched, return an end-of-stream error. - fn fetch_or_eof(&mut self) -> io::Result<()> { + fn fetch_or_eof(&mut self) -> Result<()> { self.fetch()?; if self.is_buffer_exhausted() { @@ -186,8 +187,8 @@ impl MediaSource for MediaSourceStream { } } -impl io::Read for MediaSourceStream { - fn read(&mut self, mut buf: &mut [u8]) -> io::Result { +impl Read for MediaSourceStream { + fn read(&mut self, mut buf: &mut [u8]) -> Result { let read_len = buf.len(); while !buf.is_empty() { @@ -202,7 +203,7 @@ impl io::Read for MediaSourceStream { buf = &mut buf[count..]; self.consume(count); } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(SymphoniaError::IoInterruptedError(_)) => {} Err(e) => return Err(e), } } @@ -213,17 +214,17 @@ impl io::Read for MediaSourceStream { } } -impl io::Seek for MediaSourceStream { - fn seek(&mut self, pos: io::SeekFrom) -> io::Result { +impl Seek for MediaSourceStream { + fn seek(&mut self, pos: SeekFrom) -> Result { // The current position of the underlying reader is ahead of the current position of the // MediaSourceStream by how ever many bytes have not been read from the read-ahead buffer // yet. When seeking from the current position adjust the position delta to offset that // difference. let pos = match pos { - io::SeekFrom::Current(0) => return Ok(self.pos()), - io::SeekFrom::Current(delta_pos) => { + SeekFrom::Current(0) => return Ok(self.pos()), + SeekFrom::Current(delta_pos) => { let delta = delta_pos - self.unread_buffer_len() as i64; - self.inner.seek(io::SeekFrom::Current(delta)) + self.inner.seek(SeekFrom::Current(delta)) } _ => self.inner.seek(pos), }?; @@ -236,7 +237,7 @@ impl io::Seek for MediaSourceStream { impl ReadBytes for MediaSourceStream { #[inline(always)] - fn read_byte(&mut self) -> io::Result { + fn read_byte(&mut self) -> Result { // This function, read_byte, is inlined for performance. To reduce code bloat, place the // read-ahead buffer replenishment in a seperate function. Call overhead will be negligible // compared to the actual underlying read. @@ -250,7 +251,7 @@ impl ReadBytes for MediaSourceStream { Ok(value) } - fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { + fn read_double_bytes(&mut self) -> Result<[u8; 2]> { let mut bytes = [0; 2]; let buf = self.continguous_buf(); @@ -268,7 +269,7 @@ impl ReadBytes for MediaSourceStream { Ok(bytes) } - fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { + fn read_triple_bytes(&mut self) -> Result<[u8; 3]> { let mut bytes = [0; 3]; let buf = self.continguous_buf(); @@ -285,7 +286,7 @@ impl ReadBytes for MediaSourceStream { Ok(bytes) } - fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { + fn read_quad_bytes(&mut self) -> Result<[u8; 4]> { let mut bytes = [0; 4]; let buf = self.continguous_buf(); @@ -302,7 +303,7 @@ impl ReadBytes for MediaSourceStream { Ok(bytes) } - fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { + fn read_buf(&mut self, buf: &mut [u8]) -> Result { // Implemented via io::Read trait. let read = self.read(buf)?; @@ -317,14 +318,14 @@ impl ReadBytes for MediaSourceStream { } } - fn read_buf_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> { + fn read_buf_exact(&mut self, mut buf: &mut [u8]) -> Result<()> { while !buf.is_empty() { match self.read(buf) { Ok(0) => break, Ok(count) => { buf = &mut buf[count..]; } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(SymphoniaError::IoInterruptedError(_)) => {} Err(e) => return Err(e), } } @@ -342,12 +343,12 @@ impl ReadBytes for MediaSourceStream { _: &[u8], _: usize, _: &'a mut [u8], - ) -> io::Result<&'a mut [u8]> { + ) -> Result<&'a mut [u8]> { // Intentionally left unimplemented. unimplemented!(); } - fn ignore_bytes(&mut self, mut count: u64) -> io::Result<()> { + fn ignore_bytes(&mut self, mut count: u64) -> Result<()> { // If the stream is seekable and the number of bytes to ignore is large, perform a seek // first. Note that ignored bytes are rewindable. Therefore, ensure the ring-buffer is // full after the seek just like if bytes were ignored by consuming them instead. @@ -356,7 +357,7 @@ impl ReadBytes for MediaSourceStream { // Only apply the optimization if seeking 2x or more than the ring-buffer size. while count >= 2 * ring_len && self.is_seekable() { let delta = count.clamp(0, i64::MAX as u64).sub(ring_len); - self.seek(io::SeekFrom::Current(delta as i64))?; + self.seek(SeekFrom::Current(delta as i64))?; count -= delta; } @@ -436,12 +437,12 @@ impl SeekBuffered for MediaSourceStream { // Forward seek. let delta = if pos > old_pos { - assert!(pos - old_pos < std::isize::MAX as u64); + assert!(pos - old_pos < core::isize::MAX as u64); (pos - old_pos) as isize } else if pos < old_pos { // Backward seek. - assert!(old_pos - pos < std::isize::MAX as u64); + assert!(old_pos - pos < core::isize::MAX as u64); -((old_pos - pos) as isize) } else { @@ -465,10 +466,37 @@ impl SeekBuffered for MediaSourceStream { } } +#[cfg(not(feature = "std"))] +impl Read for &[u8] { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + let amt = cmp::min(buf.len(), self.len()); + let (a, b) = self.split_at(amt); + + // First check if the amount of bytes we want to read is small: + // `copy_from_slice` will generally expand to a call to `memcpy`, and + // for a single byte the overhead is significant. + if amt == 1 { + buf[0] = a[0]; + } + else { + buf[..amt].copy_from_slice(a); + } + + *self = b; + Ok(amt) + } +} + +#[cfg(feature = "std")] #[cfg(test)] mod tests { use super::{MediaSourceStream, ReadBytes, SeekBuffered}; - use std::io::{Cursor, Read}; + use crate::io::Read; + use alloc::boxed::Box; + use alloc::vec; + use alloc::vec::Vec; + use std::io::Cursor; /// Generate a random vector of bytes of the specified length using a PRNG. fn generate_random_bytes(len: usize) -> Box<[u8]> { diff --git a/symphonia-core/src/io/mod.rs b/symphonia-core/src/io/mod.rs index e301cfcf..1e088c93 100644 --- a/symphonia-core/src/io/mod.rs +++ b/symphonia-core/src/io/mod.rs @@ -19,8 +19,20 @@ //! either the [`ReadBitsLtr`] or [`ReadBitsRtl`] traits depending on the order in which they //! consume bits. +use crate::errors::{Result, SymphoniaError}; +use alloc::boxed::Box; +use alloc::vec; +use alloc::vec::Vec; +use core::mem; + +#[cfg(feature = "std")] use std::io; -use std::mem; + +#[cfg(feature = "std")] +use std::io::IoSliceMut; + +#[cfg(not(feature = "std"))] +use no_std_compat::IoSliceMut; mod bit; mod buf_reader; @@ -34,12 +46,83 @@ pub use media_source_stream::{MediaSourceStream, MediaSourceStreamOptions}; pub use monitor_stream::{Monitor, MonitorStream}; pub use scoped_stream::ScopedStream; +pub trait Seek { + fn seek(&mut self, _: SeekFrom) -> Result; +} + +pub enum SeekFrom { + Start(u64), + End(i64), + Current(i64), +} + +pub trait Read { + fn read(&mut self, buf: &mut [u8]) -> Result; + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> Result { + default_read_vectored(|b| self.read(b), bufs) + } + + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + default_slow_read_to_end(self, buf) + } +} + +/// Warning: The default implementation in io::Read is much faster +fn default_slow_read_to_end(r: &mut R, buf: &mut Vec) -> Result { + let mut cnt: usize = 0; + let mut read_buf: [u8; 1024] = [0; 1024]; + + loop { + let r = r.read(&mut read_buf); + let n = match r { + Ok(0) => break, + Ok(n) => n, + Err(SymphoniaError::IoInterruptedError(_)) => 0, // Ignored + Err(err) => return Err(err), + }; + + buf.extend_from_slice(&read_buf[0..n]); + cnt += n; + } + + Ok(cnt) +} + +fn default_read_vectored(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result +where + F: FnOnce(&mut [u8]) -> Result, +{ + let buf = bufs.iter_mut().find(|b| !b.is_empty()).map_or(&mut [][..], |b| &mut **b); + read(buf) +} + +#[cfg(feature = "std")] +impl Read for T { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.read(buf).map_err(|e| SymphoniaError::from(e)) + } +} + +#[cfg(feature = "std")] +impl Seek for T { + fn seek(&mut self, from: SeekFrom) -> Result { + let from = match from { + SeekFrom::Start(x) => io::SeekFrom::Start(x), + SeekFrom::End(x) => io::SeekFrom::End(x), + SeekFrom::Current(x) => io::SeekFrom::Current(x), + }; + self.seek(from).map_err(|e| SymphoniaError::from(e)) + } +} + /// `MediaSource` is a composite trait of [`std::io::Read`] and [`std::io::Seek`]. A source *must* /// implement this trait to be used by [`MediaSourceStream`]. /// /// Despite requiring the [`std::io::Seek`] trait, seeking is an optional capability that can be /// queried at runtime. -pub trait MediaSource: io::Read + io::Seek + Send + Sync { +// pub trait MediaSource: io::Read + io::Seek + Send + Sync { +pub trait MediaSource: Read + Seek { /// Returns if the source is seekable. This may be an expensive operation. fn is_seekable(&self) -> bool; @@ -47,6 +130,7 @@ pub trait MediaSource: io::Read + io::Seek + Send + Sync { fn byte_len(&self) -> Option; } +#[cfg(feature = "std")] impl MediaSource for std::fs::File { /// Returns if the `std::io::File` backing the `MediaSource` is seekable. /// @@ -74,7 +158,8 @@ impl MediaSource for std::fs::File { } } -impl + Send + Sync> MediaSource for io::Cursor { +#[cfg(feature = "std")] +impl + Send + Sync> MediaSource for std::io::Cursor { /// Always returns true since a `io::Cursor` is always seekable. fn is_seekable(&self) -> bool { true @@ -91,11 +176,11 @@ impl + Send + Sync> MediaSource for io::Cursor { /// `ReadOnlySource` wraps any source implementing [`std::io::Read`] in an unseekable /// [`MediaSource`]. -pub struct ReadOnlySource { +pub struct ReadOnlySource { inner: R, } -impl ReadOnlySource { +impl ReadOnlySource { /// Instantiates a new `ReadOnlySource` by taking ownership and wrapping the provided /// `Read`er. pub fn new(inner: R) -> Self { @@ -118,7 +203,7 @@ impl ReadOnlySource { } } -impl MediaSource for ReadOnlySource { +impl MediaSource for ReadOnlySource { fn is_seekable(&self) -> bool { false } @@ -128,15 +213,15 @@ impl MediaSource for ReadOnlySource { } } -impl io::Read for ReadOnlySource { - fn read(&mut self, buf: &mut [u8]) -> io::Result { +impl Read for ReadOnlySource { + fn read(&mut self, buf: &mut [u8]) -> Result { self.inner.read(buf) } } -impl io::Seek for ReadOnlySource { - fn seek(&mut self, _: io::SeekFrom) -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, "source does not support seeking")) +impl Seek for ReadOnlySource { + fn seek(&mut self, _: SeekFrom) -> Result { + Err(SymphoniaError::Other("source does not support seeking")) } } @@ -144,67 +229,67 @@ impl io::Seek for ReadOnlySource { /// unsigned integers or floating-point values of standard widths. pub trait ReadBytes { /// Reads a single byte from the stream and returns it or an error. - fn read_byte(&mut self) -> io::Result; + fn read_byte(&mut self) -> Result; /// Reads two bytes from the stream and returns them in read-order or an error. - fn read_double_bytes(&mut self) -> io::Result<[u8; 2]>; + fn read_double_bytes(&mut self) -> Result<[u8; 2]>; /// Reads three bytes from the stream and returns them in read-order or an error. - fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]>; + fn read_triple_bytes(&mut self) -> Result<[u8; 3]>; /// Reads four bytes from the stream and returns them in read-order or an error. - fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]>; + fn read_quad_bytes(&mut self) -> Result<[u8; 4]>; /// Reads up-to the number of bytes required to fill buf or returns an error. - fn read_buf(&mut self, buf: &mut [u8]) -> io::Result; + fn read_buf(&mut self, buf: &mut [u8]) -> Result; /// Reads exactly the number of bytes required to fill be provided buffer or returns an error. - fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()>; + fn read_buf_exact(&mut self, buf: &mut [u8]) -> Result<()>; /// Reads a single unsigned byte from the stream and returns it or an error. #[inline(always)] - fn read_u8(&mut self) -> io::Result { + fn read_u8(&mut self) -> Result { self.read_byte() } /// Reads a single signed byte from the stream and returns it or an error. #[inline(always)] - fn read_i8(&mut self) -> io::Result { + fn read_i8(&mut self) -> Result { Ok(self.read_byte()? as i8) } /// Reads two bytes from the stream and interprets them as an unsigned 16-bit little-endian /// integer or returns an error. #[inline(always)] - fn read_u16(&mut self) -> io::Result { + fn read_u16(&mut self) -> Result { Ok(u16::from_le_bytes(self.read_double_bytes()?)) } /// Reads two bytes from the stream and interprets them as an signed 16-bit little-endian /// integer or returns an error. #[inline(always)] - fn read_i16(&mut self) -> io::Result { + fn read_i16(&mut self) -> Result { Ok(i16::from_le_bytes(self.read_double_bytes()?)) } /// Reads two bytes from the stream and interprets them as an unsigned 16-bit big-endian /// integer or returns an error. #[inline(always)] - fn read_be_u16(&mut self) -> io::Result { + fn read_be_u16(&mut self) -> Result { Ok(u16::from_be_bytes(self.read_double_bytes()?)) } /// Reads two bytes from the stream and interprets them as an signed 16-bit big-endian /// integer or returns an error. #[inline(always)] - fn read_be_i16(&mut self) -> io::Result { + fn read_be_i16(&mut self) -> Result { Ok(i16::from_be_bytes(self.read_double_bytes()?)) } /// Reads three bytes from the stream and interprets them as an unsigned 24-bit little-endian /// integer or returns an error. #[inline(always)] - fn read_u24(&mut self) -> io::Result { + fn read_u24(&mut self) -> Result { let mut buf = [0u8; mem::size_of::()]; buf[0..3].clone_from_slice(&self.read_triple_bytes()?); Ok(u32::from_le_bytes(buf)) @@ -213,14 +298,14 @@ pub trait ReadBytes { /// Reads three bytes from the stream and interprets them as an signed 24-bit little-endian /// integer or returns an error. #[inline(always)] - fn read_i24(&mut self) -> io::Result { + fn read_i24(&mut self) -> Result { Ok(((self.read_u24()? << 8) as i32) >> 8) } /// Reads three bytes from the stream and interprets them as an unsigned 24-bit big-endian /// integer or returns an error. #[inline(always)] - fn read_be_u24(&mut self) -> io::Result { + fn read_be_u24(&mut self) -> Result { let mut buf = [0u8; mem::size_of::()]; buf[0..3].clone_from_slice(&self.read_triple_bytes()?); Ok(u32::from_be_bytes(buf) >> 8) @@ -229,42 +314,42 @@ pub trait ReadBytes { /// Reads three bytes from the stream and interprets them as an signed 24-bit big-endian /// integer or returns an error. #[inline(always)] - fn read_be_i24(&mut self) -> io::Result { + fn read_be_i24(&mut self) -> Result { Ok(((self.read_be_u24()? << 8) as i32) >> 8) } /// Reads four bytes from the stream and interprets them as an unsigned 32-bit little-endian /// integer or returns an error. #[inline(always)] - fn read_u32(&mut self) -> io::Result { + fn read_u32(&mut self) -> Result { Ok(u32::from_le_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as an signed 32-bit little-endian /// integer or returns an error. #[inline(always)] - fn read_i32(&mut self) -> io::Result { + fn read_i32(&mut self) -> Result { Ok(i32::from_le_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as an unsigned 32-bit big-endian /// integer or returns an error. #[inline(always)] - fn read_be_u32(&mut self) -> io::Result { + fn read_be_u32(&mut self) -> Result { Ok(u32::from_be_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as a signed 32-bit big-endian /// integer or returns an error. #[inline(always)] - fn read_be_i32(&mut self) -> io::Result { + fn read_be_i32(&mut self) -> Result { Ok(i32::from_be_bytes(self.read_quad_bytes()?)) } /// Reads eight bytes from the stream and interprets them as an unsigned 64-bit little-endian /// integer or returns an error. #[inline(always)] - fn read_u64(&mut self) -> io::Result { + fn read_u64(&mut self) -> Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(u64::from_le_bytes(buf)) @@ -273,7 +358,7 @@ pub trait ReadBytes { /// Reads eight bytes from the stream and interprets them as an signed 64-bit little-endian /// integer or returns an error. #[inline(always)] - fn read_i64(&mut self) -> io::Result { + fn read_i64(&mut self) -> Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(i64::from_le_bytes(buf)) @@ -282,7 +367,7 @@ pub trait ReadBytes { /// Reads eight bytes from the stream and interprets them as an unsigned 64-bit big-endian /// integer or returns an error. #[inline(always)] - fn read_be_u64(&mut self) -> io::Result { + fn read_be_u64(&mut self) -> Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(u64::from_be_bytes(buf)) @@ -291,7 +376,7 @@ pub trait ReadBytes { /// Reads eight bytes from the stream and interprets them as an signed 64-bit big-endian /// integer or returns an error. #[inline(always)] - fn read_be_i64(&mut self) -> io::Result { + fn read_be_i64(&mut self) -> Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(i64::from_be_bytes(buf)) @@ -300,21 +385,21 @@ pub trait ReadBytes { /// Reads four bytes from the stream and interprets them as a 32-bit little-endian IEEE-754 /// floating-point value. #[inline(always)] - fn read_f32(&mut self) -> io::Result { + fn read_f32(&mut self) -> Result { Ok(f32::from_le_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as a 32-bit big-endian IEEE-754 /// floating-point value. #[inline(always)] - fn read_be_f32(&mut self) -> io::Result { + fn read_be_f32(&mut self) -> Result { Ok(f32::from_be_bytes(self.read_quad_bytes()?)) } /// Reads four bytes from the stream and interprets them as a 64-bit little-endian IEEE-754 /// floating-point value. #[inline(always)] - fn read_f64(&mut self) -> io::Result { + fn read_f64(&mut self) -> Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(f64::from_le_bytes(buf)) @@ -323,7 +408,7 @@ pub trait ReadBytes { /// Reads four bytes from the stream and interprets them as a 64-bit big-endian IEEE-754 /// floating-point value. #[inline(always)] - fn read_be_f64(&mut self) -> io::Result { + fn read_be_f64(&mut self) -> Result { let mut buf = [0u8; mem::size_of::()]; self.read_buf_exact(&mut buf)?; Ok(f64::from_be_bytes(buf)) @@ -331,7 +416,7 @@ pub trait ReadBytes { /// Reads up-to the number of bytes requested, and returns a boxed slice of the data or an /// error. - fn read_boxed_slice(&mut self, len: usize) -> io::Result> { + fn read_boxed_slice(&mut self, len: usize) -> Result> { let mut buf = vec![0u8; len]; let actual_len = self.read_buf(&mut buf)?; buf.truncate(actual_len); @@ -340,7 +425,7 @@ pub trait ReadBytes { /// Reads exactly the number of bytes requested, and returns a boxed slice of the data or an /// error. - fn read_boxed_slice_exact(&mut self, len: usize) -> io::Result> { + fn read_boxed_slice_exact(&mut self, len: usize) -> Result> { let mut buf = vec![0u8; len]; self.read_buf_exact(&mut buf)?; Ok(buf.into_boxed_slice()) @@ -349,7 +434,7 @@ pub trait ReadBytes { /// Reads bytes from the stream into a supplied buffer until a byte pattern is matched. Returns /// a mutable slice to the valid region of the provided buffer. #[inline(always)] - fn scan_bytes<'a>(&mut self, pattern: &[u8], buf: &'a mut [u8]) -> io::Result<&'a mut [u8]> { + fn scan_bytes<'a>(&mut self, pattern: &[u8], buf: &'a mut [u8]) -> Result<&'a mut [u8]> { self.scan_bytes_aligned(pattern, 1, buf) } @@ -360,10 +445,10 @@ pub trait ReadBytes { pattern: &[u8], align: usize, buf: &'a mut [u8], - ) -> io::Result<&'a mut [u8]>; + ) -> Result<&'a mut [u8]>; /// Ignores the specified number of bytes from the stream or returns an error. - fn ignore_bytes(&mut self, count: u64) -> io::Result<()>; + fn ignore_bytes(&mut self, count: u64) -> Result<()>; /// Gets the position of the stream. fn pos(&self) -> u64; @@ -371,32 +456,32 @@ pub trait ReadBytes { impl<'b, R: ReadBytes> ReadBytes for &'b mut R { #[inline(always)] - fn read_byte(&mut self) -> io::Result { + fn read_byte(&mut self) -> Result { (*self).read_byte() } #[inline(always)] - fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { + fn read_double_bytes(&mut self) -> Result<[u8; 2]> { (*self).read_double_bytes() } #[inline(always)] - fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { + fn read_triple_bytes(&mut self) -> Result<[u8; 3]> { (*self).read_triple_bytes() } #[inline(always)] - fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { + fn read_quad_bytes(&mut self) -> Result<[u8; 4]> { (*self).read_quad_bytes() } #[inline(always)] - fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { + fn read_buf(&mut self, buf: &mut [u8]) -> Result { (*self).read_buf(buf) } #[inline(always)] - fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + fn read_buf_exact(&mut self, buf: &mut [u8]) -> Result<()> { (*self).read_buf_exact(buf) } @@ -406,12 +491,12 @@ impl<'b, R: ReadBytes> ReadBytes for &'b mut R { pattern: &[u8], align: usize, buf: &'a mut [u8], - ) -> io::Result<&'a mut [u8]> { + ) -> Result<&'a mut [u8]> { (*self).scan_bytes_aligned(pattern, align, buf) } #[inline(always)] - fn ignore_bytes(&mut self, count: u64) -> io::Result<()> { + fn ignore_bytes(&mut self, count: u64) -> Result<()> { (*self).ignore_bytes(count) } @@ -475,7 +560,7 @@ pub trait SeekBuffered { /// This function is identical to [`SeekBuffered::seek_buffered_rel`] when a negative delta is /// provided. fn seek_buffered_rev(&mut self, delta: usize) { - assert!(delta < std::isize::MAX as usize); + assert!(delta < core::isize::MAX as usize); self.seek_buffered_rel(-(delta as isize)); } } @@ -505,3 +590,34 @@ pub trait FiniteStream { /// Returns the number of bytes available for reading. fn bytes_available(&self) -> u64; } + +#[cfg(not(feature = "std"))] +mod no_std_compat { + use core::ops::{Deref, DerefMut}; + + pub struct IoSliceMut<'a> { + buf: &'a mut [u8], + } + + impl<'a> IoSliceMut<'a> { + pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + IoSliceMut { buf } + } + } + + impl<'a> Deref for IoSliceMut<'a> { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + self.buf + } + } + + impl<'a> DerefMut for IoSliceMut<'a> { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + self.buf + } + } +} diff --git a/symphonia-core/src/io/monitor_stream.rs b/symphonia-core/src/io/monitor_stream.rs index 72677be9..3053c096 100644 --- a/symphonia-core/src/io/monitor_stream.rs +++ b/symphonia-core/src/io/monitor_stream.rs @@ -5,9 +5,8 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::io; - use super::ReadBytes; +use crate::errors::Result; /// A `Monitor` provides a common interface to examine the operations observed be /// a [`MonitorStream`]. @@ -73,40 +72,40 @@ impl MonitorStream { impl ReadBytes for MonitorStream { #[inline(always)] - fn read_byte(&mut self) -> io::Result { + fn read_byte(&mut self) -> Result { let byte = self.inner.read_byte()?; self.monitor.process_byte(byte); Ok(byte) } #[inline(always)] - fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { + fn read_double_bytes(&mut self) -> Result<[u8; 2]> { let bytes = self.inner.read_double_bytes()?; self.monitor.process_double_bytes(bytes); Ok(bytes) } #[inline(always)] - fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { + fn read_triple_bytes(&mut self) -> Result<[u8; 3]> { let bytes = self.inner.read_triple_bytes()?; self.monitor.process_triple_bytes(bytes); Ok(bytes) } #[inline(always)] - fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { + fn read_quad_bytes(&mut self) -> Result<[u8; 4]> { let bytes = self.inner.read_quad_bytes()?; self.monitor.process_quad_bytes(bytes); Ok(bytes) } - fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { + fn read_buf(&mut self, buf: &mut [u8]) -> Result { let len = self.inner.read_buf(buf)?; self.monitor.process_buf_bytes(&buf[0..len]); Ok(len) } - fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + fn read_buf_exact(&mut self, buf: &mut [u8]) -> Result<()> { self.inner.read_buf_exact(buf)?; self.monitor.process_buf_bytes(buf); Ok(()) @@ -117,13 +116,13 @@ impl ReadBytes for MonitorStream { pattern: &[u8], align: usize, buf: &'a mut [u8], - ) -> io::Result<&'a mut [u8]> { + ) -> Result<&'a mut [u8]> { let result = self.inner.scan_bytes_aligned(pattern, align, buf)?; self.monitor.process_buf_bytes(result); Ok(result) } - fn ignore_bytes(&mut self, count: u64) -> io::Result<()> { + fn ignore_bytes(&mut self, count: u64) -> Result<()> { self.inner.ignore_bytes(count) } diff --git a/symphonia-core/src/io/scoped_stream.rs b/symphonia-core/src/io/scoped_stream.rs index 12106062..6cf90eff 100644 --- a/symphonia-core/src/io/scoped_stream.rs +++ b/symphonia-core/src/io/scoped_stream.rs @@ -5,14 +5,14 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use std::cmp; -use std::io; +use crate::errors::{Result, SymphoniaError}; +use core::cmp; use super::{FiniteStream, ReadBytes, SeekBuffered}; #[inline(always)] -fn out_of_bounds_error() -> io::Result { - Err(io::Error::new(io::ErrorKind::UnexpectedEof, "out of bounds")) +fn out_of_bounds_error() -> Result { + Err(SymphoniaError::EndOfFile) } /// A `ScopedStream` restricts the number of bytes that may be read to an upper limit. @@ -41,7 +41,7 @@ impl ScopedStream { } /// Ignores the remainder of the `ScopedStream`. - pub fn ignore(&mut self) -> io::Result<()> { + pub fn ignore(&mut self) -> Result<()> { self.inner.ignore_bytes(self.len - self.read) } @@ -70,7 +70,7 @@ impl FiniteStream for ScopedStream { impl ReadBytes for ScopedStream { #[inline(always)] - fn read_byte(&mut self) -> io::Result { + fn read_byte(&mut self) -> Result { if self.len - self.read < 1 { return out_of_bounds_error(); } @@ -80,7 +80,7 @@ impl ReadBytes for ScopedStream { } #[inline(always)] - fn read_double_bytes(&mut self) -> io::Result<[u8; 2]> { + fn read_double_bytes(&mut self) -> Result<[u8; 2]> { if self.len - self.read < 2 { return out_of_bounds_error(); } @@ -90,7 +90,7 @@ impl ReadBytes for ScopedStream { } #[inline(always)] - fn read_triple_bytes(&mut self) -> io::Result<[u8; 3]> { + fn read_triple_bytes(&mut self) -> Result<[u8; 3]> { if self.len - self.read < 3 { return out_of_bounds_error(); } @@ -100,7 +100,7 @@ impl ReadBytes for ScopedStream { } #[inline(always)] - fn read_quad_bytes(&mut self) -> io::Result<[u8; 4]> { + fn read_quad_bytes(&mut self) -> Result<[u8; 4]> { if self.len - self.read < 4 { return out_of_bounds_error(); } @@ -109,7 +109,7 @@ impl ReadBytes for ScopedStream { self.inner.read_quad_bytes() } - fn read_buf(&mut self, buf: &mut [u8]) -> io::Result { + fn read_buf(&mut self, buf: &mut [u8]) -> Result { // Limit read_buf() to the remainder of the scoped bytes if buf has a greater length. let scoped_len = cmp::min(self.len - self.read, buf.len() as u64) as usize; let result = self.inner.read_buf(&mut buf[0..scoped_len])?; @@ -117,7 +117,7 @@ impl ReadBytes for ScopedStream { Ok(result) } - fn read_buf_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + fn read_buf_exact(&mut self, buf: &mut [u8]) -> Result<()> { if self.len - self.read < buf.len() as u64 { return out_of_bounds_error(); } @@ -132,7 +132,7 @@ impl ReadBytes for ScopedStream { pattern: &[u8], align: usize, buf: &'a mut [u8], - ) -> io::Result<&'a mut [u8]> { + ) -> Result<&'a mut [u8]> { if self.len - self.read < buf.len() as u64 { return out_of_bounds_error(); } @@ -143,7 +143,7 @@ impl ReadBytes for ScopedStream { } #[inline(always)] - fn ignore_bytes(&mut self, count: u64) -> io::Result<()> { + fn ignore_bytes(&mut self, count: u64) -> Result<()> { if self.len - self.read < count { return out_of_bounds_error(); } @@ -184,8 +184,8 @@ impl SeekBuffered for ScopedStream { fn seek_buffered_rel(&mut self, delta: isize) -> u64 { // Clamp the delta value such that the absolute position after the buffered seek will be // within the bounds of the ScopedStream. - let max_back = self.read.min(std::isize::MAX as u64) as isize; - let max_forward = (self.len - self.read).min(std::isize::MAX as u64) as isize; + let max_back = self.read.min(core::isize::MAX as u64) as isize; + let max_forward = (self.len - self.read).min(core::isize::MAX as u64) as isize; self.inner.seek_buffered_rel(delta.clamp(-max_back, max_forward)) } } diff --git a/symphonia-core/src/lib.rs b/symphonia-core/src/lib.rs index 81b0f76f..8d79fc2b 100644 --- a/symphonia-core/src/lib.rs +++ b/symphonia-core/src/lib.rs @@ -1,3 +1,4 @@ +#![no_std] // Symphonia // Copyright (c) 2019-2022 The Project Symphonia Developers. // @@ -11,6 +12,13 @@ #![allow(clippy::excessive_precision)] #![allow(clippy::identity_op)] #![allow(clippy::manual_range_contains)] +#![cfg_attr(not(feature = "std"), feature(error_in_core))] + +extern crate alloc; +extern crate core; + +#[cfg(feature = "std")] +extern crate std; pub mod audio; pub mod checksum; diff --git a/symphonia-core/src/meta.rs b/symphonia-core/src/meta.rs index c1e30fd8..4664b99e 100644 --- a/symphonia-core/src/meta.rs +++ b/symphonia-core/src/meta.rs @@ -7,11 +7,15 @@ //! The `meta` module defines basic metadata elements, and management structures. -use std::borrow::Cow; -use std::collections::VecDeque; -use std::convert::From; -use std::fmt; -use std::num::NonZeroU32; +use alloc::borrow::Cow; +use alloc::boxed::Box; +use alloc::collections::VecDeque; +use alloc::string::String; +use alloc::string::ToString; +use alloc::vec::Vec; +use core::convert::From; +use core::fmt; +use core::num::NonZeroU32; use crate::errors::Result; use crate::io::MediaSourceStream; diff --git a/symphonia-core/src/probe.rs b/symphonia-core/src/probe.rs index 823d19de..9aba21c0 100644 --- a/symphonia-core/src/probe.rs +++ b/symphonia-core/src/probe.rs @@ -12,10 +12,16 @@ use crate::errors::{unsupported_error, Result}; use crate::formats::{FormatOptions, FormatReader}; use crate::io::{MediaSourceStream, ReadBytes, SeekBuffered}; use crate::meta::{Metadata, MetadataLog, MetadataOptions, MetadataReader}; +use alloc::borrow::ToOwned; +use alloc::boxed::Box; +use alloc::string::String; +use alloc::vec::Vec; use log::{debug, error, info}; mod bloom { + use alloc::boxed::Box; + use alloc::vec; fn fnv1a32(value: &[u8; 2]) -> u32 { const INIT: u32 = 0x811c_9dc5; @@ -364,7 +370,7 @@ macro_rules! support_metadata { mime_types: $mimes, markers: $markers, score: Self::score, - inst: Instantiate::Metadata(|opt| Box::new(Self::new(&opt))), + inst: Instantiate::Metadata(|opt| alloc::boxed::Box::new(Self::new(&opt))), } }; } diff --git a/symphonia-core/src/sample.rs b/symphonia-core/src/sample.rs index eafb87af..bd195373 100644 --- a/symphonia-core/src/sample.rs +++ b/symphonia-core/src/sample.rs @@ -7,7 +7,7 @@ //! The `sample` module defines the core audio sample trait and any non-primitive sample data types. -use std::fmt; +use core::fmt; use crate::util::clamp::{clamp_f32, clamp_f64, clamp_i24, clamp_u24}; diff --git a/symphonia-core/src/units.rs b/symphonia-core/src/units.rs index 12fc4a7e..cc230f6e 100644 --- a/symphonia-core/src/units.rs +++ b/symphonia-core/src/units.rs @@ -7,7 +7,7 @@ //! The `units` module provides definitions for common units. -use std::fmt; +use core::fmt; /// A `TimeStamp` represents an instantenous instant in time since the start of a stream. One /// `TimeStamp` "tick" is equivalent to the stream's `TimeBase` in seconds. @@ -99,7 +99,7 @@ impl From for Time { impl From for Time { fn from(seconds: f32) -> Self { if seconds >= 0.0 { - Time::new(seconds.trunc() as u64, f64::from(seconds.fract())) + Time::new(libm::truncf(seconds) as u64, f64::from(seconds - libm::truncf(seconds))) } else { Time::new(0, 0.0) @@ -110,7 +110,7 @@ impl From for Time { impl From for Time { fn from(seconds: f64) -> Self { if seconds >= 0.0 { - Time::new(seconds.trunc() as u64, seconds.fract()) + Time::new(libm::trunc(seconds) as u64, seconds - libm::trunc(seconds)) } else { Time::new(0, 0.0) @@ -118,15 +118,15 @@ impl From for Time { } } -impl From for Time { - fn from(duration: std::time::Duration) -> Self { +impl From for Time { + fn from(duration: core::time::Duration) -> Self { Time::new(duration.as_secs(), f64::from(duration.subsec_nanos()) / 1_000_000_000.0) } } -impl From