Skip to content

Convert Future<Body> into Body #157

@nwtgck

Description

@nwtgck

Hi,

This is a feature request to add a conversion Future<Output=Result<Body, E>>Body<Error=E>.

http-body-util currently does not seem to provide a straightforward way to turn a Future<Body> into a Body. This is particularly useful when you create a Body through an asynchronous computation that you then send a body over a oneshot channel. The typical workaround is to use FutureExt::into_stream, StreamExt::flat_map and do map with Frame::data.

example implementation

pin_project! {
    #[project = FutureBodyProj]
    #[derive(Debug)]
    pub enum FutureBody<F, B> {
        Future{#[pin] future: F},
        Body{#[pin] body: B},
    }
}

impl<F, B> FutureBody<F, B> {
    pub fn new(future: F) -> Self {
        Self::Future { future }
    }
}

impl<F: Future<Output = Result<B, B::Error>>, B: http_body::Body> http_body::Body
    for FutureBody<F, B>
{
    type Data = B::Data;
    type Error = B::Error;

    fn poll_frame(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
        loop {
            match self.as_mut().project() {
                FutureBodyProj::Future { future } => {
                    let body = match ready!(future.poll(cx)) {
                        Ok(x) => x,
                        Err(err) => return Poll::Ready(Some(Err(err))),
                    };
                    self.set(FutureBody::Body { body });
                }
                FutureBodyProj::Body { body } => {
                    return body.poll_frame(cx);
                }
            }
        }
    }

    fn is_end_stream(&self) -> bool {
        match self {
            FutureBody::Future { .. } => false,
            FutureBody::Body { body } => body.is_end_stream(),
        }
    }

    fn size_hint(&self) -> http_body::SizeHint {
        match self {
            FutureBody::Future { .. } => http_body::SizeHint::new(),
            FutureBody::Body { body } => body.size_hint(),
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-http-body-utilCrate: http-body-utilE-easyEffort: easy. A good place to start!S-featureSeverity: feature. Something new.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions