1 use std::u32; 2 3 /// A stream identifier, as described in [Section 5.1.1] of RFC 7540. 4 /// 5 /// Streams are identified with an unsigned 31-bit integer. Streams 6 /// initiated by a client MUST use odd-numbered stream identifiers; those 7 /// initiated by the server MUST use even-numbered stream identifiers. A 8 /// stream identifier of zero (0x0) is used for connection control 9 /// messages; the stream identifier of zero cannot be used to establish a 10 /// new stream. 11 /// 12 /// [Section 5.1.1]: https://tools.ietf.org/html/rfc7540#section-5.1.1 13 #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] 14 pub struct StreamId(u32); 15 16 #[derive(Debug, Copy, Clone)] 17 pub struct StreamIdOverflow; 18 19 const STREAM_ID_MASK: u32 = 1 << 31; 20 21 impl StreamId { 22 /// Stream ID 0. 23 pub const ZERO: StreamId = StreamId(0); 24 25 /// The maximum allowed stream ID. 26 pub const MAX: StreamId = StreamId(u32::MAX >> 1); 27 28 /// Parse the stream ID 29 #[inline] parse(buf: &[u8]) -> (StreamId, bool)30 pub fn parse(buf: &[u8]) -> (StreamId, bool) { 31 let mut ubuf = [0; 4]; 32 ubuf.copy_from_slice(&buf[0..4]); 33 let unpacked = u32::from_be_bytes(ubuf); 34 let flag = unpacked & STREAM_ID_MASK == STREAM_ID_MASK; 35 36 // Now clear the most significant bit, as that is reserved and MUST be 37 // ignored when received. 38 (StreamId(unpacked & !STREAM_ID_MASK), flag) 39 } 40 41 /// Returns true if this stream ID corresponds to a stream that 42 /// was initiated by the client. is_client_initiated(&self) -> bool43 pub fn is_client_initiated(&self) -> bool { 44 let id = self.0; 45 id != 0 && id % 2 == 1 46 } 47 48 /// Returns true if this stream ID corresponds to a stream that 49 /// was initiated by the server. is_server_initiated(&self) -> bool50 pub fn is_server_initiated(&self) -> bool { 51 let id = self.0; 52 id != 0 && id % 2 == 0 53 } 54 55 /// Return a new `StreamId` for stream 0. 56 #[inline] zero() -> StreamId57 pub fn zero() -> StreamId { 58 StreamId::ZERO 59 } 60 61 /// Returns true if this stream ID is zero. is_zero(&self) -> bool62 pub fn is_zero(&self) -> bool { 63 self.0 == 0 64 } 65 66 /// Returns the next stream ID initiated by the same peer as this stream 67 /// ID, or an error if incrementing this stream ID would overflow the 68 /// maximum. next_id(&self) -> Result<StreamId, StreamIdOverflow>69 pub fn next_id(&self) -> Result<StreamId, StreamIdOverflow> { 70 let next = self.0 + 2; 71 if next > StreamId::MAX.0 { 72 Err(StreamIdOverflow) 73 } else { 74 Ok(StreamId(next)) 75 } 76 } 77 } 78 79 impl From<u32> for StreamId { from(src: u32) -> Self80 fn from(src: u32) -> Self { 81 assert_eq!(src & STREAM_ID_MASK, 0, "invalid stream ID -- MSB is set"); 82 StreamId(src) 83 } 84 } 85 86 impl From<StreamId> for u32 { from(src: StreamId) -> Self87 fn from(src: StreamId) -> Self { 88 src.0 89 } 90 } 91 92 impl PartialEq<u32> for StreamId { eq(&self, other: &u32) -> bool93 fn eq(&self, other: &u32) -> bool { 94 self.0 == *other 95 } 96 } 97