rustronomy_fits/
fits.rs

1/*
2    Copyright (C) 2022 Raúl Wolters
3
4    This file is part of rustronomy-fits.
5
6    rustronomy is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10
11    rustronomy is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with rustronomy.  If not, see <http://www.gnu.org/licenses/>.
18*/
19
20/*
21    This is the public FITS interface
22*/
23
24use core::fmt;
25use std::{
26  error::Error,
27  fmt::{Display, Formatter},
28  path::Path,
29};
30
31use crate::{
32  header_data_unit::HeaderDataUnit,
33  raw::{
34    raw_io::{RawFitsReader, RawFitsWriter},
35    BlockSized,
36  },
37};
38
39#[derive(Debug, Clone)]
40pub struct Fits {
41  hdus: Vec<HeaderDataUnit>,
42}
43
44impl Fits {
45  pub fn open(path: &Path) -> Result<Self, Box<dyn Error>> {
46    //(1) Construct a RawFitsReader
47    let mut reader = RawFitsReader::new(path)?;
48
49    //(2) Read HDU's from the fits file until it is empty
50    let mut hdus = Vec::new();
51    while reader.get_block_index() < reader.get_block_len() {
52      hdus.push(HeaderDataUnit::decode_hdu(&mut reader)?)
53    }
54
55    //File is empty, we don't need the reader anymore!
56    // (3) return the completed file
57    Ok(Fits { hdus: hdus })
58  }
59
60  pub fn write(self, path: &Path) -> Result<(), Box<dyn Error>> {
61    //(1) Construct a RawFitsWriter
62    let mut writer = RawFitsWriter::new(path)?;
63
64    //(2) Write all HDU's to this thing
65    for hdu in self.hdus {
66      hdu.encode_hdu(&mut writer)?;
67    }
68
69    //(3) Flush writer and close the file
70    writer.flush()?;
71
72    //(R) done
73    Ok(())
74  }
75
76  pub fn get_hdu(&self, index: usize) -> Option<&HeaderDataUnit> {
77    self.hdus.get(index)
78  }
79
80  pub fn remove_hdu(&mut self, index: usize) -> Option<HeaderDataUnit> {
81    if self.hdus.len() < index {
82      return None;
83    }
84    Some(self.hdus.remove(index))
85  }
86}
87
88impl BlockSized for Fits {
89  fn get_block_len(&self) -> usize {
90    (&self.hdus).iter().fold(0, |sum, hdu| sum + hdu.get_block_len())
91  }
92}
93
94impl Display for Fits {
95  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
96    writeln!(
97      f,
98      "\n>=================================<|FITS File|>================================="
99    )?;
100    writeln!(f, ">Total File size in FITS blocks: {}", self.get_block_len())?;
101    writeln!(f, ">Number of Header-Data-Units: {}", self.hdus.len())?;
102    writeln!(f, ">Contents:")?;
103    for (index, hdu) in (&self.hdus).iter().enumerate() {
104      writeln!(f, ">-------------------------------------------------------------------------------\n>  [HDU #{}]", index)?;
105      writeln!(f, ">  Total HDU size in FITS blocks: {}", hdu.get_block_len())?;
106      writeln!(f, ">    {}", hdu.pretty_print_header())?;
107      writeln!(f, ">    {}", hdu.pretty_print_data())?;
108    }
109    writeln!(
110      f,
111      ">===============================================================================\n"
112    )?;
113    Ok(())
114  }
115}