use std::{
io::{BufRead, Cursor, Write},
marker::PhantomData,
ops::Range,
};
use byteorder::BigEndian;
use log::warn;
use crate::{
deser::fits::{
common::{
check_keyword_and_parse_uint_val, check_keyword_and_val, consume_primary_hdu,
next_36_chunks_of_80_bytes, write_primary_hdu, write_uint_mandatory_keyword_record,
},
error::FitsError,
keywords::{
CoordSys, FitsCard, MocDim, MocId, MocKeywords, MocKeywordsMap, MocOrdF, MocOrdS, MocOrdT,
MocOrder, MocTool, MocVers, Ordering, TForm1, TType1, TimeSys,
},
},
elem::cell::Cell,
elemset::{
cell::{Cells, MocCells},
range::MocRanges,
},
idx::Idx,
moc::{
cell::CellMOC,
range::{op::convert::convert_to_u64, RangeMOC, RangeMocIter},
CellMOCIntoIterator, CellMOCIterator, HasMaxDepth, MOCProperties, NonOverlapping,
RangeMOCIterator, ZSorted,
},
moc2d::{
range::{RangeMOC2, RangeMOC2Elem},
HasTwoMaxDepth, MOC2Properties, RangeMOC2ElemIt, RangeMOC2IntoIterator, RangeMOC2Iterator,
},
qty::{Frequency, Hpx, MocQty, MocableQty, Time},
};
pub mod common;
pub mod error;
pub mod keywords;
pub mod multiordermap;
pub mod skymap;
#[derive(Debug)]
pub enum MocIdxType<R: BufRead> {
U16(MocQtyType<u16, R>),
U32(MocQtyType<u32, R>),
U64(MocQtyType<u64, R>),
}
impl<R: BufRead> MocIdxType<R> {
pub fn to_fits_ivoa<W: Write>(self, write: W) -> Result<(), FitsError> {
match self {
MocIdxType::U16(moc_qty_type) => moc_qty_type.to_fits_ivoa(write),
MocIdxType::U32(moc_qty_type) => moc_qty_type.to_fits_ivoa(write),
MocIdxType::U64(moc_qty_type) => moc_qty_type.to_fits_ivoa(write),
}
}
}
#[derive(Debug)]
pub enum MocQtyType<T: Idx, R: BufRead> {
Hpx(MocType<T, Hpx<T>, R>),
Time(MocType<T, Time<T>, R>),
TimeHpx(STMocType<T, R>),
FreqHpx(RangeMoc2DIterFromFits<T, R, Frequency<T>, Hpx<T>>),
Freq(MocType<T, Frequency<T>, R>),
}
impl<T: Idx, R: BufRead> MocQtyType<T, R> {
pub fn to_fits_ivoa<W: Write>(self, write: W) -> Result<(), FitsError> {
match self {
MocQtyType::Hpx(moc_type) => moc_type.to_fits_ivoa(write),
MocQtyType::Time(moc_type) => moc_type.to_fits_ivoa(write),
MocQtyType::TimeHpx(moc_type) => moc_type.to_fits_ivoa(write),
MocQtyType::FreqHpx(moc2d) => ranges_sf_to_fits_ivoa(moc2d, None, None, write),
MocQtyType::Freq(moc_type) => moc_type.to_fits_ivoa(write),
}
}
}
#[derive(Debug)]
pub enum MocType<T: Idx, Q: MocQty<T>, R: BufRead> {
Ranges(RangeMocIterFromFits<T, Q, R>),
Cells(CellMOC<T, Q>),
}
impl<T: Idx, Q: MocQty<T>, R: BufRead> MocType<T, Q, R> {
pub fn to_fits_ivoa<W: Write>(self, write: W) -> Result<(), FitsError> {
match self {
MocType::Ranges(ranges) => ranges_to_fits_ivoa(ranges, None, None, write),
MocType::Cells(cells) => {
ranges_to_fits_ivoa(cells.into_cell_moc_iter().ranges(), None, None, write)
}
}
}
pub fn collect(self) -> RangeMOC<T, Q> {
match self {
MocType::Ranges(ranges) => ranges.into_range_moc(),
MocType::Cells(cells) => cells.into_cell_moc_iter().ranges().into_range_moc(),
}
}
pub fn collect_to_u64<P: MocQty<u64>>(self) -> RangeMOC<u64, P> {
match self {
MocType::Ranges(ranges) => convert_to_u64::<T, Q, _, P>(ranges).into_range_moc(),
MocType::Cells(cells) => {
convert_to_u64::<T, Q, _, P>(cells.into_cell_moc_iter().ranges()).into_range_moc()
}
}
}
}
#[derive(Debug)]
pub enum STMocType<T: Idx, R: BufRead> {
V2(RangeMoc2DIterFromFits<T, R, Time<T>, Hpx<T>>),
PreV2(RangeMoc2DPreV2IterFromFits<T, R>),
}
impl<T: Idx, R: BufRead> STMocType<T, R> {
pub fn to_fits_ivoa<W: Write>(self, write: W) -> Result<(), FitsError> {
match self {
STMocType::V2(ranges2) => ranges_st_to_fits_ivoa(ranges2, None, None, write),
STMocType::PreV2(ranges2) => ranges_st_to_fits_ivoa(ranges2, None, None, write),
}
}
}
pub fn hpx_cells_to_fits_ivoa<T, I, W>(
moc_it: I,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
mut writer: W,
) -> Result<(), FitsError>
where
T: Idx,
I: CellMOCIterator<T, Qty = Hpx<T>>,
W: Write,
{
let depth_max = moc_it.depth_max();
let moc_kw_map = build_hpx_uniq_moc_keywords(depth_max, moc_id, moc_type, PhantomData::<T>);
let mut buffers: Vec<Cursor<Vec<u8>>> = Vec::with_capacity((depth_max + 1) as usize);
let n_cells_guess = moc_it.size_hint().0.max(10_000);
for d in 0..=depth_max {
let size_guess = (n_cells_guess / 4_usize.pow((depth_max - d) as u32)).max(100);
buffers.push(Cursor::new(Vec::with_capacity(size_guess)));
}
let mut n_cells = 0_u64;
for e in moc_it {
let d = e.depth;
if d > depth_max {
return Err(FitsError::UnexpectedDepth(d, depth_max));
}
e.uniq_hpx()
.write::<_, BigEndian>(&mut buffers[d as usize])?;
n_cells += 1;
}
write_fits_header(&mut writer, T::N_BYTES, n_cells, moc_kw_map)?;
let mut len = 0;
for buf in &mut buffers {
let buf_ref = buf.get_ref();
len += buf_ref.len();
writer.write_all(buf_ref)?;
}
let mod2880 = len % 2880;
if mod2880 != 0 {
writer.write_all(&vec![0_u8; 2880 - mod2880])?;
}
Ok(())
}
fn build_hpx_uniq_moc_keywords<T: Idx>(
depth_max: u8,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
_t_type: PhantomData<T>,
) -> MocKeywordsMap {
let mut moc_kws = MocKeywordsMap::new();
moc_kws.insert(MocKeywords::MOCVers(MocVers::V2_0));
moc_kws.insert(MocKeywords::MOCDim(Hpx::<T>::MOC_DIM));
moc_kws.insert(MocKeywords::Ordering(Ordering::Nuniq));
moc_kws.insert(MocKeywords::CoordSys(CoordSys::ICRS));
moc_kws.insert(MocKeywords::MOCOrdS(MocOrdS { depth: depth_max }));
moc_kws.insert(MocKeywords::MOCOrder(MocOrder { depth: depth_max })); if let Some(id) = moc_id {
moc_kws.insert(MocKeywords::MOCId(MocId { id }));
}
moc_kws.insert(MocKeywords::MOCTool(MocTool {
tool: String::from("CDS MOC Rust lib"),
}));
if let Some(mtype) = moc_type {
moc_kws.insert(MocKeywords::MOCType(mtype));
}
moc_kws.insert(MocKeywords::TForm1(T::TFORM));
moc_kws.insert(MocKeywords::TType1(TType1 {
ttype: String::from("UNIQ"),
}));
moc_kws
}
fn write_fits_header<R: Write>(
mut writer: R,
naxis1_n_bytes: u8,
naxis2_n_elems: u64,
moc_kw_map: MocKeywordsMap,
) -> Result<(), FitsError> {
write_primary_hdu(&mut writer)?;
let mut header_block = [b' '; 2880];
let mut it = header_block.chunks_mut(80);
it.next().unwrap()[0..20].copy_from_slice(b"XTENSION= 'BINTABLE'");
it.next().unwrap()[0..30].copy_from_slice(b"BITPIX = 8");
it.next().unwrap()[0..30].copy_from_slice(b"NAXIS = 2");
write_uint_mandatory_keyword_record(it.next().unwrap(), b"NAXIS1 ", naxis1_n_bytes as u64);
write_uint_mandatory_keyword_record(it.next().unwrap(), b"NAXIS2 ", naxis2_n_elems);
it.next().unwrap()[0..30].copy_from_slice(b"PCOUNT = 0");
it.next().unwrap()[0..30].copy_from_slice(b"GCOUNT = 1");
it.next().unwrap()[0..30].copy_from_slice(b"TFIELDS = 1");
moc_kw_map.write_all(&mut it)?;
it.next().unwrap()[0..3].copy_from_slice(b"END");
writer.write_all(&header_block[..])?;
Ok(())
}
pub fn ranges_to_fits_ivoa<T, Q, I, W>(
moc_it: I,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
writer: W,
) -> Result<(), FitsError>
where
T: Idx,
Q: MocQty<T>,
I: RangeMOCIterator<T, Qty = Q>,
W: Write,
{
let depth_max = moc_it.depth_max();
let moc_kw_map = build_range_moc_keywords(
depth_max,
moc_id,
moc_type,
PhantomData::<T>,
PhantomData::<Q>,
);
match moc_it.size_hint() {
(len_min, Some(len_max)) if len_min == len_max => {
ranges_to_fits_ivoa_internal(len_max, moc_it, moc_kw_map, writer)
}
_ => {
let ranges: Vec<Range<T>> = moc_it.collect();
ranges_to_fits_ivoa_internal(ranges.len(), ranges.into_iter(), moc_kw_map, writer)
}
}
}
fn build_range_moc_keywords<T: Idx, Q: MocQty<T>>(
depth_max: u8,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
_t_type: PhantomData<T>,
_q_type: PhantomData<Q>,
) -> MocKeywordsMap {
let mut moc_kws = MocKeywordsMap::new();
moc_kws.insert(MocKeywords::MOCVers(MocVers::V2_0));
moc_kws.insert(MocKeywords::MOCDim(Q::MOC_DIM));
moc_kws.insert(MocKeywords::Ordering(Ordering::Range));
if Q::HAS_COOSYS {
moc_kws.insert(MocKeywords::CoordSys(CoordSys::ICRS));
moc_kws.insert(MocKeywords::MOCOrdS(MocOrdS { depth: depth_max }));
}
if Q::HAS_TIMESYS {
moc_kws.insert(MocKeywords::TimeSys(TimeSys::TCB));
moc_kws.insert(MocKeywords::MOCOrdT(MocOrdT { depth: depth_max }));
}
if Q::HAS_FREQSYS {
moc_kws.insert(MocKeywords::MOCOrdF(MocOrdF { depth: depth_max }));
}
if let Some(id) = moc_id {
moc_kws.insert(MocKeywords::MOCId(MocId { id }));
}
moc_kws.insert(MocKeywords::MOCTool(MocTool {
tool: String::from("CDS MOC Rust lib"),
}));
if let Some(mtype) = moc_type {
moc_kws.insert(MocKeywords::MOCType(mtype));
}
moc_kws.insert(MocKeywords::TForm1(T::TFORM));
moc_kws.insert(MocKeywords::TType1(TType1 {
ttype: String::from("RANGE"),
}));
moc_kws
}
fn ranges_to_fits_ivoa_internal<T, I, W>(
n_ranges: usize,
mut range_it: I,
moc_kw_map: MocKeywordsMap,
mut writer: W,
) -> Result<(), FitsError>
where
T: Idx,
I: Iterator<Item = Range<T>>,
W: Write,
{
write_fits_header(&mut writer, T::N_BYTES, (n_ranges as u64) << 1, moc_kw_map)?;
for _ in 0..n_ranges {
if let Some(Range { start, end }) = range_it.next() {
start.write::<_, BigEndian>(&mut writer)?;
end.write::<_, BigEndian>(&mut writer)?;
} else {
return Err(FitsError::PrematureEndOfData);
}
}
let mod2880 = ((n_ranges << 1) * T::N_BYTES as usize) % 2880;
if mod2880 != 0 {
writer.write_all(&vec![0_u8; 2880 - mod2880])?;
}
if range_it.next().is_some() {
Err(FitsError::RemainingData)
} else {
Ok(())
}
}
pub fn range_stmoc_to_fits_ivoa<T: Idx, W: Write>(
moc: &RangeMOC2<T, Time<T>, T, Hpx<T>>,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
mut writer: W,
) -> Result<(), FitsError> {
let depth_max_time = moc.depth_max_1();
let depth_max_hpx = moc.depth_max_2();
let n_ranges = moc.compute_n_ranges();
let moc_kw_map = build_range_stmoc_keywords(
depth_max_time,
depth_max_hpx,
moc_id,
moc_type,
PhantomData::<T>,
);
write_fits_header(&mut writer, T::N_BYTES, n_ranges << 1, moc_kw_map)?;
let n_ranges_written = write_ranges2d_data(moc.into_range_moc2_iter(), writer)?;
if n_ranges != n_ranges_written as u64 {
Err(FitsError::UnexpectedWrittenSize)
} else {
Ok(())
}
}
pub fn range_sfmoc_to_fits_ivoa<T: Idx, W: Write>(
moc: &RangeMOC2<T, Frequency<T>, T, Hpx<T>>,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
mut writer: W,
) -> Result<(), FitsError> {
let depth_max_freq = moc.depth_max_1();
let depth_max_hpx = moc.depth_max_2();
let n_ranges = moc.compute_n_ranges();
let moc_kw_map = build_range_sfmoc_keywords(
depth_max_freq,
depth_max_hpx,
moc_id,
moc_type,
PhantomData::<T>,
);
write_fits_header(&mut writer, T::N_BYTES, n_ranges << 1, moc_kw_map)?;
let n_ranges_written = write_ranges2d_data(moc.into_range_moc2_iter(), writer)?;
if n_ranges != n_ranges_written as u64 {
Err(FitsError::UnexpectedWrittenSize)
} else {
Ok(())
}
}
pub fn ranges_st_to_fits_ivoa<T, I, J, K, L, W>(
moc_it: L,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
mut writer: W,
) -> Result<(), FitsError>
where
T: Idx,
I: RangeMOCIterator<T, Qty = Time<T>>,
J: RangeMOCIterator<T, Qty = Hpx<T>>,
K: RangeMOC2ElemIt<T, I::Qty, T, J::Qty, It1 = I, It2 = J>,
L: RangeMOC2Iterator<T, I::Qty, I, T, J::Qty, J, K>,
W: Write,
{
let depth_max_time = moc_it.depth_max_1();
let depth_max_hpx = moc_it.depth_max_2();
let moc_kw_map = build_range_stmoc_keywords(
depth_max_time,
depth_max_hpx,
moc_id,
moc_type,
PhantomData::<T>,
);
let mut mem_writter: Vec<u8> = Vec::with_capacity(1024); let n_ranges_written = write_ranges2d_data(moc_it, &mut mem_writter)?;
write_fits_header(
&mut writer,
T::N_BYTES,
(n_ranges_written as u64) << 1,
moc_kw_map,
)?;
writer.write_all(&mem_writter)?;
Ok(())
}
pub fn ranges_sf_to_fits_ivoa<T, I, J, K, L, W>(
moc_it: L,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
mut writer: W,
) -> Result<(), FitsError>
where
T: Idx,
I: RangeMOCIterator<T, Qty = Frequency<T>>,
J: RangeMOCIterator<T, Qty = Hpx<T>>,
K: RangeMOC2ElemIt<T, I::Qty, T, J::Qty, It1 = I, It2 = J>,
L: RangeMOC2Iterator<T, I::Qty, I, T, J::Qty, J, K>,
W: Write,
{
let depth_max_freq = moc_it.depth_max_1();
let depth_max_hpx = moc_it.depth_max_2();
let moc_kw_map = build_range_sfmoc_keywords(
depth_max_freq,
depth_max_hpx,
moc_id,
moc_type,
PhantomData::<T>,
);
let mut mem_writter: Vec<u8> = Vec::with_capacity(1024); let n_ranges_written = write_ranges2d_data(moc_it, &mut mem_writter)?;
write_fits_header(
&mut writer,
T::N_BYTES,
(n_ranges_written as u64) << 1,
moc_kw_map,
)?;
writer.write_all(&mem_writter)?;
Ok(())
}
fn write_ranges2d_data<T, I, J, K, L, W>(moc2_it: L, mut writer: W) -> Result<usize, FitsError>
where
T: Idx,
I: RangeMOCIterator<T>,
J: RangeMOCIterator<T>,
K: RangeMOC2ElemIt<T, I::Qty, T, J::Qty, It1 = I, It2 = J>,
L: RangeMOC2Iterator<T, I::Qty, I, T, J::Qty, J, K>,
W: Write,
{
let mut n_ranges_written = 0_usize;
for e in moc2_it {
let (moc1_it, moc2_it) = e.range_mocs_it();
for Range { start, end } in moc1_it {
(start | T::MSB_MASK).write::<_, BigEndian>(&mut writer)?;
(end | T::MSB_MASK).write::<_, BigEndian>(&mut writer)?;
n_ranges_written += 1;
}
for Range { start, end } in moc2_it {
(start).write::<_, BigEndian>(&mut writer)?;
(end).write::<_, BigEndian>(&mut writer)?;
n_ranges_written += 1;
}
}
let mod2880 = ((n_ranges_written << 1) * T::N_BYTES as usize) % 2880;
if mod2880 != 0 {
writer.write_all(&vec![0_u8; 2880 - mod2880])?;
}
Ok(n_ranges_written)
}
fn build_range_stmoc_keywords<T: Idx>(
depth_max_time: u8,
depth_max_hpx: u8,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
_t_type: PhantomData<T>,
) -> MocKeywordsMap {
let mut moc_kws = MocKeywordsMap::new();
moc_kws.insert(MocKeywords::MOCVers(MocVers::V2_0));
moc_kws.insert(MocKeywords::MOCDim(MocDim::TimeSpace)); moc_kws.insert(MocKeywords::Ordering(Ordering::Range));
moc_kws.insert(MocKeywords::CoordSys(CoordSys::ICRS));
moc_kws.insert(MocKeywords::MOCOrdS(MocOrdS {
depth: depth_max_hpx,
}));
moc_kws.insert(MocKeywords::TimeSys(TimeSys::TCB));
moc_kws.insert(MocKeywords::MOCOrdT(MocOrdT {
depth: depth_max_time,
}));
if let Some(id) = moc_id {
moc_kws.insert(MocKeywords::MOCId(MocId { id }));
}
moc_kws.insert(MocKeywords::MOCTool(MocTool {
tool: String::from("CDS MOC Rust lib"),
}));
if let Some(mtype) = moc_type {
moc_kws.insert(MocKeywords::MOCType(mtype));
}
moc_kws.insert(MocKeywords::TForm1(T::TFORM));
moc_kws
}
fn build_range_sfmoc_keywords<T: Idx>(
depth_max_freq: u8,
depth_max_hpx: u8,
moc_id: Option<String>,
moc_type: Option<keywords::MocType>,
_t_type: PhantomData<T>,
) -> MocKeywordsMap {
let mut moc_kws = MocKeywordsMap::new();
moc_kws.insert(MocKeywords::MOCVers(MocVers::V2_0));
moc_kws.insert(MocKeywords::MOCDim(MocDim::FrequencySpace)); moc_kws.insert(MocKeywords::Ordering(Ordering::Range));
moc_kws.insert(MocKeywords::CoordSys(CoordSys::ICRS));
moc_kws.insert(MocKeywords::MOCOrdS(MocOrdS {
depth: depth_max_hpx,
}));
moc_kws.insert(MocKeywords::MOCOrdF(MocOrdF {
depth: depth_max_freq,
}));
if let Some(id) = moc_id {
moc_kws.insert(MocKeywords::MOCId(MocId { id }));
}
moc_kws.insert(MocKeywords::MOCTool(MocTool {
tool: String::from("CDS MOC Rust lib"),
}));
if let Some(mtype) = moc_type {
moc_kws.insert(MocKeywords::MOCType(mtype));
}
moc_kws.insert(MocKeywords::TForm1(T::TFORM));
moc_kws
}
pub fn from_fits_ivoa<R: BufRead>(reader: R) -> Result<MocIdxType<R>, FitsError> {
from_fits_ivoa_custom(reader, false)
}
pub fn from_fits_ivoa_custom<R: BufRead>(
mut reader: R,
coosys_permissive: bool,
) -> Result<MocIdxType<R>, FitsError> {
let mut header_block = [b' '; 2880];
consume_primary_hdu(&mut reader, &mut header_block)?;
let mut it80 = next_36_chunks_of_80_bytes(&mut reader, &mut header_block)?;
check_keyword_and_val(it80.next().unwrap(), b"XTENSION", b"'BINTABLE'")?;
check_keyword_and_val(it80.next().unwrap(), b"BITPIX ", b"8")?;
check_keyword_and_val(it80.next().unwrap(), b"NAXIS ", b"2")?;
let n_bytes = check_keyword_and_parse_uint_val::<u8>(it80.next().unwrap(), b"NAXIS1 ")?;
let n_elems = check_keyword_and_parse_uint_val::<u64>(it80.next().unwrap(), b"NAXIS2 ")?;
check_keyword_and_val(it80.next().unwrap(), b"PCOUNT ", b"0")?;
check_keyword_and_val(it80.next().unwrap(), b"GCOUNT ", b"1")?;
check_keyword_and_val(it80.next().unwrap(), b"TFIELDS ", b"1")?;
let mut moc_kws = MocKeywordsMap::new();
'hr: loop {
for kw_record in &mut it80 {
if let Some(mkw) = MocKeywords::is_moc_kw(kw_record) {
if mkw.is_err() && common::get_keyword(kw_record) == b"COORDSYS" && coosys_permissive {
continue;
}
if let Some(previous_mkw) = moc_kws.insert(mkw?) {
warn!(
"Keyword '{}' found more than once in a same HDU! We use the first occurrence.",
previous_mkw.keyword_str()
);
moc_kws.insert(previous_mkw);
}
} else if &kw_record[0..4] == b"END " {
break 'hr;
}
}
it80 = next_36_chunks_of_80_bytes(&mut reader, &mut header_block)?;
}
match moc_kws.get::<MocVers>() {
Some(MocKeywords::MOCVers(MocVers::V2_0)) | Some(MocKeywords::MOCVers(MocVers::V2_1)) => {
match moc_kws.get::<MocDim>() {
Some(MocKeywords::MOCDim(MocDim::Space)) => {
let depth_max = match moc_kws.get::<MocOrdS>() {
Some(MocKeywords::MOCOrdS(MocOrdS { depth })) => *depth,
_ => match moc_kws.get::<MocOrder>() {
Some(MocKeywords::MOCOrder(MocOrder { depth })) => {
warn!("Keyword 'MOCORDER' deprecated in version 2.0. Use 'MOCORD_S' instead.");
*depth
}
_ => return Err(FitsError::MissingKeyword(MocOrdS::keyword_string())),
},
};
moc_kws.check_coordsys()?;
match moc_kws.get::<Ordering>() {
Some(MocKeywords::Ordering(Ordering::Nuniq)) => {
load_s_moc_nuniq(reader, n_bytes, n_elems, depth_max, &moc_kws)
}
Some(MocKeywords::Ordering(Ordering::Range)) => {
load_s_moc_range(reader, n_bytes, n_elems, depth_max, &moc_kws)
}
Some(MocKeywords::Ordering(Ordering::Range29)) => {
Err(FitsError::UncompatibleKeywordContent(
String::from("ORDERING = 'RABGE29'"),
String::from("MOCVERS= '2.x'"),
))
}
_ => Err(FitsError::MissingKeyword(Ordering::keyword_string())),
}
}
Some(MocKeywords::MOCDim(MocDim::Time)) => {
let depth_max = match moc_kws.get::<MocOrdT>() {
Some(MocKeywords::MOCOrdT(MocOrdT { depth })) => *depth,
_ => return Err(FitsError::MissingKeyword(MocOrder::keyword_string())),
};
match moc_kws.get::<Ordering>() {
Some(MocKeywords::Ordering(Ordering::Nuniq)) => {
Err(FitsError::UncompatibleKeywordContent(
String::from("MOCDIM = 'TIME'"),
String::from("ORDERING= 'NUNIQ'"),
))
}
Some(MocKeywords::Ordering(Ordering::Range)) => {
load_t_moc_range(reader, n_bytes, n_elems, depth_max, &moc_kws)
}
Some(MocKeywords::Ordering(Ordering::Range29)) => {
Err(FitsError::UncompatibleKeywordContent(
String::from("ORDERING = 'RANGE29'"),
String::from("MOCVERS= '2.x'"),
))
}
_ => Err(FitsError::MissingKeyword(Ordering::keyword_string())),
}
}
Some(MocKeywords::MOCDim(MocDim::TimeSpace)) => {
let depth_max_time = match moc_kws.get::<MocOrdT>() {
Some(MocKeywords::MOCOrdT(MocOrdT { depth })) => *depth,
_ => return Err(FitsError::MissingKeyword(MocOrdT::keyword_string())),
};
let depth_max_hpx = match moc_kws.get::<MocOrdS>() {
Some(MocKeywords::MOCOrdS(MocOrdS { depth })) => *depth,
_ => return Err(FitsError::MissingKeyword(MocOrdS::keyword_string())),
};
match moc_kws.get::<Ordering>() {
Some(MocKeywords::Ordering(Ordering::Nuniq)) => {
Err(FitsError::UncompatibleKeywordContent(
String::from("MOCDIM = 'TIME.SPACE'"),
String::from("ORDERING= 'NUNIQ'"),
))
}
Some(MocKeywords::Ordering(Ordering::Range)) => load_st_moc_range(
reader,
n_bytes,
n_elems,
depth_max_time,
depth_max_hpx,
&moc_kws,
),
Some(MocKeywords::Ordering(Ordering::Range29)) => {
Err(FitsError::UncompatibleKeywordContent(
String::from("ORDERING = 'RANGE29'"),
String::from("MOCVERS= '2.x'"),
))
}
_ => Err(FitsError::MissingKeyword(Ordering::keyword_string())),
}
}
Some(MocKeywords::MOCDim(MocDim::Frequency)) => {
let depth_max = match moc_kws.get::<MocOrdF>() {
Some(MocKeywords::MOCOrdF(MocOrdF { depth })) => *depth,
_ => return Err(FitsError::MissingKeyword(MocOrder::keyword_string())),
};
match moc_kws.get::<Ordering>() {
Some(MocKeywords::Ordering(Ordering::Nuniq)) => {
Err(FitsError::UncompatibleKeywordContent(
String::from("MOCDIM = 'FREQUENCY'"),
String::from("ORDERING= 'NUNIQ'"),
))
}
Some(MocKeywords::Ordering(Ordering::Range)) => {
load_f_moc_range(reader, n_bytes, n_elems, depth_max, &moc_kws)
}
Some(MocKeywords::Ordering(Ordering::Range29)) => {
Err(FitsError::UncompatibleKeywordContent(
String::from("ORDERING = 'RANGE29'"),
String::from("MOCVERS= '2.x'"),
))
}
_ => Err(FitsError::MissingKeyword(Ordering::keyword_string())),
}
}
Some(MocKeywords::MOCDim(MocDim::FrequencySpace)) => {
let depth_max_freq = match moc_kws.get::<MocOrdF>() {
Some(MocKeywords::MOCOrdF(MocOrdF { depth })) => *depth,
_ => return Err(FitsError::MissingKeyword(MocOrdF::keyword_string())),
};
let depth_max_hpx = match moc_kws.get::<MocOrdS>() {
Some(MocKeywords::MOCOrdS(MocOrdS { depth })) => *depth,
_ => return Err(FitsError::MissingKeyword(MocOrdS::keyword_string())),
};
match moc_kws.get::<Ordering>() {
Some(MocKeywords::Ordering(Ordering::Nuniq)) => {
Err(FitsError::UncompatibleKeywordContent(
String::from("MOCDIM = 'TREQUENCY.SPACE'"),
String::from("ORDERING= 'NUNIQ'"),
))
}
Some(MocKeywords::Ordering(Ordering::Range)) => load_sf_moc_range(
reader,
n_bytes,
n_elems,
depth_max_freq,
depth_max_hpx,
&moc_kws,
),
Some(MocKeywords::Ordering(Ordering::Range29)) => {
Err(FitsError::UncompatibleKeywordContent(
String::from("ORDERING = 'RANGE29'"),
String::from("MOCVERS= '2.x'"),
))
}
_ => Err(FitsError::MissingKeyword(Ordering::keyword_string())),
}
}
_ => Err(FitsError::MissingKeyword(MocDim::keyword_string())),
}
}
_ => {
let depth_max = match moc_kws.get::<MocOrder>() {
Some(MocKeywords::MOCOrder(MocOrder { depth })) => *depth,
_ => return Err(FitsError::MissingKeyword(MocOrder::keyword_string())),
};
match moc_kws.get::<Ordering>() {
Some(MocKeywords::Ordering(Ordering::Nuniq)) => {
load_s_moc_nuniq(reader, n_bytes, n_elems, depth_max, &moc_kws)
}
Some(MocKeywords::Ordering(Ordering::Range)) => {
load_s_moc_range(reader, n_bytes, n_elems, depth_max, &moc_kws)
}
Some(MocKeywords::Ordering(Ordering::Range29)) => {
let (depth_max_time, depth_max_hpx) =
match (moc_kws.get::<MocOrdT>(), moc_kws.get::<MocOrdS>()) {
(None, Some(MocKeywords::MOCOrdS(MocOrdS { depth }))) => (depth_max << 1, *depth),
(Some(MocKeywords::MOCOrdT(MocOrdT { depth })), None) => ((*depth) << 1, depth_max),
(
Some(MocKeywords::MOCOrdT(MocOrdT { depth: tdepth })),
Some(MocKeywords::MOCOrdS(MocOrdS { depth: sdepth })),
) => ((*tdepth) << 1, *sdepth),
_ => {
return Err(FitsError::MissingKeyword(String::from(
"MOCORD_1 or TORDER",
)))
}
};
load_st_moc_range29(
reader,
n_bytes,
n_elems,
depth_max_time,
depth_max_hpx,
&moc_kws,
)
}
_ => Err(FitsError::MissingKeyword(Ordering::keyword_string())),
}
}
}
}
fn load_s_moc_nuniq<R: BufRead>(
reader: R,
n_bytes: u8,
n_elems: u64,
depth_max: u8,
moc_kws: &MocKeywordsMap,
) -> Result<MocIdxType<R>, FitsError> {
match (moc_kws.get::<TForm1>(), n_bytes) {
(Some(MocKeywords::TForm1(TForm1::OneI)), u16::N_BYTES) => {
Ok(MocIdxType::U16(MocQtyType::Hpx(MocType::Cells(
from_fits_nuniq::<u16, R>(reader, depth_max, n_elems as usize)?,
))))
}
(Some(MocKeywords::TForm1(TForm1::OneJ)), u32::N_BYTES) => {
Ok(MocIdxType::U32(MocQtyType::Hpx(MocType::Cells(
from_fits_nuniq::<u32, R>(reader, depth_max, n_elems as usize)?,
))))
}
(Some(MocKeywords::TForm1(TForm1::OneK)), u64::N_BYTES) => {
Ok(MocIdxType::U64(MocQtyType::Hpx(MocType::Cells(
from_fits_nuniq::<u64, R>(reader, depth_max, n_elems as usize)?,
))))
}
(Some(MocKeywords::TForm1(tform)), nb) => Err(FitsError::UncompatibleKeywordContent(
format!("TFORM1 = {}", nb),
tform.to_string(),
)),
(None, _) => Err(FitsError::MissingKeyword(TForm1::keyword_string())),
(_, _) => unreachable!(), }
}
fn load_s_moc_range<R: BufRead>(
reader: R,
n_bytes: u8,
n_elems: u64,
depth_max: u8,
moc_kws: &MocKeywordsMap,
) -> Result<MocIdxType<R>, FitsError> {
match (moc_kws.get::<TForm1>(), n_bytes) {
(Some(MocKeywords::TForm1(TForm1::OneI)), u16::N_BYTES) => {
Ok(MocIdxType::U16(MocQtyType::Hpx(MocType::Ranges(
from_fits_range::<u16, Hpx<u16>, R>(reader, depth_max, n_elems >> 1)?,
))))
}
(Some(MocKeywords::TForm1(TForm1::OneJ)), u32::N_BYTES) => {
Ok(MocIdxType::U32(MocQtyType::Hpx(MocType::Ranges(
from_fits_range::<u32, Hpx<u32>, R>(reader, depth_max, n_elems >> 1)?,
))))
}
(Some(MocKeywords::TForm1(TForm1::OneK)), u64::N_BYTES) => {
Ok(MocIdxType::U64(MocQtyType::Hpx(MocType::Ranges(
from_fits_range::<u64, Hpx<u64>, R>(reader, depth_max, n_elems >> 1)?,
))))
}
(Some(MocKeywords::TForm1(tform)), nb) => Err(FitsError::UncompatibleKeywordContent(
format!("NAXIS1 = {}", nb),
tform.to_string(),
)),
(None, _) => Err(FitsError::MissingKeyword(TForm1::keyword_string())),
(_, _) => unreachable!(), }
}
fn load_t_moc_range<R: BufRead>(
reader: R,
n_bytes: u8,
n_elems: u64,
depth_max: u8,
moc_kws: &MocKeywordsMap,
) -> Result<MocIdxType<R>, FitsError> {
let n_ranges = n_elems >> 1;
match (moc_kws.get::<TForm1>(), n_bytes) {
(Some(MocKeywords::TForm1(TForm1::OneI)), u16::N_BYTES) => {
Ok(MocIdxType::U16(MocQtyType::Time(MocType::Ranges(
from_fits_range::<u16, Time<u16>, R>(reader, depth_max, n_ranges)?,
))))
}
(Some(MocKeywords::TForm1(TForm1::OneJ)), u32::N_BYTES) => {
Ok(MocIdxType::U32(MocQtyType::Time(MocType::Ranges(
from_fits_range::<u32, Time<u32>, R>(reader, depth_max, n_ranges)?,
))))
}
(Some(MocKeywords::TForm1(TForm1::OneK)), u64::N_BYTES) => {
Ok(MocIdxType::U64(MocQtyType::Time(MocType::Ranges(
from_fits_range::<u64, Time<u64>, R>(reader, depth_max, n_ranges)?,
))))
}
(Some(MocKeywords::TForm1(tform)), nb) => Err(FitsError::UncompatibleKeywordContent(
format!("NAXIS1 = {}", nb),
tform.to_string(),
)),
(None, _) => Err(FitsError::MissingKeyword(TForm1::keyword_string())),
_ => unreachable!(),
}
}
fn load_f_moc_range<R: BufRead>(
reader: R,
n_bytes: u8,
n_elems: u64,
depth_max: u8,
moc_kws: &MocKeywordsMap,
) -> Result<MocIdxType<R>, FitsError> {
let n_ranges = n_elems >> 1;
match (moc_kws.get::<TForm1>(), n_bytes) {
(Some(MocKeywords::TForm1(TForm1::OneI)), u16::N_BYTES) => {
Ok(MocIdxType::U16(MocQtyType::Freq(MocType::Ranges(
from_fits_range::<u16, Frequency<u16>, R>(reader, depth_max, n_ranges)?,
))))
}
(Some(MocKeywords::TForm1(TForm1::OneJ)), u32::N_BYTES) => {
Ok(MocIdxType::U32(MocQtyType::Freq(MocType::Ranges(
from_fits_range::<u32, Frequency<u32>, R>(reader, depth_max, n_ranges)?,
))))
}
(Some(MocKeywords::TForm1(TForm1::OneK)), u64::N_BYTES) => {
Ok(MocIdxType::U64(MocQtyType::Freq(MocType::Ranges(
from_fits_range::<u64, Frequency<u64>, R>(reader, depth_max, n_ranges)?,
))))
}
(Some(MocKeywords::TForm1(tform)), nb) => Err(FitsError::UncompatibleKeywordContent(
format!("NAXIS1 = {}", nb),
tform.to_string(),
)),
(None, _) => Err(FitsError::MissingKeyword(TForm1::keyword_string())),
_ => unreachable!(),
}
}
fn load_st_moc_range<R: BufRead>(
reader: R,
n_bytes: u8,
n_elems: u64,
depth_max_time: u8,
depth_max_hpx: u8,
moc_kws: &MocKeywordsMap,
) -> Result<MocIdxType<R>, FitsError> {
let n_ranges = n_elems >> 1;
match (moc_kws.get::<TForm1>(), n_bytes) {
(Some(MocKeywords::TForm1(TForm1::OneI)), u16::N_BYTES) => Ok(MocIdxType::U16(
MocQtyType::TimeHpx(STMocType::V2(from_fits_range2d::<u16, _, Time<_>, Hpx<_>>(
reader,
depth_max_time,
depth_max_hpx,
n_ranges,
)?)),
)),
(Some(MocKeywords::TForm1(TForm1::OneJ)), u32::N_BYTES) => Ok(MocIdxType::U32(
MocQtyType::TimeHpx(STMocType::V2(from_fits_range2d::<u32, _, Time<_>, Hpx<_>>(
reader,
depth_max_time,
depth_max_hpx,
n_ranges,
)?)),
)),
(Some(MocKeywords::TForm1(TForm1::OneK)), u64::N_BYTES) => Ok(MocIdxType::U64(
MocQtyType::TimeHpx(STMocType::V2(from_fits_range2d::<u64, _, Time<_>, Hpx<_>>(
reader,
depth_max_time,
depth_max_hpx,
n_ranges,
)?)),
)),
(Some(MocKeywords::TForm1(tform)), nb) => Err(FitsError::UncompatibleKeywordContent(
format!("NAXIS1 = {}", nb),
tform.to_string(),
)),
(None, _) => Err(FitsError::MissingKeyword(TForm1::keyword_string())),
_ => unreachable!(),
}
}
fn load_st_moc_range29<R: BufRead>(
reader: R,
n_bytes: u8,
n_elems: u64,
depth_max_time: u8,
depth_max_hpx: u8,
moc_kws: &MocKeywordsMap,
) -> Result<MocIdxType<R>, FitsError> {
let n_ranges = n_elems >> 1;
match (moc_kws.get::<TForm1>(), n_bytes) {
(Some(MocKeywords::TForm1(TForm1::OneK)), u64::N_BYTES) => {
Ok(MocIdxType::U64(MocQtyType::TimeHpx(STMocType::PreV2(
from_fits_range2d_29::<_>(reader, depth_max_time, depth_max_hpx, n_ranges)?,
))))
}
(Some(MocKeywords::TForm1(tform)), nb) => Err(FitsError::UncompatibleKeywordContent(
format!("NAXIS1 = {}", nb),
tform.to_string(),
)),
(None, _) => Err(FitsError::MissingKeyword(TForm1::keyword_string())),
_ => unreachable!(),
}
}
fn load_sf_moc_range<R: BufRead>(
reader: R,
n_bytes: u8,
n_elems: u64,
depth_max_freq: u8,
depth_max_hpx: u8,
moc_kws: &MocKeywordsMap,
) -> Result<MocIdxType<R>, FitsError> {
let n_ranges = n_elems >> 1;
match (moc_kws.get::<TForm1>(), n_bytes) {
(Some(MocKeywords::TForm1(TForm1::OneI)), u16::N_BYTES) => {
Ok(MocIdxType::U16(MocQtyType::FreqHpx(from_fits_range2d::<
u16,
_,
Frequency<_>,
Hpx<_>,
>(
reader,
depth_max_freq,
depth_max_hpx,
n_ranges,
)?)))
}
(Some(MocKeywords::TForm1(TForm1::OneJ)), u32::N_BYTES) => {
Ok(MocIdxType::U32(MocQtyType::FreqHpx(from_fits_range2d::<
u32,
_,
Frequency<_>,
Hpx<_>,
>(
reader,
depth_max_freq,
depth_max_hpx,
n_ranges,
)?)))
}
(Some(MocKeywords::TForm1(TForm1::OneK)), u64::N_BYTES) => {
Ok(MocIdxType::U64(MocQtyType::FreqHpx(from_fits_range2d::<
u64,
_,
Frequency<_>,
Hpx<_>,
>(
reader,
depth_max_freq,
depth_max_hpx,
n_ranges,
)?)))
}
(Some(MocKeywords::TForm1(tform)), nb) => Err(FitsError::UncompatibleKeywordContent(
format!("NAXIS1 = {}", nb),
tform.to_string(),
)),
(None, _) => Err(FitsError::MissingKeyword(TForm1::keyword_string())),
_ => unreachable!(),
}
}
fn from_fits_nuniq<T, R>(
mut reader: R,
mut depth_max: u8,
n_elems: usize,
) -> Result<CellMOC<T, Hpx<T>>, FitsError>
where
T: Idx,
R: BufRead,
{
if depth_max > Hpx::<T>::MAX_DEPTH {
warn!(
"Wrong depth_max {}. Reset to {}",
depth_max,
Hpx::<T>::MAX_DEPTH
);
depth_max = Hpx::<T>::MAX_DEPTH;
}
let mut v: Vec<Cell<T>> = Vec::with_capacity(n_elems);
for _ in 0..n_elems {
let uniq = T::read::<_, BigEndian>(&mut reader)?;
if uniq > T::zero() {
let cell = Cell::from_uniq_hpx(uniq);
if cell.depth > depth_max {
warn!(
"Wrong NUNIQ: depth {} larger than the MOC depth '{}': the NUNIQ {} is ignored!",
cell.depth, depth_max, uniq
)
} else {
v.push(cell);
}
}
}
v.sort_by(|a, b| a.flat_cmp::<Hpx<T>>(b));
Ok(CellMOC::new(
depth_max,
MocCells::<T, Hpx<T>>::new(Cells::new(v)),
))
}
#[allow(dead_code)]
fn from_fits_guniq<T, Q, R>(
mut reader: R,
depth_max: u8,
n_elems: usize,
) -> Result<CellMOC<T, Q>, FitsError>
where
T: Idx,
Q: MocQty<T>,
R: BufRead,
{
let mut v: Vec<Cell<T>> = Vec::with_capacity(n_elems);
for _ in 0..n_elems {
v.push(Cell::from_uniq::<Q>(T::read::<_, BigEndian>(&mut reader)?));
}
Ok(CellMOC::new(
depth_max,
MocCells::<T, Q>::new(Cells::new(v)),
))
}
fn from_fits_range<T, Q, R>(
reader: R,
depth_max: u8,
n_ranges: u64,
) -> Result<RangeMocIterFromFits<T, Q, R>, FitsError>
where
T: Idx,
Q: MocQty<T>,
R: BufRead,
{
Ok(RangeMocIterFromFits::new(depth_max, reader, n_ranges))
}
#[derive(Debug)]
pub struct RangeMocIterFromFits<T: Idx, Q: MocQty<T>, R: BufRead> {
depth_max: u8,
reader: R,
n_elems: u64,
_t_type: PhantomData<T>,
_t_qty: PhantomData<Q>,
}
impl<T: Idx, Q: MocQty<T>, R: BufRead> RangeMocIterFromFits<T, Q, R> {
fn new(depth_max: u8, reader: R, n_elems: u64) -> Self {
Self {
depth_max,
reader,
n_elems,
_t_type: PhantomData,
_t_qty: PhantomData,
}
}
}
impl<T: Idx, Q: MocQty<T>, R: BufRead> HasMaxDepth for RangeMocIterFromFits<T, Q, R> {
fn depth_max(&self) -> u8 {
self.depth_max
}
}
impl<T: Idx, Q: MocQty<T>, R: BufRead> ZSorted for RangeMocIterFromFits<T, Q, R> {}
impl<T: Idx, Q: MocQty<T>, R: BufRead> NonOverlapping for RangeMocIterFromFits<T, Q, R> {}
impl<T: Idx, Q: MocQty<T>, R: BufRead> MOCProperties for RangeMocIterFromFits<T, Q, R> {}
impl<T: Idx, Q: MocQty<T>, R: BufRead> Iterator for RangeMocIterFromFits<T, Q, R> {
type Item = Range<T>; fn next(&mut self) -> Option<Self::Item> {
if self.n_elems > 0_u64 {
let from = T::read::<_, BigEndian>(&mut self.reader);
let to = T::read::<_, BigEndian>(&mut self.reader);
if let (Ok(start), Ok(end)) = (from, to) {
self.n_elems -= 1;
Some(Range { start, end })
} else {
None
}
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
if self.n_elems > usize::MAX as u64 {
(usize::MAX, None)
} else {
(self.n_elems as usize, Some(self.n_elems as usize))
}
}
}
impl<T: Idx, Q: MocQty<T>, R: BufRead> RangeMOCIterator<T> for RangeMocIterFromFits<T, Q, R> {
type Qty = Q;
fn peek_last(&self) -> Option<&Range<T>> {
None
}
}
fn from_fits_range2d<T, R, Q1: MocQty<T>, Q2: MocQty<T>>(
reader: R,
depth_max_dim1: u8,
depth_max_dim2: u8,
n_ranges: u64,
) -> Result<RangeMoc2DIterFromFits<T, R, Q1, Q2>, FitsError>
where
T: Idx,
R: BufRead,
{
Ok(RangeMoc2DIterFromFits::new(
depth_max_dim1,
depth_max_dim2,
reader,
n_ranges,
))
}
#[derive(Debug)]
pub struct RangeMoc2DIterFromFits<T: Idx, R: BufRead, Q1: MocQty<T>, Q2: MocQty<T>> {
depth_max_dim1: u8,
depth_max_dim2: u8,
reader: R,
n_ranges: u64,
_t_type: PhantomData<T>,
_dim1_type: PhantomData<Q1>,
_dim2_type: PhantomData<Q2>,
prev_t: Option<Range<T>>,
}
impl<T: Idx, R: BufRead> RangeMoc2DIterFromFits<T, R, Time<T>, Hpx<T>> {
pub fn new_space_time(depth_max_time: u8, depth_max_space: u8, reader: R, n_ranges: u64) -> Self {
Self::new(depth_max_time, depth_max_space, reader, n_ranges)
}
}
impl<T: Idx, R: BufRead> RangeMoc2DIterFromFits<T, R, Frequency<T>, Hpx<T>> {
pub fn new_space_freq(depth_max_freq: u8, depth_max_space: u8, reader: R, n_ranges: u64) -> Self {
Self::new(depth_max_freq, depth_max_space, reader, n_ranges)
}
}
impl<T: Idx, R: BufRead, Q1: MocQty<T>, Q2: MocQty<T>> RangeMoc2DIterFromFits<T, R, Q1, Q2> {
fn new(depth_max_dim1: u8, depth_max_dim2: u8, reader: R, n_ranges: u64) -> Self {
RangeMoc2DIterFromFits {
depth_max_dim1,
depth_max_dim2,
reader,
n_ranges,
_t_type: PhantomData,
_dim1_type: PhantomData,
_dim2_type: PhantomData,
prev_t: None,
}
}
}
impl<T: Idx, R: BufRead, Q1: MocQty<T>, Q2: MocQty<T>> HasTwoMaxDepth
for RangeMoc2DIterFromFits<T, R, Q1, Q2>
{
fn depth_max_1(&self) -> u8 {
self.depth_max_dim1
}
fn depth_max_2(&self) -> u8 {
self.depth_max_dim2
}
}
impl<T: Idx, R: BufRead, Q1: MocQty<T>, Q2: MocQty<T>> ZSorted
for RangeMoc2DIterFromFits<T, R, Q1, Q2>
{
}
impl<T: Idx, R: BufRead, Q1: MocQty<T>, Q2: MocQty<T>> NonOverlapping
for RangeMoc2DIterFromFits<T, R, Q1, Q2>
{
}
impl<T: Idx, R: BufRead, Q1: MocQty<T>, Q2: MocQty<T>> MOC2Properties
for RangeMoc2DIterFromFits<T, R, Q1, Q2>
{
}
impl<T: Idx, R: BufRead, Q1: MocQty<T>, Q2: MocQty<T>> Iterator
for RangeMoc2DIterFromFits<T, R, Q1, Q2>
{
type Item = RangeMOC2Elem<T, Q1, T, Q2>;
fn next(&mut self) -> Option<Self::Item> {
let mut tranges: Vec<Range<T>> = Vec::with_capacity(1000);
if let Some(trange) = self.prev_t.take() {
tranges.push(trange);
}
let mut sranges: Vec<Range<T>> = Vec::with_capacity(1000);
while self.n_ranges > 0_u64 {
let from = T::read::<_, BigEndian>(&mut self.reader);
let to = T::read::<_, BigEndian>(&mut self.reader);
if let (Ok(start), Ok(end)) = (from, to) {
self.n_ranges -= 1;
if start & end & T::MSB_MASK == T::MSB_MASK {
tranges.push(Range {
start: start & !T::MSB_MASK,
end: end & !T::MSB_MASK,
})
} else {
sranges.push(Range { start, end });
break;
}
} else {
return None;
}
}
while self.n_ranges > 0_u64 {
let from = T::read::<_, BigEndian>(&mut self.reader);
let to = T::read::<_, BigEndian>(&mut self.reader);
if let (Ok(start), Ok(end)) = (from, to) {
self.n_ranges -= 1;
if start & end & T::MSB_MASK == T::MSB_MASK {
self.prev_t = Some(Range {
start: start & !T::MSB_MASK,
end: end & !T::MSB_MASK,
});
break;
} else {
sranges.push(Range { start, end });
}
} else {
return None;
}
}
if tranges.is_empty() && sranges.is_empty() {
None
} else {
Some(RangeMOC2Elem::new(
RangeMOC::new(self.depth_max_dim1, MocRanges::new_unchecked(tranges)),
RangeMOC::new(self.depth_max_dim2, MocRanges::new_unchecked(sranges)),
))
}
}
}
impl<T: Idx, R: BufRead, Q1: MocQty<T>, Q2: MocQty<T>>
RangeMOC2Iterator<
T,
Q1,
RangeMocIter<T, Q1>,
T,
Q2,
RangeMocIter<T, Q2>,
RangeMOC2Elem<T, Q1, T, Q2>,
> for RangeMoc2DIterFromFits<T, R, Q1, Q2>
{
}
fn from_fits_range2d_29<R>(
reader: R,
depth_max_time: u8,
depth_max_hpx: u8,
n_ranges: u64,
) -> Result<RangeMoc2DPreV2IterFromFits<u64, R>, FitsError>
where
R: BufRead,
{
Ok(RangeMoc2DPreV2IterFromFits::new(
depth_max_time,
depth_max_hpx,
reader,
n_ranges,
))
}
#[derive(Debug)]
pub struct RangeMoc2DPreV2IterFromFits<T: Idx, R: BufRead> {
depth_max_time: u8,
depth_max_hpx: u8,
reader: R,
n_ranges: u64,
prev_t: Option<Range<T>>,
}
impl<T: Idx, R: BufRead> RangeMoc2DPreV2IterFromFits<T, R> {
fn new(
depth_max_time: u8,
depth_max_hpx: u8,
reader: R,
n_ranges: u64,
) -> RangeMoc2DPreV2IterFromFits<T, R> {
RangeMoc2DPreV2IterFromFits {
depth_max_time,
depth_max_hpx,
reader,
n_ranges,
prev_t: None,
}
}
}
impl<T: Idx, R: BufRead> HasTwoMaxDepth for RangeMoc2DPreV2IterFromFits<T, R> {
fn depth_max_1(&self) -> u8 {
self.depth_max_time
}
fn depth_max_2(&self) -> u8 {
self.depth_max_hpx
}
}
impl<T: Idx, R: BufRead> ZSorted for RangeMoc2DPreV2IterFromFits<T, R> {}
impl<T: Idx, R: BufRead> NonOverlapping for RangeMoc2DPreV2IterFromFits<T, R> {}
impl<T: Idx, R: BufRead> MOC2Properties for RangeMoc2DPreV2IterFromFits<T, R> {}
impl<T: Idx, R: BufRead> Iterator for RangeMoc2DPreV2IterFromFits<T, R> {
type Item = RangeMOC2Elem<T, Time<T>, T, Hpx<T>>;
fn next(&mut self) -> Option<Self::Item> {
use byteorder::ReadBytesExt;
let mut tranges: Vec<Range<T>> = Vec::with_capacity(1000);
if let Some(trange) = self.prev_t.take() {
tranges.push(trange);
}
let mut sranges: Vec<Range<T>> = Vec::with_capacity(1000);
while self.n_ranges > 0_u64 {
let from = self.reader.read_i64::<BigEndian>(); let to = self.reader.read_i64::<BigEndian>(); if let (Ok(start), Ok(end)) = (from, to) {
self.n_ranges -= 1;
if start < 0 && end < 0 {
tranges.push(Range {
start: T::from_u64_idx(-start as u64),
end: T::from_u64_idx(-end as u64),
})
} else {
sranges.push(Range {
start: T::from_u64_idx(start as u64),
end: T::from_u64_idx(end as u64),
});
break;
}
} else {
return None;
}
}
while self.n_ranges > 0_u64 {
let from = self.reader.read_i64::<BigEndian>(); let to = self.reader.read_i64::<BigEndian>(); if let (Ok(start), Ok(end)) = (from, to) {
self.n_ranges -= 1;
if start < 0 && end < 0 {
self.prev_t = Some(Range {
start: T::from_u64_idx(-start as u64),
end: T::from_u64_idx(-end as u64),
});
break;
} else {
sranges.push(Range {
start: T::from_u64_idx(start as u64),
end: T::from_u64_idx(end as u64),
});
}
} else {
return None;
}
}
if tranges.is_empty() && sranges.is_empty() {
None
} else {
Some(RangeMOC2Elem::new(
RangeMOC::new(self.depth_max_time, MocRanges::new_unchecked(tranges)),
RangeMOC::new(self.depth_max_hpx, MocRanges::new_unchecked(sranges)),
))
}
}
}
impl<T: Idx, R: BufRead>
RangeMOC2Iterator<
T,
Time<T>,
RangeMocIter<T, Time<T>>,
T,
Hpx<T>,
RangeMocIter<T, Hpx<T>>,
RangeMOC2Elem<T, Time<T>, T, Hpx<T>>,
> for RangeMoc2DPreV2IterFromFits<T, R>
{
}
#[cfg(test)]
mod tests {
use std::{
fs::File,
io::{BufReader, BufWriter},
ops::Range,
path::PathBuf,
};
use crate::deser::fits::{
from_fits_ivoa, hpx_cells_to_fits_ivoa, range_stmoc_to_fits_ivoa, ranges_to_fits_ivoa,
FitsError, MocIdxType, MocQtyType, MocType, STMocType,
};
use crate::elem::cell::Cell;
use crate::elemset::{
cell::{Cells, MocCells},
range::{HpxRanges, MocRanges, TimeRanges},
};
use crate::moc::{
cell::CellMOC, range::RangeMOC, CellMOCIntoIterator, HasMaxDepth, RangeMOCIntoIterator,
};
use crate::moc2d::{
range::{RangeMOC2, RangeMOC2Elem},
HasTwoMaxDepth, RangeMOC2ElemIt,
};
use crate::qty::{Hpx, Time};
#[test]
fn test_err() {
let buff = [0_u8; 10];
let reader = BufReader::new(&buff[..]);
match from_fits_ivoa(reader) {
Err(e) => assert!(matches!(e, FitsError::Io(..))),
_ => assert!(false),
}
}
#[test]
fn test_read_v2_smoc_uniq_fits() {
let path_buf1 = PathBuf::from("resources/MOC2.0/GW190425.fits");
let path_buf2 = PathBuf::from("../resources/MOC2.0/GW190425.fits");
let file = File::open(&path_buf1)
.or_else(|_| File::open(&path_buf2))
.unwrap();
let reader = BufReader::new(file);
match from_fits_ivoa(reader) {
Ok(MocIdxType::U32(MocQtyType::Hpx(MocType::Cells(moc1)))) => {
assert_eq!(moc1.depth_max(), 8);
assert_eq!(875, moc1.len());
}
Err(e) => println!("{}", e),
_ => assert!(false),
}
}
#[test]
fn test_read_v1_smoc_fits() {
let path_buf1 = PathBuf::from("resources/MOC2.0/SMOC_test.fits");
let path_buf2 = PathBuf::from("../resources/MOC2.0/SMOC_test.fits");
let file = File::open(&path_buf1)
.or_else(|_| File::open(&path_buf2))
.unwrap();
let reader = BufReader::new(file);
match from_fits_ivoa(reader) {
Ok(MocIdxType::U64(MocQtyType::Hpx(MocType::Cells(moc1)))) => {
assert_eq!(moc1.depth_max(), 29);
assert_eq!(moc1.len(), 10);
let mut vec_cells: Vec<Cell<u64>> = vec![
Cell::from_uniq_hpx(259_u64),
Cell::from_uniq_hpx(266_u64),
Cell::from_uniq_hpx(1040_u64),
Cell::from_uniq_hpx(1041_u64),
Cell::from_uniq_hpx(1042_u64),
Cell::from_uniq_hpx(1046_u64),
Cell::from_uniq_hpx(4115_u64),
Cell::from_uniq_hpx(4116_u64),
Cell::from_uniq_hpx(68719476958_u64),
Cell::from_uniq_hpx(288230376275168533_u64),
];
vec_cells.sort_by(|a, b| a.flat_cmp::<Hpx<u64>>(&b));
let moc2 =
CellMOC::<u64, Hpx<u64>>::new(29, MocCells::new(Cells(vec_cells.into_boxed_slice())));
for (c1, c2) in moc1.into_cell_moc_iter().zip(moc2.into_cell_moc_iter()) {
assert_eq!(c1, c2);
}
}
Err(e) => println!("{}", e),
_ => assert!(false),
}
}
#[test]
fn test_read_v2_tmoc_fits() {
let path_buf1 = PathBuf::from("resources/MOC2.0/TMOC_test.fits");
let path_buf2 = PathBuf::from("../resources/MOC2.0/TMOC_test.fits");
let file = File::open(&path_buf1)
.or_else(|_| File::open(&path_buf2))
.unwrap();
let reader = BufReader::new(file);
match from_fits_ivoa(reader) {
Ok(MocIdxType::U64(MocQtyType::Time(MocType::Ranges(mut moc)))) => {
assert_eq!(moc.depth_max(), 35);
assert_eq!(moc.size_hint(), (1, Some(1)));
assert_eq!(
moc.next(),
Some(Range {
start: 1073741824,
end: 2684354560
})
);
assert_eq!(moc.next(), None);
}
_ => assert!(false),
}
}
#[test]
fn test_read_sfmoc_fits() {
let path_buf1 = PathBuf::from("resources/MOC2.1/SFMocMUSE.fits");
let path_buf2 = PathBuf::from("../resources/MOC2.1/SFMocMUSE.fits");
let file = File::open(&path_buf1)
.or_else(|_| File::open(&path_buf2))
.unwrap();
let reader = BufReader::new(file);
match from_fits_ivoa(reader) {
Ok(MocIdxType::U64(MocQtyType::FreqHpx(moc))) => {
assert_eq!(moc.depth_max_1(), 14);
assert_eq!(moc.depth_max_2(), 12);
}
Err(e) => {
eprintln!("{}", e);
panic!()
}
_ => panic!(),
}
}
#[test]
fn test_write_ranges_fits() {
let ranges = vec![Range {
start: 1073741824_u64,
end: 2684354560_u64,
}];
let moc: RangeMOC<u64, Time<u64>> = RangeMOC::new(35, MocRanges::new_unchecked(ranges));
let path_buf1 = PathBuf::from("resources/MOC2.0/TMOC_test.fits");
let path_buf2 = PathBuf::from("../resources/MOC2.0/TMOC_test.fits");
let file = File::create(&path_buf1)
.or_else(|_| File::create(&path_buf2))
.unwrap();
let writer = BufWriter::new(file);
ranges_to_fits_ivoa(moc.into_range_moc_iter(), None, None, writer).unwrap();
}
#[test]
fn test_write_cells_fits() {
let moc = CellMOC::<u64, Hpx<u64>>::new(
29,
MocCells::new(Cells(
vec![
Cell::from_uniq_hpx(259_u64),
Cell::from_uniq_hpx(266_u64),
Cell::from_uniq_hpx(1040_u64),
Cell::from_uniq_hpx(1041_u64),
Cell::from_uniq_hpx(1042_u64),
Cell::from_uniq_hpx(1046_u64),
Cell::from_uniq_hpx(4115_u64),
Cell::from_uniq_hpx(4116_u64),
Cell::from_uniq_hpx(68719476958_u64),
Cell::from_uniq_hpx(288230376275168533_u64),
]
.into_boxed_slice(),
)),
);
let path_buf1 = PathBuf::from("resources/MOC2.0/SMOC_test.fits");
let path_buf2 = PathBuf::from("../resources/MOC2.0/SMOC_test.fits");
let file = File::create(&path_buf1)
.or_else(|_| File::create(&path_buf2))
.unwrap();
let writer = BufWriter::new(file);
hpx_cells_to_fits_ivoa(moc.into_cell_moc_iter(), None, None, writer).unwrap();
}
#[test]
fn test_moc2d_to_fits() {
let path_buf1 = PathBuf::from("resources/MOC2.0/STMOC.fits");
let path_buf2 = PathBuf::from("../resources/MOC2.0/STMOC.fits");
let file = File::open(&path_buf1)
.or_else(|_| File::open(&path_buf2))
.unwrap();
let reader = BufReader::new(file);
let mut it = match from_fits_ivoa(reader).unwrap() {
MocIdxType::U64(MocQtyType::TimeHpx(STMocType::V2(it))) => it,
_ => unreachable!(),
};
assert_eq!(it.depth_max_1(), 61);
assert_eq!(it.depth_max_2(), 4);
let (mut t_it, mut s_it) = it.next().unwrap().range_mocs_it();
assert_eq!(t_it.next(), Some(Range { start: 1, end: 2 }));
assert_eq!(t_it.next(), Some(Range { start: 3, end: 4 }));
assert_eq!(t_it.next(), Some(Range { start: 5, end: 6 }));
assert_eq!(t_it.next(), None);
assert_eq!(
s_it.next(),
Some(Range {
start: 4503599627370496,
end: 18014398509481984
})
);
assert_eq!(s_it.next(), None);
let (mut t_it, mut s_it) = it.next().unwrap().range_mocs_it();
assert_eq!(t_it.next(), Some(Range { start: 50, end: 51 }));
assert_eq!(t_it.next(), Some(Range { start: 52, end: 53 }));
assert_eq!(t_it.next(), None);
assert_eq!(
s_it.next(),
Some(Range {
start: 28147497671065600,
end: 29273397577908224
})
);
assert_eq!(s_it.next(), None);
assert!(it.next().is_none());
}
#[test]
fn test_write_ranges2d_fits() {
let mut elems: Vec<RangeMOC2Elem<u64, Time<u64>, u64, Hpx<u64>>> = Default::default();
elems.push(RangeMOC2Elem::new(
RangeMOC::new(61, TimeRanges::new_unchecked(vec![1..2, 3..4, 5..6])),
RangeMOC::new(
4,
HpxRanges::new_unchecked(vec![4503599627370496..18014398509481984]),
),
));
elems.push(RangeMOC2Elem::new(
RangeMOC::new(61, TimeRanges::new_unchecked(vec![50..51, 52..53])),
RangeMOC::new(
4,
HpxRanges::new_unchecked(vec![28147497671065600..29273397577908224]),
),
));
let moc2 = RangeMOC2::new(61, 4, elems);
let path_buf1 = PathBuf::from("resources/MOC2.0/STMOC_test.fits");
let path_buf2 = PathBuf::from("../resources/MOC2.0/STMOC_test.fits");
let file = File::create(&path_buf1)
.or_else(|_| File::create(&path_buf2))
.unwrap();
let writer = BufWriter::new(file);
range_stmoc_to_fits_ivoa(&moc2, None, None, writer).unwrap();
}
}