From 1b27acc0bfca7327bdb54c334746cd8154ae8a15 Mon Sep 17 00:00:00 2001 From: Jakub Bukaj Date: Tue, 18 Nov 2014 17:59:43 +0100 Subject: [PATCH] Make `Result::{and, and_then}` generic over error types implementing FromError This change may result in additional type annotations being required when using those two methods, in particular when the error type of the Result argument is not known. [breaking-change] --- src/libcore/error.rs | 35 +++++++++++++++++++++++++++++++++++ src/libcore/lib.rs | 3 ++- src/libcore/result.rs | 9 +++++---- src/libcoretest/result.rs | 23 ++++++++++++++++++++--- src/libstd/error.rs | 14 +------------- 5 files changed, 63 insertions(+), 21 deletions(-) create mode 100644 src/libcore/error.rs diff --git a/src/libcore/error.rs b/src/libcore/error.rs new file mode 100644 index 0000000000000..f0eb9b8424a22 --- /dev/null +++ b/src/libcore/error.rs @@ -0,0 +1,35 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A trait for converting between different types of errors. +//! +//! # The `FromError` trait +//! +//! `FromError` is a simple trait that expresses conversions between different +//! error types. To provide maximum flexibility, it does not require either of +//! the types to actually implement the `Error` trait from the `std` crate, +//! although this will be the common case. +//! +//! The main use of this trait is in the `try!` macro from the `std` crate, +//! which uses it to automatically convert a given error to the error specified +//! in a function's return type. + +/// A trait for types that can be converted from a given error type `E`. +pub trait FromError { + /// Perform the conversion. + fn from_error(err: E) -> Self; +} + +// Any type is convertable from itself +impl FromError for E { + fn from_error(err: E) -> E { + err + } +} diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5e3c74477d15c..a8ad0c29c05f6 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -58,7 +58,7 @@ #![no_std] #![allow(unknown_features)] -#![feature(globs, intrinsics, lang_items, macro_rules, phase)] +#![feature(default_type_params, globs, intrinsics, lang_items, macro_rules, phase)] #![feature(simd, unsafe_destructor, slicing_syntax)] #![deny(missing_docs)] @@ -102,6 +102,7 @@ pub mod ops; pub mod cmp; pub mod clone; pub mod default; +pub mod error; /* Core types and methods on primitives */ diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 0dc4fb839659d..a8d593dcda88a 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -278,6 +278,7 @@ pub use self::Result::*; +use error::FromError; use std::fmt::Show; use slice; use slice::AsSlice; @@ -633,10 +634,10 @@ impl Result { /// ``` #[inline] #[stable] - pub fn and(self, res: Result) -> Result { + pub fn and = E>(self, res: Result) -> Result { match self { Ok(_) => res, - Err(e) => Err(e), + Err(e) => Err(FromError::from_error(e)), } } @@ -657,10 +658,10 @@ impl Result { /// ``` #[inline] #[unstable = "waiting for unboxed closures"] - pub fn and_then(self, op: |T| -> Result) -> Result { + pub fn and_then = E>(self, op: |T| -> Result) -> Result { match self { Ok(t) => op(t), - Err(e) => Err(e), + Err(e) => Err(FromError::from_error(e)), } } diff --git a/src/libcoretest/result.rs b/src/libcoretest/result.rs index 92124e2f299cd..024e360d68b8b 100644 --- a/src/libcoretest/result.rs +++ b/src/libcoretest/result.rs @@ -8,24 +8,36 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::error::FromError; use core::iter::range; +#[deriving(PartialEq, Show)] +struct Error(&'static str); +impl FromError<&'static str> for Error { + fn from_error(msg: &'static str) -> Error { + Error(msg) + } +} + pub fn op1() -> Result { Ok(666) } pub fn op2() -> Result { Err("sadface") } +pub fn op3(n: int) -> Result { Ok(n * 2) } +pub fn op4(_: int) -> Result { Err(Error("oh well :(")) } #[test] pub fn test_and() { - assert_eq!(op1().and(Ok(667i)).unwrap(), 667); + assert_eq!(op1().and(Ok::(667i)).unwrap(), 667); assert_eq!(op1().and(Err::<(), &'static str>("bad")).unwrap_err(), "bad"); - assert_eq!(op2().and(Ok(667i)).unwrap_err(), "sadface"); - assert_eq!(op2().and(Err::<(),&'static str>("bad")).unwrap_err(), + assert_eq!(op2().and(Ok::(667i)).unwrap_err(), "sadface"); + assert_eq!(op2().and(Err::<(), &'static str>("bad")).unwrap_err(), "sadface"); } #[test] pub fn test_and_then() { + assert_eq!(op1().and_then(|i| Ok::(i + 1)).unwrap(), 667); assert_eq!(op1().and_then(|_| Err::("bad")).unwrap_err(), "bad"); @@ -34,6 +46,11 @@ pub fn test_and_then() { "sadface"); assert_eq!(op2().and_then(|_| Err::("bad")).unwrap_err(), "sadface"); + + assert_eq!(op1().and_then(op3).unwrap(), 666 * 2); + assert_eq!(op2().and_then(op3).unwrap_err(), Error("sadface")); + assert_eq!(op1().and_then(op4).unwrap_err(), Error("oh well :(")); + assert_eq!(op2().and_then(op4).unwrap_err(), Error("sadface")); } #[test] diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 82ad893f88a1a..5a56e6a09f2dc 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -78,6 +78,7 @@ //! } //! ``` +pub use core::error::FromError; use option::{Option, None}; use kinds::Send; use string::String; @@ -93,16 +94,3 @@ pub trait Error: Send { /// The lower-level cause of this error, if any. fn cause(&self) -> Option<&Error> { None } } - -/// A trait for types that can be converted from a given error type `E`. -pub trait FromError { - /// Perform the conversion. - fn from_error(err: E) -> Self; -} - -// Any type is convertable from itself -impl FromError for E { - fn from_error(err: E) -> E { - err - } -}