const PACKET_HISTORY: usize = 1024;
#[derive(Debug, Clone, Copy)]
pub struct Remote {
ack: u16,
ack_bitfield: u32,
packet_data: BitArray<PACKET_HISTORY>,
packet_valid: BitArray<PACKET_HISTORY>,
receive_sequence_buffer: [u16; PACKET_HISTORY],
}
impl Default for Remote {
fn default() -> Self {
Self::new()
}
}
impl Remote {
pub fn new() -> Self {
Self {
ack: 0,
ack_bitfield: 0,
receive_sequence_buffer: [0; PACKET_HISTORY],
packet_data: BitArray::new(),
packet_valid: BitArray::new(),
}
}
pub fn get_packet_data(&self, sequence: u16) -> Option<PacketInfo> {
let index = (sequence % PACKET_HISTORY as u16) as usize;
if self.packet_valid.get(index) && self.receive_sequence_buffer[index] == sequence {
Some(PacketInfo {
acked: self.packet_data.get(index),
})
} else {
None
}
}
pub fn acknowledge_packet(&mut self, sequence: u16) -> bool {
let index = (sequence % PACKET_HISTORY as u16) as usize;
let is_newer = sequence_greater_than(sequence, self.ack);
let was_received = self.packet_valid.get(index) && self.receive_sequence_buffer[index] == sequence;
if !is_newer {
let history_distance = self.ack.wrapping_sub(sequence);
if was_received || usize::from(history_distance) >= PACKET_HISTORY {
return false;
}
}
if is_newer {
let previous_ack = self.ack;
let advance = sequence.wrapping_sub(previous_ack);
let entries_to_clear = usize::from(advance).min(PACKET_HISTORY);
for offset in 1..=entries_to_clear {
let cleared_sequence = previous_ack.wrapping_add(offset as u16);
let cleared_index = (cleared_sequence % PACKET_HISTORY as u16) as usize;
self.packet_valid.set(cleared_index, false);
}
self.ack = sequence;
let shifted_acknowledgements = self.ack_bitfield.checked_shl(u32::from(advance)).unwrap_or(0);
self.ack_bitfield = shifted_acknowledgements + 1;
} else {
let distance = self.ack.wrapping_sub(sequence);
if distance < u32::BITS as u16 {
self.ack_bitfield |= 1 << distance;
}
}
self.receive_sequence_buffer[index] = sequence;
self.packet_data.set(index, true);
self.packet_valid.set(index, true);
true
}
pub fn get_ack(&self) -> u16 {
self.ack
}
pub fn get_ack_bitfield(&self) -> u32 {
self.ack_bitfield
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_packet_acknowledgement() {
let mut remote = Remote::new();
assert_eq!(remote.get_ack(), 0);
assert_eq!(remote.get_ack_bitfield(), 0);
for i in 0..32 {
remote.acknowledge_packet(i);
}
assert_eq!(remote.get_ack(), 31);
assert_eq!(remote.get_ack_bitfield(), 0xFFFF_FFFF);
for i in 0..32 {
remote.acknowledge_packet(i);
}
assert_eq!(remote.get_ack(), 31);
assert_eq!(remote.get_ack_bitfield(), 0xFFFF_FFFF);
for i in 32..48 {
remote.acknowledge_packet(i);
}
assert_eq!(remote.get_ack(), 47);
assert_eq!(remote.get_ack_bitfield(), 0xFFFF_FFFF);
for i in 48..64 {
remote.acknowledge_packet(i);
}
assert_eq!(remote.get_ack(), 63);
assert_eq!(remote.get_ack_bitfield(), 0xFFFF_FFFF);
}
#[test]
fn test_sparse_packet_acknowledgement() {
let mut remote = Remote::new();
assert_eq!(remote.get_ack(), 0);
assert_eq!(remote.get_ack_bitfield(), 0);
remote.acknowledge_packet(0);
assert_eq!(remote.get_ack(), 0);
assert_eq!(remote.get_ack_bitfield(), 1 << 0);
remote.acknowledge_packet(2);
assert_eq!(remote.get_ack(), 2);
assert_eq!(remote.get_ack_bitfield(), 1 << 2 | 1 << 0);
remote.acknowledge_packet(4);
assert_eq!(remote.get_ack(), 4);
assert_eq!(remote.get_ack_bitfield(), 1 << 4 | 1 << 2 | 1 << 0);
remote.acknowledge_packet(1);
assert_eq!(remote.get_ack(), 4);
assert_eq!(remote.get_ack_bitfield(), 1 << 4 | 1 << 3 | 1 << 2 | 1 << 0);
remote.acknowledge_packet(3);
assert_eq!(remote.get_ack(), 4);
assert_eq!(remote.get_ack_bitfield(), 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1 << 0);
}
#[test]
fn test_out_of_range_packet_acknowledgement() {
let mut remote = Remote::new();
remote.acknowledge_packet(0);
assert_eq!(remote.get_ack(), 0);
assert_eq!(remote.get_ack_bitfield(), 1 << 0);
remote.acknowledge_packet(64);
assert_eq!(remote.get_ack(), 64);
assert_eq!(remote.get_ack_bitfield(), 1 << 0);
remote.acknowledge_packet(0);
assert_eq!(remote.get_ack(), 64);
assert_eq!(remote.get_ack_bitfield(), 1 << 0);
remote.acknowledge_packet(32);
assert_eq!(remote.get_ack(), 64);
assert_eq!(remote.get_ack_bitfield(), 1 << 0);
}
#[test]
fn acknowledgement_wraps_without_overflow() {
let mut remote = Remote::new();
remote.acknowledge_packet(u16::MAX);
assert_eq!(remote.get_ack(), 0);
assert_eq!(remote.get_ack_bitfield(), 0b10);
assert_eq!(remote.get_packet_data(u16::MAX), Some(PacketInfo { acked: true }));
}
#[test]
fn advancing_across_wrap_preserves_recent_history() {
let mut remote = Remote::new();
remote.acknowledge_packet(32_767);
remote.acknowledge_packet(u16::MAX);
remote.acknowledge_packet(0);
assert_eq!(remote.get_ack(), 0);
assert_eq!(remote.get_ack_bitfield(), 0b11);
assert_eq!(remote.get_packet_data(u16::MAX), Some(PacketInfo { acked: true }));
assert_eq!(remote.get_packet_data(0), Some(PacketInfo { acked: true }));
}
#[test]
fn empty_history_does_not_treat_max_sequence_as_received() {
let remote = Remote::new();
assert_eq!(remote.get_packet_data(u16::MAX), None);
}
#[test]
fn full_sequence_cycle_matches_a_sliding_receive_window() {
let mut remote = Remote::new();
for sequence in 0..=u16::MAX {
remote.acknowledge_packet(sequence);
assert_eq!(remote.get_ack(), sequence);
}
assert_eq!(remote.get_ack_bitfield(), u32::MAX);
assert_eq!(remote.get_packet_data(u16::MAX), Some(PacketInfo { acked: true }));
assert_eq!(remote.get_packet_data(u16::MAX - 1_023), Some(PacketInfo { acked: true }));
assert_eq!(remote.get_packet_data(u16::MAX - 1_024), None);
}
#[test]
fn duplicate_and_stale_sequences_do_not_change_acknowledgement_state() {
let mut remote = Remote::new();
for sequence in 0..=2_000 {
remote.acknowledge_packet(sequence);
}
let ack = remote.get_ack();
let ack_bitfield = remote.get_ack_bitfield();
assert!(!remote.acknowledge_packet(2_000));
assert!(!remote.acknowledge_packet(0));
assert!(!remote.acknowledge_packet(976));
assert_eq!(remote.get_ack(), ack);
assert_eq!(remote.get_ack_bitfield(), ack_bitfield);
assert_eq!(remote.get_packet_data(0), None);
}
#[test]
fn large_jumps_clear_history_and_accept_missing_packets_only_within_the_new_window() {
let mut remote = Remote::new();
for sequence in 0..=2 {
assert!(remote.acknowledge_packet(sequence));
}
assert!(remote.acknowledge_packet(2_000));
assert_eq!(remote.get_ack(), 2_000);
assert_eq!(remote.get_packet_data(2), None);
assert!(remote.acknowledge_packet(1_500));
assert!(!remote.acknowledge_packet(1_500));
assert!(!remote.acknowledge_packet(900));
assert_eq!(remote.get_packet_data(1_500), Some(PacketInfo { acked: true }));
assert_eq!(remote.get_packet_data(900), None);
}
}
use utils::bit_array::BitArray;
use super::{sequence_greater_than, PacketInfo};