use libc::{
c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong,
c_ulonglong, c_ushort,
};
#[allow(missing_docs, clippy::upper_case_acronyms)]
#[repr(C)]
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum DataType {
TBIT,
TBYTE,
TSBYTE,
TLOGICAL,
TSTRING,
TUSHORT,
TSHORT,
TUINT,
TINT,
TULONG,
TLONG,
TFLOAT,
TULONGLONG,
TLONGLONG,
TDOUBLE,
TCOMPLEX,
TDBLCOMPLEX,
}
pub(crate) trait HasFitsDataType {
const FITS_DATA_TYPE: DataType;
}
const fn size_align<T: Sized>() -> (usize, usize) {
(core::mem::size_of::<T>(), core::mem::align_of::<T>())
}
macro_rules! ctype_sign_sz_align {
($($t:ty, $name:ident);* $(;)?) => {
$(
const $name: (bool, (usize, usize)) = (<$t>::MIN == 0, size_align::<$t>());
)*
};
}
ctype_sign_sz_align!(
c_schar, SCHAR;
c_uchar, UCHAR;
c_short, SHORT;
c_ushort, USHORT;
c_int, INT;
c_uint, UINT;
c_long, LONG;
c_ulong, ULONG;
c_longlong, LONGLONG;
c_ulonglong, ULONGLONG;
);
macro_rules! has_fits_data_type_int {
($t:ty) => {
impl HasFitsDataType for $t {
const FITS_DATA_TYPE: DataType = {
#[allow(unreachable_patterns)]
match (<$t>::MIN == 0, size_align::<$t>()) {
UINT => DataType::TUINT,
USHORT => DataType::TUSHORT,
UCHAR => DataType::TBYTE,
ULONG => DataType::TULONG,
ULONGLONG => DataType::TULONGLONG,
INT => DataType::TINT,
SHORT => DataType::TSHORT,
SCHAR => DataType::TSBYTE,
LONG => DataType::TLONG,
LONGLONG => DataType::TLONGLONG,
_ => panic!(concat!(
"Type ",
stringify!($t),
" does not have a corresponding DataType"
)),
}
};
}
};
}
has_fits_data_type_int!(u8);
has_fits_data_type_int!(u16);
has_fits_data_type_int!(u32);
has_fits_data_type_int!(u64);
has_fits_data_type_int!(i8);
has_fits_data_type_int!(i16);
has_fits_data_type_int!(i32);
has_fits_data_type_int!(i64);
macro_rules! has_fits_data_type_floating {
($t:ty) => {
impl HasFitsDataType for $t {
const FITS_DATA_TYPE: DataType = {
const FLOAT: (usize, usize) = size_align::<c_float>();
const DOUBLE: (usize, usize) = size_align::<c_double>();
#[allow(unreachable_patterns)]
match size_align::<$t>() {
DOUBLE => DataType::TDOUBLE,
FLOAT => DataType::TFLOAT,
_ => panic!(concat!(
"Type ",
stringify!($t),
" does not have a corresponding DataType"
)),
}
};
}
};
}
has_fits_data_type_floating!(f32);
has_fits_data_type_floating!(f64);
#[cfg(test)]
mod test {
use crate::fitsfile::{CaseSensitivity, FileOpenMode};
use crate::hdu::HduInfo;
use crate::images::ImageType;
use crate::types::DataType;
#[test]
fn test_image_types() {
assert_eq!(i8::from(ImageType::UnsignedByte), 8);
assert_eq!(i8::from(ImageType::Byte), 10);
assert_eq!(i8::from(ImageType::Short), 16);
assert_eq!(i8::from(ImageType::UnsignedShort), 20);
assert_eq!(i8::from(ImageType::Long), 32);
assert_eq!(i8::from(ImageType::LongLong), 64);
assert_eq!(i8::from(ImageType::Float), -32);
assert_eq!(i8::from(ImageType::Double), -64);
}
#[test]
fn test_hdu_types() {
let image_info = HduInfo::ImageInfo {
shape: Vec::new(),
image_type: ImageType::LongLong,
};
let table_info = HduInfo::TableInfo {
column_descriptions: Vec::new(),
num_rows: 0,
};
assert_eq!(i32::from(image_info), 0);
assert_eq!(i32::from(table_info), 2);
assert_eq!(i32::from(HduInfo::AnyInfo), -1);
}
#[test]
fn test_file_open_modes() {
assert_eq!(u8::from(FileOpenMode::READONLY), 0);
assert_eq!(u8::from(FileOpenMode::READWRITE), 1);
}
#[test]
fn test_case_sensitivity() {
assert_eq!(u8::from(CaseSensitivity::CASESEN), 1);
assert_eq!(u8::from(CaseSensitivity::CASEINSEN), 0);
}
#[test]
fn test_converting_from_data_type() {
assert_eq!(u8::from(DataType::TBIT), 1);
assert_eq!(u8::from(DataType::TBYTE), 11);
assert_eq!(u8::from(DataType::TLOGICAL), 14);
assert_eq!(u8::from(DataType::TSTRING), 16);
assert_eq!(u8::from(DataType::TSHORT), 21);
assert_eq!(u8::from(DataType::TLONG), 41);
assert_eq!(u8::from(DataType::TFLOAT), 42);
assert_eq!(u8::from(DataType::TDOUBLE), 82);
}
}