diff options
Diffstat (limited to 'src/libstd/either.rs')
| -rw-r--r-- | src/libstd/either.rs | 366 |
1 files changed, 173 insertions, 193 deletions
diff --git a/src/libstd/either.rs b/src/libstd/either.rs index 6bdc45d7204..cfaef550c6f 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -23,29 +23,102 @@ use str::StrSlice; use vec; use vec::{OwnedVector, ImmutableVector}; -/// The either type +/// `Either` is a type that represents one of two alternatives #[deriving(Clone, Eq)] -pub enum Either<T, U> { - Left(T), - Right(U) +pub enum Either<L, R> { + Left(L), + Right(R) } -/// Applies a function based on the given either value -/// -/// If `value` is left(T) then `f_left` is applied to its contents, if -/// `value` is right(U) then `f_right` is applied to its contents, and the -/// result is returned. -#[inline] -pub fn either<T, U, V>(f_left: &fn(&T) -> V, - f_right: &fn(&U) -> V, value: &Either<T, U>) -> V { - match *value { - Left(ref l) => f_left(l), - Right(ref r) => f_right(r) +impl<L, R> Either<L, R> { + /// Applies a function based on the given either value + /// + /// If `value` is `Left(L)` then `f_left` is applied to its contents, if + /// `value` is `Right(R)` then `f_right` is applied to its contents, and the + /// result is returned. + #[inline] + pub fn either<T>(&self, f_left: &fn(&L) -> T, f_right: &fn(&R) -> T) -> T { + match *self { + Left(ref l) => f_left(l), + Right(ref r) => f_right(r) + } + } + + /// Flips between left and right of a given `Either` + #[inline] + pub fn flip(self) -> Either<R, L> { + match self { + Right(r) => Left(r), + Left(l) => Right(l) + } + } + + /// 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 { + match *self { + Left(_) => true, + _ => false + } + } + + /// Checks whether the given value is a `Right` + #[inline] + pub fn is_right(&self) -> bool { + match *self { + Right(_) => true, + _ => false + } + } + + /// Retrieves the value from a `Left`. + /// Fails with a specified reason if the `Either` is `Right`. + #[inline] + pub fn expect_left(self, reason: &str) -> L { + match self { + Left(x) => x, + Right(_) => fail!(reason.to_owned()) + } + } + + /// Retrieves the value from a `Left`. Fails if the `Either` is `Right`. + #[inline] + pub fn unwrap_left(self) -> L { + self.expect_left("called Either::unwrap_left()` on `Right` value") + } + + /// Retrieves the value from a `Right`. + /// Fails with a specified reason if the `Either` is `Left`. + #[inline] + pub fn expect_right(self, reason: &str) -> R { + match self { + Right(x) => x, + Left(_) => fail!(reason.to_owned()) + } + } + + /// Retrieves the value from a `Right`. Fails if the `Either` is `Left`. + #[inline] + pub fn unwrap_right(self) -> R { + self.expect_right("called Either::unwrap_right()` on `Left` value") } } +// FIXME: #8228 Replaceable by an external iterator? /// Extracts from a vector of either all the left values -pub fn lefts<T:Clone,U>(eithers: &[Either<T, U>]) -> ~[T] { +pub fn lefts<L: Clone, R>(eithers: &[Either<L, R>]) -> ~[L] { do vec::build_sized(eithers.len()) |push| { for elt in eithers.iter() { match *elt { @@ -56,8 +129,9 @@ pub fn lefts<T:Clone,U>(eithers: &[Either<T, U>]) -> ~[T] { } } +// FIXME: #8228 Replaceable by an external iterator? /// Extracts from a vector of either all the right values -pub fn rights<T, U: Clone>(eithers: &[Either<T, U>]) -> ~[U] { +pub fn rights<L, R: Clone>(eithers: &[Either<L, R>]) -> ~[R] { do vec::build_sized(eithers.len()) |push| { for elt in eithers.iter() { match *elt { @@ -68,13 +142,14 @@ pub fn rights<T, U: Clone>(eithers: &[Either<T, U>]) -> ~[U] { } } +// FIXME: #8228 Replaceable by an external iterator? /// Extracts from a vector of either all the left values and right values /// /// Returns a structure containing a vector of left values and a vector of /// right values. -pub fn partition<T, U>(eithers: ~[Either<T, U>]) -> (~[T], ~[U]) { - let mut lefts: ~[T] = ~[]; - let mut rights: ~[U] = ~[]; +pub fn partition<L, R>(eithers: ~[Either<L, R>]) -> (~[L], ~[R]) { + let mut lefts: ~[L] = ~[]; + let mut rights: ~[R] = ~[]; for elt in eithers.consume_iter() { match elt { Left(l) => lefts.push(l), @@ -84,196 +159,101 @@ pub fn partition<T, U>(eithers: ~[Either<T, U>]) -> (~[T], ~[U]) { return (lefts, rights); } -/// Flips between left and right of a given either -#[inline] -pub fn flip<T, U>(eith: Either<T, U>) -> Either<U, T> { - match eith { - Right(r) => Left(r), - Left(l) => Right(l) - } -} +#[cfg(test)] +mod tests { + use super::*; -/// Converts either::t to a result::t -/// -/// Converts an `either` type to a `result` type, making the "right" choice -/// an ok result, and the "left" choice a fail -#[inline] -pub fn to_result<T, U>(eith: Either<T, U>) -> Result<U, T> { - match eith { - Right(r) => result::Ok(r), - Left(l) => result::Err(l) + #[test] + fn test_either_left() { + let val = Left(10); + fn f_left(x: &int) -> bool { *x == 10 } + fn f_right(_x: &uint) -> bool { false } + assert!(val.either(f_left, f_right)); } -} -/// Checks whether the given value is a left -#[inline] -pub fn is_left<T, U>(eith: &Either<T, U>) -> bool { - match *eith { - Left(_) => true, - _ => false + #[test] + fn test_either_right() { + let val = Right(10u); + fn f_left(_x: &int) -> bool { false } + fn f_right(x: &uint) -> bool { *x == 10u } + assert!(val.either(f_left, f_right)); } -} -/// Checks whether the given value is a right -#[inline] -pub fn is_right<T, U>(eith: &Either<T, U>) -> bool { - match *eith { - Right(_) => true, - _ => false + #[test] + fn test_lefts() { + let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; + let result = lefts(input); + assert_eq!(result, ~[10, 12, 14]); } -} -/// Retrieves the value in the left branch. -/// Fails with a specified reason if the either is Right. -#[inline] -pub fn expect_left<T,U>(eith: Either<T,U>, reason: &str) -> T { - match eith { - Left(x) => x, - Right(_) => fail!(reason.to_owned()) + #[test] + fn test_lefts_none() { + let input: ~[Either<int, int>] = ~[Right(10), Right(10)]; + let result = lefts(input); + assert_eq!(result.len(), 0u); } -} -/// Retrieves the value in the left branch. Fails if the either is Right. -#[inline] -pub fn unwrap_left<T,U>(eith: Either<T,U>) -> T { - expect_left(eith, "either::unwrap_left Right") -} - -/// Retrieves the value in the right branch. -/// Fails with a specified reason if the either is Left. -#[inline] -pub fn expect_right<T,U>(eith: Either<T,U>, reason: &str) -> U { - match eith { - Right(x) => x, - Left(_) => fail!(reason.to_owned()) + #[test] + fn test_lefts_empty() { + let input: ~[Either<int, int>] = ~[]; + let result = lefts(input); + assert_eq!(result.len(), 0u); } -} -/// Retrieves the value in the right branch. Fails if the either is Left. -pub fn unwrap_right<T,U>(eith: Either<T,U>) -> U { - expect_right(eith, "either::unwrap_right Left") -} - -impl<T, U> Either<T, U> { - #[inline] - pub fn either<V>(&self, f_left: &fn(&T) -> V, f_right: &fn(&U) -> V) -> V { - either(f_left, f_right, self) + #[test] + fn test_rights() { + let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; + let result = rights(input); + assert_eq!(result, ~[11, 13]); } - #[inline] - pub fn flip(self) -> Either<U, T> { flip(self) } - - #[inline] - pub fn to_result(self) -> Result<U, T> { to_result(self) } - - #[inline] - pub fn is_left(&self) -> bool { is_left(self) } - - #[inline] - pub fn is_right(&self) -> bool { is_right(self) } - - #[inline] - pub fn expect_left(self, reason: &str) -> T { expect_left(self, reason) } - - #[inline] - pub fn unwrap_left(self) -> T { unwrap_left(self) } - - #[inline] - pub fn expect_right(self, reason: &str) -> U { expect_right(self, reason) } - - #[inline] - pub fn unwrap_right(self) -> U { unwrap_right(self) } -} - -#[test] -fn test_either_left() { - let val = Left(10); - fn f_left(x: &int) -> bool { *x == 10 } - fn f_right(_x: &uint) -> bool { false } - assert!((either(f_left, f_right, &val))); -} - -#[test] -fn test_either_right() { - let val = Right(10u); - fn f_left(_x: &int) -> bool { false } - fn f_right(x: &uint) -> bool { *x == 10u } - assert!((either(f_left, f_right, &val))); -} - -#[test] -fn test_lefts() { - let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let result = lefts(input); - assert_eq!(result, ~[10, 12, 14]); -} - -#[test] -fn test_lefts_none() { - let input: ~[Either<int, int>] = ~[Right(10), Right(10)]; - let result = lefts(input); - assert_eq!(result.len(), 0u); -} - -#[test] -fn test_lefts_empty() { - let input: ~[Either<int, int>] = ~[]; - let result = lefts(input); - assert_eq!(result.len(), 0u); -} - -#[test] -fn test_rights() { - let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let result = rights(input); - assert_eq!(result, ~[11, 13]); -} + #[test] + fn test_rights_none() { + let input: ~[Either<int, int>] = ~[Left(10), Left(10)]; + let result = rights(input); + assert_eq!(result.len(), 0u); + } -#[test] -fn test_rights_none() { - let input: ~[Either<int, int>] = ~[Left(10), Left(10)]; - let result = rights(input); - assert_eq!(result.len(), 0u); -} + #[test] + fn test_rights_empty() { + let input: ~[Either<int, int>] = ~[]; + let result = rights(input); + assert_eq!(result.len(), 0u); + } -#[test] -fn test_rights_empty() { - let input: ~[Either<int, int>] = ~[]; - let result = rights(input); - assert_eq!(result.len(), 0u); -} + #[test] + fn test_partition() { + let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; + let (lefts, rights) = partition(input); + assert_eq!(lefts[0], 10); + assert_eq!(lefts[1], 12); + assert_eq!(lefts[2], 14); + assert_eq!(rights[0], 11); + assert_eq!(rights[1], 13); + } -#[test] -fn test_partition() { - let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let (lefts, rights) = partition(input); - assert_eq!(lefts[0], 10); - assert_eq!(lefts[1], 12); - assert_eq!(lefts[2], 14); - assert_eq!(rights[0], 11); - assert_eq!(rights[1], 13); -} + #[test] + fn test_partition_no_lefts() { + let input: ~[Either<int, int>] = ~[Right(10), Right(11)]; + let (lefts, rights) = partition(input); + assert_eq!(lefts.len(), 0u); + assert_eq!(rights.len(), 2u); + } -#[test] -fn test_partition_no_lefts() { - let input: ~[Either<int, int>] = ~[Right(10), Right(11)]; - let (lefts, rights) = partition(input); - assert_eq!(lefts.len(), 0u); - assert_eq!(rights.len(), 2u); -} + #[test] + fn test_partition_no_rights() { + let input: ~[Either<int, int>] = ~[Left(10), Left(11)]; + let (lefts, rights) = partition(input); + assert_eq!(lefts.len(), 2u); + assert_eq!(rights.len(), 0u); + } -#[test] -fn test_partition_no_rights() { - let input: ~[Either<int, int>] = ~[Left(10), Left(11)]; - let (lefts, rights) = partition(input); - assert_eq!(lefts.len(), 2u); - assert_eq!(rights.len(), 0u); -} + #[test] + fn test_partition_empty() { + let input: ~[Either<int, int>] = ~[]; + let (lefts, rights) = partition(input); + assert_eq!(lefts.len(), 0u); + assert_eq!(rights.len(), 0u); + } -#[test] -fn test_partition_empty() { - let input: ~[Either<int, int>] = ~[]; - let (lefts, rights) = partition(input); - assert_eq!(lefts.len(), 0u); - assert_eq!(rights.len(), 0u); } |
