1 use super::read_until::read_until_internal;
2 use futures_core::future::Future;
3 use futures_core::ready;
4 use futures_core::task::{Context, Poll};
5 use futures_io::AsyncBufRead;
6 use std::io;
7 use std::mem;
8 use std::pin::Pin;
9 use std::str;
10 use std::string::String;
11 use std::vec::Vec;
12 
13 /// Future for the [`read_line`](super::AsyncBufReadExt::read_line) method.
14 #[derive(Debug)]
15 #[must_use = "futures do nothing unless you `.await` or poll them"]
16 pub struct ReadLine<'a, R: ?Sized> {
17     reader: &'a mut R,
18     buf: &'a mut String,
19     bytes: Vec<u8>,
20     read: usize,
21     finished: bool,
22 }
23 
24 impl<R: ?Sized + Unpin> Unpin for ReadLine<'_, R> {}
25 
26 impl<'a, R: AsyncBufRead + ?Sized + Unpin> ReadLine<'a, R> {
new(reader: &'a mut R, buf: &'a mut String) -> Self27     pub(super) fn new(reader: &'a mut R, buf: &'a mut String) -> Self {
28         Self { reader, bytes: mem::take(buf).into_bytes(), buf, read: 0, finished: false }
29     }
30 }
31 
read_line_internal<R: AsyncBufRead + ?Sized>( reader: Pin<&mut R>, cx: &mut Context<'_>, buf: &mut String, bytes: &mut Vec<u8>, read: &mut usize, ) -> Poll<io::Result<usize>>32 pub(super) fn read_line_internal<R: AsyncBufRead + ?Sized>(
33     reader: Pin<&mut R>,
34     cx: &mut Context<'_>,
35     buf: &mut String,
36     bytes: &mut Vec<u8>,
37     read: &mut usize,
38 ) -> Poll<io::Result<usize>> {
39     let mut ret = ready!(read_until_internal(reader, cx, b'\n', bytes, read));
40     if str::from_utf8(&bytes[bytes.len() - *read..bytes.len()]).is_err() {
41         bytes.truncate(bytes.len() - *read);
42         if ret.is_ok() {
43             ret = Err(io::Error::new(
44                 io::ErrorKind::InvalidData,
45                 "stream did not contain valid UTF-8",
46             ));
47         }
48     }
49     *read = 0;
50     // Safety: `bytes` is valid UTF-8 because it was taken from a String
51     // and the newly read bytes are either valid UTF-8 or have been removed.
52     mem::swap(unsafe { buf.as_mut_vec() }, bytes);
53     Poll::Ready(ret)
54 }
55 
56 impl<R: AsyncBufRead + ?Sized + Unpin> Future for ReadLine<'_, R> {
57     type Output = io::Result<usize>;
58 
poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>59     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
60         let Self { reader, buf, bytes, read, finished: _ } = &mut *self;
61         let ret = ready!(read_line_internal(Pin::new(reader), cx, buf, bytes, read));
62         self.finished = true;
63         Poll::Ready(ret)
64     }
65 }
66 
67 impl<R: ?Sized> Drop for ReadLine<'_, R> {
drop(&mut self)68     fn drop(&mut self) {
69         // restore old string contents
70         if !self.finished {
71             self.bytes.truncate(self.bytes.len() - self.read);
72             // Safety: `bytes` is valid UTF-8 because it was taken from a String
73             // and the newly read bytes have been removed.
74             mem::swap(unsafe { self.buf.as_mut_vec() }, &mut self.bytes);
75         }
76     }
77 }
78