#![allow(dead_code)]
use alloc::vec::Vec;
use core::ops::RangeInclusive;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub(crate) enum PnSpaceId {
Initial = 0,
Handshake = 1,
Application = 2,
}
pub(crate) const MAX_ACK_RANGES: usize = 32;
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub(crate) struct AckRanges {
ranges: Vec<RangeInclusive<u64>>,
}
impl AckRanges {
pub(crate) fn new() -> Self {
Self::default()
}
pub(crate) fn insert(&mut self, pn: u64) {
for r in &self.ranges {
if r.contains(&pn) {
return;
}
}
let mut insert_idx = self.ranges.len();
for (i, r) in self.ranges.iter().enumerate() {
if *r.start() <= pn {
insert_idx = i;
break;
}
}
let extended_above = if insert_idx > 0 {
let above = &mut self.ranges[insert_idx - 1];
if *above.start() == pn + 1 {
*above = pn..=*above.end();
true
} else {
false
}
} else {
false
};
let extended_below = if insert_idx < self.ranges.len() {
let below = &mut self.ranges[insert_idx];
if *below.end() + 1 == pn {
*below = *below.start()..=pn;
true
} else {
false
}
} else {
false
};
match (extended_above, extended_below) {
(true, true) => {
let below = self.ranges.remove(insert_idx);
let above = &mut self.ranges[insert_idx - 1];
*above = *below.start()..=*above.end();
}
(true, false) | (false, true) => {}
(false, false) => {
if self.ranges.len() >= MAX_ACK_RANGES && insert_idx >= self.ranges.len() {
return;
}
self.ranges.insert(insert_idx, pn..=pn);
if self.ranges.len() > MAX_ACK_RANGES {
self.ranges.truncate(MAX_ACK_RANGES);
}
}
}
}
pub(crate) fn contains(&self, pn: u64) -> bool {
self.ranges.iter().any(|r| r.contains(&pn))
}
pub(crate) fn largest(&self) -> Option<u64> {
self.ranges.first().map(|r| *r.end())
}
pub(crate) fn is_empty(&self) -> bool {
self.ranges.is_empty()
}
pub(crate) fn ranges(&self) -> &[RangeInclusive<u64>] {
&self.ranges
}
pub(crate) fn clear(&mut self) {
self.ranges.clear();
}
}
#[derive(Debug, Default)]
pub(crate) struct PnSpace {
pub(crate) next_tx: u64,
pub(crate) largest_rx: Option<u64>,
pub(crate) largest_acked_tx: Option<u64>,
pub(crate) pending_ack: AckRanges,
pub(crate) ack_eliciting_pending: bool,
pub(crate) largest_eliciting_arrival_us: Option<u64>,
}
pub(crate) fn decode_packet_number(largest_pn: u64, truncated_pn: u64, pn_nbits: u32) -> u64 {
debug_assert!(pn_nbits == 8 || pn_nbits == 16 || pn_nbits == 24 || pn_nbits == 32);
let expected_pn = largest_pn.wrapping_add(1);
let pn_win = 1u64 << pn_nbits;
let pn_hwin = pn_win >> 1;
let pn_mask = pn_win - 1;
let candidate_pn = (expected_pn & !pn_mask) | truncated_pn;
if candidate_pn.wrapping_add(pn_hwin) <= expected_pn && candidate_pn < (1u64 << 62) - pn_win {
candidate_pn.wrapping_add(pn_win)
} else if candidate_pn > expected_pn.wrapping_add(pn_hwin) && candidate_pn >= pn_win {
candidate_pn.wrapping_sub(pn_win)
} else {
candidate_pn
}
}
pub(crate) fn encode_packet_number_length(pn: u64, largest_acked: Option<u64>) -> u32 {
let gap = match largest_acked {
Some(la) => pn.saturating_sub(la),
None => pn.saturating_add(1),
};
let needed_bits = if gap == 0 {
1
} else {
64 - gap.leading_zeros()
} + 1;
if needed_bits <= 8 {
8
} else if needed_bits <= 16 {
16
} else if needed_bits <= 24 {
24
} else {
32
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn app_a_decode_examples() {
let pn = decode_packet_number(0xa82f30ea, 0x9b32, 16);
assert_eq!(pn, 0xa82f9b32);
}
#[test]
fn decode_around_wrap() {
let pn = decode_packet_number(0x100, 0x00, 8);
assert_eq!(pn, 0x100);
}
#[test]
fn encode_length_grows_with_gap() {
let nbits_small = encode_packet_number_length(10, Some(5));
assert_eq!(nbits_small, 8);
let nbits_mid = encode_packet_number_length(1 << 20, Some(0));
assert!(nbits_mid >= 24);
let nbits_max = encode_packet_number_length(1 << 60, Some(0));
assert_eq!(nbits_max, 32);
let nbits_no_ack = encode_packet_number_length(1 << 40, None);
assert_eq!(nbits_no_ack, 32);
}
#[test]
fn ackranges_insert_coalesces() {
let mut r = AckRanges::new();
r.insert(3);
r.insert(5);
r.insert(4); assert_eq!(r.ranges(), &[3..=5]);
let mut r = AckRanges::new();
r.insert(1);
r.insert(3);
assert_eq!(r.ranges(), &[3..=3, 1..=1]);
}
#[test]
fn ackranges_descending_order() {
let mut r = AckRanges::new();
for &pn in &[10u64, 1, 5, 4, 11] {
r.insert(pn);
}
assert_eq!(r.ranges(), &[10..=11, 4..=5, 1..=1]);
}
#[test]
fn ackranges_largest_and_contains() {
let mut r = AckRanges::new();
assert!(r.is_empty());
assert_eq!(r.largest(), None);
r.insert(7);
r.insert(2);
r.insert(3);
assert_eq!(r.largest(), Some(7));
assert!(r.contains(2));
assert!(r.contains(3));
assert!(r.contains(7));
assert!(!r.contains(4));
r.clear();
assert!(r.is_empty());
}
#[test]
fn ackranges_idempotent_duplicate() {
let mut r = AckRanges::new();
r.insert(5);
r.insert(5);
assert_eq!(r.ranges(), &[5..=5]);
}
#[test]
fn ackranges_capped_at_max() {
let mut r = AckRanges::new();
for i in 0..(MAX_ACK_RANGES as u64 * 4) {
r.insert(i * 2);
assert!(
r.ranges().len() <= MAX_ACK_RANGES,
"range count must stay bounded"
);
}
assert_eq!(r.ranges().len(), MAX_ACK_RANGES);
let highest = (MAX_ACK_RANGES as u64 * 4 - 1) * 2;
assert!(r.contains(highest), "highest PN retained");
assert!(!r.contains(0), "lowest PN evicted once over the cap");
assert_eq!(r.largest(), Some(highest));
}
#[test]
fn ackranges_cap_does_not_evict_when_coalescing() {
let mut r = AckRanges::new();
for i in 0..(MAX_ACK_RANGES as u64 * 8) {
r.insert(i);
}
assert_eq!(r.ranges(), &[0..=(MAX_ACK_RANGES as u64 * 8 - 1)]);
}
#[test]
fn ackranges_low_new_range_dropped_at_capacity() {
let mut r = AckRanges::new();
for i in 0..MAX_ACK_RANGES as u64 {
r.insert(1000 + i * 2);
}
assert_eq!(r.ranges().len(), MAX_ACK_RANGES);
let before = r.ranges().to_vec();
r.insert(0);
assert_eq!(r.ranges(), before.as_slice(), "low PN dropped at cap");
assert!(!r.contains(0));
}
}