Skip to main content

fuchsia_hyper_test_support/
body.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use futures::prelude::*;
6use std::pin::Pin;
7use std::task::{Context, Poll};
8
9/// An HTTP body enum supporting empty, full bytes, and streamed frames for test support.
10pub enum Body {
11    /// An empty body.
12    Empty(http_body_util::Empty<hyper::body::Bytes>),
13    /// A body consisting of a single in-memory buffer of bytes.
14    Full(http_body_util::Full<hyper::body::Bytes>),
15    /// A streamed body produced by an asynchronous stream of frames.
16    Stream(
17        http_body_util::StreamBody<
18            Pin<
19                Box<
20                    dyn Stream<
21                            Item = Result<hyper::body::Frame<hyper::body::Bytes>, std::io::Error>,
22                        > + Send
23                        + Sync,
24                >,
25            >,
26        >,
27    ),
28}
29
30impl std::fmt::Debug for Body {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        match self {
33            Body::Empty(_) => f.debug_tuple("Empty").finish(),
34            Body::Full(_) => f.debug_tuple("Full").finish(),
35            Body::Stream(_) => f.debug_tuple("Stream").finish(),
36        }
37    }
38}
39
40impl Body {
41    /// Create a new empty body.
42    pub fn empty() -> Self {
43        Body::Empty(http_body_util::Empty::new())
44    }
45    /// Create a streamed body from a stream of items convertible to bytes.
46    pub fn wrap_stream<S, O, E>(stream: S) -> Self
47    where
48        S: Stream<Item = Result<O, E>> + Send + Sync + 'static,
49        O: Into<hyper::body::Bytes>,
50        E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
51    {
52        let stream = stream.map(|res| match res {
53            Ok(data) => Ok(hyper::body::Frame::data(data.into())),
54            Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
55        });
56        Body::Stream(http_body_util::StreamBody::new(Box::pin(stream)))
57    }
58}
59
60impl From<Vec<u8>> for Body {
61    fn from(data: Vec<u8>) -> Self {
62        Body::Full(http_body_util::Full::new(data.into()))
63    }
64}
65
66impl hyper::body::Body for Body {
67    type Data = hyper::body::Bytes;
68    type Error = std::io::Error;
69
70    fn poll_frame(
71        self: Pin<&mut Self>,
72        cx: &mut Context<'_>,
73    ) -> Poll<Option<Result<hyper::body::Frame<Self::Data>, Self::Error>>> {
74        match self.get_mut() {
75            Body::Empty(b) => Pin::new(b).poll_frame(cx).map_err(|e| match e {}),
76            Body::Full(b) => Pin::new(b).poll_frame(cx).map_err(|e| match e {}),
77            Body::Stream(b) => Pin::new(b).poll_frame(cx),
78        }
79    }
80}