Make all property structs non-exhaustive

This commit is contained in:
Serial 2022-02-14 21:19:05 -05:00
parent 2ccb38a97d
commit 6bb0427c84
No known key found for this signature in database
GPG key ID: DA95198DC17C4568
9 changed files with 271 additions and 419 deletions

View file

@ -9,15 +9,16 @@ use std::time::Duration;
use byteorder::{LittleEndian, ReadBytesExt};
#[derive(Clone, Debug, PartialEq, Default)]
#[non_exhaustive]
/// An APE file's audio properties
pub struct ApeProperties {
version: u16,
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
bit_depth: u8,
channels: u8,
pub(crate) version: u16,
pub(crate) duration: Duration,
pub(crate) overall_bitrate: u32,
pub(crate) audio_bitrate: u32,
pub(crate) sample_rate: u32,
pub(crate) bit_depth: u8,
pub(crate) channels: u8,
}
impl From<ApeProperties> for FileProperties {
@ -34,27 +35,6 @@ impl From<ApeProperties> for FileProperties {
}
impl ApeProperties {
/// Creates a new [`ApeProperties`]
pub const fn new(
version: u16,
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
bit_depth: u8,
channels: u8,
) -> Self {
Self {
version,
duration,
overall_bitrate,
audio_bitrate,
sample_rate,
bit_depth,
channels,
}
}
/// Duration
pub fn duration(&self) -> Duration {
self.duration

View file

@ -26,15 +26,16 @@ impl Default for WavFormat {
}
#[derive(Debug, Copy, Clone, PartialEq, Default)]
#[non_exhaustive]
/// A WAV file's audio properties
pub struct WavProperties {
format: WavFormat,
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
bit_depth: u8,
channels: u8,
pub(crate) format: WavFormat,
pub(crate) duration: Duration,
pub(crate) overall_bitrate: u32,
pub(crate) audio_bitrate: u32,
pub(crate) sample_rate: u32,
pub(crate) bit_depth: u8,
pub(crate) channels: u8,
}
impl From<WavProperties> for FileProperties {
@ -51,27 +52,6 @@ impl From<WavProperties> for FileProperties {
}
impl WavProperties {
/// Create a new [`WavProperties`]
pub const fn new(
format: WavFormat,
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
bit_depth: u8,
channels: u8,
) -> Self {
Self {
format,
duration,
overall_bitrate,
audio_bitrate,
sample_rate,
bit_depth,
channels,
}
}
/// Duration
pub fn duration(&self) -> Duration {
self.duration

View file

@ -4,16 +4,17 @@ use crate::types::properties::FileProperties;
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Default)]
#[non_exhaustive]
/// An MP3 file's audio properties
pub struct Mp3Properties {
version: MpegVersion,
layer: Layer,
channel_mode: ChannelMode,
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
channels: u8,
pub(crate) version: MpegVersion,
pub(crate) layer: Layer,
pub(crate) channel_mode: ChannelMode,
pub(crate) duration: Duration,
pub(crate) overall_bitrate: u32,
pub(crate) audio_bitrate: u32,
pub(crate) sample_rate: u32,
pub(crate) channels: u8,
}
impl From<Mp3Properties> for FileProperties {
@ -30,29 +31,6 @@ impl From<Mp3Properties> for FileProperties {
}
impl Mp3Properties {
/// Creates a new [`Mp3Properties`]
pub const fn new(
version: MpegVersion,
layer: Layer,
channel_mode: ChannelMode,
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
channels: u8,
) -> Self {
Self {
version,
layer,
channel_mode,
duration,
overall_bitrate,
audio_bitrate,
sample_rate,
channels,
}
}
/// Duration
pub fn duration(&self) -> Duration {
self.duration

View file

@ -28,15 +28,16 @@ impl Default for Mp4Codec {
}
#[derive(Debug, Clone, PartialEq, Default)]
#[non_exhaustive]
/// An MP4 file's audio properties
pub struct Mp4Properties {
codec: Mp4Codec,
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
bit_depth: Option<u8>,
channels: u8,
pub(crate) codec: Mp4Codec,
pub(crate) duration: Duration,
pub(crate) overall_bitrate: u32,
pub(crate) audio_bitrate: u32,
pub(crate) sample_rate: u32,
pub(crate) bit_depth: Option<u8>,
pub(crate) channels: u8,
}
impl From<Mp4Properties> for FileProperties {
@ -53,27 +54,6 @@ impl From<Mp4Properties> for FileProperties {
}
impl Mp4Properties {
/// Creates a new [`Mp4Properties`]
pub const fn new(
codec: Mp4Codec,
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
bit_depth: Option<u8>,
channels: u8,
) -> Self {
Self {
codec,
duration,
overall_bitrate,
audio_bitrate,
sample_rate,
bit_depth,
channels,
}
}
/// Duration
pub fn duration(&self) -> Duration {
self.duration

View file

@ -9,14 +9,15 @@ use byteorder::{LittleEndian, ReadBytesExt};
use ogg_pager::Page;
#[derive(Debug, Copy, Clone, PartialEq, Default)]
#[non_exhaustive]
/// An Opus file's audio properties
pub struct OpusProperties {
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
channels: u8,
version: u8,
input_sample_rate: u32,
pub(crate) duration: Duration,
pub(crate) overall_bitrate: u32,
pub(crate) audio_bitrate: u32,
pub(crate) channels: u8,
pub(crate) version: u8,
pub(crate) input_sample_rate: u32,
}
impl From<OpusProperties> for FileProperties {
@ -33,25 +34,6 @@ impl From<OpusProperties> for FileProperties {
}
impl OpusProperties {
/// Create a new [`OpusProperties`]
pub const fn new(
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
channels: u8,
version: u8,
input_sample_rate: u32,
) -> Self {
Self {
duration,
overall_bitrate,
audio_bitrate,
channels,
version,
input_sample_rate,
}
}
/// Duration
pub fn duration(&self) -> Duration {
self.duration

View file

@ -10,17 +10,18 @@ use byteorder::{LittleEndian, ReadBytesExt};
use ogg_pager::Page;
#[derive(Debug, Copy, Clone, PartialEq, Default)]
#[non_exhaustive]
/// A Speex file's audio properties
pub struct SpeexProperties {
duration: Duration,
version: u32,
sample_rate: u32,
mode: u32,
channels: u8,
vbr: bool,
overall_bitrate: u32,
audio_bitrate: u32,
nominal_bitrate: i32,
pub(crate) duration: Duration,
pub(crate) version: u32,
pub(crate) sample_rate: u32,
pub(crate) mode: u32,
pub(crate) channels: u8,
pub(crate) vbr: bool,
pub(crate) overall_bitrate: u32,
pub(crate) audio_bitrate: u32,
pub(crate) nominal_bitrate: i32,
}
impl From<SpeexProperties> for FileProperties {
@ -37,31 +38,6 @@ impl From<SpeexProperties> for FileProperties {
}
impl SpeexProperties {
/// Create a new [`SpeexProperties`]
pub const fn new(
duration: Duration,
version: u32,
sample_rate: u32,
mode: u32,
channels: u8,
vbr: bool,
overall_bitrate: u32,
audio_bitrate: u32,
nominal_bitrate: i32,
) -> Self {
Self {
duration,
version,
sample_rate,
mode,
channels,
vbr,
overall_bitrate,
audio_bitrate,
nominal_bitrate,
}
}
/// Duration
pub fn duration(&self) -> Duration {
self.duration

View file

@ -9,17 +9,18 @@ use byteorder::{LittleEndian, ReadBytesExt};
use ogg_pager::Page;
#[derive(Copy, Clone, Debug, PartialEq, Default)]
#[non_exhaustive]
/// An OGG Vorbis file's audio properties
pub struct VorbisProperties {
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
channels: u8,
version: u32,
bitrate_maximum: i32,
bitrate_nominal: i32,
bitrate_minimum: i32,
pub(crate) duration: Duration,
pub(crate) overall_bitrate: u32,
pub(crate) audio_bitrate: u32,
pub(crate) sample_rate: u32,
pub(crate) channels: u8,
pub(crate) version: u32,
pub(crate) bitrate_maximum: i32,
pub(crate) bitrate_nominal: i32,
pub(crate) bitrate_minimum: i32,
}
impl From<VorbisProperties> for FileProperties {
@ -36,31 +37,6 @@ impl From<VorbisProperties> for FileProperties {
}
impl VorbisProperties {
/// Creates a new [`VorbisProperties`]
pub const fn new(
duration: Duration,
overall_bitrate: u32,
audio_bitrate: u32,
sample_rate: u32,
channels: u8,
version: u32,
bitrate_maximum: i32,
bitrate_nominal: i32,
bitrate_minimum: i32,
) -> Self {
Self {
duration,
overall_bitrate,
audio_bitrate,
sample_rate,
channels,
version,
bitrate_maximum,
bitrate_nominal,
bitrate_minimum,
}
}
/// Duration
pub fn duration(&self) -> Duration {
self.duration

View file

@ -1,6 +1,7 @@
use std::time::Duration;
#[derive(Debug, PartialEq, Clone)]
#[non_exhaustive]
/// Various *immutable* audio properties
pub struct FileProperties {
pub(crate) duration: Duration,
@ -25,25 +26,6 @@ impl Default for FileProperties {
}
impl FileProperties {
/// Creates a new [`FileProperties`]
pub const fn new(
duration: Duration,
overall_bitrate: Option<u32>,
audio_bitrate: Option<u32>,
sample_rate: Option<u32>,
bit_depth: Option<u8>,
channels: Option<u8>,
) -> Self {
Self {
duration,
overall_bitrate,
audio_bitrate,
sample_rate,
bit_depth,
channels,
}
}
/// Duration
pub fn duration(&self) -> Duration {
self.duration
@ -74,3 +56,213 @@ impl FileProperties {
self.channels
}
}
#[cfg(test)]
mod tests {
use crate::ape::{ApeFile, ApeProperties};
use crate::iff::{AiffFile, WavFile, WavFormat, WavProperties};
use crate::mp3::{ChannelMode, Layer, Mp3File, Mp3Properties, MpegVersion};
use crate::mp4::{Mp4Codec, Mp4File, Mp4Properties};
use crate::ogg::{
FlacFile, OpusFile, OpusProperties, SpeexFile, SpeexProperties, VorbisFile,
VorbisProperties,
};
use crate::{AudioFile, FileProperties};
use std::fs::File;
use std::time::Duration;
const AIFF_PROPERTIES: FileProperties = FileProperties {
duration: Duration::from_millis(1428),
overall_bitrate: Some(1542),
audio_bitrate: Some(1536),
sample_rate: Some(48000),
bit_depth: Some(16),
channels: Some(2),
};
const APE_PROPERTIES: ApeProperties = ApeProperties {
version: 3990,
duration: Duration::from_millis(1428),
overall_bitrate: 360,
audio_bitrate: 360,
sample_rate: 48000,
bit_depth: 16,
channels: 2,
};
const FLAC_PROPERTIES: FileProperties = FileProperties {
duration: Duration::from_millis(1428),
overall_bitrate: Some(321),
audio_bitrate: Some(275),
sample_rate: Some(48000),
bit_depth: Some(16),
channels: Some(2),
};
const MP3_PROPERTIES: Mp3Properties = Mp3Properties {
version: MpegVersion::V1,
layer: Layer::Layer3,
channel_mode: ChannelMode::Stereo,
duration: Duration::from_millis(1464),
overall_bitrate: 64,
audio_bitrate: 62,
sample_rate: 48000,
channels: 2,
};
const MP4_AAC_PROPERTIES: Mp4Properties = Mp4Properties {
codec: Mp4Codec::AAC,
duration: Duration::from_millis(1449),
overall_bitrate: 135,
audio_bitrate: 124,
sample_rate: 48000,
bit_depth: None,
channels: 2,
};
const MP4_ALAC_PROPERTIES: Mp4Properties = Mp4Properties {
codec: Mp4Codec::ALAC,
duration: Duration::from_millis(1428),
overall_bitrate: 331,
audio_bitrate: 1536,
sample_rate: 48000,
bit_depth: Some(16),
channels: 2,
};
const OPUS_PROPERTIES: OpusProperties = OpusProperties {
duration: Duration::from_millis(1428),
overall_bitrate: 120,
audio_bitrate: 120,
channels: 2,
version: 1,
input_sample_rate: 48000,
};
const SPEEX_PROPERTIES: SpeexProperties = SpeexProperties {
duration: Duration::from_millis(1469),
version: 1,
sample_rate: 32000,
mode: 2,
channels: 2,
vbr: false,
overall_bitrate: 32,
audio_bitrate: 29,
nominal_bitrate: 29600,
};
const VORBIS_PROPERTIES: VorbisProperties = VorbisProperties {
duration: Duration::from_millis(1450),
overall_bitrate: 96,
audio_bitrate: 112,
sample_rate: 48000,
channels: 2,
version: 0,
bitrate_maximum: 0,
bitrate_nominal: 112_000,
bitrate_minimum: 0,
};
const WAV_PROPERTIES: WavProperties = WavProperties {
format: WavFormat::PCM,
duration: Duration::from_millis(1428),
overall_bitrate: 1542,
audio_bitrate: 1536,
sample_rate: 48000,
bit_depth: 16,
channels: 2,
};
fn get_properties<T>(path: &str) -> T::Properties
where
T: AudioFile,
<T as AudioFile>::Properties: Clone,
{
let mut f = File::open(path).unwrap();
let audio_file = T::read_from(&mut f, true).unwrap();
audio_file.properties().clone()
}
#[test]
fn aiff_properties() {
assert_eq!(
get_properties::<AiffFile>("tests/files/assets/minimal/full_test.aiff"),
AIFF_PROPERTIES
);
}
#[test]
fn ape_properties() {
assert_eq!(
get_properties::<ApeFile>("tests/files/assets/minimal/full_test.ape"),
APE_PROPERTIES
);
}
#[test]
fn flac_properties() {
assert_eq!(
get_properties::<FlacFile>("tests/files/assets/minimal/full_test.flac"),
FLAC_PROPERTIES
)
}
#[test]
fn mp3_properties() {
assert_eq!(
get_properties::<Mp3File>("tests/files/assets/minimal/full_test.mp3"),
MP3_PROPERTIES
)
}
#[test]
fn mp4_aac_properties() {
assert_eq!(
get_properties::<Mp4File>("tests/files/assets/minimal/m4a_codec_aac.m4a"),
MP4_AAC_PROPERTIES
)
}
#[test]
fn mp4_alac_properties() {
assert_eq!(
get_properties::<Mp4File>("tests/files/assets/minimal/m4a_codec_alac.m4a"),
MP4_ALAC_PROPERTIES
)
}
#[test]
fn opus_properties() {
assert_eq!(
get_properties::<OpusFile>("tests/files/assets/minimal/full_test.opus"),
OPUS_PROPERTIES
)
}
#[test]
fn speex_properties() {
assert_eq!(
get_properties::<SpeexFile>("tests/files/assets/minimal/full_test.spx"),
SPEEX_PROPERTIES
)
}
#[test]
fn vorbis_properties() {
assert_eq!(
get_properties::<VorbisFile>("tests/files/assets/minimal/full_test.ogg"),
VORBIS_PROPERTIES
)
}
#[test]
fn wav_properties() {
assert_eq!(
get_properties::<WavFile>("tests/files/assets/minimal/wav_format_pcm.wav"),
WAV_PROPERTIES
)
}
}

View file

@ -1,192 +0,0 @@
use lofty::ape::{ApeFile, ApeProperties};
use lofty::iff::{AiffFile, WavFile, WavFormat, WavProperties};
use lofty::mp3::{ChannelMode, Layer, Mp3File, Mp3Properties, MpegVersion};
use lofty::mp4::{Mp4Codec, Mp4File, Mp4Properties};
use lofty::ogg::{
FlacFile, OpusFile, OpusProperties, SpeexFile, SpeexProperties, VorbisFile, VorbisProperties,
};
use lofty::{AudioFile, FileProperties};
use std::fs::File;
use std::time::Duration;
const AIFF_PROPERTIES: FileProperties = FileProperties::new(
Duration::from_millis(1428),
Some(1542),
Some(1536),
Some(48000),
Some(16),
Some(2),
);
const APE_PROPERTIES: ApeProperties =
ApeProperties::new(3990, Duration::from_millis(1428), 360, 360, 48000, 16, 2);
const FLAC_PROPERTIES: FileProperties = FileProperties::new(
Duration::from_millis(1428),
Some(321),
Some(275),
Some(48000),
Some(16),
Some(2),
);
const MP3_PROPERTIES: Mp3Properties = Mp3Properties::new(
MpegVersion::V1,
Layer::Layer3,
ChannelMode::Stereo,
Duration::from_millis(1464),
64,
62,
48000,
2,
);
const MP4_AAC_PROPERTIES: Mp4Properties = Mp4Properties::new(
Mp4Codec::AAC,
Duration::from_millis(1449),
135,
124,
48000,
None,
2,
);
const MP4_ALAC_PROPERTIES: Mp4Properties = Mp4Properties::new(
Mp4Codec::ALAC,
Duration::from_millis(1428),
331,
1536,
48000,
Some(16),
2,
);
const OPUS_PROPERTIES: OpusProperties =
OpusProperties::new(Duration::from_millis(1428), 120, 120, 2, 1, 48000);
const SPEEX_PROPERTIES: SpeexProperties = SpeexProperties::new(
Duration::from_millis(1469),
1,
32000,
2,
2,
false,
32,
29,
29600,
);
const VORBIS_PROPERTIES: VorbisProperties = VorbisProperties::new(
Duration::from_millis(1450),
96,
112,
48000,
2,
0,
0,
112000,
0,
);
const WAV_PROPERTIES: WavProperties = WavProperties::new(
WavFormat::PCM,
Duration::from_millis(1428),
1542,
1536,
48000,
16,
2,
);
fn get_properties<T>(path: &str) -> T::Properties
where
T: AudioFile,
<T as AudioFile>::Properties: Clone,
{
let mut f = File::open(path).unwrap();
let audio_file = T::read_from(&mut f, true).unwrap();
audio_file.properties().clone()
}
#[test]
fn aiff_properties() {
assert_eq!(
get_properties::<AiffFile>("tests/files/assets/minimal/full_test.aiff"),
AIFF_PROPERTIES
);
}
#[test]
fn ape_properties() {
assert_eq!(
get_properties::<ApeFile>("tests/files/assets/minimal/full_test.ape"),
APE_PROPERTIES
);
}
#[test]
fn flac_properties() {
assert_eq!(
get_properties::<FlacFile>("tests/files/assets/minimal/full_test.flac"),
FLAC_PROPERTIES
)
}
#[test]
fn mp3_properties() {
assert_eq!(
get_properties::<Mp3File>("tests/files/assets/minimal/full_test.mp3"),
MP3_PROPERTIES
)
}
#[test]
fn mp4_aac_properties() {
assert_eq!(
get_properties::<Mp4File>("tests/files/assets/minimal/m4a_codec_aac.m4a"),
MP4_AAC_PROPERTIES
)
}
#[test]
fn mp4_alac_properties() {
assert_eq!(
get_properties::<Mp4File>("tests/files/assets/minimal/m4a_codec_alac.m4a"),
MP4_ALAC_PROPERTIES
)
}
#[test]
fn opus_properties() {
assert_eq!(
get_properties::<OpusFile>("tests/files/assets/minimal/full_test.opus"),
OPUS_PROPERTIES
)
}
#[test]
fn speex_properties() {
assert_eq!(
get_properties::<SpeexFile>("tests/files/assets/minimal/full_test.spx"),
SPEEX_PROPERTIES
)
}
#[test]
fn vorbis_properties() {
assert_eq!(
get_properties::<VorbisFile>("tests/files/assets/minimal/full_test.ogg"),
VORBIS_PROPERTIES
)
}
#[test]
fn wav_properties() {
assert_eq!(
get_properties::<WavFile>("tests/files/assets/minimal/wav_format_pcm.wav"),
WAV_PROPERTIES
)
}