diff options
| author | bors <bors@rust-lang.org> | 2013-09-14 00:01:04 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-09-14 00:01:04 -0700 |
| commit | 2aa578efd9834e37ad52879ff10ee2c2aa938389 (patch) | |
| tree | aa459cb42c65433dfbddca28040db544aea89f59 /src/libstd | |
| parent | 4ac10f8f6e8e07c70fadb676170c5402442e2243 (diff) | |
| parent | 93683ae6da3a47f1cd0644a093cb4b1b0bee7faa (diff) | |
| download | rust-2aa578efd9834e37ad52879ff10ee2c2aa938389.tar.gz rust-2aa578efd9834e37ad52879ff10ee2c2aa938389.zip | |
auto merge of #9115 : erickt/rust/master, r=erickt
This is a series of patches to modernize option and result. The highlights are: * rename `.unwrap_or_default(value)` and etc to `.unwrap_or(value)` * add `.unwrap_or_default()` that uses the `Default` trait * add `Default` implementations for vecs, HashMap, Option * add `Option.and(T) -> Option<T>`, `Option.and_then(&fn() -> Option<T>) -> Option<T>`, `Option.or(T) -> Option<T>`, and `Option.or_else(&fn() -> Option<T>) -> Option<T>` * add `option::ToOption`, `option::IntoOption`, `option::AsOption`, `result::ToResult`, `result::IntoResult`, `result::AsResult`, `either::ToEither`, and `either::IntoEither`, `either::AsEither` * renamed `Option::chain*` and `Result::chain*` to `and_then` and `or_else` to avoid the eventual collision with `Iterator.chain`. * Added a bunch of impls of `Default` * Added a `#[deriving(Default)]` syntax extension * Removed impls of `Zero` for `Option<T>` and vecs.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/at_vec.rs | 2 | ||||
| -rw-r--r-- | src/libstd/bool.rs | 7 | ||||
| -rw-r--r-- | src/libstd/char.rs | 10 | ||||
| -rw-r--r-- | src/libstd/default.rs | 12 | ||||
| -rw-r--r-- | src/libstd/either.rs | 196 | ||||
| -rw-r--r-- | src/libstd/hashmap.rs | 9 | ||||
| -rw-r--r-- | src/libstd/io.rs | 6 | ||||
| -rw-r--r-- | src/libstd/iter.rs | 9 | ||||
| -rw-r--r-- | src/libstd/num/f32.rs | 6 | ||||
| -rw-r--r-- | src/libstd/num/f64.rs | 6 | ||||
| -rw-r--r-- | src/libstd/num/float.rs | 6 | ||||
| -rw-r--r-- | src/libstd/num/int_macros.rs | 6 | ||||
| -rw-r--r-- | src/libstd/num/uint_macros.rs | 6 | ||||
| -rw-r--r-- | src/libstd/option.rs | 321 | ||||
| -rw-r--r-- | src/libstd/os.rs | 6 | ||||
| -rw-r--r-- | src/libstd/result.rs | 272 | ||||
| -rw-r--r-- | src/libstd/rt/io/net/ip.rs | 2 | ||||
| -rw-r--r-- | src/libstd/to_bytes.rs | 2 | ||||
| -rw-r--r-- | src/libstd/tuple.rs | 9 | ||||
| -rw-r--r-- | src/libstd/unit.rs | 11 | ||||
| -rw-r--r-- | src/libstd/vec.rs | 27 |
21 files changed, 833 insertions, 98 deletions
diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index a4e841f98f8..ce8e90e1a43 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -45,7 +45,7 @@ pub fn capacity<T>(v: @[T]) -> uint { #[inline] pub fn build<A>(size: Option<uint>, builder: &fn(push: &fn(v: A))) -> @[A] { let mut vec = @[]; - unsafe { raw::reserve(&mut vec, size.unwrap_or_default(4)); } + unsafe { raw::reserve(&mut vec, size.unwrap_or(4)); } builder(|x| unsafe { raw::push(&mut vec, x) }); vec } diff --git a/src/libstd/bool.rs b/src/libstd/bool.rs index 926e6e1f6b6..4ef50094139 100644 --- a/src/libstd/bool.rs +++ b/src/libstd/bool.rs @@ -24,6 +24,7 @@ Implementations of the following traits: * `Ord` * `TotalOrd` * `Eq` +* `Default` * `Zero` ## Various functions to compare `bool`s @@ -43,6 +44,7 @@ use to_str::ToStr; #[cfg(not(test))] use cmp::{Eq, Ord, TotalOrd, Ordering}; #[cfg(not(test))] use ops::Not; +#[cfg(not(test))] use default::Default; #[cfg(not(test))] use num::Zero; /** @@ -324,6 +326,11 @@ impl Eq for bool { } #[cfg(not(test))] +impl Default for bool { + fn default() -> bool { false } +} + +#[cfg(not(test))] impl Zero for bool { fn zero() -> bool { false } fn is_zero(&self) -> bool { *self == false } diff --git a/src/libstd/char.rs b/src/libstd/char.rs index 7f043b2ecaa..3a01e5908d9 100644 --- a/src/libstd/char.rs +++ b/src/libstd/char.rs @@ -21,6 +21,7 @@ use str; #[cfg(test)] use str::OwnedStr; #[cfg(not(test))] use cmp::{Eq, Ord}; +#[cfg(not(test))] use default::Default; #[cfg(not(test))] use num::Zero; // UTF-8 ranges and tags for encoding characters @@ -435,8 +436,17 @@ impl Ord for char { } #[cfg(not(test))] +impl Default for char { + #[inline] + fn default() -> char { '\x00' } +} + +#[cfg(not(test))] impl Zero for char { + #[inline] fn zero() -> char { '\x00' } + + #[inline] fn is_zero(&self) -> bool { *self == '\x00' } } diff --git a/src/libstd/default.rs b/src/libstd/default.rs index fbc60ffd01b..120cf3fa801 100644 --- a/src/libstd/default.rs +++ b/src/libstd/default.rs @@ -15,3 +15,15 @@ pub trait Default { /// Return the "default value" for a type. fn default() -> Self; } + +impl<T: Default + 'static> Default for @mut T { + fn default() -> @mut T { @mut Default::default() } +} + +impl<T: Default + 'static> Default for @T { + fn default() -> @T { @Default::default() } +} + +impl<T: Default> Default for ~T { + fn default() -> ~T { ~Default::default() } +} diff --git a/src/libstd/either.rs b/src/libstd/either.rs index ec9e6d1ca4b..27381f64ad4 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -13,6 +13,7 @@ #[allow(missing_doc)]; use option::{Some, None}; +use option; use clone::Clone; use container::Container; use cmp::Eq; @@ -53,18 +54,6 @@ impl<L, R> Either<L, R> { } } - /// Converts a `Either` to a `Result` - /// - /// Converts an `Either` type to a `Result` type, making the "right" choice - /// an `Ok` result, and the "left" choice a `Err` - #[inline] - pub fn to_result(self) -> Result<R, L> { - match self { - Right(r) => result::Ok(r), - Left(l) => result::Err(l) - } - } - /// Checks whether the given value is a `Left` #[inline] pub fn is_left(&self) -> bool { @@ -116,6 +105,101 @@ impl<L, R> Either<L, R> { } } +/// A generic trait for converting a value to a `Either` +pub trait ToEither<L, R> { + /// Convert to the `either` type + fn to_either(&self) -> Either<L, R>; +} + +/// A generic trait for converting a value to a `Either` +pub trait IntoEither<L, R> { + /// Convert to the `either` type + fn into_either(self) -> Either<L, R>; +} + +/// A generic trait for converting a value to a `Either` +pub trait AsEither<L, R> { + /// Convert to the `either` type + fn as_either<'a>(&'a self) -> Either<&'a L, &'a R>; +} + +impl<L, R: Clone> option::ToOption<R> for Either<L, R> { + #[inline] + fn to_option(&self)-> option::Option<R> { + match *self { + Left(_) => None, + Right(ref r) => Some(r.clone()), + } + } +} + +impl<L, R> option::IntoOption<R> for Either<L, R> { + #[inline] + fn into_option(self)-> option::Option<R> { + match self { + Left(_) => None, + Right(r) => Some(r), + } + } +} + +impl<L, R> option::AsOption<R> for Either<L, R> { + #[inline] + fn as_option<'a>(&'a self) -> option::Option<&'a R> { + match *self { + Left(_) => None, + Right(ref r) => Some(r), + } + } +} + +impl<L: Clone, R: Clone> result::ToResult<R, L> for Either<L, R> { + #[inline] + fn to_result(&self)-> result::Result<R, L> { + match *self { + Left(ref l) => result::Err(l.clone()), + Right(ref r) => result::Ok(r.clone()), + } + } +} + +impl<L, R> result::IntoResult<R, L> for Either<L, R> { + #[inline] + fn into_result(self)-> result::Result<R, L> { + match self { + Left(l) => result::Err(l), + Right(r) => result::Ok(r), + } + } +} + +impl<L, R> result::AsResult<R, L> for Either<L, R> { + #[inline] + fn as_result<'a>(&'a self) -> result::Result<&'a R, &'a L> { + match *self { + Left(ref l) => result::Err(l), + Right(ref r) => result::Ok(r), + } + } +} + +impl<L: Clone, R: Clone> ToEither<L, R> for Either<L, R> { + fn to_either(&self) -> Either<L, R> { self.clone() } +} + +impl<L, R> IntoEither<L, R> for Either<L, R> { + fn into_either(self) -> Either<L, R> { self } +} + +impl<L, R> AsEither<L, R> for Either<L, R> { + fn as_either<'a>(&'a self) -> Either<&'a L, &'a R> { + match *self { + Left(ref l) => Left(l), + Right(ref r) => Right(r), + } + } +} + /// An iterator yielding the `Left` values of its source pub type Lefts<L, R, Iter> = FilterMap<'static, Either<L, R>, L, Iter>; @@ -167,6 +251,11 @@ pub fn partition<L, R>(eithers: ~[Either<L, R>]) -> (~[L], ~[R]) { mod tests { use super::*; + use option::{IntoOption, ToOption, AsOption}; + use option; + use result::{IntoResult, ToResult, AsResult}; + use result; + #[test] fn test_either_left() { let val = Left(10); @@ -260,4 +349,87 @@ mod tests { assert_eq!(rights.len(), 0u); } + #[test] + pub fn test_to_option() { + let right: Either<int, int> = Right(100); + let left: Either<int, int> = Left(404); + + assert_eq!(right.to_option(), option::Some(100)); + assert_eq!(left.to_option(), option::None); + } + + #[test] + pub fn test_into_option() { + let right: Either<int, int> = Right(100); + let left: Either<int, int> = Left(404); + + assert_eq!(right.into_option(), option::Some(100)); + assert_eq!(left.into_option(), option::None); + } + + #[test] + pub fn test_as_option() { + let right: Either<int, int> = Right(100); + let left: Either<int, int> = Left(404); + + assert_eq!(right.as_option().unwrap(), &100); + assert_eq!(left.as_option(), option::None); + } + + #[test] + pub fn test_to_result() { + let right: Either<int, int> = Right(100); + let left: Either<int, int> = Left(404); + + assert_eq!(right.to_result(), result::Ok(100)); + assert_eq!(left.to_result(), result::Err(404)); + } + + #[test] + pub fn test_into_result() { + let right: Either<int, int> = Right(100); + let left: Either<int, int> = Left(404); + + assert_eq!(right.into_result(), result::Ok(100)); + assert_eq!(left.into_result(), result::Err(404)); + } + + #[test] + pub fn test_as_result() { + let right: Either<int, int> = Right(100); + let left: Either<int, int> = Left(404); + + let x = 100; + assert_eq!(right.as_result(), result::Ok(&x)); + + let x = 404; + assert_eq!(left.as_result(), result::Err(&x)); + } + + #[test] + pub fn test_to_either() { + let right: Either<int, int> = Right(100); + let left: Either<int, int> = Left(404); + + assert_eq!(right.to_either(), Right(100)); + assert_eq!(left.to_either(), Left(404)); + } + + #[test] + pub fn test_into_either() { + let right: Either<int, int> = Right(100); + let left: Either<int, int> = Left(404); + + assert_eq!(right.into_either(), Right(100)); + assert_eq!(left.into_either(), Left(404)); + } + + #[test] + pub fn test_as_either() { + let right: Either<int, int> = Right(100); + let left: Either<int, int> = Left(404); + + assert_eq!(right.as_either().unwrap_right(), &100); + assert_eq!(left.as_either().unwrap_left(), &404); + } } diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 09f0af00417..6c0a6a4ea0a 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -18,6 +18,7 @@ use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; use clone::Clone; use cmp::{Eq, Equiv}; +use default::Default; use hash::Hash; use iter::{Iterator, FromIterator, Extendable}; use iter::{FilterMap, Chain, Repeat, Zip}; @@ -622,6 +623,10 @@ impl<K: Eq + Hash, V> Extendable<(K, V)> for HashMap<K, V> { } } +impl<K: Eq + Hash, V> Default for HashMap<K, V> { + fn default() -> HashMap<K, V> { HashMap::new() } +} + /// An implementation of a hash set using the underlying representation of a /// HashMap where the value is (). As with the `HashMap` type, a `HashSet` /// requires that the elements implement the `Eq` and `Hash` traits. @@ -781,6 +786,10 @@ impl<K: Eq + Hash> Extendable<K> for HashSet<K> { } } +impl<K: Eq + Hash> Default for HashSet<K> { + fn default() -> HashSet<K> { HashSet::new() } +} + // `Repeat` is used to feed the filter closure an explicit capture // of a reference to the other set /// Set operations iterator diff --git a/src/libstd/io.rs b/src/libstd/io.rs index e9b704c2686..2ca36de4f49 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -1618,7 +1618,7 @@ impl<T:Writer> WriterUtil for T { } pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<@Writer, ~str> { - mk_file_writer(path, flags).chain(|w| Ok(w)) + mk_file_writer(path, flags).and_then(|w| Ok(w)) } @@ -1779,7 +1779,7 @@ pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) -> } pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> { - do read_whole_file(file).chain |bytes| { + do read_whole_file(file).and_then |bytes| { if str::is_utf8(bytes) { Ok(str::from_utf8(bytes)) } else { @@ -1791,7 +1791,7 @@ pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> { // FIXME (#2004): implement this in a low-level way. Going through the // abstractions is pointless. pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> { - do file_reader(file).chain |rdr| { + do file_reader(file).and_then |rdr| { Ok(rdr.read_whole_stream()) } } diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs index 5ca827350d0..ec3c02a31f2 100644 --- a/src/libstd/iter.rs +++ b/src/libstd/iter.rs @@ -1474,7 +1474,7 @@ pub struct Scan<'self, A, B, T, St> { impl<'self, A, B, T: Iterator<A>, St> Iterator<B> for Scan<'self, A, B, T, St> { #[inline] fn next(&mut self) -> Option<B> { - self.iter.next().chain(|a| (self.f)(&mut self.state, a)) + self.iter.next().and_then(|a| (self.f)(&mut self.state, a)) } #[inline] @@ -1494,8 +1494,7 @@ pub struct FlatMap<'self, A, T, U> { priv backiter: Option<U>, } -impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for - FlatMap<'self, A, T, U> { +impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for FlatMap<'self, A, T, U> { #[inline] fn next(&mut self) -> Option<B> { loop { @@ -1505,7 +1504,7 @@ impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for } } match self.iter.next().map_move(|x| (self.f)(x)) { - None => return self.backiter.chain_mut_ref(|it| it.next()), + None => return self.backiter.and_then_mut_ref(|it| it.next()), next => self.frontiter = next, } } @@ -1537,7 +1536,7 @@ impl<'self, } } match self.iter.next_back().map_move(|x| (self.f)(x)) { - None => return self.frontiter.chain_mut_ref(|it| it.next_back()), + None => return self.frontiter.and_then_mut_ref(|it| it.next_back()), next => self.backiter = next, } } diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 899d6236aaa..0addcce3eb6 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -12,6 +12,7 @@ #[allow(missing_doc)]; #[allow(non_uppercase_statics)]; +use default::Default; use libc::c_int; use num::{Zero, One, strconv}; use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; @@ -237,6 +238,11 @@ impl Orderable for f32 { } } +impl Default for f32 { + #[inline] + fn default() -> f32 { 0.0 } +} + impl Zero for f32 { #[inline] fn zero() -> f32 { 0.0 } diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 6ab8350a115..b0675278238 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -13,6 +13,7 @@ #[allow(missing_doc)]; #[allow(non_uppercase_statics)]; +use default::Default; use libc::c_int; use num::{Zero, One, strconv}; use num::{FPCategory, FPNaN, FPInfinite , FPZero, FPSubnormal, FPNormal}; @@ -260,6 +261,11 @@ impl Orderable for f64 { } } +impl Default for f64 { + #[inline] + fn default() -> f64 { 0.0 } +} + impl Zero for f64 { #[inline] fn zero() -> f64 { 0.0 } diff --git a/src/libstd/num/float.rs b/src/libstd/num/float.rs index df26fadae16..3952f5478f7 100644 --- a/src/libstd/num/float.rs +++ b/src/libstd/num/float.rs @@ -23,6 +23,7 @@ #[allow(missing_doc)]; #[allow(non_uppercase_statics)]; +use default::Default; use num::{Zero, One, strconv}; use num::FPCategory; use num; @@ -382,6 +383,11 @@ impl Orderable for float { } } +impl Default for float { + #[inline] + fn default() -> float { 0.0 } +} + impl Zero for float { #[inline] fn zero() -> float { 0.0 } diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index 07cafb0a4f1..ae2a56b835d 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -16,6 +16,7 @@ macro_rules! int_module (($T:ty, $bits:expr) => (mod generated { #[allow(non_uppercase_statics)]; +use default::Default; use num::{ToStrRadix, FromStrRadix}; use num::{CheckedDiv, Zero, One, strconv}; use prelude::*; @@ -167,6 +168,11 @@ impl Orderable for $T { } } +impl Default for $T { + #[inline] + fn default() -> $T { 0 } +} + impl Zero for $T { #[inline] fn zero() -> $T { 0 } diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index effeb60fc22..3deb7312b04 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -16,6 +16,7 @@ macro_rules! uint_module (($T:ty, $T_SIGNED:ty, $bits:expr) => (mod generated { #[allow(non_uppercase_statics)]; +use default::Default; use num::BitCount; use num::{ToStrRadix, FromStrRadix}; use num::{CheckedDiv, Zero, One, strconv}; @@ -172,6 +173,11 @@ impl Orderable for $T { } } +impl Default for $T { + #[inline] + fn default() -> $T { 0 } +} + impl Zero for $T { #[inline] fn zero() -> $T { 0 } diff --git a/src/libstd/option.rs b/src/libstd/option.rs index b72046cce72..ce725257dff 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -43,10 +43,13 @@ let unwrapped_msg = match msg { use clone::Clone; use cmp::{Eq,Ord}; +use default::Default; +use either; use util; use num::Zero; use iter; use iter::{Iterator, DoubleEndedIterator, ExactSize}; +use result; use str::{StrSlice, OwnedStr}; use to_str::ToStr; use clone::DeepClone; @@ -126,45 +129,64 @@ impl<T> Option<T> { #[inline] pub fn is_some(&self) -> bool { !self.is_none() } - /// Update an optional value by optionally running its content through a - /// function that returns an option. + /// Returns `None` if the option is `None`, otherwise returns `optb`. #[inline] - pub fn chain<U>(self, f: &fn(t: T) -> Option<U>) -> Option<U> { + pub fn and(self, optb: Option<T>) -> Option<T> { match self { - Some(t) => f(t), - None => None + Some(_) => optb, + None => None, } } - /// Returns the leftmost Some() value, or None if both are None. + /// Returns `None` if the option is `None`, otherwise calls `f` with the + /// wrapped value and returns the result. #[inline] - pub fn or(self, optb: Option<T>) -> Option<T> { + pub fn and_then<U>(self, f: &fn(T) -> Option<U>) -> Option<U> { match self { - Some(opta) => Some(opta), - _ => optb + Some(x) => f(x), + None => None, } } - /// Update an optional value by optionally running its content by reference - /// through a function that returns an option. + /// Returns `None` if the option is `None`, otherwise calls `f` with a + /// reference to the wrapped value and returns the result. #[inline] - pub fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option<U>) -> Option<U> { + pub fn and_then_ref<'a, U>(&'a self, f: &fn(&'a T) -> Option<U>) -> Option<U> { match *self { Some(ref x) => f(x), None => None } } - /// Update an optional value by optionally running its content by mut reference - /// through a function that returns an option. + /// Returns `None` if the option is `None`, otherwise calls `f` with a + /// mutable reference to the wrapped value and returns the result. #[inline] - pub fn chain_mut_ref<'a, U>(&'a mut self, f: &fn(x: &'a mut T) -> Option<U>) -> Option<U> { + pub fn and_then_mut_ref<'a, U>(&'a mut self, f: &fn(&'a mut T) -> Option<U>) -> Option<U> { match *self { Some(ref mut x) => f(x), None => None } } + /// Returns the option if it contains a value, otherwise returns `optb`. + #[inline] + pub fn or(self, optb: Option<T>) -> Option<T> { + match self { + Some(_) => self, + None => optb + } + } + + /// Returns the option if it contains a value, otherwise calls `f` and + /// returns the result. + #[inline] + pub fn or_else(self, f: &fn() -> Option<T>) -> Option<T> { + match self { + Some(_) => self, + None => f(), + } + } + /// Filters an optional value using given function. #[inline(always)] pub fn filtered(self, f: &fn(t: &T) -> bool) -> Option<T> { @@ -332,13 +354,22 @@ impl<T> Option<T> { /// Returns the contained value or a default #[inline] - pub fn unwrap_or_default(self, def: T) -> T { + pub fn unwrap_or(self, def: T) -> T { match self { Some(x) => x, None => def } } + /// Returns the contained value or computes it from a closure + #[inline] + pub fn unwrap_or_else(self, f: &fn() -> T) -> T { + match self { + Some(x) => x, + None => f() + } + } + /// Applies a function zero or more times until the result is `None`. #[inline] pub fn while_some(self, blk: &fn(v: T) -> Option<T>) { @@ -349,6 +380,109 @@ impl<T> Option<T> { } } +/// A generic trait for converting a value to a `Option` +pub trait ToOption<T> { + /// Convert to the `option` type + fn to_option(&self) -> Option<T>; +} + +/// A generic trait for converting a value to a `Option` +pub trait IntoOption<T> { + /// Convert to the `option` type + fn into_option(self) -> Option<T>; +} + +/// A generic trait for converting a value to a `Option` +pub trait AsOption<T> { + /// Convert to the `option` type + fn as_option<'a>(&'a self) -> Option<&'a T>; +} + +impl<T: Clone> ToOption<T> for Option<T> { + #[inline] + fn to_option(&self) -> Option<T> { self.clone() } +} + +impl<T> IntoOption<T> for Option<T> { + #[inline] + fn into_option(self) -> Option<T> { self } +} + +impl<T> AsOption<T> for Option<T> { + #[inline] + fn as_option<'a>(&'a self) -> Option<&'a T> { + match *self { + Some(ref x) => Some(x), + None => None, + } + } +} + +impl<T: Clone> result::ToResult<T, ()> for Option<T> { + #[inline] + fn to_result(&self) -> result::Result<T, ()> { + match *self { + Some(ref x) => result::Ok(x.clone()), + None => result::Err(()), + } + } +} + +impl<T> result::IntoResult<T, ()> for Option<T> { + #[inline] + fn into_result(self) -> result::Result<T, ()> { + match self { + Some(x) => result::Ok(x), + None => result::Err(()), + } + } +} + +impl<T: Clone> either::ToEither<(), T> for Option<T> { + #[inline] + fn to_either(&self) -> either::Either<(), T> { + match *self { + Some(ref x) => either::Right(x.clone()), + None => either::Left(()), + } + } +} + +impl<T> either::IntoEither<(), T> for Option<T> { + #[inline] + fn into_either(self) -> either::Either<(), T> { + match self { + Some(x) => either::Right(x), + None => either::Left(()), + } + } +} + +impl<T: Default> Option<T> { + /// Returns the contained value or default (for this type) + #[inline] + pub fn unwrap_or_default(self) -> T { + match self { + Some(x) => x, + None => Default::default() + } + } + + /// Returns self or `Some`-wrapped default value + #[inline] + pub fn or_default(self) -> Option<T> { + match self { + None => Some(Default::default()), + x => x, + } + } +} + +impl<T> Default for Option<T> { + #[inline] + fn default() -> Option<T> { None } +} + impl<T:Zero> Option<T> { /// Returns the contained value or zero (for this type) #[inline] @@ -369,11 +503,6 @@ impl<T:Zero> Option<T> { } } -impl<T> Zero for Option<T> { - fn zero() -> Option<T> { None } - fn is_zero(&self) -> bool { self.is_none() } -} - /// An iterator that yields either one or zero elements #[deriving(Clone, DeepClone)] pub struct OptionIterator<A> { @@ -407,6 +536,11 @@ impl<A> ExactSize<A> for OptionIterator<A> {} #[cfg(test)] mod tests { use super::*; + + use either::{IntoEither, ToEither}; + use either; + use result::{IntoResult, ToResult}; + use result; use util; #[test] @@ -476,6 +610,50 @@ mod tests { } #[test] + fn test_and() { + let x: Option<int> = Some(1); + assert_eq!(x.and(Some(2)), Some(2)); + assert_eq!(x.and(None), None); + + let x: Option<int> = None; + assert_eq!(x.and(Some(2)), None); + assert_eq!(x.and(None), None); + } + + #[test] + fn test_and_then() { + let x: Option<int> = Some(1); + assert_eq!(x.and_then(|x| Some(x + 1)), Some(2)); + assert_eq!(x.and_then(|_| None::<int>), None); + + let x: Option<int> = None; + assert_eq!(x.and_then(|x| Some(x + 1)), None); + assert_eq!(x.and_then(|_| None::<int>), None); + } + + #[test] + fn test_or() { + let x: Option<int> = Some(1); + assert_eq!(x.or(Some(2)), Some(1)); + assert_eq!(x.or(None), Some(1)); + + let x: Option<int> = None; + assert_eq!(x.or(Some(2)), Some(2)); + assert_eq!(x.or(None), None); + } + + #[test] + fn test_or_else() { + let x: Option<int> = Some(1); + assert_eq!(x.or_else(|| Some(2)), Some(1)); + assert_eq!(x.or_else(|| None), Some(1)); + + let x: Option<int> = None; + assert_eq!(x.or_else(|| Some(2)), Some(2)); + assert_eq!(x.or_else(|| None), None); + } + + #[test] fn test_option_while_some() { let mut i = 0; do Some(10).while_some |j| { @@ -490,6 +668,44 @@ mod tests { } #[test] + fn test_unwrap() { + assert_eq!(Some(1).unwrap(), 1); + assert_eq!(Some(~"hello").unwrap(), ~"hello"); + } + + #[test] + #[should_fail] + fn test_unwrap_fail1() { + let x: Option<int> = None; + x.unwrap(); + } + + #[test] + #[should_fail] + fn test_unwrap_fail2() { + let x: Option<~str> = None; + x.unwrap(); + } + + #[test] + fn test_unwrap_or() { + let x: Option<int> = Some(1); + assert_eq!(x.unwrap_or(2), 1); + + let x: Option<int> = None; + assert_eq!(x.unwrap_or(2), 2); + } + + #[test] + fn test_unwrap_or_else() { + let x: Option<int> = Some(1); + assert_eq!(x.unwrap_or_else(|| 2), 1); + + let x: Option<int> = None; + assert_eq!(x.unwrap_or_else(|| 2), 2); + } + + #[test] fn test_unwrap_or_zero() { let some_stuff = Some(42); assert_eq!(some_stuff.unwrap_or_zero(), 42); @@ -566,4 +782,67 @@ mod tests { assert!(!x.mutate_default(0i, |i| i+1)); assert_eq!(x, Some(0i)); } + + #[test] + pub fn test_to_option() { + let some: Option<int> = Some(100); + let none: Option<int> = None; + + assert_eq!(some.to_option(), Some(100)); + assert_eq!(none.to_option(), None); + } + + #[test] + pub fn test_into_option() { + let some: Option<int> = Some(100); + let none: Option<int> = None; + + assert_eq!(some.into_option(), Some(100)); + assert_eq!(none.into_option(), None); + } + + #[test] + pub fn test_as_option() { + let some: Option<int> = Some(100); + let none: Option<int> = None; + + assert_eq!(some.as_option().unwrap(), &100); + assert_eq!(none.as_option(), None); + } + + #[test] + pub fn test_to_result() { + let some: Option<int> = Some(100); + let none: Option<int> = None; + + assert_eq!(some.to_result(), result::Ok(100)); + assert_eq!(none.to_result(), result::Err(())); + } + + #[test] + pub fn test_into_result() { + let some: Option<int> = Some(100); + let none: Option<int> = None; + + assert_eq!(some.into_result(), result::Ok(100)); + assert_eq!(none.into_result(), result::Err(())); + } + + #[test] + pub fn test_to_either() { + let some: Option<int> = Some(100); + let none: Option<int> = None; + + assert_eq!(some.to_either(), either::Right(100)); + assert_eq!(none.to_either(), either::Left(())); + } + + #[test] + pub fn test_into_either() { + let some: Option<int> = Some(100); + let none: Option<int> = None; + + assert_eq!(some.into_either(), either::Right(100)); + assert_eq!(none.into_either(), either::Left(())); + } } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index ab1210aabad..aeeae207204 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -569,7 +569,7 @@ pub fn homedir() -> Option<Path> { #[cfg(windows)] fn secondary() -> Option<Path> { - do getenv("USERPROFILE").chain |p| { + do getenv("USERPROFILE").and_then |p| { if !p.is_empty() { Some(Path(p)) } else { @@ -611,7 +611,7 @@ pub fn tmpdir() -> Path { if cfg!(target_os = "android") { Path("/data/tmp") } else { - getenv_nonempty("TMPDIR").unwrap_or_default(Path("/tmp")) + getenv_nonempty("TMPDIR").unwrap_or(Path("/tmp")) } } @@ -620,7 +620,7 @@ pub fn tmpdir() -> Path { getenv_nonempty("TMP").or( getenv_nonempty("TEMP").or( getenv_nonempty("USERPROFILE").or( - getenv_nonempty("WINDIR")))).unwrap_or_default(Path("C:\\Windows")) + getenv_nonempty("WINDIR")))).unwrap_or(Path("C:\\Windows")) } } diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 793086dca78..3811f34cec4 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -17,6 +17,7 @@ use cmp::Eq; use either; use iter::Iterator; use option::{None, Option, Some, OptionIterator}; +use option; use vec; use vec::OwnedVector; use to_str::ToStr; @@ -36,18 +37,6 @@ pub enum Result<T, E> { } impl<T, E: ToStr> Result<T, E> { - /// Convert to the `either` type - /// - /// `Ok` result variants are converted to `either::Right` variants, `Err` - /// result variants are converted to `either::Left`. - #[inline] - pub fn to_either(self)-> either::Either<E, T>{ - match self { - Ok(t) => either::Right(t), - Err(e) => either::Left(e), - } - } - /// Get a reference to the value out of a successful result /// /// # Failure @@ -184,8 +173,20 @@ impl<T, E: ToStr> Result<T, E> { /// Call a method based on a previous result /// + /// If `self` is `Ok`, then `res` it is returned. If `self` is `Err`, + /// then `self` is returned. + #[inline] + pub fn and(self, res: Result<T, E>) -> Result<T, E> { + match self { + Ok(_) => res, + Err(_) => self, + } + } + + /// Call a method based on a previous result + /// /// If `self` is `Ok` then the value is extracted and passed to `op` - /// whereupon `op`s result is returned. if `self` is `Err` then it is + /// whereupon `op`s result is returned. If `self` is `Err` then it is /// immediately returned. This function can be used to compose the results /// of two functions. /// @@ -195,13 +196,25 @@ impl<T, E: ToStr> Result<T, E> { /// Ok(parse_bytes(buf)) /// }; #[inline] - pub fn chain<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> { + pub fn and_then<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> { match self { Ok(t) => op(t), Err(e) => Err(e), } } + /// Call a method based on a previous result + /// + /// If `self` is `Ok`, then `self` is returned. If `self` is `Err` + /// then `res` is returned. + #[inline] + pub fn or(self, res: Result<T, E>) -> Result<T, E> { + match self { + Ok(_) => self, + Err(_) => res, + } + } + /// Call a function based on a previous result /// /// If `self` is `Err` then the value is extracted and passed to `op` @@ -209,7 +222,7 @@ impl<T, E: ToStr> Result<T, E> { /// immediately returned. This function can be used to pass through a /// successful result while handling an error. #[inline] - pub fn chain_err<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> { + pub fn or_else<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> { match self { Ok(t) => Ok(t), Err(e) => op(e), @@ -255,6 +268,104 @@ impl<T, E: Clone + ToStr> Result<T, E> { } } +/// A generic trait for converting a value to a `Result` +pub trait ToResult<T, E> { + /// Convert to the `result` type + fn to_result(&self) -> Result<T, E>; +} + +/// A generic trait for converting a value to a `Result` +pub trait IntoResult<T, E> { + /// Convert to the `result` type + fn into_result(self) -> Result<T, E>; +} + +/// A generic trait for converting a value to a `Result` +pub trait AsResult<T, E> { + /// Convert to the `result` type + fn as_result<'a>(&'a self) -> Result<&'a T, &'a E>; +} + +impl<T: Clone, E> option::ToOption<T> for Result<T, E> { + #[inline] + fn to_option(&self)-> Option<T> { + match *self { + Ok(ref t) => Some(t.clone()), + Err(_) => None, + } + } +} + +impl<T, E> option::IntoOption<T> for Result<T, E> { + #[inline] + fn into_option(self)-> Option<T> { + match self { + Ok(t) => Some(t), + Err(_) => None, + } + } +} + +impl<T, E> option::AsOption<T> for Result<T, E> { + #[inline] + fn as_option<'a>(&'a self)-> Option<&'a T> { + match *self { + Ok(ref t) => Some(t), + Err(_) => None, + } + } +} + +impl<T: Clone, E: Clone> ToResult<T, E> for Result<T, E> { + #[inline] + fn to_result(&self) -> Result<T, E> { self.clone() } +} + +impl<T, E> IntoResult<T, E> for Result<T, E> { + #[inline] + fn into_result(self) -> Result<T, E> { self } +} + +impl<T, E> AsResult<T, E> for Result<T, E> { + #[inline] + fn as_result<'a>(&'a self) -> Result<&'a T, &'a E> { + match *self { + Ok(ref t) => Ok(t), + Err(ref e) => Err(e), + } + } +} + +impl<T: Clone, E: Clone> either::ToEither<E, T> for Result<T, E> { + #[inline] + fn to_either(&self)-> either::Either<E, T> { + match *self { + Ok(ref t) => either::Right(t.clone()), + Err(ref e) => either::Left(e.clone()), + } + } +} + +impl<T, E> either::IntoEither<E, T> for Result<T, E> { + #[inline] + fn into_either(self)-> either::Either<E, T> { + match self { + Ok(t) => either::Right(t), + Err(e) => either::Left(e), + } + } +} + +impl<T, E> either::AsEither<E, T> for Result<T, E> { + #[inline] + fn as_either<'a>(&'a self)-> either::Either<&'a E, &'a T> { + match *self { + Ok(ref t) => either::Right(t), + Err(ref e) => either::Left(e), + } + } +} + #[inline] #[allow(missing_doc)] pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>, @@ -334,27 +445,51 @@ pub fn fold_<T, E, Iter: Iterator<Result<T, E>>>( mod tests { use super::*; + use either::{IntoEither, ToEither, AsEither}; use either; use iter::range; + use option::{IntoOption, ToOption, AsOption}; + use option; use str::OwnedStr; use vec::ImmutableVector; pub fn op1() -> Result<int, ~str> { Ok(666) } + pub fn op2() -> Result<int, ~str> { Err(~"sadface") } + + #[test] + pub fn test_and() { + assert_eq!(op1().and(Ok(667)).unwrap(), 667); + assert_eq!(op1().and(Err(~"bad")).unwrap_err(), ~"bad"); - pub fn op2(i: int) -> Result<uint, ~str> { - Ok(i as uint + 1u) + assert_eq!(op2().and(Ok(667)).unwrap_err(), ~"sadface"); + assert_eq!(op2().and(Err(~"bad")).unwrap_err(), ~"sadface"); } - pub fn op3() -> Result<int, ~str> { Err(~"sadface") } + #[test] + pub fn test_and_then() { + assert_eq!(op1().and_then(|i| Ok::<int, ~str>(i + 1)).unwrap(), 667); + assert_eq!(op1().and_then(|_| Err::<int, ~str>(~"bad")).unwrap_err(), ~"bad"); + + assert_eq!(op2().and_then(|i| Ok::<int, ~str>(i + 1)).unwrap_err(), ~"sadface"); + assert_eq!(op2().and_then(|_| Err::<int, ~str>(~"bad")).unwrap_err(), ~"sadface"); + } #[test] - pub fn chain_success() { - assert_eq!(op1().chain(op2).unwrap(), 667u); + pub fn test_or() { + assert_eq!(op1().or(Ok(667)).unwrap(), 666); + assert_eq!(op1().or(Err(~"bad")).unwrap(), 666); + + assert_eq!(op2().or(Ok(667)).unwrap(), 667); + assert_eq!(op2().or(Err(~"bad")).unwrap_err(), ~"bad"); } #[test] - pub fn chain_failure() { - assert_eq!(op3().chain( op2).unwrap_err(), ~"sadface"); + pub fn test_or_else() { + assert_eq!(op1().or_else(|_| Ok::<int, ~str>(667)).unwrap(), 666); + assert_eq!(op1().or_else(|e| Err::<int, ~str>(e + "!")).unwrap(), 666); + + assert_eq!(op2().or_else(|_| Ok::<int, ~str>(667)).unwrap(), 667); + assert_eq!(op2().or_else(|e| Err::<int, ~str>(e + "!")).unwrap_err(), ~"sadface!"); } #[test] @@ -413,15 +548,6 @@ mod tests { } #[test] - pub fn test_to_either() { - let r: Result<int, ()> = Ok(100); - let err: Result<(), int> = Err(404); - - assert_eq!(r.to_either(), either::Right(100)); - assert_eq!(err.to_either(), either::Left(404)); - } - - #[test] fn test_collect() { assert_eq!(collect(range(0, 0) .map(|_| Ok::<int, ()>(0))), @@ -460,4 +586,88 @@ mod tests { .map(|f| (*f)())), Err(1)); } + + #[test] + pub fn test_to_option() { + let ok: Result<int, int> = Ok(100); + let err: Result<int, int> = Err(404); + + assert_eq!(ok.to_option(), option::Some(100)); + assert_eq!(err.to_option(), option::None); + } + + #[test] + pub fn test_into_option() { + let ok: Result<int, int> = Ok(100); + let err: Result<int, int> = Err(404); + + assert_eq!(ok.into_option(), option::Some(100)); + assert_eq!(err.into_option(), option::None); + } + + #[test] + pub fn test_as_option() { + let ok: Result<int, int> = Ok(100); + let err: Result<int, int> = Err(404); + + assert_eq!(ok.as_option().unwrap(), &100); + assert_eq!(err.as_option(), option::None); + } + + #[test] + pub fn test_to_result() { + let ok: Result<int, int> = Ok(100); + let err: Result<int, int> = Err(404); + + assert_eq!(ok.to_result(), Ok(100)); + assert_eq!(err.to_result(), Err(404)); + } + + #[test] + pub fn test_into_result() { + let ok: Result<int, int> = Ok(100); + let err: Result<int, int> = Err(404); + + assert_eq!(ok.into_result(), Ok(100)); + assert_eq!(err.into_result(), Err(404)); + } + + #[test] + pub fn test_as_result() { + let ok: Result<int, int> = Ok(100); + let err: Result<int, int> = Err(404); + + let x = 100; + assert_eq!(ok.as_result(), Ok(&x)); + + let x = 404; + assert_eq!(err.as_result(), Err(&x)); + } + + #[test] + pub fn test_to_either() { + let ok: Result<int, int> = Ok(100); + let err: Result<int, int> = Err(404); + + assert_eq!(ok.to_either(), either::Right(100)); + assert_eq!(err.to_either(), either::Left(404)); + } + + #[test] + pub fn test_into_either() { + let ok: Result<int, int> = Ok(100); + let err: Result<int, int> = Err(404); + + assert_eq!(ok.into_either(), either::Right(100)); + assert_eq!(err.into_either(), either::Left(404)); + } + + #[test] + pub fn test_as_either() { + let ok: Result<int, int> = Ok(100); + let err: Result<int, int> = Err(404); + + assert_eq!(ok.as_either().unwrap_right(), &100); + assert_eq!(err.as_either().unwrap_left(), &404); + } } diff --git a/src/libstd/rt/io/net/ip.rs b/src/libstd/rt/io/net/ip.rs index 956dd08ac91..041253455f0 100644 --- a/src/libstd/rt/io/net/ip.rs +++ b/src/libstd/rt/io/net/ip.rs @@ -177,7 +177,7 @@ impl<'self> Parser<'self> { } do self.read_atomically |p| { - p.read_char().chain(|c| parse_digit(c, radix)) + p.read_char().and_then(|c| parse_digit(c, radix)) } } diff --git a/src/libstd/to_bytes.rs b/src/libstd/to_bytes.rs index 855cdfcb851..f47468e1ef8 100644 --- a/src/libstd/to_bytes.rs +++ b/src/libstd/to_bytes.rs @@ -383,5 +383,5 @@ mod test { #[test] fn iterbytes_compiles () { takes_iterbytes((3,4,5,false)); } - fn takes_iterbytes<T : IterBytes>(x : T) {} + fn takes_iterbytes<T : IterBytes>(_x : T) {} } diff --git a/src/libstd/tuple.rs b/src/libstd/tuple.rs index 5d9ca6202e2..2591131f215 100644 --- a/src/libstd/tuple.rs +++ b/src/libstd/tuple.rs @@ -89,6 +89,7 @@ macro_rules! tuple_impls { pub mod inner { use clone::Clone; #[cfg(not(test))] use cmp::*; + #[cfg(not(test))] use default::Default; #[cfg(not(test))] use num::Zero; $( @@ -173,6 +174,14 @@ macro_rules! tuple_impls { } #[cfg(not(test))] + impl<$($T:Default),+> Default for ($($T,)+) { + #[inline] + fn default() -> ($($T,)+) { + ($({ let x: $T = Default::default(); x},)+) + } + } + + #[cfg(not(test))] impl<$($T:Zero),+> Zero for ($($T,)+) { #[inline] fn zero() -> ($($T,)+) { diff --git a/src/libstd/unit.rs b/src/libstd/unit.rs index 3af0322df56..dfe4abe54e5 100644 --- a/src/libstd/unit.rs +++ b/src/libstd/unit.rs @@ -46,14 +46,15 @@ impl TotalEq for () { } #[cfg(not(test))] +impl Default for () { + #[inline] + fn default() -> () { () } +} + +#[cfg(not(test))] impl Zero for () { #[inline] fn zero() -> () { () } #[inline] fn is_zero(&self) -> bool { true } } - -#[cfg(not(test))] -impl Default for () { - fn default() -> () { () } -} diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 1ff58351886..47c3a079614 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -104,9 +104,10 @@ use clone::{Clone, DeepClone}; use container::{Container, Mutable}; use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater}; use cmp; +use default::Default; use iter::*; use libc::c_void; -use num::{Integer, Zero, CheckedAdd, Saturating}; +use num::{Integer, CheckedAdd, Saturating}; use option::{None, Option, Some}; use ptr::to_unsafe_ptr; use ptr; @@ -205,7 +206,7 @@ pub fn with_capacity<T>(capacity: uint) -> ~[T] { */ #[inline] pub fn build<A>(size: Option<uint>, builder: &fn(push: &fn(v: A))) -> ~[A] { - let mut vec = with_capacity(size.unwrap_or_default(4)); + let mut vec = with_capacity(size.unwrap_or(4)); builder(|x| vec.push(x)); vec } @@ -2237,19 +2238,16 @@ impl<A: DeepClone> DeepClone for ~[A] { } // This works because every lifetime is a sub-lifetime of 'static -impl<'self, A> Zero for &'self [A] { - fn zero() -> &'self [A] { &'self [] } - fn is_zero(&self) -> bool { self.is_empty() } +impl<'self, A> Default for &'self [A] { + fn default() -> &'self [A] { &'self [] } } -impl<A> Zero for ~[A] { - fn zero() -> ~[A] { ~[] } - fn is_zero(&self) -> bool { self.len() == 0 } +impl<A> Default for ~[A] { + fn default() -> ~[A] { ~[] } } -impl<A> Zero for @[A] { - fn zero() -> @[A] { @[] } - fn is_zero(&self) -> bool { self.len() == 0 } +impl<A> Default for @[A] { + fn default() -> @[A] { @[] } } macro_rules! iterator { @@ -3588,13 +3586,12 @@ mod tests { } #[test] - fn test_vec_zero() { - use num::Zero; + fn test_vec_default() { + use default::Default; macro_rules! t ( ($ty:ty) => {{ - let v: $ty = Zero::zero(); + let v: $ty = Default::default(); assert!(v.is_empty()); - assert!(v.is_zero()); }} ); |
