<commit_before>//! which
//!
//! A Rust equivalent of Unix command `which(1)`.
//! # Example:
//!
//! To find which rustc executable binary is using:
//!
//! ``` norun
//! use which::which;
//!
//! let result = which::which("rustc").unwrap();
//! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
//!
//! ```

extern crate libc;
#[cfg(test)]
extern crate tempdir;

use std::ascii::AsciiExt;
use std::path::{Path,PathBuf};
use std::{env, fs};
#[cfg(unix)]
use std::ffi::CString;
use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;

fn is_exist(bin_path: &Path) -> bool {

    match fs::metadata(bin_path).map(|metadata|{
        metadata.is_file()
    }) {
        Ok(true) => true,
        _ => false
    }
}

/// Return `true` if `path` is executable.
#[cfg(unix)]
fn is_executable(path: &Path) -> bool {
    CString::new(path.as_os_str().as_bytes())
        .and_then(|c| {
            Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 })
        })
        .unwrap_or(false)
}

#[cfg(not(unix))]
fn is_executable(_path: &Path) -> bool { true }

/// Like `Path::with_extension`, but don't replace an existing extension.
fn ensure_exe_extension<T: AsRef<Path>>(path: T) -> PathBuf {
    if env::consts::EXE_EXTENSION.is_empty() {
        // Nothing to do.
        path.as_ref().to_path_buf()
    } else {
        match path.as_ref().extension().and_then(|e| e.to_str()).map(|e| e.eq_ignore_ascii_case(env::consts::EXE_EXTENSION)) {
            // Already has the right extension.
            Some(true) => path.as_ref().to_path_buf(),
            _ => {
                // Append the extension.
                let mut s = path.as_ref().to_path_buf().into_os_string();
                s.push(".");
                s.push(env::consts::EXE_EXTENSION);
                PathBuf::from(s)
            }
        }
    }
}

/// Find a exectable binary's path by name.
///
/// If given an absolute path, returns it if the file exists and is executable.
///
/// If given a relative path, returns an absolute path to the file if
/// it exists and is executable.
///
/// If given a string without path separators, looks for a file named
/// `binary_name` at each directory in `$PATH` and if it finds an executable
/// file there, returns it.
///
/// # Example
///
/// ``` norun
/// use which::which;
/// use std::path::PathBuf;
///
/// let result = which::which("rustc").unwrap();
/// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
///
/// ```
pub fn which<T: AsRef<OsStr>>(binary_name: T)
             -> Result<PathBuf, &'static str> {
    env::current_dir()
        .or_else(|_| Err("Couldn't get current directory"))
        .and_then(|cwd| which_in(binary_name, env::var_os("PATH"), &cwd))
}

/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V)
             -> Result<PathBuf, &'static str>
                where T: AsRef<OsStr>,
                      U: AsRef<OsStr>,
                      V: AsRef<Path> {
    // Does it have a path separator?
    let path = ensure_exe_extension(binary_name.as_ref());
    if path.components().count() > 1 {
        if path.is_absolute() {
            if is_exist(&path) && is_executable(&path) {
                // Already fine.
                Ok(path)
            } else {
                // Absolute path but it's not usable.
                Err("Bad absolute path")
            }
        } else {
            // Try to make it absolute.
            let mut new_path = PathBuf::from(cwd.as_ref());
            new_path.push(path);
            let new_path = ensure_exe_extension(new_path);
            if is_exist(&new_path) && is_executable(&new_path) {
                Ok(new_path)
            } else {
                // File doesn't exist or isn't executable.
                Err("Bad relative path")
            }
        }
    } else {
        // No separator, look it up in `paths`.
        paths.and_then(
            |paths|
            env::split_paths(paths.as_ref())
                .map(|p| ensure_exe_extension(p.join(binary_name.as_ref())))
                .skip_while(|p| !(is_exist(&p) && is_executable(&p)))
                .next())
            .ok_or("Cannot find binary path")
    }
}

#[test]
fn test_exe_extension() {
    let expected = PathBuf::from("foo").with_extension(env::consts::EXE_EXTENSION);
    assert_eq!(expected, ensure_exe_extension(PathBuf::from("foo")));
    let p = expected.clone();
    assert_eq!(expected, ensure_exe_extension(p));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension() {
    assert_eq!(PathBuf::from("foo.bar.exe"),
               ensure_exe_extension("foo.bar"));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension_uppercase() {
    assert_eq!(PathBuf::from("foo.EXE"),
               ensure_exe_extension("foo.EXE"));
}

#[cfg(test)]
mod test {
    use super::*;

    use std::env;
    use std::ffi::{OsStr,OsString};
    use std::fs;
    use std::io;
    use std::path::{Path,PathBuf};
    use tempdir::TempDir;

    struct TestFixture {
        /// Temp directory.
        pub tempdir: TempDir,
        /// $PATH
        pub paths: OsString,
        /// Binaries created in $PATH
        pub bins: Vec<PathBuf>,
    }

    const SUBDIRS: &'static [&'static str] = &["a", "b", "c"];
    const BIN_NAME: &'static str = "bin";

    #[cfg(unix)]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        use libc;
        use std::os::unix::fs::OpenOptionsExt;
        let bin = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::OpenOptions::new()
            .write(true)
            .create(true)
            .mode(0o666 | (libc::S_IXUSR as u32))
            .open(&bin)
            .and_then(|_f| bin.canonicalize())
    }

    fn touch(dir: &Path, path: &str) -> io::Result<PathBuf> {
        let b = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::File::create(&b)
            .and_then(|_f| b.canonicalize())
    }

    #[cfg(not(unix))]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        touch(dir, path)
    }

    impl TestFixture {
        pub fn new() -> TestFixture {
            let tempdir = TempDir::new("which_tests").unwrap();
            let mut builder = fs::DirBuilder::new();
            builder.recursive(true);
            let mut paths = vec!();
            let mut bins = vec!();
            for d in SUBDIRS.iter() {
                let p = tempdir.path().join(d);
                builder.create(&p).unwrap();
                bins.push(mk_bin(&p, &BIN_NAME).unwrap());
                paths.push(p);
            }
            TestFixture {
                tempdir: tempdir,
                paths: env::join_paths(paths).unwrap(),
                bins: bins,
            }
        }

        #[allow(dead_code)]
        pub fn touch(&self, path: &str) -> io::Result<PathBuf> {
            touch(self.tempdir.path(), &path)
        }

        pub fn mk_bin(&self, path: &str) -> io::Result<PathBuf> {
            mk_bin(self.tempdir.path(), &path)
        }
    }

    fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> Result<PathBuf, &'static str> {
        which_in(path, Some(f.paths.clone()), f.tempdir.path())
    }

    #[test]
    #[cfg(unix)]
    fn it_works() {
        use std::process::Command;
        let result = which("rustc");
        assert!(result.is_ok());

        let which_result = Command::new("which")
            .arg("rustc")
            .output();

        assert_eq!(String::from(result.unwrap().to_str().unwrap()),
                   String::from_utf8(which_result.unwrap().stdout).unwrap().trim());
    }

    #[test]
    fn test_which() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &BIN_NAME).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_extension() {
        let f = TestFixture::new();
        let b = Path::new(&BIN_NAME).with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_not_found() {
        let f = TestFixture::new();
        assert!(_which(&f, "a").is_err());
    }

    #[test]
    fn test_which_second() {
        let f = TestFixture::new();
        let b = f.mk_bin("b/another").unwrap();
        assert_eq!(_which(&f, "another").unwrap().canonicalize().unwrap(), b);
    }

    #[test]
    fn test_which_absolute() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &f.bins[1]).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_absolute_path_case() {
        // Test that an absolute path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let p = f.bins[1].with_extension("EXE");
        assert_eq!(_which(&f, &p).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_absolute_extension() {
        let f = TestFixture::new();
        // Don't append EXE_EXTENSION here.
        let b = f.bins[1].parent().unwrap().join(&BIN_NAME);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_extension() {
        // test_which_relative tests a relative path without an extension,
        // so test a relative path with an extension here.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_relative_extension_case() {
        // Test that a relative path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension("EXE");
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_leading_dot() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "./b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "another").is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_absolute_non_executable() {
        // Shouldn't return non-executable files, even if given an absolute path.
        let f = TestFixture::new();
        let b = f.touch("b/another").unwrap();
        assert!(_which(&f, &b).is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_relative_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "b/another").is_err());
    }
}
<commit_msg>use ood to refactor main code<commit_after>//! which
//!
//! A Rust equivalent of Unix command `which(1)`.
//! # Example:
//!
//! To find which rustc executable binary is using:
//!
//! ``` norun
//! use which::which;
//!
//! let result = which::which("rustc").unwrap();
//! assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
//!
//! ```

extern crate libc;
#[cfg(test)]
extern crate tempdir;

use std::ascii::AsciiExt;
use std::path::{Path,PathBuf};
use std::{env, fs};
#[cfg(unix)]
use std::ffi::CString;
use std::ffi::OsStr;
#[cfg(unix)]
use std::os::unix::ffi::OsStrExt;

/// Like `Path::with_extension`, but don't replace an existing extension.
fn ensure_exe_extension<T: AsRef<Path>>(path: T) -> PathBuf {
    if env::consts::EXE_EXTENSION.is_empty() {
        // Nothing to do.
        path.as_ref().to_path_buf()
    } else {
        match path.as_ref().extension().and_then(|e| e.to_str()).map(|e| e.eq_ignore_ascii_case(env::consts::EXE_EXTENSION)) {
            // Already has the right extension.
            Some(true) => path.as_ref().to_path_buf(),
            _ => {
                // Append the extension.
                let mut s = path.as_ref().to_path_buf().into_os_string();
                s.push(".");
                s.push(env::consts::EXE_EXTENSION);
                PathBuf::from(s)
            }
        }
    }
}

/// Find a exectable binary's path by name.
///
/// If given an absolute path, returns it if the file exists and is executable.
///
/// If given a relative path, returns an absolute path to the file if
/// it exists and is executable.
///
/// If given a string without path separators, looks for a file named
/// `binary_name` at each directory in `$PATH` and if it finds an executable
/// file there, returns it.
///
/// # Example
///
/// ``` norun
/// use which::which;
/// use std::path::PathBuf;
///
/// let result = which::which("rustc").unwrap();
/// assert_eq!(result, PathBuf::from("/usr/bin/rustc"));
///
/// ```
pub fn which<T: AsRef<OsStr>>(binary_name: T)
             -> Result<PathBuf, &'static str> {
    env::current_dir()
        .or_else(|_| Err("Couldn't get current directory"))
        .and_then(|cwd| which_in(binary_name, env::var_os("PATH"), &cwd))
}

/// Find `binary_name` in the path list `paths`, using `cwd` to resolve relative paths.
pub fn which_in<T, U, V>(binary_name: T, paths: Option<U>, cwd: V)
             -> Result<PathBuf, &'static str>
                where T: AsRef<OsStr>,
                      U: AsRef<OsStr>,
                      V: AsRef<Path> {
    let binary_checker = CompositeChecker::new()
        .add_checker(Box::new(ExistedChecker::new()))
        .add_checker(Box::new(ExecutableChecker::new()));

    let finder = Finder::new();

    finder.find(binary_name, paths, cwd, &binary_checker)
}

struct Finder;

impl Finder {
    fn new() -> Finder {
        Finder
    }

    fn find<T, U, V>(&self, binary_name: T, paths: Option<U>, cwd: V,
                     binary_checker: &Checker)
                     -> Result<PathBuf, &'static str>
        where T: AsRef<OsStr>,
              U: AsRef<OsStr>,
              V: AsRef<Path> {

        let path = ensure_exe_extension(binary_name.as_ref());

        // Does it have a path separator?
        if path.components().count() > 1 {
            if path.is_absolute() {
                if binary_checker.is_valid(&path) {
                    // Already fine.
                    Ok(path)
                } else {
                    // Absolute path but it's not usable.
                    Err("Bad absolute path")
                }
            } else {
                // Try to make it absolute.
                let mut new_path = PathBuf::from(cwd.as_ref());
                new_path.push(path);
                let new_path = ensure_exe_extension(new_path);
                if binary_checker.is_valid(&new_path) {
                    Ok(new_path)
                } else {
                    // File doesn't exist or isn't executable.
                    Err("Bad relative path")
                }
            }
        } else {
            // No separator, look it up in `paths`.
            paths.and_then(
                |paths|
                env::split_paths(paths.as_ref())
                    .map(|p| ensure_exe_extension(p.join(binary_name.as_ref())))
                    .skip_while(|p| !(binary_checker.is_valid(&p)))
                    .next())
                .ok_or("Cannot find binary path")
        }
    }
}

trait Checker {
    fn is_valid(&self, path: &Path) -> bool;
}

struct ExecutableChecker;

impl ExecutableChecker {
    fn new() -> ExecutableChecker {
        ExecutableChecker
    }
}

impl Checker for ExecutableChecker {
    #[cfg(unix)]
    fn is_valid(&self, path: &Path) -> bool {
        CString::new(path.as_os_str().as_bytes())
            .and_then(|c| {
                Ok(unsafe { libc::access(c.as_ptr(), libc::X_OK) == 0 })
            })
            .unwrap_or(false)
    }

    #[cfg(not(unix))]
    fn is_valid(&self, _path: &Path) -> bool { true }
}

struct ExistedChecker;

impl ExistedChecker {
    fn new() -> ExistedChecker {
        ExistedChecker
    }
}

impl Checker for ExistedChecker {
    fn is_valid(&self, path: &Path) -> bool {
        fs::metadata(path).map(|metadata|{
            metadata.is_file()
        }).unwrap_or(false)
    }
}

struct CompositeChecker {
    checkers: Vec<Box<Checker>>
}

impl CompositeChecker {
    fn new() -> CompositeChecker {
        CompositeChecker {
            checkers: Vec::new()
        }
    }

    fn add_checker(mut self, checker: Box<Checker>) -> CompositeChecker {
        self.checkers.push(checker);
        self
    }
}

impl Checker for CompositeChecker {
    fn is_valid(&self, path: &Path) -> bool {
        self.checkers.iter()
            .all(|checker| checker.is_valid(path))
    }
}

#[test]
fn test_exe_extension() {
    let expected = PathBuf::from("foo").with_extension(env::consts::EXE_EXTENSION);
    assert_eq!(expected, ensure_exe_extension(PathBuf::from("foo")));
    let p = expected.clone();
    assert_eq!(expected, ensure_exe_extension(p));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension() {
    assert_eq!(PathBuf::from("foo.bar.exe"),
               ensure_exe_extension("foo.bar"));
}

#[test]
#[cfg(windows)]
fn test_exe_extension_existing_extension_uppercase() {
    assert_eq!(PathBuf::from("foo.EXE"),
               ensure_exe_extension("foo.EXE"));
}

#[cfg(test)]
mod test {
    use super::*;

    use std::env;
    use std::ffi::{OsStr,OsString};
    use std::fs;
    use std::io;
    use std::path::{Path,PathBuf};
    use tempdir::TempDir;

    struct TestFixture {
        /// Temp directory.
        pub tempdir: TempDir,
        /// $PATH
        pub paths: OsString,
        /// Binaries created in $PATH
        pub bins: Vec<PathBuf>,
    }

    const SUBDIRS: &'static [&'static str] = &["a", "b", "c"];
    const BIN_NAME: &'static str = "bin";

    #[cfg(unix)]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        use libc;
        use std::os::unix::fs::OpenOptionsExt;
        let bin = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::OpenOptions::new()
            .write(true)
            .create(true)
            .mode(0o666 | (libc::S_IXUSR as u32))
            .open(&bin)
            .and_then(|_f| bin.canonicalize())
    }

    fn touch(dir: &Path, path: &str) -> io::Result<PathBuf> {
        let b = dir.join(path).with_extension(env::consts::EXE_EXTENSION);
        fs::File::create(&b)
            .and_then(|_f| b.canonicalize())
    }

    #[cfg(not(unix))]
    fn mk_bin(dir: &Path, path: &str) -> io::Result<PathBuf> {
        touch(dir, path)
    }

    impl TestFixture {
        pub fn new() -> TestFixture {
            let tempdir = TempDir::new("which_tests").unwrap();
            let mut builder = fs::DirBuilder::new();
            builder.recursive(true);
            let mut paths = vec!();
            let mut bins = vec!();
            for d in SUBDIRS.iter() {
                let p = tempdir.path().join(d);
                builder.create(&p).unwrap();
                bins.push(mk_bin(&p, &BIN_NAME).unwrap());
                paths.push(p);
            }
            TestFixture {
                tempdir: tempdir,
                paths: env::join_paths(paths).unwrap(),
                bins: bins,
            }
        }

        #[allow(dead_code)]
        pub fn touch(&self, path: &str) -> io::Result<PathBuf> {
            touch(self.tempdir.path(), &path)
        }

        pub fn mk_bin(&self, path: &str) -> io::Result<PathBuf> {
            mk_bin(self.tempdir.path(), &path)
        }
    }

    fn _which<T: AsRef<OsStr>>(f: &TestFixture, path: T) -> Result<PathBuf, &'static str> {
        which_in(path, Some(f.paths.clone()), f.tempdir.path())
    }

    #[test]
    #[cfg(unix)]
    fn it_works() {
        use std::process::Command;
        let result = which("rustc");
        assert!(result.is_ok());

        let which_result = Command::new("which")
            .arg("rustc")
            .output();

        assert_eq!(String::from(result.unwrap().to_str().unwrap()),
                   String::from_utf8(which_result.unwrap().stdout).unwrap().trim());
    }

    #[test]
    fn test_which() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &BIN_NAME).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_extension() {
        let f = TestFixture::new();
        let b = Path::new(&BIN_NAME).with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[0])
    }

    #[test]
    fn test_which_not_found() {
        let f = TestFixture::new();
        assert!(_which(&f, "a").is_err());
    }

    #[test]
    fn test_which_second() {
        let f = TestFixture::new();
        let b = f.mk_bin("b/another").unwrap();
        assert_eq!(_which(&f, "another").unwrap().canonicalize().unwrap(), b);
    }

    #[test]
    fn test_which_absolute() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, &f.bins[1]).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_absolute_path_case() {
        // Test that an absolute path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let p = f.bins[1].with_extension("EXE");
        assert_eq!(_which(&f, &p).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_absolute_extension() {
        let f = TestFixture::new();
        // Don't append EXE_EXTENSION here.
        let b = f.bins[1].parent().unwrap().join(&BIN_NAME);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_extension() {
        // test_which_relative tests a relative path without an extension,
        // so test a relative path with an extension here.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension(env::consts::EXE_EXTENSION);
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(windows)]
    fn test_which_relative_extension_case() {
        // Test that a relative path with an uppercase extension
        // is accepted.
        let f = TestFixture::new();
        let b = Path::new("b/bin").with_extension("EXE");
        assert_eq!(_which(&f, &b).unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    fn test_which_relative_leading_dot() {
        let f = TestFixture::new();
        assert_eq!(_which(&f, "./b/bin").unwrap().canonicalize().unwrap(),
                   f.bins[1].canonicalize().unwrap());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "another").is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_absolute_non_executable() {
        // Shouldn't return non-executable files, even if given an absolute path.
        let f = TestFixture::new();
        let b = f.touch("b/another").unwrap();
        assert!(_which(&f, &b).is_err());
    }

    #[test]
    #[cfg(unix)]
    fn test_which_relative_non_executable() {
        // Shouldn't return non-executable files.
        let f = TestFixture::new();
        f.touch("b/another").unwrap();
        assert!(_which(&f, "b/another").is_err());
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate "mpfr-sys" as mpfr_sys;

use std::mem;
use std::ptr;
use std::borrow::ToOwned;
use std::str;
use std::ffi;

use mpfr_sys::*;

pub use update_big_float::UpdateBigFloat;
pub use from_big_float::FromBigFloat;
pub use builder::{BigFloatBuilder, BigFloatBuilderWithPrec};
pub use format::FormatOptions;
pub use rounding_mode::{RoundingMode, global_rounding_mode};

mod util;
mod update_big_float;
mod from_big_float;
mod builder;
mod rounding_mode;

pub mod format;

pub mod traits {
    pub use UpdateBigFloat;
    pub use FromBigFloat;
}

#[derive(Copy)]
pub enum Sign {
    Negative,
    Positive
}

#[inline]
pub fn set_default_prec(precision: uint) {
    unsafe {
        mpfr_set_default_prec(precision as mpfr_prec_t);
    }
}

#[inline]
pub fn get_default_prec() -> uint {
    unsafe {
        mpfr_get_default_prec() as uint
    }
}

pub struct BigFloat {
    value: __mpfr_struct
}

impl Drop for BigFloat {
    fn drop(&mut self) {
        unsafe { mpfr_clear(&mut self.value) }
    }
}

impl Clone for BigFloat {
    fn clone(&self) -> BigFloat {
        let mut new_value = unsafe { mem::uninitialized() };
        unsafe {
            let prec = mpfr_get_prec(&self.value);
            mpfr_init2(&mut new_value, prec);
            // rounding mode does not matter here
            mpfr_set(&mut new_value, &self.value, MPFR_RNDN);
        }
        BigFloat { value: new_value }
    }
}

macro_rules! generate_predicates {
    ($t:ty, $($(#[$attr:meta])* fn $method:ident -> $mpfr:ident),+) => (
        impl $t {
        $(
            $(#[$attr])*
            pub fn $method(&self) -> bool {
                unsafe {
                    $mpfr(&self.value) != 0
                }
            }
        )+
        }
    )
}

impl BigFloat {
    #[inline]
    pub fn new() -> BigFloatBuilder { BigFloatBuilder }

    pub fn fresh() -> BigFloat {
        BigFloat {
            value: unsafe {
                let mut value = mem::uninitialized();
                mpfr_init(&mut value);
                value
            }
        }
    }

    pub fn fresh_with_prec(precision: uint) -> BigFloat {
        BigFloat {
            value: unsafe {
                let mut value = mem::uninitialized();
                mpfr_init2(&mut value, precision as mpfr_prec_t);
                value
            }
        }
    }

    #[inline]
    pub fn set_to<T: UpdateBigFloat>(&mut self, value: T) {
        value.update_big_float(self);
    }

    #[inline]
    pub fn get<T: FromBigFloat>(&self) -> T::Target {
        FromBigFloat::from_big_float(self, None::<T>)
    }

    #[inline]
    pub fn set_to_nan(&mut self) {
        unsafe {
            mpfr_set_nan(&mut self.value);
        }
    }

    #[inline]
    pub fn set_to_inf(&mut self, sign: Sign) {
        unsafe {
            mpfr_set_inf(&mut self.value, match sign {
                Sign::Negative => -1,
                Sign::Positive =>  1
            });
        }
    }

    #[inline]
    pub fn set_to_zero(&mut self, sign: Sign) {
        unsafe {
            mpfr_set_inf(&mut self.value, match sign {
                Sign::Negative => -1,
                Sign::Positive =>  1
            });
        }
    }

    #[inline]
    pub fn swap(&mut self, other: &mut BigFloat) {
        unsafe {
             mpfr_swap(&mut self.value, &mut other.value);
        }
    }

    pub fn prec(&self) -> uint {
        unsafe {
            mpfr_get_prec(&self.value) as uint
        }
    }

    pub fn set_prec_clear(&mut self, precision: uint) {
        unsafe {
            mpfr_set_prec(&mut self.value, precision as mpfr_prec_t);
        }
    }

    pub fn set_prec_round(&mut self, precision: uint) {
        unsafe {
            mpfr_prec_round(&mut self.value,
                            precision as mpfr_prec_t,
                            global_rounding_mode::get().to_rnd_t());
        }
    }

    pub fn to_string_in_base(&self, base: uint) -> (String, u64) {
        unsafe {
            let mut exp: mpfr_exp_t = 0;
            // We're going to ask MPFR to allocate the string itself, so the maximum
            // possible precision is used
            let s = mpfr_get_str(
                ptr::null_mut(),
                &mut exp, base as libc::c_int,
                0, &self.value,
                global_rounding_mode::get().to_rnd_t()
            );

            if s.is_null() {
                panic!("Couldn't convert big float to a string");
            }

            let r = str::from_utf8(ffi::c_str_to_bytes(&(s as *const _))).unwrap().to_owned();

            mpfr_free_str(s);

            (r, exp as u64)
        }
    }
}

generate_predicates! { BigFloat,
    #[doc="Checks that this number is NaN."]
    fn is_nan     -> mpfr_nan_p,
    #[doc="Checks that this number is an infinity (positive or negative)."]
    fn is_inf     -> mpfr_inf_p,
    #[doc="Checks that this number is an ordinary number (neither NaN nor an infinity)."]
    fn is_number  -> mpfr_number_p,
    #[doc="Checks that this number is zero."]
    fn is_zero    -> mpfr_zero_p,
    #[doc="Checks that this number is a regular number (neither NaN, nor an infinity nor zero)."]
    fn is_regular -> mpfr_regular_p
}
<commit_msg>Added basic Add implementation<commit_after>extern crate libc;
extern crate "mpfr-sys" as mpfr_sys;

use std::mem;
use std::ptr;
use std::borrow::ToOwned;
use std::str;
use std::ffi;
use std::ops::Add;

use libc::c_double;

use mpfr_sys::*;

pub use update_big_float::UpdateBigFloat;
pub use from_big_float::FromBigFloat;
pub use builder::{BigFloatBuilder, BigFloatBuilderWithPrec};
pub use format::FormatOptions;
pub use rounding_mode::{RoundingMode, global_rounding_mode};

mod util;
mod update_big_float;
mod from_big_float;
mod builder;
mod rounding_mode;

pub mod format;

pub mod traits {
    pub use UpdateBigFloat;
    pub use FromBigFloat;
}

#[derive(Copy)]
pub enum Sign {
    Negative,
    Positive
}

#[inline]
pub fn set_default_prec(precision: uint) {
    unsafe {
        mpfr_set_default_prec(precision as mpfr_prec_t);
    }
}

#[inline]
pub fn get_default_prec() -> uint {
    unsafe {
        mpfr_get_default_prec() as uint
    }
}

pub struct BigFloat {
    value: __mpfr_struct
}

impl Drop for BigFloat {
    fn drop(&mut self) {
        unsafe { mpfr_clear(&mut self.value) }
    }
}

impl Clone for BigFloat {
    fn clone(&self) -> BigFloat {
        let mut new_value = self.clone_unset();
        unsafe {
            // rounding mode does not matter here
            mpfr_set(&mut new_value.value, &self.value, MPFR_RNDN);
        }
        new_value
    }
}

macro_rules! generate_predicates {
    ($t:ty, $($(#[$attr:meta])* fn $method:ident -> $mpfr:ident),+) => (
        impl $t {
        $(
            $(#[$attr])*
            pub fn $method(&self) -> bool {
                unsafe {
                    $mpfr(&self.value) != 0
                }
            }
        )+
        }
    )
}

impl BigFloat {
    #[inline]
    pub fn new() -> BigFloatBuilder { BigFloatBuilder }

    pub fn fresh() -> BigFloat {
        BigFloat {
            value: unsafe {
                let mut value = mem::uninitialized();
                mpfr_init(&mut value);
                value
            }
        }
    }

    pub fn fresh_with_prec(precision: uint) -> BigFloat {
        BigFloat {
            value: unsafe {
                let mut value = mem::uninitialized();
                mpfr_init2(&mut value, precision as mpfr_prec_t);
                value
            }
        }
    }

    #[inline]
    pub fn set_to<T: UpdateBigFloat>(&mut self, value: T) {
        value.update_big_float(self);
    }

    #[inline]
    pub fn get<T: FromBigFloat>(&self) -> T::Target {
        FromBigFloat::from_big_float(self, None::<T>)
    }

    #[inline]
    pub fn set_to_nan(&mut self) {
        unsafe {
            mpfr_set_nan(&mut self.value);
        }
    }

    #[inline]
    pub fn set_to_inf(&mut self, sign: Sign) {
        unsafe {
            mpfr_set_inf(&mut self.value, match sign {
                Sign::Negative => -1,
                Sign::Positive =>  1
            });
        }
    }

    #[inline]
    pub fn set_to_zero(&mut self, sign: Sign) {
        unsafe {
            mpfr_set_inf(&mut self.value, match sign {
                Sign::Negative => -1,
                Sign::Positive =>  1
            });
        }
    }

    pub fn clone_unset(&self) -> BigFloat {
        let mut new_value = unsafe { mem::uninitialized() };
        unsafe {
            let prec = mpfr_get_prec(&self.value);
            mpfr_init2(&mut new_value, prec);
        }
        BigFloat { value: new_value }
    }

    #[inline]
    pub fn swap(&mut self, other: &mut BigFloat) {
        unsafe {
             mpfr_swap(&mut self.value, &mut other.value);
        }
    }

    pub fn prec(&self) -> uint {
        unsafe {
            mpfr_get_prec(&self.value) as uint
        }
    }

    pub fn set_prec_clear(&mut self, precision: uint) {
        unsafe {
            mpfr_set_prec(&mut self.value, precision as mpfr_prec_t);
        }
    }

    pub fn set_prec_round(&mut self, precision: uint) {
        unsafe {
            mpfr_prec_round(&mut self.value,
                            precision as mpfr_prec_t,
                            global_rounding_mode::get().to_rnd_t());
        }
    }

    pub fn to_string_in_base(&self, base: uint) -> (String, u64) {
        unsafe {
            let mut exp: mpfr_exp_t = 0;
            // We're going to ask MPFR to allocate the string itself, so the maximum
            // possible precision is used
            let s = mpfr_get_str(
                ptr::null_mut(),
                &mut exp, base as libc::c_int,
                0, &self.value,
                global_rounding_mode::get().to_rnd_t()
            );

            if s.is_null() {
                panic!("Couldn't convert big float to a string");
            }

            let r = str::from_utf8(ffi::c_str_to_bytes(&(s as *const _))).unwrap().to_owned();

            mpfr_free_str(s);

            (r, exp as u64)
        }
    }
}

generate_predicates! { BigFloat,
    #[doc="Checks that this number is NaN."]
    fn is_nan     -> mpfr_nan_p,
    #[doc="Checks that this number is an infinity (positive or negative)."]
    fn is_inf     -> mpfr_inf_p,
    #[doc="Checks that this number is an ordinary number (neither NaN nor an infinity)."]
    fn is_number  -> mpfr_number_p,
    #[doc="Checks that this number is zero."]
    fn is_zero    -> mpfr_zero_p,
    #[doc="Checks that this number is a regular number (neither NaN, nor an infinity nor zero)."]
    fn is_regular -> mpfr_regular_p
}

// Implementation of arithmetic operations for BigFloat.
// Basically, all operations are implemented both for BigFloat and &BigFloat as RHS and LHS
// (4 variants total: value + value, value + reference, reference + value, reference + reference).
//
// If one of the operands is a value, then it is used to hold the result. If both of the
// operands are values, LHS gets a priority. If both of the operands are references,
// the LHS is cloned and used to hold the result.
//
// The order is important if participating values have different precisions.
//
// If one of the operands is of primitive type, then either the BigFloat operand will
// be reused for the result or it will be cloned.

// x + &y
impl<'a> Add<&'a BigFloat> for BigFloat {
    type Output = BigFloat;

    fn add(mut self, rhs: &'a BigFloat) -> BigFloat {
        unsafe {
            mpfr_add(
                &mut self.value,
                &self.value, &rhs.value,
                global_rounding_mode::get().to_rnd_t()
            );
        }
        self
    }
}

// x + y
impl Add<BigFloat> for BigFloat {
    type Output = BigFloat;

    #[inline]
    fn add(self, rhs: BigFloat) -> BigFloat {
        self + &rhs
    }
}

// &x + y
impl<'r> Add<BigFloat> for &'r BigFloat {
    type Output = BigFloat;

    #[inline]
    fn add(self, rhs: BigFloat) -> BigFloat {
        rhs + self
    }
}

// &x + &y
impl<'a, 'r> Add<&'a BigFloat> for &'r BigFloat {
    type Output = BigFloat;

    #[inline]
    fn add(self, rhs: &'a BigFloat) -> BigFloat {
        let c = self.clone_unset();
        c + rhs
    }
}

// x + f
impl Add<f64> for BigFloat {
    type Output = BigFloat;

    fn add(mut self, rhs: f64) -> BigFloat {
        unsafe {
            mpfr_add_d(
                &mut self.value,
                &self.value, rhs as c_double,
                global_rounding_mode::get().to_rnd_t()
            );
        }
        self
    }
}

// &x + f
impl<'r> Add<f64> for &'r BigFloat {
    type Output = BigFloat;

    #[inline]
    fn add(self, rhs: f64) -> BigFloat {
        let r = self.clone();
        r + rhs
    }
}

/*
// f + x
impl Add<BigFloat> for f64 {
    type Output = BigFloat;

    #[inline]
    fn add(self, rhs: BigFloat) -> BigFloat {
        rhs + self
    }
}

// f + &x
impl<'r> Add<&'r BigFloat> for f64 {
    type Output = BigFloat;

    #[inline]
    fn add(self, rhs: &'r BigFloat) -> BigFloat {
        rhs + self
    }
}
*/
<|endoftext|>


<commit_before>//! Crate retry provides functionality for retrying an operation until its return value satisfies a
//! specific condition.
//!
//! # Usage
//!
//! Create a retryable operation by passing two mutable closure references to `Retry::new`. The
//! first argument, `value_fn`, will be executed to produce a value. The second argument,
//! `condition_fn`, takes the value produced by `value_fn` and returns a boolean indicating whether
//! or not some desired condition is true. Call `execute` on the returned `Retry` object to begin
//! executing the operation, ultimately returning a `Result` containing the final value or an
//! error.
//!
//! By default, the operation will be retried an infinite number of times with no delay between
//! tries. To change either of these values, you may call the following two methods on the `Retry`
//! object:
//!
//! 1. `try`: The maximum number of tries to make.  If the operation reaches this number of tries
//!    without passsing the condition, an error will be returned.
//! 2. `wait` The number of milliseconds to wait after each unsuccessful try.
//!
//! # Failures
//!
//! Executing a `Retry` will fail when:
//!
//! 1. The operation reaches the maximum number of tries without success.
//! 2. A value of 0 is supplied to `try`. It must be at least 1.
//!
//! # Examples
//!
//! Imagine an HTTP API with an endpoint that returns 204 No Content while a job is processing, and
//! eventually 200 OK when the job has completed. Retrying until the job is finished would be
//! written:
//!
//! ```
//! # use retry::Retry;
//! # struct Client;
//! # impl Client {
//! #     fn query_job_status(&self) -> Response {
//! #         Response {
//! #             code: 200,
//! #             body: "success",
//! #         }
//! #     }
//! # }
//! # struct Response {
//! #     code: u16,
//! #     body: &'static str,
//! # }
//! # let api_client = Client;
//! match Retry::new(
//!     &mut || api_client.query_job_status(),
//!     &mut |response| response.code == 200
//! ).try(10).wait(500).execute() {
//!     Ok(response) => println!("Job completed with result: {}", response.body),
//!     Err(error) => println!("Job completion could not be verified: {}", error),
//! }
//! ```
//!
//! This retries the API call up to 10 times, waiting 500 milliseconds after each unsuccessful
//! attempt.

use std::error::Error;
use std::fmt::{Display,Formatter};
use std::fmt::Error as FmtError;
use std::thread::sleep_ms;

/// Builder object for a retryable operation.
#[derive(Debug)]
pub struct Retry<'a, F: FnMut() -> R + 'a, G: FnMut(&R) -> bool + 'a, R> {
    condition_fn: &'a mut G,
    tries: Option<u32>,
    value_fn: &'a mut F,
    wait: u32,
}

impl<'a, F: FnMut() -> R, G: FnMut(&R) -> bool, R> Retry<'a, F, G, R> {
    /// Build a new `Retry` object.
    pub fn new(
        value_fn: &'a mut F,
        condition_fn: &'a mut G
    ) -> Retry<'a, F, G, R> where F: FnMut() -> R, G: FnMut(&R) -> bool {
        Retry {
            condition_fn: condition_fn,
            tries: None,
            value_fn: value_fn,
            wait: 0,
        }
    }

    /// Begin executing the retryable operation.
    pub fn execute(self) -> Result<R, RetryError> {
        if self.tries.is_some() && self.tries.unwrap() == 0 {
            return Err(RetryError { message: "tries must be non-zero" });
        }

        let mut try = 0;

        loop {
            if self.tries.is_some() && self.tries.unwrap() == try {
                return Err(RetryError { message: "reached last try without condition match" })
            }

            let value = (self.value_fn)();

            if (self.condition_fn)(&value) {
                return Ok(value);
            }

            sleep_ms(self.wait);
            try += 1;
        }
    }

    /// Set a maximum number of tries to make before failing.
    pub fn try(mut self, tries: u32) -> Retry<'a, F, G, R> {
        self.tries = Some(tries);

        self
    }

    /// Set the number of milliseconds to wait after an unsuccesful try before trying again.
    pub fn wait(mut self, wait: u32) -> Retry<'a, F, G, R> {
        self.wait = wait;

        self
    }
}

/// An error indicating that a retry call failed.
#[derive(Debug)]
pub struct RetryError {
    message: &'static str
}

impl Display for RetryError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.message)
    }
}

impl Error for RetryError {
    fn description(&self) -> &str {
        self.message
    }
}

#[cfg(test)]
mod tests {
    use super::Retry;

    #[test]
    fn succeeds_without_try_count() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 5
        ).execute().unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_on_first_try() {
        let value = Retry::new(&mut || 1, &mut |value| *value == 1).try(1).execute().ok().unwrap();

        assert_eq!(value, 1);
    }

    #[test]
    fn requires_non_zero_tries() {
        let error = Retry::new(&mut || 1, &mut |value| *value == 1).try(0).execute().err().unwrap();

        assert_eq!(error.message, "tries must be non-zero");
    }

    #[test]
    fn succeeds_on_subsequent_try() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).try(2).execute().ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let error = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).try(1).execute().err().unwrap();

        assert_eq!(error.message, "reached last try without condition match");
    }

    #[test]
    fn sets_custom_wait_time() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).wait(1).execute().ok().unwrap();

        assert_eq!(value, 2);
    }
}
<commit_msg>Add back retry function.<commit_after>//! Crate retry provides functionality for retrying an operation until its return value satisfies a
//! specific condition.
//!
//! # Usage
//!
//! Create a retryable operation by passing two mutable closure references to `Retry::new`. The
//! first argument, `value_fn`, will be executed to produce a value. The second argument,
//! `condition_fn`, takes the value produced by `value_fn` and returns a boolean indicating whether
//! or not some desired condition is true. Call `execute` on the returned `Retry` object to begin
//! executing the operation, ultimately returning a `Result` containing the final value or an
//! error.
//!
//! By default, the operation will be retried an infinite number of times with no delay between
//! tries. To change either of these values, you may call the following two methods on the `Retry`
//! object:
//!
//! 1. `try`: The maximum number of tries to make.  If the operation reaches this number of tries
//!    without passsing the condition, an error will be returned.
//! 2. `wait` The number of milliseconds to wait after each unsuccessful try.
//!
//! # Failures
//!
//! Executing a `Retry` will fail when:
//!
//! 1. The operation reaches the maximum number of tries without success.
//! 2. A value of 0 is supplied to `try`. It must be at least 1.
//!
//! # Examples
//!
//! Imagine an HTTP API with an endpoint that returns 204 No Content while a job is processing, and
//! eventually 200 OK when the job has completed. Retrying until the job is finished would be
//! written:
//!
//! ```
//! # use retry::Retry;
//! # struct Client;
//! # impl Client {
//! #     fn query_job_status(&self) -> Response {
//! #         Response {
//! #             code: 200,
//! #             body: "success",
//! #         }
//! #     }
//! # }
//! # struct Response {
//! #     code: u16,
//! #     body: &'static str,
//! # }
//! # let api_client = Client;
//! match Retry::new(
//!     &mut || api_client.query_job_status(),
//!     &mut |response| response.code == 200
//! ).try(10).wait(500).execute() {
//!     Ok(response) => println!("Job completed with result: {}", response.body),
//!     Err(error) => println!("Job completion could not be verified: {}", error),
//! }
//! ```
//!
//! This retries the API call up to 10 times, waiting 500 milliseconds after each unsuccessful
//! attempt.

use std::error::Error;
use std::fmt::{Display,Formatter};
use std::fmt::Error as FmtError;
use std::thread::sleep_ms;

/// Builder object for a retryable operation.
#[derive(Debug)]
pub struct Retry<'a, F: FnMut() -> R + 'a, G: FnMut(&R) -> bool + 'a, R> {
    condition_fn: &'a mut G,
    tries: Option<u32>,
    value_fn: &'a mut F,
    wait: u32,
}

impl<'a, F: FnMut() -> R, G: FnMut(&R) -> bool, R> Retry<'a, F, G, R> {
    /// Build a new `Retry` object.
    pub fn new(
        value_fn: &'a mut F,
        condition_fn: &'a mut G
    ) -> Retry<'a, F, G, R> where F: FnMut() -> R, G: FnMut(&R) -> bool {
        Retry {
            condition_fn: condition_fn,
            tries: None,
            value_fn: value_fn,
            wait: 0,
        }
    }

    /// Begin executing the retryable operation.
    pub fn execute(self) -> Result<R, RetryError> {
        if self.tries.is_some() && self.tries.unwrap() == 0 {
            return Err(RetryError { message: "tries must be non-zero" });
        }

        let mut try = 0;

        loop {
            if self.tries.is_some() && self.tries.unwrap() == try {
                return Err(RetryError { message: "reached last try without condition match" })
            }

            let value = (self.value_fn)();

            if (self.condition_fn)(&value) {
                return Ok(value);
            }

            sleep_ms(self.wait);
            try += 1;
        }
    }

    /// Set a maximum number of tries to make before failing.
    pub fn try(mut self, tries: u32) -> Retry<'a, F, G, R> {
        self.tries = Some(tries);

        self
    }

    /// Set the number of milliseconds to wait after an unsuccesful try before trying again.
    pub fn wait(mut self, wait: u32) -> Retry<'a, F, G, R> {
        self.wait = wait;

        self
    }
}

/// Invokes a function a certain number of times or until a condition is satisfied with a fixed
/// wait after each unsuccessful try.
pub fn retry<F, G, R>(
    tries: u32,
    wait: u32,
    mut value_fn: F,
    mut condition_fn: G
) -> Result<R, RetryError> where F: FnMut() -> R, G: FnMut(&R) -> bool {
    Retry::new(&mut value_fn, &mut condition_fn).try(tries).wait(wait).execute()
}

/// An error indicating that a retry call failed.
#[derive(Debug)]
pub struct RetryError {
    message: &'static str
}

impl Display for RetryError {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), FmtError> {
        write!(formatter, "{}", self.message)
    }
}

impl Error for RetryError {
    fn description(&self) -> &str {
        self.message
    }
}

#[cfg(test)]
mod tests {
    use super::{Retry, retry};

    #[test]
    fn succeeds_without_try_count() {
        let mut collection = vec![1, 2, 3, 4, 5].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 5
        ).execute().unwrap();

        assert_eq!(value, 5);
    }

    #[test]
    fn succeeds_on_first_try() {
        let value = Retry::new(&mut || 1, &mut |value| *value == 1).try(1).execute().ok().unwrap();

        assert_eq!(value, 1);
    }

    #[test]
    fn requires_non_zero_tries() {
        let error = Retry::new(&mut || 1, &mut |value| *value == 1).try(0).execute().err().unwrap();

        assert_eq!(error.message, "tries must be non-zero");
    }

    #[test]
    fn succeeds_on_subsequent_try() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).try(2).execute().ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn fails_after_last_try() {
        let mut collection = vec![1].into_iter();

        let error = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).try(1).execute().err().unwrap();

        assert_eq!(error.message, "reached last try without condition match");
    }

    #[test]
    fn sets_custom_wait_time() {
        let mut collection = vec![1, 2].into_iter();

        let value = Retry::new(
            &mut || collection.next().unwrap(),
            &mut |value| *value == 2
        ).wait(1).execute().ok().unwrap();

        assert_eq!(value, 2);
    }

    #[test]
    fn retry_function() {
        let mut collection = vec![1, 2].into_iter();

        let value = retry(2, 0, || collection.next().unwrap(), |value| *value == 2).ok().unwrap();

        assert_eq!(value, 2);
    }
}
<|endoftext|>


<commit_before>//! Lorem ipsum generator.
//!
//! This crate contains functions for generating pseudo-Latin lorem
//! ipsum placeholder text. The traditional lorem ipsum text start
//! like this:
//!
//! > Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
//! > eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
//! > enim ad minim veniam, quis nostrud exercitation ullamco laboris
//! > nisi ut aliquip ex ea commodo consequat. [...]
//!
//! This text is in the [`LOREM_IPSUM`] constant. Random text looking
//! like the above can be generated using the [`lipsum`] function.
//! This function allows you to generate as much text as desired and
//! each invocation will generate different text. This is done using a
//! [Markov chain] based on both the [`LOREM_IPSUM`] and
//! [`LIBER_PRIMUS`] texts. The latter constant holds the full text of
//! the first book of a work by Cicero, of which the lorem ipsum text
//! is a scrambled subset.
//!
//! The random looking text is generatd using a Markov chain of order
//! two, which simply means that the next word is based on the
//! previous two words in the input texts. The Markov chain can be
//! used with other input texts by creating an instance of
//! [`MarkovChain`] and calling its [`learn`] method.
//!
//! [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
//! [`LIBER_PRIMUS`]: constant.LIBER_PRIMUS.html
//! [`lipsum`]: fn.lipsum.html
//! [`MarkovChain`]: struct.MarkovChain.html
//! [`learn`]: struct.MarkovChain.html#method.learn
//! [Markov chain]: https://en.wikipedia.org/wiki/Markov_chain

extern crate rand;

#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;
use rand::Rng;

/// A bigram is simply two consecutive words.
pub type Bigram<'a> = (&'a str, &'a str);

/// Simple order two Markov chain implementation.
///
/// The [Markov chain] is a chain of order two, which means that it
/// will use the previous two words (a bigram) when predicting the
/// next word. This is normally enough to generate random text that
/// looks somewhat plausible. The implementation is based on
/// [Generating arbitrary text with Markov chains in Rust][blog post].
///
/// [Markov chain]: https://en.wikipedia.org/wiki/Markov_chain
/// [blog post]: https://blakewilliams.me/posts/generating-arbitrary-text-with-markov-chains-in-rust
#[derive(Default)]
pub struct MarkovChain<'a> {
    pub map: HashMap<Bigram<'a>, Vec<&'a str>>,
}

impl<'a> MarkovChain<'a> {
    /// Create a new Markov chain. It will use a default thread-local
    /// random number generator.
    pub fn new() -> MarkovChain<'a> {
        MarkovChain { map: HashMap::new() }
    }

    /// Add new text to the Markov chain. This can be called several
    /// times to build up the chain.
    ///
    /// # Examples
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("red green blue");
    /// assert_eq!(chain.map[&("red", "green")], vec!["blue"]);
    ///
    /// chain.learn("red green yellow");
    /// assert_eq!(chain.map[&("red", "green")], vec!["blue", "yellow"]);
    /// ```
    pub fn learn(&mut self, sentence: &'a str) {
        let words = sentence.split_whitespace().collect::<Vec<&str>>();
        for window in words.windows(3) {
            let (a, b, c) = (window[0], window[1], window[2]);
            self.map.entry((a, b)).or_insert(vec![]).push(c);
        }
    }

    /// Generate `n` words worth of lorem ipsum text. The text will
    /// start from a random point in the Markov chain.
    ///
    /// See [`generate_from`] if you want to control the starting
    /// point for the generated text.
    ///
    /// # Examples
    ///
    /// Generating the sounds of a grandfather clock:
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("Tick, Tock, Tick, Tock, Ding! Tick, Tock, Ding! Ding!");
    /// println!("{}", chain.generate(15));
    /// ```
    ///
    /// The output looks like this:
    ///
    /// > Ding! Tick, Tock, Tick, Tock, Ding! Ding! Tock, Ding! Tick,
    /// > Tock, Tick, Tock, Tick, Tock
    ///
    /// [`generate_from`]: struct.MarkovChain.html#method.generate_from
    pub fn generate(&self, n: usize) -> String {
        if self.map.is_empty() {
            // The learn method has not been called.
            return String::new();
        }

        let mut rng = rand::thread_rng();
        let keys = self.map.keys().collect::<Vec<&(&str, &str)>>();
        self.generate_from(n, **rng.choose(&keys).unwrap())
    }

    /// Generate `n` words worth of lorem ipsum text. The text will
    /// start from the given bigram.
    pub fn generate_from(&self, n: usize, from: Bigram<'a>) -> String {
        let mut rng = rand::thread_rng(); // make part of struct
        let keys = self.map.keys().collect::<Vec<&Bigram>>();
        let (mut a, mut b) = from;
        let mut sentence = String::from(a) + " " + b;

        for _ in 2..n {
            while !self.map.contains_key(&(a, b)) {
                let new_key = **rng.choose(&keys).unwrap();
                a = new_key.0;
                b = new_key.1;
            }

            let next_words = &self.map[&(a, b)];
            let c = rng.choose(next_words).unwrap();
            sentence.push(' ');
            sentence.push_str(c);
            a = b;
            b = c;
        }

        return sentence;
    }
}

/// The traditional lorem ipsum text as given in [Wikipedia]. Using
/// this text alone for a Markov chain of order two doesn't work very
/// well since each bigram (two consequtive words) is followed by just
/// one other word. In other words, the Markov chain will always
/// produce the same output and recreate the lorem ipsum text
/// precisely. However, combining it with the full text in
/// [`LIBER_PRIMUS`] works well.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Lorem_ipsum
/// [`LIBER_PRIMUS`]: constant.LIBER_PRIMUS.html
pub const LOREM_IPSUM: &'static str = include_str!("lorem-ipsum.txt");

/// The first book in Cicero's work De finibus bonorum et malorum ("On
/// the ends of good and evil"). The lorem ipsum text in
/// [`LOREM_IPSUM`] is derived from part of this text.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
pub const LIBER_PRIMUS: &'static str = include_str!("liber-primus.txt");

lazy_static! {
    /// Markov chain generating lorem ipsum text.
    static ref LOREM_IPSUM_CHAIN: MarkovChain<'static> = {
        let mut chain = MarkovChain::new();
        chain.learn(LOREM_IPSUM);
        chain.learn(LIBER_PRIMUS);
        chain
    };
}

/// Generate `n` words of lorem ipsum text. The output starts with
/// "Lorem ipsum" and continues with the standard lorem ipsum text
/// from [`LOREM_IPSUM`]. The text will become random if sufficiently
/// long output is requested.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
pub fn lipsum(n: usize) -> String {
    LOREM_IPSUM_CHAIN.generate_from(n, ("Lorem", "ipsum"))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn starts_with_lorem_ipsum() {
        assert_eq!(&lipsum(10)[..11], "Lorem ipsum");
    }

    #[test]
    fn two_words_minimum() {
        assert_eq!(lipsum(0).split_whitespace().count(), 2);
        assert_eq!(lipsum(1).split_whitespace().count(), 2);
        assert_eq!(lipsum(2).split_whitespace().count(), 2);
    }

    #[test]
    fn more_than_two_words() {
        assert_eq!(lipsum(17).split_whitespace().count(), 17);
    }

    #[test]
    fn empty_chain() {
        let chain = MarkovChain::new();
        assert_eq!(chain.generate(10), "");
    }

    #[test]
    fn generate_from() {
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz quuz");
        assert_eq!(chain.generate_from(3, ("foo", "bar")), "foo bar baz");
        assert_eq!(chain.generate_from(3, ("bar", "baz")), "bar baz quuz");
    }

    #[test]
    fn generate_from_no_panic() {
        // No panic when asked to generate a chain from a starting
        // point that doesn't exist in the chain.
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz");
        assert_eq!(chain.generate_from(3, ("xxx", "yyy")), "xxx yyy baz");
    }

    #[test]
    fn chain_map() {
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz quuz");
        let map = &chain.map;

        assert_eq!(map.len(), 2);
        assert_eq!(map[&("foo", "bar")], vec!["baz"]);
        assert_eq!(map[&("bar", "baz")], vec!["quuz"]);
    }
}
<commit_msg>generate_from: add link back to generate<commit_after>//! Lorem ipsum generator.
//!
//! This crate contains functions for generating pseudo-Latin lorem
//! ipsum placeholder text. The traditional lorem ipsum text start
//! like this:
//!
//! > Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
//! > eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
//! > enim ad minim veniam, quis nostrud exercitation ullamco laboris
//! > nisi ut aliquip ex ea commodo consequat. [...]
//!
//! This text is in the [`LOREM_IPSUM`] constant. Random text looking
//! like the above can be generated using the [`lipsum`] function.
//! This function allows you to generate as much text as desired and
//! each invocation will generate different text. This is done using a
//! [Markov chain] based on both the [`LOREM_IPSUM`] and
//! [`LIBER_PRIMUS`] texts. The latter constant holds the full text of
//! the first book of a work by Cicero, of which the lorem ipsum text
//! is a scrambled subset.
//!
//! The random looking text is generatd using a Markov chain of order
//! two, which simply means that the next word is based on the
//! previous two words in the input texts. The Markov chain can be
//! used with other input texts by creating an instance of
//! [`MarkovChain`] and calling its [`learn`] method.
//!
//! [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
//! [`LIBER_PRIMUS`]: constant.LIBER_PRIMUS.html
//! [`lipsum`]: fn.lipsum.html
//! [`MarkovChain`]: struct.MarkovChain.html
//! [`learn`]: struct.MarkovChain.html#method.learn
//! [Markov chain]: https://en.wikipedia.org/wiki/Markov_chain

extern crate rand;

#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;
use rand::Rng;

/// A bigram is simply two consecutive words.
pub type Bigram<'a> = (&'a str, &'a str);

/// Simple order two Markov chain implementation.
///
/// The [Markov chain] is a chain of order two, which means that it
/// will use the previous two words (a bigram) when predicting the
/// next word. This is normally enough to generate random text that
/// looks somewhat plausible. The implementation is based on
/// [Generating arbitrary text with Markov chains in Rust][blog post].
///
/// [Markov chain]: https://en.wikipedia.org/wiki/Markov_chain
/// [blog post]: https://blakewilliams.me/posts/generating-arbitrary-text-with-markov-chains-in-rust
#[derive(Default)]
pub struct MarkovChain<'a> {
    pub map: HashMap<Bigram<'a>, Vec<&'a str>>,
}

impl<'a> MarkovChain<'a> {
    /// Create a new Markov chain. It will use a default thread-local
    /// random number generator.
    pub fn new() -> MarkovChain<'a> {
        MarkovChain { map: HashMap::new() }
    }

    /// Add new text to the Markov chain. This can be called several
    /// times to build up the chain.
    ///
    /// # Examples
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("red green blue");
    /// assert_eq!(chain.map[&("red", "green")], vec!["blue"]);
    ///
    /// chain.learn("red green yellow");
    /// assert_eq!(chain.map[&("red", "green")], vec!["blue", "yellow"]);
    /// ```
    pub fn learn(&mut self, sentence: &'a str) {
        let words = sentence.split_whitespace().collect::<Vec<&str>>();
        for window in words.windows(3) {
            let (a, b, c) = (window[0], window[1], window[2]);
            self.map.entry((a, b)).or_insert(vec![]).push(c);
        }
    }

    /// Generate `n` words worth of lorem ipsum text. The text will
    /// start from a random point in the Markov chain.
    ///
    /// See [`generate_from`] if you want to control the starting
    /// point for the generated text.
    ///
    /// # Examples
    ///
    /// Generating the sounds of a grandfather clock:
    ///
    /// ```
    /// use lipsum::MarkovChain;
    ///
    /// let mut chain = MarkovChain::new();
    /// chain.learn("Tick, Tock, Tick, Tock, Ding! Tick, Tock, Ding! Ding!");
    /// println!("{}", chain.generate(15));
    /// ```
    ///
    /// The output looks like this:
    ///
    /// > Ding! Tick, Tock, Tick, Tock, Ding! Ding! Tock, Ding! Tick,
    /// > Tock, Tick, Tock, Tick, Tock
    ///
    /// [`generate_from`]: struct.MarkovChain.html#method.generate_from
    pub fn generate(&self, n: usize) -> String {
        if self.map.is_empty() {
            // The learn method has not been called.
            return String::new();
        }

        let mut rng = rand::thread_rng();
        let keys = self.map.keys().collect::<Vec<&(&str, &str)>>();
        self.generate_from(n, **rng.choose(&keys).unwrap())
    }

    /// Generate `n` words worth of lorem ipsum text. The text will
    /// start from the given bigram.
    ///
    /// Use [`generate`] if the starting point is not important.
    ///
    /// [`generate`]: struct.MarkovChain.html#method.generate
    pub fn generate_from(&self, n: usize, from: Bigram<'a>) -> String {
        let mut rng = rand::thread_rng(); // make part of struct
        let keys = self.map.keys().collect::<Vec<&Bigram>>();
        let (mut a, mut b) = from;
        let mut sentence = String::from(a) + " " + b;

        for _ in 2..n {
            while !self.map.contains_key(&(a, b)) {
                let new_key = **rng.choose(&keys).unwrap();
                a = new_key.0;
                b = new_key.1;
            }

            let next_words = &self.map[&(a, b)];
            let c = rng.choose(next_words).unwrap();
            sentence.push(' ');
            sentence.push_str(c);
            a = b;
            b = c;
        }

        return sentence;
    }
}

/// The traditional lorem ipsum text as given in [Wikipedia]. Using
/// this text alone for a Markov chain of order two doesn't work very
/// well since each bigram (two consequtive words) is followed by just
/// one other word. In other words, the Markov chain will always
/// produce the same output and recreate the lorem ipsum text
/// precisely. However, combining it with the full text in
/// [`LIBER_PRIMUS`] works well.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Lorem_ipsum
/// [`LIBER_PRIMUS`]: constant.LIBER_PRIMUS.html
pub const LOREM_IPSUM: &'static str = include_str!("lorem-ipsum.txt");

/// The first book in Cicero's work De finibus bonorum et malorum ("On
/// the ends of good and evil"). The lorem ipsum text in
/// [`LOREM_IPSUM`] is derived from part of this text.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
pub const LIBER_PRIMUS: &'static str = include_str!("liber-primus.txt");

lazy_static! {
    /// Markov chain generating lorem ipsum text.
    static ref LOREM_IPSUM_CHAIN: MarkovChain<'static> = {
        let mut chain = MarkovChain::new();
        chain.learn(LOREM_IPSUM);
        chain.learn(LIBER_PRIMUS);
        chain
    };
}

/// Generate `n` words of lorem ipsum text. The output starts with
/// "Lorem ipsum" and continues with the standard lorem ipsum text
/// from [`LOREM_IPSUM`]. The text will become random if sufficiently
/// long output is requested.
///
/// [`LOREM_IPSUM`]: constant.LOREM_IPSUM.html
pub fn lipsum(n: usize) -> String {
    LOREM_IPSUM_CHAIN.generate_from(n, ("Lorem", "ipsum"))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn starts_with_lorem_ipsum() {
        assert_eq!(&lipsum(10)[..11], "Lorem ipsum");
    }

    #[test]
    fn two_words_minimum() {
        assert_eq!(lipsum(0).split_whitespace().count(), 2);
        assert_eq!(lipsum(1).split_whitespace().count(), 2);
        assert_eq!(lipsum(2).split_whitespace().count(), 2);
    }

    #[test]
    fn more_than_two_words() {
        assert_eq!(lipsum(17).split_whitespace().count(), 17);
    }

    #[test]
    fn empty_chain() {
        let chain = MarkovChain::new();
        assert_eq!(chain.generate(10), "");
    }

    #[test]
    fn generate_from() {
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz quuz");
        assert_eq!(chain.generate_from(3, ("foo", "bar")), "foo bar baz");
        assert_eq!(chain.generate_from(3, ("bar", "baz")), "bar baz quuz");
    }

    #[test]
    fn generate_from_no_panic() {
        // No panic when asked to generate a chain from a starting
        // point that doesn't exist in the chain.
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz");
        assert_eq!(chain.generate_from(3, ("xxx", "yyy")), "xxx yyy baz");
    }

    #[test]
    fn chain_map() {
        let mut chain = MarkovChain::new();
        chain.learn("foo bar baz quuz");
        let map = &chain.map;

        assert_eq!(map.len(), 2);
        assert_eq!(map[&("foo", "bar")], vec!["baz"]);
        assert_eq!(map[&("bar", "baz")], vec!["quuz"]);
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]

//! Strided slices.
//!
//! This library provides two types `Strided` and `MutStrided` as
//! generalised forms of `&[T]` and `&mut [T]` respectively, where the
//! elements are regularly spaced in memory, but not necessarily
//! immediately adjacently.
//!
//! For example, given an underlying array `[1, 2, 3, 4, 5]`, the
//! elements `[1, 3, 5]` are a strided slice with stride 2, and
//! `[1, 4]` has stride 3. Any slice can be regarded as a strided slice
//! with stride 1.
//!
//! This provides functionality through which one can safely and
//! efficiently manipulate every `n`th element of a slice (even a
//! mutable one) as close as possible to it being a conventional
//! slice. This releases one from worries about stride bookkeeping,
//! aliasing of `&mut` or any `unsafe` code.
//!
//! # Quick start
//!
//! The work-horse functions are `.substrides(n)` and
//! `.substrides_mut(n)`, which return an iterator across a series of
//! `n` new strided slices (shared and mutable, respectively), each of
//! which points to every `n`th element, and each of which starts at
//! the next successive offset. For example, the following has `n =
//! 3`.
//!
//! ```rust
//! use strided::MutStrided;
//!
//! let mut v = [1u8, 2, 3, 4, 5];
//! let mut all = MutStrided::new(&mut v);
//!
//! let mut substrides = all.substrides_mut(3);
//!
//! let a = substrides.next().unwrap();
//! let b = substrides.next().unwrap();
//! let c = substrides.next().unwrap();
//! assert!(substrides.next().is_none()); // there was exactly 3.
//!
//! assert_eq!(a, MutStrided::new(&mut [1, 4]));
//! assert_eq!(b, MutStrided::new(&mut [2, 5]));
//! assert_eq!(c, MutStrided::new(&mut [3]));
//! ```
//!
//! The common case of `n = 2` has an abbreviation `substrides2`
//! (resp. `substrides2_mut`), which takes the liberty of returns a
//! tuple rather than an iterator to make direct destructuring
//! work. Continuing with the values above, `left` and `right` point
//! to alternate elements, starting at index `0` and `1` of their
//! parent slice respectively.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (left, right) = all.substrides2_mut();
//!
//! assert_eq!(left, MutStrided::new(&mut [1, 3, 5]));
//! assert_eq!(right, MutStrided::new(&mut [2, 4]));
//! ```
//!
//! A lot of the conventional slice functionality is available, such
//! as indexing, iterators and slicing.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (mut left, right) = all.substrides2_mut();
//! assert_eq!(left[2], 5);
//! assert!(right.get(10).is_none()); // out of bounds
//!
//! left[2] += 10;
//! match left.get_mut(0) {
//!     Some(val) => *val -= 3,
//!     None => {}
//! }
//!
//! assert_eq!(right.iter().fold(0, |sum, a| sum + *a), 2 + 4);
//! for val in left.iter_mut() {
//!     *val /= 2
//! }
//! ```
//!
//! ## Ownership and `reborrow`
//!
//! `MutStrided` has a method `reborrow` which has signature
//!
//! ```rust,ignore
//! pub fn reborrow<'b>(&'b mut self) -> Strided<'b, T>
//! ```
//!
//! That is, it allows temporarily viewing a strided slices as one
//! with a shorter lifetime. This method is key because many of the
//! methods on `MutStrided` take `self` by-value and so consume
//! ownership which is unfortunate if one needs to use a strided slice
//! multiple times.
//!
//! The temporary returned by `reborrow` can be used with the
//! consuming methods, which allows the parent slice to continuing
//! being used after that temporary has disappeared. For example, all
//! of the splitting and slicing methods on `MutStrided` consume
//! ownership, and so `reborrow` is necessary there to continue using,
//! in this case, `left`.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (mut left, right) = all.substrides2_mut();
//! assert_eq!(left.reborrow().slice_mut(1, 3), MutStrided::new(&mut [3, 5]));
//! assert_eq!(left.reborrow().slice_from_mut(2), MutStrided::new(&mut [5]));
//! assert_eq!(left.reborrow().slice_to_mut(2), MutStrided::new(&mut [1, 3]));
//!
//! // no reborrow:
//! assert_eq!(right.split_at_mut(1),
//!            (MutStrided::new(&mut [2]), MutStrided::new(&mut [4])));
//! // println!("{}", right); // error: use of moved value `right`.
//! ```
//!
//! These contortions are necessary to ensure that `&mut`s cannot
//! alias, while still maintaining flexibility: leaving elements with
//! the maximum possible lifetime (i.e. that of the non-strided slices
//! which they lie in). Theoretically they are necessary with
//! `&mut []` too, but the compiler inserts implicit reborrows and so
//! one rarely needs to do them manually.
//!
//! In practice, one should only need to insert `reborrow`s if the
//! compiler complains about the use of a moved value.
//!
//! The shared `Strided` is equivalent to `&[]` and only handles `&`
//! references, making ownership transfer and `reborrow` unnecessary,
//! so all its methods act identically to those on `&[]`.
//!
//! # Example
//!
//! The [fast Fourier transform
//! (FFT)](https://en.wikipedia.org/wiki/Fast_Fourier_transform) is a
//! signal processing algorithm that performs a discrete Fourier
//! transform (DFT) of length `n` in `O(n log n)` time. A DFT breaks a
//! waveform into the sum of sines and cosines, and is an important
//! part of many other algorithms due to certain nice properties of
//! the Fourier transform.
//!
//! The first FFT algorithm was the [Cooley-Tukey
//! algorithm](https://en.wikipedia.org/wiki/Cooley-Tukey_FFT_algorithm). The
//! decimation-in-time variant works by computing the FFT of
//! equal-length subarrays of equally spaced elements and then
//! combining these together into the desired result. This sort of
//! spacing is exactly the striding provided by this library, and
//! hence this library can be used to create an FFT algorithm in a
//! very natural way.
//!
//! Below is an implementation of the radix-2 case, that is, when the
//! length `n` is a power of two, in this case, only two strided
//! subarrays are necessary: exactly the alternating ones provided by
//! `substrides2`. Note the use of `reborrow` to allow `start` and
//! `end` to be used for the recursive `fft` calls and then again
//! later in the loop.
//!
//! ```rust
//! extern crate strided;
//! extern crate num; // https://github.com/rust-lang/num
//! use std::num::{Int, Float};
//! use num::complex::{Complex, Complex64};
//! use strided::{MutStrided, Strided};
//!
//! /// Writes the forward DFT of `input` to `output`.
//! fn fft(input: Strided<Complex64>, mut output: MutStrided<Complex64>) {
//!     // check it's a power of two.
//!     assert!(input.len() == output.len() && input.len().count_ones() == 1);
//!
//!     // base case: the DFT of a single element is itself.
//!     if input.len() == 1 {
//!         output[0] = input[0];
//!         return
//!     }
//!
//!     // split the input into two arrays of alternating elements ("decimate in time")
//!     let (evens, odds) = input.substrides2();
//!     // break the output into two halves (front and back, not alternating)
//!     let (mut start, mut end) = output.split_at_mut(input.len() / 2);
//!
//!     // recursively perform two FFTs on alternating elements of the input, writing the
//!     // results into the first and second half of the output array respectively.
//!     fft(evens, start.reborrow());
//!     fft(odds, end.reborrow());
//!
//!     let two_pi: f64 = Float::two_pi();
//!     // exp(-2πi/N)
//!     let twiddle = Complex::from_polar(&1.0, &(-two_pi / input.len() as f64));
//!
//!     let mut factor = Complex::new(1., 0.);
//!
//!     // combine the subFFTs with the relations:
//!     //   X_k = E_k + exp(-2πki/N) * O_k
//!     //   X_{k+N/2} = E_k - exp(-2πki/N) * O_k
//!     for (even, odd) in start.iter_mut().zip(end.iter_mut()) {
//!         let twiddled = factor * *odd;
//!         let e = *even;
//!
//!         *even = e + twiddled;
//!         *odd = e - twiddled;
//!         factor = factor * twiddle;
//!     }
//! }
//!
//! fn main() {
//!     let a = [Complex::new(2., 0.), Complex::new(1., 0.),
//!              Complex::new(2., 0.), Complex::new(1., 0.)];
//!     let mut b = [Complex::new(0., 0.), .. 4];
//!
//!     fft(Strided::new(&a), MutStrided::new(&mut b));
//!     println!("forward: {} -> {}", a.as_slice(), b.as_slice());
//! }
//! ```
//!
//! The above definitely has complexity `O(n log n)`, but it has a
//! much larger constant factor than an optimised library like
//! [FFTW](http://www.fftw.org/). (Strictly speaking `output` does not
//! need to be a strided slice, since it is never split into
//! alternating elements.)

#[cfg(test)] extern crate test;

pub use base::{Items, MutItems};

pub use mut_::Strided as MutStrided;
pub use mut_::Substrides as MutSubstrides;

pub use imm::Strided as Strided;
pub use imm::Substrides as Substrides;

#[cfg(test)]
mod common_tests;

mod base;
mod mut_;
mod imm;

#[cfg(test)]
mod bench {
    use super::Strided;
    use test::Bencher as B;
    use test;

    const N: uint = 100;

    #[bench]
    fn iter_slice(b: &mut B) {
        let v = Vec::from_fn(N, |i| i);
        b.iter(|| {
            test::black_box(&v);
            for e in v.iter() { test::black_box(e) }
        })
    }

    #[bench]
    fn iter_step_1(b: &mut B) {
        let v = Vec::from_fn(N, |i| i);
        let s = Strided::new(&*v);
        b.iter(|| {
            test::black_box(&s);
            for e in s.iter() { test::black_box(e) }
        })
    }

    #[bench]
    fn iter_step_13(b: &mut B) {
        let v = Vec::from_fn(N * 13, |i| i);
        let s = Strided::new(&*v);
        let s = s.substrides(13).next().unwrap();
        b.iter(|| {
            test::black_box(&s);
            for e in s.iter() { test::black_box(e) }
        })
    }
}
<commit_msg>Tweak docs.<commit_after>#![feature(macro_rules)]

//! Strided slices.
//!
//! This library provides two types `Strided` and `MutStrided` as
//! generalised forms of `&[T]` and `&mut [T]` respectively, where the
//! elements are regularly spaced in memory, but not necessarily
//! immediately adjacently.
//!
//! For example, given an underlying array `[1, 2, 3, 4, 5]`, the
//! elements `[1, 3, 5]` are a strided slice with stride 2, and
//! `[1, 4]` has stride 3. Any slice can be regarded as a strided slice
//! with stride 1.
//!
//! This provides functionality through which one can safely and
//! efficiently manipulate every `n`th element of a slice (even a
//! mutable one) as close as possible to it being a conventional
//! slice. This releases one from worries about stride bookkeeping,
//! aliasing of `&mut` or any `unsafe` code.
//!
//! # Quick start
//!
//! The work-horse functions are `.substrides(n)` and
//! `.substrides_mut(n)`, which return an iterator across a series of
//! `n` new strided slices (shared and mutable, respectively), each of
//! which points to every `n`th element, and each of which starts at
//! the next successive offset. For example, the following has
//! `n = 3`.
//!
//! ```rust
//! use strided::MutStrided;
//!
//! let mut v = [1u8, 2, 3, 4, 5];
//! let mut all = MutStrided::new(&mut v);
//!
//! let mut substrides = all.substrides_mut(3);
//!
//! let a = substrides.next().unwrap();
//! let b = substrides.next().unwrap();
//! let c = substrides.next().unwrap();
//! assert!(substrides.next().is_none()); // there was exactly 3.
//!
//! assert_eq!(a, MutStrided::new(&mut [1, 4]));
//! assert_eq!(b, MutStrided::new(&mut [2, 5]));
//! assert_eq!(c, MutStrided::new(&mut [3]));
//! ```
//!
//! The common case of `n = 2` has an abbreviation `substrides2`
//! (resp. `substrides2_mut`), which takes the liberty of returns a
//! tuple rather than an iterator to make direct destructuring
//! work. Continuing with the values above, `left` and `right` point
//! to alternate elements, starting at index `0` and `1` of their
//! parent slice respectively.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (left, right) = all.substrides2_mut();
//!
//! assert_eq!(left, MutStrided::new(&mut [1, 3, 5]));
//! assert_eq!(right, MutStrided::new(&mut [2, 4]));
//! ```
//!
//! A lot of the conventional slice functionality is available, such
//! as indexing, iterators and slicing.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (mut left, right) = all.substrides2_mut();
//! assert_eq!(left[2], 5);
//! assert!(right.get(10).is_none()); // out of bounds
//!
//! left[2] += 10;
//! match left.get_mut(0) {
//!     Some(val) => *val -= 3,
//!     None => {}
//! }
//!
//! assert_eq!(right.iter().fold(0, |sum, a| sum + *a), 2 + 4);
//! for val in left.iter_mut() {
//!     *val /= 2
//! }
//! ```
//!
//! ## Ownership and `reborrow`
//!
//! `MutStrided` has a method `reborrow` which has signature
//!
//! ```rust,ignore
//! pub fn reborrow<'b>(&'b mut self) -> Strided<'b, T>
//! ```
//!
//! That is, it allows temporarily viewing a strided slices as one
//! with a shorter lifetime. This method is key because many of the
//! methods on `MutStrided` take `self` by-value and so consume
//! ownership which is unfortunate if one needs to use a strided slice
//! multiple times.
//!
//! The temporary returned by `reborrow` can be used with the
//! consuming methods, which allows the parent slice to continuing
//! being used after that temporary has disappeared. For example, all
//! of the splitting and slicing methods on `MutStrided` consume
//! ownership, and so `reborrow` is necessary there to continue using,
//! in this case, `left`.
//!
//! ```rust
//! # use strided::MutStrided;
//! # let mut v = [1u8, 2, 3, 4, 5];
//! # let mut all = MutStrided::new(&mut v);
//! let (mut left, right) = all.substrides2_mut();
//! assert_eq!(left.reborrow().slice_mut(1, 3), MutStrided::new(&mut [3, 5]));
//! assert_eq!(left.reborrow().slice_from_mut(2), MutStrided::new(&mut [5]));
//! assert_eq!(left.reborrow().slice_to_mut(2), MutStrided::new(&mut [1, 3]));
//!
//! // no reborrow:
//! assert_eq!(right.split_at_mut(1),
//!            (MutStrided::new(&mut [2]), MutStrided::new(&mut [4])));
//! // println!("{}", right); // error: use of moved value `right`.
//! ```
//!
//! These contortions are necessary to ensure that `&mut`s cannot
//! alias, while still maintaining flexibility: leaving elements with
//! the maximum possible lifetime (i.e. that of the non-strided slices
//! which they lie in). Theoretically they are necessary with
//! `&mut []` too, but the compiler inserts implicit reborrows and so
//! one rarely needs to do them manually.
//!
//! In practice, one should only need to insert `reborrow`s if the
//! compiler complains about the use of a moved value.
//!
//! The shared `Strided` is equivalent to `&[]` and only handles `&`
//! references, making ownership transfer and `reborrow` unnecessary,
//! so all its methods act identically to those on `&[]`.
//!
//! # Example
//!
//! The [fast Fourier transform
//! (FFT)](https://en.wikipedia.org/wiki/Fast_Fourier_transform) is a
//! signal processing algorithm that performs a discrete Fourier
//! transform (DFT) of length `n` in `O(n log n)` time. A DFT breaks a
//! waveform into the sum of sines and cosines, and is an important
//! part of many other algorithms due to certain nice properties of
//! the Fourier transform.
//!
//! The first FFT algorithm was the [Cooley-Tukey
//! algorithm](https://en.wikipedia.org/wiki/Cooley-Tukey_FFT_algorithm). The
//! decimation-in-time variant works by computing the FFT of
//! equal-length subarrays of equally spaced elements and then
//! combining these together into the desired result. This sort of
//! spacing is exactly the striding provided by this library, and
//! hence this library can be used to create an FFT algorithm in a
//! very natural way.
//!
//! Below is an implementation of the radix-2 case, that is, when the
//! length `n` is a power of two, in this case, only two strided
//! subarrays are necessary: exactly the alternating ones provided by
//! `substrides2`. Note the use of `reborrow` to allow `start` and
//! `end` to be used for the recursive `fft` calls and then again
//! later in the loop.
//!
//! ```rust
//! extern crate strided;
//! extern crate num; // https://github.com/rust-lang/num
//! use std::num::{Int, Float};
//! use num::complex::{Complex, Complex64};
//! use strided::{MutStrided, Strided};
//!
//! /// Writes the forward DFT of `input` to `output`.
//! fn fft(input: Strided<Complex64>, mut output: MutStrided<Complex64>) {
//!     // check it's a power of two.
//!     assert!(input.len() == output.len() && input.len().count_ones() == 1);
//!
//!     // base case: the DFT of a single element is itself.
//!     if input.len() == 1 {
//!         output[0] = input[0];
//!         return
//!     }
//!
//!     // split the input into two arrays of alternating elements ("decimate in time")
//!     let (evens, odds) = input.substrides2();
//!     // break the output into two halves (front and back, not alternating)
//!     let (mut start, mut end) = output.split_at_mut(input.len() / 2);
//!
//!     // recursively perform two FFTs on alternating elements of the input, writing the
//!     // results into the first and second half of the output array respectively.
//!     fft(evens, start.reborrow());
//!     fft(odds, end.reborrow());
//!
//!     let two_pi: f64 = Float::two_pi();
//!     // exp(-2πi/N)
//!     let twiddle = Complex::from_polar(&1.0, &(-two_pi / input.len() as f64));
//!
//!     let mut factor = Complex::new(1., 0.);
//!
//!     // combine the subFFTs with the relations:
//!     //   X_k       = E_k + exp(-2πki/N) * O_k
//!     //   X_{k+N/2} = E_k - exp(-2πki/N) * O_k
//!     for (even, odd) in start.iter_mut().zip(end.iter_mut()) {
//!         let twiddled = factor * *odd;
//!         let e = *even;
//!
//!         *even = e + twiddled;
//!         *odd = e - twiddled;
//!         factor = factor * twiddle;
//!     }
//! }
//!
//! fn main() {
//!     let a = [Complex::new(2., 0.), Complex::new(1., 0.),
//!              Complex::new(2., 0.), Complex::new(1., 0.)];
//!     let mut b = [Complex::new(0., 0.), .. 4];
//!
//!     fft(Strided::new(&a), MutStrided::new(&mut b));
//!     println!("forward: {} -> {}", a.as_slice(), b.as_slice());
//! }
//! ```
//!
//! The above definitely has complexity `O(n log n)`, but it has a
//! much larger constant factor than an optimised library like
//! [FFTW](http://www.fftw.org/). (Strictly speaking `output` does not
//! need to be a strided slice, since it is never split into
//! alternating elements.)

#[cfg(test)] extern crate test;

pub use base::{Items, MutItems};

pub use mut_::Strided as MutStrided;
pub use mut_::Substrides as MutSubstrides;

pub use imm::Strided as Strided;
pub use imm::Substrides as Substrides;

#[cfg(test)]
mod common_tests;

mod base;
mod mut_;
mod imm;

#[cfg(test)]
mod bench {
    use super::Strided;
    use test::Bencher as B;
    use test;

    const N: uint = 100;

    #[bench]
    fn iter_slice(b: &mut B) {
        let v = Vec::from_fn(N, |i| i);
        b.iter(|| {
            test::black_box(&v);
            for e in v.iter() { test::black_box(e) }
        })
    }

    #[bench]
    fn iter_step_1(b: &mut B) {
        let v = Vec::from_fn(N, |i| i);
        let s = Strided::new(&*v);
        b.iter(|| {
            test::black_box(&s);
            for e in s.iter() { test::black_box(e) }
        })
    }

    #[bench]
    fn iter_step_13(b: &mut B) {
        let v = Vec::from_fn(N * 13, |i| i);
        let s = Strided::new(&*v);
        let s = s.substrides(13).next().unwrap();
        b.iter(|| {
            test::black_box(&s);
            for e in s.iter() { test::black_box(e) }
        })
    }
}
<|endoftext|>