Skip to main content

fits_io/header/
bitpix.rs

1use std::error::Error;
2
3/// The type of the values in an array, from its BITPIX card.
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub enum Bitpix {
6    /// Float 64
7    F64 = -64,
8
9    /// Float 32
10    F32 = -32,
11
12    /// Unsigned 8 bit
13    U8 = 8,
14
15    /// Signed 16 bit
16    I16 = 16,
17
18    /// Signed 32 bit
19    I32 = 32,
20}
21
22impl Bitpix {
23    /// How many bytes one value of this type occupies.
24    pub fn byte_size(&self) -> usize {
25        match self {
26            Bitpix::F64 => 8,
27            Bitpix::F32 => 4,
28            Bitpix::U8 => 1,
29            Bitpix::I16 => 2,
30            Bitpix::I32 => 4,
31        }
32    }
33}
34
35impl Bitpix {
36    /// Decodes one big-endian array value from the front of `bytes`, widening it
37    /// to `f64`.
38    ///
39    /// Returns `None` when `bytes` is shorter than [`Bitpix::byte_size`], so a
40    /// truncated data section produces a short read rather than a panic.
41    pub fn read_be(&self, bytes: &[u8]) -> Option<f64> {
42        fn take<const N: usize>(bytes: &[u8]) -> Option<[u8; N]> {
43            bytes.get(..N)?.try_into().ok()
44        }
45
46        match self {
47            Bitpix::F64 => Some(f64::from_be_bytes(take(bytes)?)),
48            Bitpix::F32 => Some(f32::from_be_bytes(take(bytes)?) as f64),
49            Bitpix::U8 => Some(*bytes.first()? as f64),
50            Bitpix::I16 => Some(i16::from_be_bytes(take(bytes)?) as f64),
51            Bitpix::I32 => Some(i32::from_be_bytes(take(bytes)?) as f64),
52        }
53    }
54
55    /// The inclusive range of values this type can represent, as `f64`.
56    ///
57    /// `None` for the floating point types, which have no meaningful full-scale
58    /// range to normalise against.
59    pub fn value_range(&self) -> Option<(f64, f64)> {
60        match self {
61            Bitpix::F64 | Bitpix::F32 => None,
62            Bitpix::U8 => Some((u8::MIN as f64, u8::MAX as f64)),
63            Bitpix::I16 => Some((i16::MIN as f64, i16::MAX as f64)),
64            Bitpix::I32 => Some((i32::MIN as f64, i32::MAX as f64)),
65        }
66    }
67}
68
69impl From<Bitpix> for i64 {
70    fn from(value: Bitpix) -> Self {
71        value as i64
72    }
73}
74
75impl TryFrom<i64> for Bitpix {
76    type Error = Box<dyn Error + Send + Sync>;
77
78    fn try_from(value: i64) -> Result<Self, Self::Error> {
79        match value {
80            -64 => Ok(Bitpix::F64),
81            -32 => Ok(Bitpix::F32),
82            8 => Ok(Bitpix::U8),
83            16 => Ok(Bitpix::I16),
84            32 => Ok(Bitpix::I32),
85            _ => Err(From::from(format!("Invalid bitpix value: {}", value))),
86        }
87    }
88}