netstack3_base/tcp/
seqnum.rs1use core::convert::TryFrom as _;
8use core::num::TryFromIntError;
9use core::ops;
10
11use explicit::ResultExt as _;
12
13#[derive(Debug, PartialEq, Eq, Clone, Copy)]
32pub struct SeqNum(u32);
33
34impl ops::Add<i32> for SeqNum {
35 type Output = SeqNum;
36
37 fn add(self, rhs: i32) -> Self::Output {
38 let Self(lhs) = self;
39 Self(lhs.wrapping_add_signed(rhs))
40 }
41}
42
43impl ops::Sub<i32> for SeqNum {
44 type Output = SeqNum;
45
46 fn sub(self, rhs: i32) -> Self::Output {
47 let Self(lhs) = self;
48 Self(lhs.wrapping_add_signed(rhs.wrapping_neg()))
49 }
50}
51
52impl ops::Add<u32> for SeqNum {
53 type Output = SeqNum;
54
55 fn add(self, rhs: u32) -> Self::Output {
56 let Self(lhs) = self;
57 Self(lhs.wrapping_add(rhs))
58 }
59}
60
61impl ops::Sub<u32> for SeqNum {
62 type Output = SeqNum;
63
64 fn sub(self, rhs: u32) -> Self::Output {
65 let Self(lhs) = self;
66 Self(lhs.wrapping_sub(rhs))
67 }
68}
69
70impl ops::Sub<WindowSize> for SeqNum {
71 type Output = SeqNum;
72
73 fn sub(self, WindowSize(wnd): WindowSize) -> Self::Output {
74 self - i32::try_from(wnd).unwrap()
78 }
79}
80
81impl ops::Add<usize> for SeqNum {
82 type Output = SeqNum;
83
84 fn add(self, rhs: usize) -> Self::Output {
85 self + (rhs as u32)
93 }
94}
95
96impl ops::Sub for SeqNum {
97 type Output = i32;
100
101 fn sub(self, rhs: Self) -> Self::Output {
102 let Self(lhs) = self;
103 let Self(rhs) = rhs;
104 lhs.wrapping_sub(rhs) as i32
114 }
115}
116
117impl From<u32> for SeqNum {
118 fn from(x: u32) -> Self {
119 Self::new(x)
120 }
121}
122
123impl From<SeqNum> for u32 {
124 fn from(x: SeqNum) -> Self {
125 let SeqNum(x) = x;
126 x
127 }
128}
129
130impl SeqNum {
131 pub const fn new(x: u32) -> Self {
133 Self(x)
134 }
135}
136
137impl SeqNum {
138 pub fn before(self, other: SeqNum) -> bool {
142 self - other < 0
143 }
144
145 pub fn before_or_eq(self, other: SeqNum) -> bool {
150 self - other <= 0
151 }
152
153 pub fn after(self, other: SeqNum) -> bool {
157 self - other > 0
158 }
159
160 pub fn after_or_eq(self, other: SeqNum) -> bool {
165 self - other >= 0
166 }
167
168 pub fn earliest(self, other: SeqNum) -> SeqNum {
173 if self.before(other) { self } else { other }
174 }
175
176 pub fn latest(self, other: SeqNum) -> SeqNum {
181 if self.after(other) { self } else { other }
182 }
183}
184
185#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
194pub struct WindowSize(u32);
195
196impl WindowSize {
197 pub const MAX: WindowSize = WindowSize((1 << 30) - 1);
199 pub const ZERO: WindowSize = WindowSize(0);
201 pub const ONE: WindowSize = WindowSize(1);
203
204 pub const DEFAULT: WindowSize = WindowSize(65535);
208
209 pub const fn from_u32(wnd: u32) -> Option<Self> {
213 let WindowSize(max) = Self::MAX;
214 if wnd > max { None } else { Some(Self(wnd)) }
215 }
216
217 pub fn saturating_add(self, rhs: u32) -> Self {
219 Self::from_u32(u32::from(self).saturating_add(rhs)).unwrap_or(Self::MAX)
220 }
221
222 pub fn new(wnd: usize) -> Option<Self> {
224 u32::try_from(wnd).ok_checked::<TryFromIntError>().and_then(WindowSize::from_u32)
225 }
226
227 pub fn checked_sub(self, diff: usize) -> Option<Self> {
229 usize::from(self).checked_sub(diff).and_then(Self::new)
235 }
236
237 pub fn saturating_sub(self, diff: usize) -> Self {
240 self.checked_sub(diff).unwrap_or(WindowSize::ZERO)
241 }
242
243 pub fn scale(self) -> WindowScale {
245 let WindowSize(size) = self;
246 let effective_bits = u8::try_from(32 - u32::leading_zeros(size)).unwrap();
247 let scale = WindowScale(effective_bits.saturating_sub(16));
248 scale
249 }
250
251 pub fn halved(self) -> WindowSize {
253 let WindowSize(size) = self;
254 WindowSize(size >> 1)
255 }
256}
257
258impl ops::Add<WindowSize> for SeqNum {
259 type Output = SeqNum;
260
261 fn add(self, WindowSize(wnd): WindowSize) -> Self::Output {
262 self + wnd
263 }
264}
265
266impl From<WindowSize> for u32 {
267 fn from(WindowSize(wnd): WindowSize) -> Self {
268 wnd
269 }
270}
271
272#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
273impl From<WindowSize> for usize {
274 fn from(WindowSize(wnd): WindowSize) -> Self {
275 wnd as usize
276 }
277}
278
279#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
280pub struct WindowScale(u8);
286
287impl WindowScale {
288 pub const MAX: WindowScale = WindowScale(14);
290 pub const ZERO: WindowScale = WindowScale(0);
292
293 pub const fn new(ws: u8) -> Option<Self> {
297 if ws <= Self::MAX.get() { Some(WindowScale(ws)) } else { None }
298 }
299
300 pub const fn get(&self) -> u8 {
302 let Self(ws) = self;
303 *ws
304 }
305}
306
307#[derive(Debug, PartialEq, Eq, Clone, Copy)]
308pub struct UnscaledWindowSize(u16);
313
314impl ops::Shl<WindowScale> for UnscaledWindowSize {
315 type Output = WindowSize;
316
317 fn shl(self, WindowScale(scale): WindowScale) -> Self::Output {
318 let UnscaledWindowSize(size) = self;
319 WindowSize::from_u32(u32::from(size) << scale).unwrap()
321 }
322}
323
324impl ops::Shr<WindowScale> for WindowSize {
325 type Output = UnscaledWindowSize;
326
327 fn shr(self, WindowScale(scale): WindowScale) -> Self::Output {
328 let WindowSize(size) = self;
329 UnscaledWindowSize(u16::try_from(size >> scale).unwrap_or(u16::MAX))
330 }
331}
332
333impl From<u16> for UnscaledWindowSize {
334 fn from(value: u16) -> Self {
335 Self(value)
336 }
337}
338
339impl From<UnscaledWindowSize> for u16 {
340 fn from(UnscaledWindowSize(value): UnscaledWindowSize) -> Self {
341 value
342 }
343}
344
345#[cfg(feature = "testutils")]
346mod testutils {
347 use super::*;
348
349 impl UnscaledWindowSize {
350 pub fn from_usize(size: usize) -> Self {
354 UnscaledWindowSize::from(u16::try_from(size).unwrap())
355 }
356
357 pub fn from_u32(size: u32) -> Self {
361 UnscaledWindowSize::from(u16::try_from(size).unwrap())
362 }
363 }
364}
365
366#[cfg(test)]
367mod tests {
368 use proptest::arbitrary::any;
369 use proptest::strategy::{Just, Strategy};
370 use proptest::test_runner::Config;
371 use proptest::{prop_assert, prop_assert_eq, proptest};
372 use proptest_support::failed_seeds_no_std;
373 use test_case::test_case;
374
375 use super::super::segment::MAX_PAYLOAD_AND_CONTROL_LEN;
376 use super::*;
377
378 fn arb_seqnum() -> impl Strategy<Value = SeqNum> {
379 any::<u32>().prop_map(SeqNum::from)
380 }
381
382 fn arb_seqnum_trans_tripple() -> impl Strategy<Value = (SeqNum, SeqNum, SeqNum)> {
385 arb_seqnum().prop_flat_map(|a| {
386 (1..=MAX_PAYLOAD_AND_CONTROL_LEN).prop_flat_map(move |diff_a_b| {
387 let b = a + diff_a_b;
388 (1..=MAX_PAYLOAD_AND_CONTROL_LEN - diff_a_b).prop_flat_map(move |diff_b_c| {
389 let c = b + diff_b_c;
390 (Just(a), Just(b), Just(c))
391 })
392 })
393 })
394 }
395
396 #[test_case(WindowSize::new(1).unwrap() => (UnscaledWindowSize::from(1), WindowScale::default()))]
397 #[test_case(WindowSize::new(65535).unwrap() => (UnscaledWindowSize::from(65535), WindowScale::default()))]
398 #[test_case(WindowSize::new(65536).unwrap() => (UnscaledWindowSize::from(32768), WindowScale::new(1).unwrap()))]
399 #[test_case(WindowSize::new(65537).unwrap() => (UnscaledWindowSize::from(32768), WindowScale::new(1).unwrap()))]
400 fn window_scale(size: WindowSize) -> (UnscaledWindowSize, WindowScale) {
401 let scale = size.scale();
402 (size >> scale, scale)
403 }
404
405 proptest! {
406 #![proptest_config(Config {
407 failure_persistence: failed_seeds_no_std!(),
409 ..Config::default()
410 })]
411
412 #[test]
413 fn seqnum_ord_is_reflexive(a in arb_seqnum()) {
414 prop_assert_eq!(a, a)
415 }
416
417 #[test]
418 fn seqnum_ord_is_total(a in arb_seqnum(), b in arb_seqnum()) {
419 if a == b {
420 prop_assert!(!a.before(b) && !b.before(a))
421 } else {
422 prop_assert!(a.before(b) ^ b.before(a))
423 }
424 }
425
426 #[test]
427 fn seqnum_ord_is_transitive((a, b, c) in arb_seqnum_trans_tripple()) {
428 prop_assert!(a.before(b) && b.before(c) && a.before(c));
429 }
430
431 #[test]
432 fn seqnum_add_positive_greater(a in arb_seqnum(), b in 1..=i32::MAX) {
433 prop_assert!(a.before(a + b))
434 }
435
436 #[test]
437 fn seqnum_add_negative_smaller(a in arb_seqnum(), b in i32::MIN..=-1) {
438 prop_assert!(a.after(a + b))
439 }
440
441 #[test]
442 fn seqnum_sub_positive_smaller(a in arb_seqnum(), b in 1..=i32::MAX) {
443 prop_assert!(a.after(a - b))
444 }
445
446 #[test]
447 fn seqnum_sub_negative_greater(a in arb_seqnum(), b in i32::MIN..=-1) {
448 prop_assert!(a.before(a - b))
449 }
450
451 #[test]
452 fn seqnum_zero_identity(a in arb_seqnum()) {
453 prop_assert_eq!(a, a + 0)
454 }
455
456 #[test]
457 fn seqnum_before_after_inverse(a in arb_seqnum(), b in arb_seqnum()) {
458 prop_assert_eq!(a.after(b), b.before(a))
459 }
460
461 #[test]
462 fn seqnum_wraps_around_at_max_length(a in arb_seqnum()) {
463 prop_assert!(a.before(a + MAX_PAYLOAD_AND_CONTROL_LEN));
464 prop_assert!(a.after(a + MAX_PAYLOAD_AND_CONTROL_LEN + 1));
465 }
466
467 #[test]
468 fn window_size_less_than_or_eq_to_max(wnd in 0..=WindowSize::MAX.0) {
469 prop_assert_eq!(WindowSize::from_u32(wnd), Some(WindowSize(wnd)));
470 }
471
472 #[test]
473 fn window_size_greater_than_max(wnd in WindowSize::MAX.0+1..=u32::MAX) {
474 prop_assert_eq!(WindowSize::from_u32(wnd), None);
475 }
476 }
477
478 #[test]
481 fn max_window_size() {
482 let window_size = UnscaledWindowSize(u16::MAX) << WindowScale::MAX;
485 assert!(window_size <= WindowSize::MAX, "actual={window_size:?}");
486
487 assert_eq!(WindowSize::MAX.scale(), WindowScale::MAX);
490 }
491
492 #[test]
495 fn seqnum_boundaries() {
496 assert!(SeqNum((1 << 31) - 1).after(SeqNum(0)));
497 assert!(!SeqNum((1 << 31) - 1).before(SeqNum(0)));
498 assert!(SeqNum(1 << 31).before(SeqNum(0)));
499 assert!(!SeqNum(1 << 31).after(SeqNum(0)));
500 }
501}