1use std::io;
2#[cfg(feature = "try_trait_v2")]
3use std::{
4 convert::Infallible,
5 ops::{ControlFlow, FromResidual, Residual, Try},
6};
7
8use crate::IntoInner;
9
10#[must_use]
17pub struct BufResult<T, B>(pub io::Result<T>, pub B);
18
19impl<T, B> BufResult<T, B> {
20 pub const fn is_ok(&self) -> bool {
22 self.0.is_ok()
23 }
24
25 pub const fn is_err(&self) -> bool {
27 self.0.is_err()
28 }
29
30 #[inline]
32 pub fn map<U>(self, f: impl FnOnce(T, B) -> (U, B)) -> BufResult<U, B> {
33 match self.0 {
34 Ok(res) => {
35 let (res, buf) = f(res, self.1);
36 BufResult(Ok(res), buf)
37 }
38 Err(e) => BufResult(Err(e), self.1),
39 }
40 }
41
42 #[inline]
44 pub fn map2<U, C>(
45 self,
46 f_ok: impl FnOnce(T, B) -> (U, C),
47 f_err: impl FnOnce(B) -> C,
48 ) -> BufResult<U, C> {
49 match self.0 {
50 Ok(res) => {
51 let (res, buf) = f_ok(res, self.1);
52 BufResult(Ok(res), buf)
53 }
54 Err(e) => BufResult(Err(e), f_err(self.1)),
55 }
56 }
57
58 #[inline]
60 pub fn map_res<U>(self, f: impl FnOnce(T) -> U) -> BufResult<U, B> {
61 BufResult(self.0.map(f), self.1)
62 }
63
64 #[inline]
66 pub fn map_buffer<C>(self, f: impl FnOnce(B) -> C) -> BufResult<T, C> {
67 BufResult(self.0, f(self.1))
68 }
69
70 #[inline]
72 pub fn and_then<U>(self, f: impl FnOnce(T, B) -> (io::Result<U>, B)) -> BufResult<U, B> {
73 match self.0 {
74 Ok(res) => BufResult::from(f(res, self.1)),
75 Err(e) => BufResult(Err(e), self.1),
76 }
77 }
78
79 #[inline]
81 #[track_caller]
82 pub fn expect(self, msg: &str) -> (T, B) {
83 (self.0.expect(msg), self.1)
84 }
85
86 #[inline(always)]
88 #[track_caller]
89 pub fn unwrap(self) -> (T, B) {
90 (self.0.unwrap(), self.1)
91 }
92}
93
94impl<T, B> From<(io::Result<T>, B)> for BufResult<T, B> {
95 fn from((res, buf): (io::Result<T>, B)) -> Self {
96 Self(res, buf)
97 }
98}
99
100impl<T, B> From<BufResult<T, B>> for (io::Result<T>, B) {
101 fn from(BufResult(res, buf): BufResult<T, B>) -> Self {
102 (res, buf)
103 }
104}
105
106impl<T: IntoInner, O> IntoInner for BufResult<O, T> {
107 type Inner = BufResult<O, T::Inner>;
108
109 fn into_inner(self) -> Self::Inner {
110 BufResult(self.0, self.1.into_inner())
111 }
112}
113
114#[cfg(feature = "try_trait_v2")]
125impl<T, B> FromResidual<BufResult<Infallible, B>> for BufResult<T, B> {
126 fn from_residual(residual: BufResult<Infallible, B>) -> Self {
127 match residual {
128 BufResult(Err(e), b) => BufResult(Err(e), b),
129 }
130 }
131}
132
133#[cfg(feature = "try_trait_v2")]
144impl<T, B> FromResidual<BufResult<Infallible, B>> for io::Result<T> {
145 fn from_residual(residual: BufResult<Infallible, B>) -> Self {
146 match residual {
147 BufResult(Err(e), _) => Err(e),
148 }
149 }
150}
151
152#[cfg(feature = "try_trait_v2")]
153impl<T, B> Try for BufResult<T, B> {
154 type Output = (T, B);
155 type Residual = BufResult<Infallible, B>;
156
157 fn from_output((res, buf): Self::Output) -> Self {
158 Self(Ok(res), buf)
159 }
160
161 fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
162 match self {
163 BufResult(Ok(res), buf) => ControlFlow::Continue((res, buf)),
164 BufResult(Err(e), buf) => ControlFlow::Break(BufResult(Err(e), buf)),
165 }
166 }
167}
168
169#[cfg(feature = "try_trait_v2")]
170impl<T, B> Residual<(T, B)> for BufResult<Infallible, B> {
171 type TryType = BufResult<T, B>;
172}
173
174#[macro_export]
186macro_rules! buf_try {
187 ($e:expr) => {{
188 match $e {
189 $crate::BufResult(Ok(res), buf) => (res, buf),
190 $crate::BufResult(Err(e), buf) => return $crate::BufResult(Err(e), buf),
191 }
192 }};
193 ($e:expr, $b:expr) => {{
194 let buf = $b;
195 match $e {
196 Ok(res) => (res, buf),
197 Err(e) => return $crate::BufResult(Err(e), buf),
198 }
199 }};
200 (@try $e:expr) => {{
201 let $crate::BufResult(res, buf) = $e;
202 (res?, buf)
203 }};
204}