1use pin_project_lite::pin_project;
2use std::{
3 io::{Cursor, Read},
4 pin::Pin,
5 task::{Context, Poll, ready},
6};
7use tokio::io::{self, AsyncBufRead, AsyncRead, ReadBuf};
8
9use crate::bytes::{Buf, Bytes};
10
11pub async fn discard<R>(reader: &mut R, n: u64) -> io::Result<()>
20where
21 R: AsyncRead + Unpin,
22{
23 if n == 0 {
24 return Ok(());
25 }
26 let mut limited = tokio::io::AsyncReadExt::take(reader, n);
27 let copied = tokio::io::copy(&mut limited, &mut tokio::io::sink()).await?;
28 if copied < n {
29 return Err(io::Error::new(
30 io::ErrorKind::UnexpectedEof,
31 "io::discard: reader EOF before requested byte count was consumed",
32 ));
33 }
34 Ok(())
35}
36
37pin_project! {
38 #[derive(Debug, Clone)]
40 pub struct HeapReader {
41 #[pin]
42 inner: Cursor<Vec<u8>>,
43 }
44}
45
46impl HeapReader {
47 #[must_use]
49 pub const fn new(data: Vec<u8>) -> Self {
50 Self {
51 inner: Cursor::new(data),
52 }
53 }
54
55 #[must_use]
57 pub fn remaining(&self) -> usize {
58 self.inner.remaining()
59 }
60
61 #[must_use]
63 pub fn has_remaining(&self) -> bool {
64 self.inner.has_remaining()
65 }
66}
67
68impl From<Vec<u8>> for HeapReader {
69 fn from(data: Vec<u8>) -> Self {
70 Self::new(data)
71 }
72}
73
74impl From<&[u8]> for HeapReader {
75 fn from(data: &[u8]) -> Self {
76 Self::new(data.to_vec())
77 }
78}
79
80impl From<&str> for HeapReader {
81 fn from(data: &str) -> Self {
82 Self::new(data.as_bytes().to_vec())
83 }
84}
85
86impl Default for HeapReader {
87 fn default() -> Self {
88 Self::new(Vec::new())
89 }
90}
91
92impl From<Bytes> for HeapReader {
93 fn from(data: Bytes) -> Self {
94 Self::new(data.to_vec())
95 }
96}
97
98#[warn(clippy::missing_trait_methods)]
99impl AsyncRead for HeapReader {
100 fn poll_read(
101 self: Pin<&mut Self>,
102 cx: &mut Context<'_>,
103 buf: &mut ReadBuf<'_>,
104 ) -> Poll<io::Result<()>> {
105 self.project().inner.poll_read(cx, buf)
106 }
107}
108
109#[warn(clippy::missing_trait_methods)]
110impl AsyncBufRead for HeapReader {
111 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
112 self.project().inner.poll_fill_buf(cx)
113 }
114
115 fn consume(self: Pin<&mut Self>, amt: usize) {
116 self.project().inner.consume(amt);
117 }
118}
119
120impl Read for HeapReader {
121 #[inline]
122 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
123 self.inner.read(buf)
124 }
125
126 #[inline]
127 fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
128 self.inner.read_exact(buf)
129 }
130
131 #[inline]
132 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
133 self.inner.read_to_end(buf)
134 }
135
136 #[inline]
137 fn read_to_string(&mut self, buf: &mut String) -> std::io::Result<usize> {
138 self.inner.read_to_string(buf)
139 }
140
141 #[inline]
142 fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result<usize> {
143 self.inner.read_vectored(bufs)
144 }
145}
146
147#[derive(Debug, Clone)]
149pub struct StackReader<const N: usize> {
150 data: [u8; N],
151 offset: usize,
152}
153
154impl<const N: usize> StackReader<N> {
155 #[must_use]
157 pub const fn new(data: [u8; N]) -> Self {
158 Self { data, offset: 0 }
159 }
160
161 pub fn skip(&mut self, n: usize) {
163 self.offset = (self.offset + n).min(N);
164 }
165
166 #[must_use]
168 pub fn remaining(&self) -> usize {
169 N - self.offset
170 }
171
172 #[must_use]
174 pub fn has_remaining(&self) -> bool {
175 self.remaining() > 0
176 }
177}
178
179impl<const N: usize> From<[u8; N]> for StackReader<N> {
180 #[inline]
181 fn from(data: [u8; N]) -> Self {
182 Self::new(data)
183 }
184}
185
186impl<const N: usize> AsyncRead for StackReader<N> {
187 fn poll_read(
188 mut self: Pin<&mut Self>,
189 _cx: &mut Context<'_>,
190 buf: &mut ReadBuf<'_>,
191 ) -> Poll<io::Result<()>> {
192 if self.offset < N {
193 let remaining = &self.data[self.offset..];
194 let to_copy = remaining.len().min(buf.remaining());
195
196 if to_copy > 0 {
197 buf.put_slice(&remaining[..to_copy]);
198 self.offset += to_copy;
199 }
200 }
201
202 Poll::Ready(Ok(()))
204 }
205}
206
207impl<const N: usize> AsyncBufRead for StackReader<N> {
208 fn poll_fill_buf(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
209 let me = self.get_mut();
210 Poll::Ready(Ok(if me.offset < N {
211 &me.data[me.offset..]
212 } else {
213 &[]
214 }))
215 }
216
217 fn consume(self: Pin<&mut Self>, amt: usize) {
218 self.get_mut().skip(amt)
219 }
220}
221
222impl<const N: usize> Read for StackReader<N> {
223 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
224 if self.offset < N {
225 let remaining = &self.data[self.offset..];
226 let to_copy = remaining.len().min(buf.len());
227
228 if to_copy > 0 {
229 buf[..to_copy].copy_from_slice(&remaining[..to_copy]);
230 self.offset += to_copy;
231 return Ok(to_copy);
232 }
233 }
234
235 Ok(0)
237 }
238}
239
240#[derive(Debug, Clone, Default)]
248pub struct ReplayReader {
249 data: Bytes,
250}
251
252impl ReplayReader {
253 #[must_use]
255 pub const fn new(data: Bytes) -> Self {
256 Self { data }
257 }
258
259 #[must_use]
261 pub fn remaining(&self) -> usize {
262 self.data.len()
263 }
264
265 #[must_use]
267 pub fn has_remaining(&self) -> bool {
268 !self.data.is_empty()
269 }
270
271 fn advance(&mut self, n: usize) {
272 if n >= self.data.len() {
273 self.data = Bytes::new();
275 } else {
276 self.data.advance(n);
277 }
278 }
279}
280
281impl From<Bytes> for ReplayReader {
282 #[inline]
283 fn from(data: Bytes) -> Self {
284 Self::new(data)
285 }
286}
287
288impl AsyncRead for ReplayReader {
289 fn poll_read(
290 mut self: Pin<&mut Self>,
291 _cx: &mut Context<'_>,
292 buf: &mut ReadBuf<'_>,
293 ) -> Poll<io::Result<()>> {
294 let to_copy = self.data.len().min(buf.remaining());
295 if to_copy > 0 {
296 buf.put_slice(&self.data[..to_copy]);
297 self.advance(to_copy);
298 }
299
300 Poll::Ready(Ok(()))
302 }
303}
304
305impl AsyncBufRead for ReplayReader {
306 fn poll_fill_buf(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
307 Poll::Ready(Ok(&self.get_mut().data))
308 }
309
310 fn consume(self: Pin<&mut Self>, amt: usize) {
311 self.get_mut().advance(amt);
312 }
313}
314
315impl Read for ReplayReader {
316 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
317 let to_copy = self.data.len().min(buf.len());
318 if to_copy > 0 {
319 buf[..to_copy].copy_from_slice(&self.data[..to_copy]);
320 self.advance(to_copy);
321 }
322
323 Ok(to_copy)
325 }
326}
327
328pin_project! {
329 #[must_use = "streams do nothing unless polled"]
331 #[derive(Debug, Clone)]
332 pub struct ChainReader<T, U> {
333 #[pin]
334 first: T,
335 #[pin]
336 second: U,
337 done_first: bool,
338 }
339}
340
341impl<T, U> ChainReader<T, U>
342where
343 T: AsyncRead,
344 U: AsyncRead,
345{
346 pub const fn new(first: T, second: U) -> Self {
348 Self {
349 first,
350 second,
351 done_first: false,
352 }
353 }
354
355 pub fn get_ref(&self) -> (&T, &U) {
357 (&self.first, &self.second)
358 }
359
360 pub fn get_mut(&mut self) -> (&mut T, &mut U) {
366 (&mut self.first, &mut self.second)
367 }
368
369 #[must_use]
375 pub fn get_pin_mut(self: Pin<&mut Self>) -> (Pin<&mut T>, Pin<&mut U>) {
376 let me = self.project();
377 (me.first, me.second)
378 }
379
380 pub fn into_inner(self) -> (T, U) {
382 (self.first, self.second)
383 }
384}
385
386impl<T, U> AsyncRead for ChainReader<T, U>
387where
388 T: AsyncRead,
389 U: AsyncRead,
390{
391 fn poll_read(
392 self: Pin<&mut Self>,
393 cx: &mut Context<'_>,
394 buf: &mut ReadBuf<'_>,
395 ) -> Poll<io::Result<()>> {
396 let me = self.project();
397
398 if !*me.done_first {
399 let rem = buf.remaining();
400 ready!(me.first.poll_read(cx, buf))?;
401 if buf.remaining() == rem {
402 *me.done_first = true;
403 } else {
404 return Poll::Ready(Ok(()));
405 }
406 }
407 me.second.poll_read(cx, buf)
408 }
409}
410
411impl<T, U> Read for ChainReader<T, U>
412where
413 T: Read,
414 U: Read,
415{
416 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
417 if !self.done_first {
418 let n = self.first.read(buf)?;
419 if n == 0 {
420 self.done_first = true;
421 } else {
422 return Ok(n);
423 }
424 }
425 self.second.read(buf)
426 }
427}
428
429impl<T, U> AsyncBufRead for ChainReader<T, U>
430where
431 T: AsyncBufRead,
432 U: AsyncBufRead,
433{
434 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
435 let me = self.project();
436
437 if !*me.done_first {
438 match ready!(me.first.poll_fill_buf(cx)?) {
439 [] => {
440 *me.done_first = true;
441 }
442 buf => return Poll::Ready(Ok(buf)),
443 }
444 }
445 me.second.poll_fill_buf(cx)
446 }
447
448 fn consume(self: Pin<&mut Self>, amt: usize) {
449 let me = self.project();
450 if !*me.done_first {
451 me.first.consume(amt)
452 } else {
453 me.second.consume(amt)
454 }
455 }
456}
457
458#[cfg(test)]
459mod test {
460 use super::*;
461
462 use tokio::io::AsyncReadExt;
463
464 #[tokio::test]
465 async fn test_replay_reader_releases_buffer_at_eof() {
466 let data = Bytes::from(vec![7u8; 64]);
467 let mut reader = ReplayReader::new(data.clone());
468 let mut out = Vec::new();
469 tokio::io::AsyncReadExt::read_to_end(&mut reader, &mut out)
470 .await
471 .unwrap();
472 assert_eq!(vec![7u8; 64], out);
473 data.try_into_mut().expect("replay buffer was released");
475 }
476
477 #[tokio::test]
478 async fn test_discard_consumes_exact_bytes() {
479 let mut reader = Cursor::new(b"abcdefghij".to_vec());
480 discard(&mut reader, 4).await.unwrap();
481 let mut rest = Vec::new();
482 tokio::io::AsyncReadExt::read_to_end(&mut reader, &mut rest)
483 .await
484 .unwrap();
485 assert_eq!(rest, b"efghij");
486 }
487
488 #[tokio::test]
489 async fn test_discard_zero_is_noop() {
490 let mut reader = Cursor::new(b"abc".to_vec());
491 discard(&mut reader, 0).await.unwrap();
492 let mut rest = Vec::new();
493 tokio::io::AsyncReadExt::read_to_end(&mut reader, &mut rest)
494 .await
495 .unwrap();
496 assert_eq!(rest, b"abc");
497 }
498
499 #[tokio::test]
500 async fn test_discard_eof_before_n_errors() {
501 let mut reader = Cursor::new(b"abc".to_vec());
502 let err = discard(&mut reader, 10).await.unwrap_err();
503 assert_eq!(err.kind(), io::ErrorKind::UnexpectedEof);
504 }
505
506 async fn test_multi_read_async<const N: usize>(
507 mut stream: impl AsyncRead + Unpin,
508 cases: &[&str],
509 ) {
510 let mut buf = [0u8; N];
511
512 for (i, case) in cases.iter().enumerate() {
513 let n = stream.read(&mut buf).await.unwrap();
514 assert_eq!(
515 n,
516 case.len(),
517 "[{N}][async] step #{} for cases: {:?}",
518 i + 1,
519 cases
520 );
521 assert_eq!(
522 &buf[..n],
523 case.as_bytes(),
524 "[{N}][async] step #{} for cases: {:?}",
525 i + 1,
526 cases
527 );
528 }
529 }
530
531 fn test_multi_read_sync<const N: usize>(mut stream: impl Read, cases: &[&str]) {
532 let mut buf = [0u8; N];
533
534 for (i, case) in cases.iter().enumerate() {
535 let n = stream.read(&mut buf).unwrap();
536 assert_eq!(
537 n,
538 case.len(),
539 "[{N}][sync] step #{} for cases: {:?}",
540 i + 1,
541 cases
542 );
543 assert_eq!(
544 &buf[..n],
545 case.as_bytes(),
546 "[{N}][sync] step #{} for cases: {:?}",
547 i + 1,
548 cases
549 );
550 }
551 }
552
553 #[derive(Debug)]
554 struct TestCase<const N: usize, R> {
555 reader: R,
556 expected_reads: &'static [&'static str],
557 }
558
559 impl<const N: usize, R: AsyncRead + Clone + Unpin + Read> TestCase<N, R> {
560 async fn test_sync_and_async(&self) {
561 let new_stream = || self.reader.clone();
562
563 test_multi_read_async::<N>(&mut new_stream(), self.expected_reads).await;
564 test_multi_read_sync::<N>(&mut new_stream(), self.expected_reads);
565 }
566 }
567
568 #[tokio::test]
569 async fn test_heap_reader() {
570 TestCase::<5, _> {
571 reader: HeapReader::from(""),
572 expected_reads: &[""],
573 }
574 .test_sync_and_async()
575 .await;
576
577 TestCase::<5, _> {
578 reader: HeapReader::from("hello world"),
579 expected_reads: &["hello", " worl", "d", ""],
580 }
581 .test_sync_and_async()
582 .await;
583
584 TestCase::<10, _> {
585 reader: HeapReader::from("hello world"),
586 expected_reads: &["hello worl", "d", ""],
587 }
588 .test_sync_and_async()
589 .await;
590 }
591
592 #[tokio::test]
593 async fn test_stack_reader() {
594 TestCase::<5, _> {
595 reader: StackReader::new(*b""),
596 expected_reads: &[""],
597 }
598 .test_sync_and_async()
599 .await;
600
601 TestCase::<5, _> {
602 reader: StackReader::new(*b"hello world"),
603 expected_reads: &["hello", " worl", "d", ""],
604 }
605 .test_sync_and_async()
606 .await;
607
608 TestCase::<10, _> {
609 reader: StackReader::from(*b"hello world"),
610 expected_reads: &["hello worl", "d", ""],
611 }
612 .test_sync_and_async()
613 .await;
614 }
615
616 #[tokio::test]
617 async fn test_chain_reader() {
618 TestCase::<5, _> {
619 reader: ChainReader::new(Cursor::new(""), Cursor::new("")),
620 expected_reads: &[""],
621 }
622 .test_sync_and_async()
623 .await;
624
625 TestCase::<5, _> {
626 reader: ChainReader::new(Cursor::new("hello world"), Cursor::new("")),
627 expected_reads: &["hello", " worl", "d", ""],
628 }
629 .test_sync_and_async()
630 .await;
631
632 TestCase::<5, _> {
633 reader: ChainReader::new(Cursor::new("hello "), Cursor::new("world")),
634 expected_reads: &["hello", " ", "world", ""],
635 }
636 .test_sync_and_async()
637 .await;
638
639 TestCase::<5, _> {
640 reader: ChainReader::new(Cursor::new(""), Cursor::new("hello world")),
641 expected_reads: &["hello", " worl", "d", ""],
642 }
643 .test_sync_and_async()
644 .await;
645 }
646}