use std::{
error::Error,
fmt::{Display, Formatter}
};
pub(crate) mod optimizer;
pub(crate) mod codebook;
macro_rules! try_from_impl {
{ type Enum = $enum_type:ident($repr_type:ty) { $( $variant:ident ),+ }; type Error = $error_type:ident } => {
#[doc = "The error type for fallible conversions from integers to a `"]
#[doc = stringify!($enum_type)]
#[doc = "`."]
#[derive(Debug)]
#[repr(transparent)]
pub struct $error_type($repr_type);
impl Display for $error_type {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for $error_type {}
impl TryFrom<$repr_type> for $enum_type {
type Error = $error_type;
fn try_from(value: $repr_type) -> Result<Self, Self::Error> {
match value {
$( value if Self::$variant as $repr_type == value => Ok(Self::$variant) ),+,
_ => Err($error_type(value))
}
}
}
impl $error_type {
pub const fn integer(&self) -> $repr_type {
self.0
}
}
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[repr(u8)]
pub enum PacketType {
Audio = 0,
IdentificationHeader = 1,
CommentHeader = 3,
SetupHeader = 5
}
try_from_impl! {
type Enum = PacketType(u8) { Audio, IdentificationHeader, CommentHeader, SetupHeader };
type Error = TryPacketTypeFromInt
}
impl Display for PacketType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Audio => "audio packet",
Self::IdentificationHeader => "identification header packet",
Self::CommentHeader => "comment header packet",
Self::SetupHeader => "setup header packet"
})
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[repr(u8)]
enum VectorLookupType {
NoLookup = 0,
ImplicitlyPopulated = 1,
ExplicitlyPopulated = 2
}
try_from_impl! {
type Enum = VectorLookupType(u8) { NoLookup, ImplicitlyPopulated, ExplicitlyPopulated };
type Error = TryVectorLookupTypeFromInt
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
#[repr(u16)]
enum ResidueType {
Interleaved = 0,
Ordered = 1,
InterleavedVectors = 2
}
try_from_impl! {
type Enum = ResidueType(u16) { Interleaved, Ordered, InterleavedVectors };
type Error = TryResidueTypeFromInt
}
const fn ilog(n: i32) -> u8 {
if n > 0 {
32 - n.leading_zeros() as u8
} else {
0
}
}
fn lookup1_values(codebook_entries: u32, codebook_dimensions: u16) -> u32 {
if codebook_dimensions == 0 {
u32::MAX
} else {
(codebook_entries as f32).powf(1.0 / codebook_dimensions as f32) as u32
}
}
#[cfg(test)]
mod tests {
use super::{ilog, lookup1_values};
#[test]
fn ilog_works() {
assert_eq!(ilog(0), 0);
assert_eq!(ilog(1), 1);
assert_eq!(ilog(2), 2);
assert_eq!(ilog(3), 2);
assert_eq!(ilog(4), 3);
assert_eq!(ilog(7), 3);
assert_eq!(ilog(i32::MAX), 31);
assert_eq!(ilog(i32::MIN), 0);
}
#[test]
fn lookup1_values_works() {
assert_eq!(lookup1_values(100, 5), 2);
assert_eq!(lookup1_values(1, 5), 1);
assert_eq!(lookup1_values(0, u16::MAX), 0);
assert_eq!(lookup1_values(0xFFFFFF, 0), u32::MAX);
assert_eq!(lookup1_values(0xFFFFFF, u16::MAX), 1);
}
}