Skip to main content

http_body_alt/
size_hint.rs

1use std::ops::Add;
2
3/// Size hint for type impl [`Body`] trait
4///
5/// Size is for [`Frame::Data`] variant only. [`Frame::Trailers`] is not inclued in hint
6///
7/// [`Body`]: crate::body::Body
8/// [`Frame::Data`]: crate::frame::Frame::Data
9/// [`Frame::Trailers`]: crate::frame::Frame::Trailers
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
11pub enum SizeHint {
12    /// No sized. [`Body::poll_frame`] can be skipped entirely
13    ///
14    /// [`Body::poll_frame`]: crate::body::Body::poll_frame
15    None,
16    /// Exact sized. [`Body::poll_frame`] can reliably expect all [`Frame::Data`] it can yield
17    /// have a total byte length in exact number
18    ///
19    /// [`Body::poll_frame`]: crate::body::Body::poll_frame
20    /// [`Frame::Data`]: crate::frame::Frame::Data
21    Exact(u64),
22    /// Unknown sized. Escape hatch when size can't be reliably determined
23    #[default]
24    Unknown,
25}
26
27impl Add for SizeHint {
28    type Output = Self;
29
30    fn add(self, rhs: Self) -> Self::Output {
31        match (self, rhs) {
32            (Self::None, Self::None) => Self::None,
33            (Self::None, Self::Exact(size)) => Self::Exact(size),
34            (Self::Exact(size), Self::None) => Self::Exact(size),
35            (Self::Exact(size1), Self::Exact(size2)) => size1.checked_add(size2).map_or(Self::Unknown, Self::Exact),
36            _ => Self::Unknown,
37        }
38    }
39}
40
41impl SizeHint {
42    /// a crate hack for expressing [`SizeHint::None`] through [`Stream::size_hint`]
43    ///
44    /// [`Stream::size_hint`]: futures_core::stream::Stream::size_hint
45    pub const NO_BODY_HINT: (usize, Option<usize>) = (usize::MAX, Some(0));
46
47    pub(crate) fn exact<U>(size: U) -> Self
48    where
49        u64: TryFrom<U>,
50        <u64 as TryFrom<U>>::Error: core::fmt::Debug,
51    {
52        SizeHint::Exact(u64::try_from(size).unwrap())
53    }
54
55    pub(crate) fn as_stream_size_hint(&self) -> (usize, Option<usize>) {
56        match self {
57            Self::Exact(len) => {
58                let len = usize::try_from(*len).unwrap();
59                (len, Some(len))
60            }
61            Self::Unknown => (0, None),
62            Self::None => Self::NO_BODY_HINT,
63        }
64    }
65
66    pub(crate) fn from_stream_size_hint(hint: (usize, Option<usize>)) -> Self {
67        match hint {
68            Self::NO_BODY_HINT => Self::None,
69            (low, Some(up)) if low == up => Self::exact(low),
70            _ => Self::Unknown,
71        }
72    }
73}