use std::iter::Iterator;
use super::SeqNumber;
pub struct CompressLossList<I> {
iterator: I,
next: Option<SeqNumber>,
last_in_loop: Option<SeqNumber>,
}
impl<I> Iterator for CompressLossList<I>
where
I: Iterator<Item = SeqNumber>,
{
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.next.is_none() {
self.next = Some(self.iterator.next()?)
}
loop {
let this = self.next?;
match self.iterator.next() {
Some(i) => self.next = Some(i),
None => {
self.next = None;
return Some(this.as_raw());
}
};
assert!(this < self.next?, "error: {}!<{}", this.0, self.next?.0);
if let Some(last_in_loop) = self.last_in_loop {
if last_in_loop + 2 == self.next? {
self.last_in_loop = Some(last_in_loop + 1);
continue;
} else {
self.last_in_loop = None;
return Some(this.as_raw());
}
} else if this + 1 == self.next? {
self.last_in_loop = Some(this);
return Some(this.as_raw() | 1 << 31);
} else {
return Some(this.as_raw());
}
}
}
}
pub fn compress_loss_list<I>(loss_list: I) -> CompressLossList<I>
where
I: Iterator<Item = SeqNumber>,
{
CompressLossList {
iterator: loss_list,
next: None,
last_in_loop: None,
}
}
pub struct DecompressLossList<I> {
iterator: I,
loop_next_end: Option<(u32, u32)>,
}
impl<I: Iterator<Item = u32>> Iterator for DecompressLossList<I> {
type Item = SeqNumber;
fn next(&mut self) -> Option<SeqNumber> {
match self.loop_next_end {
Some((next, end)) if next == end => {
self.loop_next_end = None;
Some(SeqNumber::new_truncate(next))
}
Some((next, end)) => {
self.loop_next_end = Some((next + 1, end));
Some(SeqNumber::new_truncate(next))
}
None => {
let next = self.iterator.next()?;
if next & (1 << 31) != 0 {
let next_num = next & !(1 << 31);
self.loop_next_end = Some((
next_num + 1,
match self.iterator.next() {
Some(i) => i,
None => panic!("unterminated loop while decompressing loss list"),
},
));
Some(SeqNumber::new_truncate(next_num))
} else {
Some(SeqNumber::new_truncate(next))
}
}
}
}
}
pub fn decompress_loss_list<I: Iterator<Item = u32>>(loss_list: I) -> DecompressLossList<I> {
DecompressLossList {
iterator: loss_list,
loop_next_end: None,
}
}
#[cfg(test)]
mod test {
use super::*;
const ONE: u32 = 1 << 31;
#[test]
fn loss_compression_test() {
macro_rules! test_comp_decomp {
($x:expr, $y:expr) => {{
assert_eq!(
compress_loss_list($x.iter().cloned().map(SeqNumber::new_truncate))
.collect::<Vec<_>>(),
$y.iter().cloned().collect::<Vec<_>>(),
"Compressed wasn't same as given"
);
assert_eq!(
decompress_loss_list($y.iter().cloned()).collect::<Vec<_>>(),
$x.iter()
.cloned()
.map(SeqNumber::new_truncate)
.collect::<Vec<_>>(),
"Decompressed not same as given"
);
}};
}
test_comp_decomp!([13, 14, 15, 16, 17, 18, 19], [13 | ONE, 19]);
test_comp_decomp!(
[1, 2, 3, 4, 5, 9, 11, 12, 13, 16, 17],
[1 | ONE, 5, 9, 11 | ONE, 13, 16 | ONE, 17]
);
test_comp_decomp!([15, 16], [15 | ONE, 16]);
test_comp_decomp!(
[1_687_761_238, 1_687_761_239],
[1_687_761_238 | ONE, 1_687_761_239]
);
}
#[test]
#[should_panic(expected = "error: 10!<1")]
fn invalid_ordering() {
let _ = compress_loss_list([10, 1].iter().copied().map(SeqNumber::new_truncate))
.collect::<Vec<_>>();
}
#[test]
#[should_panic(expected = "unterminated loop")]
fn unterminated_loop() {
let _ = decompress_loss_list([10 | ONE].iter().copied()).collect::<Vec<_>>();
}
}