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)]
26pub struct SeqNum(u32);
27
28impl ops::Add<i32> for SeqNum {
29 type Output = SeqNum;
30
31 fn add(self, rhs: i32) -> Self::Output {
32 let Self(lhs) = self;
33 Self(lhs.wrapping_add_signed(rhs))
34 }
35}
36
37impl ops::Sub<i32> for SeqNum {
38 type Output = SeqNum;
39
40 fn sub(self, rhs: i32) -> Self::Output {
41 let Self(lhs) = self;
42 Self(lhs.wrapping_add_signed(rhs.wrapping_neg()))
43 }
44}
45
46impl ops::Add<u32> for SeqNum {
47 type Output = SeqNum;
48
49 fn add(self, rhs: u32) -> Self::Output {
50 let Self(lhs) = self;
51 Self(lhs.wrapping_add(rhs))
52 }
53}
54
55impl ops::Sub<u32> for SeqNum {
56 type Output = SeqNum;
57
58 fn sub(self, rhs: u32) -> Self::Output {
59 let Self(lhs) = self;
60 Self(lhs.wrapping_sub(rhs))
61 }
62}
63
64impl ops::Sub<WindowSize> for SeqNum {
65 type Output = SeqNum;
66
67 fn sub(self, WindowSize(wnd): WindowSize) -> Self::Output {
68 self - i32::try_from(wnd).unwrap()
72 }
73}
74
75impl ops::Add<usize> for SeqNum {
76 type Output = SeqNum;
77
78 fn add(self, rhs: usize) -> Self::Output {
79 self + (rhs as u32)
87 }
88}
89
90impl ops::Sub for SeqNum {
91 type Output = i32;
94
95 fn sub(self, rhs: Self) -> Self::Output {
96 let Self(lhs) = self;
97 let Self(rhs) = rhs;
98 lhs.wrapping_sub(rhs) as i32
108 }
109}
110
111impl From<u32> for SeqNum {
112 fn from(x: u32) -> Self {
113 Self::new(x)
114 }
115}
116
117impl From<SeqNum> for u32 {
118 fn from(x: SeqNum) -> Self {
119 let SeqNum(x) = x;
120 x
121 }
122}
123
124impl SeqNum {
125 pub const fn new(x: u32) -> Self {
127 Self(x)
128 }
129}
130
131impl SeqNum {
132 pub fn before(self, other: SeqNum) -> bool {
136 self - other < 0
137 }
138
139 pub fn before_or_eq(self, other: SeqNum) -> bool {
144 self - other <= 0
145 }
146
147 pub fn after(self, other: SeqNum) -> bool {
151 self - other > 0
152 }
153
154 pub fn after_or_eq(self, other: SeqNum) -> bool {
159 self - other >= 0
160 }
161
162 pub fn earliest(self, other: SeqNum) -> SeqNum {
167 if self.before(other) {
168 self
169 } else {
170 other
171 }
172 }
173
174 pub fn latest(self, other: SeqNum) -> SeqNum {
179 if self.after(other) {
180 self
181 } else {
182 other
183 }
184 }
185}
186
187#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
196pub struct WindowSize(u32);
197
198impl WindowSize {
199 pub const MAX: WindowSize = WindowSize(1 << 30 - 1);
201 pub const ZERO: WindowSize = WindowSize(0);
203 pub const ONE: WindowSize = WindowSize(1);
205
206 pub const DEFAULT: WindowSize = WindowSize(65535);
210
211 pub const fn from_u32(wnd: u32) -> Option<Self> {
215 let WindowSize(max) = Self::MAX;
216 if wnd > max {
217 None
218 } else {
219 Some(Self(wnd))
220 }
221 }
222
223 pub fn saturating_add(self, rhs: u32) -> Self {
225 Self::from_u32(u32::from(self).saturating_add(rhs)).unwrap_or(Self::MAX)
226 }
227
228 pub fn new(wnd: usize) -> Option<Self> {
230 u32::try_from(wnd).ok_checked::<TryFromIntError>().and_then(WindowSize::from_u32)
231 }
232
233 pub fn checked_sub(self, diff: usize) -> Option<Self> {
235 usize::from(self).checked_sub(diff).and_then(Self::new)
241 }
242
243 pub fn saturating_sub(self, diff: usize) -> Self {
246 self.checked_sub(diff).unwrap_or(WindowSize::ZERO)
247 }
248
249 pub fn scale(self) -> WindowScale {
251 let WindowSize(size) = self;
252 let effective_bits = u8::try_from(32 - u32::leading_zeros(size)).unwrap();
253 let scale = WindowScale(effective_bits.saturating_sub(16));
254 scale
255 }
256
257 pub fn halved(self) -> WindowSize {
259 let WindowSize(size) = self;
260 WindowSize(size >> 1)
261 }
262}
263
264impl ops::Add<WindowSize> for SeqNum {
265 type Output = SeqNum;
266
267 fn add(self, WindowSize(wnd): WindowSize) -> Self::Output {
268 self + wnd
269 }
270}
271
272impl From<WindowSize> for u32 {
273 fn from(WindowSize(wnd): WindowSize) -> Self {
274 wnd
275 }
276}
277
278#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
279impl From<WindowSize> for usize {
280 fn from(WindowSize(wnd): WindowSize) -> Self {
281 wnd as usize
282 }
283}
284
285#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
286pub struct WindowScale(u8);
292
293impl WindowScale {
294 pub const MAX: WindowScale = WindowScale(14);
296 pub const ZERO: WindowScale = WindowScale(0);
298
299 pub fn new(ws: u8) -> Option<Self> {
303 (ws <= Self::MAX.get()).then_some(WindowScale(ws))
304 }
305
306 pub fn get(&self) -> u8 {
308 let Self(ws) = self;
309 *ws
310 }
311}
312
313#[derive(Debug, PartialEq, Eq, Clone, Copy)]
314pub struct UnscaledWindowSize(u16);
319
320impl ops::Shl<WindowScale> for UnscaledWindowSize {
321 type Output = WindowSize;
322
323 fn shl(self, WindowScale(scale): WindowScale) -> Self::Output {
324 let UnscaledWindowSize(size) = self;
325 WindowSize::from_u32(u32::from(size) << scale).unwrap()
327 }
328}
329
330impl ops::Shr<WindowScale> for WindowSize {
331 type Output = UnscaledWindowSize;
332
333 fn shr(self, WindowScale(scale): WindowScale) -> Self::Output {
334 let WindowSize(size) = self;
335 UnscaledWindowSize(u16::try_from(size >> scale).unwrap_or(u16::MAX))
336 }
337}
338
339impl From<u16> for UnscaledWindowSize {
340 fn from(value: u16) -> Self {
341 Self(value)
342 }
343}
344
345impl From<UnscaledWindowSize> for u16 {
346 fn from(UnscaledWindowSize(value): UnscaledWindowSize) -> Self {
347 value
348 }
349}
350
351#[cfg(feature = "testutils")]
352mod testutils {
353 use super::*;
354
355 impl UnscaledWindowSize {
356 pub fn from_usize(size: usize) -> Self {
360 UnscaledWindowSize::from(u16::try_from(size).unwrap())
361 }
362
363 pub fn from_u32(size: u32) -> Self {
367 UnscaledWindowSize::from(u16::try_from(size).unwrap())
368 }
369 }
370}
371
372#[cfg(test)]
373mod tests {
374 use alloc::format;
375
376 use proptest::arbitrary::any;
377 use proptest::strategy::{Just, Strategy};
378 use proptest::test_runner::Config;
379 use proptest::{prop_assert, prop_assert_eq, proptest};
380 use proptest_support::failed_seeds_no_std;
381 use test_case::test_case;
382
383 use super::super::segment::MAX_PAYLOAD_AND_CONTROL_LEN;
384 use super::*;
385
386 fn arb_seqnum() -> impl Strategy<Value = SeqNum> {
387 any::<u32>().prop_map(SeqNum::from)
388 }
389
390 fn arb_seqnum_trans_tripple() -> impl Strategy<Value = (SeqNum, SeqNum, SeqNum)> {
393 arb_seqnum().prop_flat_map(|a| {
394 (1..=MAX_PAYLOAD_AND_CONTROL_LEN).prop_flat_map(move |diff_a_b| {
395 let b = a + diff_a_b;
396 (1..=MAX_PAYLOAD_AND_CONTROL_LEN - diff_a_b).prop_flat_map(move |diff_b_c| {
397 let c = b + diff_b_c;
398 (Just(a), Just(b), Just(c))
399 })
400 })
401 })
402 }
403
404 #[test_case(WindowSize::new(1).unwrap() => (UnscaledWindowSize::from(1), WindowScale::default()))]
405 #[test_case(WindowSize::new(65535).unwrap() => (UnscaledWindowSize::from(65535), WindowScale::default()))]
406 #[test_case(WindowSize::new(65536).unwrap() => (UnscaledWindowSize::from(32768), WindowScale::new(1).unwrap()))]
407 #[test_case(WindowSize::new(65537).unwrap() => (UnscaledWindowSize::from(32768), WindowScale::new(1).unwrap()))]
408 fn window_scale(size: WindowSize) -> (UnscaledWindowSize, WindowScale) {
409 let scale = size.scale();
410 (size >> scale, scale)
411 }
412
413 proptest! {
414 #![proptest_config(Config {
415 failure_persistence: failed_seeds_no_std!(),
417 ..Config::default()
418 })]
419
420 #[test]
421 fn seqnum_ord_is_reflexive(a in arb_seqnum()) {
422 prop_assert_eq!(a, a)
423 }
424
425 #[test]
426 fn seqnum_ord_is_total(a in arb_seqnum(), b in arb_seqnum()) {
427 if a == b {
428 prop_assert!(!a.before(b) && !b.before(a))
429 } else {
430 prop_assert!(a.before(b) ^ b.before(a))
431 }
432 }
433
434 #[test]
435 fn seqnum_ord_is_transitive((a, b, c) in arb_seqnum_trans_tripple()) {
436 prop_assert!(a.before(b) && b.before(c) && a.before(c));
437 }
438
439 #[test]
440 fn seqnum_add_positive_greater(a in arb_seqnum(), b in 1..=i32::MAX) {
441 prop_assert!(a.before(a + b))
442 }
443
444 #[test]
445 fn seqnum_add_negative_smaller(a in arb_seqnum(), b in i32::MIN..=-1) {
446 prop_assert!(a.after(a + b))
447 }
448
449 #[test]
450 fn seqnum_sub_positive_smaller(a in arb_seqnum(), b in 1..=i32::MAX) {
451 prop_assert!(a.after(a - b))
452 }
453
454 #[test]
455 fn seqnum_sub_negative_greater(a in arb_seqnum(), b in i32::MIN..=-1) {
456 prop_assert!(a.before(a - b))
457 }
458
459 #[test]
460 fn seqnum_zero_identity(a in arb_seqnum()) {
461 prop_assert_eq!(a, a + 0)
462 }
463
464 #[test]
465 fn seqnum_before_after_inverse(a in arb_seqnum(), b in arb_seqnum()) {
466 prop_assert_eq!(a.after(b), b.before(a))
467 }
468
469 #[test]
470 fn seqnum_wraps_around_at_max_length(a in arb_seqnum()) {
471 prop_assert!(a.before(a + MAX_PAYLOAD_AND_CONTROL_LEN));
472 prop_assert!(a.after(a + MAX_PAYLOAD_AND_CONTROL_LEN + 1));
473 }
474
475 #[test]
476 fn window_size_less_than_or_eq_to_max(wnd in 0..=WindowSize::MAX.0) {
477 prop_assert_eq!(WindowSize::from_u32(wnd), Some(WindowSize(wnd)));
478 }
479
480 #[test]
481 fn window_size_greater_than_max(wnd in WindowSize::MAX.0+1..=u32::MAX) {
482 prop_assert_eq!(WindowSize::from_u32(wnd), None);
483 }
484 }
485}