use crate::protocol::dds::types::guid::Guid;
use crate::protocol::dds::types::locator::Locator;
use crate::protocol::dds::types::sequence::{SequenceNumber, SequenceNumberSet};
pub struct WriterProxy {
pub remote_writer_guid: Guid,
pub unicast_locators: Vec<Locator>,
pub highest_contiguous_sn: Option<SequenceNumber>,
pub received_out_of_order: Vec<SequenceNumber>,
pub acknack_count: i32,
}
impl WriterProxy {
pub fn new(guid: Guid, unicast_locators: Vec<Locator>) -> Self {
Self {
remote_writer_guid: guid,
unicast_locators,
highest_contiguous_sn: None,
received_out_of_order: Vec::new(),
acknack_count: 0,
}
}
pub fn received(&mut self, sn: SequenceNumber) {
let next_expected = match self.highest_contiguous_sn {
None => SequenceNumber::new(1),
Some(h) => h.increment(),
};
if sn == next_expected {
self.highest_contiguous_sn = Some(sn);
let mut current = sn;
loop {
let next = current.increment();
if let Some(pos) = self.received_out_of_order.iter().position(|&x| x == next) {
self.received_out_of_order.swap_remove(pos);
current = next;
self.highest_contiguous_sn = Some(next);
} else {
break;
}
}
} else {
let above_contiguous = match self.highest_contiguous_sn {
None => sn.to_i64() > 0,
Some(h) => sn > h,
};
if above_contiguous && !self.received_out_of_order.contains(&sn) {
self.received_out_of_order.push(sn);
}
}
}
pub fn build_missing_sn_set(&self, writer_last_sn: SequenceNumber) -> SequenceNumberSet {
let base = match self.highest_contiguous_sn {
None => SequenceNumber::new(1),
Some(h) => h.increment(),
};
let mut set = SequenceNumberSet::empty(base);
let start_v = base.to_i64();
let end_v = writer_last_sn.to_i64();
if end_v < start_v {
return set;
}
let window = (end_v - start_v + 1).min(256) as u64;
for offset in 0..window {
let sn = SequenceNumber::new(start_v + offset as i64);
if !self.received_out_of_order.contains(&sn) {
let _ = set.set(sn);
}
}
set
}
pub fn next_acknack_count(&mut self) -> i32 {
self.acknack_count = self.acknack_count.saturating_add(1);
self.acknack_count
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::protocol::dds::types::guid::{EntityId, GuidPrefix};
fn sn(v: i64) -> SequenceNumber {
SequenceNumber::new(v)
}
fn make_proxy() -> WriterProxy {
let guid = Guid {
prefix: GuidPrefix([0xAAu8; 12]),
entity_id: EntityId {
entity_key: [0, 0, 1],
entity_kind: 0x02,
},
};
WriterProxy::new(guid, Vec::new())
}
#[test]
fn writer_proxy_received_in_order() {
let mut proxy = make_proxy();
proxy.received(sn(1));
proxy.received(sn(2));
proxy.received(sn(3));
assert_eq!(proxy.highest_contiguous_sn, Some(sn(3)));
assert!(proxy.received_out_of_order.is_empty());
}
#[test]
fn writer_proxy_received_gap() {
let mut proxy = make_proxy();
proxy.received(sn(1));
proxy.received(sn(3));
assert_eq!(proxy.highest_contiguous_sn, Some(sn(1)));
assert!(proxy.received_out_of_order.contains(&sn(3)));
proxy.received(sn(2));
assert_eq!(proxy.highest_contiguous_sn, Some(sn(3)));
assert!(proxy.received_out_of_order.is_empty());
}
#[test]
fn writer_proxy_build_missing_set() {
let mut proxy = make_proxy();
proxy.received(sn(1));
proxy.received(sn(3));
let set = proxy.build_missing_sn_set(sn(4));
assert!(set.is_set(sn(2)), "SN(2) should be requested");
assert!(!set.is_set(sn(1)), "SN(1) already received — not missing");
assert!(!set.is_set(sn(3)), "SN(3) already received — not missing");
assert!(set.is_set(sn(4)), "SN(4) should be requested");
}
}