Coverage Report

Created: 2026-06-30 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/http-body-util-0.1.3/src/either.rs
Line
Count
Source
1
use std::error::Error;
2
use std::fmt::Debug;
3
use std::pin::Pin;
4
use std::task::{Context, Poll};
5
6
use bytes::Buf;
7
use http_body::{Body, Frame, SizeHint};
8
use proj::EitherProj;
9
10
/// Sum type with two cases: [`Left`] and [`Right`], used if a body can be one of
11
/// two distinct types.
12
///
13
/// [`Left`]: Either::Left
14
/// [`Right`]: Either::Right
15
#[derive(Debug, Clone, Copy)]
16
pub enum Either<L, R> {
17
    /// A value of type `L`
18
    Left(L),
19
    /// A value of type `R`
20
    Right(R),
21
}
22
23
impl<L, R> Either<L, R> {
24
    /// This function is part of the generated code from `pin-project-lite`,
25
    /// for a more in depth explanation and the rest of the generated code refer
26
    /// to the [`proj`] module.
27
0
    pub(crate) fn project(self: Pin<&mut Self>) -> EitherProj<L, R> {
28
        unsafe {
29
0
            match self.get_unchecked_mut() {
30
0
                Self::Left(left) => EitherProj::Left(Pin::new_unchecked(left)),
31
0
                Self::Right(right) => EitherProj::Right(Pin::new_unchecked(right)),
32
            }
33
        }
34
0
    }
35
}
36
37
impl<L> Either<L, L> {
38
    /// Convert [`Either`] into the inner type, if both `Left` and `Right` are
39
    /// of the same type.
40
0
    pub fn into_inner(self) -> L {
41
0
        match self {
42
0
            Either::Left(left) => left,
43
0
            Either::Right(right) => right,
44
        }
45
0
    }
46
}
47
48
impl<L, R, Data> Body for Either<L, R>
49
where
50
    L: Body<Data = Data>,
51
    R: Body<Data = Data>,
52
    L::Error: Into<Box<dyn Error + Send + Sync>>,
53
    R::Error: Into<Box<dyn Error + Send + Sync>>,
54
    Data: Buf,
55
{
56
    type Data = Data;
57
    type Error = Box<dyn Error + Send + Sync>;
58
59
0
    fn poll_frame(
60
0
        self: Pin<&mut Self>,
61
0
        cx: &mut Context<'_>,
62
0
    ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
63
0
        match self.project() {
64
0
            EitherProj::Left(left) => left
65
0
                .poll_frame(cx)
66
0
                .map(|poll| poll.map(|opt| opt.map_err(Into::into))),
67
0
            EitherProj::Right(right) => right
68
0
                .poll_frame(cx)
69
0
                .map(|poll| poll.map(|opt| opt.map_err(Into::into))),
70
        }
71
0
    }
72
73
0
    fn is_end_stream(&self) -> bool {
74
0
        match self {
75
0
            Either::Left(left) => left.is_end_stream(),
76
0
            Either::Right(right) => right.is_end_stream(),
77
        }
78
0
    }
79
80
0
    fn size_hint(&self) -> SizeHint {
81
0
        match self {
82
0
            Either::Left(left) => left.size_hint(),
83
0
            Either::Right(right) => right.size_hint(),
84
        }
85
0
    }
86
}
87
88
pub(crate) mod proj {
89
    //! This code is the (cleaned output) generated by [pin-project-lite], as it
90
    //! does not support tuple variants.
91
    //!
92
    //! This is the altered expansion from the following snippet, expanded by
93
    //! `cargo-expand`:
94
    //!
95
    //! ```rust
96
    //! use pin_project_lite::pin_project;
97
    //!
98
    //! pin_project! {
99
    //!     #[project = EitherProj]
100
    //!     pub enum Either<L, R> {
101
    //!         Left {#[pin] left: L},
102
    //!         Right {#[pin] right: R}
103
    //!     }
104
    //! }
105
    //! ```
106
    //!
107
    //! [pin-project-lite]: https://docs.rs/pin-project-lite/latest/pin_project_lite/
108
    use std::marker::PhantomData;
109
    use std::pin::Pin;
110
111
    use super::Either;
112
113
    #[allow(dead_code)]
114
    #[allow(single_use_lifetimes)]
115
    #[allow(unknown_lints)]
116
    #[allow(clippy::mut_mut)]
117
    #[allow(clippy::redundant_pub_crate)]
118
    #[allow(clippy::ref_option_ref)]
119
    #[allow(clippy::type_repetition_in_bounds)]
120
    pub(crate) enum EitherProj<'__pin, L, R>
121
    where
122
        Either<L, R>: '__pin,
123
    {
124
        Left(Pin<&'__pin mut L>),
125
        Right(Pin<&'__pin mut R>),
126
    }
127
128
    #[allow(single_use_lifetimes)]
129
    #[allow(unknown_lints)]
130
    #[allow(clippy::used_underscore_binding)]
131
    #[allow(missing_debug_implementations)]
132
    const _: () = {
133
        #[allow(non_snake_case)]
134
        pub struct __Origin<'__pin, L, R> {
135
            __dummy_lifetime: PhantomData<&'__pin ()>,
136
            _Left: L,
137
            _Right: R,
138
        }
139
        impl<'__pin, L, R> Unpin for Either<L, R> where __Origin<'__pin, L, R>: Unpin {}
140
141
        trait MustNotImplDrop {}
142
        #[allow(drop_bounds)]
143
        impl<T: Drop> MustNotImplDrop for T {}
144
        impl<L, R> MustNotImplDrop for Either<L, R> {}
145
    };
146
}
147
148
#[cfg(test)]
149
mod tests {
150
    use super::*;
151
    use crate::{BodyExt, Empty, Full};
152
153
    #[tokio::test]
154
    async fn data_left() {
155
        let full = Full::new(&b"hello"[..]);
156
157
        let mut value: Either<_, Empty<&[u8]>> = Either::Left(full);
158
159
        assert_eq!(value.size_hint().exact(), Some(b"hello".len() as u64));
160
        assert_eq!(
161
            value.frame().await.unwrap().unwrap().into_data().unwrap(),
162
            &b"hello"[..]
163
        );
164
        assert!(value.frame().await.is_none());
165
    }
166
167
    #[tokio::test]
168
    async fn data_right() {
169
        let full = Full::new(&b"hello!"[..]);
170
171
        let mut value: Either<Empty<&[u8]>, _> = Either::Right(full);
172
173
        assert_eq!(value.size_hint().exact(), Some(b"hello!".len() as u64));
174
        assert_eq!(
175
            value.frame().await.unwrap().unwrap().into_data().unwrap(),
176
            &b"hello!"[..]
177
        );
178
        assert!(value.frame().await.is_none());
179
    }
180
181
    #[test]
182
    fn into_inner() {
183
        let a = Either::<i32, i32>::Left(2);
184
        assert_eq!(a.into_inner(), 2)
185
    }
186
}