Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion http-body-util/src/collected.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ mod tests {

#[tokio::test]
async fn full_body() {
let body = Full::new(&b"hello"[..]);
let body = Full::<_, Infallible>::new(&b"hello"[..]);

let buffered = body.collect().await.unwrap();

Expand All @@ -121,6 +121,7 @@ mod tests {
}

#[tokio::test]
#[allow(unused_must_use)]
async fn delayed_segments() {
let one = stream::once(async { Ok::<_, Infallible>(Frame::data(&b"hello "[..])) });
let two = stream::once(async {
Expand Down
8 changes: 4 additions & 4 deletions http-body-util/src/combinators/box_body.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use crate::BodyExt as _;

use bytes::Buf;
use http_body::{Body, Frame, SizeHint};
use std::{
Expand Down Expand Up @@ -63,9 +61,10 @@ where
impl<D, E> Default for BoxBody<D, E>
where
D: Buf + 'static,
E: 'static,
{
fn default() -> Self {
BoxBody::new(crate::Empty::new().map_err(|err| match err {}))
BoxBody::new(crate::Empty::new())
}
}

Expand Down Expand Up @@ -115,8 +114,9 @@ where
impl<D, E> Default for UnsyncBoxBody<D, E>
where
D: Buf + 'static,
E: 'static,
{
fn default() -> Self {
UnsyncBoxBody::new(crate::Empty::new().map_err(|err| match err {}))
UnsyncBoxBody::new(crate::Empty::new())
}
}
10 changes: 6 additions & 4 deletions http-body-util/src/either.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,16 @@ pub(crate) mod proj {

#[cfg(test)]
mod tests {
use std::convert::Infallible;

use super::*;
use crate::{BodyExt, Empty, Full};

#[tokio::test]
async fn data_left() {
let full = Full::new(&b"hello"[..]);
let full = Full::<_, Infallible>::new(&b"hello"[..]);

let mut value: Either<_, Empty<&[u8]>> = Either::Left(full);
let mut value: Either<_, Empty<&[u8], Infallible>> = Either::Left(full);

assert_eq!(value.size_hint().exact(), Some(b"hello".len() as u64));
assert_eq!(
Expand All @@ -163,9 +165,9 @@ mod tests {

#[tokio::test]
async fn data_right() {
let full = Full::new(&b"hello!"[..]);
let full = Full::<_, Infallible>::new(&b"hello!"[..]);

let mut value: Either<Empty<&[u8]>, _> = Either::Right(full);
let mut value: Either<Empty<&[u8], Infallible>, _> = Either::Right(full);

assert_eq!(value.size_hint().exact(), Some(b"hello!".len() as u64));
assert_eq!(
Expand Down
19 changes: 9 additions & 10 deletions http-body-util/src/empty.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
use bytes::Buf;
use http_body::{Body, Frame, SizeHint};
use std::{
convert::Infallible,
fmt,
marker::PhantomData,
pin::Pin,
task::{Context, Poll},
};

/// A body that is always empty.
pub struct Empty<D> {
_marker: PhantomData<fn() -> D>,
pub struct Empty<D, E> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth discussing: what if it still had a default? Empty<D, E = Infallible>? It seems useful, but there's probably some cons to consider too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes sense!

_marker: PhantomData<fn() -> (D, E)>,
}

impl<D> Empty<D> {
impl<D, E> Empty<D, E> {
/// Create a new `Empty`.
pub fn new() -> Self {
Self::default()
}
}

impl<D: Buf> Body for Empty<D> {
impl<D: Buf, E> Body for Empty<D, E> {
type Data = D;
type Error = Infallible;
type Error = E;

#[inline]
fn poll_frame(
Expand All @@ -41,26 +40,26 @@ impl<D: Buf> Body for Empty<D> {
}
}

impl<D> fmt::Debug for Empty<D> {
impl<D, E> fmt::Debug for Empty<D, E> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Empty").finish()
}
}

impl<D> Default for Empty<D> {
impl<D, E> Default for Empty<D, E> {
fn default() -> Self {
Self {
_marker: PhantomData,
}
}
}

impl<D> Clone for Empty<D> {
impl<D, E> Clone for Empty<D, E> {
fn clone(&self) -> Self {
Self {
_marker: PhantomData,
}
}
}

impl<D> Copy for Empty<D> {}
impl<D, E> Copy for Empty<D, E> {}
69 changes: 51 additions & 18 deletions http-body-util/src/full.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ use bytes::{Buf, Bytes};
use http_body::{Body, Frame, SizeHint};
use pin_project_lite::pin_project;
use std::borrow::Cow;
use std::convert::{Infallible, TryFrom};
use std::convert::TryFrom;
use std::fmt;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};

pin_project! {
/// A body that consists of a single chunk.
#[derive(Clone, Copy, Debug)]
pub struct Full<D> {
pub struct Full<D, E> {
data: Option<D>,
_marker: PhantomData<fn() -> E>,
}
}

impl<D> Full<D>
impl<D, E> Full<D, E>
where
D: Buf,
{
Expand All @@ -25,16 +27,19 @@ where
} else {
None
};
Full { data }
Full {
data,
_marker: PhantomData,
}
}
}

impl<D> Body for Full<D>
impl<D, E> Body for Full<D, E>
where
D: Buf,
{
type Data = D;
type Error = Infallible;
type Error = E;

fn poll_frame(
mut self: Pin<&mut Self>,
Expand All @@ -55,17 +60,43 @@ where
}
}

impl<D> Default for Full<D>
impl<D, E> Clone for Full<D, E>
where
D: Clone,
{
fn clone(&self) -> Self {
Self {
data: self.data.clone(),
_marker: self._marker,
}
}
}

impl<D, E> Copy for Full<D, E> where D: Copy {}

impl<D, E> fmt::Debug for Full<D, E>
where
D: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Full").field("data", &self.data).finish()
}
}

impl<D, E> Default for Full<D, E>
where
D: Buf,
{
/// Create an empty `Full`.
fn default() -> Self {
Full { data: None }
Full {
data: None,
_marker: PhantomData,
}
}
}

impl<D> From<Bytes> for Full<D>
impl<D, E> From<Bytes> for Full<D, E>
where
D: Buf + From<Bytes>,
{
Expand All @@ -74,7 +105,7 @@ where
}
}

impl<D> From<Vec<u8>> for Full<D>
impl<D, E> From<Vec<u8>> for Full<D, E>
where
D: Buf + From<Vec<u8>>,
{
Expand All @@ -83,7 +114,7 @@ where
}
}

impl<D> From<&'static [u8]> for Full<D>
impl<D, E> From<&'static [u8]> for Full<D, E>
where
D: Buf + From<&'static [u8]>,
{
Expand All @@ -92,7 +123,7 @@ where
}
}

impl<D, B> From<Cow<'static, B>> for Full<D>
impl<D, E, B> From<Cow<'static, B>> for Full<D, E>
where
D: Buf + From<&'static B> + From<B::Owned>,
B: ToOwned + ?Sized,
Expand All @@ -105,7 +136,7 @@ where
}
}

impl<D> From<String> for Full<D>
impl<D, E> From<String> for Full<D, E>
where
D: Buf + From<String>,
{
Expand All @@ -114,7 +145,7 @@ where
}
}

impl<D> From<&'static str> for Full<D>
impl<D, E> From<&'static str> for Full<D, E>
where
D: Buf + From<&'static str>,
{
Expand All @@ -125,12 +156,14 @@ where

#[cfg(test)]
mod tests {
use std::convert::Infallible;

use super::*;
use crate::BodyExt;

#[tokio::test]
async fn full_returns_some() {
let mut full = Full::new(&b"hello"[..]);
let mut full = Full::<_, Infallible>::new(&b"hello"[..]);
assert_eq!(full.size_hint().exact(), Some(b"hello".len() as u64));
assert_eq!(
full.frame().await.unwrap().unwrap().into_data().unwrap(),
Expand All @@ -141,7 +174,7 @@ mod tests {

#[tokio::test]
async fn empty_full_returns_none() {
assert!(Full::<&[u8]>::default().frame().await.is_none());
assert!(Full::new(&b""[..]).frame().await.is_none());
assert!(Full::<&[u8], Infallible>::default().frame().await.is_none());
assert!(Full::<_, Infallible>::new(&b""[..]).frame().await.is_none());
}
}
4 changes: 2 additions & 2 deletions http-body-util/src/limited.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ mod tests {
#[tokio::test]
async fn read_for_body_under_limit_returns_data() {
const DATA: &[u8] = b"testing";
let inner = Full::new(Bytes::from(DATA));
let inner = Full::<_, Infallible>::new(Bytes::from(DATA));
let body = &mut Limited::new(inner, 8);

let mut hint = SizeHint::new();
Expand All @@ -128,7 +128,7 @@ mod tests {
#[tokio::test]
async fn read_for_body_over_limit_returns_error() {
const DATA: &[u8] = b"testing a string that is too long";
let inner = Full::new(Bytes::from(DATA));
let inner = Full::<_, Infallible>::new(Bytes::from(DATA));
let body = &mut Limited::new(inner, 8);

let mut hint = SizeHint::new();
Expand Down
1 change: 1 addition & 0 deletions http-body/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub trait Body {
type Error;

/// Attempt to pull out the next data buffer of this stream.
#[allow(clippy::type_complexity)]
fn poll_frame(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
Expand Down