| 
 | 1 | +use crate::ops::ControlFlow;  | 
 | 2 | + | 
 | 3 | +/// The `?` operator and `try {}` blocks.  | 
 | 4 | +///  | 
 | 5 | +/// `try_*` methods typically involve a type implementing this trait.  For  | 
 | 6 | +/// example, the closures passed to [`Iterator::try_fold`] and  | 
 | 7 | +/// [`Iterator::try_for_each`] must return such a type.  | 
 | 8 | +///  | 
 | 9 | +/// `Try` types are typically those containing two or more categories of values,  | 
 | 10 | +/// some subset of which are so commonly handled via early returns that it's  | 
 | 11 | +/// worth providing a terse (but still visible) syntax to make that easy.  | 
 | 12 | +///  | 
 | 13 | +/// This is most often seen for error handling with [`Result`] and [`Option`].  | 
 | 14 | +/// The quintessential implementation of this trait is on [`ControlFlow`].  | 
 | 15 | +///  | 
 | 16 | +/// # Using `Try` in Generic Code  | 
 | 17 | +///  | 
 | 18 | +/// `Iterator::try_fold` was stabilized to call back in Rust 1.27, but  | 
 | 19 | +/// this trait is much newer.  To illustrate the various associated types and  | 
 | 20 | +/// methods, let's implement our own version.  | 
 | 21 | +///  | 
 | 22 | +/// As a reminder, an infallible version of a fold looks something like this:  | 
 | 23 | +/// ```  | 
 | 24 | +/// fn simple_fold<A, T>(  | 
 | 25 | +///     iter: impl Iterator<Item = T>,  | 
 | 26 | +///     mut accum: A,  | 
 | 27 | +///     mut f: impl FnMut(A, T) -> A,  | 
 | 28 | +/// ) -> A {  | 
 | 29 | +///     for x in iter {  | 
 | 30 | +///         accum = f(accum, x);  | 
 | 31 | +///     }  | 
 | 32 | +///     accum  | 
 | 33 | +/// }  | 
 | 34 | +/// ```  | 
 | 35 | +///  | 
 | 36 | +/// So instead of `f` returning just an `A`, we'll need it to return some other  | 
 | 37 | +/// type that produces an `A` in the "don't short circuit" path.  Conveniently,  | 
 | 38 | +/// that's also the type we need to return from the function.  | 
 | 39 | +///  | 
 | 40 | +/// Let's add a new generic parameter `R` for that type, and bound it to the  | 
 | 41 | +/// output type that we want:  | 
 | 42 | +/// ```  | 
 | 43 | +/// # #![feature(try_trait_v2)]  | 
 | 44 | +/// # #![feature(try_trait_transition)]  | 
 | 45 | +/// # use std::ops::TryV2 as Try;  | 
 | 46 | +/// fn simple_try_fold_1<A, T, R: Try<Output = A>>(  | 
 | 47 | +///     iter: impl Iterator<Item = T>,  | 
 | 48 | +///     mut accum: A,  | 
 | 49 | +///     mut f: impl FnMut(A, T) -> R,  | 
 | 50 | +/// ) -> R {  | 
 | 51 | +///     todo!()  | 
 | 52 | +/// }  | 
 | 53 | +/// ```  | 
 | 54 | +///  | 
 | 55 | +/// If we get through the entire iterator, we need to wrap up the accumulator  | 
 | 56 | +/// into the return type using [`Try::from_output`]:  | 
 | 57 | +/// ```  | 
 | 58 | +/// # #![feature(try_trait_v2)]  | 
 | 59 | +/// # #![feature(try_trait_transition)]  | 
 | 60 | +/// # #![feature(control_flow_enum)]  | 
 | 61 | +/// # use std::ops::{ControlFlow, TryV2 as Try};  | 
 | 62 | +/// fn simple_try_fold_2<A, T, R: Try<Output = A>>(  | 
 | 63 | +///     iter: impl Iterator<Item = T>,  | 
 | 64 | +///     mut accum: A,  | 
 | 65 | +///     mut f: impl FnMut(A, T) -> R,  | 
 | 66 | +/// ) -> R {  | 
 | 67 | +///     for x in iter {  | 
 | 68 | +///         let cf = f(accum, x).branch();  | 
 | 69 | +///         match cf {  | 
 | 70 | +///             ControlFlow::Continue(a) => accum = a,  | 
 | 71 | +///             ControlFlow::Break(_) => todo!(),  | 
 | 72 | +///         }  | 
 | 73 | +///     }  | 
 | 74 | +///     R::from_output(accum)  | 
 | 75 | +/// }  | 
 | 76 | +/// ```  | 
 | 77 | +///  | 
 | 78 | +/// We'll also need [`FromResidual::from_residual`] to turn the residual back  | 
 | 79 | +/// into the original type.  But because it's a supertrait of `Try`, we don't  | 
 | 80 | +/// need to mention it in the bounds.  All types which implement `Try` can be  | 
 | 81 | +/// recreated from their corresponding residual, so we'll just call it:  | 
 | 82 | +/// ```  | 
 | 83 | +/// # #![feature(try_trait_v2)]  | 
 | 84 | +/// # #![feature(try_trait_transition)]  | 
 | 85 | +/// # #![feature(control_flow_enum)]  | 
 | 86 | +/// # use std::ops::{ControlFlow, TryV2 as Try};  | 
 | 87 | +/// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>(  | 
 | 88 | +///     iter: impl Iterator<Item = T>,  | 
 | 89 | +///     mut accum: A,  | 
 | 90 | +///     mut f: impl FnMut(A, T) -> R,  | 
 | 91 | +/// ) -> R {  | 
 | 92 | +///     for x in iter {  | 
 | 93 | +///         let cf = f(accum, x).branch();  | 
 | 94 | +///         match cf {  | 
 | 95 | +///             ControlFlow::Continue(a) => accum = a,  | 
 | 96 | +///             ControlFlow::Break(r) => return R::from_residual(r),  | 
 | 97 | +///         }  | 
 | 98 | +///     }  | 
 | 99 | +///     R::from_output(accum)  | 
 | 100 | +/// }  | 
 | 101 | +/// ```  | 
 | 102 | +///  | 
 | 103 | +/// But this "call `branch`, then `match` on it, and `return` if it was a  | 
 | 104 | +/// `Break`" is exactly what happens inside the `?` operator.  So rather than  | 
 | 105 | +/// do all this manually, we can just use `?` instead:  | 
 | 106 | +/// ```compile_fail (enable again once ? converts to the new trait)  | 
 | 107 | +/// # #![feature(try_trait_v2)]  | 
 | 108 | +/// # #![feature(try_trait_transition)]  | 
 | 109 | +/// # use std::ops::TryV2 as Try;  | 
 | 110 | +/// fn simple_try_fold<A, T, R: Try<Output = A>>(  | 
 | 111 | +///     iter: impl Iterator<Item = T>,  | 
 | 112 | +///     mut accum: A,  | 
 | 113 | +///     mut f: impl FnMut(A, T) -> R,  | 
 | 114 | +/// ) -> R {  | 
 | 115 | +///     for x in iter {  | 
 | 116 | +///         accum = f(accum, x)?;  | 
 | 117 | +///     }  | 
 | 118 | +///     R::from_output(accum)  | 
 | 119 | +/// }  | 
 | 120 | +/// ```  | 
 | 121 | +#[unstable(feature = "try_trait_v2", issue = "84277")]  | 
 | 122 | +pub trait Try: FromResidual {  | 
 | 123 | +    /// The type of the value produced by `?` when *not* short-circuiting.  | 
 | 124 | +    #[unstable(feature = "try_trait_v2", issue = "84277")]  | 
 | 125 | +    type Output;  | 
 | 126 | + | 
 | 127 | +    /// The type of the value passed to [`FromResidual::from_residual`]  | 
 | 128 | +    /// as part of `?` when short-circuiting.  | 
 | 129 | +    ///  | 
 | 130 | +    /// This represents the possible values of the `Self` type which are *not*  | 
 | 131 | +    /// represented by the `Output` type.  | 
 | 132 | +    ///  | 
 | 133 | +    /// # Note to Implementors  | 
 | 134 | +    ///  | 
 | 135 | +    /// The choice of this type is critical to interconversion.  | 
 | 136 | +    /// Unlike the `Output` type, which will often be a raw generic type,  | 
 | 137 | +    /// this type is typically a newtype of some sort to "color" the type  | 
 | 138 | +    /// so that it's distinguishable from the residuals of other types.  | 
 | 139 | +    ///  | 
 | 140 | +    /// This is why `Result<T, E>::Residual` is not `E`, but `Result<Infallible, E>`.  | 
 | 141 | +    /// That way it's distinct from `ControlFlow<E>::Residual`, for example,  | 
 | 142 | +    /// and thus `?` on `ControlFlow` cannot be used in a method returning `Result`.  | 
 | 143 | +    ///  | 
 | 144 | +    /// If you're making a generic type `Foo<T>` that implements `Try<Output = T>`,  | 
 | 145 | +    /// then typically you can use `Foo<std::convert::Infallible>` as its `Residual`  | 
 | 146 | +    /// type: that type will have a "hole" in the correct place, and will maintain the  | 
 | 147 | +    /// "foo-ness" of the residual so other types need to opt-in to interconversion.  | 
 | 148 | +    #[unstable(feature = "try_trait_v2", issue = "84277")]  | 
 | 149 | +    type Residual;  | 
 | 150 | + | 
 | 151 | +    /// Constructs the type from its `Output` type.  | 
 | 152 | +    ///  | 
 | 153 | +    /// This should be implemented consistently with the `branch` method  | 
 | 154 | +    /// such that applying the `?` operator will get back the original value:  | 
 | 155 | +    /// `Try::from_output(x).branch() --> ControlFlow::Continue(x)`.  | 
 | 156 | +    ///  | 
 | 157 | +    /// # Examples  | 
 | 158 | +    ///  | 
 | 159 | +    /// ```  | 
 | 160 | +    /// #![feature(try_trait_v2)]  | 
 | 161 | +    /// #![feature(control_flow_enum)]  | 
 | 162 | +    /// #![feature(try_trait_transition)]  | 
 | 163 | +    /// use std::ops::TryV2 as Try;  | 
 | 164 | +    ///  | 
 | 165 | +    /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));  | 
 | 166 | +    /// assert_eq!(<Option<_> as Try>::from_output(4), Some(4));  | 
 | 167 | +    /// assert_eq!(  | 
 | 168 | +    ///     <std::ops::ControlFlow<String, _> as Try>::from_output(5),  | 
 | 169 | +    ///     std::ops::ControlFlow::Continue(5),  | 
 | 170 | +    /// );  | 
 | 171 | +    ///  | 
 | 172 | +    /// # fn make_question_mark_work() -> Option<()> {  | 
 | 173 | +    /// assert_eq!(Option::from_output(4)?, 4);  | 
 | 174 | +    /// # None }  | 
 | 175 | +    /// # make_question_mark_work();  | 
 | 176 | +    ///  | 
 | 177 | +    /// // This is used, for example, on the accumulator in `try_fold`:  | 
 | 178 | +    /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() });  | 
 | 179 | +    /// assert_eq!(r, Some(4));  | 
 | 180 | +    /// ```  | 
 | 181 | +    #[unstable(feature = "try_trait_v2", issue = "84277")]  | 
 | 182 | +    fn from_output(output: Self::Output) -> Self;  | 
 | 183 | + | 
 | 184 | +    /// Used in `?` to decide whether the operator should produce a value  | 
 | 185 | +    /// (because this returned [`ControlFlow::Continue`])  | 
 | 186 | +    /// or propagate a value back to the caller  | 
 | 187 | +    /// (because this returned [`ControlFlow::Break`]).  | 
 | 188 | +    ///  | 
 | 189 | +    /// # Examples  | 
 | 190 | +    ///  | 
 | 191 | +    /// ```  | 
 | 192 | +    /// #![feature(try_trait_v2)]  | 
 | 193 | +    /// #![feature(control_flow_enum)]  | 
 | 194 | +    /// #![feature(try_trait_transition)]  | 
 | 195 | +    /// use std::ops::{ControlFlow, TryV2 as Try};  | 
 | 196 | +    ///  | 
 | 197 | +    /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));  | 
 | 198 | +    /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3)));  | 
 | 199 | +    ///  | 
 | 200 | +    /// assert_eq!(Some(3).branch(), ControlFlow::Continue(3));  | 
 | 201 | +    /// assert_eq!(None::<String>.branch(), ControlFlow::Break(None));  | 
 | 202 | +    ///  | 
 | 203 | +    /// assert_eq!(ControlFlow::<String, _>::Continue(3).branch(), ControlFlow::Continue(3));  | 
 | 204 | +    /// assert_eq!(  | 
 | 205 | +    ///     ControlFlow::<_, String>::Break(3).branch(),  | 
 | 206 | +    ///     ControlFlow::Break(ControlFlow::Break(3)),  | 
 | 207 | +    /// );  | 
 | 208 | +    /// ```  | 
 | 209 | +    #[unstable(feature = "try_trait_v2", issue = "84277")]  | 
 | 210 | +    fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;  | 
 | 211 | +}  | 
 | 212 | + | 
 | 213 | +/// Used to specify which residuals can be converted into which [`Try`] types.  | 
 | 214 | +///  | 
 | 215 | +/// Every `Try` type needs to be recreatable from its own associated  | 
 | 216 | +/// `Residual` type, but can also have additional `FromResidual` implementations  | 
 | 217 | +/// to support interconversion with other `Try` types.  | 
 | 218 | +#[unstable(feature = "try_trait_v2", issue = "84277")]  | 
 | 219 | +pub trait FromResidual<R = <Self as Try>::Residual> {  | 
 | 220 | +    /// Constructs the type from a compatible `Residual` type.  | 
 | 221 | +    ///  | 
 | 222 | +    /// This should be implemented consistently with the `branch` method such  | 
 | 223 | +    /// that applying the `?` operator will get back an equivalent residual:  | 
 | 224 | +    /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`.  | 
 | 225 | +    /// (It may not be an *identical* residual when interconversion is involved.)  | 
 | 226 | +    ///  | 
 | 227 | +    /// # Examples  | 
 | 228 | +    ///  | 
 | 229 | +    /// ```  | 
 | 230 | +    /// #![feature(try_trait_v2)]  | 
 | 231 | +    /// #![feature(control_flow_enum)]  | 
 | 232 | +    /// use std::ops::{ControlFlow, FromResidual};  | 
 | 233 | +    ///  | 
 | 234 | +    /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));  | 
 | 235 | +    /// assert_eq!(Option::<String>::from_residual(None), None);  | 
 | 236 | +    /// assert_eq!(  | 
 | 237 | +    ///     ControlFlow::<_, String>::from_residual(ControlFlow::Break(5)),  | 
 | 238 | +    ///     ControlFlow::Break(5),  | 
 | 239 | +    /// );  | 
 | 240 | +    /// ```  | 
 | 241 | +    #[unstable(feature = "try_trait_v2", issue = "84277")]  | 
 | 242 | +    fn from_residual(residual: R) -> Self;  | 
 | 243 | +}  | 
0 commit comments