result.rs 11.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
//! A type representing either success or failure
12

B
Brian Anderson 已提交
13
// NB: transitionary, de-mode-ing.
14

P
Patrick Walton 已提交
15
use cmp::Eq;
16
use either;
P
Patrick Walton 已提交
17
use either::Either;
18 19
use kinds::Copy;
use option::{None, Option, Some};
20
use vec;
21

22
/// The result type
23
#[deriving(Clone, Eq)]
24
pub enum Result<T, U> {
25
    /// Contains the successful result value
26
    Ok(T),
27
    /// Contains the error value
28
    Err(U)
29 30
}

31 32 33 34 35 36 37
/**
 * Get the value out of a successful result
 *
 * # Failure
 *
 * If the result is an error
 */
G
gifnksm 已提交
38
#[inline(always)]
39
pub fn get<T:Copy,U>(res: &Result<T, U>) -> T {
B
Brian Anderson 已提交
40
    match *res {
B
Brian Anderson 已提交
41
      Ok(copy t) => t,
42
      Err(ref the_err) =>
43
        fail!(fmt!("get called on error result: %?", *the_err))
44 45 46
    }
}

47 48 49 50 51 52 53
/**
 * Get a reference to the value out of a successful result
 *
 * # Failure
 *
 * If the result is an error
 */
G
gifnksm 已提交
54
#[inline(always)]
55
pub fn get_ref<'a, T, U>(res: &'a Result<T, U>) -> &'a T {
56
    match *res {
57
        Ok(ref t) => t,
58
        Err(ref the_err) =>
59
            fail!(fmt!("get_ref called on error result: %?", *the_err))
60 61 62
    }
}

63 64 65 66 67 68 69
/**
 * Get the value out of an error result
 *
 * # Failure
 *
 * If the result is not an error
 */
G
gifnksm 已提交
70
#[inline(always)]
71
pub fn get_err<T, U: Copy>(res: &Result<T, U>) -> U {
B
Brian Anderson 已提交
72
    match *res {
B
Brian Anderson 已提交
73
      Err(copy u) => u,
74
      Ok(_) => fail!(~"get_err called on ok result")
75 76 77
    }
}

78
/// Returns true if the result is `ok`
G
gifnksm 已提交
79
#[inline(always)]
80
pub fn is_ok<T, U>(res: &Result<T, U>) -> bool {
B
Brian Anderson 已提交
81
    match *res {
82 83
      Ok(_) => true,
      Err(_) => false
84 85 86
    }
}

87
/// Returns true if the result is `err`
G
gifnksm 已提交
88
#[inline(always)]
89
pub fn is_err<T, U>(res: &Result<T, U>) -> bool {
90
    !is_ok(res)
91 92
}

93 94 95 96 97 98
/**
 * Convert to the `either` type
 *
 * `ok` result variants are converted to `either::right` variants, `err`
 * result variants are converted to `either::left`.
 */
G
gifnksm 已提交
99
#[inline(always)]
100
pub fn to_either<T:Copy,U:Copy>(res: &Result<U, T>)
101
    -> Either<T, U> {
B
Brian Anderson 已提交
102
    match *res {
B
Brian Anderson 已提交
103 104
      Ok(copy res) => either::Right(res),
      Err(copy fail_) => either::Left(fail_)
105 106 107
    }
}

108 109 110 111 112 113 114 115 116 117 118
/**
 * Call a function based on a previous result
 *
 * If `res` is `ok` then the value is extracted and passed to `op` whereupon
 * `op`s result is returned. if `res` is `err` then it is immediately
 * returned. This function can be used to compose the results of two
 * functions.
 *
 * Example:
 *
 *     let res = chain(read_file(file)) { |buf|
119
 *         ok(parse_bytes(buf))
120 121
 *     }
 */
G
gifnksm 已提交
122
#[inline(always)]
123
pub fn chain<T, U, V>(res: Result<T, V>, op: &fn(T)
T
Tim Chevalier 已提交
124
    -> Result<U, V>) -> Result<U, V> {
L
Luqman Aden 已提交
125 126 127
    match res {
        Ok(t) => op(t),
        Err(e) => Err(e)
128 129
    }
}
130

131 132 133 134 135 136 137 138
/**
 * Call a function based on a previous result
 *
 * If `res` is `err` then the value is extracted and passed to `op`
 * whereupon `op`s result is returned. if `res` is `ok` then it is
 * immediately returned.  This function can be used to pass through a
 * successful result while handling an error.
 */
G
gifnksm 已提交
139
#[inline(always)]
140
pub fn chain_err<T, U, V>(
T
Tim Chevalier 已提交
141
    res: Result<T, V>,
142
    op: &fn(t: V) -> Result<T, U>)
143
    -> Result<T, U> {
L
Luqman Aden 已提交
144 145 146
    match res {
      Ok(t) => Ok(t),
      Err(v) => op(v)
147 148 149
    }
}

150 151 152 153 154 155 156 157 158 159 160 161 162 163
/**
 * Call a function based on a previous result
 *
 * If `res` is `ok` then the value is extracted and passed to `op` whereupon
 * `op`s result is returned. if `res` is `err` then it is immediately
 * returned. This function can be used to compose the results of two
 * functions.
 *
 * Example:
 *
 *     iter(read_file(file)) { |buf|
 *         print_buf(buf)
 *     }
 */
G
gifnksm 已提交
164
#[inline(always)]
165
pub fn iter<T, E>(res: &Result<T, E>, f: &fn(&T)) {
B
Brian Anderson 已提交
166
    match *res {
B
Brian Anderson 已提交
167
      Ok(ref t) => f(t),
168
      Err(_) => ()
169 170 171
    }
}

172 173 174 175 176 177 178 179
/**
 * Call a function based on a previous result
 *
 * If `res` is `err` then the value is extracted and passed to `op` whereupon
 * `op`s result is returned. if `res` is `ok` then it is immediately returned.
 * This function can be used to pass through a successful result while
 * handling an error.
 */
G
gifnksm 已提交
180
#[inline(always)]
181
pub fn iter_err<T, E>(res: &Result<T, E>, f: &fn(&E)) {
B
Brian Anderson 已提交
182
    match *res {
183
      Ok(_) => (),
B
Brian Anderson 已提交
184
      Err(ref e) => f(e)
185 186 187
    }
}

188 189 190 191 192 193 194 195 196 197 198
/**
 * Call a function based on a previous result
 *
 * If `res` is `ok` then the value is extracted and passed to `op` whereupon
 * `op`s result is wrapped in `ok` and returned. if `res` is `err` then it is
 * immediately returned.  This function can be used to compose the results of
 * two functions.
 *
 * Example:
 *
 *     let res = map(read_file(file)) { |buf|
199
 *         parse_bytes(buf)
200 201
 *     }
 */
G
gifnksm 已提交
202
#[inline(always)]
203
pub fn map<T, E: Copy, U: Copy>(res: &Result<T, E>, op: &fn(&T) -> U)
204
  -> Result<U, E> {
B
Brian Anderson 已提交
205
    match *res {
B
Brian Anderson 已提交
206 207
      Ok(ref t) => Ok(op(t)),
      Err(copy e) => Err(e)
208 209 210
    }
}

211 212 213 214 215 216 217 218
/**
 * Call a function based on a previous result
 *
 * If `res` is `err` then the value is extracted and passed to `op` whereupon
 * `op`s result is wrapped in an `err` and returned. if `res` is `ok` then it
 * is immediately returned.  This function can be used to pass through a
 * successful result while handling an error.
 */
G
gifnksm 已提交
219
#[inline(always)]
220
pub fn map_err<T:Copy,E,F:Copy>(res: &Result<T, E>, op: &fn(&E) -> F)
221
  -> Result<T, F> {
B
Brian Anderson 已提交
222
    match *res {
B
Brian Anderson 已提交
223 224
      Ok(copy t) => Ok(t),
      Err(ref e) => Err(op(e))
225 226 227
    }
}

228
pub impl<T, E> Result<T, E> {
229
    #[inline(always)]
230
    fn get_ref(&self) -> &'self T { get_ref(self) }
B
Brian Anderson 已提交
231

232
    #[inline(always)]
233
    fn is_ok(&self) -> bool { is_ok(self) }
234

235
    #[inline(always)]
236
    fn is_err(&self) -> bool { is_err(self) }
237

238
    #[inline(always)]
239
    fn iter(&self, f: &fn(&T)) { iter(self, f) }
240 241

    #[inline(always)]
242
    fn iter_err(&self, f: &fn(&E)) { iter_err(self, f) }
243 244

    #[inline(always)]
245
    fn unwrap(self) -> T { unwrap(self) }
246 247

    #[inline(always)]
248
    fn unwrap_err(self) -> E { unwrap_err(self) }
249 250

    #[inline(always)]
251
    fn chain<U>(self, op: &fn(T) -> Result<U,E>) -> Result<U,E> {
252
        chain(self, op)
253 254
    }

255
    #[inline(always)]
256
    fn chain_err<F>(self, op: &fn(E) -> Result<T,F>) -> Result<T,F> {
257
        chain_err(self, op)
258
    }
259 260
}

261
pub impl<T:Copy,E> Result<T, E> {
262
    #[inline(always)]
263
    fn get(&self) -> T { get(self) }
264

265
    #[inline(always)]
266
    fn map_err<F:Copy>(&self, op: &fn(&E) -> F) -> Result<T,F> {
267
        map_err(self, op)
268 269 270
    }
}

271
pub impl<T, E: Copy> Result<T, E> {
272
    #[inline(always)]
273
    fn get_err(&self) -> E { get_err(self) }
274

275
    #[inline(always)]
276
    fn map<U:Copy>(&self, op: &fn(&T) -> U) -> Result<U,E> {
277
        map(self, op)
278
    }
279
}
280

281 282 283 284 285 286 287 288 289 290
/**
 * Maps each element in the vector `ts` using the operation `op`.  Should an
 * error occur, no further mappings are performed and the error is returned.
 * Should no error occur, a vector containing the result of each map is
 * returned.
 *
 * Here is an example which increments every integer in a vector,
 * checking for overflow:
 *
 *     fn inc_conditionally(x: uint) -> result<uint,str> {
B
Brian Anderson 已提交
291 292
 *         if x == uint::max_value { return err("overflow"); }
 *         else { return ok(x+1u); }
293
 *     }
294
 *     map(~[1u, 2u, 3u], inc_conditionally).chain {|incd|
P
Patrick Walton 已提交
295
 *         assert!(incd == ~[2u, 3u, 4u]);
296 297
 *     }
 */
G
gifnksm 已提交
298
#[inline(always)]
299
pub fn map_vec<T,U:Copy,V:Copy>(
300
    ts: &[T], op: &fn(&T) -> Result<V,U>) -> Result<~[V],U> {
301

302
    let mut vs: ~[V] = vec::with_capacity(vec::len(ts));
303
    for vec::each(ts) |t| {
304
        match op(t) {
B
Brian Anderson 已提交
305 306
          Ok(copy v) => vs.push(v),
          Err(copy u) => return Err(u)
307 308
        }
    }
L
Luqman Aden 已提交
309
    return Ok(vs);
310 311
}

G
gifnksm 已提交
312
#[inline(always)]
313
pub fn map_opt<T,U:Copy,V:Copy>(
314
    o_t: &Option<T>, op: &fn(&T) -> Result<V,U>) -> Result<Option<V>,U> {
315

B
Brian Anderson 已提交
316
    match *o_t {
317
      None => Ok(None),
B
Brian Anderson 已提交
318 319 320
      Some(ref t) => match op(t) {
        Ok(copy v) => Ok(Some(v)),
        Err(copy e) => Err(e)
321 322 323 324
      }
    }
}

325 326 327 328 329 330 331 332 333
/**
 * Same as map, but it operates over two parallel vectors.
 *
 * A precondition is used here to ensure that the vectors are the same
 * length.  While we do not often use preconditions in the standard
 * library, a precondition is used here because result::t is generally
 * used in 'careful' code contexts where it is both appropriate and easy
 * to accommodate an error like the vectors being of different lengths.
 */
G
gifnksm 已提交
334
#[inline(always)]
335
pub fn map_vec2<S,T,U:Copy,V:Copy>(ss: &[S], ts: &[T],
336
                op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> {
337

P
Patrick Walton 已提交
338
    assert!(vec::same_length(ss, ts));
339
    let n = vec::len(ts);
340
    let mut vs = vec::with_capacity(n);
341 342
    let mut i = 0u;
    while i < n {
B
Brian Anderson 已提交
343
        match op(&ss[i],&ts[i]) {
B
Brian Anderson 已提交
344 345
          Ok(copy v) => vs.push(v),
          Err(copy u) => return Err(u)
346 347 348
        }
        i += 1u;
    }
L
Luqman Aden 已提交
349
    return Ok(vs);
350 351
}

352 353 354 355 356
/**
 * Applies op to the pairwise elements from `ss` and `ts`, aborting on
 * error.  This could be implemented using `map2()` but it is more efficient
 * on its own as no result vector is built.
 */
G
gifnksm 已提交
357
#[inline(always)]
358
pub fn iter_vec2<S,T,U:Copy>(ss: &[S], ts: &[T],
359
                         op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> {
360

P
Patrick Walton 已提交
361
    assert!(vec::same_length(ss, ts));
362 363 364
    let n = vec::len(ts);
    let mut i = 0u;
    while i < n {
B
Brian Anderson 已提交
365
        match op(&ss[i],&ts[i]) {
366
          Ok(()) => (),
B
Brian Anderson 已提交
367
          Err(copy u) => return Err(u)
368 369 370
        }
        i += 1u;
    }
371
    return Ok(());
372 373
}

374
/// Unwraps a result, assuming it is an `ok(T)`
375
#[inline(always)]
376
pub fn unwrap<T, U>(res: Result<T, U>) -> T {
L
Luqman Aden 已提交
377 378
    match res {
      Ok(t) => t,
379
      Err(_) => fail!(~"unwrap called on an err result")
380
    }
381 382
}

383
/// Unwraps a result, assuming it is an `err(U)`
384
#[inline(always)]
385
pub fn unwrap_err<T, U>(res: Result<T, U>) -> U {
L
Luqman Aden 已提交
386 387
    match res {
      Err(u) => u,
388
      Ok(_) => fail!(~"unwrap called on an ok result")
389 390 391
    }
}

392
#[cfg(test)]
393
#[allow(non_implicitly_copyable_typarams)]
394
mod tests {
395
    use result::{Err, Ok, Result, chain, get, get_err};
396 397
    use result;

398
    pub fn op1() -> result::Result<int, ~str> { result::Ok(666) }
399

400
    pub fn op2(i: int) -> result::Result<uint, ~str> {
401
        result::Ok(i as uint + 1u)
402
    }
403

404
    pub fn op3() -> result::Result<int, ~str> { result::Err(~"sadface") }
405 406

    #[test]
407
    pub fn chain_success() {
P
Patrick Walton 已提交
408
        assert!(get(&chain(op1(), op2)) == 667u);
409 410 411
    }

    #[test]
412
    pub fn chain_failure() {
P
Patrick Walton 已提交
413
        assert!(get_err(&chain(op3(), op2)) == ~"sadface");
414
    }
415 416

    #[test]
417
    pub fn test_impl_iter() {
418
        let mut valid = false;
419
        Ok::<~str, ~str>(~"a").iter(|_x| valid = true);
P
Patrick Walton 已提交
420
        assert!(valid);
421

422
        Err::<~str, ~str>(~"b").iter(|_x| valid = false);
P
Patrick Walton 已提交
423
        assert!(valid);
424 425 426
    }

    #[test]
427
    pub fn test_impl_iter_err() {
428
        let mut valid = true;
429
        Ok::<~str, ~str>(~"a").iter_err(|_x| valid = false);
P
Patrick Walton 已提交
430
        assert!(valid);
431 432

        valid = false;
433
        Err::<~str, ~str>(~"b").iter_err(|_x| valid = true);
P
Patrick Walton 已提交
434
        assert!(valid);
435 436 437
    }

    #[test]
438
    pub fn test_impl_map() {
P
Patrick Walton 已提交
439 440
        assert!(Ok::<~str, ~str>(~"a").map(|_x| ~"b") == Ok(~"b"));
        assert!(Err::<~str, ~str>(~"a").map(|_x| ~"b") == Err(~"a"));
441 442 443
    }

    #[test]
444
    pub fn test_impl_map_err() {
P
Patrick Walton 已提交
445 446
        assert!(Ok::<~str, ~str>(~"a").map_err(|_x| ~"b") == Ok(~"a"));
        assert!(Err::<~str, ~str>(~"a").map_err(|_x| ~"b") == Err(~"b"));
447
    }
B
Brian Anderson 已提交
448 449

    #[test]
450
    pub fn test_get_ref_method() {
B
Brian Anderson 已提交
451
        let foo: Result<int, ()> = Ok(100);
P
Patrick Walton 已提交
452
        assert!(*foo.get_ref() == 100);
B
Brian Anderson 已提交
453
    }
454
}