1use std::{
2 error::Error as StdError,
3 fmt,
4 pin::Pin,
5 task::{Context, Poll},
6};
7
8use bytes::Bytes;
9
10use super::{BodySize, MessageBody, MessageBodyMapErr};
11use crate::body;
12
13#[derive(Debug)]
15pub struct BoxBody(BoxBodyInner);
16
17enum BoxBodyInner {
18 None(body::None),
19 Bytes(Bytes),
20 Stream(Pin<Box<dyn MessageBody<Error = Box<dyn StdError>>>>),
21}
22
23impl fmt::Debug for BoxBodyInner {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 Self::None(arg0) => f.debug_tuple("None").field(arg0).finish(),
27 Self::Bytes(arg0) => f.debug_tuple("Bytes").field(arg0).finish(),
28 Self::Stream(_) => f.debug_tuple("Stream").field(&"dyn MessageBody").finish(),
29 }
30 }
31}
32
33impl BoxBody {
34 #[inline]
39 pub fn new<B>(body: B) -> Self
40 where
41 B: MessageBody + 'static,
42 {
43 match body.size() {
44 BodySize::None => Self(BoxBodyInner::None(body::None)),
45 _ => match body.try_into_bytes() {
46 Ok(bytes) => Self(BoxBodyInner::Bytes(bytes)),
47 Err(body) => {
48 let body = MessageBodyMapErr::new(body, Into::into);
49 Self(BoxBodyInner::Stream(Box::pin(body)))
50 }
51 },
52 }
53 }
54
55 #[inline]
57 pub fn as_pin_mut(&mut self) -> Pin<&mut Self> {
58 Pin::new(self)
59 }
60}
61
62impl MessageBody for BoxBody {
63 type Error = Box<dyn StdError>;
64
65 #[inline]
66 fn size(&self) -> BodySize {
67 match &self.0 {
68 BoxBodyInner::None(none) => none.size(),
69 BoxBodyInner::Bytes(bytes) => bytes.size(),
70 BoxBodyInner::Stream(stream) => stream.size(),
71 }
72 }
73
74 #[inline]
75 fn poll_next(
76 mut self: Pin<&mut Self>,
77 cx: &mut Context<'_>,
78 ) -> Poll<Option<Result<Bytes, Self::Error>>> {
79 match &mut self.0 {
80 BoxBodyInner::None(body) => Pin::new(body).poll_next(cx).map_err(|err| match err {}),
81 BoxBodyInner::Bytes(body) => Pin::new(body).poll_next(cx).map_err(|err| match err {}),
82 BoxBodyInner::Stream(body) => Pin::new(body).poll_next(cx),
83 }
84 }
85
86 #[inline]
87 fn try_into_bytes(self) -> Result<Bytes, Self> {
88 match self.0 {
89 BoxBodyInner::None(body) => Ok(body.try_into_bytes().unwrap()),
90 BoxBodyInner::Bytes(body) => Ok(body.try_into_bytes().unwrap()),
91 _ => Err(self),
92 }
93 }
94
95 #[inline]
96 fn boxed(self) -> BoxBody {
97 self
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use static_assertions::{assert_impl_all, assert_not_impl_any};
104
105 use super::*;
106 use crate::body::to_bytes;
107
108 assert_impl_all!(BoxBody: fmt::Debug, MessageBody, Unpin);
109 assert_not_impl_any!(BoxBody: Send, Sync);
110
111 #[actix_rt::test]
112 async fn nested_boxed_body() {
113 let body = Bytes::from_static(&[1, 2, 3]);
114 let boxed_body = BoxBody::new(BoxBody::new(body));
115
116 assert_eq!(
117 to_bytes(boxed_body).await.unwrap(),
118 Bytes::from(vec![1, 2, 3]),
119 );
120 }
121}