astro_rs/fits/header_value/
tform.rs1use crate::fits::hdu_macros::return_box;
4use crate::fits::FitsHeaderError;
5
6use super::FitsHeaderValue;
7
8#[allow(missing_docs)]
10#[derive(Debug, Clone, Copy)]
11pub enum TFormType {
12 Logical,
13 Bit,
14 UnsignedByte,
15 I16,
16 I32,
17 Character,
18 F32,
19 F64,
20 C64,
21 C128,
22 ArrayDescriptor,
23}
24
25impl TryFrom<char> for TFormType {
26 type Error = FitsHeaderError;
27
28 fn try_from(value: char) -> Result<Self, Self::Error> {
29 match value {
30 'L' => Ok(TFormType::Logical),
31 'X' => Ok(TFormType::Bit),
32 'B' => Ok(TFormType::UnsignedByte),
33 'I' => Ok(TFormType::I16),
34 'J' => Ok(TFormType::I32),
35 'A' => Ok(TFormType::Character),
36 'E' => Ok(TFormType::F32),
37 'D' => Ok(TFormType::F64),
38 'C' => Ok(TFormType::C64),
39 'M' => Ok(TFormType::C128),
40 'P' => Ok(TFormType::ArrayDescriptor),
41 _ => Err(FitsHeaderError::DeserializationError {
42 found: vec![value as u8],
43 intent: String::from("header card TFORM type value"),
44 }),
45 }
46 }
47}
48
49#[derive(Debug, Clone)]
51pub struct TForm {
52 pub r: usize,
54 pub t: TFormType,
56 pub a: String,
58}
59
60impl TForm {
61 pub fn value(&self) -> usize {
63 let type_bytes = match self.t {
64 TFormType::Logical => 1,
65 TFormType::Bit => todo!(),
66 TFormType::UnsignedByte => 1,
67 TFormType::I16 => 2,
68 TFormType::I32 => 4,
69 TFormType::Character => 1,
70 TFormType::F32 => 4,
71 TFormType::F64 => 8,
72 TFormType::C64 => 8,
73 TFormType::C128 => 16,
74 TFormType::ArrayDescriptor => 8,
75 };
76 self.r * type_bytes
77 }
78
79 pub fn create_column<T>(
81 &self,
82 data: &[u8],
83 column_start: usize,
84 row_len: usize,
85 num_rows: usize,
86 ) -> Box<Vec<T>> {
87 let column_len = self.value();
88 unsafe {
89 match self.t {
90 TFormType::Logical => {
91 let mut result = Vec::with_capacity(num_rows * self.r);
92 for i in 0..num_rows {
93 let start = row_len * i + column_start;
94 let column = data[start..start + column_len].to_vec();
95 for value in column.iter().take(self.r) {
96 result.push(*value != 0);
97 }
98 }
99
100 return_box!(result)
101 }
102 TFormType::Bit => todo!(),
103 TFormType::UnsignedByte => {
104 let mut result = Vec::with_capacity(num_rows * self.r);
105 for i in 0..num_rows {
106 let start = row_len * i + column_start;
107 let mut column = data[start..start + column_len].to_vec();
108 result.append(&mut column);
109 }
110
111 return_box!(result)
112 }
113 TFormType::I16 => {
114 tform_macros::deserialize_column!(
115 i16,
116 num_rows,
117 row_len,
118 column_start,
119 column_len,
120 self.r,
121 data,
122 )
123 }
124 TFormType::I32 => {
125 tform_macros::deserialize_column!(
126 i32,
127 num_rows,
128 row_len,
129 column_start,
130 column_len,
131 self.r,
132 data,
133 )
134 }
135 TFormType::Character => {
136 unsafe fn deserialize_char(value: [u8; 4]) -> char {
137 char::from_u32_unchecked(u32::from_be_bytes(value))
138 }
139 tform_macros::deserialize_column!(
140 char,
141 num_rows,
142 row_len,
143 column_start,
144 column_len,
145 self.r,
146 data,
147 deserialize_char,
148 )
149 }
150 TFormType::F32 => {
151 tform_macros::deserialize_column!(
152 f32,
153 num_rows,
154 row_len,
155 column_start,
156 column_len,
157 self.r,
158 data,
159 )
160 }
161 TFormType::F64 => {
162 tform_macros::deserialize_column!(
163 f64,
164 num_rows,
165 row_len,
166 column_start,
167 column_len,
168 self.r,
169 data,
170 )
171 }
172 TFormType::C64 => todo!(),
173 TFormType::C128 => todo!(),
174 TFormType::ArrayDescriptor => todo!(),
175 }
176 }
177 }
178}
179
180#[macro_use]
181mod tform_macros {
182 macro_rules! deserialize_column {
184 (@dfn $value_type: ty) => {{
185 <$value_type>::from_be_bytes
186 }};
187 ($value_type: ty, $num_rows: expr, $row_len: expr, $column_start: expr, $column_len: expr, $repeats: expr, $data: expr,) => {{
188 let deserialize_fn = $crate::fits::header_value::tform::tform_macros::deserialize_column!(@dfn $value_type);
189 $crate::fits::header_value::tform::tform_macros::deserialize_column!(
190 $value_type,
191 $num_rows,
192 $row_len,
193 $column_start,
194 $column_len,
195 $repeats,
196 $data,
197 deserialize_fn,
198 )
199 }};
200 ($value_type: ty, $num_rows: expr, $row_len: expr, $column_start: expr, $column_len: expr, $repeats: expr, $data: expr, $deserialize_fn: tt,) => {{
201 let mut result = Vec::with_capacity($num_rows * $repeats);
202 for i in 0..$num_rows {
203 let start = $row_len * i + $column_start;
204 let column = $data[start..start + $column_len].to_vec();
205 let value_size = std::mem::size_of::<$value_type>();
206 for repeat in 0..$repeats {
207 let value_start = repeat * value_size;
208 let raw_value = column[value_start..value_start + value_size]
209 .try_into()
210 .unwrap();
211 result.push($deserialize_fn(raw_value));
212 }
213 }
214
215 $crate::fits::hdu_macros::return_box!(result)
216 }};
217 }
218
219 pub(crate) use deserialize_column;
220}
221
222impl FitsHeaderValue for TForm {
249 fn from_bytes(raw: Vec<u8>) -> Result<Self, FitsHeaderError> {
250 let mut repeats = String::new();
251 let mut ttype = None;
252 let mut i = 1;
253 while i < raw.len() - 1 {
254 let ch = raw[i] as char;
255 if ch.is_ascii_digit() {
256 repeats.push(ch);
257 i += 1;
258 } else {
259 ttype = Some(TFormType::try_from(ch)?);
260 i += 1;
261 break;
262 }
263 }
264 let r = repeats.parse::<u32>().unwrap_or(1) as usize;
265 if let Some(t) = ttype {
266 if let Ok(a) = String::from_utf8(raw[i..raw.len() - 1].to_vec()) {
267 return Ok(TForm {
268 r,
269 t,
270 a: a.trim_end().to_owned(),
271 });
272 }
273 }
274 Err(FitsHeaderError::DeserializationError {
275 found: raw,
276 intent: String::from("header card TFORM value"),
277 })
278 }
279
280 fn to_bytes(&self) -> [u8; 70] {
281 let mut result = [b' '; 70];
282 let mut i = 0;
283 result[i] = b'\'';
284 i += 1;
285 let repeats = self.r.to_string();
286 for b in repeats.bytes() {
287 result[i] = b;
288 i += 1;
289 }
290 match self.t {
291 TFormType::Logical => result[i] = b'L',
292 TFormType::Bit => result[i] = b'X',
293 TFormType::UnsignedByte => result[i] = b'B',
294 TFormType::I16 => result[i] = b'I',
295 TFormType::I32 => result[i] = b'J',
296 TFormType::Character => result[i] = b'A',
297 TFormType::F32 => result[i] = b'E',
298 TFormType::F64 => result[i] = b'D',
299 TFormType::C64 => result[i] = b'C',
300 TFormType::C128 => result[i] = b'M',
301 TFormType::ArrayDescriptor => result[i] = b'P',
302 }
303 i += 1;
304 for b in self.a.bytes() {
305 result[i] = b;
306 i += 1;
307 }
308 if i < 9 {
309 i = 9;
310 }
311 result[i] = b'\'';
312 result
313 }
314}