moqtap_session/
request_id.rs1use moqtap_codec::varint::VarInt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum Role {
6 Client,
8 Server,
10}
11
12#[derive(Debug, thiserror::Error, PartialEq, Eq)]
13pub enum RequestIdError {
14 #[error("request ID {0} exceeds max {1}")]
15 ExceedsMax(u64, u64),
16 #[error("request ID {0} has wrong parity for {1:?}")]
17 WrongParity(u64, Role),
18 #[error("max request ID can only increase: was {0}, got {1}")]
19 Decreased(u64, u64),
20 #[error("no request IDs available (blocked)")]
21 Blocked,
22}
23
24pub struct RequestIdAllocator {
31 role: Role,
32 next_id: u64,
33 max_id: u64,
34}
35
36impl RequestIdAllocator {
37 pub fn new(role: Role) -> Self {
38 let next_id = match role {
39 Role::Client => 0,
40 Role::Server => 1,
41 };
42 Self { role, next_id, max_id: 0 }
43 }
44
45 pub fn allocate(&mut self) -> Result<VarInt, RequestIdError> {
47 if self.max_id == 0 || self.next_id > self.max_id {
48 return Err(RequestIdError::Blocked);
49 }
50 let id = VarInt::from_u64(self.next_id).unwrap();
51 self.next_id += 2;
52 Ok(id)
53 }
54
55 pub fn update_max(&mut self, new_max: u64) -> Result<(), RequestIdError> {
57 if new_max <= self.max_id {
58 return Err(RequestIdError::Decreased(self.max_id, new_max));
59 }
60 self.max_id = new_max;
61 Ok(())
62 }
63
64 pub fn validate_peer_id(&self, id: u64) -> Result<(), RequestIdError> {
66 let expected_even = match self.role {
68 Role::Client => false, Role::Server => true, };
71 let is_even = id % 2 == 0;
72 if is_even != expected_even {
73 let peer_role = match self.role {
74 Role::Client => Role::Server,
75 Role::Server => Role::Client,
76 };
77 return Err(RequestIdError::WrongParity(id, peer_role));
78 }
79 if id > self.max_id {
80 return Err(RequestIdError::ExceedsMax(id, self.max_id));
81 }
82 Ok(())
83 }
84
85 pub fn is_blocked(&self) -> bool {
87 self.max_id == 0 || self.next_id > self.max_id
88 }
89
90 pub fn max_id(&self) -> u64 {
92 self.max_id
93 }
94}