use thiserror::Error;
#[derive(Debug, Clone, Error)]
pub enum TurboQuantError {
#[error("dimension must be even, got {0}")]
OddDimension(usize),
#[error("dimension must be > 0")]
ZeroDimension,
#[error("bit width must be 1..=16, got {0}")]
InvalidBitWidth(u8),
#[error("projections must be > 0")]
ZeroProjections,
#[error("dimension {0} too large for compact format (max {1})")]
DimensionTooLarge(usize, usize),
#[error("dimension mismatch: quantizer expects {expected}, got {actual}")]
DimensionMismatch {
expected: usize,
actual: usize,
},
#[error("empty input: {0}")]
EmptyInput(&'static str),
#[error("input contains non-finite values (NaN or Inf) at index {index}")]
NonFiniteInput {
index: usize,
},
#[error("deserialization failed: {reason}")]
DeserializationError {
reason: String,
},
#[error("index {index} out of bounds (length {length})")]
IndexOutOfBounds {
index: usize,
length: usize,
},
}
pub type Result<T> = core::result::Result<T, TurboQuantError>;
#[inline]
pub fn validate_finite(vector: &[f32]) -> Result<()> {
for (i, &v) in vector.iter().enumerate() {
if !v.is_finite() {
return Err(TurboQuantError::NonFiniteInput { index: i });
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_finite_ok() {
let v = vec![1.0, -2.5, 0.0, 1e30, -1e-30];
assert!(validate_finite(&v).is_ok());
}
#[test]
fn test_validate_finite_nan() {
let v = vec![1.0, 2.0, f32::NAN, 4.0];
match validate_finite(&v) {
Err(TurboQuantError::NonFiniteInput { index }) => assert_eq!(index, 2),
other => panic!("expected NonFiniteInput, got {:?}", other),
}
}
#[test]
fn test_validate_finite_inf() {
let v = vec![f32::INFINITY, 1.0];
match validate_finite(&v) {
Err(TurboQuantError::NonFiniteInput { index }) => assert_eq!(index, 0),
other => panic!("expected NonFiniteInput, got {:?}", other),
}
}
#[test]
fn test_validate_finite_neg_inf() {
let v = vec![1.0, f32::NEG_INFINITY];
match validate_finite(&v) {
Err(TurboQuantError::NonFiniteInput { index }) => assert_eq!(index, 1),
other => panic!("expected NonFiniteInput, got {:?}", other),
}
}
#[test]
fn test_validate_finite_empty() {
assert!(validate_finite(&[]).is_ok());
}
#[test]
fn test_error_display() {
let e = TurboQuantError::DimensionMismatch {
expected: 128,
actual: 256,
};
assert_eq!(
e.to_string(),
"dimension mismatch: quantizer expects 128, got 256"
);
}
}