use super::REPLAY_WINDOW_SIZE;
use std::fmt;
#[derive(Clone)]
pub struct ReplayWindow {
highest: u64,
bitmap: [u64; REPLAY_WINDOW_SIZE / 64],
}
impl ReplayWindow {
pub fn new() -> Self {
Self {
highest: 0,
bitmap: [0; REPLAY_WINDOW_SIZE / 64],
}
}
pub fn check(&self, counter: u64) -> bool {
if counter > self.highest {
return true;
}
let diff = self.highest - counter;
if diff as usize >= REPLAY_WINDOW_SIZE {
return false;
}
let word_idx = (diff as usize) / 64;
let bit_idx = (diff as usize) % 64;
(self.bitmap[word_idx] & (1u64 << bit_idx)) == 0
}
pub fn accept(&mut self, counter: u64) {
if counter > self.highest {
let shift = counter - self.highest;
if shift as usize >= REPLAY_WINDOW_SIZE {
self.bitmap = [0; REPLAY_WINDOW_SIZE / 64];
} else {
self.shift_bitmap(shift as usize);
}
self.highest = counter;
self.bitmap[0] |= 1;
} else {
let diff = self.highest - counter;
let word_idx = (diff as usize) / 64;
let bit_idx = (diff as usize) % 64;
self.bitmap[word_idx] |= 1u64 << bit_idx;
}
}
fn shift_bitmap(&mut self, shift: usize) {
if shift >= REPLAY_WINDOW_SIZE {
self.bitmap = [0; REPLAY_WINDOW_SIZE / 64];
return;
}
let word_shift = shift / 64;
let bit_shift = shift % 64;
if word_shift > 0 {
for i in (word_shift..self.bitmap.len()).rev() {
self.bitmap[i] = self.bitmap[i - word_shift];
}
for i in 0..word_shift {
self.bitmap[i] = 0;
}
}
if bit_shift > 0 {
let mut carry = 0u64;
for i in 0..self.bitmap.len() {
let new_carry = self.bitmap[i] >> (64 - bit_shift);
self.bitmap[i] = (self.bitmap[i] << bit_shift) | carry;
carry = new_carry;
}
}
}
pub fn highest(&self) -> u64 {
self.highest
}
pub fn reset(&mut self) {
self.highest = 0;
self.bitmap = [0; REPLAY_WINDOW_SIZE / 64];
}
}
impl Default for ReplayWindow {
fn default() -> Self {
Self::new()
}
}
impl fmt::Debug for ReplayWindow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplayWindow")
.field("highest", &self.highest)
.field("window_size", &REPLAY_WINDOW_SIZE)
.finish()
}
}