1use crate::header::card::Card;
2use crate::header::table_null_value::TableNullValue;
3
4#[derive(Debug, Clone, PartialEq)]
22pub enum Value {
23 Integer {
25 value: i64,
27 comment: Option<String>,
29 },
30 Float {
32 value: f64,
34 comment: Option<String>,
36 },
37 Logical {
39 value: bool,
41 comment: Option<String>,
43 },
44 String {
46 value: String,
48 comment: Option<String>,
50 },
51 Undefined,
53 Invalid(String),
56}
57
58impl Value {
59 pub fn comment_to_string(&self) -> String {
61 let comment = match self {
62 Value::Integer { comment, .. } => comment,
63 Value::Float { comment, .. } => comment,
64 Value::Logical { comment, .. } => comment,
65 Value::String { comment, .. } => comment,
66 Value::Undefined => &None,
67 Value::Invalid(_) => &None,
68 };
69
70 if let Some(comment) = comment {
71 comment.to_string()
72 } else {
73 "".to_string()
74 }
75 }
76
77 pub fn value_to_string(&self) -> String {
81 match self {
82 Value::Integer { value, .. } => {
83 format!("{}", value)
84 }
85 Value::Float { value, .. } => {
86 format!("{}", value)
87 }
88 Value::Logical { value, .. } => match value {
89 true => "T".to_string(),
90 false => "F".to_string(),
91 },
92 Value::String { value, .. } => value.to_string(),
93 Value::Undefined => "".to_string(),
94 Value::Invalid(_) => "".to_string(),
95 }
96 }
97}
98
99impl From<&Card> for Value {
100 fn from(card: &Card) -> Self {
101 card.clone().into()
102 }
103}
104
105impl From<Card> for Value {
106 fn from(value: Card) -> Self {
107 match value {
108 Card::Author { value, comment } => Value::String { value, comment },
109 Card::Bitpix { value, comment } => Value::Integer {
110 value: value.into(),
111 comment,
112 },
113 Card::Blank { value, comment } => Value::Integer { value, comment },
114 Card::Blocked { value, comment } => Value::Logical { value, comment },
115 Card::BScale { value, comment } => Value::Float { value, comment },
116 Card::BUnit { value, comment } => Value::String { value, comment },
117 Card::BZero { value, comment } => Value::Float { value, comment },
118 Card::CoordinateDeltaN { value, comment, .. } => Value::Float { value, comment },
119 Card::CoordinateRotationN { value, comment, .. } => Value::Float { value, comment },
120 Card::CoordinateReferencePixelN { value, comment, .. } => {
121 Value::Float { value, comment }
122 }
123 Card::CoordinateValueAtPixelN { value, comment, .. } => Value::Float { value, comment },
124 Card::CoordinateAxisNameN { value, comment, .. } => Value::String { value, comment },
125 Card::Comment(_) => Value::Undefined,
126 Card::DataMax { value, comment } => Value::Float { value, comment },
127 Card::DataMin { value, comment } => Value::Float { value, comment },
128 Card::Date { value, comment } => Value::String {
129 value: value.to_rfc3339(),
130 comment,
131 },
132 Card::DateObserved { value, comment } => Value::String {
133 value: value.to_rfc3339(),
134 comment,
135 },
136 Card::End => Value::Undefined,
137 Card::Epoch { value, comment } => Value::Float { value, comment },
138 Card::Equinox { value, comment } => Value::Float { value, comment },
139 Card::Extend { value, comment } => Value::Logical { value, comment },
140 Card::ExtensionLevel { value, comment } => Value::Integer { value, comment },
141 Card::ExtensionName { value, comment } => Value::String { value, comment },
142 Card::ExtensionVersion { value, comment } => Value::Integer { value, comment },
143 Card::GroupCount { value, comment } => Value::Integer { value, comment },
144 Card::Groups { value, comment } => Value::Logical { value, comment },
145 Card::History(_) => Value::Undefined,
146 Card::Instrument { value, comment } => Value::String { value, comment },
147 Card::NAxis { value, comment } => Value::Integer { value, comment },
148 Card::NAxisN { value, comment, .. } => Value::Integer { value, comment },
149 Card::Object { value, comment } => Value::String { value, comment },
150 Card::Observer { value, comment } => Value::String { value, comment },
151 Card::Origin { value, comment } => Value::String { value, comment },
152 Card::ParameterCount { value, comment } => Value::Integer { value, comment },
153 Card::ParameterScalingFactorN { value, comment, .. } => Value::Float { value, comment },
154 Card::ParameterTypeN { value, comment, .. } => Value::String { value, comment },
155 Card::ParameterScalingZeroPointN { value, comment, .. } => {
156 Value::Float { value, comment }
157 }
158 Card::Reference { value, comment } => Value::String { value, comment },
159 Card::Simple { value, comment } => Value::Logical { value, comment },
160 Card::TableColumnN { value, comment, .. } => Value::Integer { value, comment },
161 Card::TableDimensionsN { value, comment, .. } => Value::String { value, comment },
162 Card::TableDisplayFormatN { value, comment, .. } => Value::String { value, comment },
163 Card::Telescope { value, comment } => Value::String { value, comment },
164 Card::TableFields { value, comment } => Value::Integer { value, comment },
165 Card::TableHeap { value, comment } => Value::Integer { value, comment },
166 Card::TableNullValueN { value, comment, .. } => match value {
167 TableNullValue::Integer(value) => Value::Integer { value, comment },
168 TableNullValue::Text(value) => Value::String { value, comment },
169 },
170 Card::TableScalingFactorN { value, comment, .. } => Value::Float { value, comment },
171 Card::TableTypeN { value, comment, .. } => Value::String { value, comment },
172 Card::TableUnitN { value, comment, .. } => Value::String { value, comment },
173 Card::TableScalingZeroPointN { value, comment, .. } => Value::Float { value, comment },
174 Card::Xtension { value, comment } => Value::String {
175 value: value.into(),
176 comment,
177 },
178 Card::FocalLength { value, comment } => Value::Float { value, comment },
179 Card::ExposureTime { value, comment } => Value::Float {
180 value: value.as_secs_f64(),
181 comment,
182 },
183 Card::CCDTemperature { value, comment } => Value::Float { value, comment },
184 Card::BayerPattern { value, comment } => Value::String {
185 value: value.into(),
186 comment,
187 },
188 Card::Value { value, .. } => value,
189 Card::Continuation { string, comment } => match string {
191 Some(value) => Value::String { value, comment },
192 None => Value::Undefined,
193 },
194 Card::Hierarch { value, .. } => value,
195 Card::Space => Value::Undefined,
196 Card::Undefined(_) => Value::Undefined,
197 Card::TableFormatN { value, comment, .. } => Value::String { value, comment },
198 Card::Creator { value, comment } => Value::String { value, comment },
199 Card::SubframeXPositionInBinnedPixels { value, comment } => {
200 Value::Integer { value, comment }
201 }
202 Card::SubframeYPositionInBinnedPixels { value, comment } => {
203 Value::Integer { value, comment }
204 }
205 Card::BinnedPixelsX { value, comment } => Value::Integer { value, comment },
206 Card::BinnedPixelsY { value, comment } => Value::Integer { value, comment },
207 Card::CCDBinnedPixelsX { value, comment } => Value::Integer { value, comment },
208 Card::CCDBinnedPixelsY { value, comment } => Value::Integer { value, comment },
209 Card::PixelSizeXWithBinningInMicrons { value, comment } => {
210 Value::Float { value, comment }
211 }
212 Card::PixelSizeYWithBinningInMicrons { value, comment } => {
213 Value::Float { value, comment }
214 }
215 Card::ImageType { value, comment } => Value::String {
216 value: value.to_string(),
217 comment,
218 },
219 Card::Exposure { value, comment } => Value::Float {
220 value: value.as_secs_f64(),
221 comment,
222 },
223 Card::Ra { value, comment } => Value::Float { value, comment },
224 Card::Dec { value, comment } => Value::Float { value, comment },
225 Card::GuideCam { value, comment } => Value::String { value, comment },
226 Card::FocusPosition { value, comment } => Value::Integer { value, comment },
227 Card::SiteLongitude { value, comment } => Value::Float { value, comment },
228 Card::SiteLatitude { value, comment } => Value::Float { value, comment },
229 Card::ImageWidth { value, comment } => Value::Integer { value, comment },
230 Card::ImageHeight { value, comment } => Value::Integer { value, comment },
231 }
232 }
233}
234
235impl Value {
237 #[must_use]
243 pub fn with_comment(self, comment: impl Into<String>) -> Self {
244 let comment = Some(comment.into());
245 match self {
246 Value::Integer { value, .. } => Value::Integer { value, comment },
247 Value::Float { value, .. } => Value::Float { value, comment },
248 Value::Logical { value, .. } => Value::Logical { value, comment },
249 Value::String { value, .. } => Value::String { value, comment },
250 other => other,
251 }
252 }
253}
254
255impl From<i64> for Value {
256 fn from(value: i64) -> Self {
257 Value::Integer {
258 value,
259 comment: None,
260 }
261 }
262}
263
264impl From<i32> for Value {
265 fn from(value: i32) -> Self {
266 Value::from(i64::from(value))
267 }
268}
269
270impl From<u32> for Value {
271 fn from(value: u32) -> Self {
272 Value::from(i64::from(value))
273 }
274}
275
276impl From<usize> for Value {
277 fn from(value: usize) -> Self {
278 Value::from(i64::try_from(value).unwrap_or(i64::MAX))
281 }
282}
283
284impl From<f64> for Value {
285 fn from(value: f64) -> Self {
286 Value::Float {
287 value,
288 comment: None,
289 }
290 }
291}
292
293impl From<f32> for Value {
294 fn from(value: f32) -> Self {
295 Value::from(f64::from(value))
296 }
297}
298
299impl From<bool> for Value {
300 fn from(value: bool) -> Self {
301 Value::Logical {
302 value,
303 comment: None,
304 }
305 }
306}
307
308impl From<String> for Value {
309 fn from(value: String) -> Self {
310 Value::String {
311 value,
312 comment: None,
313 }
314 }
315}
316
317impl From<&str> for Value {
318 fn from(value: &str) -> Self {
319 Value::from(value.to_string())
320 }
321}
322
323impl From<&String> for Value {
324 fn from(value: &String) -> Self {
325 Value::from(value.clone())
326 }
327}
328
329impl<T: Into<Value>> From<Option<T>> for Value {
332 fn from(value: Option<T>) -> Self {
333 match value {
334 Some(value) => value.into(),
335 None => Value::Undefined,
336 }
337 }
338}