Skip to content

Commit

Permalink
Fix ASCII and JSON deser/serialisation with empty ST-MOCs
Browse files Browse the repository at this point in the history
  • Loading branch information
fxpineau committed May 27, 2024
1 parent 7b27a05 commit 78446e3
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 31 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,18 @@ Released 2024-XX-XX
### Added

* `U64MocStore.new_empty_stmoc`
* `is_empty` in `CellOrCellRangeMOC` and `CellOrCellRangeMOC2`

### Changed

* Add max time depth and max space depth at the end of the ST-MOC ASCII representation
* Add max time depth and max space depth at the end of the ST-MOC JSON representation

### Fixed

* Fix the empty ASCII represention of an empty ST-MOC
* Fix the empty JSON represention of an empty ST-MOC
* Empty ST-MOC loaded as... empty (instead of containing one element imade of an empty T-MOC and and emtpy S-MOC)

## 0.13.0

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "moc"
version = "0.13.0"
version = "0.14.0"
authors = [
"F.-X. Pineau <[email protected]>",
"Matthieu Baumann <[email protected]>"
Expand Down
62 changes: 48 additions & 14 deletions src/deser/ascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,9 @@ where
let r: CellOrCellRangeMOC<U, R> = from_ascii_ivoa(r)?;
depth_max_l = depth_max_l.max(l.depth_max());
depth_max_r = depth_max_r.max(r.depth_max());
elems.push(CellOrCellRangeMOC2Elem::new(l, r));
if !l.is_empty() && !r.is_empty() {
elems.push(CellOrCellRangeMOC2Elem::new(l, r));
}
} else {
return Err(AsciiError::ElemNotFound(
R::PREFIX.to_string(),
Expand Down Expand Up @@ -375,14 +377,17 @@ where
L: CellOrCellRangeMOC2Iterator<T, Q, I, U, R, J, K>,
W: Write,
{
let d1 = moc2_it.depth_max_1();
let d2 = moc2_it.depth_max_2();
for e in moc2_it {
writer.write_u8(Q::PREFIX as u8)?;
let (moc1_it, moc2_it) = e.cellcellrange_mocs_it();
to_ascii_ivoa(moc1_it, fold, use_range_len, &mut writer)?;
writer.write_u8(R::PREFIX as u8)?;
to_ascii_ivoa(moc2_it, fold, use_range_len, &mut writer)?;
}
Ok(())
// Always write maximum depth in both dimensions
write!(&mut writer, "{}{}/ {}{}/", Q::PREFIX, d1, R::PREFIX, d2).map_err(AsciiError::Io)
}

/// This serialization is less compact than the IVOA ASCII serialization
Expand Down Expand Up @@ -561,19 +566,24 @@ impl<T: Idx, Q: MocQty<T>, R: BufRead> CellOrCellRangeMOCIterator<T>

#[cfg(test)]
mod tests {
use std::str;

use crate::deser::ascii::{
from_ascii_ivoa, from_ascii_stream, moc2d_from_ascii_ivoa, moc2d_to_ascii_ivoa,
use std::str::{self, from_utf8};

use crate::{
deser::ascii::{
from_ascii_ivoa, from_ascii_stream, moc2d_from_ascii_ivoa, moc2d_to_ascii_ivoa,
},
elem::cell::Cell,
elemset::range::MocRanges,
moc::{
range::RangeMOC, CellMOCIterator, CellOrCellRangeMOCIntoIterator, CellOrCellRangeMOCIterator,
HasMaxDepth, RangeMOCIntoIterator, RangeMOCIterator,
},
moc2d::{
range::RangeMOC2, CellOrCellRangeMOC2IntoIterator, CellOrCellRangeMOC2Iterator,
HasTwoMaxDepth, RangeMOC2IntoIterator, RangeMOC2Iterator,
},
qty::{Hpx, Time},
};
use crate::elem::cell::Cell;
use crate::elemset::range::MocRanges;
use crate::moc::{
range::RangeMOC, CellMOCIterator, CellOrCellRangeMOCIntoIterator, CellOrCellRangeMOCIterator,
HasMaxDepth, RangeMOCIntoIterator, RangeMOCIterator,
};
use crate::moc2d::CellOrCellRangeMOC2IntoIterator;
use crate::qty::{Hpx, Time};

#[test]
fn test_from_ascii_ivoa() {
Expand Down Expand Up @@ -773,4 +783,28 @@ mod tests {
.unwrap();
println!("{}\n", str::from_utf8(&res_ascii_1).unwrap());
}

#[test]
fn test_moc2d_empty_to_ascii_ivoa() {
let stmoc = RangeMOC2::<u64, Time<u64>, u64, Hpx<u64>>::new_empty(12, 8);
let mut res_ascii = Vec::new();
stmoc
.into_range_moc2_iter()
.into_cellcellrange_moc2_iter()
.to_ascii_ivoa(None, false, &mut res_ascii)
.unwrap();
let ascii = from_utf8(res_ascii.as_ref()).unwrap();
let expected = "t12/ s8/";
// println!("moc: {}", ascii);
assert_eq!(ascii, expected);

let stmoc2 = moc2d_from_ascii_ivoa::<u64, Time<u64>, u64, Hpx<u64>>(expected)
.unwrap()
.into_cellcellrange_moc2_iter()
.into_range_moc2_iter()
.into_range_moc2();
assert!(stmoc2.is_empty());
assert_eq!(stmoc2.depth_max_1(), 12);
assert_eq!(stmoc2.depth_max_2(), 8);
}
}
75 changes: 61 additions & 14 deletions src/deser/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ where
L: CellMOC2Iterator<T, Q, I, U, R, J, K>,
W: Write,
{
let d1 = moc2_it.depth_max_1();
let d2 = moc2_it.depth_max_2();
writer.write_all(b"[\n")?;
let mut is_first = true;
for e in moc2_it {
Expand All @@ -112,8 +114,18 @@ where
to_json_aladin(moc2_it, fold, " ", &mut writer)?;
writer.write_all(b"\n}")?;
}
writer.write_all(b"\n]\n")?;
Ok(())
if !is_first {
writer.write_all(b",\n")?;
}
write!(
&mut writer,
"{{ \"{}\": {{ \"{}\": [] }}, \"{}\": {{ \"{}\": [] }} }}",
Q::PREFIX,
d1,
R::PREFIX,
d2
)?;
writer.write_all(b"\n]\n")
}

/*pub fn rangemoc2d_to_json_aladin<T, Q, I, U, R, J, K, L, W>(
Expand Down Expand Up @@ -253,7 +265,9 @@ where
let r: CellMOC<U, R> = from_json_aladin_internal::<U, R>(obj2)?;
depth_max_l = depth_max_l.max(l.depth_max());
depth_max_r = depth_max_r.max(r.depth_max());
elems.push(CellMOC2Elem::new(l, r));
if !l.is_empty() && !r.is_empty() {
elems.push(CellMOC2Elem::new(l, r));
}
}
_ => {
return Err(
Expand Down Expand Up @@ -291,19 +305,21 @@ where
#[cfg(test)]
mod tests {

use std::fs;
use std::path::PathBuf;
use std::{fs, path::PathBuf, str::from_utf8};

use crate::deser::json::{
cellmoc2d_from_json_aladin, cellmoc2d_to_json_aladin, from_json_aladin,
use crate::moc2d::{HasTwoMaxDepth, RangeMOC2Iterator};
use crate::{
deser::json::{cellmoc2d_from_json_aladin, cellmoc2d_to_json_aladin, from_json_aladin},
elemset::range::{HpxRanges, MocRanges, TimeRanges},
moc::{
range::RangeMOC, CellMOCIntoIterator, CellMOCIterator, RangeMOCIntoIterator, RangeMOCIterator,
},
moc2d::{
range::{RangeMOC2, RangeMOC2Elem},
CellMOC2IntoIterator, CellMOC2Iterator, RangeMOC2IntoIterator,
},
qty::{Hpx, Time},
};
use crate::elemset::range::{HpxRanges, MocRanges, TimeRanges};
use crate::moc::{
range::RangeMOC, CellMOCIntoIterator, CellMOCIterator, RangeMOCIntoIterator, RangeMOCIterator,
};
use crate::moc2d::range::{RangeMOC2, RangeMOC2Elem};
use crate::moc2d::CellMOC2IntoIterator;
use crate::qty::{Hpx, Time};

#[test]
fn test_fromto_json() {
Expand Down Expand Up @@ -402,4 +418,35 @@ mod tests {
// println!("{}\n", &json);
*/
}

#[test]
fn test_stmoc_empty_to_json() {
let stmoc = RangeMOC2::<u64, Time<u64>, u64, Hpx<u64>>::new_empty(12, 8);
let mut res_json = Vec::new();
stmoc
.into_range_moc2_iter()
.into_cell_moc2_iter()
.to_json_aladin(&None, &mut res_json)
.unwrap();
let json = from_utf8(res_json.as_ref()).unwrap();
// println!("moc: {}", json);
let expected = r#"[
{ "t": { "12": [] }, "s": { "8": [] } }
]
"#;
assert_eq!(json, expected);

let cellmoc2 = cellmoc2d_from_json_aladin::<u64, Time<u64>, u64, Hpx<u64>>(&expected).unwrap();
assert_eq!(cellmoc2.depth_max_1(), 12);
assert_eq!(cellmoc2.depth_max_2(), 8);
assert_eq!(cellmoc2.n_entries(), 0);

let stmoc2 = cellmoc2
.into_cell_moc2_iter()
.into_range_moc2_iter()
.into_range_moc2();
assert!(stmoc2.is_empty());
assert_eq!(stmoc2.depth_max_1(), 12);
assert_eq!(stmoc2.depth_max_2(), 8);
}
}
3 changes: 3 additions & 0 deletions src/moc/cellcellrange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ impl<T: Idx, Q: MocQty<T>> CellOrCellRangeMOC<T, Q> {
pub fn new(depth_max: u8, ranges: MocCellOrCellRanges<T, Q>) -> Self {
Self { depth_max, ranges }
}
pub fn is_empty(&self) -> bool {
self.ranges.0 .0.is_empty()
}
pub fn elems(self) -> CellOrCellRanges<T> {
self.ranges.0
}
Expand Down
3 changes: 3 additions & 0 deletions src/moc2d/cellcellrange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ impl<T: Idx, Q: MocQty<T>, U: Idx, R: MocQty<U>> CellOrCellRangeMOC2<T, Q, U, R>
elems,
}
}
pub fn is_empty(&self) -> bool {
self.elems.is_empty()
}
}
impl<T: Idx, Q: MocQty<T>, U: Idx, R: MocQty<U>> HasTwoMaxDepth
for CellOrCellRangeMOC2<T, Q, U, R>
Expand Down
5 changes: 3 additions & 2 deletions src/moc2d/range/op/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ s7/88307-88308
1412900-1412901 1412903 1412909 1412956 1412958-1412959 1413009 1413021
1413023 1413084 1413092-1413093 1415312 1415324 1415406 1415712 1415714
1415726 1415808-1415810
"#;
t29/ s10/"#;

let left_it = moc2d_from_ascii_ivoa::<u64, Time<u64>, u64, Hpx<u64>>(left)
.unwrap()
Expand Down Expand Up @@ -398,7 +398,8 @@ s7/88307-88308
&mut actual_ascii,
)
.unwrap();
// println!("{}", std::str::from_utf8(&actual_ascii).unwrap());
println!("{}", std::str::from_utf8(&actual_ascii).unwrap());
println!("{}", expected);

assert_eq!(actual_ascii, expected.as_bytes());
}
Expand Down

0 comments on commit 78446e3

Please sign in to comment.