use crate::error::FitsError;
use crate::error::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Bitpix {
U8,
I16,
I32,
I64,
F32,
F64,
}
impl Bitpix {
pub fn from_code(code: i64) -> Result<Self> {
match code {
8 => Ok(Bitpix::U8),
16 => Ok(Bitpix::I16),
32 => Ok(Bitpix::I32),
64 => Ok(Bitpix::I64),
-32 => Ok(Bitpix::F32),
-64 => Ok(Bitpix::F64),
_ => Err(FitsError::InvalidBitpix { code }),
}
}
pub fn code(self) -> i64 {
match self {
Bitpix::U8 => 8,
Bitpix::I16 => 16,
Bitpix::I32 => 32,
Bitpix::I64 => 64,
Bitpix::F32 => -32,
Bitpix::F64 => -64,
}
}
pub fn elem_size(self) -> usize {
(self.code().unsigned_abs() / 8) as usize
}
pub fn is_float(self) -> bool {
matches!(self, Bitpix::F32 | Bitpix::F64)
}
pub fn is_integer(self) -> bool {
!self.is_float()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn code_round_trips_for_every_variant() {
for bp in [
Bitpix::U8,
Bitpix::I16,
Bitpix::I32,
Bitpix::I64,
Bitpix::F32,
Bitpix::F64,
] {
assert_eq!(Bitpix::from_code(bp.code()).unwrap(), bp);
}
}
#[test]
fn codes_and_sizes_match_the_standard() {
let cases = [
(Bitpix::U8, 8, 1, false),
(Bitpix::I16, 16, 2, false),
(Bitpix::I32, 32, 4, false),
(Bitpix::I64, 64, 8, false),
(Bitpix::F32, -32, 4, true),
(Bitpix::F64, -64, 8, true),
];
for (bp, code, size, is_float) in cases {
assert_eq!(bp.code(), code);
assert_eq!(bp.elem_size(), size);
assert_eq!(bp.is_float(), is_float);
assert_eq!(bp.is_integer(), !is_float);
}
}
#[test]
fn rejects_codes_outside_the_allowed_set() {
for bad in [0, 7, 1, -1, 24, 128, -16] {
assert!(matches!(
Bitpix::from_code(bad),
Err(FitsError::InvalidBitpix { code }) if code == bad
));
}
}
}