1use crate::error::FitsError;
2use crate::error::Result;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum Bitpix {
12 U8,
14 I16,
16 I32,
18 I64,
20 F32,
22 F64,
24}
25
26impl Bitpix {
27 pub fn from_code(code: i64) -> Result<Self> {
29 match code {
30 8 => Ok(Bitpix::U8),
31 16 => Ok(Bitpix::I16),
32 32 => Ok(Bitpix::I32),
33 64 => Ok(Bitpix::I64),
34 -32 => Ok(Bitpix::F32),
35 -64 => Ok(Bitpix::F64),
36 _ => Err(FitsError::InvalidBitpix { code }),
37 }
38 }
39
40 pub fn code(self) -> i64 {
42 match self {
43 Bitpix::U8 => 8,
44 Bitpix::I16 => 16,
45 Bitpix::I32 => 32,
46 Bitpix::I64 => 64,
47 Bitpix::F32 => -32,
48 Bitpix::F64 => -64,
49 }
50 }
51
52 pub fn elem_size(self) -> usize {
54 (self.code().unsigned_abs() / 8) as usize
55 }
56
57 pub fn is_float(self) -> bool {
58 matches!(self, Bitpix::F32 | Bitpix::F64)
59 }
60
61 pub fn is_integer(self) -> bool {
62 !self.is_float()
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn code_round_trips_for_every_variant() {
72 for bp in [
73 Bitpix::U8,
74 Bitpix::I16,
75 Bitpix::I32,
76 Bitpix::I64,
77 Bitpix::F32,
78 Bitpix::F64,
79 ] {
80 assert_eq!(Bitpix::from_code(bp.code()).unwrap(), bp);
81 }
82 }
83
84 #[test]
85 fn codes_and_sizes_match_the_standard() {
86 let cases = [
88 (Bitpix::U8, 8, 1, false),
89 (Bitpix::I16, 16, 2, false),
90 (Bitpix::I32, 32, 4, false),
91 (Bitpix::I64, 64, 8, false),
92 (Bitpix::F32, -32, 4, true),
93 (Bitpix::F64, -64, 8, true),
94 ];
95 for (bp, code, size, is_float) in cases {
96 assert_eq!(bp.code(), code);
97 assert_eq!(bp.elem_size(), size);
98 assert_eq!(bp.is_float(), is_float);
99 assert_eq!(bp.is_integer(), !is_float);
100 }
101 }
102
103 #[test]
104 fn rejects_codes_outside_the_allowed_set() {
105 for bad in [0, 7, 1, -1, 24, 128, -16] {
106 assert!(matches!(
107 Bitpix::from_code(bad),
108 Err(FitsError::InvalidBitpix { code }) if code == bad
109 ));
110 }
111 }
112}