1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//! Traits for retryable conversions between types.
//!
//! Much like the rust standard library, the traits in this module provide a
//! way to convert from one type to another type, albeit with a focus on using
//! the [`Outcome`](crate::prelude::Outcome). In `outcome`'s case, only two
//! traits are provided, [`AttemptFrom`] and [`AttemptInto`], which mirror
//! [`TryFrom`] and [`TryInto`] respectively.
//!
//! As a library author, you should always prefer implementing [`AttemptFrom`]
//! over [`AttemptInto`], as [`AttemptFrom`] offers greater flexibility and
//! offers an equivalent [`AttemptInto`] implementation for free, thanks to a
//! blanket implementation in the `outcome` crate.
//!
//! # Generic Implementations
//!
//!  - [`AttemptFrom`]`<U> for T` implies [`AttemptInto`]`<T> for U`
//!
//! [`AttemptFrom`]: crate::convert::AttemptFrom
//! [`AttemptInto`]: crate::convert::AttemptInto
//! [`TryFrom`]: core::convert::TryFrom
//! [`TryInto`]: core::convert::TryInto

use core::convert::Infallible;

use crate::prelude::{Outcome, Success};

/// Outcome's analogue to [`TryFrom`], and the reciprocal of [`TryInto`].
///
/// This is useful when doing a type conversion that *might* trivially succeed,
/// but also might need special error handling. `AttemptFrom` adds the
/// additional ability to inform the caller that they are free to *retry* the
/// conversion event. This is extremely useful in cases where non-[`Copy`]able
/// types are consumed during the conversion, but users
///
///   1. Cannot control the error type returned to give useful diagnostics,
///      either to a caller further up the chain OR to logging information
///   2. May want to try a *different* conversion operation instead (e.g.,
///      trying to treat a string as a filepath *without* having to convert it
///      to the underlying native storage format first)
///
/// # Examples
///
/// ```
/// use outcome::convert::*;
/// use outcome::prelude::*;
///
/// #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
/// enum Version { V1, V2 }
///
/// #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
/// struct EmptyInput;
///
/// #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
/// enum ParseError {
///   InvalidVersion(u8),
/// }
///
/// impl std::fmt::Display for ParseError {
///   fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
///     match self {
///       Self::InvalidVersion(v) => write!(f, "Expected a valid version, received: {:x?}", v)
///     }
///   }
/// }
///
/// impl<const N: usize> AttemptFrom<&[u8; N]> for Version {
///   type Mistake = EmptyInput;
///   type Failure = ParseError;
///
///   fn attempt_from (value: &[u8; N]) -> Outcome<Self, Self::Mistake, Self::Failure> {
///     match value.get(0) {
///       None => Mistake(EmptyInput),
///       Some(&1) => Success(Version::V1),
///       Some(&2) => Success(Version::V2),
///       Some(&value) => Failure(ParseError::InvalidVersion(value)),
///     }
///   }
/// }
///
/// let empty = Version::attempt_from(&[]);
/// let v1 = Version::attempt_from(&[1u8]);
/// let v2 = Version::attempt_from(&[2u8]);
/// let v3 = Version::attempt_from(&[3u8]);
/// assert_eq!(empty, Mistake(EmptyInput));
/// assert_eq!(v1, Success(Version::V1));
/// assert_eq!(v2, Success(Version::V2));
/// assert_eq!(v3, Failure(ParseError::InvalidVersion(3)));
/// ```
///
/// [`TryFrom`]: core::convert::TryFrom
/// [`TryInto`]: core::convert::TryInto
/// [`Copy`]: core::marker::Copy
pub trait AttemptFrom<T>: Sized {
  /// The *retryable* error type
  type Mistake;
  /// The *failure* error type
  type Failure;

  /// Performs the conversion
  fn attempt_from(value: T) -> Outcome<Self, Self::Mistake, Self::Failure>;
}

/// An attempted conversion that consumes `self`, which may or may not be
/// expensive. Outcome's analogue to [`TryInto`].
///
/// Library writers should *usually* not implement this trait directly, but
/// should prefer implementing the [`AttemptFrom`] trait, which offers more
/// flexibility and provides an equivalent `AttemptInto` implementation for
/// free, thanks to the blanket implementation provided by the `outcome` crate.
///
/// Unlike [`TryInto`], users are free to return a *retryable* error, which
/// *should* return the data consumed (however this cannot be enforced in
/// practice).
///
/// For more information on this, see the documentation for [`Into`].
///
/// # Examples
///
/// The following example uses the same code from [`AttemptFrom`], but calls
/// `attempt_into` on each object instead.
///
/// ```
/// use outcome::convert::*;
/// use outcome::prelude::*;
///
/// #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
/// enum Version { V1, V2 }
///
/// #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
/// struct EmptyInput;
///
/// #[derive(Debug, PartialOrd, PartialEq, Ord, Eq, Hash)]
/// enum ParseError {
///   InvalidVersion(u8),
/// }
///
/// impl std::fmt::Display for ParseError {
///   fn fmt (&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
///     match self {
///       Self::InvalidVersion(v) => write!(f, "Expected a valid version, received: {:x?}", v)
///     }
///   }
/// }
///
/// impl<const N: usize> AttemptFrom<&[u8; N]> for Version {
///   type Mistake = EmptyInput;
///   type Failure = ParseError;
///
///   fn attempt_from (value: &[u8; N]) -> Outcome<Self, Self::Mistake, Self::Failure> {
///     match value.get(0) {
///       None => Mistake(EmptyInput),
///       Some(&1) => Success(Version::V1),
///       Some(&2) => Success(Version::V2),
///       Some(&value) => Failure(ParseError::InvalidVersion(value)),
///     }
///   }
/// }
///
/// type ParseOutcome = Outcome<Version, EmptyInput, ParseError>;
///
/// let empty: ParseOutcome = (&[]).attempt_into();
/// let v1: ParseOutcome = (&[1u8]).attempt_into();
/// let v2: ParseOutcome = (&[2u8]).attempt_into();
/// let v3: ParseOutcome = (&[3u8]).attempt_into();
/// assert_eq!(empty, Mistake(EmptyInput));
/// assert_eq!(v1, Success(Version::V1));
/// assert_eq!(v2, Success(Version::V2));
/// assert_eq!(v3, Failure(ParseError::InvalidVersion(3)));
/// ```
///
///
/// [`TryInto`]: core::convert::TryInto
/// [`Mutex`]: core::sync::Mutex
/// [`Into`]: core::convert::Into
pub trait AttemptInto<T>: Sized {
  /// The type returned in the event of a conversion error where the caller
  /// *may* retry the conversion.
  type Mistake;
  /// The type returned in the event of a conversion error where the caller
  /// *may not* retry the conversion.
  type Failure;

  /// Performs the conversion.
  fn attempt_into(self) -> Outcome<T, Self::Mistake, Self::Failure>;
}

/* Blanket Trait Implementations */
impl<T, U> AttemptInto<U> for T
where
  U: AttemptFrom<Self>,
{
  type Mistake = U::Mistake;
  type Failure = U::Failure;

  fn attempt_into(self) -> Outcome<U, Self::Mistake, Self::Failure> {
    U::attempt_from(self)
  }
}

impl<T, U> AttemptFrom<U> for T
where
  U: Into<Self>,
{
  type Mistake = Infallible;
  type Failure = Infallible;

  fn attempt_from(value: U) -> Outcome<Self, Self::Mistake, Self::Failure> {
    Success(value.into())
  }
}

// Reflexive implementation for all [`TryInto`] implementations.
//
// # Notes
//
// If a [`TryInto`] implementation exists because of an [`Into`]
// implementation, the type returned by [`AttemptFrom`] will be an `Outcome<T,
// !, !>`. If the [`unstable` feature](crate#features) is enabled, users can
// then call [`Outcome::into_success`], which will never panic.
//
// ```compile_fail
// # use outcome::prelude::*;
// # use core::convert::Infallible;
// let x: Outcome<u16, Infallible, Infallible> = 1u8.attempt_into();
// assert_eq!(x.into_success(), 1);
// ```
//impl<T, U> AttemptFrom<U> for T
//where
//  U: TryInto<Self>,
//{
//  type Mistake = Infallible;
//  type Failure = <U as TryInto<Self>>::Error;
//
//  fn attempt_from(value: U) -> Outcome<Self, Self::Mistake, Self::Failure> {
//    match value.try_into() {
//      Ok(s) => Success(s),
//      Err(f) => Failure(f),
//    }
//  }
//}