use std::collections::HashMap;
#[derive(Debug)]
pub struct Acknowledgement {
pub ack_begin: u32,
pub ack_end: u16,
pub miss_count: u16,
pub miss: Vec<u16>,
}
impl Clone for Acknowledgement {
fn clone(&self) -> Acknowledgement {
Acknowledgement {
ack_begin: self.ack_begin,
ack_end: self.ack_end,
miss_count: self.miss_count,
miss: self.miss.clone(),
}
}
}
pub const MAX_WINDOW: u16 = 65000;
#[derive(Debug)]
pub struct AcknowledgementCheck {
begin: u32,
list: HashMap<u32, bool>,
}
impl AcknowledgementCheck {
pub fn new(begin: u32) -> AcknowledgementCheck {
AcknowledgementCheck {
begin,
list: HashMap::new(),
}
}
fn update_begin(&mut self) {
while self.check(&(self.begin + 1)) {
self.list.remove(&(self.begin + 1));
self.begin += 1;
}
}
pub fn acknowledge(&mut self, ack: Acknowledgement) {
if self.begin < ack.ack_begin {
for i in self.begin..(ack.ack_begin + 1) {
self.insert(i);
}
}
let mut missing: HashMap<u16, bool> = HashMap::new();
for i in ack.miss {
missing.insert(i, true);
}
for i in 0..(ack.ack_end + 1) {
match missing.get(&i) {
None => self.insert(i as u32 + ack.ack_begin),
Some(false) => self.insert(i as u32 + ack.ack_begin),
Some(true) => (),
}
}
}
pub fn insert(&mut self, ack: u32) {
if ack > self.begin {
self.list.insert(ack, true);
}
self.update_begin();
}
pub fn check(&self, ack: &u32) -> bool {
if *ack <= self.begin {
return true;
}
match self.list.get(ack) {
None => false,
Some(v) => *v,
}
}
}
#[derive(Debug)]
pub struct AcknowledgementList {
list: HashMap<u32, bool>,
ack_begin: u32,
ack_end: u16,
}
impl AcknowledgementList {
pub fn new(ack_begin: u32) -> AcknowledgementList {
let mut list: HashMap<u32, bool> = HashMap::new();
list.insert(ack_begin, true);
AcknowledgementList {
list,
ack_begin,
ack_end: 0,
}
}
pub fn check(&self, ack: &u32) -> bool {
if *ack <= self.ack_begin {
true
} else if self.ack_begin < *ack && *ack <= (self.ack_begin + self.ack_end as u32) {
match self.list.get(ack) {
None => false,
Some(v) => *v,
}
} else {
false
}
}
pub fn insert(&mut self, ack: u32) {
if ack > (MAX_WINDOW as u32 + self.ack_begin) {
panic!("ack too large {}\t Diff: {}", ack, ack - self.ack_begin);
} else if ack > self.ack_begin {
let n = (ack - self.ack_begin) as u16;
if n > self.ack_end {
self.ack_end = n;
}
self.list.insert(ack, true);
self.update_begin();
}
}
fn update_begin(&mut self) {
while self.check(&(self.ack_begin + 1)) {
self.list.remove(&(self.ack_begin + 1));
self.ack_begin += 1;
self.ack_end -= 1;
}
}
pub fn get(&self) -> Acknowledgement {
let mut miss: Vec<u16> = Vec::new();
for i in 1..(self.ack_end + 1) {
match self.list.get(&(i as u32 + self.ack_begin)) {
None => miss.push(i),
Some(false) => miss.push(i),
Some(true) => (),
}
}
Acknowledgement {
ack_begin: self.ack_begin,
ack_end: self.ack_end,
miss_count: miss.len() as u16,
miss,
}
}
pub fn is_complete(&self) -> bool {
self.get().miss_count == 0
}
}
#[cfg(test)]
mod tests {
mod ack_check {
use crate::acknowledgement::{AcknowledgementCheck, AcknowledgementList};
#[test]
fn false_positive_raw() {
let values = [16, 1024, 99, 45];
let check = [19, 32, 63, 6000];
let mut ack_check = AcknowledgementCheck::new(16);
for v in values {
ack_check.insert(v);
}
for c in check {
assert!(!ack_check.check(&c));
}
}
#[test]
fn true_negatives_raw() {
let values = [16, 1024, 99, 45];
let mut ack_check = AcknowledgementCheck::new(16);
for v in values {
ack_check.insert(v);
}
for c in values {
assert!(ack_check.check(&c));
}
}
#[test]
fn false_positives() {
let values = [16, 20, 17, 18, 22, 23];
let check = [19, 21, 63];
let mut ack_list = AcknowledgementList::new(16);
for v in values {
ack_list.insert(v);
}
let mut ack_check = AcknowledgementCheck::new(16);
let ack = ack_list.get();
ack_check.acknowledge(ack);
for c in check {
assert!(!ack_check.check(&c));
}
}
#[test]
fn true_negatives() {
let values = [16, 17, 18, 20, 21, 22, 32];
let mut ack_list = AcknowledgementList::new(16);
for v in values {
ack_list.insert(v);
}
let mut ack_check = AcknowledgementCheck::new(16);
let ack = ack_list.get();
ack_check.acknowledge(ack);
for c in values {
assert!(ack_check.check(&c));
}
}
}
mod ack_list {
use crate::acknowledgement::AcknowledgementList;
#[test]
fn false_positives() {
let sequence = 10;
let mut ack_list = AcknowledgementList::new(sequence);
let values = [10, 20, 30, 40];
let check = [12, 15, 320, 44, 39];
for v in values {
ack_list.insert(v);
}
for c in check {
assert!(!ack_list.check(&c));
}
}
#[test]
fn true_negatives() {
let sequence = 10;
let mut ack_list = AcknowledgementList::new(sequence);
let values = [10, 20, 30, 40];
for v in values {
ack_list.insert(v);
}
for c in values {
assert!(ack_list.check(&c));
}
}
#[test]
fn missing_test() {
let sequence = 10;
let mut ack_list = AcknowledgementList::new(sequence);
let misses = [11, 14, 22, 28];
for v in sequence..(sequence + 20) {
if !misses.contains(&v) {
ack_list.insert(v);
}
}
let ack = ack_list.get();
for m in ack.miss {
assert!(misses.contains(&(m as u32 + sequence)));
}
}
#[test]
fn check_complete_test() {
let sequence = 10;
let mut ack_list = AcknowledgementList::new(sequence);
let values = sequence..(sequence + 20);
for v in values {
ack_list.insert(v);
}
assert!(ack_list.is_complete());
}
}
}