<commit_before>#![allow(unused)]

extern crate websocket;
extern crate futures;
extern crate tokio_core;
#[macro_use]
extern crate tokio_io;
extern crate tokio_stdin_stdout;

#[cfg(unix)]
extern crate tokio_file_unix;
#[cfg(unix)]
extern crate tokio_signal;

use std::thread;
use std::io::stdin;
use tokio_core::reactor::Core;
use futures::future::Future;
use futures::sink::Sink;
use futures::stream::Stream;
use futures::sync::mpsc;
use websocket::result::WebSocketError;
use websocket::{ClientBuilder, OwnedMessage};
use tokio_io::{AsyncRead,AsyncWrite};
use std::io::{Read,Write};
use std::io::Result as IoResult;

use std::rc::Rc;
use std::cell::RefCell;

use websocket::stream::async::Stream as WsStream;
use futures::Async::{Ready, NotReady};

use tokio_io::io::copy;

use tokio_io::codec::FramedRead;
use std::fs::File;

#[cfg(unix)]
use tokio_file_unix::{File as UnixFile, StdFile};
#[cfg(unix)]
use std::os::unix::io::FromRawFd;

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

#[cfg(feature="ssl")]
type WaitingForImplTraitFeature0 = tokio_io::codec::Framed<std::boxed::Box<websocket::async::Stream + std::marker::Send>, websocket::async::MessageCodec<websocket::OwnedMessage>>;
#[cfg(not(feature="ssl"))]
type WaitingForImplTraitFeature0 = tokio_io::codec::Framed<websocket::async::TcpStream, websocket::async::MessageCodec<websocket::OwnedMessage>>;
type WaitingForImplTraitFeature2 = futures::stream::SplitSink<WaitingForImplTraitFeature0>;
type WsSource = futures::stream::SplitStream<WaitingForImplTraitFeature0>;
type MultiProducerWsSink = Rc<RefCell<WaitingForImplTraitFeature2>>;

fn wouldblock<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::WouldBlock, ""))
}
fn brokenpipe<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, ""))
}
fn io_other_error<E : std::error::Error + Send + Sync + 'static>(e:E) -> std::io::Error {
    std::io::Error::new(std::io::ErrorKind::Other,e)
}

mod my_copy;

struct WsReadWrapper {
    s: WsSource,
    pingreply : MultiProducerWsSink,
    debt: Option<Vec<u8>>,
}

impl AsyncRead for WsReadWrapper {

}

impl WsReadWrapper {
    fn process_message(&mut self, buf: &mut [u8], buf_in: &[u8]) -> std::result::Result<usize, std::io::Error> {
        let l = buf_in.len().min(buf.len());
        buf[..l].copy_from_slice(&buf_in[..l]);

        if l < buf_in.len() {
            self.debt = Some(buf_in[l..].to_vec());
        }

        Ok(l)
    }
}

impl Read for WsReadWrapper {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        if let Some(debt) = self.debt.take() {
            return self.process_message(buf, debt.as_slice())
        }
        match self.s.poll().map_err(io_other_error)? {
            Ready(Some(OwnedMessage::Close(_))) => {
                brokenpipe()
            },
            Ready(None) => {
                brokenpipe()
            }
            Ready(Some(OwnedMessage::Ping(x))) => {
                let om = OwnedMessage::Pong(x);
                let mut sink = self.pingreply.borrow_mut();
                let mut proceed = false;
                // I'm not sure this is safe enough, RefCell-wise and Futures-wise
                // And pings and their replies are not tested yet
                match sink.start_send(om).map_err(io_other_error)? {
                    futures::AsyncSink::NotReady(_) => {
                        // drop the ping
                    },
                    futures::AsyncSink::Ready => {
                        proceed = true;
                    }
                }
                if proceed {
                    let _ = sink.poll_complete().map_err(io_other_error)?;
                }

                Ok(0)
            }
            Ready(Some(OwnedMessage::Pong(_))) => {
                Ok(0)
            }
            Ready(Some(OwnedMessage::Text(x))) => {
                self.process_message(buf, x.as_str().as_bytes())
            }
            Ready(Some(OwnedMessage::Binary(x))) => {
                self.process_message(buf, x.as_slice())
            }
            NotReady => {
                wouldblock()
            }
        }
    }
}

struct WsWriteWrapper(MultiProducerWsSink);

impl AsyncWrite for WsWriteWrapper {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        // TODO: check this
        Ok(Ready(()))
    }
}

impl Write for WsWriteWrapper {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let om = OwnedMessage::Binary(buf.to_vec());
        match self.0.borrow_mut().start_send(om).map_err(io_other_error)? {
            futures::AsyncSink::NotReady(_) => {
                wouldblock()
            },
            futures::AsyncSink::Ready => {
                Ok(buf.len())
            }
        }
    }
    fn flush(&mut self) -> IoResult<()> {
        match self.0.borrow_mut().poll_complete().map_err(io_other_error)? {
            NotReady => {
                wouldblock()
            },
            Ready(()) => {
                Ok(())
            }
        }
    }
}

impl WsWriteWrapper {
    fn into_inner(self) -> MultiProducerWsSink {
        self.0
    }
    fn inner(&self) -> &MultiProducerWsSink {
        &self.0
    }
}

fn run() -> Result<()> {
    let peeraddr = std::env::args().nth(1).ok_or("no arg")?;

    //println!("Connecting to {}", peeraddr);
    let mut core = Core::new()?;
    let handle = core.handle();

    let si;
    let so;

    #[cfg(any(not(unix),feature="no_unix_stdio"))]
    {
        si = tokio_stdin_stdout::stdin(0);
        so = tokio_stdin_stdout::stdout(0);
    }

    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    {
        let stdin  = UnixFile::new_nb(std::io::stdin())?;
        let stdout = UnixFile::new_nb(std::io::stdout())?;

        si = stdin.into_reader(&handle)?;
        so = stdout.into_io(&handle)?;

        let ctrl_c = tokio_signal::ctrl_c(&handle).flatten_stream();
        let prog = ctrl_c.for_each(|()| {
            UnixFile::raw_new(std::io::stdin()).set_nonblocking(false);
            UnixFile::raw_new(std::io::stdout()).set_nonblocking(false);
            ::std::process::exit(0);
            Ok(())
        });
        handle.spawn(prog.map_err(|_|()));
    }

    let before_connect = ClientBuilder::new(peeraddr.as_ref())?
        .add_protocol("rust-websocket");
    #[cfg(feature="ssl")]
    let after_connect = before_connect
        .async_connect(None, &core.handle());
    #[cfg(not(feature="ssl"))]
    let after_connect = before_connect
        .async_connect_insecure(&core.handle());
    let runner = after_connect
        .and_then(|(duplex, _)| {
            let (sink, stream) = duplex.split();
            let mpsink = Rc::new(RefCell::new(sink));

            let ws_str = WsReadWrapper {
                s: stream,
                pingreply: mpsink.clone(),
                debt: None,
            };
            let ws_sin = WsWriteWrapper(mpsink);

            handle.spawn(
                my_copy::copy(si, ws_sin, true)
                    .map_err(|_|())
                    .and_then(|(_,_,sinkwr)| {
                        let mut sink = sinkwr.inner().borrow_mut();
                        sink.start_send(OwnedMessage::Close(None))
                            .map_err(|_|())
                            .map(|_|());
                        sink.poll_complete()
                            .map_err(|_|())
                            .map(|_|())
                    })
            );
            my_copy::copy(ws_str, so, false).map_err(|e| WebSocketError::IoError(e))
        });
    core.run(runner)?;
    Ok(())
}

fn main() {
    let r = run();

    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    {
        UnixFile::raw_new(std::io::stdin()).set_nonblocking(false);
        UnixFile::raw_new(std::io::stdout()).set_nonblocking(false);
    }

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<commit_msg>Enforce two command-line arguments<commit_after>#![allow(unused)]

extern crate websocket;
extern crate futures;
extern crate tokio_core;
#[macro_use]
extern crate tokio_io;
extern crate tokio_stdin_stdout;

#[cfg(unix)]
extern crate tokio_file_unix;
#[cfg(unix)]
extern crate tokio_signal;

use std::thread;
use std::io::stdin;
use tokio_core::reactor::Core;
use futures::future::Future;
use futures::sink::Sink;
use futures::stream::Stream;
use futures::sync::mpsc;
use websocket::result::WebSocketError;
use websocket::{ClientBuilder, OwnedMessage};
use tokio_io::{AsyncRead,AsyncWrite};
use std::io::{Read,Write};
use std::io::Result as IoResult;

use std::rc::Rc;
use std::cell::RefCell;

use websocket::stream::async::Stream as WsStream;
use futures::Async::{Ready, NotReady};

use tokio_io::io::copy;

use tokio_io::codec::FramedRead;
use std::fs::File;

#[cfg(unix)]
use tokio_file_unix::{File as UnixFile, StdFile};
#[cfg(unix)]
use std::os::unix::io::FromRawFd;

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

#[cfg(feature="ssl")]
type WaitingForImplTraitFeature0 = tokio_io::codec::Framed<std::boxed::Box<websocket::async::Stream + std::marker::Send>, websocket::async::MessageCodec<websocket::OwnedMessage>>;
#[cfg(not(feature="ssl"))]
type WaitingForImplTraitFeature0 = tokio_io::codec::Framed<websocket::async::TcpStream, websocket::async::MessageCodec<websocket::OwnedMessage>>;
type WaitingForImplTraitFeature2 = futures::stream::SplitSink<WaitingForImplTraitFeature0>;
type WsSource = futures::stream::SplitStream<WaitingForImplTraitFeature0>;
type MultiProducerWsSink = Rc<RefCell<WaitingForImplTraitFeature2>>;

fn wouldblock<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::WouldBlock, ""))
}
fn brokenpipe<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, ""))
}
fn io_other_error<E : std::error::Error + Send + Sync + 'static>(e:E) -> std::io::Error {
    std::io::Error::new(std::io::ErrorKind::Other,e)
}

mod my_copy;

struct WsReadWrapper {
    s: WsSource,
    pingreply : MultiProducerWsSink,
    debt: Option<Vec<u8>>,
}

impl AsyncRead for WsReadWrapper {

}

impl WsReadWrapper {
    fn process_message(&mut self, buf: &mut [u8], buf_in: &[u8]) -> std::result::Result<usize, std::io::Error> {
        let l = buf_in.len().min(buf.len());
        buf[..l].copy_from_slice(&buf_in[..l]);

        if l < buf_in.len() {
            self.debt = Some(buf_in[l..].to_vec());
        }

        Ok(l)
    }
}

impl Read for WsReadWrapper {
    fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
        if let Some(debt) = self.debt.take() {
            return self.process_message(buf, debt.as_slice())
        }
        match self.s.poll().map_err(io_other_error)? {
            Ready(Some(OwnedMessage::Close(_))) => {
                brokenpipe()
            },
            Ready(None) => {
                brokenpipe()
            }
            Ready(Some(OwnedMessage::Ping(x))) => {
                let om = OwnedMessage::Pong(x);
                let mut sink = self.pingreply.borrow_mut();
                let mut proceed = false;
                // I'm not sure this is safe enough, RefCell-wise and Futures-wise
                // And pings and their replies are not tested yet
                match sink.start_send(om).map_err(io_other_error)? {
                    futures::AsyncSink::NotReady(_) => {
                        // drop the ping
                    },
                    futures::AsyncSink::Ready => {
                        proceed = true;
                    }
                }
                if proceed {
                    let _ = sink.poll_complete().map_err(io_other_error)?;
                }

                Ok(0)
            }
            Ready(Some(OwnedMessage::Pong(_))) => {
                Ok(0)
            }
            Ready(Some(OwnedMessage::Text(x))) => {
                self.process_message(buf, x.as_str().as_bytes())
            }
            Ready(Some(OwnedMessage::Binary(x))) => {
                self.process_message(buf, x.as_slice())
            }
            NotReady => {
                wouldblock()
            }
        }
    }
}

struct WsWriteWrapper(MultiProducerWsSink);

impl AsyncWrite for WsWriteWrapper {
    fn shutdown(&mut self) -> futures::Poll<(),std::io::Error> {
        // TODO: check this
        Ok(Ready(()))
    }
}

impl Write for WsWriteWrapper {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let om = OwnedMessage::Binary(buf.to_vec());
        match self.0.borrow_mut().start_send(om).map_err(io_other_error)? {
            futures::AsyncSink::NotReady(_) => {
                wouldblock()
            },
            futures::AsyncSink::Ready => {
                Ok(buf.len())
            }
        }
    }
    fn flush(&mut self) -> IoResult<()> {
        match self.0.borrow_mut().poll_complete().map_err(io_other_error)? {
            NotReady => {
                wouldblock()
            },
            Ready(()) => {
                Ok(())
            }
        }
    }
}

impl WsWriteWrapper {
    fn into_inner(self) -> MultiProducerWsSink {
        self.0
    }
    fn inner(&self) -> &MultiProducerWsSink {
        &self.0
    }
}

fn run() -> Result<()> {
    let _        = std::env::args().nth(1).ok_or("Usage: websocat - ws[s]://...")?;
    let peeraddr = std::env::args().nth(2).ok_or("no second arg")?;

    //println!("Connecting to {}", peeraddr);
    let mut core = Core::new()?;
    let handle = core.handle();

    let si;
    let so;

    #[cfg(any(not(unix),feature="no_unix_stdio"))]
    {
        si = tokio_stdin_stdout::stdin(0);
        so = tokio_stdin_stdout::stdout(0);
    }

    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    {
        let stdin  = UnixFile::new_nb(std::io::stdin())?;
        let stdout = UnixFile::new_nb(std::io::stdout())?;

        si = stdin.into_reader(&handle)?;
        so = stdout.into_io(&handle)?;

        let ctrl_c = tokio_signal::ctrl_c(&handle).flatten_stream();
        let prog = ctrl_c.for_each(|()| {
            UnixFile::raw_new(std::io::stdin()).set_nonblocking(false);
            UnixFile::raw_new(std::io::stdout()).set_nonblocking(false);
            ::std::process::exit(0);
            Ok(())
        });
        handle.spawn(prog.map_err(|_|()));
    }

    let before_connect = ClientBuilder::new(peeraddr.as_ref())?
        .add_protocol("rust-websocket");
    #[cfg(feature="ssl")]
    let after_connect = before_connect
        .async_connect(None, &core.handle());
    #[cfg(not(feature="ssl"))]
    let after_connect = before_connect
        .async_connect_insecure(&core.handle());
    let runner = after_connect
        .and_then(|(duplex, _)| {
            let (sink, stream) = duplex.split();
            let mpsink = Rc::new(RefCell::new(sink));

            let ws_str = WsReadWrapper {
                s: stream,
                pingreply: mpsink.clone(),
                debt: None,
            };
            let ws_sin = WsWriteWrapper(mpsink);

            handle.spawn(
                my_copy::copy(si, ws_sin, true)
                    .map_err(|_|())
                    .and_then(|(_,_,sinkwr)| {
                        let mut sink = sinkwr.inner().borrow_mut();
                        sink.start_send(OwnedMessage::Close(None))
                            .map_err(|_|())
                            .map(|_|());
                        sink.poll_complete()
                            .map_err(|_|())
                            .map(|_|())
                    })
            );
            my_copy::copy(ws_str, so, false).map_err(|e| WebSocketError::IoError(e))
        });
    core.run(runner)?;
    Ok(())
}

fn main() {
    let r = run();

    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    {
        UnixFile::raw_new(std::io::stdin()).set_nonblocking(false);
        UnixFile::raw_new(std::io::stdout()).set_nonblocking(false);
    }

    if let Err(e) = r {
        eprintln!("websocat: {}", e);
        ::std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::{self, Command};

#[cfg(unix)]
use std::process::{Child, Stdio};

extern crate isatty;
use isatty::{stdout_isatty, stderr_isatty};

#[cfg(unix)]
extern crate tempdir;
#[cfg(unix)]
use tempdir::TempDir;

fn main() {
    let result = cargo_expand();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(&mut io::stderr(), "{}", err);
            1
        }
    });
}

#[cfg(windows)]
fn cargo_expand() -> io::Result<i32> {
    // Build cargo command
    let mut cmd = Command::new("cargo");
    cmd.args(&wrap_args(env::args_os(), None));
    run(cmd)
}

#[cfg(unix)]
fn cargo_expand() -> io::Result<i32> {
    let args: Vec<_> = env::args_os().collect();
    match args.last().unwrap().to_str().unwrap_or("") {
        "--filter-cargo" => filter_err(ignore_cargo_err),
        "--filter-rustfmt" => filter_err(ignore_rustfmt_err),
        _ => {}
    }

    macro_rules! shell {
        ($($arg:expr)*) => {
            &[$(OsStr::new(&$arg)),*]
        };
    }

    let which_rustfmt = which(&["rustfmt"]);
    let which_pygmentize = if stdout_isatty() {
        which(&["pygmentize", "-l", "rust"])
    } else {
        None
    };

    let outdir = if which_rustfmt.is_some() || which_pygmentize.is_some() {
        Some(TempDir::new("cargo-expand").expect("failed to create tmp file"))
    } else {
        None
    };
    let outfile = outdir.as_ref().map(|dir| dir.path().join("expanded"));

    // Build cargo command
    let mut cmd = Command::new("cargo");
    cmd.args(&wrap_args(args.clone(), outfile.as_ref()));

    // Pipe to a tmp file to separate out any println output from build scripts
    if let Some(outfile) = outfile {
        let mut filter_cargo = Vec::new();
        filter_cargo.extend(args.iter().map(OsString::as_os_str));
        filter_cargo.push(OsStr::new("--filter-cargo"));

        let _wait = cmd.pipe_to(shell!("cat"), Some(&filter_cargo))?;
        run(cmd)?;
        drop(_wait);

        cmd = Command::new("cat");
        cmd.arg(outfile);
    }

    // Pipe to rustfmt
    let _wait = match which_rustfmt {
        Some(ref fmt) => {
            let args: Vec<_> = env::args_os().collect();
            let mut filter_rustfmt = Vec::new();
            filter_rustfmt.extend(args.iter().map(OsString::as_os_str));
            filter_rustfmt.push(OsStr::new("--filter-rustfmt"));

            Some((
                cmd.pipe_to(shell!(fmt), None)?,
                cmd.pipe_to(shell!("cat"), Some(&filter_rustfmt))?,
            ))
        }
        None => None,
    };

    // Pipe to pygmentize
    let _wait = match which_pygmentize {
        Some(pyg) => Some(cmd.pipe_to(shell!(pyg "-l" "rust"), None)?),
        None => None,
    };

    run(cmd)
}

fn run(mut cmd: Command) -> io::Result<i32> {
    cmd.status().map(|status| status.code().unwrap_or(1))
}

#[cfg(unix)]
struct Wait(Vec<Child>);

#[cfg(unix)]
impl Drop for Wait {
    fn drop(&mut self) {
        for child in &mut self.0 {
            if let Err(err) = child.wait() {
                let _ = writeln!(&mut io::stderr(), "{}", err);
            }
        }
    }
}

#[cfg(unix)]
trait PipeTo {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait>;
}

#[cfg(unix)]
impl PipeTo for Command {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait> {
        use std::os::unix::io::{AsRawFd, FromRawFd};

        self.stdout(Stdio::piped());
        if err.is_some() {
            self.stderr(Stdio::piped());
        }

        let child = self.spawn()?;

        *self = Command::new(out[0]);
        self.args(&out[1..]);
        self.stdin(unsafe {
            Stdio::from_raw_fd(child.stdout.as_ref().map(AsRawFd::as_raw_fd).unwrap())
        });

        match err {
            None => {
                Ok(Wait(vec![child]))
            }
            Some(err) => {
                let mut errcmd = Command::new(err[0]);
                errcmd.args(&err[1..]);
                errcmd.stdin(unsafe {
                    Stdio::from_raw_fd(child.stderr.as_ref().map(AsRawFd::as_raw_fd).unwrap())
                });
                errcmd.stdout(Stdio::null());
                errcmd.stderr(Stdio::inherit());
                let spawn = errcmd.spawn()?;
                Ok(Wait(vec![spawn, child]))
            }
        }
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn wrap_args<I>(it: I, outfile: Option<&PathBuf>) -> Vec<OsString>
    where I: IntoIterator<Item=OsString>
{
    let mut args = vec!["rustc".into()];
    let mut ends_with_test = false;
    let mut ends_with_example = false;
    let mut has_color = false;

    let mut it = it.into_iter().skip(2);
    for arg in &mut it {
        if arg == *"--" {
            break;
        }
        ends_with_test = arg == *"--test";
        ends_with_example = arg == *"--example";
        has_color |= arg.to_str().unwrap_or("").starts_with("--color");
        args.push(arg.into());
    }

    if ends_with_test {
        // Expand the `test.rs` test by default.
        args.push("test".into());
    }

    if ends_with_example {
        // Expand the `example.rs` example by default.
        args.push("example".into());
    }

    if !has_color {
        let color = stderr_isatty();
        let setting = if color { "always" } else { "never" };
        args.push(format!("--color={}", setting).into());
    }

    args.push("--".into());
    if let Some(path) = outfile {
        args.push("-o".into());
        args.push(path.into());
    }
    args.push("-Zunstable-options".into());
    args.push("--pretty=expanded".into());
    args.extend(it);
    args
}

#[cfg(unix)]
fn which(cmd: &[&str]) -> Option<OsString> {
    if env::args_os().find(|arg| arg == "--help").is_some() {
        return None;
    }

    if let Some(which) = env::var_os(&cmd[0].to_uppercase()) {
        return if which.is_empty() {
            None
        } else {
            Some(which)
        };
    }

    let spawn = Command::new(cmd[0])
        .args(&cmd[1..])
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn();
    let mut child = match spawn {
        Ok(child) => child,
        Err(_) => {
            return None;
        }
    };

    let exit = match child.wait() {
        Ok(exit) => exit,
        Err(_) => {
            return None;
        }
    };

    if exit.success() {
        Some(cmd[0].into())
    } else {
        None
    }
}

#[cfg(unix)]
fn filter_err(ignore: fn(&str) -> bool) -> ! {
    let mut line = String::new();
    while let Ok(n) = io::stdin().read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(&mut io::stderr(), "{}", line);
        }
        line.clear();
    }
    process::exit(0);
}

#[cfg(unix)]
fn ignore_rustfmt_err(_line: &str) -> bool {
    true
}

#[cfg(unix)]
fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let blacklist = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag.",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
    ];
    for s in &blacklist {
        if line.contains(s) {
            return true;
        }
    }

    false
}
<commit_msg>Format with rustfmt-nightly 0.2.9<commit_after>use std::env;
use std::ffi::{OsStr, OsString};
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::{self, Command};

#[cfg(unix)]
use std::process::{Child, Stdio};

extern crate isatty;
use isatty::{stderr_isatty, stdout_isatty};

#[cfg(unix)]
extern crate tempdir;
#[cfg(unix)]
use tempdir::TempDir;

fn main() {
    let result = cargo_expand();
    process::exit(match result {
        Ok(code) => code,
        Err(err) => {
            let _ = writeln!(&mut io::stderr(), "{}", err);
            1
        }
    });
}

#[cfg(windows)]
fn cargo_expand() -> io::Result<i32> {
    // Build cargo command
    let mut cmd = Command::new("cargo");
    cmd.args(&wrap_args(env::args_os(), None));
    run(cmd)
}

#[cfg(unix)]
fn cargo_expand() -> io::Result<i32> {
    let args: Vec<_> = env::args_os().collect();
    match args.last().unwrap().to_str().unwrap_or("") {
        "--filter-cargo" => filter_err(ignore_cargo_err),
        "--filter-rustfmt" => filter_err(ignore_rustfmt_err),
        _ => {}
    }

    macro_rules! shell {
        ($($arg:expr)*) => {
            &[$(OsStr::new(&$arg)),*]
        };
    }

    let which_rustfmt = which(&["rustfmt"]);
    let which_pygmentize = if stdout_isatty() {
        which(&["pygmentize", "-l", "rust"])
    } else {
        None
    };

    let outdir = if which_rustfmt.is_some() || which_pygmentize.is_some() {
        Some(TempDir::new("cargo-expand").expect("failed to create tmp file"))
    } else {
        None
    };
    let outfile = outdir.as_ref().map(|dir| dir.path().join("expanded"));

    // Build cargo command
    let mut cmd = Command::new("cargo");
    cmd.args(&wrap_args(args.clone(), outfile.as_ref()));

    // Pipe to a tmp file to separate out any println output from build scripts
    if let Some(outfile) = outfile {
        let mut filter_cargo = Vec::new();
        filter_cargo.extend(args.iter().map(OsString::as_os_str));
        filter_cargo.push(OsStr::new("--filter-cargo"));

        let _wait = cmd.pipe_to(shell!("cat"), Some(&filter_cargo))?;
        run(cmd)?;
        drop(_wait);

        cmd = Command::new("cat");
        cmd.arg(outfile);
    }

    // Pipe to rustfmt
    let _wait = match which_rustfmt {
        Some(ref fmt) => {
            let args: Vec<_> = env::args_os().collect();
            let mut filter_rustfmt = Vec::new();
            filter_rustfmt.extend(args.iter().map(OsString::as_os_str));
            filter_rustfmt.push(OsStr::new("--filter-rustfmt"));

            Some((
                cmd.pipe_to(shell!(fmt), None)?,
                cmd.pipe_to(shell!("cat"), Some(&filter_rustfmt))?,
            ))
        }
        None => None,
    };

    // Pipe to pygmentize
    let _wait = match which_pygmentize {
        Some(pyg) => Some(cmd.pipe_to(shell!(pyg "-l" "rust"), None)?),
        None => None,
    };

    run(cmd)
}

fn run(mut cmd: Command) -> io::Result<i32> {
    cmd.status().map(|status| status.code().unwrap_or(1))
}

#[cfg(unix)]
struct Wait(Vec<Child>);

#[cfg(unix)]
impl Drop for Wait {
    fn drop(&mut self) {
        for child in &mut self.0 {
            if let Err(err) = child.wait() {
                let _ = writeln!(&mut io::stderr(), "{}", err);
            }
        }
    }
}

#[cfg(unix)]
trait PipeTo {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait>;
}

#[cfg(unix)]
impl PipeTo for Command {
    fn pipe_to(&mut self, out: &[&OsStr], err: Option<&[&OsStr]>) -> io::Result<Wait> {
        use std::os::unix::io::{AsRawFd, FromRawFd};

        self.stdout(Stdio::piped());
        if err.is_some() {
            self.stderr(Stdio::piped());
        }

        let child = self.spawn()?;

        *self = Command::new(out[0]);
        self.args(&out[1..]);
        self.stdin(unsafe {
            Stdio::from_raw_fd(child.stdout.as_ref().map(AsRawFd::as_raw_fd).unwrap())
        });

        match err {
            None => Ok(Wait(vec![child])),
            Some(err) => {
                let mut errcmd = Command::new(err[0]);
                errcmd.args(&err[1..]);
                errcmd.stdin(unsafe {
                    Stdio::from_raw_fd(child.stderr.as_ref().map(AsRawFd::as_raw_fd).unwrap())
                });
                errcmd.stdout(Stdio::null());
                errcmd.stderr(Stdio::inherit());
                let spawn = errcmd.spawn()?;
                Ok(Wait(vec![spawn, child]))
            }
        }
    }
}

// Based on https://github.com/rsolomo/cargo-check
fn wrap_args<I>(it: I, outfile: Option<&PathBuf>) -> Vec<OsString>
where
    I: IntoIterator<Item = OsString>,
{
    let mut args = vec!["rustc".into()];
    let mut ends_with_test = false;
    let mut ends_with_example = false;
    let mut has_color = false;

    let mut it = it.into_iter().skip(2);
    for arg in &mut it {
        if arg == *"--" {
            break;
        }
        ends_with_test = arg == *"--test";
        ends_with_example = arg == *"--example";
        has_color |= arg.to_str().unwrap_or("").starts_with("--color");
        args.push(arg.into());
    }

    if ends_with_test {
        // Expand the `test.rs` test by default.
        args.push("test".into());
    }

    if ends_with_example {
        // Expand the `example.rs` example by default.
        args.push("example".into());
    }

    if !has_color {
        let color = stderr_isatty();
        let setting = if color { "always" } else { "never" };
        args.push(format!("--color={}", setting).into());
    }

    args.push("--".into());
    if let Some(path) = outfile {
        args.push("-o".into());
        args.push(path.into());
    }
    args.push("-Zunstable-options".into());
    args.push("--pretty=expanded".into());
    args.extend(it);
    args
}

#[cfg(unix)]
fn which(cmd: &[&str]) -> Option<OsString> {
    if env::args_os().find(|arg| arg == "--help").is_some() {
        return None;
    }

    if let Some(which) = env::var_os(&cmd[0].to_uppercase()) {
        return if which.is_empty() { None } else { Some(which) };
    }

    let spawn = Command::new(cmd[0])
        .args(&cmd[1..])
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .spawn();
    let mut child = match spawn {
        Ok(child) => child,
        Err(_) => {
            return None;
        }
    };

    let exit = match child.wait() {
        Ok(exit) => exit,
        Err(_) => {
            return None;
        }
    };

    if exit.success() {
        Some(cmd[0].into())
    } else {
        None
    }
}

#[cfg(unix)]
fn filter_err(ignore: fn(&str) -> bool) -> ! {
    let mut line = String::new();
    while let Ok(n) = io::stdin().read_line(&mut line) {
        if n == 0 {
            break;
        }
        if !ignore(&line) {
            let _ = write!(&mut io::stderr(), "{}", line);
        }
        line.clear();
    }
    process::exit(0);
}

#[cfg(unix)]
fn ignore_rustfmt_err(_line: &str) -> bool {
    true
}

#[cfg(unix)]
fn ignore_cargo_err(line: &str) -> bool {
    if line.trim().is_empty() {
        return true;
    }

    let blacklist = [
        "ignoring specified output filename because multiple outputs were \
         requested",
        "ignoring specified output filename for 'link' output because multiple \
         outputs were requested",
        "ignoring --out-dir flag due to -o flag.",
        "due to multiple output types requested, the explicitly specified \
         output file name will be adapted for each output type",
    ];
    for s in &blacklist {
        if line.contains(s) {
            return true;
        }
    }

    false
}
<|endoftext|>


<commit_before>extern crate ansi_term;
#[macro_use]
extern crate clap;
extern crate hyper;
extern crate libsnatch;
extern crate num_cpus;

use ansi_term::Colour::{Green, Yellow, Red};
use clap::{App, Arg};
use libsnatch::download::download_chunks;
use libsnatch::write::OutputFileWriter;
use libsnatch::util::prompt_user;
use libsnatch::filesize::format_filesize;
use libsnatch::cargo_helper::get_cargo_info;
use std::fs::{File, remove_file};
use std::path::Path;
use std::process::exit;

static DEFAULT_FILENAME: &'static str = "index.html";

fn main() {

    // Parse arguments

    let argparse = App::new("Snatch")
        .about("Snatch, a simple, fast and interruptable download accelerator, written in Rust.")
        .version(crate_version!())
        .arg(Arg::with_name("file")
                 .long("file")
                 .short("f")
                 .takes_value(true)
                 .help("The local file to save the remote content file"))
        .arg(Arg::with_name("threads")
                 .long("threads")
                 .short("t")
                 .takes_value(true)
                 .help("Threads which can use to download"))
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .short("d")
                 .help("Active the debug mode"))
        .arg(Arg::with_name("force")
                 .long("force")
                 .help("Assume Yes to all queries and do not prompt"))
        .arg(Arg::with_name("url")
            .index(1)
            //.multiple(true)
            .required(true))
        .get_matches();

    // Get informations from arguments

    let url = argparse.value_of("url").unwrap();

    let file = argparse
        .value_of("file")
        .unwrap_or_else(|| url.split('/').last().unwrap_or(DEFAULT_FILENAME));

    let threads: usize = value_t!(argparse, "threads", usize)
        .and_then(|v| if v != 0 {
                      Ok(v)
                  } else {
                      Err(clap::Error::with_description("Cannot download a file using 0 thread",
                                                        clap::ErrorKind::InvalidValue))
                  })
        .unwrap_or(num_cpus::get_physical());

    if argparse.is_present("debug") {
        println!("# [{}] version: {}",
                 Yellow.bold().paint("DEBUG_MODE"),
                 crate_version!());
        println!("# [{}] file: {}", Yellow.bold().paint("DEBUG_MODE"), file);
        println!("# [{}] threads: {}",
                 Yellow.bold().paint("DEBUG_MODE"),
                 threads);
    }

    let local_path = Path::new(&file);

    if local_path.exists() {
        if local_path.is_dir() {
            panic!(Red.bold()
                .paint("[ERROR] The local path to store the remote content is already exists, \
                        and is a directory!"));
        }
        if !argparse.is_present("force") {
            let user_input = prompt_user(Yellow.bold(),
                                         "[WARNING] The path to store the file already exists! \
                                          Do you want to override it? [y/N]");

            if !(user_input == "y" || user_input == "Y") {
                exit(0);
            }
        } else {
            println!("{}",
                     Yellow
                         .bold()
                         .paint("[WARNING] The path to store the file already exists! \
                                 It is going to be overriden."));
        }
    }

    let cargo_info = get_cargo_info(&url).expect("fail to parse url");
    println!("# Remote content length: {}",
             format_filesize(cargo_info.content_length));

    let local_file = File::create(local_path).expect("[ERROR] Cannot create a file !");

    local_file
        .set_len(cargo_info.content_length)
        .expect("[ERROR] Cannot extend file to download size!");
    let out_file = OutputFileWriter::new(local_file);

    if download_chunks(cargo_info, out_file, threads as u64, &url) {
        println!("{} Your download is available in {}",
                 Green.bold().paint("Done!"),
                 local_path.to_str().unwrap());
    } else {
        // If the file is not ok, delete it from the file system
        print!("{} An error occured - erasing file... ",
               Red.bold().paint("Failed!"));
        match remove_file(local_path) {
            Ok(_) => println!("done !"),
            Err(e) => println!("failed ({}) !", e),
        }
    }

}
<commit_msg>Code to prevent the user about monothreading<commit_after>extern crate ansi_term;
#[macro_use]
extern crate clap;
extern crate hyper;
extern crate libsnatch;
extern crate num_cpus;

use ansi_term::Colour::{Green, Yellow, Red};
use clap::{App, Arg};
use libsnatch::cargo_helper::get_cargo_info;
use libsnatch::download::download_chunks;
use libsnatch::filesize::format_filesize;
use libsnatch::util::prompt_user;
use libsnatch::write::OutputFileWriter;
use std::fs::{File, remove_file};
use std::path::Path;
use std::process::exit;

static DEFAULT_FILENAME: &'static str = "index.html";

fn main() {

    // Parse arguments

    let argparse = App::new("Snatch")
        .about("Snatch, a simple, fast and interruptable download accelerator, written in Rust.")
        .version(crate_version!())
        .arg(Arg::with_name("file")
                 .long("file")
                 .short("f")
                 .takes_value(true)
                 .help("The local file to save the remote content file"))
        .arg(Arg::with_name("threads")
                 .long("threads")
                 .short("t")
                 .takes_value(true)
                 .help("Threads which can use to download"))
        .arg(Arg::with_name("debug")
                 .long("debug")
                 .short("d")
                 .help("Active the debug mode"))
        .arg(Arg::with_name("force")
                 .long("force")
                 .help("Assume Yes to all queries and do not prompt"))
        .arg(Arg::with_name("url")
            .index(1)
            //.multiple(true)
            .required(true))
        .get_matches();

    // Get informations from arguments

    let url = argparse.value_of("url").unwrap();

    let file = argparse
        .value_of("file")
        .unwrap_or_else(|| url.split('/').last().unwrap_or(DEFAULT_FILENAME));

    // Check if multi-threaded download is possible
    let mut threads: usize = value_t!(argparse, "threads", usize)
        .and_then(|v| if v != 0 {
                      Ok(v)
                  } else {
                      Err(clap::Error::with_description("Cannot download a file using 0 thread",
                                                        clap::ErrorKind::InvalidValue))
                  })
        .unwrap_or(num_cpus::get_physical());

    if argparse.is_present("debug") {
        println!("# [{}] version: {}",
                 Yellow.bold().paint("DEBUG_MODE"),
                 crate_version!());
        println!("# [{}] file: {}", Yellow.bold().paint("DEBUG_MODE"), file);
        println!("# [{}] threads: {}",
                 Yellow.bold().paint("DEBUG_MODE"),
                 threads);
    }

    let local_path = Path::new(&file);

    if local_path.exists() {
        if local_path.is_dir() {
            panic!(Red.bold()
                .paint("[ERROR] The local path to store the remote content is already exists, \
                        and is a directory!"));
        }
        if !argparse.is_present("force") {
            let user_input = prompt_user(Yellow.bold(),
                                         "[WARNING] The path to store the file already exists! \
                                          Do you want to override it? [y/N]");

            if !(user_input == "y" || user_input == "Y") {
                exit(0);
            }
        } else {
            println!("{}",
                     Yellow
                         .bold()
                         .paint("[WARNING] The path to store the file already exists! \
                                 It is going to be overriden."));
        }
    }

    let cargo_info = get_cargo_info(&url).expect("fail to parse url");
    println!("# Remote content length: {}",
             format_filesize(cargo_info.content_length));

    let local_file = File::create(local_path).expect("[ERROR] Cannot create a file !");

    local_file
        .set_len(cargo_info.content_length)
        .expect("[ERROR] Cannot extend file to download size!");
    let out_file = OutputFileWriter::new(local_file);

    // If the server does not accept PartialContent status, download the remote file
    // using only one thread
    if !cargo_info.accept_partialcontent {
        println!("{}",
                 Yellow
                     .bold()
                     .paint("[WARNING] The remote server does not accept PartialContent status! \
                             Downloading the remote file using one thread."));
        threads = 1;
    }

    if download_chunks(cargo_info, out_file, threads as u64, &url) {
        println!("{} Your download is available in {}",
                 Green.bold().paint("Done!"),
                 local_path.to_str().unwrap());
    } else {
        // If the file is not ok, delete it from the file system
        print!("{} An error occured - erasing file... ",
               Red.bold().paint("Failed!"));
        match remove_file(local_path) {
            Ok(_) => println!("done !"),
            Err(e) => println!("failed ({}) !", e),
        }
    }

}
<|endoftext|>


<commit_before>struct AddressSpace {
    data: [u8; 0xFFFF],
}

impl AddressSpace {

    fn new() -> AddressSpace {
        AddressSpace { data: [0; 0xFFFF] }
    }

    fn read(&self, addr: u16) -> u8 {
        self.data[addr as usize]
    }

    fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        self.data.slice(addr as usize, (addr + bytes) as usize)
    }

    fn write(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }

}

struct Instr {
    opcode: u8,
    data: Vec<u8>,
    cycles: u32,
}

impl Instr {

    fn parse(reg: &mut RegData, rom: &AddressSpace) -> Instr {
        let opcode = rom.read(reg.advance_pc());
        Instr {
            opcode: opcode,
            data: Vec::new(),
            cycles: 4,
        }
    }

    fn opcode(&self) -> u8 {
        self.opcode
    }

    fn cycles(&self) -> u32 {
        self.cycles
    }

    fn param(&self, i: usize) -> u8 {
        self.data[i]
    }

    fn param_u16(&self, i: usize) -> u16 {
        (self.data[i] as u16) | ((self.data[i + 1] as u16) << 8)
    }

}

enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

#[derive(Copy)]
enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x100,
            flag: 0,
        }
    }

    fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = ((data & 0xFF00 >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.c = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    fn copy(&mut self, dst: Register, src: Register) {
        let data = self.read(src);
        self.write(dst, data);
    }

    fn copy_u16(&mut self, dst: Register, src: Register) {
        let data = self.read_u16(src);
        self.write_u16(dst, data);
    }

    fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

}

static GB_FREQUENCY: u32 = 4194304;

struct Cpu {
    reg: RegData,
    ram: AddressSpace,
    freq: u32,
    clock: u64,
    cycle_block: u32,
}

impl Cpu {

    fn new() -> Cpu {
        Cpu::new_with_freq(GB_FREQUENCY)
    }

    fn new_with_freq(freq: u32) -> Cpu {
        Cpu {
            reg: RegData::new(),
            ram: AddressSpace::new(),
            freq: freq,
            clock: 0,
            cycle_block: 0,
        }
    }

    fn do_cycle(&mut self) {
        self.clock += 1;
        if self.cycle_block > 0 {
            self.cycle_block -= 1;
        } else {
            let instr = Instr::parse(&mut self.reg, &self.ram);
            match instr.opcode() {
                _ => panic!("Instruction not implemented!"),
            }
        }
    }

}

fn main() {
    println!("Hello, world!");
}
<commit_msg>Implement 16-bit LE read/write to AddressSpace<commit_after>struct AddressSpace {
    data: [u8; 0xFFFF],
}

impl AddressSpace {

    fn new() -> AddressSpace {
        AddressSpace { data: [0; 0xFFFF] }
    }

    fn read(&self, addr: u16) -> u8 {
        self.data[addr as usize]
    }

    fn read_u16(&self, addr: u16) -> u16 {
        self.data[addr as usize] as u16 | ((self.data[addr as usize + 1] as u16) << 8)
    }

    fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        self.data.slice(addr as usize, (addr + bytes) as usize)
    }

    fn write(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }

    fn write_u16(&mut self, addr: u16, data: u16) {
        let lo = (data & 0xFF) as u8;
        let hi = ((data & 0xFF00) >> 8) as u8;
        self.data[addr as usize] = lo;
        self.data[addr as usize + 1] = hi;
    }

}

struct Instr {
    opcode: u8,
    data: Vec<u8>,
    cycles: u32,
}

impl Instr {

    fn parse(reg: &mut RegData, rom: &AddressSpace) -> Instr {
        let opcode = rom.read(reg.advance_pc());
        Instr {
            opcode: opcode,
            data: Vec::new(),
            cycles: 4,
        }
    }

    fn opcode(&self) -> u8 {
        self.opcode
    }

    fn cycles(&self) -> u32 {
        self.cycles
    }

    fn param(&self, i: usize) -> u8 {
        self.data[i]
    }

    fn param_u16(&self, i: usize) -> u16 {
        (self.data[i] as u16) | ((self.data[i + 1] as u16) << 8)
    }

}

enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

#[derive(Copy)]
enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x100,
            flag: 0,
        }
    }

    fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = ((data & 0xFF00 >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.c = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    fn copy(&mut self, dst: Register, src: Register) {
        let data = self.read(src);
        self.write(dst, data);
    }

    fn copy_u16(&mut self, dst: Register, src: Register) {
        let data = self.read_u16(src);
        self.write_u16(dst, data);
    }

    fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

}

static GB_FREQUENCY: u32 = 4194304;

struct Cpu {
    reg: RegData,
    ram: AddressSpace,
    freq: u32,
    clock: u64,
    cycle_block: u32,
}

impl Cpu {

    fn new() -> Cpu {
        Cpu::new_with_freq(GB_FREQUENCY)
    }

    fn new_with_freq(freq: u32) -> Cpu {
        Cpu {
            reg: RegData::new(),
            ram: AddressSpace::new(),
            freq: freq,
            clock: 0,
            cycle_block: 0,
        }
    }

    fn do_cycle(&mut self) {
        self.clock += 1;
        if self.cycle_block > 0 {
            self.cycle_block -= 1;
        } else {
            let instr = Instr::parse(&mut self.reg, &self.ram);
            match instr.opcode() {
                _ => panic!("Instruction not implemented!"),
            }
        }
    }

}

fn main() {
    println!("Hello, world!");
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate chrono;
extern crate chrono_humanize;
extern crate json;
extern crate requests;
extern crate pager;

mod crates;

use clap::{App, SubCommand, Arg, AppSettings, ArgMatches};
use pager::Pager;

const CARGO: &'static str = "cargo";

#[derive(Debug, PartialEq)]
enum Flag {
    Repository,
    Documentation,
    Downloads,
    Homepage,
    Default,
}

#[derive(Debug)]
struct Report {
    flags: Vec<Flag>,
    verbose: bool,
    json: bool,
    versions: usize,
    keywords: bool,
}

impl Report {
    pub fn new(info: &ArgMatches) -> Self {

        let mut flags: Vec<Flag> = vec![];
        if info.is_present("repository") {
            flags.push(Flag::Repository);
        }
        if info.is_present("documentation") {
            flags.push(Flag::Documentation);
        }
        if info.is_present("downloads") {
            flags.push(Flag::Downloads);
        }
        if info.is_present("homepage") {
            flags.push(Flag::Homepage);
        }

        if flags.is_empty() {
            flags.push(Flag::Default);
        }

        let versions = match info.occurrences_of("versions") {
            0 => 0, // No flags - nothing to do
            1 => 5, // Single -V - show 5 last versions
            _ => usize::max_value(), // All the other cases - show everything
        };

        Report {
            flags: flags,
            verbose: info.is_present("verbose"),
            json: info.is_present("json"),
            versions: versions,
            keywords: info.is_present("keywords"),
        }
    }

    pub fn report(&self, name: &str) -> Result<String, requests::Error> {
        let response = try!(query(name));
        let mut output = String::new();

        if self.json {
            output = output + &self.report_json(&response);
        } else if let Some(krate) = get_crate(&response) {
            if self.versions > 0 {
                output = output + &self.report_versions(&krate, self.versions);
            } else if self.keywords {
                output = output + &self.report_keywords(&krate);
            } else {
                output = output + &self.report_crate(&krate);
            }
        };
        Ok(output)
    }

    pub fn report_json(&self, response: &requests::Response) -> String {
        let mut output = String::new();
        if self.verbose {
            if let Ok(json) = response.json() {
                output = output + &format!("{:#}", json);
            }
        } else if let Some(json) = response.text() {
            output = output + json;
        }
        output
    }

    pub fn report_crate(&self, krate: &crates::Crate) -> String {
        let mut output = String::new();
        for flag in &self.flags {
            output = output +
                     &match *flag {
                Flag::Repository => krate.print_repository(self.verbose),
                Flag::Documentation => krate.print_documentation(self.verbose),
                Flag::Downloads => krate.print_downloads(self.verbose),
                Flag::Homepage => krate.print_homepage(self.verbose),
                Flag::Default => reportv(krate, self.verbose),
            }
        }
        output
    }

    pub fn report_versions(&self, krate: &crates::Crate, limit: usize) -> String {
        if limit > 0 {
            krate.print_last_versions(limit, self.verbose)
        } else {
            String::new()
        }
    }

    pub fn report_keywords(&self, krate: &crates::Crate) -> String {
        krate.print_keywords(self.verbose)
    }
}

fn reportv(krate: &crates::Crate, verbose: bool) -> String {
    if verbose {
        format!("{:#}", krate)
    } else {
        format!("{}", krate)
    }
}

fn query(krate: &str) -> requests::Result {
    requests::get(&format!("http://crates.io/api/v1/crates/{}", krate))
}

fn get_crate(response: &requests::Response) -> Option<crates::Crate> {
    response.json().ok().map(|k| crates::Crate::new(&k))
}

// use std::fmt;
// fn debug<T>(item: &T)
//     where T: fmt::Debug
// {
//     println!("{:#?}", item);
// }

fn main() {

    Pager::new().setup();

    let matches = App::new(CARGO)
        .bin_name(CARGO)
        .author(crate_authors!())
        .version(crate_version!())
        .about("Query crates.io registry for crates details")
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .subcommand(SubCommand::with_name("info")
            .setting(AppSettings::ArgRequiredElseHelp)
            .setting(AppSettings::TrailingVarArg)
            .arg(Arg::with_name("documentation")
                .short("d")
                .long("documentation")
                .help("Report documentation URL"))
            .arg(Arg::with_name("downloads")
                .short("D")
                .long("downloads")
                .help("Report number of crate downloads"))
            .arg(Arg::with_name("homepage")
                .short("H")
                .long("homepage")
                .help("Report home page URL"))
            .arg(Arg::with_name("repository")
                .short("r")
                .long("repository")
                .help("Report crate repository URL"))
            .arg(Arg::with_name("json")
                .short("j")
                .long("json")
                .help("Report raw JSON data from crates.io")
                .conflicts_with_all(&["documentation", "downloads", "homepage", "repository"]))
            .arg(Arg::with_name("verbose")
                .short("v")
                .long("verbose")
                .help("Report more details"))
            .arg(Arg::with_name("versions")
                .short("V")
                .long("versions")
                .multiple(true)
                .help("Report version history of the crate (5 last versions), twice for full \
                       history"))
            .arg_from_usage("<crate>... 'crate to query'"))
        .get_matches();

    if let Some(info) = matches.subcommand_matches("info") {
        if let Some(crates) = info.values_of("crate") {
            let rep = Report::new(info);
            for krate in crates {
                // debug(&krate);
                match rep.report(krate) {
                    Ok(text) => println!("\n{}\n", text),
                    Err(err) => println!("\n{}\n", err),
                };
            }
        }
    }
}
<commit_msg>Use https instead of http<commit_after>#[macro_use]
extern crate clap;
extern crate chrono;
extern crate chrono_humanize;
extern crate json;
extern crate requests;
extern crate pager;

mod crates;

use clap::{App, SubCommand, Arg, AppSettings, ArgMatches};
use pager::Pager;

const CARGO: &'static str = "cargo";

#[derive(Debug, PartialEq)]
enum Flag {
    Repository,
    Documentation,
    Downloads,
    Homepage,
    Default,
}

#[derive(Debug)]
struct Report {
    flags: Vec<Flag>,
    verbose: bool,
    json: bool,
    versions: usize,
    keywords: bool,
}

impl Report {
    pub fn new(info: &ArgMatches) -> Self {

        let mut flags: Vec<Flag> = vec![];
        if info.is_present("repository") {
            flags.push(Flag::Repository);
        }
        if info.is_present("documentation") {
            flags.push(Flag::Documentation);
        }
        if info.is_present("downloads") {
            flags.push(Flag::Downloads);
        }
        if info.is_present("homepage") {
            flags.push(Flag::Homepage);
        }

        if flags.is_empty() {
            flags.push(Flag::Default);
        }

        let versions = match info.occurrences_of("versions") {
            0 => 0, // No flags - nothing to do
            1 => 5, // Single -V - show 5 last versions
            _ => usize::max_value(), // All the other cases - show everything
        };

        Report {
            flags: flags,
            verbose: info.is_present("verbose"),
            json: info.is_present("json"),
            versions: versions,
            keywords: info.is_present("keywords"),
        }
    }

    pub fn report(&self, name: &str) -> Result<String, requests::Error> {
        let response = try!(query(name));
        let mut output = String::new();

        if self.json {
            output = output + &self.report_json(&response);
        } else if let Some(krate) = get_crate(&response) {
            if self.versions > 0 {
                output = output + &self.report_versions(&krate, self.versions);
            } else if self.keywords {
                output = output + &self.report_keywords(&krate);
            } else {
                output = output + &self.report_crate(&krate);
            }
        };
        Ok(output)
    }

    pub fn report_json(&self, response: &requests::Response) -> String {
        let mut output = String::new();
        if self.verbose {
            if let Ok(json) = response.json() {
                output = output + &format!("{:#}", json);
            }
        } else if let Some(json) = response.text() {
            output = output + json;
        }
        output
    }

    pub fn report_crate(&self, krate: &crates::Crate) -> String {
        let mut output = String::new();
        for flag in &self.flags {
            output = output +
                     &match *flag {
                Flag::Repository => krate.print_repository(self.verbose),
                Flag::Documentation => krate.print_documentation(self.verbose),
                Flag::Downloads => krate.print_downloads(self.verbose),
                Flag::Homepage => krate.print_homepage(self.verbose),
                Flag::Default => reportv(krate, self.verbose),
            }
        }
        output
    }

    pub fn report_versions(&self, krate: &crates::Crate, limit: usize) -> String {
        if limit > 0 {
            krate.print_last_versions(limit, self.verbose)
        } else {
            String::new()
        }
    }

    pub fn report_keywords(&self, krate: &crates::Crate) -> String {
        krate.print_keywords(self.verbose)
    }
}

fn reportv(krate: &crates::Crate, verbose: bool) -> String {
    if verbose {
        format!("{:#}", krate)
    } else {
        format!("{}", krate)
    }
}

fn query(krate: &str) -> requests::Result {
    requests::get(&format!("https://crates.io/api/v1/crates/{}", krate))
}

fn get_crate(response: &requests::Response) -> Option<crates::Crate> {
    response.json().ok().map(|k| crates::Crate::new(&k))
}

// use std::fmt;
// fn debug<T>(item: &T)
//     where T: fmt::Debug
// {
//     println!("{:#?}", item);
// }

fn main() {

    Pager::new().setup();

    let matches = App::new(CARGO)
        .bin_name(CARGO)
        .author(crate_authors!())
        .version(crate_version!())
        .about("Query crates.io registry for crates details")
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .subcommand(SubCommand::with_name("info")
            .setting(AppSettings::ArgRequiredElseHelp)
            .setting(AppSettings::TrailingVarArg)
            .arg(Arg::with_name("documentation")
                .short("d")
                .long("documentation")
                .help("Report documentation URL"))
            .arg(Arg::with_name("downloads")
                .short("D")
                .long("downloads")
                .help("Report number of crate downloads"))
            .arg(Arg::with_name("homepage")
                .short("H")
                .long("homepage")
                .help("Report home page URL"))
            .arg(Arg::with_name("repository")
                .short("r")
                .long("repository")
                .help("Report crate repository URL"))
            .arg(Arg::with_name("json")
                .short("j")
                .long("json")
                .help("Report raw JSON data from crates.io")
                .conflicts_with_all(&["documentation", "downloads", "homepage", "repository"]))
            .arg(Arg::with_name("verbose")
                .short("v")
                .long("verbose")
                .help("Report more details"))
            .arg(Arg::with_name("versions")
                .short("V")
                .long("versions")
                .multiple(true)
                .help("Report version history of the crate (5 last versions), twice for full \
                       history"))
            .arg_from_usage("<crate>... 'crate to query'"))
        .get_matches();

    if let Some(info) = matches.subcommand_matches("info") {
        if let Some(crates) = info.values_of("crate") {
            let rep = Report::new(info);
            for krate in crates {
                // debug(&krate);
                match rep.report(krate) {
                    Ok(text) => println!("\n{}\n", text),
                    Err(err) => println!("\n{}\n", err),
                };
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate regex;

use std::fs::File;
use std::process::{Command, Stdio};
use std::collections::BinaryHeap;
use std::fs;
use regex::Regex;
use std::io::{self, Read, Write};

#[derive(Debug)]
struct Testcase {
    input: String,
    output: String,
}

enum Error {
    Io(io::Error),
    TooManyInputs((BinaryHeap<String>, BinaryHeap<String>)),
    TooManyOutputs((BinaryHeap<String>, BinaryHeap<String>)),
}

impl std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

fn get_testcases() -> Result<Vec<Testcase>, Error> {
    let input_re = Regex::new(r"input.*").unwrap();
    let output_re = Regex::new(r"output.*").unwrap();

    let mut testcases = vec![];
    let mut inputs = BinaryHeap::new();
    let mut outputs = BinaryHeap::new();

    for entry in fs::read_dir(".")? {
        let path = entry?.path().into_os_string();
        if let Some(input) = input_re.captures(path.to_str().unwrap()) {
            inputs.push(input[0].to_string());
        }
        if let Some(output) = output_re.captures(path.to_str().unwrap()) {
            outputs.push(output[0].to_string());
        }
    }
    if inputs.len() < outputs.len() {
        return Err(Error::TooManyOutputs((inputs, outputs)));
    } else if inputs.len() > outputs.len() {
        return Err(Error::TooManyInputs((inputs, outputs)));
    }
    while !inputs.is_empty() {
        testcases.push(Testcase {
            input: inputs.pop().unwrap(),
            output: outputs.pop().unwrap(),
        });
    }
    Ok(testcases)
}

fn run_testcase(binary: &str, testcase: &Testcase) -> Result<(), io::Error> {
    let process = Command::new(binary).stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;
    let mut f = File::open(&testcase.input)?;
    let mut inp = String::new();
    f.read_to_string(&mut inp)?;
    process.stdin.unwrap().write_all(inp.as_bytes())?;

    let mut outf = File::open(&testcase.output)?;
    let mut out_expected = String::new();
    outf.read_to_string(&mut out_expected)?;

    let mut out = String::new();
    process.stdout.unwrap().read_to_string(&mut out)?;
    if out == out_expected {
        Ok(())
    } else {
        Err(io::Error::new(io::ErrorKind::Other,
                           format!("  Expected: '{}'
  Actual:   '{}'",
                                   out_expected,
                                   out)))
    }
}

fn main() {
    let binary = "./a.out";

    let mut failed_testcases = vec![];
    match get_testcases() {
        Ok(testcases) => {
            println!("{} testcases found", testcases.len());
            for testcase in testcases {
                match run_testcase(binary, &testcase) {
                    Ok(_) => print!("."),
                    Err(e) => {
                        failed_testcases.push((testcase, e));
                        print!("E");
                    }
                }
            }
            println!();
        }
        Err(Error::Io(e)) => println!("I/O error: {}", e),
        Err(Error::TooManyInputs((i, o))) => {
            println!("There are more inputs than outputs.
Inputs : {:?}
Outputs: {:?}",
                     i,
                     o);
        }
        Err(Error::TooManyOutputs((i, o))) => {
            println!("There are more outputs than inputs.
Inputs : {:?}
Outputs: {:?}",
                     i,
                     o);
        }
    }
    if !failed_testcases.is_empty() {
        println!("Failed testcases:");
        for (testcase, e) in failed_testcases {
            println!("{:?}:\n{}\n", testcase, e);
        }
    } else {
        println!("OK");
    }
}
<commit_msg>Hide stderr messages of running program<commit_after>extern crate regex;

use std::fs::File;
use std::process::{Command, Stdio};
use std::collections::BinaryHeap;
use std::fs;
use regex::Regex;
use std::io::{self, Read, Write};

#[derive(Debug)]
struct Testcase {
    input: String,
    output: String,
}

enum Error {
    Io(io::Error),
    TooManyInputs((BinaryHeap<String>, BinaryHeap<String>)),
    TooManyOutputs((BinaryHeap<String>, BinaryHeap<String>)),
}

impl std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

fn get_testcases() -> Result<Vec<Testcase>, Error> {
    let input_re = Regex::new(r"input.*").unwrap();
    let output_re = Regex::new(r"output.*").unwrap();

    let mut testcases = vec![];
    let mut inputs = BinaryHeap::new();
    let mut outputs = BinaryHeap::new();

    for entry in fs::read_dir(".")? {
        let path = entry?.path().into_os_string();
        if let Some(input) = input_re.captures(path.to_str().unwrap()) {
            inputs.push(input[0].to_string());
        }
        if let Some(output) = output_re.captures(path.to_str().unwrap()) {
            outputs.push(output[0].to_string());
        }
    }
    if inputs.len() < outputs.len() {
        return Err(Error::TooManyOutputs((inputs, outputs)));
    } else if inputs.len() > outputs.len() {
        return Err(Error::TooManyInputs((inputs, outputs)));
    }
    while !inputs.is_empty() {
        testcases.push(Testcase {
            input: inputs.pop().unwrap(),
            output: outputs.pop().unwrap(),
        });
    }
    Ok(testcases)
}

fn run_testcase(binary: &str, testcase: &Testcase) -> Result<(), io::Error> {
    let process = Command::new(binary).stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::null())
        .spawn()?;
    let mut f = File::open(&testcase.input)?;
    let mut inp = String::new();
    f.read_to_string(&mut inp)?;
    process.stdin.unwrap().write_all(inp.as_bytes())?;

    let mut outf = File::open(&testcase.output)?;
    let mut out_expected = String::new();
    outf.read_to_string(&mut out_expected)?;

    let mut out = String::new();
    process.stdout.unwrap().read_to_string(&mut out)?;
    if out == out_expected {
        Ok(())
    } else {
        Err(io::Error::new(io::ErrorKind::Other,
                           format!("  Expected: '{}'
  Actual:   '{}'",
                                   out_expected,
                                   out)))
    }
}

fn main() {
    let binary = "./a.out";

    let mut failed_testcases = vec![];
    match get_testcases() {
        Ok(testcases) => {
            println!("{} testcases found", testcases.len());
            for testcase in testcases {
                match run_testcase(binary, &testcase) {
                    Ok(_) => print!("."),
                    Err(e) => {
                        failed_testcases.push((testcase, e));
                        print!("E");
                    }
                }
            }
            println!();
        }
        Err(Error::Io(e)) => println!("I/O error: {}", e),
        Err(Error::TooManyInputs((i, o))) => {
            println!("There are more inputs than outputs.
Inputs : {:?}
Outputs: {:?}",
                     i,
                     o);
        }
        Err(Error::TooManyOutputs((i, o))) => {
            println!("There are more outputs than inputs.
Inputs : {:?}
Outputs: {:?}",
                     i,
                     o);
        }
    }
    if !failed_testcases.is_empty() {
        println!("Failed testcases:");
        for (testcase, e) in failed_testcases {
            println!("{:?}:\n{}\n", testcase, e);
        }
    } else {
        println!("OK");
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};

#[derive(Copy, Clone)]
enum Operator {
    Add,
    Subtract,
    Divide,
    Multiply,
    Mod,
    Power,
    Negate
}

#[derive(Clone)]
enum Token {
    LeftParen,
    RightParen,
    Comma,
    Operator{ operator: Operator, unary: bool, precedence: u32 },
    Function(String),
    Number(f64),
    None
}

fn get_variable(name: &str) -> f64 {
    match name {
        "pi"  => 3.1415926535,
        "tau" => 3.1415926535*2.0,
        "e"   => 2.7182818284,
        _ => 0.0
    }
}

fn run_function(name: &str, stack: &mut Vec<f64>) -> f64 {
    match name {
        "sin"  => get_param(stack).sin(),
        "cos"  => get_param(stack).cos(),
        "tan"  => get_param(stack).tan(),
        "abs"  => get_param(stack).abs(),
        "sign" => get_param(stack).signum(),
        "frac" => get_param(stack).fract(),
        "min"  => f64::min(get_param(stack), get_param(stack)),
        "max"  => f64::max(get_param(stack), get_param(stack)),
        "pow"  => get_param(stack).powf(get_param(stack)),
        "sqrt" => get_param(stack).sqrt(),
        "rad"  => get_param(stack).to_radians(),
        "deg"  => get_param(stack).to_degrees(),
        "add2" => get_param(stack) + get_param(stack),
        "add3" => get_param(stack) + get_param(stack) + get_param(stack),
        "add4" => get_param(stack) + get_param(stack) + get_param(stack) + get_param(stack),
        _ => 0.0
    }
}

fn is_numeric(c: char) -> bool {
    if c.is_digit(10) || c == '.' { true } else { false }
}

fn is_unary(last_token: &Token) -> bool {
    match *last_token {
        Token::LeftParen | Token::Comma | Token::Operator{..} | Token::None => true,
        _ => false
    }
}

fn push_token(token: Token, stack: &mut Vec<Token>, output: &mut Vec<Token>) -> Token {
    let ret = token.clone();
    match token {
        Token::LeftParen | Token::Function(_) => stack.push(token),
        Token::RightParen => {
            while stack.len() > 0 {
                let t = stack.pop().unwrap();
                match t {
                    Token::LeftParen => return ret,
                    _ => output.push(t)
                }
            }
            panic!("Mismatched parentheses");
        },
        Token::Operator{ unary, precedence: op_precedence, .. } => {
            if unary { stack.push(token) }
            else {
                while stack.len() > 0 {
                    match *stack.last().unwrap() {
                        Token::LeftParen | Token::RightParen => break,
                        Token::Operator{ precedence, .. } => if precedence < op_precedence { break },
                        _ => {}
                    }
                    output.push(stack.pop().unwrap());
                }
                stack.push(token);
            }
        },
        Token::Comma => {
            while stack.len() > 0 {
                match *stack.last().unwrap() {
                    Token::LeftParen => return ret,
                    _ => output.push(stack.pop().unwrap())
                }
            }
            panic!("Misplaced comma or mismatched parentheses");
        },
        Token::Number(_) => output.push(token),
        _ => {}
    }
    ret
}

fn parse(input: &str) -> Vec<Token> {
    enum ReadState {
        Number,
        Name,
        None
    }

    let mut read_state = ReadState::None;
    let mut current_str = String::new();
    let mut stack: Vec<Token> = Vec::new();
    let mut output: Vec<Token> = Vec::new();
    let mut last_token: Token = Token::None;

    for(i, c) in input.chars().enumerate() {
        loop {
            match read_state {
                ReadState::Number => {
                    if is_numeric(c) {
                        current_str.push(c);
                        if i+1 == input.len() {
                            last_token = push_token(Token::Number(current_str.parse().unwrap()), &mut stack, &mut output);
                        }
                        break;
                    }
                    else {
                        read_state = ReadState::None;
                        last_token = push_token(Token::Number(current_str.parse().unwrap()), &mut stack, &mut output);
                        current_str.clear();
                    }
                },
                ReadState::Name => {
                    if c.is_alphabetic() || is_numeric(c) {
                        current_str.push(c);
                        if i+1 == input.len() {
                            last_token = push_token(Token::Number(get_variable(&current_str)), &mut stack, &mut output);
                        }
                        break;
                    }
                    else if c == '(' {
                        read_state = ReadState::None;
                        last_token = push_token(Token::Function(current_str.clone()), &mut stack, &mut output);
                        current_str.clear();
                    }
                    else {
                        read_state = ReadState::None;
                        last_token = push_token(Token::Number(get_variable(&current_str)), &mut stack, &mut output);
                        current_str.clear();
                    }
                },
                ReadState::None => {
                    if is_numeric(c) {
                        read_state = ReadState::Number;
                        continue;
                    }
                    else if c.is_alphabetic() {
                        read_state = ReadState::Name;
                        continue;
                    }
                    else if c.is_whitespace() { break }
                    else {
                        let token = match c {
                            '(' => Token::LeftParen,
                            ')' => Token::RightParen,
                            '+' => if !is_unary(&last_token) { Token::Operator{ operator: Operator::Add, unary: false, precedence: 1 } }
                                else { Token::None },
                            '-' => if is_unary(&last_token) { Token::Operator{ operator: Operator::Negate, unary: true, precedence: 3 } }
                                else { Token::Operator{ operator: Operator::Subtract, unary: false, precedence: 1 } },
                            '/' => Token::Operator{ operator: Operator::Divide, unary: false, precedence: 2 },
                            '*' => Token::Operator{ operator: Operator::Multiply, unary: false, precedence: 2 },
                            '%' => Token::Operator{ operator: Operator::Mod, unary: false, precedence: 2 },
                            '^' => Token::Operator{ operator: Operator::Power, unary: false, precedence: 4 },
                            ',' => Token::Comma,
                            _ => panic!("Invalid character in expression")
                        };
                        last_token = push_token(token, &mut stack, &mut output);
                    }
                    break;
                }
            }
        }
    }
    while stack.len() > 0 {
        match *stack.last().unwrap() {
            Token::LeftParen | Token::RightParen => panic!("Mismatched parentheses!"),
            _ => output.push(stack.pop().unwrap())
        }
    }
    output
}

fn get_param(stack: &mut Vec<f64>) -> f64 {
    stack.pop().expect("Missing operand")
}

fn solve(tokens: Vec<Token>) -> f64 {
    let mut stack: Vec<f64> = Vec::new();
    for token in &tokens {
        let result: f64 = match *token {
            Token::Number(n) => n,
            Token::Operator{ operator, .. } => match operator {
                Operator::Add => get_param(&mut stack) + get_param(&mut stack),
                Operator::Subtract => {
                    let n = get_param(&mut stack);
                    get_param(&mut stack) - n
                }
                Operator::Multiply => get_param(&mut stack) * get_param(&mut stack),
                Operator::Divide => {
                    let n = get_param(&mut stack);
                    get_param(&mut stack) / n
                }
                Operator::Mod => {
                    let n = get_param(&mut stack) as u64;
                    ((get_param(&mut stack) as u64) % n) as f64
                }
                Operator::Negate => -get_param(&mut stack),
                Operator::Power => {
                    let n = get_param(&mut stack);
                    get_param(&mut stack).powf(n)
                }
            },
            Token::Function(ref name) => run_function(name, &mut stack),
            _ => 0.0
        };
        stack.push(result);
    }
    if stack.len() != 1 {
        panic!("Invalid expression");
    }
    *stack.last().unwrap()
}

fn solve_expression(input: &str) -> f64 {
    solve(parse(input))
}

fn main() {
    let args: Vec<_> = std::env::args().collect();
    if args.len() > 1 {
        println!("{}", solve_expression(&args[1]));
    }
    else {
        print!(">>> ");
        io::stdout().flush().unwrap();
        let mut input = String::new();
        io::stdin().read_line(&mut input).expect("Failed to read input");
        input.pop();
        println!("{}", solve_expression(&input));
    }
}

#[test]
fn long_expression() {
    assert_eq!(100.0, solve_expression(&String::from("
        ((abs(cos(((((--(abs((((1+1+(1+1)+1+1+(4*1))+1+(10-11))/10 * 10) % 9 - 10)^2-80+9))
        *10/10+(2*2 + 6)-5-2-(2+1))*2.00000000-5.6-4.400000000000000000000)-9)*pi))*10.0*
        sign(max(12.44343234, 11.84934))*add4(1.0, 2.0, -1.0, 1.0)/3)^2)+(2*2+2^2*2-2)-10")));
}
<commit_msg>Add error handling<commit_after>use std::io::{self, Write};

#[derive(Copy, Clone)]
enum Operator {
    Add,
    Subtract,
    Divide,
    Multiply,
    Modulus,
    Power,
    Negate
}

#[derive(Clone)]
enum Token {
    LeftParen,
    RightParen,
    Comma,
    Operator{ operator: Operator, unary: bool, precedence: u32 },
    Function(String),
    Number(f64),
    None
}

fn get_variable(name: &str) -> Option<f64> {
    match name {
        "pi"  => Some(3.1415926535),
        "tau" => Some(3.1415926535*2.0),
        "e"   => Some(2.7182818284),
        _ => None
    }
}

fn params(name: &str, stack: &mut Vec<f64>, args: usize) -> Result<Vec<f64>, String> {
    if stack.len() >= args {
        let index = stack.len() - args;
        Ok(stack.split_off(index))
    }
    else { Err(format!("Not enough parameters for function '{}'", name)) }
}

fn run_function(name: &str, p: &mut Vec<f64>) -> Result<f64, String> {
    match name {
        "sin"  => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].sin()),
            Err(msg) => Err(msg)
        },
        "cos" => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].cos()),
            Err(msg) => Err(msg)
        },
        "tan" => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].tan()),
            Err(msg) => Err(msg)
        },
        "abs" => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].abs()),
            Err(msg) => Err(msg)
        },
        "sign" => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].signum()),
            Err(msg) => Err(msg)
        },
        "frac" => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].fract()),
            Err(msg) => Err(msg)
        },
        "min" => match params(&name, p, 2) {
            Ok(v) => Ok(f64::min(v[0], v[1])),
            Err(msg) => Err(msg)
        },
        "max" => match params(&name, p, 2) {
            Ok(v) => Ok(f64::max(v[0], v[1])),
            Err(msg) => Err(msg)
        },
        "pow" => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].powf(v[1])),
            Err(msg) => Err(msg)
        },
        "sqrt" => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].sqrt()),
            Err(msg) => Err(msg)
        },
        "rad" => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].to_radians()),
            Err(msg) => Err(msg)
        },
        "deg" => match params(&name, p, 1) {
            Ok(v) => Ok(v[0].to_degrees()),
            Err(msg) => Err(msg)
        },
        "add2" => match params(&name, p, 2) {
            Ok(v) => Ok(v[0] + v[1]),
            Err(msg) => Err(msg)
        },
        "add3" => match params(&name, p, 3) {
            Ok(v) => Ok(v[0] + v[1] + v[2]),
            Err(msg) => Err(msg)
        },
        "add4" => match params(&name, p, 4) {
            Ok(v) => Ok(v[0] + v[1] + v[2] + v[3]),
            Err(msg) => Err(msg)
        },
        _ => Err(format!("Unknown function '{}'", name))
    }
}

fn push_token(token: Token, stack: &mut Vec<Token>, output: &mut Vec<Token>) -> Result<Token, String> {
    let ret = token.clone();
    match token {
        Token::LeftParen | Token::Function(_) => stack.push(token),
        Token::RightParen => {
            while stack.len() > 0 {
                let t = stack.pop().unwrap();
                match t {
                    Token::LeftParen => return Ok(ret),
                    _ => output.push(t)
                }
            }
            return Err(String::from("Mismatched parentheses"))
        },
        Token::Operator{ unary, precedence: op_precedence, .. } => {
            if unary { stack.push(token) }
            else {
                while stack.len() > 0 {
                    match *stack.last().unwrap() {
                        Token::LeftParen | Token::RightParen => break,
                        Token::Operator{ precedence, .. } => if precedence < op_precedence { break },
                        _ => {}
                    }
                    output.push(stack.pop().unwrap());
                }
                stack.push(token);
            }
        },
        Token::Comma => {
            while stack.len() > 0 {
                match *stack.last().unwrap() {
                    Token::LeftParen => return Ok(ret),
                    _ => output.push(stack.pop().unwrap())
                }
            }
            return Err(String::from("Mismatched comma or mismatched parentheses"))
        },
        Token::Number(_) => output.push(token),
        _ => {}
    }
    Ok(ret)
}

fn is_unary(last_token: &Token) -> bool {
    match *last_token {
        Token::LeftParen | Token::Comma | Token::Operator{..} | Token::None => true,
        _ => false
    }
}

fn parse(input: &str) -> Result<Vec<Token>, String> {
    enum ReadState {
        Number,
        Name,
        None
    }

    let mut read_state = ReadState::None;
    let mut current_str = String::new();
    let mut stack: Vec<Token> = Vec::new();
    let mut output: Vec<Token> = Vec::new();
    let mut last_token: Token = Token::None;

    for(i, c) in input.chars().enumerate() {
        loop {
            match read_state {
                ReadState::Number => {
                    if c.is_digit(10) || c == '.' {
                        current_str.push(c);
                        if i+1 == input.len() {
                            match push_token(Token::Number(current_str.parse().unwrap()), &mut stack, &mut output) {
                                Ok(token) => last_token = token,
                                Err(msg) => return Err(msg)
                            }
                            current_str.clear();
                        }
                        break;
                    }
                    else {
                        read_state = ReadState::None;
                        match push_token(Token::Number(current_str.parse().unwrap()), &mut stack, &mut output) {
                            Ok(token) => last_token = token,
                            Err(msg) => return Err(msg)
                        }
                        current_str.clear();
                    }
                },
                ReadState::Name => {
                    if c.is_alphabetic() || c.is_digit(10) {
                        current_str.push(c);
                        if i+1 == input.len() {
                            if let Some(val) = get_variable(&current_str) {
                                match push_token(Token::Number(val), &mut stack, &mut output) {
                                    Ok(token) => last_token = token,
                                    Err(msg) => return Err(msg)
                                }
                            }
                            else { return Err(format!("Unknown variable '{}'", current_str)) }
                            current_str.clear();
                        }
                        break;
                    }
                    else if c == '(' {
                        read_state = ReadState::None;
                        match push_token(Token::Function(current_str.clone()), &mut stack, &mut output) {
                            Ok(token) => last_token = token,
                            Err(msg) => return Err(msg)
                        }
                        current_str.clear();
                    }
                    else {
                        read_state = ReadState::None;
                        if let Some(val) = get_variable(&current_str) {
                            match push_token(Token::Number(val), &mut stack, &mut output) {
                                Ok(token) => last_token = token,
                                Err(msg) => return Err(msg)
                            }
                        }
                        else { return Err(format!("Unknown variable '{}'", current_str)) }
                        current_str.clear();
                    }
                },
                ReadState::None => {
                    if c.is_digit(10) || c == '.' {
                        read_state = ReadState::Number;
                        continue;
                    }
                    else if c.is_alphabetic() {
                        read_state = ReadState::Name;
                        continue;
                    }
                    else if c.is_whitespace() { break }
                    else {
                        if let Some(token) = match c {
                            '(' => Some(Token::LeftParen),
                            ')' => Some(Token::RightParen),
                            '+' => if !is_unary(&last_token) { Some(Token::Operator{ operator: Operator::Add, unary: false, precedence: 1 }) }
                                else { Some(Token::None) },
                            '-' => if is_unary(&last_token) { Some(Token::Operator{ operator: Operator::Negate, unary: true, precedence: 3 }) }
                                else { Some(Token::Operator{ operator: Operator::Subtract, unary: false, precedence: 1 }) },
                            '/' => Some(Token::Operator{ operator: Operator::Divide, unary: false, precedence: 2 }),
                            '*' => Some(Token::Operator{ operator: Operator::Multiply, unary: false, precedence: 2 }),
                            '%' => Some(Token::Operator{ operator: Operator::Modulus, unary: false, precedence: 2 }),
                            '^' => Some(Token::Operator{ operator: Operator::Power, unary: false, precedence: 4 }),
                            ',' => Some(Token::Comma),
                            _ => None
                        } {
                            match push_token(token, &mut stack, &mut output) {
                                Ok(token) => last_token = token,
                                Err(msg) => return Err(msg)
                            }
                        }
                        else { return Err(format!("Invalid character '{}' in expression", c)) }
                    }
                    break;
                }
            }
        }
    }
    while stack.len() > 0 {
        match *stack.last().unwrap() {
            Token::LeftParen | Token::RightParen => return Err(String::from("Mismatched parentheses")),
            _ => output.push(stack.pop().unwrap())
        }
    }
    Ok(output)
}

fn solve(tokens: Vec<Token>) -> Result<f64, String> {
    let mut stack: Vec<f64> = Vec::new();
    for token in &tokens {
        let result: f64;
        match *token {
            Token::Number(n) => result = n,
            Token::Operator{ operator, .. } => match operator {
                Operator::Add => {
                    if stack.len() >= 2 { result = stack.pop().unwrap() + stack.pop().unwrap() }
                    else { return Err(String::from("Add operator requires 2 operands")) }
                },
                Operator::Subtract => {
                    if stack.len() >= 2 {
                        let n = stack.pop().unwrap();
                        result = stack.pop().unwrap() - n;
                    }
                    else { return Err(String::from("Minus operator requires 2 operands")) }
                },
                Operator::Multiply => {
                    if stack.len() >= 2 { result = stack.pop().unwrap() * stack.pop().unwrap() }
                    else { return Err(String::from("Multiply operator requires 2 operands")) }
                },
                Operator::Divide => {
                    if stack.len() >= 2 {
                        let n = stack.pop().unwrap();
                        result = stack.pop().unwrap() / n;
                    }
                    else { return Err(String::from("Divide operator requires 2 operands")) }
                }
                Operator::Modulus => {
                    if stack.len() >= 2 {
                        let n = stack.pop().unwrap();
                        result = stack.pop().unwrap() % n;
                    }
                    else { return Err(String::from("Modulus operator requires 2 operands")) }
                }
                Operator::Negate =>  {
                    if stack.len() >= 1 { result = -stack.pop().unwrap() }
                    else { return Err(String::from("Negate operator has no operand")) }
                },
                Operator::Power => {
                    if stack.len() >= 2 {
                        let n = stack.pop().unwrap();
                        result = stack.pop().unwrap().powf(n);
                    }
                    else { return Err(String::from("Exponent operator requires 2 operands")) }
                }
            },
            Token::Function(ref name) => {
                match run_function(name, &mut stack) {
                    Ok(value) => result = value,
                    Err(msg) => return Err(msg)
                }
            },
            _ => return Err(String::from("Invalid expression"))
        };
        stack.push(result);
    }
    if stack.len() != 1 { return Err(String::from("Invalid expression")) }
    Ok(*stack.last().unwrap())
}

fn solve_expression(input: &str) -> Result<f64, String> {
    match parse(input) {
        Ok(tokens) => solve(tokens),
        Err(msg) => Err(msg)
    }
}

fn main() {
    let mut input = String::new();
    let args: Vec<_> = std::env::args().collect();
    if args.len() > 1 {
        input = args[1].clone();
    }
    else {
        print!(">>> ");
        io::stdout().flush().unwrap();
        io::stdin().read_line(&mut input).expect("Failed to read input");
        input.pop();
    }
    match solve_expression(&input) {
        Ok(val) => println!("{}", val),
        Err(msg) => println!("Error: {}", msg)
    }
}

#[test]
fn long_expression() {
    assert_eq!(Ok(100.0), solve_expression(&String::from("
        ((abs(cos(((((--(abs((((1+1+(1+1)+1+1+(4*1))+1+(10-11))/10 * 10) % 9 - 10)^2-80+9))
        *10/10+(2*2 + 6)-5-2-(2+1))*2.00000000-5.6-4.400000000000000000000)-9)*pi))*10.0*
        sign(max(12.44343234, 11.84934))*add4(1.0, 2.0, -1.0, 1.0)/3)^2)+(2*2+2^2*2-2)-10")));
}
<|endoftext|>


<commit_before>#![feature(plugin, custom_attribute)]
#![plugin(async)]
// Run the following command to view expanded code
// cargo rustc --bin async_tests -- --pretty=expanded
// -Z unstable-options -o target/debug/main.expanded.rs

fn main() {}

#[async]
fn foo() -> Option<i32> {
//    let a = await!(test(1));
}

#[test]
fn test_async_fn_return_removed() {
	assert_eq!(foo(), ());
}

<commit_msg>Fix async_fn_removed test<commit_after>#![feature(plugin, custom_attribute)]
#![plugin(async)]
// Run the following command to view expanded code
// cargo rustc --bin async_tests -- --pretty=expanded
// -Z unstable-options -o target/debug/main.expanded.rs

fn main() {}

#[async]
fn foo() -> Option<i32> {
//    let a = await!(test(1));
}

#[test]
fn test_async_fn_return_removed() {
	assert_eq!(foo(&|res| {}), ());
}

<|endoftext|>