use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum SampleFormat {
U8,
I16,
I32,
F32,
F64,
U8p,
I16p,
I32p,
F32p,
F64p,
Other(u32),
}
impl SampleFormat {
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::U8 => "u8",
Self::I16 => "s16",
Self::I32 => "s32",
Self::F32 => "flt",
Self::F64 => "dbl",
Self::U8p => "u8p",
Self::I16p => "s16p",
Self::I32p => "s32p",
Self::F32p => "fltp",
Self::F64p => "dblp",
Self::Other(_) => "unknown",
}
}
#[must_use]
pub const fn bytes_per_sample(&self) -> usize {
match self {
Self::U8 | Self::U8p => 1,
Self::I16 | Self::I16p => 2,
Self::I32 | Self::I32p | Self::F32 | Self::F32p | Self::Other(_) => 4,
Self::F64 | Self::F64p => 8,
}
}
#[must_use]
pub const fn is_planar(&self) -> bool {
matches!(
self,
Self::U8p | Self::I16p | Self::I32p | Self::F32p | Self::F64p
)
}
#[must_use]
pub const fn is_packed(&self) -> bool {
!self.is_planar()
}
#[must_use]
pub const fn is_float(&self) -> bool {
matches!(self, Self::F32 | Self::F64 | Self::F32p | Self::F64p)
}
#[must_use]
pub const fn is_integer(&self) -> bool {
matches!(
self,
Self::U8 | Self::I16 | Self::I32 | Self::U8p | Self::I16p | Self::I32p
)
}
#[must_use]
pub const fn is_signed(&self) -> bool {
!matches!(self, Self::U8 | Self::U8p | Self::Other(_))
}
#[must_use]
pub const fn packed_equivalent(&self) -> Self {
match self {
Self::U8p => Self::U8,
Self::I16p => Self::I16,
Self::I32p => Self::I32,
Self::F32p => Self::F32,
Self::F64p => Self::F64,
other => *other,
}
}
#[must_use]
pub const fn planar_equivalent(&self) -> Self {
match self {
Self::U8 => Self::U8p,
Self::I16 => Self::I16p,
Self::I32 => Self::I32p,
Self::F32 => Self::F32p,
Self::F64 => Self::F64p,
other => *other,
}
}
#[must_use]
pub const fn bit_depth(&self) -> usize {
self.bytes_per_sample() * 8
}
}
impl fmt::Display for SampleFormat {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl Default for SampleFormat {
fn default() -> Self {
Self::F32
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_names() {
assert_eq!(SampleFormat::U8.name(), "u8");
assert_eq!(SampleFormat::I16.name(), "s16");
assert_eq!(SampleFormat::I32.name(), "s32");
assert_eq!(SampleFormat::F32.name(), "flt");
assert_eq!(SampleFormat::F64.name(), "dbl");
assert_eq!(SampleFormat::U8p.name(), "u8p");
assert_eq!(SampleFormat::I16p.name(), "s16p");
assert_eq!(SampleFormat::I32p.name(), "s32p");
assert_eq!(SampleFormat::F32p.name(), "fltp");
assert_eq!(SampleFormat::F64p.name(), "dblp");
assert_eq!(SampleFormat::Other(999).name(), "unknown");
}
#[test]
fn test_bytes_per_sample() {
assert_eq!(SampleFormat::U8.bytes_per_sample(), 1);
assert_eq!(SampleFormat::U8p.bytes_per_sample(), 1);
assert_eq!(SampleFormat::I16.bytes_per_sample(), 2);
assert_eq!(SampleFormat::I16p.bytes_per_sample(), 2);
assert_eq!(SampleFormat::I32.bytes_per_sample(), 4);
assert_eq!(SampleFormat::I32p.bytes_per_sample(), 4);
assert_eq!(SampleFormat::F32.bytes_per_sample(), 4);
assert_eq!(SampleFormat::F32p.bytes_per_sample(), 4);
assert_eq!(SampleFormat::F64.bytes_per_sample(), 8);
assert_eq!(SampleFormat::F64p.bytes_per_sample(), 8);
assert_eq!(SampleFormat::Other(123).bytes_per_sample(), 4);
}
#[test]
fn test_is_planar() {
assert!(!SampleFormat::U8.is_planar());
assert!(!SampleFormat::I16.is_planar());
assert!(!SampleFormat::I32.is_planar());
assert!(!SampleFormat::F32.is_planar());
assert!(!SampleFormat::F64.is_planar());
assert!(!SampleFormat::Other(0).is_planar());
assert!(SampleFormat::U8p.is_planar());
assert!(SampleFormat::I16p.is_planar());
assert!(SampleFormat::I32p.is_planar());
assert!(SampleFormat::F32p.is_planar());
assert!(SampleFormat::F64p.is_planar());
}
#[test]
fn test_is_packed() {
assert!(SampleFormat::U8.is_packed());
assert!(SampleFormat::I16.is_packed());
assert!(SampleFormat::I32.is_packed());
assert!(SampleFormat::F32.is_packed());
assert!(SampleFormat::F64.is_packed());
assert!(!SampleFormat::U8p.is_packed());
assert!(!SampleFormat::I16p.is_packed());
assert!(!SampleFormat::I32p.is_packed());
assert!(!SampleFormat::F32p.is_packed());
assert!(!SampleFormat::F64p.is_packed());
}
#[test]
fn test_is_float() {
assert!(SampleFormat::F32.is_float());
assert!(SampleFormat::F64.is_float());
assert!(SampleFormat::F32p.is_float());
assert!(SampleFormat::F64p.is_float());
assert!(!SampleFormat::U8.is_float());
assert!(!SampleFormat::I16.is_float());
assert!(!SampleFormat::I32.is_float());
assert!(!SampleFormat::U8p.is_float());
assert!(!SampleFormat::I16p.is_float());
assert!(!SampleFormat::I32p.is_float());
assert!(!SampleFormat::Other(0).is_float());
}
#[test]
fn test_is_integer() {
assert!(SampleFormat::U8.is_integer());
assert!(SampleFormat::I16.is_integer());
assert!(SampleFormat::I32.is_integer());
assert!(SampleFormat::U8p.is_integer());
assert!(SampleFormat::I16p.is_integer());
assert!(SampleFormat::I32p.is_integer());
assert!(!SampleFormat::F32.is_integer());
assert!(!SampleFormat::F64.is_integer());
assert!(!SampleFormat::F32p.is_integer());
assert!(!SampleFormat::F64p.is_integer());
assert!(!SampleFormat::Other(0).is_integer());
}
#[test]
fn test_is_signed() {
assert!(SampleFormat::I16.is_signed());
assert!(SampleFormat::I32.is_signed());
assert!(SampleFormat::F32.is_signed());
assert!(SampleFormat::F64.is_signed());
assert!(SampleFormat::I16p.is_signed());
assert!(SampleFormat::I32p.is_signed());
assert!(SampleFormat::F32p.is_signed());
assert!(SampleFormat::F64p.is_signed());
assert!(!SampleFormat::U8.is_signed());
assert!(!SampleFormat::U8p.is_signed());
assert!(!SampleFormat::Other(0).is_signed());
}
#[test]
fn test_packed_equivalent() {
assert_eq!(SampleFormat::U8p.packed_equivalent(), SampleFormat::U8);
assert_eq!(SampleFormat::I16p.packed_equivalent(), SampleFormat::I16);
assert_eq!(SampleFormat::I32p.packed_equivalent(), SampleFormat::I32);
assert_eq!(SampleFormat::F32p.packed_equivalent(), SampleFormat::F32);
assert_eq!(SampleFormat::F64p.packed_equivalent(), SampleFormat::F64);
assert_eq!(SampleFormat::U8.packed_equivalent(), SampleFormat::U8);
assert_eq!(SampleFormat::I16.packed_equivalent(), SampleFormat::I16);
assert_eq!(SampleFormat::F32.packed_equivalent(), SampleFormat::F32);
assert_eq!(
SampleFormat::Other(42).packed_equivalent(),
SampleFormat::Other(42)
);
}
#[test]
fn test_planar_equivalent() {
assert_eq!(SampleFormat::U8.planar_equivalent(), SampleFormat::U8p);
assert_eq!(SampleFormat::I16.planar_equivalent(), SampleFormat::I16p);
assert_eq!(SampleFormat::I32.planar_equivalent(), SampleFormat::I32p);
assert_eq!(SampleFormat::F32.planar_equivalent(), SampleFormat::F32p);
assert_eq!(SampleFormat::F64.planar_equivalent(), SampleFormat::F64p);
assert_eq!(SampleFormat::U8p.planar_equivalent(), SampleFormat::U8p);
assert_eq!(SampleFormat::I16p.planar_equivalent(), SampleFormat::I16p);
assert_eq!(SampleFormat::F32p.planar_equivalent(), SampleFormat::F32p);
assert_eq!(
SampleFormat::Other(42).planar_equivalent(),
SampleFormat::Other(42)
);
}
#[test]
fn test_bit_depth() {
assert_eq!(SampleFormat::U8.bit_depth(), 8);
assert_eq!(SampleFormat::U8p.bit_depth(), 8);
assert_eq!(SampleFormat::I16.bit_depth(), 16);
assert_eq!(SampleFormat::I16p.bit_depth(), 16);
assert_eq!(SampleFormat::I32.bit_depth(), 32);
assert_eq!(SampleFormat::F32.bit_depth(), 32);
assert_eq!(SampleFormat::F64.bit_depth(), 64);
assert_eq!(SampleFormat::F64p.bit_depth(), 64);
}
#[test]
fn test_display() {
assert_eq!(format!("{}", SampleFormat::F32), "flt");
assert_eq!(format!("{}", SampleFormat::I16), "s16");
assert_eq!(format!("{}", SampleFormat::F32p), "fltp");
assert_eq!(format!("{}", SampleFormat::Other(123)), "unknown");
}
#[test]
fn test_default() {
assert_eq!(SampleFormat::default(), SampleFormat::F32);
}
#[test]
fn test_debug() {
assert_eq!(format!("{:?}", SampleFormat::F32), "F32");
assert_eq!(format!("{:?}", SampleFormat::I16p), "I16p");
assert_eq!(format!("{:?}", SampleFormat::Other(42)), "Other(42)");
}
#[test]
fn test_equality_and_hash() {
use std::collections::HashSet;
assert_eq!(SampleFormat::F32, SampleFormat::F32);
assert_ne!(SampleFormat::F32, SampleFormat::F32p);
assert_eq!(SampleFormat::Other(1), SampleFormat::Other(1));
assert_ne!(SampleFormat::Other(1), SampleFormat::Other(2));
let mut set = HashSet::new();
set.insert(SampleFormat::F32);
set.insert(SampleFormat::I16);
assert!(set.contains(&SampleFormat::F32));
assert!(!set.contains(&SampleFormat::F64));
}
#[test]
fn test_copy() {
let format = SampleFormat::F32;
let copied = format;
assert_eq!(format, copied);
assert_eq!(format.name(), copied.name());
}
#[test]
fn test_round_trip_equivalents() {
let packed_formats = [
SampleFormat::U8,
SampleFormat::I16,
SampleFormat::I32,
SampleFormat::F32,
SampleFormat::F64,
];
for format in packed_formats {
assert_eq!(format.planar_equivalent().packed_equivalent(), format);
}
let planar_formats = [
SampleFormat::U8p,
SampleFormat::I16p,
SampleFormat::I32p,
SampleFormat::F32p,
SampleFormat::F64p,
];
for format in planar_formats {
assert_eq!(format.packed_equivalent().planar_equivalent(), format);
}
}
}