use super::message::SyncMessage;
#[derive(Debug, Clone, Default)]
pub struct SyncTracker {
current_num: u64,
last_sent_num: u64,
last_acked: u64,
peer_state_num: u64,
}
impl SyncTracker {
pub fn new() -> Self {
Self::default()
}
pub fn with_initial_version(version: u64) -> Self {
Self {
current_num: version,
last_sent_num: 0,
last_acked: 0,
peer_state_num: 0,
}
}
pub fn current_version(&self) -> u64 {
self.current_num
}
pub fn last_sent_version(&self) -> u64 {
self.last_sent_num
}
pub fn last_acked_version(&self) -> u64 {
self.last_acked
}
pub fn peer_version(&self) -> u64 {
self.peer_state_num
}
pub fn has_pending_updates(&self) -> bool {
self.current_num > self.last_sent_num
}
pub fn needs_ack(&self) -> bool {
self.peer_state_num > self.last_acked
}
pub fn is_synchronized(&self) -> bool {
self.last_acked == self.current_num && !self.needs_ack()
}
pub fn bump_version(&mut self) -> u64 {
self.current_num += 1;
self.current_num
}
pub fn record_sent(&mut self, sent_version: u64) {
if sent_version > self.last_sent_num {
self.last_sent_num = sent_version;
}
}
pub fn process_incoming(&mut self, msg: &SyncMessage) -> bool {
if msg.acked_state_num > self.last_acked {
self.last_acked = msg.acked_state_num;
}
let is_new_state = msg.sender_state_num > self.peer_state_num;
if is_new_state {
self.peer_state_num = msg.sender_state_num;
}
is_new_state && !msg.is_ack_only()
}
pub fn create_message(&self, diff: Vec<u8>, base_state_num: u64) -> SyncMessage {
SyncMessage::new(
self.current_num,
self.peer_state_num,
base_state_num,
diff,
)
}
pub fn create_ack(&self) -> SyncMessage {
SyncMessage::ack_only(self.current_num, self.peer_state_num)
}
pub fn reset(&mut self) {
*self = Self::default();
}
pub fn diff_base_version(&self) -> u64 {
self.last_acked
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_tracker() {
let tracker = SyncTracker::new();
assert_eq!(tracker.current_version(), 0);
assert_eq!(tracker.last_sent_version(), 0);
assert_eq!(tracker.last_acked_version(), 0);
assert_eq!(tracker.peer_version(), 0);
}
#[test]
fn test_bump_version() {
let mut tracker = SyncTracker::new();
assert_eq!(tracker.bump_version(), 1);
assert_eq!(tracker.bump_version(), 2);
assert_eq!(tracker.bump_version(), 3);
assert_eq!(tracker.current_version(), 3);
}
#[test]
fn test_has_pending_updates() {
let mut tracker = SyncTracker::new();
assert!(!tracker.has_pending_updates());
tracker.bump_version();
assert!(tracker.has_pending_updates());
tracker.record_sent(1);
assert!(!tracker.has_pending_updates());
tracker.bump_version();
assert!(tracker.has_pending_updates());
}
#[test]
fn test_process_incoming() {
let mut tracker = SyncTracker::new();
tracker.bump_version();
let msg = SyncMessage::new(5, 1, 4, vec![1, 2, 3]);
let has_new_state = tracker.process_incoming(&msg);
assert!(has_new_state);
assert_eq!(tracker.peer_version(), 5);
assert_eq!(tracker.last_acked_version(), 1);
}
#[test]
fn test_process_ack_only() {
let mut tracker = SyncTracker::new();
tracker.bump_version();
tracker.bump_version();
let msg = SyncMessage::ack_only(3, 2);
let has_new_state = tracker.process_incoming(&msg);
assert!(!has_new_state);
assert_eq!(tracker.peer_version(), 3);
assert_eq!(tracker.last_acked_version(), 2);
}
#[test]
fn test_needs_ack() {
let mut tracker = SyncTracker::new();
assert!(!tracker.needs_ack());
let msg = SyncMessage::new(5, 0, 0, vec![1, 2, 3]);
tracker.process_incoming(&msg);
assert!(tracker.needs_ack());
assert_eq!(tracker.peer_version(), 5);
}
#[test]
fn test_create_message() {
let mut tracker = SyncTracker::new();
tracker.bump_version();
let incoming = SyncMessage::new(3, 0, 0, vec![]);
tracker.process_incoming(&incoming);
let msg = tracker.create_message(vec![10, 20, 30], 0);
assert_eq!(msg.sender_state_num, 1);
assert_eq!(msg.acked_state_num, 3); assert_eq!(msg.diff, vec![10, 20, 30]);
}
#[test]
fn test_create_ack() {
let mut tracker = SyncTracker::new();
tracker.bump_version();
let incoming = SyncMessage::new(5, 0, 0, vec![1]);
tracker.process_incoming(&incoming);
let ack = tracker.create_ack();
assert!(ack.is_ack_only());
assert_eq!(ack.sender_state_num, 1);
assert_eq!(ack.acked_state_num, 5);
}
#[test]
fn test_is_synchronized() {
let mut tracker = SyncTracker::new();
assert!(tracker.is_synchronized());
tracker.bump_version();
assert!(!tracker.is_synchronized());
tracker.record_sent(1);
let ack = SyncMessage::new(1, 1, 0, vec![]);
tracker.process_incoming(&ack);
assert!(tracker.is_synchronized());
}
#[test]
fn test_diff_base_version() {
let mut tracker = SyncTracker::new();
assert_eq!(tracker.diff_base_version(), 0);
let msg = SyncMessage::new(10, 5, 0, vec![]);
tracker.process_incoming(&msg);
assert_eq!(tracker.diff_base_version(), 5);
}
#[test]
fn test_with_initial_version() {
let tracker = SyncTracker::with_initial_version(100);
assert_eq!(tracker.current_version(), 100);
assert_eq!(tracker.last_sent_version(), 0);
}
#[test]
fn test_reset() {
let mut tracker = SyncTracker::new();
tracker.bump_version();
tracker.bump_version();
tracker.record_sent(2);
let msg = SyncMessage::new(5, 2, 0, vec![1]);
tracker.process_incoming(&msg);
tracker.reset();
assert_eq!(tracker.current_version(), 0);
assert_eq!(tracker.last_sent_version(), 0);
assert_eq!(tracker.last_acked_version(), 0);
assert_eq!(tracker.peer_version(), 0);
}
}