daf5f5a4d1
Who doesn't like a massive renaming?
436 lines
12 KiB
Rust
436 lines
12 KiB
Rust
// Copyright 2012 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.
|
|
|
|
//! A type that represents one of two alternatives
|
|
|
|
#[allow(missing_doc)];
|
|
|
|
use option::{Some, None};
|
|
use option;
|
|
use clone::Clone;
|
|
use container::Container;
|
|
use cmp::Eq;
|
|
use iter::{Iterator, FilterMap};
|
|
use result::Result;
|
|
use result;
|
|
use str::StrSlice;
|
|
use vec;
|
|
use vec::{OwnedVector, ImmutableVector};
|
|
|
|
/// `Either` is a type that represents one of two alternatives
|
|
#[deriving(Clone, Eq, IterBytes)]
|
|
pub enum Either<L, R> {
|
|
Left(L),
|
|
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)
|
|
}
|
|
}
|
|
|
|
/// 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")
|
|
}
|
|
}
|
|
|
|
/// 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>;
|
|
|
|
/// An iterator yielding the `Right` values of its source
|
|
pub type Rights<L, R, Iter> = FilterMap<'static, Either<L, R>, R, Iter>;
|
|
|
|
/// Extracts all the left values
|
|
pub fn lefts<L, R, Iter: Iterator<Either<L, R>>>(eithers: Iter)
|
|
-> Lefts<L, R, Iter> {
|
|
do eithers.filter_map |elt| {
|
|
match elt {
|
|
Left(x) => Some(x),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Extracts all the right values
|
|
pub fn rights<L, R, Iter: Iterator<Either<L, R>>>(eithers: Iter)
|
|
-> Rights<L, R, Iter> {
|
|
do eithers.filter_map |elt| {
|
|
match elt {
|
|
Right(x) => Some(x),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// 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<L, R>(eithers: ~[Either<L, R>]) -> (~[L], ~[R]) {
|
|
let n_lefts = eithers.iter().count(|elt| elt.is_left());
|
|
let mut lefts = vec::with_capacity(n_lefts);
|
|
let mut rights = vec::with_capacity(eithers.len() - n_lefts);
|
|
for elt in eithers.move_iter() {
|
|
match elt {
|
|
Left(l) => lefts.push(l),
|
|
Right(r) => rights.push(r)
|
|
}
|
|
}
|
|
return (lefts, rights);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
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);
|
|
fn f_left(x: &int) -> bool { *x == 10 }
|
|
fn f_right(_x: &uint) -> bool { false }
|
|
assert!(val.either(f_left, f_right));
|
|
}
|
|
|
|
#[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));
|
|
}
|
|
|
|
#[test]
|
|
fn test_lefts() {
|
|
let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)];
|
|
let result = lefts(input.move_iter()).to_owned_vec();
|
|
assert_eq!(result, ~[10, 12, 14]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_lefts_none() {
|
|
let input: ~[Either<int, int>] = ~[Right(10), Right(10)];
|
|
let result = lefts(input.move_iter()).to_owned_vec();
|
|
assert_eq!(result.len(), 0u);
|
|
}
|
|
|
|
#[test]
|
|
fn test_lefts_empty() {
|
|
let input: ~[Either<int, int>] = ~[];
|
|
let result = lefts(input.move_iter()).to_owned_vec();
|
|
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.move_iter()).to_owned_vec();
|
|
assert_eq!(result, ~[11, 13]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_rights_none() {
|
|
let input: ~[Either<int, int>] = ~[Left(10), Left(10)];
|
|
let result = rights(input.move_iter()).to_owned_vec();
|
|
assert_eq!(result.len(), 0u);
|
|
}
|
|
|
|
#[test]
|
|
fn test_rights_empty() {
|
|
let input: ~[Either<int, int>] = ~[];
|
|
let result = rights(input.move_iter()).to_owned_vec();
|
|
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_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_empty() {
|
|
let input: ~[Either<int, int>] = ~[];
|
|
let (lefts, rights) = partition(input);
|
|
assert_eq!(lefts.len(), 0u);
|
|
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);
|
|
}
|
|
}
|