channels_packet/
seq.rs

1/// A 6-bit frame number.
2#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3pub struct FrameNum(u8);
4
5impl FrameNum {
6	/// Create a new [`FrameNum`] from `num`.
7	///
8	/// Only the lower 6 bits of `num` will be used.
9	#[inline]
10	#[must_use]
11	pub const fn new(num: u8) -> Self {
12		Self(num & 0b0011_1111)
13	}
14
15	/// Get the frame number.
16	///
17	/// Frame numbers are only 6 bits in length so the upper 2 bits of the returned value
18	/// can be safely ignored.
19	#[inline]
20	#[must_use]
21	pub const fn get(&self) -> u8 {
22		self.0
23	}
24}
25
26/// An endless sequence of consecutive frame numbers.
27///
28/// This sequence will yield frame numbers for consecutive frames. Each frame number is
29/// calculated by incrementing the number of the previous frame by one and wrapping around
30/// on overflow. Being 6 bits in size, frame numbers can only go up to 63 and thus the sequence
31/// has a period of 64. Skipping frame numbers is considered bad practice.
32#[derive(Debug, Clone)]
33pub struct FrameNumSequence {
34	state: u8,
35}
36
37impl FrameNumSequence {
38	/// Create a new sequence that starts at `x`.
39	#[inline]
40	#[must_use]
41	pub const fn starting_at(x: u8) -> Self {
42		Self { state: x }
43	}
44
45	/// Create a new frame number sequence starting at 0.
46	#[inline]
47	#[must_use]
48	pub const fn new() -> Self {
49		Self::starting_at(0)
50	}
51
52	/// Return the next frame number in the sequence and advance it by one.
53	#[inline]
54	#[must_use = "unused frame number"]
55	pub fn advance(&mut self) -> FrameNum {
56		let x = self.peek();
57		self.state = self.state.wrapping_add(1);
58		x
59	}
60
61	/// Peek at the next frame number in the sequence without advancing it.
62	#[inline]
63	#[must_use]
64	pub const fn peek(&self) -> FrameNum {
65		self.peek_n(1)
66	}
67
68	/// Peek at the n-th next frame number in the sequence without advancing it.
69	///
70	/// # Panics
71	///
72	/// If `n` is 0.
73	#[allow(clippy::cast_possible_truncation)]
74	#[inline]
75	#[must_use]
76	pub const fn peek_n(&self, n: usize) -> FrameNum {
77		assert!(n >= 1, "n must be greater or equal to 1");
78		FrameNum::new(self.state.wrapping_add((n - 1) as u8))
79	}
80}
81
82impl Default for FrameNumSequence {
83	fn default() -> Self {
84		Self::new()
85	}
86}
87
88impl Iterator for FrameNumSequence {
89	type Item = FrameNum;
90
91	#[inline]
92	fn next(&mut self) -> Option<Self::Item> {
93		Some(self.advance())
94	}
95}
96
97#[cfg(test)]
98mod tests {
99	use super::*;
100
101	const N: usize = 512;
102
103	#[test]
104	#[allow(clippy::cast_possible_truncation)]
105	fn test_sequence() {
106		let seq = FrameNumSequence::new().take(N);
107		let expected = (0..N).map(|x| x as u8).map(FrameNum::new);
108
109		assert!(seq.eq(expected));
110	}
111
112	#[test]
113	fn test_sequence_peek() {
114		let mut seq = FrameNumSequence::new();
115
116		for _ in 0..N {
117			let peeked = seq.peek();
118			let next = seq.advance();
119			assert_eq!(peeked, next);
120		}
121	}
122}