pavex/response/body/body_.rs
1use std::pin::{Pin, pin};
2use std::task::{Context, Poll};
3
4use http_body::{Frame, SizeHint};
5use http_body_util::combinators::UnsyncBoxBody;
6
7use crate::response::body::body_::boxed::boxed;
8use crate::response::body::raw::RawBody;
9
10use super::raw::Bytes;
11
12/// The body type used in Pavex's [`Response`](crate::Response)s.
13///
14/// # Low-level
15///
16/// You'll rarely have to work with `ResponseBody` directly.
17/// Rely on [`Response::set_typed_body`] and [`Response::set_raw_body`] to
18/// build the body of your responses.
19/// `ResponseBody` is part of the public API to give a name to the type returned by
20/// [`Response::body`] and [`Response::body_mut`].
21///
22/// [`Response::set_typed_body`]: crate::Response::set_typed_body
23/// [`Response::set_raw_body`]: crate::Response::set_raw_body
24/// [`Response::body`]: crate::Response::body
25/// [`Response::body_mut`]: crate::Response::body_mut
26#[derive(Debug)]
27pub struct ResponseBody(UnsyncBoxBody<Bytes, crate::Error>);
28
29impl ResponseBody {
30 /// Create a new [`ResponseBody`] from a raw body type.
31 pub fn new<B>(body: B) -> Self
32 where
33 B: RawBody<Data = Bytes> + Send + 'static,
34 <B as RawBody>::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
35 {
36 boxed(body)
37 }
38}
39
40impl RawBody for ResponseBody {
41 type Data = Bytes;
42 type Error = crate::Error;
43
44 fn poll_frame(
45 mut self: Pin<&mut Self>,
46 cx: &mut Context<'_>,
47 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
48 pin!(&mut self.0).as_mut().poll_frame(cx)
49 }
50
51 fn is_end_stream(&self) -> bool {
52 self.0.is_end_stream()
53 }
54
55 fn size_hint(&self) -> SizeHint {
56 self.0.size_hint()
57 }
58}
59
60impl Default for ResponseBody {
61 fn default() -> Self {
62 ResponseBody::new(super::raw::Empty::new())
63 }
64}
65
66// Most of this module is a direct copy (with, from time to time,
67// minor modifications) of the corresponding `body` module in
68// `axum-core`.
69//
70// Copyright (c) 2019 Axum Contributors
71//
72// Permission is hereby granted, free of charge, to any
73// person obtaining a copy of this software and associated
74// documentation files (the "Software"), to deal in the
75// Software without restriction, including without
76// limitation the rights to use, copy, modify, merge,
77// publish, distribute, sublicense, and/or sell copies of
78// the Software, and to permit persons to whom the Software
79// is furnished to do so, subject to the following
80// conditions:
81//
82// The above copyright notice and this permission notice
83// shall be included in all copies or substantial portions
84// of the Software.
85//
86// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
87// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
88// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
89// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
90// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
91// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
92// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
93// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
94// DEALINGS IN THE SOFTWARE.
95mod boxed {
96 //! Body types and utilities used by Pavex.
97 use http_body_util::BodyExt;
98
99 use crate::Error;
100 use crate::response::body::raw::RawBody;
101
102 use super::{Bytes, ResponseBody};
103
104 /// Convert a [`RawBody`] into a [`ResponseBody`].
105 pub(super) fn boxed<B>(body: B) -> ResponseBody
106 where
107 B: RawBody<Data = Bytes> + Send + 'static,
108 B::Error: Into<Box<dyn std::error::Error + Sync + Send>>,
109 {
110 ResponseBody(
111 try_downcast(body).unwrap_or_else(|body| body.map_err(Error::new).boxed_unsync()),
112 )
113 }
114
115 fn try_downcast<T, K>(k: K) -> Result<T, K>
116 where
117 T: 'static,
118 K: Send + 'static,
119 {
120 let mut k = Some(k);
121 match <dyn std::any::Any>::downcast_mut::<Option<T>>(&mut k) {
122 Some(k) => Ok(k.take().unwrap()),
123 _ => Err(k.unwrap()),
124 }
125 }
126
127 #[test]
128 fn test_try_downcast() {
129 assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32));
130 assert_eq!(try_downcast::<i32, _>(5_i32), Ok(5_i32));
131 }
132}