Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement error interoperation (RFC 70) #17753

Merged
merged 3 commits into from
Nov 3, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/libcore/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ pub use ops::{Shl, Shr};
pub use ops::{Index, IndexMut};
pub use ops::{Slice, SliceMut};
pub use ops::{Fn, FnMut, FnOnce};
pub use option::{Option, Some, None};
pub use result::{Result, Ok, Err};

// Reexported functions
pub use iter::range;
Expand All @@ -56,7 +54,9 @@ pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
pub use num::{Signed, Unsigned, Float};
pub use num::{Primitive, Int, ToPrimitive, FromPrimitive};
pub use option::{Option, Some, None};
pub use ptr::RawPtr;
pub use result::{Result, Ok, Err};
pub use str::{Str, StrSlice};
pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4};
pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8};
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ fn write_out_deps(sess: &Session,
_ => return,
};

let result = (|| {
let result = (|| -> io::IoResult<()> {
// Build a list of files used to compile the output and
// write Makefile-compatible dependency rules
let files: Vec<String> = sess.codemap().files.borrow()
Expand Down
14 changes: 14 additions & 0 deletions src/libserialize/base64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//! Base64 binary-to-text encoding
use std::fmt;
use std::string;
use std::error;

/// Available encoding character sets
pub enum CharacterSet {
Expand Down Expand Up @@ -178,6 +179,19 @@ impl fmt::Show for FromBase64Error {
}
}

impl error::Error for FromBase64Error {
fn description(&self) -> &str {
match *self {
InvalidBase64Byte(_, _) => "invalid character",
InvalidBase64Length => "invalid length",
}
}

fn detail(&self) -> Option<String> {
Some(self.to_string())
}
}

impl<'a> FromBase64 for &'a str {
/**
* Convert any base64 encoded string (literal, `@`, `&`, or `~`)
Expand Down
15 changes: 15 additions & 0 deletions src/libserialize/hex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//! Hex binary-to-text encoding
use std::fmt;
use std::string;
use std::error;

/// A trait for converting a value to hexadecimal encoding
pub trait ToHex {
Expand Down Expand Up @@ -77,6 +78,20 @@ impl fmt::Show for FromHexError {
}
}

impl error::Error for FromHexError {
fn description(&self) -> &str {
match *self {
InvalidHexCharacter(_, _) => "invalid character",
InvalidHexLength => "invalid length",
}
}

fn detail(&self) -> Option<String> {
Some(self.to_string())
}
}


impl<'a> FromHex for &'a str {
/**
* Convert any hexadecimal encoded string (literal, `@`, `&`, or `~`)
Expand Down
5 changes: 5 additions & 0 deletions src/libserialize/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,11 @@ fn io_error_to_error(io: io::IoError) -> ParserError {
IoError(io.kind, io.desc)
}

impl std::error::Error for DecoderError {
fn description(&self) -> &str { "decoder error" }
fn detail(&self) -> Option<std::string::String> { Some(self.to_string()) }
}

pub type EncodeResult = io::IoResult<()>;
pub type DecodeResult<T> = Result<T, DecoderError>;

Expand Down
111 changes: 111 additions & 0 deletions src/libstd/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// 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 <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.

//! Traits for working with Errors.
//!
//! # The `Error` trait
//!
//! `Error` is a trait representing the basic expectations for error values,
//! i.e. values of type `E` in `Result<T, E>`. At a minimum, errors must provide
//! a description, but they may optionally provide additional detail and cause
//! chain information:
//!
//! ```
//! trait Error: Send {
//! fn description(&self) -> &str;
//!
//! fn detail(&self) -> Option<String> { None }
//! fn cause(&self) -> Option<&Error> { None }
//! }
//! ```
//!
//! The `cause` method is generally used when errors cross "abstraction
//! boundaries", i.e. when a one module must report an error that is "caused"
//! by an error from a lower-level module. This setup makes it possible for the
//! high-level module to provide its own errors that do not commit to any
//! particular implementation, but also reveal some of its implementation for
//! debugging via `cause` chains.
//!
//! The trait inherits from `Any` to allow *downcasting*: converting from a
//! trait object to a specific concrete type when applicable.
//!
//! # 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, although this will be the
//! common case.
//!
//! The main use of this trait is in the `try!` macro, which uses it to
//! automatically convert a given error to the error specified in a function's
//! return type.
//!
//! For example,
//!
//! ```
//! use std::error::FromError;
//! use std::io::{File, IoError};
//! use std::os::{MemoryMap, MapError};
//! use std::path::Path;
//!
//! enum MyError {
//! Io(IoError),
//! Map(MapError)
//! }
//!
//! impl FromError<IoError> for MyError {
//! fn from_error(err: IoError) -> MyError {
//! Io(err)
//! }
//! }
//!
//! impl FromError<MapError> for MyError {
//! fn from_error(err: MapError) -> MyError {
//! Map(err)
//! }
//! }
//!
//! #[allow(unused_variables)]
//! fn open_and_map() -> Result<(), MyError> {
//! let f = try!(File::open(&Path::new("foo.txt")));
//! let m = try!(MemoryMap::new(0, &[]));
//! // do something interesting here...
//! Ok(())
//! }
//! ```

use option::{Option, None};
use kinds::Send;
use string::String;

/// Base functionality for all errors in Rust.
pub trait Error: Send {
/// A short description of the error; usually a static string.
fn description(&self) -> &str;

/// A detailed description of the error, usually including dynamic information.
fn detail(&self) -> Option<String> { None }

/// 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<E> {
/// Perform the conversion.
fn from_error(err: E) -> Self;
}

// Any type is convertable from itself
impl<E> FromError<E> for E {
fn from_error(err: E) -> E {
err
}
}
18 changes: 18 additions & 0 deletions src/libstd/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ responding to errors that may occur while attempting to read the numbers.
#![deny(unused_must_use)]

use char::Char;
use clone::Clone;
use default::Default;
use error::{FromError, Error};
use fmt;
use int;
use iter::Iterator;
Expand Down Expand Up @@ -433,6 +435,22 @@ impl fmt::Show for IoError {
}
}

impl Error for IoError {
fn description(&self) -> &str {
self.desc
}

fn detail(&self) -> Option<String> {
self.detail.clone()
}
}

impl FromError<IoError> for Box<Error> {
fn from_error(err: IoError) -> Box<Error> {
box err
}
}

/// A list specifying general categories of I/O error.
#[deriving(PartialEq, Eq, Clone, Show)]
pub enum IoErrorKind {
Expand Down
2 changes: 2 additions & 0 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ pub mod time;

/* Common traits */

pub mod error;
pub mod from_str;
pub mod num;
pub mod to_string;
Expand Down Expand Up @@ -257,6 +258,7 @@ mod std {
pub use hash;

pub use comm; // used for select!()
pub use error; // used for try!()
pub use fmt; // used for any formatting strings
pub use io; // used for println!()
pub use local_data; // used for local_data_key!()
Expand Down
9 changes: 7 additions & 2 deletions src/libstd/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,13 @@ macro_rules! local_data_key(
/// error if the value of the expression is `Err`. For more information, see
/// `std::io`.
#[macro_export]
macro_rules! try(
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
macro_rules! try (
($expr:expr) => ({
match $expr {
Ok(val) => val,
Err(err) => return Err(::std::error::FromError::from_error(err))
}
})
)

/// Create a `std::vec::Vec` containing the arguments.
Expand Down
14 changes: 14 additions & 0 deletions src/libstd/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@
#![allow(non_snake_case)]

use clone::Clone;
use error::{FromError, Error};
use fmt;
use io::{IoResult, IoError};
use iter::Iterator;
use libc::{c_void, c_int};
use libc;
use boxed::Box;
use ops::Drop;
use option::{Some, None, Option};
use os;
Expand All @@ -48,6 +50,7 @@ use slice::{AsSlice, ImmutableSlice, MutableSlice, ImmutablePartialEqSlice};
use slice::CloneableVector;
use str::{Str, StrSlice, StrAllocating};
use string::String;
use to_string::ToString;
use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
use vec::Vec;

Expand Down Expand Up @@ -1437,6 +1440,17 @@ impl fmt::Show for MapError {
}
}

impl Error for MapError {
fn description(&self) -> &str { "memory map error" }
fn detail(&self) -> Option<String> { Some(self.to_string()) }
}

impl FromError<MapError> for Box<Error> {
fn from_error(err: MapError) -> Box<Error> {
box err
}
}

#[cfg(unix)]
impl MemoryMap {
/// Create a new mapping with the given `options`, at least `min_len` bytes
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@
#[doc(no_inline)] pub use ops::{Index, IndexMut};
#[doc(no_inline)] pub use ops::{Slice, SliceMut};
#[doc(no_inline)] pub use ops::{Fn, FnMut, FnOnce};
#[doc(no_inline)] pub use option::{Option, Some, None};
#[doc(no_inline)] pub use result::{Result, Ok, Err};

// Reexported functions
#[doc(no_inline)] pub use from_str::from_str;
Expand All @@ -73,8 +71,10 @@
#[doc(no_inline)] pub use num::{Signed, Unsigned, Primitive, Int, Float};
#[doc(no_inline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive};
#[doc(no_inline)] pub use boxed::Box;
#[doc(no_inline)] pub use option::{Option, Some, None};
#[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath};
#[doc(no_inline)] pub use ptr::{RawPtr, RawMutPtr};
#[doc(no_inline)] pub use result::{Result, Ok, Err};
#[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek};
#[doc(no_inline)] pub use str::{Str, StrVector, StrSlice};
#[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrSlice};
Expand Down