moq_uring/quic/noq/
stream.rs1use std::task::{Context, Poll};
9
10use bytes::{Buf, Bytes, BytesMut};
11use moq_noq_proto::{StreamId, VarInt};
12
13use super::super::Error;
14use super::{End, Shared};
15
16pub struct SendStream {
18 shared: Shared,
19 id: StreamId,
20 park: kio::Park,
21 fin: bool,
24 reset: bool,
26}
27
28impl SendStream {
29 pub(crate) fn new(shared: Shared, id: StreamId) -> Self {
30 shared.track(id);
33 Self {
34 shared,
35 id,
36 park: kio::Park::default(),
37 fin: false,
38 reset: false,
39 }
40 }
41
42 pub(crate) fn id(&self) -> u64 {
44 self.id.into()
45 }
46
47 pub(crate) fn ended(&self) -> bool {
51 self.fin || self.reset
52 }
53
54 pub(crate) fn try_write(&mut self, buf: &[u8]) -> usize {
57 if self.fin || self.reset {
58 return 0;
59 }
60 let n = self
61 .shared
62 .conn
63 .borrow_mut()
64 .send_stream(self.id)
65 .write(buf)
66 .unwrap_or(0);
67 if n > 0 {
68 self.shared.kick();
69 }
70 n
71 }
72
73 pub(crate) fn reset_code(&mut self, code: u64) {
76 if self.reset {
77 return;
78 }
79 let _ = self
81 .shared
82 .conn
83 .borrow_mut()
84 .send_stream(self.id)
85 .reset(VarInt::from_u64(code).unwrap_or(VarInt::MAX));
86 self.reset = true;
87 self.shared.kick();
88 }
89}
90
91impl web_transport_trait::poll::SendStream for SendStream {
92 type Error = Error;
93
94 fn poll_write(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, Self::Error>> {
95 let waiter = self.park.hold(cx);
96 if self.fin || self.reset {
97 return Poll::Ready(Err(Error::Quic("stream already finished".to_string())));
98 }
99 if let Some(err) = self.shared.closed() {
100 return Poll::Ready(Err(err));
101 }
102 let result = self.shared.conn.borrow_mut().send_stream(self.id).write(buf);
103 match result {
104 Ok(n) => {
105 self.shared.kick();
106 Poll::Ready(Ok(n))
107 }
108 Err(moq_noq_proto::WriteError::Blocked) => {
111 self.shared.park_writable(self.id, waiter);
112 Poll::Pending
113 }
114 Err(moq_noq_proto::WriteError::Stopped(code)) => Poll::Ready(Err(Error::Stop(code.into_inner()))),
115 Err(moq_noq_proto::WriteError::ClosedStream) => {
116 Poll::Ready(Err(Error::Quic("stream already finished".to_string())))
117 }
118 }
119 }
120
121 fn set_priority(&mut self, order: u8) {
122 let _ = self
125 .shared
126 .conn
127 .borrow_mut()
128 .send_stream(self.id)
129 .set_priority(i32::from(order));
130 }
131
132 fn finish(&mut self) -> Result<(), Self::Error> {
133 if self.fin || self.reset {
134 return Ok(());
135 }
136 match self.shared.conn.borrow_mut().send_stream(self.id).finish() {
137 Ok(()) => {}
138 Err(moq_noq_proto::FinishError::Stopped(code)) => {
142 self.reset = true;
143 return Err(Error::Stop(code.into_inner()));
144 }
145 Err(moq_noq_proto::FinishError::ClosedStream) => {}
147 }
148 self.fin = true;
149 self.shared.kick();
150 Ok(())
151 }
152
153 fn reset(&mut self, code: u32) {
154 self.reset_code(u64::from(code));
155 }
156
157 fn poll_closed(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
158 let waiter = self.park.hold(cx);
159 if self.reset {
160 return Poll::Ready(Ok(()));
161 }
162 match self.shared.ended(self.id) {
165 Some(End::Stopped(code)) => Poll::Ready(Err(Error::Stop(code))),
166 Some(End::Delivered) => Poll::Ready(Ok(())),
167 None => match self.shared.closed() {
170 Some(err) => Poll::Ready(Err(err)),
171 None => {
172 self.shared.park_finishing(self.id, waiter);
173 Poll::Pending
174 }
175 },
176 }
177 }
178}
179
180impl Drop for SendStream {
181 fn drop(&mut self) {
182 self.shared.forget_send(self.id);
183 if !self.fin && !self.reset {
184 let _ = self
185 .shared
186 .conn
187 .borrow_mut()
188 .send_stream(self.id)
189 .reset(VarInt::from_u32(0));
190 self.shared.kick();
191 }
192 }
193}
194
195impl std::fmt::Debug for SendStream {
196 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
197 f.debug_struct("SendStream").field("id", &self.id).finish()
198 }
199}
200
201const READ_AHEAD: usize = 64 * 1024;
204const READ_CHUNK: usize = 8 * 1024;
206
207enum Read {
209 Chunk(Bytes),
211 Finished,
213 Blocked,
215 Reset(u64),
217}
218
219pub struct RecvStream {
221 shared: Shared,
222 id: StreamId,
223 park: kio::Park,
224 finished: bool,
227 stopped: bool,
229 backlog: BytesMut,
231}
232
233impl RecvStream {
234 pub(crate) fn new(shared: Shared, id: StreamId) -> Self {
235 Self {
236 shared,
237 id,
238 park: kio::Park::default(),
239 finished: false,
240 stopped: false,
241 backlog: BytesMut::new(),
242 }
243 }
244
245 pub(crate) fn ended(&self) -> bool {
248 self.finished || self.stopped
249 }
250
251 pub(crate) fn stop_code(&mut self, code: u64) {
254 self.backlog.clear();
255 if self.stopped || self.finished {
256 return;
257 }
258 let _ = self
260 .shared
261 .conn
262 .borrow_mut()
263 .recv_stream(self.id)
264 .stop(VarInt::from_u64(code).unwrap_or(VarInt::MAX));
265 self.stopped = true;
266 self.shared.kick();
267 }
268
269 fn read(shared: &Shared, id: StreamId, max: usize) -> Read {
277 let mut conn = shared.conn.borrow_mut();
278 let mut recv = conn.recv_stream(id);
279 let mut chunks = match recv.read(true) {
280 Ok(chunks) => chunks,
281 Err(_) => return Read::Finished,
283 };
284 let read = match chunks.next(max) {
285 Ok(Some(chunk)) => Read::Chunk(chunk.bytes),
286 Ok(None) => Read::Finished,
287 Err(moq_noq_proto::ReadError::Blocked) => Read::Blocked,
288 Err(moq_noq_proto::ReadError::Reset(code)) => Read::Reset(code.into_inner()),
289 };
290 let transmit = chunks.finalize().should_transmit();
291 drop(conn);
292 if transmit {
293 shared.kick();
294 }
295 read
296 }
297
298 fn drain(&mut self, dst: &mut [u8]) -> usize {
303 let n = dst.len().min(self.backlog.len());
304 dst[..n].copy_from_slice(&self.backlog[..n]);
305 self.backlog.advance(n);
306 if n > 0 {
307 self.shared.wake_readable(self.id);
308 }
309 n
310 }
311}
312
313impl web_transport_trait::poll::RecvStream for RecvStream {
314 type Error = Error;
315
316 fn poll_read(&mut self, cx: &mut Context<'_>, dst: &mut [u8]) -> Poll<Result<Option<usize>, Self::Error>> {
317 let waiter = self.park.hold(cx);
318 if dst.is_empty() {
319 return Poll::Ready(Ok(Some(0)));
320 }
321 if !self.backlog.is_empty() {
322 return Poll::Ready(Ok(Some(self.drain(dst))));
323 }
324 if self.finished {
325 return Poll::Ready(Ok(None));
326 }
327 match Self::read(&self.shared, self.id, dst.len()) {
328 Read::Chunk(bytes) => {
329 let n = bytes.len().min(dst.len());
330 dst[..n].copy_from_slice(&bytes[..n]);
331 Poll::Ready(Ok(Some(n)))
332 }
333 Read::Finished => {
334 self.finished = true;
335 Poll::Ready(Ok(None))
336 }
337 Read::Blocked => {
338 if let Some(err) = self.shared.closed() {
339 return Poll::Ready(Err(err));
340 }
341 self.shared.park_readable(self.id, waiter);
342 Poll::Pending
343 }
344 Read::Reset(code) => Poll::Ready(Err(Error::Reset(code))),
345 }
346 }
347
348 fn stop(&mut self, code: u32) {
349 self.stop_code(u64::from(code));
352 }
353
354 fn poll_closed(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
355 let waiter = self.park.hold(cx);
356 if self.finished || self.stopped {
357 return Poll::Ready(Ok(()));
358 }
359 loop {
366 if self.backlog.len() >= READ_AHEAD {
367 self.shared.park_readable(self.id, waiter);
373 return Poll::Pending;
374 }
375 match Self::read(&self.shared, self.id, READ_CHUNK) {
376 Read::Chunk(bytes) => self.backlog.extend_from_slice(&bytes),
377 Read::Finished => {
378 self.finished = true;
379 return Poll::Ready(Ok(()));
380 }
381 Read::Blocked => {
382 if let Some(err) = self.shared.closed() {
383 return Poll::Ready(Err(err));
384 }
385 self.shared.park_readable(self.id, waiter);
386 return Poll::Pending;
387 }
388 Read::Reset(code) => return Poll::Ready(Err(Error::Reset(code))),
389 }
390 }
391 }
392}
393
394impl Drop for RecvStream {
395 fn drop(&mut self) {
396 self.shared.forget_recv(self.id);
397 if !self.finished && !self.stopped {
398 let _ = self
399 .shared
400 .conn
401 .borrow_mut()
402 .recv_stream(self.id)
403 .stop(VarInt::from_u32(0));
404 self.shared.kick();
405 }
406 }
407}
408
409impl std::fmt::Debug for RecvStream {
410 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
411 f.debug_struct("RecvStream").field("id", &self.id).finish()
412 }
413}