http3_datagram/
datagram.rs1use bytes::Buf;
2use http3::{
3 error::{Code, internal_error::InternalConnectionError},
4 proto::varint::VarInt,
5 quic::StreamId,
6};
7
8#[derive(Debug, Clone)]
11pub struct Datagram<B> {
12 stream_id: StreamId,
14 payload: B,
16}
17
18impl<B> Datagram<B>
19where
20 B: Buf,
21{
22 #[allow(unknown_lints, clippy::manual_is_multiple_of)]
25 pub fn new(stream_id: StreamId, payload: B) -> Self {
26 assert!(
27 stream_id.into_inner() % 4 == 0,
28 "StreamId is not divisible by 4"
29 );
30 Self { stream_id, payload }
32 }
33
34 pub fn decode(mut buf: B) -> Result<Self, InternalConnectionError> {
36 let q_stream_id = VarInt::decode(&mut buf).map_err(|_| {
37 InternalConnectionError::new(Code::H3_DATAGRAM_ERROR, "invalid stream id".to_string())
38 })?;
39
40 let stream_id = StreamId::try_from(u64::from(q_stream_id) * 4).map_err(|_| {
50 InternalConnectionError::new(Code::H3_DATAGRAM_ERROR, "invalid stream id".to_string())
51 })?;
52
53 let payload = buf;
54
55 Ok(Self { stream_id, payload })
56 }
57
58 #[inline]
59 pub fn stream_id(&self) -> StreamId {
61 self.stream_id
62 }
63
64 #[inline]
65 pub fn payload(&self) -> &B {
67 &self.payload
68 }
69
70 pub fn encode(self) -> EncodedDatagram<B> {
72 let mut buffer = [0; VarInt::MAX_SIZE];
73 let varint = VarInt::from(self.stream_id) / 4;
74 varint.encode(&mut buffer.as_mut_slice());
75 EncodedDatagram {
76 stream_id: [0; VarInt::MAX_SIZE],
77 len: varint.size(),
78 pos: 0,
79 payload: self.payload,
80 }
81 }
82
83 pub fn into_payload(self) -> B {
85 self.payload
86 }
87}
88
89#[derive(Debug)]
90pub struct EncodedDatagram<B: Buf> {
91 stream_id: [u8; VarInt::MAX_SIZE],
93 len: usize,
95 pos: usize,
97 payload: B,
99}
100
101impl<B> Buf for EncodedDatagram<B>
103where
104 B: Buf,
105{
106 fn remaining(&self) -> usize {
107 self.len - self.pos + self.payload.remaining()
108 }
109
110 fn chunk(&self) -> &[u8] {
111 if self.len - self.pos > 0 {
112 &self.stream_id[self.pos..self.len]
113 } else {
114 self.payload.chunk()
115 }
116 }
117
118 fn advance(&mut self, mut cnt: usize) {
119 let remaining_header = self.len - self.pos;
120 if remaining_header > 0 {
121 let advanced = usize::min(cnt, remaining_header);
122 self.pos += advanced;
123 cnt -= advanced;
124 }
125 self.payload.advance(cnt);
126 }
127}