1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
use std::iter::Iterator;
use super::SeqNumber;
/// Iterator for compressing loss lists
pub struct CompressLossList<I> {
/// Underlying iterator
iterator: I,
/// The next item
next: Option<SeqNumber>,
/// Some if looping
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 we're at the start, assign a next
if self.next.is_none() {
self.next = Some(self.iterator.next()?)
}
loop {
// The state right here is
// neither this nor next have been returned, and we need to figure out if this is
// a) already in a loop and we continue on with that loop
// b) already in a loop and need to break out
// c) not in a loop and need to start one
// d) not in a loop and doesn't need to start one
let this = self.next?;
match self.iterator.next() {
Some(i) => self.next = Some(i),
None => {
// invalidate next, so it None will be returned next time
self.next = None;
// return the one we have
return Some(this.as_raw());
}
};
// the list must be sorted
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? {
// continue with the loop
self.last_in_loop = Some(last_in_loop + 1);
continue;
} else {
// break out of the loop
self.last_in_loop = None;
return Some(this.as_raw());
}
} else if this + 1 == self.next? {
// create a loop
self.last_in_loop = Some(this);
// set the first bit to 1
return Some(this.as_raw() | 1 << 31);
} else {
// no looping necessary
return Some(this.as_raw());
}
}
}
}
// keep in mind loss_list must be sorted
// takes in a list of u32, which is the loss list
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 => {
// loop is over
self.loop_next_end = None;
Some(SeqNumber::new_truncate(next))
}
Some((next, end)) => {
// continue the loop
self.loop_next_end = Some((next + 1, end));
Some(SeqNumber::new_truncate(next))
}
None => {
// no current loop
let next = self.iterator.next()?;
// is this a loop start
if next & (1 << 31) != 0 {
// set the first bit to zero
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 {
// no looping is possible
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<_>>();
}
}