1 use crate::Stream; 2 use pin_project_lite::pin_project; 3 use std::io; 4 use std::pin::Pin; 5 use std::task::{Context, Poll}; 6 use tokio::io::{AsyncBufRead, Lines}; 7 8 pin_project! { 9 /// A wrapper around [`tokio::io::Lines`] that implements [`Stream`]. 10 /// 11 /// [`tokio::io::Lines`]: struct@tokio::io::Lines 12 /// [`Stream`]: trait@crate::Stream 13 #[derive(Debug)] 14 #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))] 15 pub struct LinesStream<R> { 16 #[pin] 17 inner: Lines<R>, 18 } 19 } 20 21 impl<R> LinesStream<R> { 22 /// Create a new `LinesStream`. new(lines: Lines<R>) -> Self23 pub fn new(lines: Lines<R>) -> Self { 24 Self { inner: lines } 25 } 26 27 /// Get back the inner `Lines`. into_inner(self) -> Lines<R>28 pub fn into_inner(self) -> Lines<R> { 29 self.inner 30 } 31 32 /// Obtain a pinned reference to the inner `Lines<R>`. 33 #[allow(clippy::wrong_self_convention)] // https://github.com/rust-lang/rust-clippy/issues/4546 as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Lines<R>>34 pub fn as_pin_mut(self: Pin<&mut Self>) -> Pin<&mut Lines<R>> { 35 self.project().inner 36 } 37 } 38 39 impl<R: AsyncBufRead> Stream for LinesStream<R> { 40 type Item = io::Result<String>; 41 poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>42 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { 43 self.project() 44 .inner 45 .poll_next_line(cx) 46 .map(Result::transpose) 47 } 48 } 49 50 impl<R> AsRef<Lines<R>> for LinesStream<R> { as_ref(&self) -> &Lines<R>51 fn as_ref(&self) -> &Lines<R> { 52 &self.inner 53 } 54 } 55 56 impl<R> AsMut<Lines<R>> for LinesStream<R> { as_mut(&mut self) -> &mut Lines<R>57 fn as_mut(&mut self) -> &mut Lines<R> { 58 &mut self.inner 59 } 60 } 61