<commit_before>// Copyright 2017 Daniel P. Clark & other digits Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.
//
#![deny(missing_docs,trivial_casts,trivial_numeric_casts,
        missing_debug_implementations, missing_copy_implementations,
        unsafe_code,unstable_features,unused_import_braces,unused_qualifications)
]
//! # digits
//!
//! The digits crate is a linked list implementation of a score card flipper.  But
//! in this case it's with any characters you want and you can enumerate through
//! possibilities beyond the numeric limits intrinsic in basic numerc types like `u64`.
//!
//! Primary use case would be brute forcing character sequences.
extern crate base_custom;
use base_custom::BaseCustom;
use std::fmt;

/// # struct Digits
///
/// This struct acts similar to a full number with a custom numeric character base.
/// But the underlying implementation is a linked list where all the methods recurse
/// as far as need to to implement the operations.
#[derive(Clone)]
pub struct Digits<'a> {
  mapping: &'a BaseCustom<char>,
  digit: u64,
  left: Option<Box<Digits<'a>>>,
}

impl<'a> Digits<'a> {
  /// `new` creates a new Digits instance with the provided character set and value.
  ///
  /// The first parameter must be a BaseCustom object which defines and maps all values.
  /// The second parameter is a string value with all valid characters from the BaseCustom set.
  ///
  /// You can view the numbers current value at any time with `to_s()` or `to_string()`.
  pub fn new<S>(mapping: &'a BaseCustom<char>, number: S) -> Digits<'a>
  where S: Into<String> {
    let number = number.into();
    if number.is_empty() { return Digits { mapping: mapping, digit: 0, left: None }; };
    let (last, rest) = {
      let mut n = number.chars().rev();
      (n.next().unwrap(), n.rev().collect::<String>())
    };

    let continuation = {
      if rest.is_empty() {
        None
      } else {
        Some(Box::new(Digits::new(&mapping, rest)))
      }
    };
    Digits {
      mapping: mapping,
      digit: mapping.decimal(last.to_string()),
      left: continuation,
    }
  }

  /// `replicate` — alias for clone (useful for unboxing)
  pub fn replicate(self) -> Self { self.clone() }

  /// `propagate` creates a new number from the same underlying numeric base
  pub fn propagate<S>(&self, number: S) -> Self
  where S: Into<String> {
    Digits::new(self.mapping, number)
  }

  /// Gives the full value of all digits within the linked list as a String.
  pub fn to_s(&self) -> String {
    let num = self.mapping.gen(self.digit);
    match &self.left {
      &None => format!("{}", num),
      &Some(ref bx) => format!("{}{}", bx.to_s(), num),
    }
  }

  /// Gives the full value of all digits within the linked list as a String.
  pub fn to_string(&self) -> String {
    self.to_s()
  }

  // the way to recurse and process Digits
  fn head_tail(self) -> (u64, Option<Box<Self>>) {
    match self.left {
      Some(bx) => (self.digit, Some(bx)),
      None => (self.digit, None),
    }
  }

  // logic for setting left linked list continuation
  fn set_left(&mut self, d: Digits<'a>) {
    if d.is_end() {
      self.left = None;
    } else {
      self.left = Some(Box::new(d));
    }
  }

  /// `length` returns a `usize` of the total linked list length.
  pub fn length(&self) -> usize {
    match &self.left {
      &None => 1,
      &Some(ref l) => { l.length() + 1 }
    }
  }

  /// `zero` returns a Digits instance with value of zero and the current character mapping.
  pub fn zero(&self) -> Self {
    Digits::new_zero(self.mapping)
  }

  /// `new_zero` returns a Digits instance with value of zero and the current character mapping.
  pub fn new_zero(mapping: &'a BaseCustom<char>) -> Self {
    Digits { mapping: mapping, digit: 0, left: None }
  }

  /// `is_zero` returns bool value of if the number is zero
  pub fn is_zero(&self) -> bool {
    if self.digit != 0 { return false }
    match &self.left {
      &None => { true },
      &Some(ref bx) => { bx.is_zero() },
    }
  }

  /// `pinky` is the smallest digit.
  /// a.k.a. current digit in the linked list.
  /// a.k.a. the right most digit.
  /// This will be a char value for that digit.
  pub fn pinky(&self) -> char {
    self.mapping.char(self.digit as usize).unwrap()
  }

  /// `one` returns a Digits instance with value of one and the current character mapping.
  pub fn one(&self) -> Self {
    Digits::new_one(self.mapping)
  }

  /// `new_one` returns a Digits instance with value of one and the current character mapping.
  pub fn new_one(mapping: &'a BaseCustom<char>) -> Self {
    Digits { mapping: mapping, digit: 1, left: None }
  }

  // A non-consuming quick end check.
  // More efficient than calling `is_zero` when this applies.
  fn is_end(&self) -> bool {
    self.digit == 0 && match self.left { None => true, _ => false }
  }

  /// Add two Digits instances together.  The one the `add` method is called on
  /// must be mutable and modifies itself.  The other is consumed.
  ///
  /// Returns a clone of the updated `Self` as well.
  pub fn add(&mut self, other: Self) -> Self {
    assert!(self.mapping == other.mapping);
    if other.is_end() { return self.clone(); };
    let (last, rest) = other.head_tail();

    // sums current single digit
    let added = self.propagate(self.mapping.gen(last + self.digit));
    let (l, r) = added.head_tail();
    self.digit = l;

    // sums for left
    let mut intermediate = Digits::new_zero(self.mapping);
    if let Some(dg) = r { intermediate.add(dg.replicate()); }
    if let Some(dg) = rest { intermediate.add(dg.replicate()); }

    let current_left = match self.left.clone() {
      None => { Box::new(self.zero()) },
      Some(bx) => { bx },
    }.as_ref().clone();

    self.set_left( intermediate.add(current_left).clone() );
    self.clone()
  }

  /// Multiply two Digits instances together.  The one the `mul` method is called on
  /// must be mutable and modifies itself.  The other is consumed.
  ///
  /// Returns a clone of the updated `Self` as well.
  pub fn mul(&mut self, other: Self) -> Self {
    let mut additives: Vec<Digits> = vec![];
    let mut position: u32 = 0;
    let mut o = Some(Box::new(other));
    loop {
      match o.clone() {
        Some(thing) => {
          let (dgt, tail) = thing.head_tail();
          o = tail;

          println!("{:?} * {:?} = {:?}", self.digit, dgt, self.digit * dgt);
          let mltply = self.propagate((self.digit * dgt * 10_u64.pow(position)).to_string());
          println!("{:?} {}", position, mltply.to_s());

          let mapping = self.mapping.clone();

          if let Some(ref mut bx) = self.left {
            additives.push(
              bx.clone().mul(
                Digits::new(
                  mapping,
                  dgt.to_string()
                )
              )
            );
          };

          if !mltply.is_zero() { additives.push( mltply ); }
        },
        None => break,
      }

      position += 1; // TODO! FIXME! The second iteration is only 1 the first time
    }

    loop {
      match additives.pop() {
        Some(dg) => {
          self.add(dg);
        },
        None => break,
      }
    }

    self.clone()
  }
}

/// NODOC
pub trait Into<String> {
  /// NODOC
  fn into(self) -> String;
}

impl<'a> From<Digits<'a>> for String {
  fn from(d: Digits) -> String {
    d.to_s()
  }
}

impl<'a> Into<String> for Digits<'a> {
  fn into(self) -> String {
    self.to_s()
  }
}

impl Into<String> for String {
  fn into(self) -> String {
    self.clone()
  }
}

impl<'a> fmt::Display for Digits<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   write!(f, "Digits<'a> — (Character: '{}', Decimal Value: {}{})",
     self.mapping.gen(self.digit), self.digit, {
       match self.left {
         None => "".to_string(),
         Some(ref l) => format!(", With Preceeding: '{}'", l.to_s()),
       }
     }
     )
  }
}

impl<'a> fmt::Debug for Digits<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{} with base: {:?}", self, self.mapping)
  }
}
<commit_msg>Nope, carry-over needed power of<commit_after>// Copyright 2017 Daniel P. Clark & other digits Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.
//
#![deny(missing_docs,trivial_casts,trivial_numeric_casts,
        missing_debug_implementations, missing_copy_implementations,
        unsafe_code,unstable_features,unused_import_braces,unused_qualifications)
]
//! # digits
//!
//! The digits crate is a linked list implementation of a score card flipper.  But
//! in this case it's with any characters you want and you can enumerate through
//! possibilities beyond the numeric limits intrinsic in basic numerc types like `u64`.
//!
//! Primary use case would be brute forcing character sequences.
extern crate base_custom;
use base_custom::BaseCustom;
use std::fmt;

/// # struct Digits
///
/// This struct acts similar to a full number with a custom numeric character base.
/// But the underlying implementation is a linked list where all the methods recurse
/// as far as need to to implement the operations.
#[derive(Clone)]
pub struct Digits<'a> {
  mapping: &'a BaseCustom<char>,
  digit: u64,
  left: Option<Box<Digits<'a>>>,
}

impl<'a> Digits<'a> {
  /// `new` creates a new Digits instance with the provided character set and value.
  ///
  /// The first parameter must be a BaseCustom object which defines and maps all values.
  /// The second parameter is a string value with all valid characters from the BaseCustom set.
  ///
  /// You can view the numbers current value at any time with `to_s()` or `to_string()`.
  pub fn new<S>(mapping: &'a BaseCustom<char>, number: S) -> Digits<'a>
  where S: Into<String> {
    let number = number.into();
    if number.is_empty() { return Digits { mapping: mapping, digit: 0, left: None }; };
    let (last, rest) = {
      let mut n = number.chars().rev();
      (n.next().unwrap(), n.rev().collect::<String>())
    };

    let continuation = {
      if rest.is_empty() {
        None
      } else {
        Some(Box::new(Digits::new(&mapping, rest)))
      }
    };
    Digits {
      mapping: mapping,
      digit: mapping.decimal(last.to_string()),
      left: continuation,
    }
  }

  /// `replicate` — alias for clone (useful for unboxing)
  pub fn replicate(self) -> Self { self.clone() }

  /// `propagate` creates a new number from the same underlying numeric base
  pub fn propagate<S>(&self, number: S) -> Self
  where S: Into<String> {
    Digits::new(self.mapping, number)
  }

  /// Gives the full value of all digits within the linked list as a String.
  pub fn to_s(&self) -> String {
    let num = self.mapping.gen(self.digit);
    match &self.left {
      &None => format!("{}", num),
      &Some(ref bx) => format!("{}{}", bx.to_s(), num),
    }
  }

  /// Gives the full value of all digits within the linked list as a String.
  pub fn to_string(&self) -> String {
    self.to_s()
  }

  // the way to recurse and process Digits
  fn head_tail(self) -> (u64, Option<Box<Self>>) {
    match self.left {
      Some(bx) => (self.digit, Some(bx)),
      None => (self.digit, None),
    }
  }

  // logic for setting left linked list continuation
  fn set_left(&mut self, d: Digits<'a>) {
    if d.is_end() {
      self.left = None;
    } else {
      self.left = Some(Box::new(d));
    }
  }

  /// `length` returns a `usize` of the total linked list length.
  pub fn length(&self) -> usize {
    match &self.left {
      &None => 1,
      &Some(ref l) => { l.length() + 1 }
    }
  }

  /// `zero` returns a Digits instance with value of zero and the current character mapping.
  pub fn zero(&self) -> Self {
    Digits::new_zero(self.mapping)
  }

  /// `new_zero` returns a Digits instance with value of zero and the current character mapping.
  pub fn new_zero(mapping: &'a BaseCustom<char>) -> Self {
    Digits { mapping: mapping, digit: 0, left: None }
  }

  /// `is_zero` returns bool value of if the number is zero
  pub fn is_zero(&self) -> bool {
    if self.digit != 0 { return false }
    match &self.left {
      &None => { true },
      &Some(ref bx) => { bx.is_zero() },
    }
  }

  /// `pinky` is the smallest digit.
  /// a.k.a. current digit in the linked list.
  /// a.k.a. the right most digit.
  /// This will be a char value for that digit.
  pub fn pinky(&self) -> char {
    self.mapping.char(self.digit as usize).unwrap()
  }

  /// `one` returns a Digits instance with value of one and the current character mapping.
  pub fn one(&self) -> Self {
    Digits::new_one(self.mapping)
  }

  /// `new_one` returns a Digits instance with value of one and the current character mapping.
  pub fn new_one(mapping: &'a BaseCustom<char>) -> Self {
    Digits { mapping: mapping, digit: 1, left: None }
  }

  // A non-consuming quick end check.
  // More efficient than calling `is_zero` when this applies.
  fn is_end(&self) -> bool {
    self.digit == 0 && match self.left { None => true, _ => false }
  }

  /// Add two Digits instances together.  The one the `add` method is called on
  /// must be mutable and modifies itself.  The other is consumed.
  ///
  /// Returns a clone of the updated `Self` as well.
  pub fn add(&mut self, other: Self) -> Self {
    assert!(self.mapping == other.mapping);
    if other.is_end() { return self.clone(); };
    let (last, rest) = other.head_tail();

    // sums current single digit
    let added = self.propagate(self.mapping.gen(last + self.digit));
    let (l, r) = added.head_tail();
    self.digit = l;

    // sums for left
    let mut intermediate = Digits::new_zero(self.mapping);
    if let Some(dg) = r { intermediate.add(dg.replicate()); }
    if let Some(dg) = rest { intermediate.add(dg.replicate()); }

    let current_left = match self.left.clone() {
      None => { Box::new(self.zero()) },
      Some(bx) => { bx },
    }.as_ref().clone();

    self.set_left( intermediate.add(current_left).clone() );
    self.clone()
  }

  /// Multiply two Digits instances together.  The one the `mul` method is called on
  /// must be mutable and modifies itself.  The other is consumed.
  ///
  /// Returns a clone of the updated `Self` as well.
  pub fn mul(&mut self, other: Self) -> Self {
    self.multiply(other, 0)
  }

  fn multiply(&mut self, other: Self, power_of_ten: u32) -> Self {
    println!("STILL DEBUGGING THIS!");
    let mut additives: Vec<Digits> = vec![];
    let mut position: u32 = power_of_ten;
    let mut o = Some(Box::new(other));
    loop {
      match o.clone() {
        Some(thing) => {
          let (dgt, tail) = thing.head_tail();
          o = tail;

          println!("{:?} * {:?} = {:?}", self.digit, dgt, self.digit * dgt);
          let mltply = self.propagate((self.digit * dgt * 10_u64.pow(position)).to_string());
          println!("{:?} {}", position, mltply.to_s());

          let mapping = self.mapping.clone();

          if let Some(ref mut bx) = self.left {
            additives.push(
              bx.clone().multiply(
                Digits::new(
                  mapping,
                  dgt.to_string()
                ),
                position + 1
              )
            );
          };

          if !mltply.is_zero() { additives.push( mltply ); }
        },
        None => break,
      }

      position += 1;
    }

    loop {
      match additives.pop() {
        Some(dg) => {
          self.add(dg);
        },
        None => break,
      }
    }

    self.clone()
  }
}

/// NODOC
pub trait Into<String> {
  /// NODOC
  fn into(self) -> String;
}

impl<'a> From<Digits<'a>> for String {
  fn from(d: Digits) -> String {
    d.to_s()
  }
}

impl<'a> Into<String> for Digits<'a> {
  fn into(self) -> String {
    self.to_s()
  }
}

impl Into<String> for String {
  fn into(self) -> String {
    self.clone()
  }
}

impl<'a> fmt::Display for Digits<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
   write!(f, "Digits<'a> — (Character: '{}', Decimal Value: {}{})",
     self.mapping.gen(self.digit), self.digit, {
       match self.left {
         None => "".to_string(),
         Some(ref l) => format!(", With Preceeding: '{}'", l.to_s()),
       }
     }
     )
  }
}

impl<'a> fmt::Debug for Digits<'a> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{} with base: {:?}", self, self.mapping)
  }
}
<|endoftext|>


<commit_before>#![cfg_attr(unix, feature(old_io, core, old_path))]
#![feature(os, env, std_misc, path)]

//! xdg-rs is a utility library to make conforming to the [XDG specification](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) easier.
//!
//! Some code borrowed from [rust-xdg](https://github.com/o11c/rust-xdg). ```rust-xdg``` is
//! currently a more complete implementation of the specification. The APIs provided by
//! ```rust-xdg``` and ```xdg-rs``` are different.

use std::path::PathBuf;
use std::env;
use std::ffi::{self, AsOsStr, OsString};

fn home_dir() -> PathBuf {
    PathBuf::new(env::home_dir().unwrap().as_os_str())
}

fn split_paths<P: ?Sized>(paths: &P) -> Vec<PathBuf>
    where P: AsOsStr
{
    env::split_paths(paths).map(|x| PathBuf::new(x.as_os_str())).collect()
}

/// Get the data home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home_from_env<F>(get_env_var: &F) -> PathBuf where
    F: Fn(&str) -> Option<OsString>
{
    getenv_path(get_env_var, "XDG_DATA_HOME")
        .unwrap_or(home_dir().join(".local/share"))
}

/// Get the data home directory.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home() -> PathBuf {
    get_data_home_from_env(&env::var_os)
}

/// Get the default data directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs_from_env<F>(get_env_var: &F) -> Vec<PathBuf> where
    F: Fn(&str) -> Option<OsString>
{
    let default_paths = "/usr/local/share:/usr/share".as_os_str().to_os_string();
    let paths = match (*get_env_var)("XDG_DATA_DIRS") {
        Some(paths) => {
            if paths != ffi::OsString::from_str("") {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    split_paths(&paths)
}

/// Get the data directories.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs() -> Vec<PathBuf> {
    get_data_dirs_from_env(&env::var_os)
}

/// Get the config home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home_from_env<F>(get_env_var: &F) -> PathBuf where
    F: Fn(&str) -> Option<OsString>
{
    getenv_path(get_env_var, "XDG_CONFIG_HOME")
        .unwrap_or(home_dir().join(".config"))
}
/// Get the config home directory.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home() -> PathBuf {
    get_config_home_from_env(&env::var_os)
}

/// Get the default config directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs_from_env<F>(get_env_var: &F) -> Vec<PathBuf> where
    F: Fn(&str) -> Option<OsString>
{
    let default_paths = "/etc/xdg".as_os_str().to_os_string();
    let paths = match (*get_env_var)("XDG_CONFIG_DIRS") {
        Some(paths) => {
            if paths != OsString::from_str("") {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    split_paths(&paths)
}

/// Get the config directories.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs() -> Vec<PathBuf> {
    get_config_dirs_from_env(&env::var_os)
}

/// Get the cache home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home_from_env<F>(get_env_var: &F) -> PathBuf where
    F: Fn(&str) -> Option<OsString>
{
    getenv_path(get_env_var, "XDG_CACHE_HOME")
        .unwrap_or(home_dir().join(".cache"))
}

/// Get the cache home directory.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home() -> PathBuf {
    get_cache_home_from_env(&env::var_os)
}

/// Get $XDG_RUNTIME_DIR if found in the environment.
///
/// Returns None if ```$XDG_RUNTIME_PATH``` is not set, in which case it is up to the application
/// to fallback to a location that conforms to the specification.
pub fn get_runtime_dir_from_env<F>(get_env_var: &F) -> Option<PathBuf> where
    F: Fn(&str) -> Option<OsString>
{
    getenv_path(get_env_var, "XDG_RUNTIME_DIR")
}

pub fn get_runtime_dir() -> Option<PathBuf> {
    getenv_path(&env::var_os, "XDG_RUNTIME_DIR")
}

/// Check that the value set for ```$XDG_RUNTIME_DIR``` meets the requirements of the specification
///
/// >$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.
/// >
/// >The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than once he should get pointed to the same directory, and it is mandatory that the directory continues to exist from his first login to his last logout on the system, and not removed in between. Files in the directory MUST not survive reboot or a full logout/login cycle.
/// >
/// >The directory MUST be on a local file system and not shared with any other system. The directory MUST by fully-featured by the standards of the operating system. More specifically, on Unix-like operating systems AF_UNIX sockets, symbolic links, hard links, proper permissions, file locking, sparse files, memory mapping, file change notifications, a reliable hard link count must be supported, and no restrictions on the file name character set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To ensure that your files are not removed, they should have their access time timestamp modified at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file.
#[cfg(unix)]
pub fn test_runtime_dir(path: &PathBuf) -> Result<(), String> {
    use std::old_path;
    use std::old_io;
    use std::os::unix::prelude::OsStrExt;
    use std::old_io::fs::PathExtensions;
    use std::error::Error;
    // FIXME: https://github.com/rust-lang/rfcs/issues/905
    match old_path::Path::new(path.as_os_str().as_bytes()).stat() {
        Ok(stat) => {
            if stat.perm.intersects(old_io::GROUP_RWX | old_io::OTHER_RWX) {
                Err("Incorrect permissions".to_string())
            } else {
                Ok(())
            }
        },

        Err(error) => Err(error.description().to_string())
    }
}

#[cfg(not(unix))]
pub fn test_runtime_dir(_path: &PathBuf) -> Result<(), String> {
    Ok(())
}

/// Get an environment variable's value as a PathBuf.
fn getenv_path<F>(get_env_var: &F, env_var: &str) -> Option<PathBuf> where
    F: Fn(&str) -> Option<OsString>
{
    let path = (*get_env_var)(env_var);
    match path {
        Some(path) => {
            let path = PathBuf::new(&path);
            if path.is_absolute() {
                Some(path)
            } else {
                None
            }
        },

        None => None
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::env;
    use std::path::PathBuf;
    use std::ffi::AsOsStr;

    #[test]
    fn test_env_with_no_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("dummy", "");

        let f = |var: &str| { custom_env.get(var).map(|x| x.as_os_str().to_os_string()) };
        assert!(super::get_data_home_from_env(&f)
                == super::home_dir().join(".local/share"));
        assert!(super::get_data_dirs_from_env(&f)
                == vec![PathBuf::new("/usr/local/share"), PathBuf::new("/usr/share")]);
        assert!(super::get_config_home_from_env(&f)
                == super::home_dir().join(".config"));
        assert!(super::get_config_dirs_from_env(&f)
                == vec![PathBuf::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(&f)
                == super::home_dir().join(".cache"));
        assert!(super::get_runtime_dir_from_env(&f)
                == None);
    }

    #[test]
    fn test_env_with_empty_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", "");
        custom_env.insert("XDG_DATA_DIRS", "");
        custom_env.insert("XDG_CONFIG_HOME", "");
        custom_env.insert("XDG_CONFIG_DIRS", "");
        custom_env.insert("XDG_CACHE_HOME", "");

        let f = |var: &str| { custom_env.get(var).map(|x| x.as_os_str().to_os_string()) };
        assert!(super::get_data_home_from_env(&f)
                == super::home_dir().join(".local/share"));
        assert!(super::get_data_dirs_from_env(&f)
                == vec![PathBuf::new("/usr/local/share"), PathBuf::new("/usr/share")]);
        assert!(super::get_config_home_from_env(&f)
                == super::home_dir().join(".config"));
        assert!(super::get_config_dirs_from_env(&f)
                == vec![PathBuf::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(&f)
                == super::home_dir().join(".cache"));
        assert!(super::get_runtime_dir_from_env(&f)
                == None);
    }

    #[test]
    fn test_env_with_xdg_vars() {
        let cwd = PathBuf::new(&env::current_dir().unwrap());
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", cwd.join("user/data").as_os_str().to_os_string());
        custom_env.insert("XDG_DATA_DIRS", env::join_paths(
                vec![cwd.join("share/data"),cwd.join("local/data")].into_iter()).unwrap());
        custom_env.insert("XDG_CONFIG_HOME", cwd.join("user/config").as_os_str().to_os_string());
        custom_env.insert("XDG_CONFIG_DIRS", env::join_paths(
                vec![cwd.join("config"), cwd.join("local/config")].into_iter()).unwrap());
        custom_env.insert("XDG_CACHE_HOME", cwd.join("user/cache").as_os_str().to_os_string());

        let f = |var: &str| { custom_env.get(var).map(|x| x.clone()) };
        assert!(super::get_data_home_from_env(&f)
                == custom_env.get("XDG_DATA_HOME").map(PathBuf::new).unwrap());
        assert!(super::get_data_dirs_from_env(&f)
                == (super::split_paths(&custom_env["XDG_DATA_DIRS"])));
        assert!(super::get_config_home_from_env(&f)
                == custom_env.get("XDG_CONFIG_HOME").map(PathBuf::new).unwrap());
        assert!(super::get_config_dirs_from_env(&f)
                == super::split_paths(&custom_env["XDG_CONFIG_DIRS"]));
        assert!(super::get_cache_home_from_env(&f)
                == custom_env.get("XDG_CACHE_HOME").map(PathBuf::new).unwrap());
    }
}
<commit_msg>remove feature gate for env<commit_after>#![cfg_attr(unix, feature(old_io, core, old_path))]
#![feature(os, std_misc, path)]

//! xdg-rs is a utility library to make conforming to the [XDG specification](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) easier.
//!
//! Some code borrowed from [rust-xdg](https://github.com/o11c/rust-xdg). ```rust-xdg``` is
//! currently a more complete implementation of the specification. The APIs provided by
//! ```rust-xdg``` and ```xdg-rs``` are different.

use std::path::PathBuf;
use std::env;
use std::ffi::{self, AsOsStr, OsString};

fn home_dir() -> PathBuf {
    PathBuf::new(env::home_dir().unwrap().as_os_str())
}

fn split_paths<P: ?Sized>(paths: &P) -> Vec<PathBuf>
    where P: AsOsStr
{
    env::split_paths(paths).map(|x| PathBuf::new(x.as_os_str())).collect()
}

/// Get the data home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home_from_env<F>(get_env_var: &F) -> PathBuf where
    F: Fn(&str) -> Option<OsString>
{
    getenv_path(get_env_var, "XDG_DATA_HOME")
        .unwrap_or(home_dir().join(".local/share"))
}

/// Get the data home directory.
///
/// If ```$XDG_DATA_HOME``` is not set, it returns ```$HOME/.local/share```.
pub fn get_data_home() -> PathBuf {
    get_data_home_from_env(&env::var_os)
}

/// Get the default data directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs_from_env<F>(get_env_var: &F) -> Vec<PathBuf> where
    F: Fn(&str) -> Option<OsString>
{
    let default_paths = "/usr/local/share:/usr/share".as_os_str().to_os_string();
    let paths = match (*get_env_var)("XDG_DATA_DIRS") {
        Some(paths) => {
            if paths != ffi::OsString::from_str("") {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    split_paths(&paths)
}

/// Get the data directories.
///
/// If ```$XDG_DATA_DIRS``` is not set, it returns ```[/usr/local/share, /usr/share]```.
pub fn get_data_dirs() -> Vec<PathBuf> {
    get_data_dirs_from_env(&env::var_os)
}

/// Get the config home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home_from_env<F>(get_env_var: &F) -> PathBuf where
    F: Fn(&str) -> Option<OsString>
{
    getenv_path(get_env_var, "XDG_CONFIG_HOME")
        .unwrap_or(home_dir().join(".config"))
}
/// Get the config home directory.
///
/// If ```$XDG_CONFIG_HOME``` is not set, it returns ```$HOME/.config```.
pub fn get_config_home() -> PathBuf {
    get_config_home_from_env(&env::var_os)
}

/// Get the default config directories given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs_from_env<F>(get_env_var: &F) -> Vec<PathBuf> where
    F: Fn(&str) -> Option<OsString>
{
    let default_paths = "/etc/xdg".as_os_str().to_os_string();
    let paths = match (*get_env_var)("XDG_CONFIG_DIRS") {
        Some(paths) => {
            if paths != OsString::from_str("") {
                paths
            } else {
                default_paths
            }
        },
        None => default_paths
    };

    split_paths(&paths)
}

/// Get the config directories.
///
/// If ```$XDG_CONFIG_DIRS``` is not set, it returns ```[/etc/xdg]```.
pub fn get_config_dirs() -> Vec<PathBuf> {
    get_config_dirs_from_env(&env::var_os)
}

/// Get the cache home directory given a closure that returns the the value of an environment variable.
/// This method allows having a custom environment.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home_from_env<F>(get_env_var: &F) -> PathBuf where
    F: Fn(&str) -> Option<OsString>
{
    getenv_path(get_env_var, "XDG_CACHE_HOME")
        .unwrap_or(home_dir().join(".cache"))
}

/// Get the cache home directory.
///
/// If ```$XDG_CACHE_HOME``` is not set, it returns ```$HOME/.cache```.
pub fn get_cache_home() -> PathBuf {
    get_cache_home_from_env(&env::var_os)
}

/// Get $XDG_RUNTIME_DIR if found in the environment.
///
/// Returns None if ```$XDG_RUNTIME_PATH``` is not set, in which case it is up to the application
/// to fallback to a location that conforms to the specification.
pub fn get_runtime_dir_from_env<F>(get_env_var: &F) -> Option<PathBuf> where
    F: Fn(&str) -> Option<OsString>
{
    getenv_path(get_env_var, "XDG_RUNTIME_DIR")
}

pub fn get_runtime_dir() -> Option<PathBuf> {
    getenv_path(&env::var_os, "XDG_RUNTIME_DIR")
}

/// Check that the value set for ```$XDG_RUNTIME_DIR``` meets the requirements of the specification
///
/// >$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.
/// >
/// >The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than once he should get pointed to the same directory, and it is mandatory that the directory continues to exist from his first login to his last logout on the system, and not removed in between. Files in the directory MUST not survive reboot or a full logout/login cycle.
/// >
/// >The directory MUST be on a local file system and not shared with any other system. The directory MUST by fully-featured by the standards of the operating system. More specifically, on Unix-like operating systems AF_UNIX sockets, symbolic links, hard links, proper permissions, file locking, sparse files, memory mapping, file change notifications, a reliable hard link count must be supported, and no restrictions on the file name character set should be imposed. Files in this directory MAY be subjected to periodic clean-up. To ensure that your files are not removed, they should have their access time timestamp modified at least once every 6 hours of monotonic time or the 'sticky' bit should be set on the file.
#[cfg(unix)]
pub fn test_runtime_dir(path: &PathBuf) -> Result<(), String> {
    use std::old_path;
    use std::old_io;
    use std::os::unix::prelude::OsStrExt;
    use std::old_io::fs::PathExtensions;
    use std::error::Error;
    // FIXME: https://github.com/rust-lang/rfcs/issues/905
    match old_path::Path::new(path.as_os_str().as_bytes()).stat() {
        Ok(stat) => {
            if stat.perm.intersects(old_io::GROUP_RWX | old_io::OTHER_RWX) {
                Err("Incorrect permissions".to_string())
            } else {
                Ok(())
            }
        },

        Err(error) => Err(error.description().to_string())
    }
}

#[cfg(not(unix))]
pub fn test_runtime_dir(_path: &PathBuf) -> Result<(), String> {
    Ok(())
}

/// Get an environment variable's value as a PathBuf.
fn getenv_path<F>(get_env_var: &F, env_var: &str) -> Option<PathBuf> where
    F: Fn(&str) -> Option<OsString>
{
    let path = (*get_env_var)(env_var);
    match path {
        Some(path) => {
            let path = PathBuf::new(&path);
            if path.is_absolute() {
                Some(path)
            } else {
                None
            }
        },

        None => None
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;
    use std::env;
    use std::path::PathBuf;
    use std::ffi::AsOsStr;

    #[test]
    fn test_env_with_no_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("dummy", "");

        let f = |var: &str| { custom_env.get(var).map(|x| x.as_os_str().to_os_string()) };
        assert!(super::get_data_home_from_env(&f)
                == super::home_dir().join(".local/share"));
        assert!(super::get_data_dirs_from_env(&f)
                == vec![PathBuf::new("/usr/local/share"), PathBuf::new("/usr/share")]);
        assert!(super::get_config_home_from_env(&f)
                == super::home_dir().join(".config"));
        assert!(super::get_config_dirs_from_env(&f)
                == vec![PathBuf::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(&f)
                == super::home_dir().join(".cache"));
        assert!(super::get_runtime_dir_from_env(&f)
                == None);
    }

    #[test]
    fn test_env_with_empty_xdg_vars() {
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", "");
        custom_env.insert("XDG_DATA_DIRS", "");
        custom_env.insert("XDG_CONFIG_HOME", "");
        custom_env.insert("XDG_CONFIG_DIRS", "");
        custom_env.insert("XDG_CACHE_HOME", "");

        let f = |var: &str| { custom_env.get(var).map(|x| x.as_os_str().to_os_string()) };
        assert!(super::get_data_home_from_env(&f)
                == super::home_dir().join(".local/share"));
        assert!(super::get_data_dirs_from_env(&f)
                == vec![PathBuf::new("/usr/local/share"), PathBuf::new("/usr/share")]);
        assert!(super::get_config_home_from_env(&f)
                == super::home_dir().join(".config"));
        assert!(super::get_config_dirs_from_env(&f)
                == vec![PathBuf::new("/etc/xdg")]);
        assert!(super::get_cache_home_from_env(&f)
                == super::home_dir().join(".cache"));
        assert!(super::get_runtime_dir_from_env(&f)
                == None);
    }

    #[test]
    fn test_env_with_xdg_vars() {
        let cwd = PathBuf::new(&env::current_dir().unwrap());
        let mut custom_env = HashMap::new();
        custom_env.insert("XDG_DATA_HOME", cwd.join("user/data").as_os_str().to_os_string());
        custom_env.insert("XDG_DATA_DIRS", env::join_paths(
                vec![cwd.join("share/data"),cwd.join("local/data")].into_iter()).unwrap());
        custom_env.insert("XDG_CONFIG_HOME", cwd.join("user/config").as_os_str().to_os_string());
        custom_env.insert("XDG_CONFIG_DIRS", env::join_paths(
                vec![cwd.join("config"), cwd.join("local/config")].into_iter()).unwrap());
        custom_env.insert("XDG_CACHE_HOME", cwd.join("user/cache").as_os_str().to_os_string());

        let f = |var: &str| { custom_env.get(var).map(|x| x.clone()) };
        assert!(super::get_data_home_from_env(&f)
                == custom_env.get("XDG_DATA_HOME").map(PathBuf::new).unwrap());
        assert!(super::get_data_dirs_from_env(&f)
                == (super::split_paths(&custom_env["XDG_DATA_DIRS"])));
        assert!(super::get_config_home_from_env(&f)
                == custom_env.get("XDG_CONFIG_HOME").map(PathBuf::new).unwrap());
        assert!(super::get_config_dirs_from_env(&f)
                == super::split_paths(&custom_env["XDG_CONFIG_DIRS"]));
        assert!(super::get_cache_home_from_env(&f)
                == custom_env.get("XDG_CACHE_HOME").map(PathBuf::new).unwrap());
    }
}
<|endoftext|>


<commit_before>//! Runtime support for the async/await syntax for futures.
//!
//! This crate serves as a masquerade over the `futures` crate itself,
//! reexporting all of its contents. It's intended that you'll do:
//!
//! ```
//! extern crate futures_await as futures;
//! ```
//!
//! This crate adds a `prelude` module which contains various traits as well as
//! the `async` and `await` macros you'll likely want to use.
//!
//! See the crates's README for more information about usage.

#![feature(conservative_impl_trait)]
#![feature(generator_trait)]
#![feature(try_trait)]
#![feature(use_extern_macros)]

extern crate futures_async_macro; // the compiler lies that this has no effect
extern crate futures_await_macro;
extern crate futures;

pub use futures::*;

pub mod prelude {
    pub use {Future, Stream, Sink, Poll, Async, AsyncSink, StartSend};
    pub use {IntoFuture};
    pub use futures_async_macro::{async, async_block};
    pub use futures_await_macro::await;
}

/// A hidden module that's the "runtime support" for the async/await syntax.
///
/// The `async` attribute and the `await` macro both assume that they can find
/// this module and use its contents. All of their dependencies are defined or
/// reexported here in one way shape or form.
///
/// This module has absolutely not stability at all. All contents may change at
/// any time without notice. Do not use this module in your code if you wish
/// your code to be stable.
#[doc(hidden)]
pub mod __rt {
    pub use std::boxed::Box;
    pub use std::option::Option::{Some, None};
    pub use std::result::Result::{Ok, Err};
    pub use std::ops::Generator;

    use futures::Poll;
    use futures::{Future, Async};
    use std::ops::State;
    use std::ops::Try;

    /// Random hack for this causing problems in the compiler's typechecking
    /// pass. Ideally this trait and impl would not be needed.
    ///
    /// ```ignore
    /// -> impl Future<Item = <T as Try>::Ok,
    ///                Error = <T as Try>::Error>
    /// ```
    pub trait MyFuture<T: Try>: Future<Item=T::Ok, Error=T::Error> {}

    impl<F, T> MyFuture<T> for F
        where F: Future<Item = T::Ok, Error = T::Error> + ?Sized,
              T: Try,
    {}

    pub trait MyTry {
        type MyOk;
        type MyError;
    }
    impl<T: Try> MyTry for T {
        type MyOk = T::Ok;
        type MyError = T::Error;
    }

    /// Small shim to translate from a generator to a future.
    ///
    /// This is the translation layer from the generator/coroutine protocol to
    /// the futures protocol.
    struct GenFuture<T>(T);

    pub fn gen<T>(t: T) -> impl Future<Item = <T::Return as Try>::Ok,
                                       Error = <T::Return as Try>::Error>
        where T: Generator<Yield = ()>,
              T::Return: Try,
    {
        GenFuture(t)
    }

    impl<T> Future for GenFuture<T>
        where T: Generator<Yield = ()>,
              T::Return: Try,
    {
        type Item = <T::Return as Try>::Ok;
        type Error = <T::Return as Try>::Error;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.0.resume() {
                State::Yielded(()) => Ok(Async::NotReady),
                State::Complete(e) => e.into_result().map(Async::Ready),
            }
        }
    }
}
<commit_msg>Fix a compile error<commit_after>//! Runtime support for the async/await syntax for futures.
//!
//! This crate serves as a masquerade over the `futures` crate itself,
//! reexporting all of its contents. It's intended that you'll do:
//!
//! ```
//! extern crate futures_await as futures;
//! ```
//!
//! This crate adds a `prelude` module which contains various traits as well as
//! the `async` and `await` macros you'll likely want to use.
//!
//! See the crates's README for more information about usage.

#![feature(conservative_impl_trait)]
#![feature(generator_trait)]
#![feature(try_trait)]
#![feature(use_extern_macros)]

extern crate futures_async_macro; // the compiler lies that this has no effect
extern crate futures_await_macro;
extern crate futures;

pub use futures::*;

pub mod prelude {
    pub use {Future, Stream, Sink, Poll, Async, AsyncSink, StartSend};
    pub use {IntoFuture};
    pub use futures_async_macro::{async, async_block};
    pub use futures_await_macro::await;
}

/// A hidden module that's the "runtime support" for the async/await syntax.
///
/// The `async` attribute and the `await` macro both assume that they can find
/// this module and use its contents. All of their dependencies are defined or
/// reexported here in one way shape or form.
///
/// This module has absolutely not stability at all. All contents may change at
/// any time without notice. Do not use this module in your code if you wish
/// your code to be stable.
#[doc(hidden)]
pub mod __rt {
    pub use std::boxed::Box;
    pub use std::option::Option::{Some, None};
    pub use std::result::Result::{Ok, Err};
    pub use std::ops::Generator;

    use futures::Poll;
    use futures::{Future, Async};
    use std::ops::State;
    use std::ops::Try;

    /// Random hack for this causing problems in the compiler's typechecking
    /// pass. Ideally this trait and impl would not be needed.
    ///
    /// ```ignore
    /// -> impl Future<Item = <T as Try>::Ok,
    ///                Error = <T as Try>::Error>
    /// ```
    pub trait MyFuture<T: Try>: Future<Item=T::Ok, Error=T::Error> + 'static {}

    impl<F, T> MyFuture<T> for F
        where F: Future<Item = T::Ok, Error = T::Error> + ?Sized + 'static,
              T: Try,
    {}

    pub trait MyTry {
        type MyOk;
        type MyError;
    }
    impl<T: Try> MyTry for T {
        type MyOk = T::Ok;
        type MyError = T::Error;
    }

    /// Small shim to translate from a generator to a future.
    ///
    /// This is the translation layer from the generator/coroutine protocol to
    /// the futures protocol.
    struct GenFuture<T>(T);

    pub fn gen<T>(t: T) -> impl Future<Item = <T::Return as Try>::Ok,
                                       Error = <T::Return as Try>::Error>
        where T: Generator<Yield = ()>,
              T::Return: Try,
    {
        GenFuture(t)
    }

    impl<T> Future for GenFuture<T>
        where T: Generator<Yield = ()>,
              T::Return: Try,
    {
        type Item = <T::Return as Try>::Ok;
        type Error = <T::Return as Try>::Error;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.0.resume() {
                State::Yielded(()) => Ok(Async::NotReady),
                State::Complete(e) => e.into_result().map(Async::Ready),
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

#[derive(Clone, Debug)]
pub struct Expression {
    // TODO: Make these private.
    pub inner: ExpressionInner,
    pub ioargs: IoArgs,
}

// TODO: Make this private.
#[derive(Clone, Debug)]
pub enum ExpressionInner {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression>, Box<Expression>),
    Then(Box<Expression>, Box<Expression>),
}

impl Expression {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }

    pub fn stdin(&mut self, arg: InputArg) -> &mut Self {
        self.ioargs.stdin = arg;
        self
    }

    pub fn stdout(&mut self, arg: OutputArg) -> &mut Self {
        self.ioargs.stdout = arg;
        self
    }

    pub fn stderr(&mut self, arg: OutputArg) -> &mut Self {
        self.ioargs.stderr = arg;
        self
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };
    // TODO: Use a scoped thread here, to avoid this stupid clone.
    let left_expression_clone = left.clone();
    let thread = std::thread::spawn(move || left_expression_clone.exec(left_context));
    let right_status = try!(right.exec(right_context));
    let left_status = try!(thread.join().unwrap());
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<std::str::Utf8Error> for Error {
    fn from(err: std::str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
// TODO: Make this private.
#[derive(Clone, Debug)]
pub struct IoArgs {
    stdin: InputArg,
    stdout: OutputArg,
    stderr: OutputArg,
}

impl IoArgs {
    fn new() -> IoArgs {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        let (stdin, maybe_stdin_thread) = try!(self.stdin.update_handle(parent_context.stdin));
        let stdout = try!(self.stdout.update_handle(parent_context.stdout));
        let stderr = try!(self.stderr.update_handle(parent_context.stderr));
        let child_context = IoContext {
            stdin: stdin,
            stdout: stdout,
            stderr: stderr,
        };

        let result = try!(inner(child_context));

        if let Some(thread) = maybe_stdin_thread {
            try!(thread.join().unwrap());
        }

        Ok(result)
    }
}

#[derive(Clone, Debug)]
pub enum InputArg {
    Inherit,
    Null,
    Path(PathBuf),
    Bytes(Vec<u8>),
}

impl InputArg {
    fn update_handle(&self,
                     parent_handle: pipe::Handle)
                     -> io::Result<(pipe::Handle, Option<JoinHandle<io::Result<()>>>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open(&p))),
            &InputArg::Bytes(ref v) => {
                // TODO: figure out a way to get rid of this clone
                let (handle, thread) = pipe_with_writer_thread(v.clone());
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

#[derive(  Clone, Debug)]
pub enum OutputArg {
    Inherit,
    Null,
    Path(PathBuf), // TODO: stdout/stderr swaps
}

impl OutputArg {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            &OutputArg::Inherit => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create(&p))),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

fn pipe_with_writer_thread(input: Vec<u8>) -> (pipe::Handle, JoinHandle<io::Result<()>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

#[cfg(test)]
mod test {
    use super::{cmd, sh, pipe, then, InputArg, OutputArg};
    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.stdin(InputArg::Bytes(b"foo".to_vec()));
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::Null);
        expr.stdout(OutputArg::Null);
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let input_path = sh("mktemp").read().unwrap();
        let output_path = sh("mktemp").read().unwrap();
        println!("Here are the paths: {:?} {:?}", &input_path, &output_path);
        File::create(&input_path).unwrap().write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.stdin(InputArg::Path(input_path.into()));
        expr.stdout(OutputArg::Path(output_path.clone().into()));
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        File::open(&output_path).unwrap().read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }
}
<commit_msg>use Cows in the InputArg<commit_after>extern crate crossbeam;

use std::borrow::Cow;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression<'static> {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression<'static> {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then<'a>(left: Expression<'a>, right: Expression<'a>) -> Expression<'a> {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

#[derive(Clone, Debug)]
pub struct Expression<'a> {
    // TODO: Make these private.
    pub inner: ExpressionInner<'a>,
    pub ioargs: IoArgs<'a>,
}

// TODO: Make this private.
#[derive(Clone, Debug)]
pub enum ExpressionInner<'a> {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression<'a>>, Box<Expression<'a>>),
    Then(Box<Expression<'a>>, Box<Expression<'a>>),
}

impl<'a> Expression<'a> {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }

    pub fn stdin(&mut self, arg: InputArg<'a>) -> &mut Self {
        self.ioargs.stdin = arg;
        self
    }

    pub fn stdout(&mut self, arg: OutputArg) -> &mut Self {
        self.ioargs.stdout = arg;
        self
    }

    pub fn stderr(&mut self, arg: OutputArg) -> &mut Self {
        self.ioargs.stderr = arg;
        self
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };

    let (left_result, right_result) = crossbeam::scope(|scope| {
        let left_joiner = scope.spawn(|| left.exec(left_context));
        let right_result = right.exec(right_context);
        let left_result = left_joiner.join();
        (left_result, right_result)
    });

    let right_status = try!(right_result);
    let left_status = try!(left_result);
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<std::str::Utf8Error> for Error {
    fn from(err: std::str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
// TODO: Make this private.
#[derive(Clone, Debug)]
pub struct IoArgs<'a> {
    stdin: InputArg<'a>,
    stdout: OutputArg,
    stderr: OutputArg,
}

impl<'a> IoArgs<'a> {
    fn new() -> IoArgs<'static> {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        let (stdin, maybe_stdin_thread) = try!(self.stdin.update_handle(parent_context.stdin));
        let stdout = try!(self.stdout.update_handle(parent_context.stdout));
        let stderr = try!(self.stderr.update_handle(parent_context.stderr));
        let child_context = IoContext {
            stdin: stdin,
            stdout: stdout,
            stderr: stderr,
        };

        let result = try!(inner(child_context));

        if let Some(thread) = maybe_stdin_thread {
            try!(thread.join().unwrap());
        }

        Ok(result)
    }
}

#[derive(Clone, Debug)]
pub enum InputArg<'a> {
    Inherit,
    Null,
    Path(Cow<'a, Path>),
    Bytes(Cow<'a, [u8]>),
}

impl<'a> InputArg<'a> {
    fn update_handle(&self,
                     parent_handle: pipe::Handle)
                     -> io::Result<(pipe::Handle, Option<JoinHandle<io::Result<()>>>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open(&p))),
            &InputArg::Bytes(ref v) => {
                // TODO: figure out a way to get rid of this clone
                let (handle, thread) = pipe_with_writer_thread(v.clone().into_owned());
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

#[derive(  Clone, Debug)]
pub enum OutputArg {
    Inherit,
    Null,
    Path(PathBuf), // TODO: stdout/stderr swaps
}

impl OutputArg {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            &OutputArg::Inherit => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create(&p))),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

fn pipe_with_writer_thread(input: Vec<u8>) -> (pipe::Handle, JoinHandle<io::Result<()>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

#[cfg(test)]
mod test {
    use super::{cmd, sh, pipe, then, InputArg, OutputArg};
    use std::borrow::Cow;
    use std::fs::File;
    use std::io::prelude::*;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.stdin(InputArg::Bytes(Cow::Owned(b"foo".to_vec())));
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.stdin(InputArg::Null);
        expr.stdout(OutputArg::Null);
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let input_path = sh("mktemp").read().unwrap();
        let output_path = sh("mktemp").read().unwrap();
        println!("Here are the paths: {:?} {:?}", &input_path, &output_path);
        File::create(&input_path).unwrap().write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.stdin(InputArg::Path(Cow::Owned(input_path.into())));
        expr.stdout(OutputArg::Path(output_path.clone().into()));
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        File::open(&output_path).unwrap().read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }
}
<|endoftext|>


<commit_before>#![crate_name = "bincode"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]

#![doc(html_logo_url = "./icon.png")]
#![feature(unicode)]

extern crate rustc_serialize;
extern crate byteorder;

use rustc_serialize::{Encodable, Decodable};

pub use refbox::RefBox;
pub use writer::{EncoderWriter, EncodingResult, EncodingError};
pub use reader::{DecoderReader, DecodingResult, DecodingError};
use writer::SizeChecker;

use std::io::{Write, Read};

mod writer;
mod reader;
mod refbox;
#[cfg(test)] mod test;

///! `bincode` is a crate for encoding and decoding using a tiny binary
///! serialization strategy.
///!
///! There are simple functions for encoding to `Vec<u8>` and decoding from
///! `&[u8]`, but the meat of the library is the `encode_into` and `decode_from`
///! functions which respectively allow encoding into a `std::io::Writer`
///! and decoding from a `std::io::Buffer`.
///!
///! ### Using Basic Functions
///!
///! ```rust
///! #![allow(unstable)]
///! extern crate bincode;
///! fn main() {
///!     // The object that we will serialize.
///!     let target = Some("hello world".to_string());
///!     // The maximum size of the encoded message.
///!     let limit = bincode::SizeLimit::Bounded(20);
///!
///!     let encoded: Vec<u8>        = bincode::encode(&target, limit).unwrap();
///!     let decoded: Option<String> = bincode::decode(&encoded[..]).unwrap();
///!     assert_eq!(target, decoded);
///! }
///! ```

/// A limit on the amount of bytes that can be read or written.
///
/// Size limits are an incredibly important part of both encoding and decoding.
///
/// In order to prevent DOS attacks on a decoder, it is important to limit the
/// amount of bytes that a single encoded message can be; otherwise, if you
/// are decoding bytes right off of a TCP stream for example, it would be
/// possible for an attacker to flood your server with a 3TB vec, causing the
/// decoder to run out of memory and crash your application!
/// Because of this, you can provide a maximum-number-of-bytes that can be read
/// during decoding, and the decoder will explicitly fail if it has to read
/// any more than that.
///
/// On the other side, you want to make sure that you aren't encoding a message
/// that is larger than your decoder expects.  By supplying a size limit to an
/// encoding function, the encoder will verify that the structure can be encoded
/// within that limit.  This verification occurs before any bytes are written to
/// the Writer, so recovering from an the error is easy.
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum SizeLimit {
    Infinite,
    Bounded(u64)
}

/// Encodes an encodable object into a `Vec` of bytes.
///
/// If the encoding would take more bytes than allowed by `size_limit`,
/// an error is returned.
pub fn encode<T: Encodable>(t: &T, size_limit: SizeLimit) -> EncodingResult<Vec<u8>> {
    // Since we are putting values directly into a vector, we can do size
    // computation out here and pre-allocate a buffer of *exactly*
    // the right size.
    let mut w = if let SizeLimit::Bounded(l) = size_limit {
        let actual_size = encoded_size_bounded(t, l);
        let actual_size = try!(actual_size.ok_or(EncodingError::SizeLimit));
        Vec::with_capacity(actual_size as usize)
    } else {
        vec![]
    };

    match encode_into(t, &mut w, SizeLimit::Infinite) {
        Ok(()) => Ok(w),
        Err(e) => Err(e)
    }
}

/// Decodes a slice of bytes into an object.
///
/// This method does not have a size-limit because if you already have the bytes
/// in memory, then you don't gain anything by having a limiter.
pub fn decode<T: Decodable>(b: &[u8]) -> DecodingResult<T> {
    let mut b = b;
    decode_from(&mut b, SizeLimit::Infinite)
}

/// Encodes an object directly into a `Writer`.
///
/// If the encoding would take more bytes than allowed by `size_limit`, an error
/// is returned and *no bytes* will be written into the `Writer`.
///
/// If this returns an `EncodingError` (other than SizeLimit), assume that the
/// writer is in an invalid state, as writing could bail out in the middle of
/// encoding.
pub fn encode_into<T: Encodable, W: Write>(t: &T, w: &mut W, size_limit: SizeLimit) -> EncodingResult<()> {
    try!(match size_limit {
        SizeLimit::Infinite => Ok(()),
        SizeLimit::Bounded(x) => {
            let mut size_checker = SizeChecker::new(x);
            t.encode(&mut size_checker)
        }
    });

    t.encode(&mut writer::EncoderWriter::new(w))
}

/// Decoes an object directly from a `Buffer`ed Reader.
///
/// If the provided `SizeLimit` is reached, the decode will bail immediately.
/// A SizeLimit can help prevent an attacker from flooding your server with
/// a neverending stream of values that runs your server out of memory.
///
/// If this returns an `DecodingError`, assume that the buffer that you passed
/// in is in an invalid state, as the error could be returned during any point
/// in the reading.
pub fn decode_from<R: Read, T: Decodable>(r: &mut R, size_limit: SizeLimit) ->
DecodingResult<T> {
    Decodable::decode(&mut reader::DecoderReader::new(r, size_limit))
}

/// Returns the size that an object would be if encoded using bincode.
///
/// This is used internally as part of the check for encode_into, but it can
/// be useful for preallocating buffers if thats your style.
pub fn encoded_size<T: Encodable>(t: &T) -> u64 {
    use std::u64::MAX;
    let mut size_checker = SizeChecker::new(MAX);
    t.encode(&mut size_checker).ok();
    size_checker.written
}

/// Given a maximum size limit, check how large an object would be if it
/// were to be encoded.
///
/// If it can be encoded in `max` or fewer bytes, that number will be returned
/// inside `Some`.  If it goes over bounds, then None is returned.
pub fn encoded_size_bounded<T: Encodable>(t: &T, max: u64) -> Option<u64> {
    let mut size_checker = SizeChecker::new(max);
    t.encode(&mut size_checker).ok().map(|_| size_checker.written)
}
<commit_msg>Fix rustdoc comment syntax<commit_after>//! `bincode` is a crate for encoding and decoding using a tiny binary
//! serialization strategy.
//!
//! There are simple functions for encoding to `Vec<u8>` and decoding from
//! `&[u8]`, but the meat of the library is the `encode_into` and `decode_from`
//! functions which respectively allow encoding into a `std::io::Writer`
//! and decoding from a `std::io::Buffer`.
//!
//! ### Using Basic Functions
//!
//! ```rust
//! #![allow(unstable)]
//! extern crate bincode;
//! fn main() {
//!     // The object that we will serialize.
//!     let target = Some("hello world".to_string());
//!     // The maximum size of the encoded message.
//!     let limit = bincode::SizeLimit::Bounded(20);
//!
//!     let encoded: Vec<u8>        = bincode::encode(&target, limit).unwrap();
//!     let decoded: Option<String> = bincode::decode(&encoded[..]).unwrap();
//!     assert_eq!(target, decoded);
//! }
//! ```

#![crate_name = "bincode"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]

#![doc(html_logo_url = "./icon.png")]
#![feature(unicode)]

extern crate rustc_serialize;
extern crate byteorder;

use rustc_serialize::{Encodable, Decodable};

pub use refbox::RefBox;
pub use writer::{EncoderWriter, EncodingResult, EncodingError};
pub use reader::{DecoderReader, DecodingResult, DecodingError};
use writer::SizeChecker;

use std::io::{Write, Read};

mod writer;
mod reader;
mod refbox;
#[cfg(test)] mod test;

/// A limit on the amount of bytes that can be read or written.
///
/// Size limits are an incredibly important part of both encoding and decoding.
///
/// In order to prevent DOS attacks on a decoder, it is important to limit the
/// amount of bytes that a single encoded message can be; otherwise, if you
/// are decoding bytes right off of a TCP stream for example, it would be
/// possible for an attacker to flood your server with a 3TB vec, causing the
/// decoder to run out of memory and crash your application!
/// Because of this, you can provide a maximum-number-of-bytes that can be read
/// during decoding, and the decoder will explicitly fail if it has to read
/// any more than that.
///
/// On the other side, you want to make sure that you aren't encoding a message
/// that is larger than your decoder expects.  By supplying a size limit to an
/// encoding function, the encoder will verify that the structure can be encoded
/// within that limit.  This verification occurs before any bytes are written to
/// the Writer, so recovering from an the error is easy.
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum SizeLimit {
    Infinite,
    Bounded(u64)
}

/// Encodes an encodable object into a `Vec` of bytes.
///
/// If the encoding would take more bytes than allowed by `size_limit`,
/// an error is returned.
pub fn encode<T: Encodable>(t: &T, size_limit: SizeLimit) -> EncodingResult<Vec<u8>> {
    // Since we are putting values directly into a vector, we can do size
    // computation out here and pre-allocate a buffer of *exactly*
    // the right size.
    let mut w = if let SizeLimit::Bounded(l) = size_limit {
        let actual_size = encoded_size_bounded(t, l);
        let actual_size = try!(actual_size.ok_or(EncodingError::SizeLimit));
        Vec::with_capacity(actual_size as usize)
    } else {
        vec![]
    };

    match encode_into(t, &mut w, SizeLimit::Infinite) {
        Ok(()) => Ok(w),
        Err(e) => Err(e)
    }
}

/// Decodes a slice of bytes into an object.
///
/// This method does not have a size-limit because if you already have the bytes
/// in memory, then you don't gain anything by having a limiter.
pub fn decode<T: Decodable>(b: &[u8]) -> DecodingResult<T> {
    let mut b = b;
    decode_from(&mut b, SizeLimit::Infinite)
}

/// Encodes an object directly into a `Writer`.
///
/// If the encoding would take more bytes than allowed by `size_limit`, an error
/// is returned and *no bytes* will be written into the `Writer`.
///
/// If this returns an `EncodingError` (other than SizeLimit), assume that the
/// writer is in an invalid state, as writing could bail out in the middle of
/// encoding.
pub fn encode_into<T: Encodable, W: Write>(t: &T, w: &mut W, size_limit: SizeLimit) -> EncodingResult<()> {
    try!(match size_limit {
        SizeLimit::Infinite => Ok(()),
        SizeLimit::Bounded(x) => {
            let mut size_checker = SizeChecker::new(x);
            t.encode(&mut size_checker)
        }
    });

    t.encode(&mut writer::EncoderWriter::new(w))
}

/// Decoes an object directly from a `Buffer`ed Reader.
///
/// If the provided `SizeLimit` is reached, the decode will bail immediately.
/// A SizeLimit can help prevent an attacker from flooding your server with
/// a neverending stream of values that runs your server out of memory.
///
/// If this returns an `DecodingError`, assume that the buffer that you passed
/// in is in an invalid state, as the error could be returned during any point
/// in the reading.
pub fn decode_from<R: Read, T: Decodable>(r: &mut R, size_limit: SizeLimit) ->
DecodingResult<T> {
    Decodable::decode(&mut reader::DecoderReader::new(r, size_limit))
}

/// Returns the size that an object would be if encoded using bincode.
///
/// This is used internally as part of the check for encode_into, but it can
/// be useful for preallocating buffers if thats your style.
pub fn encoded_size<T: Encodable>(t: &T) -> u64 {
    use std::u64::MAX;
    let mut size_checker = SizeChecker::new(MAX);
    t.encode(&mut size_checker).ok();
    size_checker.written
}

/// Given a maximum size limit, check how large an object would be if it
/// were to be encoded.
///
/// If it can be encoded in `max` or fewer bytes, that number will be returned
/// inside `Some`.  If it goes over bounds, then None is returned.
pub fn encoded_size_bounded<T: Encodable>(t: &T, max: u64) -> Option<u64> {
    let mut size_checker = SizeChecker::new(max);
    t.encode(&mut size_checker).ok().map(|_| size_checker.written)
}
<|endoftext|>


<commit_before>//! The enum `Either`.

use std::io::{self, Write, Read, BufRead};
use std::convert::{AsRef, AsMut};
use std::ops::Deref;
use std::ops::DerefMut;

pub use Either::{Left, Right};

/// `Either` represents an alternative holding one value out of
/// either of the two possible values.
///
/// `Either` is a general purpose sum type of two parts. For representing
/// success or error, use the regular `Result<T, E>` instead.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Either<L, R> {
    /// A value of type `L`.
    Left(L),
    /// A value of type `R`.
    Right(R),
}

macro_rules! either {
    ($value:expr, $inner:ident => $result:expr) => (
        match $value {
            Either::Left(ref $inner) => $result,
            Either::Right(ref $inner) => $result,
        }
    )
}

macro_rules! either_mut {
    ($value:expr, $inner:ident => $result:expr) => (
        match $value {
            Either::Left(ref mut $inner) => $result,
            Either::Right(ref mut $inner) => $result,
        }
    )
}

/// Macro for unwrapping the left side of an `Either`, which fails early
/// with the opposite side. Can only be used in functions that return
/// `Either` because of the early return of `Right` that it provides.
///
/// See also `try_right!` for its dual, which applies the same just to the
/// right side.
///
/// # Example
///
/// ```
/// #[macro_use] extern crate either;
/// use either::{Either, Left, Right};
///
/// fn twice(wrapper: Either<u32, &str>) -> Either<u32, &str> {
///     let value = try_left!(wrapper);
///     Left(value * 2)
/// }
///
/// fn main() {
///     assert_eq!(twice(Left(2)), Left(4));
///     assert_eq!(twice(Right("ups")), Right("ups"));
/// }
/// ```
#[macro_export]
macro_rules! try_left {
    ($expr:expr) => (
        match $expr {
            $crate::Left(val) => val,
            $crate::Right(err) => return $crate::Right(::std::convert::From::from(err))
        }
    )
}

/// Dual to `try_left!`, see its documentation for more information.
#[macro_export]
macro_rules! try_right {
    ($expr:expr) => (
        match $expr {
            $crate::Left(err) => return $crate::Left(::std::convert::From::from(err)),
            $crate::Right(val) => val
        }
    )
}

impl<L, R> Either<L, R> {
    pub fn is_left(&self) -> bool {
        match *self {
            Left(_) => true,
            Right(_) => false,
        }
    }

    pub fn is_right(&self) -> bool {
        !self.is_left()
    }

    pub fn left(self) -> Option<L> {
        match self {
            Left(l) => Some(l),
            Right(_) => None,
        }
    }

    pub fn right(self) -> Option<R> {
        match self {
            Left(_) => None,
            Right(r) => Some(r),
        }
    }

    pub fn as_ref(&self) -> Either<&L, &R> {
        match *self {
            Left(ref inner) => Left(inner),
            Right(ref inner) => Right(inner),
        }
    }

    pub fn as_mut(&mut self) -> Either<&mut L, &mut R> {
        match *self {
            Left(ref mut inner) => Left(inner),
            Right(ref mut inner) => Right(inner),
        }
    }

    pub fn flip(self) -> Either<R, L> {
        match self {
            Left(l) => Right(l),
            Right(r) => Left(r),
        }
    }
}

/// Convert from `Result` to `Either` with `Ok => Right` and `Err => Left`.
impl<L, R> From<Result<R, L>> for Either<L, R> {
    fn from(r: Result<R, L>) -> Self {
        match r {
            Err(e) => Left(e),
            Ok(o) => Right(o),
        }
    }
}

/// Convert from `Either` to `Result` with `Right => Ok` and `Left => Err`.
impl<L, R> Into<Result<R, L>> for Either<L, R> {
    fn into(self) -> Result<R, L> {
        match self {
            Left(l) => Err(l),
            Right(r) => Ok(r),
        }
    }
}

/// `Either<L, R>` is an iterator if both `L` and `R` are iterators.
impl<L, R> Iterator for Either<L, R>
    where L: Iterator, R: Iterator<Item=L::Item>
{
    type Item = L::Item;

    fn next(&mut self) -> Option<L::Item> {
        either_mut!(*self, inner => inner.next())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        either!(*self, inner => inner.size_hint())
    }
}

impl<L, R> DoubleEndedIterator for Either<L, R>
    where L: DoubleEndedIterator, R: DoubleEndedIterator<Item=L::Item>
{
    fn next_back(&mut self) -> Option<L::Item> {
        either_mut!(*self, inner => inner.next_back())
    }
}

impl<L, R> ExactSizeIterator for Either<L, R>
    where L: ExactSizeIterator, R: ExactSizeIterator<Item=L::Item>
{
}

/// `Either<L, R>` implements `Read` if both `L` and `R` do.
impl<L, R> Read for Either<L, R>
    where L: Read, R: Read
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        either_mut!(*self, inner => inner.read(buf))
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        either_mut!(*self, inner => inner.read_to_end(buf))
    }
}

impl<L, R> BufRead for Either<L, R>
    where L: BufRead, R: BufRead
{
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        either_mut!(*self, inner => inner.fill_buf())
    }

    fn consume(&mut self, amt: usize) {
        either_mut!(*self, inner => inner.consume(amt))
    }
}

/// `Either<L, R>` implements `Write` if both `L` and `R` do.
impl<L, R> Write for Either<L, R>
    where L: Write, R: Write
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        either_mut!(*self, inner => inner.write(buf))
    }

    fn flush(&mut self) -> io::Result<()> {
        either_mut!(*self, inner => inner.flush())
    }
}

impl<L, R, Target> AsRef<Target> for Either<L, R>
    where L: AsRef<Target>, R: AsRef<Target>
{
    fn as_ref(&self) -> &Target {
        either!(*self, inner => inner.as_ref())
    }
}

impl<L, R, Target> AsMut<Target> for Either<L, R>
    where L: AsMut<Target>, R: AsMut<Target>
{
    fn as_mut(&mut self) -> &mut Target {
        either_mut!(*self, inner => inner.as_mut())
    }
}

impl<L, R> Deref for Either<L, R>
    where L: Deref, R: Deref<Target=L::Target>
{
    type Target = L::Target;

    fn deref(&self) -> &Self::Target {
        either!(*self, inner => &*inner)
    }
}

impl<L, R> DerefMut for Either<L, R>
    where L: DerefMut, R: DerefMut<Target=L::Target>
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        either_mut!(*self, inner => &mut *inner)
    }
}

#[test]
fn basic() {
    let mut e = Left(2);
    let r = Right(2);
    assert_eq!(e, Left(2));
    e = r;
    assert_eq!(e, Right(2));
    assert_eq!(e.left(), None);
    assert_eq!(e.right(), Some(2));
    assert_eq!(e.as_ref().right(), Some(&2));
    assert_eq!(e.as_mut().right(), Some(&mut 2));
}

#[test]
fn macros() {
    fn a() -> Either<u32, u32> {
        let x: u32 = try_left!(Right(1337));
        Left(x * 2)
    }
    assert_eq!(a(), Right(1337));

    fn b() -> Either<String, &'static str> {
        Right(try_right!(Left("foo bar")))
    }
    assert_eq!(b(), Left(String::from("foo bar")));
}

#[test]
fn deref() {
    fn is_str(_: &str) {}
    let value: Either<String, &str> = Left(String::from("test"));
    is_str(&*value);
}

#[test]
fn iter() {
    let x = 3;
    let mut iter = match x {
        1...3 => Left(0..10),
        _ => Right(17..),
    };

    assert_eq!(iter.next(), Some(0));
    assert_eq!(iter.count(), 9);
}

#[test]
fn read_write() {
    use std::io;

    let use_stdio = false;
    let mockdata = [0xff; 256];

    let mut reader = if use_stdio {
        Left(io::stdin())
    } else {
        Right(&mockdata[..])
    };

    let mut buf = [0u8; 16];
    assert_eq!(reader.read(&mut buf).unwrap(), buf.len());
    assert_eq!(&buf, &mockdata[..buf.len()]);

    let mut mockbuf = [0u8; 256];
    let mut writer = if use_stdio {
        Left(io::stdout())
    } else {
        Right(&mut mockbuf[..])
    };

    let buf = [1u8; 16];
    assert_eq!(writer.write(&buf).unwrap(), buf.len());
}
<commit_msg>Add Error impl for Either<commit_after>//! The enum `Either`.

use std::error::Error;
use std::fmt;
use std::io::{self, Write, Read, BufRead};
use std::convert::{AsRef, AsMut};
use std::ops::Deref;
use std::ops::DerefMut;

pub use Either::{Left, Right};

/// `Either` represents an alternative holding one value out of
/// either of the two possible values.
///
/// `Either` is a general purpose sum type of two parts. For representing
/// success or error, use the regular `Result<T, E>` instead.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Either<L, R> {
    /// A value of type `L`.
    Left(L),
    /// A value of type `R`.
    Right(R),
}

macro_rules! either {
    ($value:expr, $inner:ident => $result:expr) => (
        match $value {
            Either::Left(ref $inner) => $result,
            Either::Right(ref $inner) => $result,
        }
    )
}

macro_rules! either_mut {
    ($value:expr, $inner:ident => $result:expr) => (
        match $value {
            Either::Left(ref mut $inner) => $result,
            Either::Right(ref mut $inner) => $result,
        }
    )
}

/// Macro for unwrapping the left side of an `Either`, which fails early
/// with the opposite side. Can only be used in functions that return
/// `Either` because of the early return of `Right` that it provides.
///
/// See also `try_right!` for its dual, which applies the same just to the
/// right side.
///
/// # Example
///
/// ```
/// #[macro_use] extern crate either;
/// use either::{Either, Left, Right};
///
/// fn twice(wrapper: Either<u32, &str>) -> Either<u32, &str> {
///     let value = try_left!(wrapper);
///     Left(value * 2)
/// }
///
/// fn main() {
///     assert_eq!(twice(Left(2)), Left(4));
///     assert_eq!(twice(Right("ups")), Right("ups"));
/// }
/// ```
#[macro_export]
macro_rules! try_left {
    ($expr:expr) => (
        match $expr {
            $crate::Left(val) => val,
            $crate::Right(err) => return $crate::Right(::std::convert::From::from(err))
        }
    )
}

/// Dual to `try_left!`, see its documentation for more information.
#[macro_export]
macro_rules! try_right {
    ($expr:expr) => (
        match $expr {
            $crate::Left(err) => return $crate::Left(::std::convert::From::from(err)),
            $crate::Right(val) => val
        }
    )
}

impl<L, R> Either<L, R> {
    pub fn is_left(&self) -> bool {
        match *self {
            Left(_) => true,
            Right(_) => false,
        }
    }

    pub fn is_right(&self) -> bool {
        !self.is_left()
    }

    pub fn left(self) -> Option<L> {
        match self {
            Left(l) => Some(l),
            Right(_) => None,
        }
    }

    pub fn right(self) -> Option<R> {
        match self {
            Left(_) => None,
            Right(r) => Some(r),
        }
    }

    pub fn as_ref(&self) -> Either<&L, &R> {
        match *self {
            Left(ref inner) => Left(inner),
            Right(ref inner) => Right(inner),
        }
    }

    pub fn as_mut(&mut self) -> Either<&mut L, &mut R> {
        match *self {
            Left(ref mut inner) => Left(inner),
            Right(ref mut inner) => Right(inner),
        }
    }

    pub fn flip(self) -> Either<R, L> {
        match self {
            Left(l) => Right(l),
            Right(r) => Left(r),
        }
    }
}

/// Convert from `Result` to `Either` with `Ok => Right` and `Err => Left`.
impl<L, R> From<Result<R, L>> for Either<L, R> {
    fn from(r: Result<R, L>) -> Self {
        match r {
            Err(e) => Left(e),
            Ok(o) => Right(o),
        }
    }
}

/// Convert from `Either` to `Result` with `Right => Ok` and `Left => Err`.
impl<L, R> Into<Result<R, L>> for Either<L, R> {
    fn into(self) -> Result<R, L> {
        match self {
            Left(l) => Err(l),
            Right(r) => Ok(r),
        }
    }
}

/// `Either<L, R>` is an iterator if both `L` and `R` are iterators.
impl<L, R> Iterator for Either<L, R>
    where L: Iterator, R: Iterator<Item=L::Item>
{
    type Item = L::Item;

    fn next(&mut self) -> Option<L::Item> {
        either_mut!(*self, inner => inner.next())
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        either!(*self, inner => inner.size_hint())
    }
}

impl<L, R> DoubleEndedIterator for Either<L, R>
    where L: DoubleEndedIterator, R: DoubleEndedIterator<Item=L::Item>
{
    fn next_back(&mut self) -> Option<L::Item> {
        either_mut!(*self, inner => inner.next_back())
    }
}

impl<L, R> ExactSizeIterator for Either<L, R>
    where L: ExactSizeIterator, R: ExactSizeIterator<Item=L::Item>
{
}

/// `Either<L, R>` implements `Read` if both `L` and `R` do.
impl<L, R> Read for Either<L, R>
    where L: Read, R: Read
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        either_mut!(*self, inner => inner.read(buf))
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        either_mut!(*self, inner => inner.read_to_end(buf))
    }
}

impl<L, R> BufRead for Either<L, R>
    where L: BufRead, R: BufRead
{
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        either_mut!(*self, inner => inner.fill_buf())
    }

    fn consume(&mut self, amt: usize) {
        either_mut!(*self, inner => inner.consume(amt))
    }
}

/// `Either<L, R>` implements `Write` if both `L` and `R` do.
impl<L, R> Write for Either<L, R>
    where L: Write, R: Write
{
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        either_mut!(*self, inner => inner.write(buf))
    }

    fn flush(&mut self) -> io::Result<()> {
        either_mut!(*self, inner => inner.flush())
    }
}

impl<L, R, Target> AsRef<Target> for Either<L, R>
    where L: AsRef<Target>, R: AsRef<Target>
{
    fn as_ref(&self) -> &Target {
        either!(*self, inner => inner.as_ref())
    }
}

impl<L, R, Target> AsMut<Target> for Either<L, R>
    where L: AsMut<Target>, R: AsMut<Target>
{
    fn as_mut(&mut self) -> &mut Target {
        either_mut!(*self, inner => inner.as_mut())
    }
}

impl<L, R> Deref for Either<L, R>
    where L: Deref, R: Deref<Target=L::Target>
{
    type Target = L::Target;

    fn deref(&self) -> &Self::Target {
        either!(*self, inner => &*inner)
    }
}

impl<L, R> DerefMut for Either<L, R>
    where L: DerefMut, R: DerefMut<Target=L::Target>
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        either_mut!(*self, inner => &mut *inner)
    }
}

/// `Either` implements `Error` if *both* `L` and `R` implement it.
impl<L, R> Error for Either<L, R>
    where L: Error, R: Error
{
    fn description(&self) -> &str {
        either!(*self, inner => inner.description())
    }

    fn cause(&self) -> Option<&Error> {
        either!(*self, inner => inner.cause())
    }
}

impl<L, R> fmt::Display for Either<L, R>
    where L: fmt::Display, R: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        either!(*self, inner => inner.fmt(f))
    }
}

#[test]
fn basic() {
    let mut e = Left(2);
    let r = Right(2);
    assert_eq!(e, Left(2));
    e = r;
    assert_eq!(e, Right(2));
    assert_eq!(e.left(), None);
    assert_eq!(e.right(), Some(2));
    assert_eq!(e.as_ref().right(), Some(&2));
    assert_eq!(e.as_mut().right(), Some(&mut 2));
}

#[test]
fn macros() {
    fn a() -> Either<u32, u32> {
        let x: u32 = try_left!(Right(1337));
        Left(x * 2)
    }
    assert_eq!(a(), Right(1337));

    fn b() -> Either<String, &'static str> {
        Right(try_right!(Left("foo bar")))
    }
    assert_eq!(b(), Left(String::from("foo bar")));
}

#[test]
fn deref() {
    fn is_str(_: &str) {}
    let value: Either<String, &str> = Left(String::from("test"));
    is_str(&*value);
}

#[test]
fn iter() {
    let x = 3;
    let mut iter = match x {
        1...3 => Left(0..10),
        _ => Right(17..),
    };

    assert_eq!(iter.next(), Some(0));
    assert_eq!(iter.count(), 9);
}

#[test]
fn read_write() {
    use std::io;

    let use_stdio = false;
    let mockdata = [0xff; 256];

    let mut reader = if use_stdio {
        Left(io::stdin())
    } else {
        Right(&mockdata[..])
    };

    let mut buf = [0u8; 16];
    assert_eq!(reader.read(&mut buf).unwrap(), buf.len());
    assert_eq!(&buf, &mockdata[..buf.len()]);

    let mut mockbuf = [0u8; 256];
    let mut writer = if use_stdio {
        Left(io::stdout())
    } else {
        Right(&mut mockbuf[..])
    };

    let buf = [1u8; 16];
    assert_eq!(writer.write(&buf).unwrap(), buf.len());
}

#[test]
fn error() {
    let invalid_utf8 = b"\xff";
    let res = || -> Result<_, Either<_, _>> {
        try!(::std::str::from_utf8(invalid_utf8).map_err(Left));
        try!("x".parse::<i32>().map_err(Right));
        Ok(())
    }();
    assert!(res.is_err());
    res.unwrap_err().description(); // make sure this can be called
}
<|endoftext|>