rocket_community/response/stream/bytes.rs
1use futures::stream::{Stream, StreamExt};
2
3use crate::http::ContentType;
4use crate::request::Request;
5use crate::response::stream::ReaderStream;
6use crate::response::{self, Responder, Response};
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/// # extern crate rocket_community as rocket;
31/// # use rocket::*;
32/// use rocket::response::stream::ByteStream;
33/// use rocket::futures::stream::{repeat, StreamExt};
34/// use rocket::tokio::time::{self, Duration};
35///
36/// #[get("/bytes")]
37/// fn bytes() -> ByteStream![&'static [u8]] {
38/// ByteStream(repeat(&[1, 2, 3][..]))
39/// }
40///
41/// #[get("/byte/stream")]
42/// fn stream() -> ByteStream![Vec<u8>] {
43/// ByteStream! {
44/// let mut interval = time::interval(Duration::from_secs(1));
45/// for i in 0..10u8 {
46/// yield vec![i, i + 1, i + 2];
47/// interval.tick().await;
48/// }
49/// }
50/// }
51/// ```
52///
53/// The syntax of `ByteStream!` as an expression is identical to that of
54/// [`stream!`](crate::response::stream::stream).
55#[derive(Debug, Clone)]
56pub struct ByteStream<S>(pub S);
57
58impl<S> From<S> for ByteStream<S> {
59 /// Creates a `ByteStream` from any `S: Stream`.
60 fn from(stream: S) -> Self {
61 ByteStream(stream)
62 }
63}
64
65impl<'r, S: Stream> Responder<'r, 'r> for ByteStream<S>
66where
67 S: Send + 'r,
68 S::Item: AsRef<[u8]> + Send + Unpin + 'r,
69{
70 fn respond_to(self, _: &'r Request<'_>) -> response::Result<'r> {
71 Response::build()
72 .header(ContentType::Binary)
73 .streamed_body(ReaderStream::from(self.0.map(std::io::Cursor::new)))
74 .ok()
75 }
76}
77
78crate::export! {
79 /// Type and stream expression macro for [`struct@ByteStream`].
80 ///
81 /// See [`stream!`](crate::response::stream::stream) for the syntax
82 /// supported by this macro.
83 ///
84 /// See [`struct@ByteStream`] and the [module level
85 /// docs](crate::response::stream#typed-streams) for usage details.
86 macro_rules! ByteStream {
87 ($($s:tt)*) => ($crate::_typed_stream!(ByteStream, $($s)*));
88 }
89}