#[derive(Debug, Clone)]
pub struct AecParams {
pub bits_per_sample: u32,
pub block_size: u32,
pub rsi: u32,
pub flags: u32,
}
pub const AEC_DATA_SIGNED: u32 = 1;
pub const AEC_DATA_3BYTE: u32 = 2;
pub const AEC_DATA_MSB: u32 = 4;
pub const AEC_DATA_PREPROCESS: u32 = 8;
pub const AEC_ALLOW_K13: u32 = 16;
pub const AEC_PAD_RSI: u32 = 32;
pub const AEC_NOT_ENFORCE: u32 = 64;
pub const AEC_RESTRICTED: u32 = 128;
pub(crate) fn sample_byte_width(bits_per_sample: u32, flags: u32) -> usize {
let nbytes = (bits_per_sample as usize).div_ceil(8);
if nbytes == 3 && flags & AEC_DATA_3BYTE == 0 {
4 } else {
nbytes
}
}
pub(crate) fn effective_flags(params: &AecParams) -> u32 {
let mut flags = params.flags;
if params.bits_per_sample > 16 && params.bits_per_sample <= 24 {
flags |= AEC_DATA_3BYTE;
}
flags
}
pub(crate) fn id_len(bits_per_sample: u32, flags: u32) -> u32 {
if bits_per_sample > 16 {
5
} else if bits_per_sample > 8 {
4
} else if flags & AEC_RESTRICTED != 0 {
if bits_per_sample <= 2 {
1
} else {
2 }
} else {
3
}
}
pub(crate) fn kmax(id_len: u32) -> u32 {
(1u32 << id_len).saturating_sub(3)
}
pub(crate) fn validate(params: &AecParams) -> Result<(), crate::AecError> {
use crate::AecError;
if params.bits_per_sample == 0 || params.bits_per_sample > 32 {
return Err(AecError::Config(format!(
"bits_per_sample must be 1–32, got {}",
params.bits_per_sample
)));
}
if params.block_size == 0 {
return Err(AecError::Config("block_size must be non-zero".to_string()));
}
if params.flags & AEC_NOT_ENFORCE != 0 {
if params.block_size & 1 != 0 {
return Err(AecError::Config(format!(
"block_size must be even, got {}",
params.block_size
)));
}
} else if !matches!(params.block_size, 8 | 16 | 32 | 64) {
return Err(AecError::Config(format!(
"block_size must be 8, 16, 32, or 64, got {}",
params.block_size
)));
}
if params.rsi == 0 || params.rsi > 4096 {
return Err(AecError::Config(format!(
"rsi must be 1–4096, got {}",
params.rsi
)));
}
if params.flags & AEC_RESTRICTED != 0 && params.bits_per_sample > 4 {
return Err(AecError::Config(format!(
"AEC_RESTRICTED requires bits_per_sample ≤ 4, got {}",
params.bits_per_sample
)));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_id_len_values() {
assert_eq!(id_len(32, 0), 5);
assert_eq!(id_len(24, 0), 5);
assert_eq!(id_len(17, 0), 5);
assert_eq!(id_len(16, 0), 4);
assert_eq!(id_len(9, 0), 4);
assert_eq!(id_len(8, 0), 3);
assert_eq!(id_len(1, 0), 3);
assert_eq!(id_len(2, AEC_RESTRICTED), 1);
assert_eq!(id_len(4, AEC_RESTRICTED), 2);
}
#[test]
fn test_kmax_values() {
assert_eq!(kmax(5), 29);
assert_eq!(kmax(4), 13);
assert_eq!(kmax(3), 5);
assert_eq!(kmax(2), 1);
assert_eq!(kmax(1), 0); }
#[test]
fn test_sample_byte_width() {
assert_eq!(sample_byte_width(8, 0), 1);
assert_eq!(sample_byte_width(16, 0), 2);
assert_eq!(sample_byte_width(24, 0), 4); assert_eq!(sample_byte_width(24, AEC_DATA_3BYTE), 3);
assert_eq!(sample_byte_width(32, 0), 4);
}
#[test]
fn test_effective_flags_auto_3byte() {
let p = AecParams {
bits_per_sample: 24,
block_size: 16,
rsi: 128,
flags: AEC_DATA_PREPROCESS,
};
let f = effective_flags(&p);
assert!(f & AEC_DATA_3BYTE != 0);
assert!(f & AEC_DATA_PREPROCESS != 0);
}
#[test]
fn test_validate_ok() {
let p = AecParams {
bits_per_sample: 8,
block_size: 16,
rsi: 128,
flags: AEC_DATA_PREPROCESS,
};
assert!(validate(&p).is_ok());
}
#[test]
fn test_validate_bad_bps() {
let p = AecParams {
bits_per_sample: 0,
block_size: 16,
rsi: 128,
flags: 0,
};
assert!(validate(&p).is_err());
let p2 = AecParams {
bits_per_sample: 33,
block_size: 16,
rsi: 128,
flags: 0,
};
assert!(validate(&p2).is_err());
}
#[test]
fn test_validate_bad_block_size() {
let p = AecParams {
bits_per_sample: 8,
block_size: 12,
rsi: 128,
flags: 0,
};
assert!(validate(&p).is_err());
let p2 = AecParams {
bits_per_sample: 8,
block_size: 12,
rsi: 128,
flags: AEC_NOT_ENFORCE,
};
assert!(validate(&p2).is_ok());
}
}