]> git.lizzy.rs Git - rust.git/blob - src/libstd/result.rs
std: add result.map_move, result.map_err_move
[rust.git] / src / libstd / result.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! A type representing either success or failure
12
13 #[allow(missing_doc)];
14
15 use clone::Clone;
16 use cmp::Eq;
17 use either;
18 use iterator::Iterator;
19 use option::{None, Option, Some, OptionIterator};
20 use vec;
21 use vec::{OwnedVector, ImmutableVector};
22 use container::Container;
23 use to_str::ToStr;
24 use str::StrSlice;
25
26 /// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
27 ///
28 /// In order to provide informative error messages, `E` is reqired to implement `ToStr`.
29 /// It is further recommended for `E` to be a descriptive error type, eg a `enum` for
30 /// all possible errors cases.
31 #[deriving(Clone, Eq)]
32 pub enum Result<T, E> {
33     /// Contains the successful result value
34     Ok(T),
35     /// Contains the error value
36     Err(E)
37 }
38
39 impl<T, E: ToStr> Result<T, E> {
40     /// Convert to the `either` type
41     ///
42     /// `Ok` result variants are converted to `either::Right` variants, `Err`
43     /// result variants are converted to `either::Left`.
44     #[inline]
45     pub fn to_either(self)-> either::Either<E, T>{
46         match self {
47             Ok(t) => either::Right(t),
48             Err(e) => either::Left(e),
49         }
50     }
51
52     /// Get a reference to the value out of a successful result
53     ///
54     /// # Failure
55     ///
56     /// If the result is an error
57     #[inline]
58     pub fn get_ref<'a>(&'a self) -> &'a T {
59         match *self {
60             Ok(ref t) => t,
61             Err(ref e) => fail!("called `Result::get_ref()` on `Err` value: %s", e.to_str()),
62         }
63     }
64
65     /// Returns true if the result is `Ok`
66     #[inline]
67     pub fn is_ok(&self) -> bool {
68         match *self {
69             Ok(_) => true,
70             Err(_) => false
71         }
72     }
73
74     /// Returns true if the result is `Err`
75     #[inline]
76     pub fn is_err(&self) -> bool {
77         !self.is_ok()
78     }
79
80     /// Call a method based on a previous result
81     ///
82     /// If `self` is `Ok` then the value is extracted and passed to `op`
83     /// whereupon `op`s result is returned. if `self` is `Err` then it is
84     /// immediately returned. This function can be used to compose the results
85     /// of two functions.
86     ///
87     /// Example:
88     ///
89     ///     for buf in read_file(file) {
90     ///         print_buf(buf)
91     ///     }
92     #[inline]
93     pub fn iter<'r>(&'r self) -> OptionIterator<&'r T> {
94         match *self {
95             Ok(ref t) => Some(t),
96             Err(*) => None,
97         }.consume()
98     }
99
100     /// Call a method based on a previous result
101     ///
102     /// If `self` is `Err` then the value is extracted and passed to `op`
103     /// whereupon `op`s result is returned. if `self` is `Ok` then it is
104     /// immediately returned.  This function can be used to pass through a
105     /// successful result while handling an error.
106     #[inline]
107     pub fn iter_err<'r>(&'r self) -> OptionIterator<&'r E> {
108         match *self {
109             Ok(*) => None,
110             Err(ref t) => Some(t),
111         }.consume()
112     }
113
114     /// Unwraps a result, yielding the content of an `Ok`.
115     /// Fails if the value is a `Err` with an error message derived
116     /// from `E`'s `ToStr` implementation.
117     #[inline]
118     pub fn unwrap(self) -> T {
119         match self {
120             Ok(t) => t,
121             Err(e) => fail!("called `Result::unwrap()` on `Err` value: %s", e.to_str()),
122         }
123     }
124
125     /// Unwraps a result, yielding the content of an `Err`.
126     /// Fails if the value is a `Ok`.
127     #[inline]
128     pub fn unwrap_err(self) -> E {
129         self.expect_err("called `Result::unwrap_err()` on `Ok` value")
130     }
131
132     /// Unwraps a result, yielding the content of an `Ok`.
133     /// Fails if the value is a `Err` with a custom failure message.
134     #[inline]
135     pub fn expect(self, reason: &str) -> T {
136         match self {
137             Ok(t) => t,
138             Err(_) => fail!(reason.to_owned()),
139         }
140     }
141
142     /// Unwraps a result, yielding the content of an `Err`
143     /// Fails if the value is a `Ok` with a custom failure message.
144     #[inline]
145     pub fn expect_err(self, reason: &str) -> E {
146         match self {
147             Err(e) => e,
148             Ok(_) => fail!(reason.to_owned()),
149         }
150     }
151
152     /// Call a method based on a previous result
153     ///
154     /// If `self` is `Ok` then the value is extracted and passed to `op`
155     /// whereupon `op`s result is wrapped in `Ok` and returned. if `self` is
156     /// `Err` then it is immediately returned.  This function can be used to
157     /// compose the results of two functions.
158     ///
159     /// Example:
160     ///
161     ///     let res = do read_file(file).map_move |buf| {
162     ///         parse_bytes(buf)
163     ///     }
164     #[inline]
165     pub fn map_move<U>(self, op: &fn(T) -> U) -> Result<U,E> {
166         match self {
167           Ok(t) => Ok(op(t)),
168           Err(e) => Err(e)
169         }
170     }
171
172     /// Call a method based on a previous result
173     ///
174     /// If `self` is `Err` then the value is extracted and passed to `op`
175     /// whereupon `op`s result is wrapped in an `Err` and returned. if `self` is
176     /// `Ok` then it is immediately returned.  This function can be used to pass
177     /// through a successful result while handling an error.
178     #[inline]
179     pub fn map_err_move<F>(self, op: &fn(E) -> F) -> Result<T,F> {
180         match self {
181           Ok(t) => Ok(t),
182           Err(e) => Err(op(e))
183         }
184     }
185
186     /// Call a method based on a previous result
187     ///
188     /// If `self` is `Ok` then the value is extracted and passed to `op`
189     /// whereupon `op`s result is returned. if `self` is `Err` then it is
190     /// immediately returned. This function can be used to compose the results
191     /// of two functions.
192     ///
193     /// Example:
194     ///
195     ///     let res = do read_file(file) |buf| {
196     ///         Ok(parse_bytes(buf))
197     ///     };
198     #[inline]
199     pub fn chain<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> {
200         match self {
201             Ok(t) => op(t),
202             Err(e) => Err(e),
203         }
204     }
205
206     /// Call a function based on a previous result
207     ///
208     /// If `self` is `Err` then the value is extracted and passed to `op`
209     /// whereupon `op`s result is returned. if `self` is `Ok` then it is
210     /// immediately returned.  This function can be used to pass through a
211     /// successful result while handling an error.
212     #[inline]
213     pub fn chain_err<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> {
214         match self {
215             Ok(t) => Ok(t),
216             Err(e) => op(e),
217         }
218     }
219 }
220
221 impl<T: Clone, E: ToStr> Result<T, E> {
222     /// Call a method based on a previous result
223     ///
224     /// If `self` is `Err` then the value is extracted and passed to `op`
225     /// whereupon `op`s result is wrapped in an `Err` and returned. if `self` is
226     /// `Ok` then it is immediately returned.  This function can be used to pass
227     /// through a successful result while handling an error.
228     #[inline]
229     pub fn map_err<F: Clone>(&self, op: &fn(&E) -> F) -> Result<T,F> {
230         match *self {
231             Ok(ref t) => Ok(t.clone()),
232             Err(ref e) => Err(op(e))
233         }
234     }
235 }
236
237 impl<T, E: Clone + ToStr> Result<T, E> {
238     /// Call a method based on a previous result
239     ///
240     /// If `self` is `Ok` then the value is extracted and passed to `op`
241     /// whereupon `op`s result is wrapped in `Ok` and returned. if `self` is
242     /// `Err` then it is immediately returned.  This function can be used to
243     /// compose the results of two functions.
244     ///
245     /// Example:
246     ///
247     ///     let res = do read_file(file).map |buf| {
248     ///         parse_bytes(buf)
249     ///     };
250     #[inline]
251     pub fn map<U>(&self, op: &fn(&T) -> U) -> Result<U,E> {
252         match *self {
253             Ok(ref t) => Ok(op(t)),
254             Err(ref e) => Err(e.clone())
255         }
256     }
257 }
258
259 #[inline]
260 #[allow(missing_doc)]
261 pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>,
262                                op: &fn(&T) -> Result<V,U>) -> Result<Option<V>,U> {
263     match *o_t {
264         None => Ok(None),
265         Some(ref t) => match op(t) {
266             Ok(v) => Ok(Some(v)),
267             Err(e) => Err(e)
268         }
269     }
270 }
271
272 // FIXME: #8228 Replaceable by an external iterator?
273 /// Maps each element in the vector `ts` using the operation `op`.  Should an
274 /// error occur, no further mappings are performed and the error is returned.
275 /// Should no error occur, a vector containing the result of each map is
276 /// returned.
277 ///
278 /// Here is an example which increments every integer in a vector,
279 /// checking for overflow:
280 ///
281 ///     fn inc_conditionally(x: uint) -> result<uint,str> {
282 ///         if x == uint::max_value { return Err("overflow"); }
283 ///         else { return Ok(x+1u); }
284 ///     }
285 ///     map(~[1u, 2u, 3u], inc_conditionally).chain {|incd|
286 ///         assert!(incd == ~[2u, 3u, 4u]);
287 ///     }
288 #[inline]
289 pub fn map_vec<T,U,V>(ts: &[T], op: &fn(&T) -> Result<V,U>)
290                       -> Result<~[V],U> {
291     let mut vs: ~[V] = vec::with_capacity(ts.len());
292     for t in ts.iter() {
293         match op(t) {
294           Ok(v) => vs.push(v),
295           Err(u) => return Err(u)
296         }
297     }
298     return Ok(vs);
299 }
300
301 // FIXME: #8228 Replaceable by an external iterator?
302 /// Same as map, but it operates over two parallel vectors.
303 ///
304 /// A precondition is used here to ensure that the vectors are the same
305 /// length.  While we do not often use preconditions in the standard
306 /// library, a precondition is used here because result::t is generally
307 /// used in 'careful' code contexts where it is both appropriate and easy
308 /// to accommodate an error like the vectors being of different lengths.
309 #[inline]
310 pub fn map_vec2<S, T, U: ToStr, V>(ss: &[S], ts: &[T],
311                                    op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> {
312     assert!(vec::same_length(ss, ts));
313     let n = ts.len();
314     let mut vs = vec::with_capacity(n);
315     let mut i = 0u;
316     while i < n {
317         match op(&ss[i],&ts[i]) {
318           Ok(v) => vs.push(v),
319           Err(u) => return Err(u)
320         }
321         i += 1u;
322     }
323     return Ok(vs);
324 }
325
326 // FIXME: #8228 Replaceable by an external iterator?
327 /// Applies op to the pairwise elements from `ss` and `ts`, aborting on
328 /// error.  This could be implemented using `map_zip()` but it is more efficient
329 /// on its own as no result vector is built.
330 #[inline]
331 pub fn iter_vec2<S, T, U: ToStr>(ss: &[S], ts: &[T],
332                                  op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> {
333     assert!(vec::same_length(ss, ts));
334     let n = ts.len();
335     let mut i = 0u;
336     while i < n {
337         match op(&ss[i],&ts[i]) {
338           Ok(()) => (),
339           Err(u) => return Err(u)
340         }
341         i += 1u;
342     }
343     return Ok(());
344 }
345
346 #[cfg(test)]
347 mod tests {
348     use super::*;
349
350     use either;
351     use str::OwnedStr;
352
353     pub fn op1() -> Result<int, ~str> { Ok(666) }
354
355     pub fn op2(i: int) -> Result<uint, ~str> {
356         Ok(i as uint + 1u)
357     }
358
359     pub fn op3() -> Result<int, ~str> { Err(~"sadface") }
360
361     #[test]
362     pub fn chain_success() {
363         assert_eq!(op1().chain(op2).unwrap(), 667u);
364     }
365
366     #[test]
367     pub fn chain_failure() {
368         assert_eq!(op3().chain( op2).unwrap_err(), ~"sadface");
369     }
370
371     #[test]
372     pub fn test_impl_iter() {
373         let mut valid = false;
374         let okval = Ok::<~str, ~str>(~"a");
375         do okval.iter().next().map |_| { valid = true; };
376         assert!(valid);
377
378         let errval = Err::<~str, ~str>(~"b");
379         do errval.iter().next().map |_| { valid = false; };
380         assert!(valid);
381     }
382
383     #[test]
384     pub fn test_impl_iter_err() {
385         let mut valid = true;
386         let okval = Ok::<~str, ~str>(~"a");
387         do okval.iter_err().next().map |_| { valid = false };
388         assert!(valid);
389
390         valid = false;
391         let errval = Err::<~str, ~str>(~"b");
392         do errval.iter_err().next().map |_| { valid = true };
393         assert!(valid);
394     }
395
396     #[test]
397     pub fn test_impl_map() {
398         assert_eq!(Ok::<~str, ~str>(~"a").map(|x| (~"b").append(*x)), Ok(~"ba"));
399         assert_eq!(Err::<~str, ~str>(~"a").map(|x| (~"b").append(*x)), Err(~"a"));
400     }
401
402     #[test]
403     pub fn test_impl_map_err() {
404         assert_eq!(Ok::<~str, ~str>(~"a").map_err(|x| (~"b").append(*x)), Ok(~"a"));
405         assert_eq!(Err::<~str, ~str>(~"a").map_err(|x| (~"b").append(*x)), Err(~"ba"));
406     }
407
408     #[test]
409     pub fn test_impl_map_move() {
410         assert_eq!(Ok::<~str, ~str>(~"a").map_move(|x| x + ~"b"), Ok(~"ab"));
411         assert_eq!(Err::<~str, ~str>(~"a").map_move(|x| x + ~"b"), Err(~"a"));
412     }
413
414     #[test]
415     pub fn test_impl_map_err_move() {
416         assert_eq!(Ok::<~str, ~str>(~"a").map_err_move(|x| x + ~"b"), Ok(~"a"));
417         assert_eq!(Err::<~str, ~str>(~"a").map_err_move(|x| x + ~"b"), Err(~"ab"));
418     }
419
420     #[test]
421     pub fn test_get_ref_method() {
422         let foo: Result<int, ()> = Ok(100);
423         assert_eq!(*foo.get_ref(), 100);
424     }
425
426     #[test]
427     pub fn test_to_either() {
428         let r: Result<int, ()> = Ok(100);
429         let err: Result<(), int> = Err(404);
430
431         assert_eq!(r.to_either(), either::Right(100));
432         assert_eq!(err.to_either(), either::Left(404));
433     }
434 }