1#[cfg(feature = "try_trait_v2")]
2use std::{
3 convert::Infallible,
4 ops::{ControlFlow, FromResidual, Residual, Try},
5};
6use std::{fmt::Debug, io};
7
8use crate::IntoInner;
9
10#[must_use]
17#[derive(Debug)]
18pub struct BufResult<T, B>(pub io::Result<T>, pub B);
19
20impl<T, B> BufResult<T, B> {
21 pub const fn is_ok(&self) -> bool {
23 self.0.is_ok()
24 }
25
26 pub const fn is_err(&self) -> bool {
28 self.0.is_err()
29 }
30
31 #[inline]
33 pub fn map<U>(self, f: impl FnOnce(T, B) -> (U, B)) -> BufResult<U, B> {
34 match self.0 {
35 Ok(res) => {
36 let (res, buf) = f(res, self.1);
37 BufResult(Ok(res), buf)
38 }
39 Err(e) => BufResult(Err(e), self.1),
40 }
41 }
42
43 #[inline]
45 pub fn map2<U, C>(
46 self,
47 f_ok: impl FnOnce(T, B) -> (U, C),
48 f_err: impl FnOnce(B) -> C,
49 ) -> BufResult<U, C> {
50 match self.0 {
51 Ok(res) => {
52 let (res, buf) = f_ok(res, self.1);
53 BufResult(Ok(res), buf)
54 }
55 Err(e) => BufResult(Err(e), f_err(self.1)),
56 }
57 }
58
59 #[inline]
61 pub fn map_res<U>(self, f: impl FnOnce(T) -> U) -> BufResult<U, B> {
62 BufResult(self.0.map(f), self.1)
63 }
64
65 #[inline]
67 pub fn map_buffer<C>(self, f: impl FnOnce(B) -> C) -> BufResult<T, C> {
68 BufResult(self.0, f(self.1))
69 }
70
71 #[inline]
73 pub fn and_then<U>(self, f: impl FnOnce(T, B) -> (io::Result<U>, B)) -> BufResult<U, B> {
74 match self.0 {
75 Ok(res) => BufResult::from(f(res, self.1)),
76 Err(e) => BufResult(Err(e), self.1),
77 }
78 }
79
80 #[inline]
82 #[track_caller]
83 pub fn expect(self, msg: &str) -> (T, B) {
84 (self.0.expect(msg), self.1)
85 }
86
87 #[inline(always)]
89 #[track_caller]
90 pub fn unwrap(self) -> (T, B) {
91 (self.0.unwrap(), self.1)
92 }
93
94 #[inline]
96 pub fn into_parts(self) -> (io::Result<T>, B) {
97 (self.0, self.1)
98 }
99}
100
101impl<T: Debug, B> BufResult<T, B> {
102 #[inline(always)]
104 #[track_caller]
105 pub fn unwrap_err(self) -> (io::Error, B) {
106 (self.0.unwrap_err(), self.1)
107 }
108}
109
110impl<T, B> From<(io::Result<T>, B)> for BufResult<T, B> {
111 fn from((res, buf): (io::Result<T>, B)) -> Self {
112 Self(res, buf)
113 }
114}
115
116impl<T, B> From<BufResult<T, B>> for (io::Result<T>, B) {
117 fn from(BufResult(res, buf): BufResult<T, B>) -> Self {
118 (res, buf)
119 }
120}
121
122impl<T: IntoInner, O> IntoInner for BufResult<O, T> {
123 type Inner = BufResult<O, T::Inner>;
124
125 fn into_inner(self) -> Self::Inner {
126 BufResult(self.0, self.1.into_inner())
127 }
128}
129
130#[cfg(feature = "try_trait_v2")]
141impl<T, B> FromResidual<BufResult<Infallible, B>> for BufResult<T, B> {
142 fn from_residual(residual: BufResult<Infallible, B>) -> Self {
143 match residual {
144 BufResult(Err(e), b) => BufResult(Err(e), b),
145 }
146 }
147}
148
149#[cfg(feature = "try_trait_v2")]
160impl<T, B, E> FromResidual<BufResult<Infallible, B>> for Result<T, E>
161where
162 E: From<io::Error>,
163{
164 fn from_residual(residual: BufResult<Infallible, B>) -> Self {
165 match residual {
166 BufResult(Err(e), _) => Err(e.into()),
167 }
168 }
169}
170
171#[cfg(feature = "try_trait_v2")]
172impl<T, B> Try for BufResult<T, B> {
173 type Output = (T, B);
174 type Residual = BufResult<Infallible, B>;
175
176 fn from_output((res, buf): Self::Output) -> Self {
177 Self(Ok(res), buf)
178 }
179
180 fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
181 match self {
182 BufResult(Ok(res), buf) => ControlFlow::Continue((res, buf)),
183 BufResult(Err(e), buf) => ControlFlow::Break(BufResult(Err(e), buf)),
184 }
185 }
186}
187
188#[cfg(feature = "try_trait_v2")]
189impl<T, B> Residual<(T, B)> for BufResult<Infallible, B> {
190 type TryType = BufResult<T, B>;
191}
192
193#[macro_export]
205macro_rules! buf_try {
206 ($e:expr) => {{
207 match $e {
208 $crate::BufResult(Ok(res), buf) => (res, buf),
209 $crate::BufResult(Err(e), buf) => return $crate::BufResult(Err(e), buf),
210 }
211 }};
212 ($e:expr, $b:expr) => {{
213 let buf = $b;
214 match $e {
215 Ok(res) => (res, buf),
216 Err(e) => return $crate::BufResult(Err(e), buf),
217 }
218 }};
219 (@try $e:expr) => {{
220 let $crate::BufResult(res, buf) = $e;
221 (res?, buf)
222 }};
223}
224
225#[cfg(test)]
226mod test {
227 #[cfg(feature = "try_trait_v2")]
228 #[test]
229 fn test_buf_result_try() {
230 use crate::BufResult;
231
232 fn returns_buf_result() -> BufResult<i32, i32> {
233 let (a, b) = BufResult(Ok(1), 2)?;
234 assert_eq!(a, 1);
235 assert_eq!(b, 2);
236 (Ok(3), 4).into()
237 }
238 assert!(returns_buf_result().is_ok());
239
240 fn returns_result() -> std::io::Result<i32> {
241 let (a, b) = BufResult(Ok(1), 2)?;
242 assert_eq!(a, 1);
243 assert_eq!(b, 2);
244 Ok(3)
245 }
246 assert!(returns_result().is_ok());
247
248 struct MyError;
249
250 impl From<std::io::Error> for MyError {
251 fn from(_: std::io::Error) -> Self {
252 MyError
253 }
254 }
255
256 fn returns_custom_result() -> Result<i32, MyError> {
257 let (a, b) = BufResult(Ok(1), 2)?;
258 assert_eq!(a, 1);
259 assert_eq!(b, 2);
260 Ok(3)
261 }
262 assert!(returns_custom_result().is_ok());
263 }
264}