rocket/response/stream/
bytes.rs

1use futures::stream::{Stream, StreamExt};
2
3use crate::request::Request;
4use crate::response::{self, Response, Responder};
5use crate::http::ContentType;
6use crate::response::stream::ReaderStream;
7
8/// A potentially infinite stream of bytes: any `T: AsRef<[u8]>`.
9///
10/// A `ByteStream` can be constructed from any [`Stream`] of items of type `T`
11/// where `T: AsRef<[u8]>`. This includes `Vec<u8>`, `&[u8]`, `&str`, `&RawStr`,
12/// and more. The stream can be constructed directly, via `ByteStream(..)` or
13/// [`ByteStream::from()`], or through generator syntax via [`ByteStream!`].
14///
15/// [`Stream`]: https://docs.rs/futures/0.3/futures/stream/trait.Stream.html
16///
17/// # Responder
18///
19/// `ByteStream` is a (potentially infinite) responder. The response
20/// `Content-Type` is set to [`Binary`](ContentType::Binary). The body is
21/// [unsized](crate::response::Body#unsized), and values are sent as soon as
22/// they are yielded by the internal iterator.
23///
24/// # Example
25///
26/// Use [`ByteStream!`] to yield 10 3-byte vectors, one every second, of the
27/// form `vec![i, i + 1, i + 2]` for `i` from `0` to `10` exclusive:
28///
29/// ```rust
30/// # use rocket::*;
31/// use rocket::response::stream::ByteStream;
32/// use rocket::futures::stream::{repeat, StreamExt};
33/// use rocket::tokio::time::{self, Duration};
34///
35/// #[get("/bytes")]
36/// fn bytes() -> ByteStream![&'static [u8]] {
37///     ByteStream(repeat(&[1, 2, 3][..]))
38/// }
39///
40/// #[get("/byte/stream")]
41/// fn stream() -> ByteStream![Vec<u8>] {
42///     ByteStream! {
43///         let mut interval = time::interval(Duration::from_secs(1));
44///         for i in 0..10u8 {
45///             yield vec![i, i + 1, i + 2];
46///             interval.tick().await;
47///         }
48///     }
49/// }
50/// ```
51///
52/// The syntax of `ByteStream!` as an expression is identical to that of
53/// [`stream!`](crate::response::stream::stream).
54#[derive(Debug, Clone)]
55pub struct ByteStream<S>(pub S);
56
57impl<S> From<S> for ByteStream<S> {
58    /// Creates a `ByteStream` from any `S: Stream`.
59    fn from(stream: S) -> Self {
60        ByteStream(stream)
61    }
62}
63
64impl<'r, S: Stream> Responder<'r, 'r> for ByteStream<S>
65    where S: Send + 'r, S::Item: AsRef<[u8]> + Send + Unpin + 'r
66{
67    fn respond_to(self, _: &'r Request<'_>) -> response::Result<'r> {
68        Response::build()
69            .header(ContentType::Binary)
70            .streamed_body(ReaderStream::from(self.0.map(std::io::Cursor::new)))
71            .ok()
72    }
73}
74
75crate::export! {
76    /// Type and stream expression macro for [`struct@ByteStream`].
77    ///
78    /// See [`stream!`](crate::response::stream::stream) for the syntax
79    /// supported by this macro.
80    ///
81    /// See [`struct@ByteStream`] and the [module level
82    /// docs](crate::response::stream#typed-streams) for usage details.
83    macro_rules! ByteStream {
84        ($($s:tt)*) => ($crate::_typed_stream!(ByteStream, $($s)*));
85    }
86}