mod json;
mod line;
mod text;
use std::fmt;
use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::Bytes;
use futures_core::Stream;
use serde::Serialize;
use serde::de::DeserializeOwned;
pub use self::json::JsonStream;
pub use self::line::LineStream;
pub use self::text::TextStream;
use crate::client::Endpoint;
use crate::error::Result;
impl Endpoint {
#[cfg_attr(feature = "tracing", tracing::instrument(skip(self, payload), fields(route = %self.route(), request_id = self.request_id()), err))]
pub async fn stream<T>(&self, payload: &T) -> Result<ByteStream>
where
T: Serialize + ?Sized + Sync,
{
let req = self.request(self.route())?.json(payload);
let resp = self.client().send(req).await?;
Ok(ByteStream::new(resp.bytes_stream()))
}
}
pub struct ByteStream {
inner: Pin<Box<dyn Stream<Item = reqwest::Result<Bytes>> + Send>>,
}
impl ByteStream {
pub(super) fn new(inner: impl Stream<Item = reqwest::Result<Bytes>> + Send + 'static) -> Self {
Self {
inner: Box::pin(inner),
}
}
pub fn text(self) -> TextStream {
TextStream::new(self)
}
pub fn lines(self) -> LineStream {
LineStream::new(self)
}
pub fn json<T: DeserializeOwned>(self) -> JsonStream<T> {
JsonStream::new(self)
}
}
impl Stream for ByteStream {
type Item = Result<Bytes>;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
self.inner
.as_mut()
.poll_next(cx)
.map(|opt| opt.map(|res| res.map_err(Into::into)))
}
}
impl fmt::Debug for ByteStream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ByteStream").finish_non_exhaustive()
}
}