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}