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}