<commit_before>use std::borrow::Cow;
use std::fs;
use std::path::{Path, PathBuf};
use std::str;

use csv;
use docopt::Docopt;
use rustc_serialize::Decodable;

use CliResult;
use config::{Config, Delimiter};

pub fn num_cpus() -> usize {
    unsafe {
        return rust_get_num_cpus() as usize;
    }

    extern {
        fn rust_get_num_cpus() -> ::libc::uintptr_t;
    }
}

pub fn version() -> String {
    let (maj, min, pat) = (
        option_env!("CARGO_PKG_VERSION_MAJOR"),
        option_env!("CARGO_PKG_VERSION_MINOR"),
        option_env!("CARGO_PKG_VERSION_PATCH"),
    );
    match (maj, min, pat) {
        (Some(maj), Some(min), Some(pat)) =>
            format!("{}.{}.{}", maj, min, pat),
        _ => "".to_string(),
    }
}

pub fn get_args<T>(usage: &str, argv: &[&str]) -> CliResult<T>
        where T: Decodable {
    Docopt::new(usage)
           .and_then(|d| d.argv(argv.iter().map(|&x| x))
                          .version(Some(version()))
                          .decode())
           .map_err(From::from)
}

pub fn many_configs(inps: &[String], delim: Option<Delimiter>,
                    no_headers: bool) -> Result<Vec<Config>, String> {
    let mut inps = inps.to_vec();
    if inps.is_empty() {
        inps.push("-".to_string()); // stdin
    }
    let confs = inps.into_iter()
                    .map(|p| Config::new(&Some(p))
                                    .delimiter(delim)
                                    .no_headers(no_headers))
                    .collect::<Vec<_>>();
    try!(errif_greater_one_stdin(&*confs));
    Ok(confs)
}

pub fn errif_greater_one_stdin(inps: &[Config]) -> Result<(), String> {
    let nstd = inps.iter().filter(|inp| inp.is_std()).count();
    if nstd > 1 {
        return Err("At most one <stdin> input is allowed.".to_string());
    }
    Ok(())
}

pub fn empty_field() -> csv::ByteString { vec![] }

pub fn chunk_size(nitems: usize, njobs: usize) -> usize {
    if nitems < njobs {
        nitems
    } else {
        nitems / njobs
    }
}

pub fn num_of_chunks(nitems: usize, chunk_size: usize) -> usize {
    if chunk_size == 0 {
        return nitems;
    }
    let mut n = nitems / chunk_size;
    if nitems % chunk_size != 0 {
        n += 1;
    }
    n
}

pub fn last_modified(md: &fs::Metadata) -> u64 {
    use filetime::FileTime;
    FileTime::from_last_modification_time(md).seconds_relative_to_1970()
}

pub fn condense<'a>(val: Cow<'a, [u8]>, n: Option<usize>) -> Cow<'a, [u8]> {
    match n {
        None => val,
        Some(n) => {
            // It would be much nicer to just use a `match` here, but the
            // borrow checker won't allow it. ---AG
            //
            // (We could circumvent it by allocating a new Unicode string,
            // but that seems excessive.)
            let mut is_short_utf8 = false;
            if let Ok(s) = str::from_utf8(&*val) {
                if n >= s.chars().count() {
                    is_short_utf8 = true;
                } else {
                    let mut s = s.chars().take(n).collect::<String>();
                    s.push_str("...");
                    return Cow::Owned(s.into_bytes());
                }
            }
            if is_short_utf8 || n >= (*val).len() { // already short enough
                val
            } else {
                // This is a non-Unicode string, so we just trim on bytes.
                let mut s = val[0..n].to_vec();
                s.extend(b"...".iter().cloned());
                Cow::Owned(s)
            }
        }
    }
}

pub fn idx_path(csv_path: &Path) -> PathBuf {
    let mut p = csv_path.to_path_buf().into_os_string().into_string().unwrap();
    p.push_str(".idx");
    PathBuf::from(&p)
}

pub type Idx = Option<usize>;

pub fn range(start: Idx, end: Idx, len: Idx, index: Idx)
            -> Result<(usize, usize), String> {
    match (start, end, len, index) {
        (Some(_), _, _, Some(_)) |
        (_, Some(_), _, Some(_)) |
        (_, _, Some(_), Some(_)) => {
            return Err("--index cannot be used with \
                        --start, --end or --len".to_string());
        }
        (_, _, _, Some(i)) => return Ok((i, i+1)),
        (_, Some(_), Some(_), None) => {
            return Err("--end and --len cannot be used
                        at the same time.".to_string());
        }
        (_, None, None, None) => return Ok((start.unwrap_or(0), ::std::usize::MAX)),
        (_, Some(e), None, None) => {
            let s = start.unwrap_or(0);
            if s > e {
                return Err(format!(
                    "The end of the range ({}) must be greater than or\n\
                     equal to the start of the range ({}).", e, s));
            } else {
                return Ok((start.unwrap_or(0), e));
            }
        }
        (_, None, Some(l), None) => {
            let s = start.unwrap_or(0);
            return Ok((s, s + l));
        }
    }
}
<commit_msg>Simplify the conditions when index is Some<commit_after>use std::borrow::Cow;
use std::fs;
use std::path::{Path, PathBuf};
use std::str;

use csv;
use docopt::Docopt;
use rustc_serialize::Decodable;

use CliResult;
use config::{Config, Delimiter};

pub fn num_cpus() -> usize {
    unsafe {
        return rust_get_num_cpus() as usize;
    }

    extern {
        fn rust_get_num_cpus() -> ::libc::uintptr_t;
    }
}

pub fn version() -> String {
    let (maj, min, pat) = (
        option_env!("CARGO_PKG_VERSION_MAJOR"),
        option_env!("CARGO_PKG_VERSION_MINOR"),
        option_env!("CARGO_PKG_VERSION_PATCH"),
    );
    match (maj, min, pat) {
        (Some(maj), Some(min), Some(pat)) =>
            format!("{}.{}.{}", maj, min, pat),
        _ => "".to_string(),
    }
}

pub fn get_args<T>(usage: &str, argv: &[&str]) -> CliResult<T>
        where T: Decodable {
    Docopt::new(usage)
           .and_then(|d| d.argv(argv.iter().map(|&x| x))
                          .version(Some(version()))
                          .decode())
           .map_err(From::from)
}

pub fn many_configs(inps: &[String], delim: Option<Delimiter>,
                    no_headers: bool) -> Result<Vec<Config>, String> {
    let mut inps = inps.to_vec();
    if inps.is_empty() {
        inps.push("-".to_string()); // stdin
    }
    let confs = inps.into_iter()
                    .map(|p| Config::new(&Some(p))
                                    .delimiter(delim)
                                    .no_headers(no_headers))
                    .collect::<Vec<_>>();
    try!(errif_greater_one_stdin(&*confs));
    Ok(confs)
}

pub fn errif_greater_one_stdin(inps: &[Config]) -> Result<(), String> {
    let nstd = inps.iter().filter(|inp| inp.is_std()).count();
    if nstd > 1 {
        return Err("At most one <stdin> input is allowed.".to_string());
    }
    Ok(())
}

pub fn empty_field() -> csv::ByteString { vec![] }

pub fn chunk_size(nitems: usize, njobs: usize) -> usize {
    if nitems < njobs {
        nitems
    } else {
        nitems / njobs
    }
}

pub fn num_of_chunks(nitems: usize, chunk_size: usize) -> usize {
    if chunk_size == 0 {
        return nitems;
    }
    let mut n = nitems / chunk_size;
    if nitems % chunk_size != 0 {
        n += 1;
    }
    n
}

pub fn last_modified(md: &fs::Metadata) -> u64 {
    use filetime::FileTime;
    FileTime::from_last_modification_time(md).seconds_relative_to_1970()
}

pub fn condense<'a>(val: Cow<'a, [u8]>, n: Option<usize>) -> Cow<'a, [u8]> {
    match n {
        None => val,
        Some(n) => {
            // It would be much nicer to just use a `match` here, but the
            // borrow checker won't allow it. ---AG
            //
            // (We could circumvent it by allocating a new Unicode string,
            // but that seems excessive.)
            let mut is_short_utf8 = false;
            if let Ok(s) = str::from_utf8(&*val) {
                if n >= s.chars().count() {
                    is_short_utf8 = true;
                } else {
                    let mut s = s.chars().take(n).collect::<String>();
                    s.push_str("...");
                    return Cow::Owned(s.into_bytes());
                }
            }
            if is_short_utf8 || n >= (*val).len() { // already short enough
                val
            } else {
                // This is a non-Unicode string, so we just trim on bytes.
                let mut s = val[0..n].to_vec();
                s.extend(b"...".iter().cloned());
                Cow::Owned(s)
            }
        }
    }
}

pub fn idx_path(csv_path: &Path) -> PathBuf {
    let mut p = csv_path.to_path_buf().into_os_string().into_string().unwrap();
    p.push_str(".idx");
    PathBuf::from(&p)
}

pub type Idx = Option<usize>;

pub fn range(start: Idx, end: Idx, len: Idx, index: Idx)
            -> Result<(usize, usize), String> {
    match (start, end, len, index) {
        (None, None, None, Some(i)) => return Ok((i, i+1)),
        (_, _, _, Some(_)) => {
            return Err("--index cannot be used with \
                        --start, --end or --len".to_string());
        }
        (_, _, _, Some(i)) => return Ok((i, i+1)),
        (_, Some(_), Some(_), None) => {
            return Err("--end and --len cannot be used
                        at the same time.".to_string());
        }
        (_, None, None, None) => return Ok((start.unwrap_or(0), ::std::usize::MAX)),
        (_, Some(e), None, None) => {
            let s = start.unwrap_or(0);
            if s > e {
                return Err(format!(
                    "The end of the range ({}) must be greater than or\n\
                     equal to the start of the range ({}).", e, s));
            } else {
                return Ok((start.unwrap_or(0), e));
            }
        }
        (_, None, Some(l), None) => {
            let s = start.unwrap_or(0);
            return Ok((s, s + l));
        }
    }
}
<|endoftext|>


<commit_before>use line::Line;
use update::Update;

#[derive(Clone)]
pub struct View {
    last_rev: u64,
    pub filepath: String,
    pub lines: Vec<Line>,
}

impl View {
    pub fn new(filepath: String) -> View {
        View {
            last_rev: 0,
            filepath: filepath,
            lines: vec![],
        }
    }

    pub fn update(&mut self, update: &Update) {
        if self.last_rev > update.rev {
            return;
        }

        let mut lines = vec![];
        let mut index = 0;

        for operation in &update.operations {
            index = operation.apply(&self.lines, index, &mut lines);
        }

        self.last_rev = update.rev;
        self.lines = lines;
    }
}
<commit_msg>fixup<commit_after>use line::Line;
use update::Update;

#[derive(Clone)]
pub struct View {
    last_rev: u64,
    pub filepath: String,
    pub lines: Vec<Line>,
}

impl View {
    pub fn new(filepath: String) -> View {
        View {
            last_rev: 0,
            filepath: filepath,
            lines: vec![],
        }
    }

    pub fn update(&mut self, update: &Update) {
        // if self.last_rev > update.rev {
        //     return;
        // }

        let mut lines = vec![];
        let mut index = 0;

        for operation in &update.operations {
            index = operation.apply(&self.lines, index, &mut lines);
        }

        // self.last_rev = update.rev;
        self.lines = lines;
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(reason = "not public", issue = "0", feature = "fd")]

use prelude::v1::*;

use io::{self, Read};
use libc::{self, c_int, size_t, c_void};
use mem;
use sync::atomic::{AtomicBool, Ordering};
use sys::cvt;
use sys_common::AsInner;
use sys_common::io::read_to_end_uninitialized;

pub struct FileDesc {
    fd: c_int,
}

impl FileDesc {
    pub fn new(fd: c_int) -> FileDesc {
        FileDesc { fd: fd }
    }

    pub fn raw(&self) -> c_int { self.fd }

    /// Extracts the actual filedescriptor without closing it.
    pub fn into_raw(self) -> c_int {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::read(self.fd,
                       buf.as_mut_ptr() as *mut c_void,
                       buf.len() as size_t)
        })?;
        Ok(ret as usize)
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::write(self.fd,
                        buf.as_ptr() as *const c_void,
                        buf.len() as size_t)
        })?;
        Ok(ret as usize)
    }

    #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten")))]
    pub fn set_cloexec(&self) {
        unsafe {
            let ret = libc::ioctl(self.fd, libc::FIOCLEX);
            debug_assert_eq!(ret, 0);
        }
    }
    #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))]
    pub fn set_cloexec(&self) {
        unsafe {
            let previous = libc::fcntl(self.fd, libc::F_GETFD);
            let ret = libc::fcntl(self.fd, libc::F_SETFD, previous | libc::FD_CLOEXEC);
            debug_assert_eq!(ret, 0);
        }
    }

    pub fn set_nonblocking(&self, nonblocking: bool) {
        unsafe {
            let previous = libc::fcntl(self.fd, libc::F_GETFL);
            debug_assert!(previous != -1);
            let new = if nonblocking {
                previous | libc::O_NONBLOCK
            } else {
                previous & !libc::O_NONBLOCK
            };
            let ret = libc::fcntl(self.fd, libc::F_SETFL, new);
            debug_assert!(ret != -1);
        }
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        // We want to atomically duplicate this file descriptor and set the
        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
        // flag, however, isn't supported on older Linux kernels (earlier than
        // 2.6.24).
        //
        // To detect this and ensure that CLOEXEC is still set, we
        // follow a strategy similar to musl [1] where if passing
        // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
        // supported (the third parameter, 0, is always valid), so we stop
        // trying that.
        //
        // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
        // resolve so we at least compile this.
        //
        // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
        #[cfg(target_os = "android")]
        use libc::F_DUPFD as F_DUPFD_CLOEXEC;
        #[cfg(not(target_os = "android"))]
        use libc::F_DUPFD_CLOEXEC;

        let make_filedesc = |fd| {
            let fd = FileDesc::new(fd);
            fd.set_cloexec();
            fd
        };
        static TRY_CLOEXEC: AtomicBool =
            AtomicBool::new(!cfg!(target_os = "android"));
        let fd = self.raw();
        if TRY_CLOEXEC.load(Ordering::Relaxed) {
            match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
                // We *still* call the `set_cloexec` method as apparently some
                // linux kernel at some point stopped setting CLOEXEC even
                // though it reported doing so on F_DUPFD_CLOEXEC.
                Ok(fd) => {
                    return Ok(if cfg!(target_os = "linux") {
                        make_filedesc(fd)
                    } else {
                        FileDesc::new(fd)
                    })
                }
                Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
                    TRY_CLOEXEC.store(false, Ordering::Relaxed);
                }
                Err(e) => return Err(e),
            }
        }
        cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).map(make_filedesc)
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        unsafe { read_to_end_uninitialized(self, buf) }
    }
}

impl AsInner<c_int> for FileDesc {
    fn as_inner(&self) -> &c_int { &self.fd }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // (opened after we closed ours.
        let _ = unsafe { libc::close(self.fd) };
    }
}
<commit_msg>Don't ignore errors of syscalls in std::sys::unix::fd<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(reason = "not public", issue = "0", feature = "fd")]

use prelude::v1::*;

use io::{self, Read};
use libc::{self, c_int, size_t, c_void};
use mem;
use sync::atomic::{AtomicBool, Ordering};
use sys::cvt;
use sys_common::AsInner;
use sys_common::io::read_to_end_uninitialized;

pub struct FileDesc {
    fd: c_int,
}

impl FileDesc {
    pub fn new(fd: c_int) -> FileDesc {
        FileDesc { fd: fd }
    }

    pub fn raw(&self) -> c_int { self.fd }

    /// Extracts the actual filedescriptor without closing it.
    pub fn into_raw(self) -> c_int {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::read(self.fd,
                       buf.as_mut_ptr() as *mut c_void,
                       buf.len() as size_t)
        })?;
        Ok(ret as usize)
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::write(self.fd,
                        buf.as_ptr() as *const c_void,
                        buf.len() as size_t)
        })?;
        Ok(ret as usize)
    }

    #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten")))]
    pub fn set_cloexec(&self) {
        unsafe {
            let ret = libc::ioctl(self.fd, libc::FIOCLEX);
            assert_eq!(ret, 0);
        }
    }
    #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))]
    pub fn set_cloexec(&self) {
        unsafe {
            let previous = libc::fcntl(self.fd, libc::F_GETFD);
            let ret = libc::fcntl(self.fd, libc::F_SETFD, previous | libc::FD_CLOEXEC);
            assert_eq!(ret, 0);
        }
    }

    pub fn set_nonblocking(&self, nonblocking: bool) {
        unsafe {
            let previous = libc::fcntl(self.fd, libc::F_GETFL);
            assert!(previous != -1);
            let new = if nonblocking {
                previous | libc::O_NONBLOCK
            } else {
                previous & !libc::O_NONBLOCK
            };
            let ret = libc::fcntl(self.fd, libc::F_SETFL, new);
            assert!(ret != -1);
        }
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        // We want to atomically duplicate this file descriptor and set the
        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
        // flag, however, isn't supported on older Linux kernels (earlier than
        // 2.6.24).
        //
        // To detect this and ensure that CLOEXEC is still set, we
        // follow a strategy similar to musl [1] where if passing
        // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
        // supported (the third parameter, 0, is always valid), so we stop
        // trying that.
        //
        // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
        // resolve so we at least compile this.
        //
        // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
        #[cfg(target_os = "android")]
        use libc::F_DUPFD as F_DUPFD_CLOEXEC;
        #[cfg(not(target_os = "android"))]
        use libc::F_DUPFD_CLOEXEC;

        let make_filedesc = |fd| {
            let fd = FileDesc::new(fd);
            fd.set_cloexec();
            fd
        };
        static TRY_CLOEXEC: AtomicBool =
            AtomicBool::new(!cfg!(target_os = "android"));
        let fd = self.raw();
        if TRY_CLOEXEC.load(Ordering::Relaxed) {
            match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
                // We *still* call the `set_cloexec` method as apparently some
                // linux kernel at some point stopped setting CLOEXEC even
                // though it reported doing so on F_DUPFD_CLOEXEC.
                Ok(fd) => {
                    return Ok(if cfg!(target_os = "linux") {
                        make_filedesc(fd)
                    } else {
                        FileDesc::new(fd)
                    })
                }
                Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
                    TRY_CLOEXEC.store(false, Ordering::Relaxed);
                }
                Err(e) => return Err(e),
            }
        }
        cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).map(make_filedesc)
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        unsafe { read_to_end_uninitialized(self, buf) }
    }
}

impl AsInner<c_int> for FileDesc {
    fn as_inner(&self) -> &c_int { &self.fd }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // (opened after we closed ours.
        let _ = unsafe { libc::close(self.fd) };
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "qc", feature(plugin, custom_attribute))]
#![cfg_attr(feature="qc", plugin(quickcheck_macros))]
#![allow(dead_code)]

//! The purpose of these tests is to cover corner cases of iterators
//! and adaptors.
//!
//! In particular we test the tedious size_hint and exact size correctness.

#[macro_use]
extern crate itertools;

#[cfg(feature = "qc")]
extern crate quickcheck;

#[cfg(feature = "qc")]
mod quicktests {

use quickcheck as qc;
use std::ops::Range;
use itertools;
use itertools::Itertools;
use itertools::{
    Zip,
    Stride,
    EitherOrBoth,
};

/// Our base iterator that we can impl Arbitrary for
#[derive(Clone, Debug)]
pub struct Iter<T>(Range<T>);

impl<T> Iterator for Iter<T> where Range<T>: Iterator
{
    type Item = <Range<T> as Iterator>::Item;
    fn next(&mut self) -> Option<Self::Item> { self.0.next() }
    fn size_hint(&self) -> (usize, Option<usize>)
    {
        self.0.size_hint()
    }
}

impl<T> DoubleEndedIterator for Iter<T> where Range<T>: DoubleEndedIterator
{
    fn next_back(&mut self) -> Option<Self::Item> { self.0.next_back() }
}

impl<T> ExactSizeIterator for Iter<T> where Range<T>: ExactSizeIterator
{ }

impl<T> qc::Arbitrary for Iter<T> where T: qc::Arbitrary
{
    fn arbitrary<G: qc::Gen>(g: &mut G) -> Self
    {
        Iter(T::arbitrary(g)..T::arbitrary(g))
    }

    fn shrink(&self) -> Box<Iterator<Item=Iter<T>>>
    {
        let r = self.0.clone();
        Box::new(
            r.start.shrink().flat_map(move |x| {
                r.end.shrink().map(move |y| (x.clone(), y))
            })
            .map(|(a, b)| Iter(a..b))
        )
    }
}

fn correct_size_hint_fast<I: Iterator>(it: I) -> bool {
    let (low, hi) = it.size_hint();
    let cnt = it.count();
    cnt >= low &&
        (hi.is_none() || hi.unwrap() >= cnt)
}

fn correct_size_hint<I: Iterator>(mut it: I) -> bool {
    // record size hint at each iteration
    let initial_hint = it.size_hint();
    let mut hints = Vec::with_capacity(initial_hint.0 + 1);
    hints.push(initial_hint);
    while let Some(_) = it.next() {
        hints.push(it.size_hint())
    }

    let mut true_count = hints.len(); // start off +1 too much

    // check all the size hints
    for &(low, hi) in &hints {
        true_count -= 1;
        if low > true_count ||
            (hi.is_some() && hi.unwrap() < true_count)
        {
            println!("True size: {:?}, size hint: {:?}", true_count, (low, hi));
            println!("All hints: {:?}", hints);
            return false
        }
    }
    true
}

fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
    // check every iteration
    let (mut low, mut hi) = it.size_hint();
    if Some(low) != hi { return false; }
    while let Some(_) = it.next() {
        let (xlow, xhi) = it.size_hint();
        if low != xlow + 1 { return false; }
        low = xlow;
        hi = xhi;
        if Some(low) != hi { return false; }
    }
    let (low, hi) = it.size_hint();
    low == 0 && hi == Some(0)
}

/*
 * NOTE: Range<i8> is broken!
 * (all signed ranges are)
#[quickcheck]
fn size_range_i8(a: Iter<i8>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_i16(a: Iter<i16>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_u8(a: Iter<u8>) -> bool {
    exact_size(a)
}
 */

#[quickcheck]
fn size_stride(data: Vec<u8>, mut stride: isize) -> bool {
    if stride == 0 {
        stride += 1; // never zero
    }
    exact_size(Stride::from_slice(&data, stride))
}

#[quickcheck]
fn equal_stride(data: Vec<u8>, mut stride: i8) -> bool {
    if stride == 0 {
        // never zero
        stride += 1;
    }
    if stride > 0 {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().step(stride as usize))
    } else {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().rev().step(-stride as usize))
    }
}

#[quickcheck]
fn size_product(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.cartesian_product(b))
}

#[quickcheck]
fn size_product3(a: Iter<u16>, b: Iter<u16>, c: Iter<u16>) -> bool {
    correct_size_hint(iproduct!(a, b, c))
}

#[quickcheck]
fn size_step(a: Iter<i16>, mut s: usize) -> bool {
    if s == 0 {
        s += 1; // never zero
    }
    let filt = a.clone().dedup();
    correct_size_hint(filt.step(s)) &&
        exact_size(a.step(s))
}

#[quickcheck]
fn size_multipeek(a: Iter<u16>, s: u8) -> bool {
    let mut it = a.multipeek();
    // peek a few times
    for _ in 0..s {
        it.peek();
    }
    exact_size(it)
}

#[quickcheck]
fn equal_merge(a: Vec<i16>, b: Vec<i16>) -> bool {
    let mut sa = a.clone();
    let mut sb = b.clone();
    sa.sort();
    sb.sort();
    let mut merged = sa.clone() + &sb;
    merged.sort();
    itertools::equal(&merged, sa.iter().merge(&sb))

}
#[quickcheck]
fn size_merge(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.merge(b))
}

#[quickcheck]
fn size_zip(a: Iter<i16>, b: Iter<i16>, c: Iter<i16>) -> bool {
    let filt = a.clone().dedup();
    correct_size_hint(Zip::new((filt, b.clone(), c.clone()))) &&
        exact_size(Zip::new((a, b, c)))
}

#[quickcheck]
fn size_zip_rc(a: Iter<i16>, b: Iter<i16>) -> bool {
    let rc = a.clone().into_rc();
    correct_size_hint(Zip::new((&rc, &rc, b)))
}

#[quickcheck]
fn size_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let filt = a.clone().dedup();
    let filt2 = b.clone().dedup();
    correct_size_hint(filt.zip_longest(b.clone())) &&
    correct_size_hint(a.clone().zip_longest(filt2)) &&
        exact_size(a.zip_longest(b))
}

#[quickcheck]
fn size_2_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let it = a.clone().zip_longest(b.clone());
    let jt = a.clone().zip_longest(b.clone());
    itertools::equal(a.clone(),
                     it.filter_map(|elt| match elt {
                         EitherOrBoth::Both(x, _) => Some(x),
                         EitherOrBoth::Left(x) => Some(x),
                         _ => None,
                     }
                     ))
        &&
    itertools::equal(b.clone(),
                     jt.filter_map(|elt| match elt {
                         EitherOrBoth::Both(_, y) => Some(y),
                         EitherOrBoth::Right(y) => Some(y),
                         _ => None,
                     }
                     ))
}

fn equal_islice(a: Vec<i16>, x: usize, y: usize) -> bool {
    if x > y || y > a.len() { return true; }
    let slc = &a[x..y];
    itertools::equal(a.iter().slice(x..y), slc)
}

fn size_islice(a: Vec<i16>, x: usize, y: usize) -> bool {
    if x > y || y > a.len() { return true; }
    correct_size_hint(a.iter().dedup().slice(x..y)) &&
        exact_size(a.iter().slice(x..y))
}

#[quickcheck]
fn size_interleave(a: Iter<i16>, b: Iter<i16>) -> bool {
    correct_size_hint(a.interleave(b))
}

#[quickcheck]
fn size_intersperse(a: Iter<i16>, x: i16) -> bool {
    correct_size_hint(a.intersperse(x))
}

#[quickcheck]
fn equal_intersperse(a: Vec<i32>, x: i32) -> bool {
    let mut inter = false;
    let mut i = 0;
    for elt in a.iter().cloned().intersperse(x) {
        if inter {
            if elt != x { return false }
        } else {
            if elt != a[i] { return false }
            i += 1;
        }
        inter = !inter;
    }
    true
}

#[quickcheck]
fn equal_dedup(a: Vec<i32>) -> bool {
    let mut b = a.clone();
    b.dedup();
    itertools::equal(&b, a.iter().dedup())
}

#[quickcheck]
fn size_dedup(a: Vec<i32>) -> bool {
    correct_size_hint(a.iter().dedup())
}

#[quickcheck]
fn size_group_by(a: Vec<i8>) -> bool {
    correct_size_hint(a.iter().group_by(|x| x.abs()))
}

#[quickcheck]
fn size_linspace(a: f32, b: f32, n: usize) -> bool {
    let it = itertools::linspace(a, b, n);
    it.len() == n &&
        exact_size(it)
}

#[quickcheck]
fn equal_repeatn(n: usize, x: i32) -> bool {
    let it = itertools::RepeatN::new(x, n);
    exact_size(it)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted(a: Vec<u8>, b: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted3(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), c.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn equal_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    let it = itertools::ZipTrusted::new((a.iter(), b.iter(), x..y));
    let jt = Zip::new((a.iter(), b.iter(), x..y));
    itertools::equal(it, jt)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), x..y)))
}

#[quickcheck]
fn size_put_back(a: Vec<u8>, x: Option<u8>) -> bool {
    let mut it = itertools::PutBack::new(a.into_iter());
    match x {
        Some(t) => it.put_back(t),
        None => {}
    }
    correct_size_hint(it)
}

#[quickcheck]
fn size_tee(a: Vec<u8>) -> bool {
    let (mut t1, mut t2) = a.iter().tee();
    t1.next();
    t1.next();
    t2.next();
    exact_size(t1) && exact_size(t2)
}

#[quickcheck]
fn size_tee_2(a: Vec<u8>) -> bool {
    let (mut t1, mut t2) = a.iter().dedup().tee();
    t1.next();
    t1.next();
    t2.next();
    correct_size_hint(t1) && correct_size_hint(t2)
}

}
<commit_msg>Use a non-fused iterator for quickchecks<commit_after>#![cfg_attr(feature = "qc", feature(plugin, custom_attribute))]
#![cfg_attr(feature="qc", plugin(quickcheck_macros))]
#![allow(dead_code)]

//! The purpose of these tests is to cover corner cases of iterators
//! and adaptors.
//!
//! In particular we test the tedious size_hint and exact size correctness.

#[macro_use]
extern crate itertools;

#[cfg(feature = "qc")]
extern crate quickcheck;

#[cfg(feature = "qc")]
mod quicktests {

use std::default::Default;

use quickcheck as qc;
use std::ops::Range;
use itertools;
use itertools::Itertools;
use itertools::{
    Zip,
    Stride,
    EitherOrBoth,
};

/// Our base iterator that we can impl Arbitrary for
///
/// NOTE: Iter is tricky and is not fused, to help catch bugs.
/// At the end it will return None once, then return Some(0),
/// then return None again.
#[derive(Clone, Debug)]
struct Iter<T>(Range<T>, i32); // with fuse/done flag

impl<T> Iter<T>
{
    fn new(it: Range<T>) -> Self
    {
        Iter(it, 0)
    }
}

impl<T> Iterator for Iter<T> where Range<T>: Iterator,
    <Range<T> as Iterator>::Item: Default,
{
    type Item = <Range<T> as Iterator>::Item;

    fn next(&mut self) -> Option<Self::Item>
    {
        let elt = self.0.next();
        if elt.is_none() {
            self.1 += 1;
            // check fuse flag
            if self.1 == 2 {
                return Some(Default::default())
            }
        }
        elt
    }

    fn size_hint(&self) -> (usize, Option<usize>)
    {
        self.0.size_hint()
    }
}

impl<T> DoubleEndedIterator for Iter<T> where Range<T>: DoubleEndedIterator,
    <Range<T> as Iterator>::Item: Default,
{
    fn next_back(&mut self) -> Option<Self::Item> { self.0.next_back() }
}

impl<T> ExactSizeIterator for Iter<T> where Range<T>: ExactSizeIterator,
    <Range<T> as Iterator>::Item: Default,
{ }

impl<T> qc::Arbitrary for Iter<T> where T: qc::Arbitrary
{
    fn arbitrary<G: qc::Gen>(g: &mut G) -> Self
    {
        Iter::new(T::arbitrary(g)..T::arbitrary(g))
    }

    fn shrink(&self) -> Box<Iterator<Item=Iter<T>>>
    {
        let r = self.0.clone();
        Box::new(
            r.start.shrink().flat_map(move |x| {
                r.end.shrink().map(move |y| (x.clone(), y))
            })
            .map(|(a, b)| Iter::new(a..b))
        )
    }
}

fn correct_size_hint_fast<I: Iterator>(it: I) -> bool {
    let (low, hi) = it.size_hint();
    let cnt = it.count();
    cnt >= low &&
        (hi.is_none() || hi.unwrap() >= cnt)
}

fn correct_size_hint<I: Iterator>(mut it: I) -> bool {
    // record size hint at each iteration
    let initial_hint = it.size_hint();
    let mut hints = Vec::with_capacity(initial_hint.0 + 1);
    hints.push(initial_hint);
    while let Some(_) = it.next() {
        hints.push(it.size_hint())
    }

    let mut true_count = hints.len(); // start off +1 too much

    // check all the size hints
    for &(low, hi) in &hints {
        true_count -= 1;
        if low > true_count ||
            (hi.is_some() && hi.unwrap() < true_count)
        {
            println!("True size: {:?}, size hint: {:?}", true_count, (low, hi));
            //println!("All hints: {:?}", hints);
            return false
        }
    }
    true
}

fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
    // check every iteration
    let (mut low, mut hi) = it.size_hint();
    if Some(low) != hi { return false; }
    while let Some(_) = it.next() {
        let (xlow, xhi) = it.size_hint();
        if low != xlow + 1 { return false; }
        low = xlow;
        hi = xhi;
        if Some(low) != hi { return false; }
    }
    let (low, hi) = it.size_hint();
    low == 0 && hi == Some(0)
}

/*
 * NOTE: Range<i8> is broken!
 * (all signed ranges are)
#[quickcheck]
fn size_range_i8(a: Iter<i8>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_i16(a: Iter<i16>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_u8(a: Iter<u8>) -> bool {
    exact_size(a)
}
 */

#[quickcheck]
fn size_stride(data: Vec<u8>, mut stride: isize) -> bool {
    if stride == 0 {
        stride += 1; // never zero
    }
    exact_size(Stride::from_slice(&data, stride))
}

#[quickcheck]
fn equal_stride(data: Vec<u8>, mut stride: i8) -> bool {
    if stride == 0 {
        // never zero
        stride += 1;
    }
    if stride > 0 {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().step(stride as usize))
    } else {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().rev().step(-stride as usize))
    }
}

#[quickcheck]
fn size_product(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.cartesian_product(b))
}

#[quickcheck]
fn size_product3(a: Iter<u16>, b: Iter<u16>, c: Iter<u16>) -> bool {
    correct_size_hint(iproduct!(a, b, c))
}

#[quickcheck]
fn size_step(a: Iter<i16>, mut s: usize) -> bool {
    if s == 0 {
        s += 1; // never zero
    }
    let filt = a.clone().dedup();
    correct_size_hint(filt.step(s)) &&
        exact_size(a.step(s))
}

#[quickcheck]
fn size_multipeek(a: Iter<u16>, s: u8) -> bool {
    let mut it = a.multipeek();
    // peek a few times
    for _ in 0..s {
        it.peek();
    }
    exact_size(it)
}

#[quickcheck]
fn equal_merge(a: Vec<i16>, b: Vec<i16>) -> bool {
    let mut sa = a.clone();
    let mut sb = b.clone();
    sa.sort();
    sb.sort();
    let mut merged = sa.clone() + &sb;
    merged.sort();
    itertools::equal(&merged, sa.iter().merge(&sb))

}
#[quickcheck]
fn size_merge(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.merge(b))
}

#[quickcheck]
fn size_zip(a: Iter<i16>, b: Iter<i16>, c: Iter<i16>) -> bool {
    let filt = a.clone().dedup();
    correct_size_hint(Zip::new((filt, b.clone(), c.clone()))) &&
        exact_size(Zip::new((a, b, c)))
}

#[quickcheck]
fn size_zip_rc(a: Iter<i16>, b: Iter<i16>) -> bool {
    let rc = a.clone().into_rc();
    correct_size_hint(Zip::new((&rc, &rc, b)))
}

#[quickcheck]
fn size_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let filt = a.clone().dedup();
    let filt2 = b.clone().dedup();
    correct_size_hint(filt.zip_longest(b.clone())) &&
    correct_size_hint(a.clone().zip_longest(filt2)) &&
        exact_size(a.zip_longest(b))
}

#[quickcheck]
fn size_2_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let it = a.clone().zip_longest(b.clone());
    let jt = a.clone().zip_longest(b.clone());
    itertools::equal(a.clone(),
                     it.filter_map(|elt| match elt {
                         EitherOrBoth::Both(x, _) => Some(x),
                         EitherOrBoth::Left(x) => Some(x),
                         _ => None,
                     }
                     ))
        &&
    itertools::equal(b.clone(),
                     jt.filter_map(|elt| match elt {
                         EitherOrBoth::Both(_, y) => Some(y),
                         EitherOrBoth::Right(y) => Some(y),
                         _ => None,
                     }
                     ))
}

fn equal_islice(a: Vec<i16>, x: usize, y: usize) -> bool {
    if x > y || y > a.len() { return true; }
    let slc = &a[x..y];
    itertools::equal(a.iter().slice(x..y), slc)
}

fn size_islice(a: Iter<i16>, x: usize, y: usize) -> bool {
    correct_size_hint(a.clone().dedup().slice(x..y)) &&
        exact_size(a.clone().slice(x..y))
}

#[quickcheck]
fn size_interleave(a: Iter<i16>, b: Iter<i16>) -> bool {
    correct_size_hint(a.interleave(b))
}

#[quickcheck]
fn size_intersperse(a: Iter<i16>, x: i16) -> bool {
    correct_size_hint(a.intersperse(x))
}

#[quickcheck]
fn equal_intersperse(a: Vec<i32>, x: i32) -> bool {
    let mut inter = false;
    let mut i = 0;
    for elt in a.iter().cloned().intersperse(x) {
        if inter {
            if elt != x { return false }
        } else {
            if elt != a[i] { return false }
            i += 1;
        }
        inter = !inter;
    }
    true
}

#[quickcheck]
fn equal_dedup(a: Vec<i32>) -> bool {
    let mut b = a.clone();
    b.dedup();
    itertools::equal(&b, a.iter().dedup())
}

#[quickcheck]
fn size_dedup(a: Vec<i32>) -> bool {
    correct_size_hint(a.iter().dedup())
}

#[quickcheck]
fn size_group_by(a: Vec<i8>) -> bool {
    correct_size_hint(a.iter().group_by(|x| x.abs()))
}

#[quickcheck]
fn size_linspace(a: f32, b: f32, n: usize) -> bool {
    let it = itertools::linspace(a, b, n);
    it.len() == n &&
        exact_size(it)
}

#[quickcheck]
fn equal_repeatn(n: usize, x: i32) -> bool {
    let it = itertools::RepeatN::new(x, n);
    exact_size(it)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted(a: Vec<u8>, b: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted3(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), c.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn equal_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    let it = itertools::ZipTrusted::new((a.iter(), b.iter(), x..y));
    let jt = Zip::new((a.iter(), b.iter(), x..y));
    itertools::equal(it, jt)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), x..y)))
}

#[quickcheck]
fn size_put_back(a: Vec<u8>, x: Option<u8>) -> bool {
    let mut it = itertools::PutBack::new(a.into_iter());
    match x {
        Some(t) => it.put_back(t),
        None => {}
    }
    correct_size_hint(it)
}

#[quickcheck]
fn size_tee(a: Vec<u8>) -> bool {
    let (mut t1, mut t2) = a.iter().tee();
    t1.next();
    t1.next();
    t2.next();
    exact_size(t1) && exact_size(t2)
}

#[quickcheck]
fn size_tee_2(a: Vec<u8>) -> bool {
    let (mut t1, mut t2) = a.iter().dedup().tee();
    t1.next();
    t1.next();
    t2.next();
    correct_size_hint(t1) && correct_size_hint(t2)
}

}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_variables, unused_imports)]
#![cfg(test)]
/// The utils module is used by other tests to make writing tests easier.
///
/// The idea is to provide tests with a neat interface that allows tests to define a pipeline of
/// transformations on the input.
/// The test is then returned with a result struct that contains information about all the
/// intermediate stages to assert! for correctness.

extern crate radeco;

use radeco::frontend::parser::{Parser};
use radeco::frontend::structs::{LOpInfo};
use radeco::frontend::r2::R2;
use radeco::middle::ir::{MInst};
use radeco::middle::cfg::CFG;
use radeco::middle::dot;
use radeco::middle::ssa::SSAStorage;

use std::io::prelude::*;
use std::fs::{File, create_dir};

fn write_file(fname: &str, res: String) {
	let mut file = File::create(fname).ok().expect("Error. Cannot create file!\n");
	file.write_all(res.as_bytes()).ok().expect("Error. Cannot write file!\n");
}

#[derive(Clone, Copy, Debug)]
pub enum Analysis {
	ConstProp,
}

#[derive(Clone, Copy, Debug)]
pub enum Pipeline {
	ReadFromR2,
	ParseEsil,
	CFG,
	SSA,
	AnalyzeSSA(Analysis),
	CWriter,
}

impl Pipeline {
	fn to_string(&self) -> String {
		let s = match *self {
			Pipeline::ReadFromR2 => "r2",
			Pipeline::ParseEsil => "radecoIR",
			Pipeline::CFG => "cfg",
			Pipeline::SSA => "ssa",
			Pipeline::AnalyzeSSA(a) => unimplemented!(),
			Pipeline::CWriter => unimplemented!(),
		};
		s.to_string()
	}
}

// Enum that represents the output of a stage in the Pipeline.
// Every stage has a corresponding Pipeout type.
pub enum Pipeout {
	LOpInfo(Vec<LOpInfo>),
	Instructions(Vec<MInst>),
	CFG(CFG),
	SSA(SSAStorage),
}

// Bundles all the vars important to various stages of the pipeline together.
// Also acts as the result struct.
pub struct Bundle<'a> {
	r2: Option<R2>,
	esil: Option<Vec<String>>,
	p: Option<Parser<'a>>,
	cfg: Option<CFG>,
	ssa: Option<SSAStorage>,
	pipeout: Option<Pipeout>,
}

impl<'a> Bundle<'a> {
	fn new() -> Bundle<'a> {
		Bundle {
			r2: None,
			esil: None,
			p: None,
			cfg: None,
			ssa: None,
			pipeout: None,
		}
	}
}

// TODO: Improve this result struct.
// Right now: `f` -> Filename to write out `res` to.
pub struct Results {
	f: String,
	res: String,
}

// Function to initialize all your vars to sane defaults.
fn init_vars() {
}

// Function to run the integration test.
// The common pipeline is esil -> cfg -> ssa.
// Returns a result struct which can be used to assert! the results.
fn run_test(pipeline: &Vec<Pipeline>, bundle: &mut Bundle) -> Results {
	for stage in pipeline.iter() {
		match *stage {
			Pipeline::ReadFromR2 => { },
			Pipeline::ParseEsil => { },
			Pipeline::CFG => { },
			Pipeline::SSA => { },
			Pipeline::AnalyzeSSA(a) => unimplemented!(),
			Pipeline::CWriter => unimplemented!(),
		}
	}
	unimplemented!();
}
<commit_msg>WIP. Improve Pipeline.<commit_after>#![allow(dead_code, unused_variables, unused_imports)]
#![cfg(test)]
/// The utils module is used by other tests to make writing tests easier.
///
/// The idea is to provide tests with a neat interface that allows tests to define a pipeline of
/// transformations on the input.
/// The test is then returned with a result struct that contains information about all the
/// intermediate stages to assert! for correctness.

extern crate radeco;

use radeco::frontend::parser::{Parser};
use radeco::frontend::structs::{LOpInfo, LRegInfo};
use radeco::frontend::r2::R2;
use radeco::middle::ir::{MInst};
use radeco::middle::cfg::CFG;
use radeco::middle::dot;
use radeco::middle::ssa::SSAStorage;

use std::io::prelude::*;
use std::fs::{File, create_dir};

fn write_file(fname: &str, res: String) {
	let mut file = File::create(fname).ok().expect("Error. Cannot create file!\n");
	file.write_all(res.as_bytes()).ok().expect("Error. Cannot write file!\n");
}

#[derive(Clone, Copy, Debug)]
pub enum Analysis {
	ConstProp,
}

#[derive(Clone, Copy, Debug)]
pub enum Pipeline {
	ReadFromR2,
	ParseEsil,
	CFG,
	SSA,
	AnalyzeSSA(Analysis),
	CWriter,
}

impl Pipeline {
	fn to_string(&self) -> String {
		let s = match *self {
			Pipeline::ReadFromR2 => "r2",
			Pipeline::ParseEsil => "radecoIR",
			Pipeline::CFG => "cfg",
			Pipeline::SSA => "ssa",
			Pipeline::AnalyzeSSA(a) => unimplemented!(),
			Pipeline::CWriter => unimplemented!(),
		};
		s.to_string()
	}
}

// Enum that represents the output of a stage in the Pipeline.
// Every stage has a corresponding Pipeout type.
#[derive(Clone)]
pub enum Pipeout {
	Esil(Vec<String>),
	LOpInfo(Vec<LOpInfo>),
	Instructions(Vec<MInst>),
	CFG(CFG),
	SSA(SSAStorage),
}

// States all the vars important to various stages of the pipeline together.
// Also acts as the result struct.
pub struct State<'a> {
	r2: Option<R2>,
	esil: Option<Vec<String>>,
	reg_info: Option<LRegInfo>,
	p: Option<Parser<'a>>,
	cfg: Option<CFG>,
	ssa: Option<SSAStorage>,
	pipeout: Option<Pipeout>,
}

impl<'a> State<'a> {
	fn new() -> State<'a> {
		State {
			r2: None,
			esil: None,
			reg_info: None,
			p: None,
			cfg: None,
			ssa: None,
			pipeout: None,
		}
	}
}

pub struct Test<'a> {
	name: String,
	bin_name: Option<String>,
	addr: Option<String>,
	pipeline: Vec<Pipeline>,
	results: Vec<Pipeout>,
	state: State<'a>,
}

impl<'a> Test<'a> {

	pub fn new(name: String, bin_name: Option<String>,
			   addr: Option<String>, pipeline: Vec<Pipeline>) -> Test<'a> {
		Test {
			name: name,
			bin_name: bin_name,
			addr: addr,
			pipeline: pipeline,
			results: Vec::new(),
			state: State::new(),
		}
	}

	fn read_from_r2(&mut self) {
		assert!(!self.bin_name.is_none());
		assert!(!self.addr.is_none());

		let bin_name = self.bin_name.clone().unwrap();
		let mut r2 = R2::new(&*bin_name);
		r2.init();
		self.state.reg_info = Some(r2.get_reg_info().unwrap());
		let addr = self.addr.clone().unwrap();
		let func_info = r2.get_function(&*addr).unwrap();
		self.state.pipeout = Some(Pipeout::LOpInfo(func_info.ops.unwrap()));
		self.state.r2 = Some(r2);
	}

	fn parse_esil(&mut self) {
		let pipein = self.state.pipeout.clone().unwrap();
		match pipein {
			Pipeout::Esil(s)      => { },
			Pipeout::LOpInfo(ops) => { },
			_                     => panic!("Incompatible type found in the pipeline!"),
		}
	}

	fn construct_cfg(&mut self) {
		let pipein = self.state.pipeout.clone().unwrap();
		match pipein {
			Pipeout::Instructions(insts) => { },
			_ => panic!("Incompatible type found in the pipeline!"),
		}
	}

	fn construct_ssa(&mut self) {
		let pipein = self.state.pipeout.clone().unwrap();
		match pipein {
			Pipeout::CFG(cfg) => { },
			_ => panic!("Incompatible type found in the pipeline!"),
		}
	}

	pub fn run_test(&mut self) {
		let pipe_iter = self.pipeline.clone();
		for stage in pipe_iter.iter() {
			match *stage {
				Pipeline::ReadFromR2 => self.read_from_r2(),
				Pipeline::ParseEsil => self.parse_esil(),
				Pipeline::CFG => self.construct_cfg(),
				Pipeline::SSA => self.construct_ssa(),
				Pipeline::AnalyzeSSA(a) => unimplemented!(),
				Pipeline::CWriter => unimplemented!(),
			}
		}
	}
}
<|endoftext|>


<commit_before>#![feature(convert)]
#![feature(slice_patterns)]
#![feature(collections)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

struct VM<'a> {
  stack: Vec<Expr>,
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
}

fn parse_labels<'a>(instructions: &Vec<&'a str>) -> HashMap<&'a str, usize> {
  let mut map = HashMap::new();
  for (i, instr) in instructions.iter().enumerate() {
    if instr.starts_with("$label") {
      match instr.split(' ').nth(1) {
        Some(label) => map.insert(label, i),
        None => panic!("VM error: missing label"),
      };
    }
  };
  map
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  fn unsafe_pop(&mut self) -> Expr {
    self.stack.pop().expect("VM error: stack is empty")
  }

  pub fn run(&mut self) {
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false; // comparison carry

    let labels = parse_labels(&self.instructions);

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      if instr.starts_with("#") || instr.trim() == "" {
        continue;
      }
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["$label", _] => (),
        ["push", "int", n] => self.stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        ["push", "str", n] => self.stack.push(Expr::Str(String::from_str(n))),

        ["dup"] => {
          let expr = self.unsafe_pop();
          self.stack.push(expr.clone());
          self.stack.push(expr);
        },

        // convert to string
        ["convert", "int", "str"] => if let Some(&Expr::Int(arg)) = self.stack.last() {
          self.stack.push(Expr::Str(arg.to_string()));
        } else {
          panic!("VM error: cannot convert int to string");
        },

        ["convert", from, to] => panic!("VM error: cannot convert from {} to {}", from, to),

        // how = "always" | "carry"
        ["jump", how, n] => {
          let new_ip = if n.starts_with("$") {
            labels.get(n.trim_matches('$')).expect("VM error: no such label").clone()
          } else {
            n.parse::<usize>().unwrap()
          };

          if new_ip < len {
            // only check carry if we are conditionally jumping
            if how == "always" || (how == "carry" && carry) {
              ip = new_ip;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        ["call", "say"] => if let Some(Expr::Str(arg)) = self.stack.pop() {
          println!("hey {}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call!
        ["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 + arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          self.stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `add`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        ["cmp", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        // TODO this *shouldn't* be an identifier
        //      the backend should transform SSAF to tons of load/store
        //      (probably)
        //      (see backend#1)
        ["local", "load", name] => match self.locals.get(name) {
          Some(expr) => self.stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = self.stack.pop() {
          let _ = self.locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"),
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        panic!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    panic!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<commit_msg>Cleanup experimentals (switch to rust 1.8-nightly)<commit_after>#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

#[derive(Clone)]
enum Expr {
  Int(i64),
  Str(String)
}

struct VM<'a> {
  stack: Vec<Expr>,
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
}

fn parse_labels<'a>(instructions: &Vec<&'a str>) -> HashMap<&'a str, usize> {
  let mut map = HashMap::new();
  for (i, instr) in instructions.iter().enumerate() {
    if instr.starts_with("$label") {
      match instr.split(' ').nth(1) {
        Some(label) => map.insert(label, i),
        None => panic!("VM error: missing label"),
      };
    }
  };
  map
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  fn unsafe_pop(&mut self) -> Expr {
    self.stack.pop().expect("VM error: stack is empty")
  }

  pub fn run(&mut self) {
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false; // comparison carry

    let labels = parse_labels(&self.instructions);

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      if instr.starts_with("#") || instr.trim() == "" {
        continue;
      }
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["$label", _] => (),
        ["push", "int", n] => self.stack.push(Expr::Int(n.parse::<i64>().unwrap())),
        ["push", "str", n] => self.stack.push(Expr::Str(String::from(n))),

        ["dup"] => {
          let expr = self.unsafe_pop();
          self.stack.push(expr.clone());
          self.stack.push(expr);
        },

        // convert to string
        ["convert", "int", "str"] => if let Some(&Expr::Int(arg)) = self.stack.last() {
          self.stack.push(Expr::Str(arg.to_string()));
        } else {
          panic!("VM error: cannot convert int to string");
        },

        ["convert", from, to] => panic!("VM error: cannot convert from {} to {}", from, to),

        // how = "always" | "carry"
        ["jump", how, n] => {
          let new_ip = if n.starts_with("$") {
            labels.get(n.trim_matches('$')).expect("VM error: no such label").clone()
          } else {
            n.parse::<usize>().unwrap()
          };

          if new_ip < len {
            // only check carry if we are conditionally jumping
            if how == "always" || (how == "carry" && carry) {
              ip = new_ip;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["carry", "set", val] => carry = val == "true",
        ["carry", "invert"] => carry = !carry,

        ["call", "say"] => if let Some(Expr::Str(arg)) = self.stack.pop() {
          println!("hey {}", arg);
        } else {
          panic!("VM error: incorrect arguments to `say`");
        },

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        /// XXX this should JUST be a call!
        ["math", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          let value = match op {
            "+" => arg1 + arg2,
            "-" => arg1 + arg2,
            //"/" => TODO. this should have very specific rules...
            "*" => arg1 * arg2,
            _ => panic!("VM error: unrecognized `op` operator: {}", op),
          };
          self.stack.push(Expr::Int(value));
        } else {
          panic!("VM error: not enough arguments to `add`");
        },

        // same note about "2 OP 1"
        // XXX same note about how this should be a `call`
        ["cmp", op] => if let
            (Some(Expr::Int(arg1)), Some(Expr::Int(arg2)))
            =
            (self.stack.pop(), self.stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        // TODO this *shouldn't* be an identifier
        //      the backend should transform SSAF to tons of load/store
        //      (probably)
        //      (see backend#1)
        ["local", "load", name] => match self.locals.get(name) {
          Some(expr) => self.stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = self.stack.pop() {
          let _ = self.locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"),
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        panic!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    panic!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/24_game
// with a recursive descent parser for a simple calculator (+ - * /)
// using the shunting yard algorithm as explained on
// http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
// It follows operator precedence (i.e. 2 + 3 * 3 = 11),
// understands negation (-5 + 6 = 1), ignores whitespace
// and allows the use of parentheses

// We use a glob import in our test module. Seperating tests into a seperate
// module enforces visibility restrictions so the test module can only access
// publically exported code, the same as any user of the code.
#![feature(globs, associated_types)]
use std::cmp::Ordering::{self, Greater};
use std::char::CharExt;

#[cfg(not(test))]
fn main() {
    use std::{rand, io};

    let mut rng = rand::thread_rng();
    let mut input = io::stdin();

    loop {
        let mut sample = rand::sample(&mut rng, (1us..10), 4);

        println!("make 24 by combining the following 4 numbers with + - * / or (q)uit");
        println!("{:?}", sample);

        let line = input.read_line().unwrap();
        match line.trim() {
            "q" => break,
            input => {
                if check_values(sample.as_mut_slice(), input) {
                    match Parser::new(input).parse() {
                        Ok(i) if i == 24. => println!("you made it!"),
                        Ok(i) => println!("you entered {}, try again!", i),
                        Err(s)  => println!("{}", s)
                    };
                } else {
                    println!("unrecognized input, try again")
                }
            }
        }
    }
}

// Returns true if the entered expression uses the values contained in sample
pub fn check_values(sample:&mut [usize], input:&str) -> bool {
    let lex = Lexer::new(input);

    let mut numbers_used = lex.filter_map(|a| {
        match a {
            Token::Int(i) => Some(i),
            _ => None
        }
    }).collect::<Vec<usize>>();

    numbers_used.sort();
    sample.sort();
    numbers_used == sample
}

// the tokens that our parser is going to recognize
#[derive(PartialEq,Eq,Show, Copy)]
pub enum Token {
    LParen,
    RParen,
    Plus,
    Minus,
    Slash,
    Star,
    Int(usize)
}

impl Token {
   // are tokens associated to a binary operation?
   fn is_binary(&self) -> bool {
        match *self {
            Token::Plus | Token::Minus | Token::Slash | Token::Star => true,
            _ => false
        }
    }
}

trait Tokenable { fn as_token(&self) -> Option<Token>; }

// map a character to its corresponding token
impl Tokenable for char {
    #[inline]
    fn as_token(&self) -> Option<Token> {
        let tok = match *self {
            '(' => Token::LParen,
            ')' => Token::RParen,
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Slash,
            '*' => Token::Star,
            _ => return None
        };

        Some(tok)
    }
}

// Lexer reads an expression like (a + b) / c * d
// as an iterator on the tokens that compose it
// Int(a), LParen, Plus, Int(b), RParen...
#[derive(Copy)]
pub struct Lexer<'a> {
    input: &'a str,
    offset: usize
}

impl <'a> Lexer<'a> {
    pub fn new(input: &str) -> Lexer {
        Lexer { input: input, offset: 0us }
    }

    fn expect(&mut self, expected:&[Token]) -> Result<Token, String> {
        let n = self.offset;
        match self.next() {
            Some(a) if expected.contains(&a)  => Ok(a),
            other  => Err(format!("Parsing error: {:?} was unexpected at offset {}",
                                  other,
                                  n))
        }
    }
}

impl <'a> Iterator for Lexer<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        // slice the original string starting from the current offset
        let mut remaining = self.input.slice_from(self.offset)
                                      // keep track of the original indice
                                      .char_indices()
                                      // advance to the next non-whitespace char
                                      .skip_while(|&(_, ch)| ch.is_whitespace());

        let (tok, cur_offset) = match remaining.next() {
            // Found a digit. if there are others, transform them to `usize`
            Some((mut offset, ch)) if ch.is_numeric() => {
                let mut val = ch.to_digit(10).unwrap();
                let mut more = false;

                for (idx, ch) in remaining {
                    more = true;
                    if CharExt::is_numeric(ch) {
                        let digit = CharExt::to_digit(ch, 10).unwrap();
                        val = val * 10 + digit;
                    } else {
                        offset = idx;
                        break;
                    }
                }
                if !more {
                    offset = 1;
                }
                (Some(Token::Int(val)), offset)
            },
            // found non-digit, try transforming it to the corresponding token
            Some((o, ch)) => (ch.as_token(), o + 1),
            _   => (None, 0us)
        };

        // update the offset for the next iteration
        self.offset += cur_offset;
        tok
    }
}

// Operators are a "higher level" concept than tokens as they define the
// semantics of the expression language e.g. token "Minus" can correspond to
// the unary Neg Operator (-a) or to the binary Sub operator (a - b)
#[derive(PartialEq, Eq, Copy)]
pub enum Operator {
    Neg,
    Add,
    Sub,
    Mul,
    Div,
    Sentinel
}

impl Operator {
     fn precedence(&self) -> usize  {
        match *self {
            Operator::Sentinel => 0,
            Operator::Add | Operator::Sub => 1,
            Operator::Neg => 2,
            Operator::Mul | Operator::Div => 3
        }
    }
}

// Operator precedence for binary operators:
// * if x has higher precedence than y precedence for x > precedence for y
// * if x and y have equal precedence the first one has precedence
// e.g. in expression (4 / 2 * 2) operators * and / have the same precedence,
// but the operations must be performed in the order they appear
// (division first, multiplication second) otherwise results are different
impl PartialOrd for Operator {
    fn partial_cmp(&self, other: &Operator) -> Option<Ordering> {
        match (self.precedence(), other.precedence()) {
            (a, b) if a == b => Some(Greater),
            (a, b) => a.partial_cmp(&b)
        }
    }
}

// recursive descent parser
// with the shunting yard algorithm as explained on
// http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
// I followed the names of the methods as closely as possible vs the pseudo-code
// that illustrates the algorithm
pub struct Parser<'a> {
    operators: Vec<Operator>,
    operands: Vec<f32>,
    lexer: Lexer<'a>
}

impl <'a> Parser<'a> {
    pub fn new(input: &str) -> Parser {
        Parser {
            operators: vec![],
            operands: vec![],
            lexer: Lexer::new(input)
        }
    }

    pub fn parse(&mut self) -> Result<f32, String> {
        self.operators.push(Operator::Sentinel);
        try!(self.e());
        return match self.operands.last() {
            Some(r) => Ok(*r),
            None => Err("something went wrong, got no result".to_string())
        }
    }

    fn e(&mut self) -> Result<(), String> {
        try!(self.p());

        loop {
            match self.lexer.peekable().peek() {
                Some(&x) if x.is_binary() => {
                    let op = match x {
                        Token::Plus => Operator::Add,
                        Token::Minus => Operator::Sub,
                        Token::Star => Operator::Mul,
                        Token::Slash => Operator::Div,
                        // there are no other binary operators
                        _ => unreachable!()
                    };

                    self.push_operator(op);

                    // Consume the peeked value
                    self.lexer.next();
                    try!(self.p());
                }
                _ => break
            }
        }

        loop {
            match self.operators.last() {
                Some(&op) if op != Operator::Sentinel => self.pop_operator(),
                _ => return Ok(())
            }
        }
    }

    fn p(&mut self) -> Result<(), String> {
        match self.lexer.next() {
            Some(Token::Int(n)) => self.operands.push(n as f32),
            Some(Token::LParen) => {
                self.operators.push(Operator::Sentinel);
                try!(self.e());
                try!(self.lexer.expect(&[Token::RParen]));
                self.operators.pop();
            },
            Some(Token::Minus) => {
                self.push_operator(Operator::Neg);
                try!(self.p());
            },
            Some(e) => return Err(format!("unexpected token {:?}", e)),
            _ => return Err("unexpected end of command".to_string())
        }
        Ok(())
    }

    fn pop_operator(&mut self) {
        match self.operators.pop() {
            Some(Operator::Add) => self.binary_op(|t1, t2| t1 + t2),
            Some(Operator::Sub) => self.binary_op(|t1, t2| t1 - t2),
            Some(Operator::Mul) => self.binary_op(|t1, t2| t1 * t2),
            Some(Operator::Div) => self.binary_op(|t1, t2| t1 / t2),
            Some(Operator::Neg) => self.unary_op(|t1| -t1),
            _ => unreachable!()
        }
    }

    fn push_operator(&mut self, op: Operator) {
        match self.operators.last() {
            Some(&last_op) if last_op > op => self.pop_operator(),
            _ => {}
        }
        self.operators.push(op);
    }

    #[inline]
    fn binary_op<F>(&mut self, op: F) where F: Fn(f32, f32) -> f32 {
        match (self.operands.pop(), self.operands.pop()) {
            (Some(t1), Some(t2)) => self.operands.push(op(t2, t1)),
            _ => unreachable!()
        }
    }

    #[inline]
    fn unary_op<F>(&mut self, op: F) where F: Fn(f32) -> f32 {
        match self.operands.pop() {
            Some(t1) => self.operands.push(op(t1)),
            _ => unreachable!()
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Token, Lexer, Parser};
    use super::Operator::{Add, Sub, Mul, Div};
    use super::{check_values};
    use super::Token::{LParen, RParen, Plus, Slash, Star, Int};

    #[test]
    fn test_precedence() {
        assert!(Mul > Add);
        // Ordering matters for these pairs
        assert!(Mul > Div);
        assert!(Div > Mul);

        assert!(Add > Sub);
        assert!(Sub > Add);

        assert!(!(Mul < Div));
    }

    #[test]
    fn lexer_iter() {
        // test read token and character's offset in the iterator
        let t = |&: lex: &mut Lexer, exp_tok: Token, exp_pos: usize| {
            assert_eq!(lex.next(), Some(exp_tok));
            assert_eq!(lex.offset, exp_pos);
        };

        let tok = &mut Lexer::new("  15 + 4");
        t(tok, Int(15), 4);
        t(tok, Plus, 6);
        let read = tok.expect(&[LParen,Int(4),RParen]);
        assert_eq!(read, Ok(Int(4)));

        let mut tok = Lexer::new("");
        assert_eq!(tok.next(), None);

        let tok = &mut Lexer::new("     ");
        assert_eq!(tok.next(), None);

        let tok = &mut Lexer::new("2 * (3+4/2)");
        t(tok, Int(2), 1);
        t(tok, Star, 3);
        t(tok, LParen, 5);
        t(tok, Int(3), 6);
        t(tok, Plus, 7);
        t(tok, Int(4), 8);
        t(tok, Slash, 9);
        t(tok, Int(2), 10);
        t(tok, RParen, 11);
    }

    #[test]
    fn parse() {
        fn t(input: &str, expected: Result<f32, String>) {
            assert_eq!(Parser::new(input).parse(), expected)
        }

        t("2+2", Ok(4.));
        t("2+3*4", Ok(14.));
        t("4*(3+2)", Ok(20.));
        t("5/(3+2)*3", Ok(3.));
        t("2++12", Err("unexpected token Plus".to_string()));
        t("-2+12", Ok(10.));
        t("-2*(2+3)", Ok(-10.));

        // Testing precedence
        t("4 / 2 * 2", Ok(4.));
        t("2 * 2 / 4", Ok(1.));
    }

    #[test]
    fn try_check_values() {
        let m = &mut [1, 2, 3, 4];
        assert!(check_values(m, "1+3 -(4/2)"));
        // new testcase for #314
        assert!(check_values(m, "1+2+3+4"));
    }
}
<commit_msg>24_game<commit_after>// Implements http://rosettacode.org/wiki/24_game
// with a recursive descent parser for a simple calculator (+ - * /)
// using the shunting yard algorithm as explained on
// http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
// It follows operator precedence (i.e. 2 + 3 * 3 = 11),
// understands negation (-5 + 6 = 1), ignores whitespace
// and allows the use of parentheses

// We use a glob import in our test module. Seperating tests into a seperate
// module enforces visibility restrictions so the test module can only access
// publically exported code, the same as any user of the code.
#![allow(unstable)]
use std::cmp::Ordering::{self, Greater};
use std::char::CharExt;

#[cfg(not(test))]
fn main() {
    use std::{rand, io};

    let mut rng = rand::thread_rng();
    let mut input = io::stdin();

    loop {
        let mut sample = rand::sample(&mut rng, (1us..10), 4);

        println!("make 24 by combining the following 4 numbers with + - * / or (q)uit");
        println!("{:?}", sample);

        let line = input.read_line().unwrap();
        match line.trim() {
            "q" => break,
            input => {
                if check_values(&mut sample[], input) {
                    match Parser::new(input).parse() {
                        Ok(i) if i == 24. => println!("you made it!"),
                        Ok(i) => println!("you entered {}, try again!", i),
                        Err(s)  => println!("{}", s)
                    };
                } else {
                    println!("unrecognized input, try again")
                }
            }
        }
    }
}

// Returns true if the entered expression uses the values contained in sample
pub fn check_values(sample:&mut [usize], input:&str) -> bool {
    let lex = Lexer::new(input);

    let mut numbers_used = lex.filter_map(|a| {
        match a {
            Token::Int(i) => Some(i),
            _ => None
        }
    }).collect::<Vec<usize>>();

    numbers_used.sort();
    sample.sort();
    numbers_used == sample
}

// the tokens that our parser is going to recognize
#[derive(PartialEq,Eq,Show, Copy)]
pub enum Token {
    LParen,
    RParen,
    Plus,
    Minus,
    Slash,
    Star,
    Int(usize)
}

impl Token {
   // are tokens associated to a binary operation?
   fn is_binary(&self) -> bool {
        match *self {
            Token::Plus | Token::Minus | Token::Slash | Token::Star => true,
            _ => false
        }
    }
}

trait Tokenable { fn as_token(&self) -> Option<Token>; }

// map a character to its corresponding token
impl Tokenable for char {
    #[inline]
    fn as_token(&self) -> Option<Token> {
        let tok = match *self {
            '(' => Token::LParen,
            ')' => Token::RParen,
            '+' => Token::Plus,
            '-' => Token::Minus,
            '/' => Token::Slash,
            '*' => Token::Star,
            _ => return None
        };

        Some(tok)
    }
}

// Lexer reads an expression like (a + b) / c * d
// as an iterator on the tokens that compose it
// Int(a), LParen, Plus, Int(b), RParen...
#[derive(Copy)]
pub struct Lexer<'a> {
    input: &'a str,
    offset: usize
}

impl <'a> Lexer<'a> {
    pub fn new(input: &str) -> Lexer {
        Lexer { input: input, offset: 0us }
    }

    fn expect(&mut self, expected:&[Token]) -> Result<Token, String> {
        let n = self.offset;
        match self.next() {
            Some(a) if expected.contains(&a)  => Ok(a),
            other  => Err(format!("Parsing error: {:?} was unexpected at offset {}",
                                  other,
                                  n))
        }
    }
}

impl <'a> Iterator for Lexer<'a> {
    type Item = Token;

    fn next(&mut self) -> Option<Token> {
        // slice the original string starting from the current offset
        let mut remaining = self.input[self.offset..]
                                      // keep track of the original indice
                                      .char_indices()
                                      // advance to the next non-whitespace char
                                      .skip_while(|&(_, ch)| ch.is_whitespace());

        let (tok, cur_offset) = match remaining.next() {
            // Found a digit. if there are others, transform them to `usize`
            Some((mut offset, ch)) if ch.is_numeric() => {
                let mut val = ch.to_digit(10).unwrap();
                let mut more = false;

                for (idx, ch) in remaining {
                    more = true;
                    if CharExt::is_numeric(ch) {
                        let digit = CharExt::to_digit(ch, 10).unwrap();
                        val = val * 10 + digit;
                    } else {
                        offset = idx;
                        break;
                    }
                }
                if !more {
                    offset = 1;
                }
                (Some(Token::Int(val)), offset)
            },
            // found non-digit, try transforming it to the corresponding token
            Some((o, ch)) => (ch.as_token(), o + 1),
            _   => (None, 0us)
        };

        // update the offset for the next iteration
        self.offset += cur_offset;
        tok
    }
}

// Operators are a "higher level" concept than tokens as they define the
// semantics of the expression language e.g. token "Minus" can correspond to
// the unary Neg Operator (-a) or to the binary Sub operator (a - b)
#[derive(PartialEq, Eq, Copy)]
pub enum Operator {
    Neg,
    Add,
    Sub,
    Mul,
    Div,
    Sentinel
}

impl Operator {
     fn precedence(&self) -> usize  {
        match *self {
            Operator::Sentinel => 0,
            Operator::Add | Operator::Sub => 1,
            Operator::Neg => 2,
            Operator::Mul | Operator::Div => 3
        }
    }
}

// Operator precedence for binary operators:
// * if x has higher precedence than y precedence for x > precedence for y
// * if x and y have equal precedence the first one has precedence
// e.g. in expression (4 / 2 * 2) operators * and / have the same precedence,
// but the operations must be performed in the order they appear
// (division first, multiplication second) otherwise results are different
impl PartialOrd for Operator {
    fn partial_cmp(&self, other: &Operator) -> Option<Ordering> {
        match (self.precedence(), other.precedence()) {
            (a, b) if a == b => Some(Greater),
            (a, b) => a.partial_cmp(&b)
        }
    }
}

// recursive descent parser
// with the shunting yard algorithm as explained on
// http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
// I followed the names of the methods as closely as possible vs the pseudo-code
// that illustrates the algorithm
pub struct Parser<'a> {
    operators: Vec<Operator>,
    operands: Vec<f32>,
    lexer: Lexer<'a>
}

impl <'a> Parser<'a> {
    pub fn new(input: &str) -> Parser {
        Parser {
            operators: vec![],
            operands: vec![],
            lexer: Lexer::new(input)
        }
    }

    pub fn parse(&mut self) -> Result<f32, String> {
        self.operators.push(Operator::Sentinel);
        try!(self.e());
        return match self.operands.last() {
            Some(r) => Ok(*r),
            None => Err("something went wrong, got no result".to_string())
        }
    }

    fn e(&mut self) -> Result<(), String> {
        try!(self.p());

        loop {
            match self.lexer.peekable().peek() {
                Some(&x) if x.is_binary() => {
                    let op = match x {
                        Token::Plus => Operator::Add,
                        Token::Minus => Operator::Sub,
                        Token::Star => Operator::Mul,
                        Token::Slash => Operator::Div,
                        // there are no other binary operators
                        _ => unreachable!()
                    };

                    self.push_operator(op);

                    // Consume the peeked value
                    self.lexer.next();
                    try!(self.p());
                }
                _ => break
            }
        }

        loop {
            match self.operators.last() {
                Some(&op) if op != Operator::Sentinel => self.pop_operator(),
                _ => return Ok(())
            }
        }
    }

    fn p(&mut self) -> Result<(), String> {
        match self.lexer.next() {
            Some(Token::Int(n)) => self.operands.push(n as f32),
            Some(Token::LParen) => {
                self.operators.push(Operator::Sentinel);
                try!(self.e());
                try!(self.lexer.expect(&[Token::RParen]));
                self.operators.pop();
            },
            Some(Token::Minus) => {
                self.push_operator(Operator::Neg);
                try!(self.p());
            },
            Some(e) => return Err(format!("unexpected token {:?}", e)),
            _ => return Err("unexpected end of command".to_string())
        }
        Ok(())
    }

    fn pop_operator(&mut self) {
        match self.operators.pop() {
            Some(Operator::Add) => self.binary_op(|t1, t2| t1 + t2),
            Some(Operator::Sub) => self.binary_op(|t1, t2| t1 - t2),
            Some(Operator::Mul) => self.binary_op(|t1, t2| t1 * t2),
            Some(Operator::Div) => self.binary_op(|t1, t2| t1 / t2),
            Some(Operator::Neg) => self.unary_op(|t1| -t1),
            _ => unreachable!()
        }
    }

    fn push_operator(&mut self, op: Operator) {
        match self.operators.last() {
            Some(&last_op) if last_op > op => self.pop_operator(),
            _ => {}
        }
        self.operators.push(op);
    }

    #[inline]
    fn binary_op<F>(&mut self, op: F) where F: Fn(f32, f32) -> f32 {
        match (self.operands.pop(), self.operands.pop()) {
            (Some(t1), Some(t2)) => self.operands.push(op(t2, t1)),
            _ => unreachable!()
        }
    }

    #[inline]
    fn unary_op<F>(&mut self, op: F) where F: Fn(f32) -> f32 {
        match self.operands.pop() {
            Some(t1) => self.operands.push(op(t1)),
            _ => unreachable!()
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Token, Lexer, Parser};
    use super::Operator::{Add, Sub, Mul, Div};
    use super::{check_values};
    use super::Token::{LParen, RParen, Plus, Slash, Star, Int};

    #[test]
    fn test_precedence() {
        assert!(Mul > Add);
        // Ordering matters for these pairs
        assert!(Mul > Div);
        assert!(Div > Mul);

        assert!(Add > Sub);
        assert!(Sub > Add);

        assert!(!(Mul < Div));
    }

    #[test]
    fn lexer_iter() {
        // test read token and character's offset in the iterator
        let t = |&: lex: &mut Lexer, exp_tok: Token, exp_pos: usize| {
            assert_eq!(lex.next(), Some(exp_tok));
            assert_eq!(lex.offset, exp_pos);
        };

        let tok = &mut Lexer::new("  15 + 4");
        t(tok, Int(15), 4);
        t(tok, Plus, 6);
        let read = tok.expect(&[LParen,Int(4),RParen]);
        assert_eq!(read, Ok(Int(4)));

        let mut tok = Lexer::new("");
        assert_eq!(tok.next(), None);

        let tok = &mut Lexer::new("     ");
        assert_eq!(tok.next(), None);

        let tok = &mut Lexer::new("2 * (3+4/2)");
        t(tok, Int(2), 1);
        t(tok, Star, 3);
        t(tok, LParen, 5);
        t(tok, Int(3), 6);
        t(tok, Plus, 7);
        t(tok, Int(4), 8);
        t(tok, Slash, 9);
        t(tok, Int(2), 10);
        t(tok, RParen, 11);
    }

    #[test]
    fn parse() {
        fn t(input: &str, expected: Result<f32, String>) {
            assert_eq!(Parser::new(input).parse(), expected)
        }

        t("2+2", Ok(4.));
        t("2+3*4", Ok(14.));
        t("4*(3+2)", Ok(20.));
        t("5/(3+2)*3", Ok(3.));
        t("2++12", Err("unexpected token Plus".to_string()));
        t("-2+12", Ok(10.));
        t("-2*(2+3)", Ok(-10.));

        // Testing precedence
        t("4 / 2 * 2", Ok(4.));
        t("2 * 2 / 4", Ok(1.));
    }

    #[test]
    fn try_check_values() {
        let m = &mut [1, 2, 3, 4];
        assert!(check_values(m, "1+3 -(4/2)"));
        // new testcase for #314
        assert!(check_values(m, "1+2+3+4"));
    }
}
<|endoftext|>


<commit_before>use super::{DataStore, DataStoreError};
use std::collections::HashMap;

pub type HashMapStore = HashMap<String,String>;

/// Implement the DataStore methods for HashMap
impl DataStore for HashMapStore {

    fn store(&mut self, key: &str, value: &str) -> Result<(), DataStoreError> {
        self.insert(key.into(), value.into());
        Ok(())
    }

    fn retrieve(&self, key: &str) -> Result<String, DataStoreError> {
        self.get(key).map(|v| v.clone()).ok_or(DataStoreError::HashMapError)
    }

    fn delete(&mut self, key: &str) -> Result<(), DataStoreError> {
        self.remove(key);
        Ok(())
    }

}

<commit_msg>server: Add unit tests for HashMapStore<commit_after>use super::{DataStore, DataStoreError};
use std::collections::HashMap;

pub type HashMapStore = HashMap<String,String>;

/// Implement the DataStore methods for HashMap
impl DataStore for HashMapStore {

    fn store(&mut self, key: &str, value: &str) -> Result<(), DataStoreError> {
        self.insert(key.into(), value.into());
        Ok(())
    }

    fn retrieve(&self, key: &str) -> Result<String, DataStoreError> {
        self.get(key).map(|v| v.clone()).ok_or(DataStoreError::HashMapError)
    }

    fn delete(&mut self, key: &str) -> Result<(), DataStoreError> {
        self.remove(key);
        Ok(())
    }
}

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

    #[test]
    fn roundtrip() {
        let mut store = HashMapStore::new();
        store.store("key", "value");
        let result = store.retrieve("key").unwrap();
        assert_eq!(result, "value");
        store.delete("key");
    }

    #[test]
    #[should_panic()]
    fn nonexistant() {
        let store = HashMapStore::new();
        store.retrieve("nonexistant").unwrap();
    }

}
<|endoftext|>