miku_h2/frame/
priority.rs

1use bytes::BufMut;
2
3use crate::frame::*;
4
5#[derive(Debug, Copy, Clone, Eq, PartialEq)]
6/// The PRIORITY frame (type=0x2) specifies the sender-advised priority
7/// of a stream [Section 5.3].  It can be sent in any stream state,
8/// including idle or closed streams.
9/// [Section 5.3]: https://tools.ietf.org/html/rfc7540#section-5.3
10pub struct Priority {
11    /// The stream ID of the stream that this priority frame is for
12    stream_id: StreamId,
13
14    /// The stream dependency target
15    dependency: StreamDependency,
16}
17
18#[derive(Debug, Copy, Clone, Eq, PartialEq)]
19pub struct StreamDependency {
20    /// The ID of the stream dependency target
21    dependency_id: StreamId,
22
23    /// The weight for the stream. The value exposed (and set) here is always in
24    /// the range [0, 255], instead of [1, 256] (as defined in section 5.3.2.)
25    /// so that the value fits into a `u8`.
26    weight: u8,
27
28    /// True if the stream dependency is exclusive.
29    is_exclusive: bool,
30}
31
32// ===== impl Priority =====
33
34impl Priority {
35    /// Create a new priority frame
36    pub fn new(stream_id: StreamId, dependency: StreamDependency) -> Self {
37        assert!(stream_id != 0);
38        Priority {
39            stream_id,
40            dependency,
41        }
42    }
43
44    /// Loads the priority frame but doesn't actually do HPACK decoding.
45    pub fn load(head: Head, payload: &[u8]) -> Result<Self, Error> {
46        let dependency = StreamDependency::load(payload)?;
47
48        if dependency.dependency_id() == head.stream_id() {
49            return Err(Error::InvalidDependencyId);
50        }
51
52        Ok(Priority {
53            stream_id: head.stream_id(),
54            dependency,
55        })
56    }
57
58    pub fn head(&self) -> Head {
59        Head::new(Kind::Priority, 0, self.stream_id)
60    }
61
62    pub fn stream_id(&self) -> StreamId {
63        self.stream_id
64    }
65
66    pub fn encode<B: BufMut>(&self, dst: &mut B) {
67        let head = self.head();
68        head.encode(5, dst);
69
70        // Priority frame payload is exactly 5 bytes
71        // Format:
72        // +---------------+
73        // |E|  Dep ID (31)|
74        // +---------------+
75        // |   Weight (8)  |
76        // +---------------+
77        self.dependency.encode(dst);
78    }
79}
80
81impl<B> From<Priority> for Frame<B> {
82    fn from(src: Priority) -> Self {
83        Frame::Priority(src)
84    }
85}
86
87// ===== impl StreamDependency =====
88
89impl StreamDependency {
90    /// Create a new stream dependency
91    pub fn new(dependency_id: StreamId, weight: u8, is_exclusive: bool) -> Self {
92        StreamDependency {
93            dependency_id,
94            weight,
95            is_exclusive,
96        }
97    }
98
99    /// Loads the stream dependency from a buffer
100    pub fn load(src: &[u8]) -> Result<Self, Error> {
101        if src.len() != 5 {
102            return Err(Error::InvalidPayloadLength);
103        }
104
105        // Parse the stream ID and exclusive flag
106        let (dependency_id, is_exclusive) = StreamId::parse(&src[..4]);
107
108        // Read the weight
109        let weight = src[4];
110
111        Ok(StreamDependency::new(dependency_id, weight, is_exclusive))
112    }
113
114    pub fn dependency_id(&self) -> StreamId {
115        self.dependency_id
116    }
117
118    pub fn weight(&self) -> u8 {
119        self.weight
120    }
121
122    pub fn is_exclusive(&self) -> bool {
123        self.is_exclusive
124    }
125
126    pub fn encode<T: BufMut>(&self, dst: &mut T) {
127        let dependency_id: u32 = self.dependency_id().into();
128
129        let mut buf = dependency_id.to_be_bytes();
130
131        if self.is_exclusive {
132            buf[0] |= 0x80;
133        }
134
135        dst.put_slice(&buf);
136        dst.put_u8(self.weight);
137    }
138}
139
140mod tests {
141
142    #[test]
143    fn test_priority_frame() {
144        use crate::frame::{self, Priority, StreamDependency, StreamId};
145
146        let mut dependency_buf = Vec::new();
147        let dependency = StreamDependency::new(StreamId::zero(), 201, false);
148        dependency.encode(&mut dependency_buf);
149        let dependency = StreamDependency::load(&dependency_buf).unwrap();
150        assert_eq!(dependency.dependency_id(), StreamId::zero());
151        assert_eq!(dependency.weight(), 201);
152        assert!(!dependency.is_exclusive());
153
154        let priority = Priority::new(StreamId::from(3), dependency);
155        let mut priority_buf = Vec::new();
156        priority.encode(&mut priority_buf);
157        let priority = Priority::load(priority.head(), &priority_buf[frame::HEADER_LEN..]).unwrap();
158        assert_eq!(priority.stream_id(), StreamId::from(3));
159        assert_eq!(priority.dependency.dependency_id(), StreamId::zero());
160        assert_eq!(priority.dependency.weight(), 201);
161        assert!(!priority.dependency.is_exclusive());
162    }
163}