about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/failure.rs50
-rw-r--r--src/libcore/result.rs29
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/prelude.rs3
-rw-r--r--src/libstd/result.rs312
-rw-r--r--src/libstd/rt/unwind.rs18
6 files changed, 66 insertions, 348 deletions
diff --git a/src/libcore/failure.rs b/src/libcore/failure.rs
index 8a28f7b1392..c4a2c9a6099 100644
--- a/src/libcore/failure.rs
+++ b/src/libcore/failure.rs
@@ -9,21 +9,28 @@
 // except according to those terms.
 
 //! Failure support for libcore
+//!
+//! The core library cannot define failure, but it does *declare* failure. This
+//! means that the functions inside of libcore are allowed to fail, but to be
+//! useful an upstream crate must define failure for libcore to use. The current
+//! interface for failure is:
+//!
+//!     fn begin_unwind(fmt: &fmt::Arguments, file: &str, line: uint) -> !;
+//!
+//! This definition allows for failing with any general message, but it does not
+//! allow for failing with a `~Any` value. The reason for this is that libcore
+//! is not allowed to allocate.
+//!
+//! This module contains a few other failure functions, but these are just the
+//! necessary lang items for the compiler. All failure is funneled through this
+//! one function. Currently, the actual symbol is declared in the standard
+//! library, but the location of this may change over time.
 
 #![allow(dead_code, missing_doc)]
 
 #[cfg(not(test))]
 use str::raw::c_str_to_static_slice;
-
-// FIXME: Once std::fmt is in libcore, all of these functions should delegate
-//        to a common failure function with this signature:
-//
-//          extern {
-//              fn rust_unwind(f: &fmt::Arguments, file: &str, line: uint) -> !;
-//          }
-//
-//        Each of these functions can create a temporary fmt::Arguments
-//        structure to pass to this function.
+use fmt;
 
 #[cold] #[inline(never)] // this is the slow path, always
 #[lang="fail_"]
@@ -32,7 +39,11 @@ fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
     unsafe {
         let expr = c_str_to_static_slice(expr as *i8);
         let file = c_str_to_static_slice(file as *i8);
-        begin_unwind(expr, file, line)
+        format_args!(|args| -> () {
+            begin_unwind(args, file, line);
+        }, "{}", expr);
+
+        loop {}
     }
 }
 
@@ -40,16 +51,19 @@ fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
 #[lang="fail_bounds_check"]
 #[cfg(not(test))]
 fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
-    #[allow(ctypes)]
-    extern { fn rust_fail_bounds_check(file: *u8, line: uint,
-                                       index: uint, len: uint,) -> !; }
-    unsafe { rust_fail_bounds_check(file, line, index, len) }
+    let file = unsafe { c_str_to_static_slice(file as *i8) };
+    format_args!(|args| -> () {
+        begin_unwind(args, file, line);
+    }, "index out of bounds: the len is {} but the index is {}", len, index);
+    loop {}
 }
 
 #[cold]
-pub fn begin_unwind(msg: &str, file: &'static str, line: uint) -> ! {
+pub fn begin_unwind(fmt: &fmt::Arguments, file: &'static str, line: uint) -> ! {
+    // FIXME: this should be a proper lang item, it should not just be some
+    //        undefined symbol sitting in the middle of nowhere.
     #[allow(ctypes)]
-    extern { fn rust_begin_unwind(msg: &str, file: &'static str,
+    extern { fn rust_begin_unwind(fmt: &fmt::Arguments, file: &'static str,
                                   line: uint) -> !; }
-    unsafe { rust_begin_unwind(msg, file, line) }
+    unsafe { rust_begin_unwind(fmt, file, line) }
 }
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index cced5028460..81f089ae67d 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -268,6 +268,7 @@
 
 use clone::Clone;
 use cmp::Eq;
+use fmt::Show;
 use iter::{Iterator, FromIterator};
 use option::{None, Option, Some};
 
@@ -515,6 +516,34 @@ impl<T, E> Result<T, E> {
     }
 }
 
+impl<T, E: Show> Result<T, E> {
+    /// Unwraps a result, yielding the content of an `Ok`.
+    ///
+    /// Fails if the value is an `Err`.
+    #[inline]
+    pub fn unwrap(self) -> T {
+        match self {
+            Ok(t) => t,
+            Err(e) =>
+                fail!("called `Result::unwrap()` on an `Err` value: {}", e)
+        }
+    }
+}
+
+impl<T: Show, E> Result<T, E> {
+    /// Unwraps a result, yielding the content of an `Err`.
+    ///
+    /// Fails if the value is an `Ok`.
+    #[inline]
+    pub fn unwrap_err(self) -> E {
+        match self {
+            Ok(t) =>
+                fail!("called `Result::unwrap_err()` on an `Ok` value: {}", t),
+            Err(e) => e
+        }
+    }
+}
+
 /////////////////////////////////////////////////////////////////////////////
 // Free functions
 /////////////////////////////////////////////////////////////////////////////
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 87c4ef1046f..119cd9aa2ca 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -153,6 +153,7 @@ pub use core::mem;
 pub use core::ptr;
 pub use core::raw;
 pub use core::tuple;
+pub use core::result;
 
 // Run tests with libgreen instead of libnative.
 //
@@ -218,7 +219,6 @@ pub mod hash;
 
 /* Common data structures */
 
-pub mod result;
 pub mod option;
 
 /* Tasks and communication */
diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs
index 6cd9e96496f..e39d8d34447 100644
--- a/src/libstd/prelude.rs
+++ b/src/libstd/prelude.rs
@@ -64,13 +64,12 @@ pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIte
 pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize};
 pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul};
 pub use num::{Signed, Unsigned};
-pub use num::{Primitive, Int, Float, ToPrimitive, FromPrimitive};
+pub use num::{Primitive, Int, Float, FloatMath, ToPrimitive, FromPrimitive};
 pub use option::Expect;
 pub use owned::Box;
 pub use path::{GenericPath, Path, PosixPath, WindowsPath};
 pub use ptr::RawPtr;
 pub use io::{Buffer, Writer, Reader, Seek};
-pub use result::{ResultUnwrap, ResultUnwrapErr};
 pub use str::{Str, StrVector, StrSlice, OwnedStr, IntoMaybeOwned};
 pub use str::{StrAllocating};
 pub use to_str::{ToStr, IntoStr};
diff --git a/src/libstd/result.rs b/src/libstd/result.rs
deleted file mode 100644
index ecbc164590b..00000000000
--- a/src/libstd/result.rs
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2012-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.
-
-//! Error handling with the `Result` type
-//!
-//! `Result<T>` is the type used for returning and propagating
-//! errors. It is an enum with the variants, `Ok(T)`, representing
-//! success and containing a value, and `Err(E)`, representing error
-//! and containing an error value.
-//!
-//! ~~~
-//! enum Result<T, E> {
-//!    Ok(T),
-//!    Err(E)
-//! }
-//! ~~~
-//!
-//! Functions return `Result` whenever errors are expected and
-//! recoverable. In the `std` crate `Result` is most prominently used
-//! for [I/O](../io/index.html).
-//!
-//! A simple function returning `Result` might be
-//! defined and used like so:
-//!
-//! ~~~
-//! #[deriving(Show)]
-//! enum Version { Version1, Version2 }
-//!
-//! fn parse_version(header: &[u8]) -> Result<Version, &'static str> {
-//!     if header.len() < 1 {
-//!         return Err("invalid header length");
-//!     }
-//!     match header[0] {
-//!         1 => Ok(Version1),
-//!         2 => Ok(Version2),
-//!         _ => Err("invalid version")
-//!     }
-//! }
-//!
-//! let version = parse_version(&[1, 2, 3, 4]);
-//! match version {
-//!     Ok(v) => {
-//!         println!("working with version: {}", v);
-//!     }
-//!     Err(e) => {
-//!         println!("error parsing header: {}", e);
-//!     }
-//! }
-//! ~~~
-//!
-//! Pattern matching on `Result`s is clear and straightforward for
-//! simple cases, but `Result` comes with some convenience methods
-//! that make working it more succinct.
-//!
-//! ~~~
-//! let good_result: Result<int, int> = Ok(10);
-//! let bad_result: Result<int, int> = Err(10);
-//!
-//! // The `is_ok` and `is_err` methods do what they say.
-//! assert!(good_result.is_ok() && !good_result.is_err());
-//! assert!(bad_result.is_err() && !bad_result.is_ok());
-//!
-//! // `map` consumes the `Result` and produces another.
-//! let good_result: Result<int, int> = good_result.map(|i| i + 1);
-//! let bad_result: Result<int, int> = bad_result.map(|i| i - 1);
-//!
-//! // Use `and_then` to continue the computation.
-//! let good_result: Result<bool, int> = good_result.and_then(|i| Ok(i == 11));
-//!
-//! // Use `or_else` to handle the error.
-//! let bad_result: Result<int, int> = bad_result.or_else(|i| Ok(11));
-//!
-//! // Consume the result and return the contents with `unwrap`.
-//! let final_awesome_result = good_result.ok().unwrap();
-//! ~~~
-//!
-//! # Results must be used
-//!
-//! A common problem with using return values to indicate errors is
-//! that it is easy to ignore the return value, thus failing to handle
-//! the error. Result is annotated with the #[must_use] attribute,
-//! which will cause the compiler to issue a warning when a Result
-//! value is ignored. This makes `Result` especially useful with
-//! functions that may encounter errors but don't otherwise return a
-//! useful value.
-//!
-//! Consider the `write_line` method defined for I/O types
-//! by the [`Writer`](../io/trait.Writer.html) trait:
-//!
-//! ~~~
-//! use std::io::IoError;
-//!
-//! trait Writer {
-//!     fn write_line(&mut self, s: &str) -> Result<(), IoError>;
-//! }
-//! ~~~
-//!
-//! *Note: The actual definition of `Writer` uses `IoResult`, which
-//! is just a synonym for `Result<T, IoError>`.*
-//!
-//! This method doesn`t produce a value, but the write may
-//! fail. It's crucial to handle the error case, and *not* write
-//! something like this:
-//!
-//! ~~~ignore
-//! use std::io::{File, Open, Write};
-//!
-//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
-//! // If `write_line` errors, then we'll never know, because the return
-//! // value is ignored.
-//! file.write_line("important message");
-//! drop(file);
-//! ~~~
-//!
-//! If you *do* write that in Rust, the compiler will by give you a
-//! warning (by default, controlled by the `unused_must_use` lint).
-//!
-//! You might instead, if you don't want to handle the error, simply
-//! fail, by converting to an `Option` with `ok`, then asserting
-//! success with `expect`. This will fail if the write fails, proving
-//! a marginally useful message indicating why:
-//!
-//! ~~~no_run
-//! use std::io::{File, Open, Write};
-//!
-//! let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
-//! file.write_line("important message").ok().expect("failed to write message");
-//! drop(file);
-//! ~~~
-//!
-//! You might also simply assert success:
-//!
-//! ~~~no_run
-//! # use std::io::{File, Open, Write};
-//!
-//! # let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
-//! assert!(file.write_line("important message").is_ok());
-//! # drop(file);
-//! ~~~
-//!
-//! Or propagate the error up the call stack with `try!`:
-//!
-//! ~~~
-//! # use std::io::{File, Open, Write, IoError};
-//! fn write_message() -> Result<(), IoError> {
-//!     let mut file = File::open_mode(&Path::new("valuable_data.txt"), Open, Write);
-//!     try!(file.write_line("important message"));
-//!     drop(file);
-//!     return Ok(());
-//! }
-//! ~~~
-//!
-//! # The `try!` macro
-//!
-//! When writing code that calls many functions that return the
-//! `Result` type, the error handling can be tedious.  The `try!`
-//! macro hides some of the boilerplate of propagating errors up the
-//! call stack.
-//!
-//! It replaces this:
-//!
-//! ~~~
-//! use std::io::{File, Open, Write, IoError};
-//!
-//! struct Info { name: ~str, age: int, rating: int }
-//!
-//! fn write_info(info: &Info) -> Result<(), IoError> {
-//!     let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write);
-//!     // Early return on error
-//!     match file.write_line(format!("name: {}", info.name)) {
-//!         Ok(_) => (),
-//!         Err(e) => return Err(e)
-//!     }
-//!     match file.write_line(format!("age: {}", info.age)) {
-//!         Ok(_) => (),
-//!         Err(e) => return Err(e)
-//!     }
-//!     return file.write_line(format!("rating: {}", info.rating));
-//! }
-//! ~~~
-//!
-//! With this:
-//!
-//! ~~~
-//! use std::io::{File, Open, Write, IoError};
-//!
-//! struct Info { name: ~str, age: int, rating: int }
-//!
-//! fn write_info(info: &Info) -> Result<(), IoError> {
-//!     let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write);
-//!     // Early return on error
-//!     try!(file.write_line(format!("name: {}", info.name)));
-//!     try!(file.write_line(format!("age: {}", info.age)));
-//!     try!(file.write_line(format!("rating: {}", info.rating)));
-//!     return Ok(());
-//! }
-//! ~~~
-//!
-//! *It's much nicer!*
-//!
-//! Wrapping an expression in `try!` will result in the unwrapped
-//! success (`Ok`) value, unless the result is `Err`, in which case
-//! `Err` is returned early from the enclosing function. Its simple definition
-//! makes it clear:
-//!
-//! ~~~
-//! # #![feature(macro_rules)]
-//! macro_rules! try(
-//!     ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
-//! )
-//! # fn main() { }
-//! ~~~
-//!
-//! `try!` is imported by the prelude, and is available everywhere.
-//!
-//! # `Result` and `Option`
-//!
-//! The `Result` and [`Option`](../option/index.html) types are
-//! similar and complementary: they are often employed to indicate a
-//! lack of a return value; and they are trivially converted between
-//! each other, so `Result`s are often handled by first converting to
-//! `Option` with the [`ok`](../../core/result/enum.Result.html#method.ok) and
-//! [`err`](../../core/result/enum.Result.html#method.ok) methods.
-//!
-//! Whereas `Option` only indicates the lack of a value, `Result` is
-//! specifically for error reporting, and carries with it an error
-//! value.  Sometimes `Option` is used for indicating errors, but this
-//! is only for simple cases and is generally discouraged. Even when
-//! there is no useful error value to return, prefer `Result<T, ()>`.
-//!
-//! Converting to an `Option` with `ok()` to handle an error:
-//!
-//! ~~~
-//! use std::io::Timer;
-//! let mut t = Timer::new().ok().expect("failed to create timer!");
-//! ~~~
-//!
-//! # `Result` vs. `fail!`
-//!
-//! `Result` is for recoverable errors; `fail!` is for unrecoverable
-//! errors. Callers should always be able to avoid failure if they
-//! take the proper precautions, for example, calling `is_some()`
-//! on an `Option` type before calling `unwrap`.
-//!
-//! The suitability of `fail!` as an error handling mechanism is
-//! limited by Rust's lack of any way to "catch" and resume execution
-//! from a thrown exception. Therefore using failure for error
-//! handling requires encapsulating fallable code in a task. Calling
-//! the `fail!` macro, or invoking `fail!` indirectly should be
-//! avoided as an error reporting strategy. Failure is only for
-//! unrecoverable errors and a failing task is typically the sign of
-//! a bug.
-//!
-//! A module that instead returns `Results` is alerting the caller
-//! that failure is possible, and providing precise control over how
-//! it is handled.
-//!
-//! Furthermore, failure may not be recoverable at all, depending on
-//! the context. The caller of `fail!` should assume that execution
-//! will not resume after failure, that failure is catastrophic.
-
-use fmt::Show;
-
-pub use core::result::{Result, Ok, Err, collect, fold, fold_};
-
-// FIXME: These traits should not exist. Once std::fmt is moved to libcore,
-//        these can once again become inherent methods on Result.
-
-/// Temporary trait for unwrapping a result
-pub trait ResultUnwrap<T, E> {
-    /// Unwraps a result, yielding the content of an `Ok`.
-    ///
-    /// Fails if the value is an `Err`.
-    fn unwrap(self) -> T;
-}
-
-/// Temporary trait for unwrapping the error of a result
-pub trait ResultUnwrapErr<T, E> {
-    /// Unwraps a result, yielding the content of an `Err`.
-    ///
-    /// Fails if the value is an `Ok`.
-    fn unwrap_err(self) -> E;
-}
-
-impl<T, E: Show> ResultUnwrap<T, E> for Result<T, E> {
-    #[inline]
-    fn unwrap(self) -> T {
-        match self {
-            Ok(t) => t,
-            Err(e) =>
-                fail!("called `Result::unwrap()` on an `Err` value: {}", e)
-        }
-    }
-}
-
-impl<T: Show, E> ResultUnwrapErr<T, E> for Result<T, E> {
-    #[inline]
-    fn unwrap_err(self) -> E {
-        match self {
-            Ok(t) =>
-                fail!("called `Result::unwrap_err()` on an `Ok` value: {}", t),
-            Err(e) => e
-        }
-    }
-}
diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs
index e10e0716f67..c53346f69ee 100644
--- a/src/libstd/rt/unwind.rs
+++ b/src/libstd/rt/unwind.rs
@@ -295,24 +295,12 @@ pub mod eabi {
     }
 }
 
-#[cold]
-#[no_mangle]
-#[cfg(not(test))]
-pub extern fn rust_fail_bounds_check(file: *u8, line: uint,
-                                     index: uint, len: uint) -> ! {
-    use str::raw::c_str_to_static_slice;
-
-    let msg = format!("index out of bounds: the len is {} but the index is {}",
-                      len as uint, index as uint);
-    begin_unwind(msg, unsafe { c_str_to_static_slice(file as *i8) }, line)
-}
-
 // Entry point of failure from the libcore crate
 #[no_mangle]
 #[cfg(not(test))]
-pub extern fn rust_begin_unwind(msg: &str, file: &'static str, line: uint) -> ! {
-    use str::StrAllocating;
-    begin_unwind(msg.to_owned(), file, line)
+pub extern fn rust_begin_unwind(msg: &fmt::Arguments,
+                                file: &'static str, line: uint) -> ! {
+    begin_unwind_fmt(msg, file, line)
 }
 
 /// The entry point for unwinding with a formatted message.