<commit_before>extern crate rustbox;

use rustbox::{Color, RustBox};

use keys::key_to_string;
use mode::ModeType;
use point::Point;
use state::{State,MicroState};

const BG_COLOR: Color = Color::Byte(234);
const FG_COLOR: Color = Color::Byte(0);
const BAR_BG_COLOR: Color = Color::Byte(237);
const BAR_FG_COLOR: Color = Color::Byte(233);
const BAR_BG_MODE_COLOR: Color = Color::Byte(26);
const BAR_HEIGHT: usize = 2;
const DEFAULT_MODE_COLOR: u16 = 220;

pub struct View<'a> {
    rustbox: &'a RustBox,
    /// Highest visible buffer line
    topline: usize,
    /// Leftmost visible buffer column
    leftcol: usize,
    /// Entire width (including bottom bar)
    width: usize,
    /// Entire height (including bottom bar)
    height: usize,
    /// Buffer window height
    window_height: usize,
    /// Buffer window width
    window_width: usize,
    /// Index of the last row before the bottom bar
    last_row: usize,
    /// The absolute cursor position (as oppose to the cursor position inside the buffer)
    cursor: Point,
}

/// The editor frontend.
///
/// Holds a reference to a `RustBox` instance created by the main app.
impl<'a> View<'a> {
    pub fn new(rustbox: &'a RustBox) -> View {
        View {
            rustbox: rustbox,
            topline: 0,
            leftcol: 0,
            width: 0,
            height: 0,
            window_height: 0,
            window_width: 0,
            last_row: 0,
            cursor: Point::new(0, 0),
        }
    }

    /// Renders the whole editor into the termbox: text, bottom bar, cursor... etc
    pub fn render(&mut self, state: &State) {
        self.height = state.height;
        self.width = state.width;
        self.window_height = state.height - BAR_HEIGHT;
        self.window_width = state.width - 1;
        self.last_row  = self.window_height - 1;

        if state.cursor.y < self.topline {
            self.topline = state.cursor.y;
        } else if state.cursor.y > self.last_row + self.topline {
            self.topline = state.cursor.y - self.last_row;
        }

        if state.cursor.x < self.leftcol {
            self.leftcol = state.cursor.x;
        } else if state.cursor.x > self.window_width + self.leftcol {
            self.leftcol = state.cursor.x - self.window_width
        }

        self.cursor = self.adjusted_cursor(state.cursor);

        self.rustbox.clear();
        self.fill_background(state);

        for (y, line) in state.buffer.borrow().data.iter().skip(self.topline).take(self.window_height).enumerate() {
            for (x, character) in line.chars().skip(self.leftcol).take(self.window_width + 1).enumerate() {
                if character == '\n' { continue };
                self.rustbox.print_char(x, y, rustbox::RB_NORMAL, FG_COLOR, BG_COLOR, character);
            }
        }

        let cursor = self.adjusted_cursor(state.cursor);
        self.rustbox.set_cursor(cursor.x as isize, cursor.y as isize);
        self.print_bar(state);

        self.rustbox.present();
    }

    /// The cursor passed by State is the absolute position in the text buffer.
    /// This adjusts the position by `topline` and `leftcol`. Used for scrolling.
    fn adjusted_cursor(&self, cursor: Point) -> Point {
        Point { x: cursor.x - self.leftcol, y: cursor.y - self.topline }
    }

    fn print_bar(&self, state: &State) {
        if !state.keystrokes.is_empty() {
            let keys: String = state.keystrokes.iter()
                .filter_map(|&k| key_to_string(k).or(None))
                .collect();
            self.rustbox.print(18, self.window_height, rustbox::RB_BOLD, Color::White, BAR_BG_COLOR, keys.as_ref());
        }

        self.print_coords(state);
        self.print_status(state);
        self.print_mode(state);
    }

    fn print_mode(&self, state: &State) {
        let mode = format!(" {}  ", state.mode.display());
        let color = Color::Byte(state.mode.color().unwrap_or(DEFAULT_MODE_COLOR));
        self.rustbox.print(0, self.window_height, rustbox::RB_BOLD, BAR_FG_COLOR, color, mode.as_ref());
    }

    fn print_coords(&self, state: &State) {
        let coords = format!("  {}:{}  ", state.cursor.y + 1, state.cursor.x);
        let color = Color::Byte(state.mode.color().unwrap_or(DEFAULT_MODE_COLOR));
        self.rustbox.print(self.window_width - coords.len(), self.window_height, rustbox::RB_BOLD, BAR_FG_COLOR, color, coords.as_ref());
    }

    fn print_status(&self, state: &State) {
        if let Some(status) = state.status.clone() {
            self.rustbox.print(0, self.window_height + 1, rustbox::RB_BOLD, Color::White, BG_COLOR, status.as_ref());
        }

        if state.microstate == MicroState::MiniBuffer {
            self.rustbox.print(0, self.window_height + 1, rustbox::RB_BOLD, Color::White, BG_COLOR, ":");
            self.rustbox.print(1, self.window_height + 1, rustbox::RB_BOLD, Color::White, BG_COLOR, state.minibuffer.as_ref());
        }
    }

    fn fill_background(&self, state: &State) {
        // Background
        for y in 0..self.rustbox.height() {
            for x in 0..self.rustbox.width() {
                self.rustbox.print(x, y, rustbox::RB_NORMAL, Color::White, BG_COLOR, " ");
            }
        }

        // Info bar
        let y = self.window_height;
        let bg_color = self.bar_bg_color(state);
        for x in 0..self.rustbox.width() {
            self.rustbox.print(x, y, rustbox::RB_NORMAL, Color::White, bg_color, " ");
        }
    }

    fn bar_bg_color(&self, state: &State) -> Color {
        if state.mode_type == ModeType::Normal {
            BAR_BG_COLOR
        } else {
            BAR_BG_MODE_COLOR
        }
    }
}
<commit_msg>Show cursor on minibuffer<commit_after>extern crate rustbox;

use rustbox::{Color, RustBox};

use keys::key_to_string;
use mode::ModeType;
use point::Point;
use state::{State,MicroState};

const BG_COLOR: Color = Color::Byte(234);
const FG_COLOR: Color = Color::Byte(0);
const BAR_BG_COLOR: Color = Color::Byte(237);
const BAR_FG_COLOR: Color = Color::Byte(233);
const BAR_BG_MODE_COLOR: Color = Color::Byte(26);
const BAR_HEIGHT: usize = 2;
const DEFAULT_MODE_COLOR: u16 = 220;

pub struct View<'a> {
    rustbox: &'a RustBox,
    /// Highest visible buffer line
    topline: usize,
    /// Leftmost visible buffer column
    leftcol: usize,
    /// Entire width (including bottom bar)
    width: usize,
    /// Entire height (including bottom bar)
    height: usize,
    /// Buffer window height
    window_height: usize,
    /// Buffer window width
    window_width: usize,
    /// Index of the last row before the bottom bar
    last_row: usize,
    /// The absolute cursor position (as oppose to the cursor position inside the buffer)
    cursor: Point,
}

/// The editor frontend.
///
/// Holds a reference to a `RustBox` instance created by the main app.
impl<'a> View<'a> {
    pub fn new(rustbox: &'a RustBox) -> View {
        View {
            rustbox: rustbox,
            topline: 0,
            leftcol: 0,
            width: 0,
            height: 0,
            window_height: 0,
            window_width: 0,
            last_row: 0,
            cursor: Point::new(0, 0),
        }
    }

    /// Renders the whole editor into the termbox: text, bottom bar, cursor... etc
    pub fn render(&mut self, state: &State) {
        self.height = state.height;
        self.width = state.width;
        self.window_height = state.height - BAR_HEIGHT;
        self.window_width = state.width - 1;
        self.last_row  = self.window_height - 1;

        if state.cursor.y < self.topline {
            self.topline = state.cursor.y;
        } else if state.cursor.y > self.last_row + self.topline {
            self.topline = state.cursor.y - self.last_row;
        }

        if state.cursor.x < self.leftcol {
            self.leftcol = state.cursor.x;
        } else if state.cursor.x > self.window_width + self.leftcol {
            self.leftcol = state.cursor.x - self.window_width
        }

        self.cursor = self.adjusted_cursor(state.cursor);

        self.rustbox.clear();
        self.fill_background(state);

        for (y, line) in state.buffer.borrow().data.iter().skip(self.topline).take(self.window_height).enumerate() {
            for (x, character) in line.chars().skip(self.leftcol).take(self.window_width + 1).enumerate() {
                if character == '\n' { continue };
                self.rustbox.print_char(x, y, rustbox::RB_NORMAL, FG_COLOR, BG_COLOR, character);
            }
        }

        self.print_cursor(state);
        self.print_bar(state);

        self.rustbox.present();
    }

    /// The cursor passed by State is the absolute position in the text buffer.
    /// This adjusts the position by `topline` and `leftcol`. Used for scrolling.
    fn adjusted_cursor(&self, cursor: Point) -> Point {
        Point { x: cursor.x - self.leftcol, y: cursor.y - self.topline }
    }

    fn print_bar(&self, state: &State) {
        if !state.keystrokes.is_empty() {
            let keys: String = state.keystrokes.iter()
                .filter_map(|&k| key_to_string(k).or(None))
                .collect();
            self.rustbox.print(18, self.window_height, rustbox::RB_BOLD, Color::White, BAR_BG_COLOR, keys.as_ref());
        }

        self.print_coords(state);
        self.print_status(state);
        self.print_mode(state);
    }

    fn print_mode(&self, state: &State) {
        let mode = format!(" {}  ", state.mode.display());
        let color = Color::Byte(state.mode.color().unwrap_or(DEFAULT_MODE_COLOR));
        self.rustbox.print(0, self.window_height, rustbox::RB_BOLD, BAR_FG_COLOR, color, mode.as_ref());
    }

    fn print_coords(&self, state: &State) {
        let coords = format!("  {}:{}  ", state.cursor.y + 1, state.cursor.x);
        let color = Color::Byte(state.mode.color().unwrap_or(DEFAULT_MODE_COLOR));
        self.rustbox.print(self.window_width - coords.len(), self.window_height, rustbox::RB_BOLD, BAR_FG_COLOR, color, coords.as_ref());
    }

    fn print_cursor(&self, state: &State) {
        if state.microstate == MicroState::MiniBuffer {
            self.rustbox.set_cursor(state.minibuffer.len() as isize + 1, self.height as isize);
        } else {
            let cursor = self.adjusted_cursor(state.cursor);
            self.rustbox.set_cursor(cursor.x as isize, cursor.y as isize);
        }
    }

    fn print_status(&self, state: &State) {
        if let Some(status) = state.status.clone() {
            self.rustbox.print(0, self.window_height + 1, rustbox::RB_BOLD, Color::White, BG_COLOR, status.as_ref());
        }

        if state.microstate == MicroState::MiniBuffer {
            self.rustbox.print(0, self.window_height + 1, rustbox::RB_BOLD, Color::White, BG_COLOR, ":");
            self.rustbox.print(1, self.window_height + 1, rustbox::RB_BOLD, Color::White, BG_COLOR, state.minibuffer.as_ref());
        }
    }

    fn fill_background(&self, state: &State) {
        // Background
        for y in 0..self.rustbox.height() {
            for x in 0..self.rustbox.width() {
                self.rustbox.print(x, y, rustbox::RB_NORMAL, Color::White, BG_COLOR, " ");
            }
        }

        // Info bar
        let y = self.window_height;
        let bg_color = self.bar_bg_color(state);
        for x in 0..self.rustbox.width() {
            self.rustbox.print(x, y, rustbox::RB_NORMAL, Color::White, bg_color, " ");
        }
    }

    fn bar_bg_color(&self, state: &State) -> Color {
        if state.mode_type == ModeType::Normal {
            BAR_BG_COLOR
        } else {
            BAR_BG_MODE_COLOR
        }
    }
}
<|endoftext|>


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

extern crate gcc;
extern crate build_helper;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::run;

fn main() {
    println!("cargo:rustc-cfg=cargobuild");

    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    if !target.contains("apple") && !target.contains("msvc") {
        build_libbacktrace(&host, &target);
    }

    if target.contains("unknown-linux") {
        if target.contains("musl") {
            println!("cargo:rustc-link-lib=static=unwind");
        } else {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("android") {
        println!("cargo:rustc-link-lib=dl");
        println!("cargo:rustc-link-lib=log");
        println!("cargo:rustc-link-lib=gcc");
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");

        if target.contains("rumprun") {
            println!("cargo:rustc-link-lib=unwind");
        } else if target.contains("netbsd") || target.contains("openbsd") {
            println!("cargo:rustc-link-lib=gcc");
        } else if target.contains("bitrig") {
            println!("cargo:rustc-link-lib=c++abi");
        } else if target.contains("dragonfly") {
            println!("cargo:rustc-link-lib=gcc_pic");
        }
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
    } else if target.contains("windows") {
        if target.contains("windows-gnu") {
            println!("cargo:rustc-link-lib=gcc_eh");
        }
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    }
}

fn build_libbacktrace(host: &str, target: &str) {
    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    println!("cargo:rustc-link-lib=static=backtrace");
    println!("cargo:rustc-link-search=native={}/.libs", build_dir.display());

    if fs::metadata(&build_dir.join(".libs/libbacktrace.a")).is_ok() {
        return
    }

    let compiler = gcc::Config::new().get_compiler();
    let ar = build_helper::cc2ar(compiler.path(), target);
    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                         .collect::<Vec<_>>().join(" ");
    run(Command::new("sh")
                .current_dir(&build_dir)
                .arg(src_dir.join("configure").to_str().unwrap()
                            .replace("C:\\", "/c/")
                            .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));
    run(Command::new("make")
                .current_dir(&build_dir)
                .arg(format!("INCDIR={}", src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").unwrap()));
}
<commit_msg>Rollup merge of #31985 - ashleysommer:libbackgrace_emscripten_fix, r=alexcrichton<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate gcc;
extern crate build_helper;

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::run;

fn main() {
    println!("cargo:rustc-cfg=cargobuild");

    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    if !target.contains("apple") && !target.contains("msvc") && !target.contains("emscripten"){
        build_libbacktrace(&host, &target);
    }

    if target.contains("unknown-linux") {
        if target.contains("musl") {
            println!("cargo:rustc-link-lib=static=unwind");
        } else {
            println!("cargo:rustc-link-lib=dl");
            println!("cargo:rustc-link-lib=rt");
            println!("cargo:rustc-link-lib=pthread");
            println!("cargo:rustc-link-lib=gcc_s");
        }
    } else if target.contains("android") {
        println!("cargo:rustc-link-lib=dl");
        println!("cargo:rustc-link-lib=log");
        println!("cargo:rustc-link-lib=gcc");
    } else if target.contains("freebsd") {
        println!("cargo:rustc-link-lib=execinfo");
        println!("cargo:rustc-link-lib=pthread");
        println!("cargo:rustc-link-lib=gcc_s");
    } else if target.contains("dragonfly") || target.contains("bitrig") ||
              target.contains("netbsd") || target.contains("openbsd") {
        println!("cargo:rustc-link-lib=pthread");

        if target.contains("rumprun") {
            println!("cargo:rustc-link-lib=unwind");
        } else if target.contains("netbsd") || target.contains("openbsd") {
            println!("cargo:rustc-link-lib=gcc");
        } else if target.contains("bitrig") {
            println!("cargo:rustc-link-lib=c++abi");
        } else if target.contains("dragonfly") {
            println!("cargo:rustc-link-lib=gcc_pic");
        }
    } else if target.contains("apple-darwin") {
        println!("cargo:rustc-link-lib=System");
    } else if target.contains("apple-ios") {
        println!("cargo:rustc-link-lib=System");
        println!("cargo:rustc-link-lib=objc");
        println!("cargo:rustc-link-lib=framework=Security");
        println!("cargo:rustc-link-lib=framework=Foundation");
    } else if target.contains("windows") {
        if target.contains("windows-gnu") {
            println!("cargo:rustc-link-lib=gcc_eh");
        }
        println!("cargo:rustc-link-lib=advapi32");
        println!("cargo:rustc-link-lib=ws2_32");
        println!("cargo:rustc-link-lib=userenv");
        println!("cargo:rustc-link-lib=shell32");
    }
}

fn build_libbacktrace(host: &str, target: &str) {
    let src_dir = env::current_dir().unwrap().join("../libbacktrace");
    let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());

    println!("cargo:rustc-link-lib=static=backtrace");
    println!("cargo:rustc-link-search=native={}/.libs", build_dir.display());

    if fs::metadata(&build_dir.join(".libs/libbacktrace.a")).is_ok() {
        return
    }

    let compiler = gcc::Config::new().get_compiler();
    let ar = build_helper::cc2ar(compiler.path(), target);
    let cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
                         .collect::<Vec<_>>().join(" ");
    run(Command::new("sh")
                .current_dir(&build_dir)
                .arg(src_dir.join("configure").to_str().unwrap()
                            .replace("C:\\", "/c/")
                            .replace("\\", "/"))
                .arg("--with-pic")
                .arg("--disable-multilib")
                .arg("--disable-shared")
                .arg("--disable-host-shared")
                .arg(format!("--host={}", build_helper::gnu_target(target)))
                .arg(format!("--build={}", build_helper::gnu_target(host)))
                .env("CC", compiler.path())
                .env("AR", &ar)
                .env("RANLIB", format!("{} s", ar.display()))
                .env("CFLAGS", cflags));
    run(Command::new("make")
                .current_dir(&build_dir)
                .arg(format!("INCDIR={}", src_dir.display()))
                .arg("-j").arg(env::var("NUM_JOBS").unwrap()));
}
<|endoftext|>


<commit_before>//
// gash.rs
// by Nathan Typanski
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{run, os};
use std::io::buffered::BufferedReader;
use std::io::{stdin, stdio, File, Truncate, Write};
use std::io::process::ProcessExit;
use std::io::signal::{Listener, Interrupt};
use std::path::posix::Path;
use std::option::Option;
use std::task::try;
use std::run::Process;
use std::run::ProcessOptions;
use std::comm::Port;

use extra::getopts;

use std::libc::types::os::arch::posix88::pid_t;
use std::libc::consts::os::posix88::{STDOUT_FILENO, STDIN_FILENO};
use std::libc;

extern {
  pub fn kill(pid: pid_t, sig: libc::c_int) -> libc::c_int;
}

// The basic unit for a command that could be run.
#[deriving(Clone)]
struct Cmd {
    program : ~str,
    argv : ~[~str],
}

impl Cmd {
    fn new(cmd_name: &str) -> Option<Cmd> {
        let mut argv: ~[~str] = split_words(cmd_name);
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            let argv : ~[~str] = argv;
            Some(Cmd {
                program : program,
                argv : argv,
            })
        }
        else {
            None
        }
    }
}

struct FgProcess {
    command     : ~str,
    args        : ~[~str],
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl FgProcess {
    fn new(cmd : Cmd,
           stdin : Option<i32>,
           stdout : Option<i32>)
        -> Option<FgProcess>
    {
        if (cmd_exists(&cmd)) {
            Some(FgProcess {
                command     : cmd.program.to_owned(),
                args        : cmd.argv.to_owned(),
                stdin       : stdin,
                stdout      : stdout,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<Process> {
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        let options = ProcessOptions {
            env    : None,
            dir    : None,
            in_fd  : self.stdin,
            out_fd : self.stdout,
            err_fd : None,
        };
        Process::new(command, args, options)
    }
}

// Background processes are handled differently, but not *that* differently:
// we need to keep track of an ProcessExit port for determining whether a
// process has finished running, as well as a pid for the process (for killing
// it when the shell terminates).
struct BgProcess {
    command      : ~str,
    args         : ~[~str],
    exit_port    : Option<Port<ProcessExit>>,
    pid          : Option<i32>,
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl BgProcess {
    fn new(cmd : Cmd) -> Option<BgProcess> {
        if (cmd_exists(&cmd)) {
            Some(BgProcess {
                command: cmd.program.to_owned(),
                args: cmd.argv.to_owned(),
                exit_port: None,
                pid: None,
                stdin: None,
                stdout: None,
            })
        }
        else { None }
    }

    fn run(&mut self) -> Option<pid_t> {
        // Process exit ports; used for checking dead status.
        let (port, chan): (Port<ProcessExit>, Chan<ProcessExit>) = Chan::new();
        // Process ports; these don't leave this function and are used for
        // sending the PID out in the return value.
        let (pidport, pidchan): (Port<Option<pid_t>>, Chan<Option<pid_t>>)
                            = Chan::new();
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        spawn(proc() {
            let options = ProcessOptions {
                env    : None,
                dir    : None,
                in_fd  : None,
                out_fd : None,
                err_fd : None,
            };
            let maybe_process = Process::new(command, args, options);
            match maybe_process {
                Some(mut process) => {
                    // Send the pid out for the return value
                    pidchan.try_send_deferred(Some(process.get_id()));
                    chan.try_send_deferred(process.finish());
                }
                None => {
                    pidchan.try_send_deferred(None);
                }
            }
        });
        self.exit_port = Some(port);
        self.pid = pidport.recv();
        self.pid
    }
}

struct Shell {
    cmd_prompt : ~str,
    history    : ~[~str],
    processes  : ~[~BgProcess],
    broken : bool,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
            processes: ~[],
            broken: false,
        }
    }

    fn start(&mut self) {
        // Setup the interrupt handler. Has to happen here, or it won't
        // retain control over interrupts.
        let mut listener = Listener::new();
        listener.register(Interrupt);
        let port = listener.port;
        spawn(proc() {
            try(proc() {
                loop {
                    match port.recv_opt() {
                        Some(Interrupt) => {
                        }
                        None => {
                            break;
                        }
                        _ => {
                        }
                    }
                }
                return 0
            });
            return ();
        });

        self.display_prompt();
    }

    fn display_prompt(&mut self) {
        // Standard input reader
        let mut stdin = BufferedReader::new(stdin());
        // Show the prompt
        print(self.cmd_prompt);
        stdio::flush();

        let line = stdin.read_line().unwrap();
        let cmd_line = line.trim().to_owned();
        let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
        self.disown_dead();

        // Push commands onto the history
        match program {
            "" => {}
            _  => {
                self.push_hist(cmd_line)
            }
        }

        match program {
            "" =>  {
                self.display_prompt();
            }
            "exit" =>  {
                self.kill_all();
            }
            "history" => {
                self.show_hist();
                self.display_prompt();
            }
            "jobs" => {
                self.jobs();
                self.display_prompt();
            }
            "cd" =>  {
                self.chdir(cmd_line);
                self.display_prompt();
            }
            _ => {
                self.run_cmdline(cmd_line);
                self.display_prompt();
            }
        }
    }

    // Nice extra feature: list running jobs.
    fn jobs(&mut self) {
        for cmd in self.processes.iter() {
            print!("{:s}", cmd.command);
            match cmd.pid {
                Some(pid) => {
                    println!(" {:i}", pid);
                }
                None => {
                    println("");
                }
            }
        }
    }

    // Remove dead processes from the list of processes.
    fn disown_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            borrowed_maybe(&cmd.exit_port, |port| match port.try_recv() {
                Some(_) => {dead.push(i); Some(i)},
                _ => None,
            });
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.pid {
                Some(pid) => {
                    unsafe {
                        // Kill perhaps isn't the best way to do this, but
                        // without it we have no way of killing our background
                        // processes with only the PID - we'd need the process
                        // object itself, and that can't be moved out of the
                        // spawn() that it's trapped inside.
                        kill(pid, 15);
                    }
                }
                None => {
                }
            }
        }
    }

    // Push a new command onto history.
    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] = split_words(cmd_line);
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    // Determine the type of the current block, and send it to the right
    // parsing function.
    fn run_cmdline(&mut self, cmd_line: &str) {
        if cmd_line.contains_char('>') {
            parse_r_redirect(cmd_line);
        }
        else if cmd_line.contains_char('<') {
            parse_l_redirect(cmd_line);
        }
        else {
            self.parse_process(cmd_line);
        }
    }

    // Parse a new lone process. Background/foreground it appropriately.
    fn parse_process(&mut self, cmd_line : &str) -> Option<Process>{
        maybe(Cmd::new(cmd_line), |cmd| {
            if (cmd.argv.len() > 0 && cmd.argv.last() == &~"&") {
                let mut argv = cmd.argv.to_owned();
                argv.pop();
                self.make_bg_process(Cmd{
                    program:cmd.program,
                    argv:argv});
                None
            }
            else {
                make_process(cmd, Some(STDIN_FILENO), Some(STDOUT_FILENO))
            }
        })
    }

    // background processes.
    fn make_bg_process(&mut self, cmd : Cmd) {
        let name = cmd.program.to_owned();
        match BgProcess::new(cmd) {
            Some(mut process) => {
                match process.run() {
                    Some(pid) => {
                        println!("{:s} {:i}", name, pid);
                        self.processes.push(~process);
                    }
                    None => {
                    }
                }
            }
            None => {
            }
        }
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
            Some(cmd_str) => {cmd_str.to_owned()},
            None          => {~""}
        };
        return Some(cmd_str);
    } else {
        return None;
    }
}

// Determine whether a command exists using "which".
fn cmd_exists(command : &Cmd) -> bool {
    let ret = run::process_output("which", [command.program.to_owned()]);
    return ret.expect("exit code error.").status.success();
}

fn split_words(word : &str) -> ~[~str] {
    word.split(' ').filter_map(
        |x| if x != "" { Some(x.to_owned()) } else { None }
        ).to_owned_vec()
}

fn make_process(cmd : Cmd,
                stdin: Option<i32>,
                stdout: Option<i32>) -> Option<run::Process> {
    maybe(FgProcess::new(cmd, stdin, stdout),
          |mut cmdprocess| cmdprocess.run())
}

fn parse_l_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('<').collect();
    let filename = pair[0].trim();
    match maybe(Cmd::new(pair[1].trim()), |c|
                make_process(c, None, Some(STDOUT_FILENO))) {
        Some(mut process) => {
            match File::open_mode(&Path::new(filename),
                                    std::io::Append,
                                    std::io::ReadWrite) {
                Some(file) => {
                    let proc_input = process.input();
                    let mut file_buffer = BufferedReader::new(file);
                    proc_input.write(file_buffer.read_to_end());
                }
                None => {
                }
            }
        }
        None => {
        }
    }
}

fn write_output_to_file(output : std::run::ProcessOutput,
                        filename : &str) {
    if output.status.success() {
        match File::open_mode(&Path::new(filename),
                                std::io::Truncate,
                                std::io::Write)
        {
            Some(mut file) => {
                file.write(output.output);
            }
            None =>{
                println!("Opening {:s} failed!", filename);
            }
        }
    }
    else {
        println!("{:?}", output.error);
    }
}

fn parse_r_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('>').collect();
    let file = pair[0].trim();
    let cmd = Cmd::new(pair[1].trim());
    match maybe(cmd, |c| make_process(c, None, None)) {
        Some(mut process) => {
            write_output_to_file(
                process.finish_with_output(),
                file);
        }
        None => {
        }
    }
}

// Describes a computation that could fail.
// If v is Some(...), then f is called on v and the result is returned.
// Otherwise, None is returned.
fn maybe<A, B>(v : Option<A>, f : |A| -> Option<B>) -> Option<B> {
    match v {
        Some(v) => f(v),
        None    => None,
    }
}

// Same as maybe(v, f), but for &v.
fn borrowed_maybe<A, B>(v : &Option<A>, f : |&A| -> Option<B>) -> Option<B> {
    match *v {
        Some(ref v) => f(v),
        None    => None,
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => {
            let mut shell = Shell::new("");
            shell.run_cmdline(cmd_line);
        }
        None => {
            let mut shell = Shell::new("gash > ");
            shell.start();
        }
    }
}
<commit_msg>simplifies Option<...> blocks everywhere<commit_after>//
// gash.rs
// by Nathan Typanski
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{run, os};
use std::io::buffered::BufferedReader;
use std::io::{stdin, stdio, File, Truncate, Write};
use std::io::process::ProcessExit;
use std::io::signal::{Listener, Interrupt};
use std::path::posix::Path;
use std::option::Option;
use std::task::try;
use std::run::Process;
use std::run::ProcessOptions;
use std::comm::Port;

use extra::getopts;

use std::libc::types::os::arch::posix88::pid_t;
use std::libc::consts::os::posix88::{STDOUT_FILENO, STDIN_FILENO};
use std::libc;

extern {
  pub fn kill(pid: pid_t, sig: libc::c_int) -> libc::c_int;
}

// The basic unit for a command that could be run.
#[deriving(Clone)]
struct Cmd {
    program : ~str,
    argv : ~[~str],
}

impl Cmd {
    fn new(cmd_name: &str) -> Option<Cmd> {
        let mut argv: ~[~str] = split_words(cmd_name);
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            let argv : ~[~str] = argv;
            cmd_exists(Cmd {
                program : program,
                argv : argv,
            })
        }
        else {
            None
        }
    }
}

struct FgProcess {
    command     : ~str,
    args        : ~[~str],
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl FgProcess {
    fn new(cmd : Cmd,
           stdin : Option<i32>,
           stdout : Option<i32>)
        -> FgProcess
    {
        FgProcess {
            command     : cmd.program.to_owned(),
            args        : cmd.argv.to_owned(),
            stdin       : stdin,
            stdout      : stdout,
        }
    }

    fn run(&mut self) -> Process {
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        let options = ProcessOptions {
            env    : None,
            dir    : None,
            in_fd  : self.stdin,
            out_fd : self.stdout,
            err_fd : None,
        };
        Process::new(command, args, options).expect("Couldn't run!")
    }
}

// Background processes are handled differently, but not *that* differently:
// we need to keep track of an ProcessExit port for determining whether a
// process has finished running, as well as a pid for the process (for killing
// it when the shell terminates).
struct BgProcess {
    command      : ~str,
    args         : ~[~str],
    exit_port    : Option<Port<ProcessExit>>,
    pid          : Option<i32>,
    stdin       : Option<i32>,
    stdout      : Option<i32>,
}
impl BgProcess {
    fn new(cmd : Cmd) -> BgProcess {
        BgProcess {
            command: cmd.program.to_owned(),
            args: cmd.argv.to_owned(),
            exit_port: None,
            pid: None,
            stdin: None,
            stdout: None,
        }
    }

    fn run(&mut self) -> Option<pid_t> {
        // Process exit ports; used for checking dead status.
        let (port, chan): (Port<ProcessExit>, Chan<ProcessExit>) = Chan::new();
        // Process ports; these don't leave this function and are used for
        // sending the PID out in the return value.
        let (pidport, pidchan): (Port<Option<pid_t>>, Chan<Option<pid_t>>)
                            = Chan::new();
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        spawn(proc() {
            let options = ProcessOptions {
                env    : None,
                dir    : None,
                in_fd  : None,
                out_fd : None,
                err_fd : None,
            };
            let maybe_process = Process::new(command, args, options);
            match maybe_process {
                Some(mut process) => {
                    // Send the pid out for the return value
                    pidchan.try_send_deferred(Some(process.get_id()));
                    chan.try_send_deferred(process.finish());
                }
                None => {
                    pidchan.try_send_deferred(None);
                }
            }
        });
        self.exit_port = Some(port);
        self.pid = pidport.recv();
        self.pid
    }
}

struct Shell {
    cmd_prompt : ~str,
    history    : ~[~str],
    processes  : ~[~BgProcess],
    broken : bool,
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
            processes: ~[],
            broken: false,
        }
    }

    fn start(&mut self) {
        // Setup the interrupt handler. Has to happen here, or it won't
        // retain control over interrupts.
        let mut listener = Listener::new();
        listener.register(Interrupt);
        let port = listener.port;
        spawn(proc() {
            try(proc() {
                loop {
                    match port.recv_opt() {
                        Some(Interrupt) => {
                        }
                        None => {
                            break;
                        }
                        _ => {
                        }
                    }
                }
                return 0
            });
            return ();
        });

        self.display_prompt();
    }

    fn display_prompt(&mut self) {
        // Standard input reader
        let mut stdin = BufferedReader::new(stdin());
        // Show the prompt
        print(self.cmd_prompt);
        stdio::flush();

        let line = stdin.read_line().unwrap();
        let cmd_line = line.trim().to_owned();
        let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
        self.disown_dead();

        // Push commands onto the history
        match program {
            "" => {}
            _  => {
                self.push_hist(cmd_line)
            }
        }

        match program {
            "" =>  {
                self.display_prompt();
            }
            "exit" =>  {
                self.kill_all();
            }
            "history" => {
                self.show_hist();
                self.display_prompt();
            }
            "jobs" => {
                self.jobs();
                self.display_prompt();
            }
            "cd" =>  {
                self.chdir(cmd_line);
                self.display_prompt();
            }
            _ => {
                self.run_cmdline(cmd_line);
                self.display_prompt();
            }
        }
    }

    // Nice extra feature: list running jobs.
    fn jobs(&mut self) {
        for cmd in self.processes.iter() {
            print!("{:s}", cmd.command);
            match cmd.pid {
                Some(pid) => {
                    println!(" {:i}", pid);
                }
                None => {
                    println("");
                }
            }
        }
    }

    // Remove dead processes from the list of processes.
    fn disown_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            borrowed_maybe(&cmd.exit_port, |port| match port.try_recv() {
                Some(_) => {dead.push(i); Some(i)},
                _ => None,
            });
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.pid {
                Some(pid) => {
                    unsafe {
                        // Kill perhaps isn't the best way to do this, but
                        // without it we have no way of killing our background
                        // processes with only the PID - we'd need the process
                        // object itself, and that can't be moved out of the
                        // spawn() that it's trapped inside.
                        kill(pid, 15);
                    }
                }
                None => {
                }
            }
        }
    }

    // Push a new command onto history.
    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] = split_words(cmd_line);
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    // Determine the type of the current block, and send it to the right
    // parsing function.
    fn run_cmdline(&mut self, cmd_line: &str) {
        if cmd_line.contains_char('>') {
            parse_r_redirect(cmd_line);
        }
        else if cmd_line.contains_char('<') {
            parse_l_redirect(cmd_line);
        }
        else {
            self.parse_process(cmd_line);
        }
    }

    // Parse a new lone process. Background/foreground it appropriately.
    fn parse_process(&mut self, cmd_line : &str) -> Option<Process> {
        maybe(Cmd::new(cmd_line), |cmd| {
                if (cmd.argv.len() > 0 && cmd.argv.last() == &~"&") {
                    let mut argv = cmd.argv.to_owned();
                    argv.pop();
                    self.make_bg_process(Cmd{
                        program:cmd.program,
                        argv:argv});
                    None
                }
                else {
                    Some(make_process(cmd, Some(STDIN_FILENO), Some(STDOUT_FILENO)))
                }
        })
    }

    // background processes.
    fn make_bg_process(&mut self, cmd : Cmd) {
        let name = cmd.program.to_owned();
        let mut process = BgProcess::new(cmd);
        match process.run() {
            Some(pid) => {
                println!("{:s} {:i}", name, pid);
                self.processes.push(~process);
            }
            None => {
            }
        }
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
            Some(cmd_str) => {cmd_str.to_owned()},
            None          => {~""}
        };
        return Some(cmd_str);
    } else {
        return None;
    }
}

// Determine whether a command exists using "which".
fn cmd_exists(cmd : Cmd) -> Option<Cmd> {
    let ret = run::process_output("which", [cmd.program.to_owned()]);
    if (ret.expect("exit code error.").status.success()) {
        Some(cmd)
    }
    else {
        None
    }
}

fn split_words(word : &str) -> ~[~str] {
    word.split(' ').filter_map(
        |x| if x != "" { Some(x.to_owned()) } else { None }
        ).to_owned_vec()
}

fn make_process(cmd : Cmd,
                stdin: Option<i32>,
                stdout: Option<i32>) -> run::Process {
    FgProcess::new(cmd, stdin, stdout).run()
}

fn parse_l_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('<').collect();
    let filename = pair[0].trim();
    match Cmd::new(pair[1].trim()) {
        Some(cmd) => {
            let mut process = make_process(cmd, None, Some(STDOUT_FILENO));
            match File::open_mode(&Path::new(filename),
                                    std::io::Append,
                                    std::io::ReadWrite) {
                Some(file) => {
                    let proc_input = process.input();
                    let mut file_buffer = BufferedReader::new(file);
                    proc_input.write(file_buffer.read_to_end());
                }
                None => {
                }
            }
        }
        None => {
        }
    }
}

fn write_output_to_file(output : std::run::ProcessOutput,
                        filename : &str) {
    if output.status.success() {
        match File::open_mode(&Path::new(filename),
                                std::io::Truncate,
                                std::io::Write)
        {
            Some(mut file) => {
                file.write(output.output);
            }
            None =>{
                println!("Opening {:s} failed!", filename);
            }
        }
    }
    else {
        println!("{:?}", output.error);
    }
}

fn parse_r_redirect(cmd_line : &str) {
    let pair : ~[&str] = cmd_line.rsplit('>').collect();
    let file = pair[0].trim();
    match Cmd::new(pair[1].trim()) {
        Some(cmd) => {
            let mut process = make_process(cmd, None, None);
            write_output_to_file(process.finish_with_output(), file);
        }
        None => {
        }
    }
}

// Describes a computation that could fail.
// If v is Some(...), then f is called on v and the result is returned.
// Otherwise, None is returned.
fn maybe<A, B>(v : Option<A>, f : |A| -> Option<B>) -> Option<B> {
    match v {
        Some(v) => f(v),
        None    => None,
    }
}

// Same as maybe(v, f), but for &v.
fn borrowed_maybe<A, B>(v : &Option<A>, f : |&A| -> Option<B>) -> Option<B> {
    match *v {
        Some(ref v) => f(v),
        None    => None,
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => {
            let mut shell = Shell::new("");
            shell.run_cmdline(cmd_line);
        }
        None => {
            let mut shell = Shell::new("gash > ");
            shell.start();
        }
    }
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::stdin;
use std::option::Option;
use std::io::process;
use std::io::{IoError, io_error};
use std::run::Process;
use std::io::process::ProcessExit;
use std::run::ProcessOptions;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    history: ~[~str],
    processes : ~[~BackgroundProcess],
}

struct CmdProcess {
    command: ~str,
    args: ~[~str],
    exit_status: Option<process::ProcessExit>,
}

struct BackgroundProcess {
    command: ~str,
    args: ~[~str],
    exit_status: Option<ProcessExit>,
    io_port: Option<Port<ProcessExit>>,
    kill_chan : Option<Chan<int>>,
}

trait Command {
    fn run(&mut self);
    fn cmd_exists(&mut self) -> bool;
//    fn is_running(&mut self) -> bool;
}

impl CmdProcess {
    fn new(program: &str, args: ~[~str]) -> CmdProcess {
        let cmd = CmdProcess {
            command: program.to_owned(),
            args: args.to_owned(),
            exit_status: None,
        };
        cmd
    }
}

impl BackgroundProcess {
    fn new(program: &str, args: ~[~str]) -> BackgroundProcess {
        let cmd = BackgroundProcess {
            command: program.to_owned(),
            args: args.to_owned(),
            exit_status: None,
            io_port: None,
            kill_chan: None,
        };
        cmd
    }
}

impl Command for CmdProcess {
    fn run(&mut self) {
        if self.cmd_exists() {
            self.exit_status = run::process_status(self.command, self.args);
        }
        else {
            println!("{:s}: command not found", self.command);
        }
    }

    fn cmd_exists(&mut self) -> bool {
        let ret = run::process_output("which", [self.command.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }
}

impl Command for BackgroundProcess {
    fn run(&mut self) {
        if self.cmd_exists() {
            let (port, chan) : (Port<ProcessExit>, Chan<ProcessExit>)
                    = Chan::new();
            let (killport, killchan) : (Port<int>, Chan<int>) = Chan::new();
            let command = self.command.to_owned();
            let args = self.args.to_owned();
            spawn(proc() {
                let options = ProcessOptions {
                    env : None,
                    dir : None,
                    in_fd : None,
                    out_fd : None,
                    err_fd : None,
                };
                let maybe_process = Process::new(command, args, options);
                match maybe_process {
                    Some(mut process) => {
                        let signal = killport.recv();
                        let mut error = None;
                        match signal {
                            9 => {
                                io_error::cond.trap(|e: IoError| {
                                    error = Some(e);
                                    }).inside(|| {
                                        process.force_destroy()
                                    })
                            }
                            15 => {
                                io_error::cond.trap(|e: IoError| {
                                    error = Some(e);
                                    }).inside(|| {
                                        process.force_destroy()
                                    })
                            }
                            _ => {}
                        }
                        chan.try_send_deferred(process.finish());
                    }
                    None => {
                    }
                }
            });
            self.io_port = Some(port);
            self.kill_chan = Some(killchan);
        }
        else {
            println!("{:s}: command not found", self.command);
        }
    }

    fn cmd_exists(&mut self) -> bool {
        let ret = run::process_output("which", [self.command.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
            processes: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            self.kill_dead();
            match program {
                "" => {}
                _  => { self.push_hist(cmd_line) }
            }
            match program {
                ""        =>  { continue; }
                "exit"    =>  {
                    self.kill_all();
                    return;
                }
                "history" =>  { self.show_hist(); }
                "cd"      =>  { self.chdir(cmd_line); }
                _         =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn kill_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            match cmd.io_port {
                Some(ref p) => {
                    match p.try_recv() {
                        Some (exitstatus) => {
                            if (exitstatus.success()) {
                                dead.push(i);
                            }
                        },
                        None => {}
                    }
                },
                None       => {},
            }
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.kill_chan {
                Some(ref kill_channel) => {
                    kill_channel.try_send_deferred(15);
                }
                None => {}
            }

        }
    }

    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            let program: ~str = argv.remove(0);
            if argv.len() > 0 {
                let last = argv.last().to_owned();
                if last == ~"&" {
                    argv.pop();
                    self.add_process(~BackgroundProcess::new(program, argv));
                }
                else {
                    CmdProcess::new(program, argv).run();
                }
            }
            else {
                CmdProcess::new(program, argv).run();
            }
        }
    }

    fn add_process(&mut self, mut process : ~BackgroundProcess) {
        &process.run();
        self.processes.push(process);
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>cleanup code<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::path::posix::Path;
use std::io::stdin;
use std::option::Option;
use std::io::process;
use std::io::{IoError, io_error};
use std::run::Process;
use std::io::process::ProcessExit;
use std::run::ProcessOptions;
use extra::getopts;

struct Shell {
    cmd_prompt : ~str,
    history    : ~[~str],
    processes  : ~[~BackgroundProcess],
}

struct CmdProcess {
    command     : ~str,
    args        : ~[~str],
    exit_status : Option<process::ProcessExit>,
}

struct BackgroundProcess {
    command      : ~str,
    args         : ~[~str],
    exit_status  : Option<ProcessExit>,
    exit_port    : Option<Port<ProcessExit>>,
    kill_chan    : Option<Chan<int>>,
}

fn cmd_exists(command : &str) -> bool {
    let ret = run::process_output("which", [command.to_owned()]);
    return ret.expect("exit code error.").status.success();
}

fn is_dead(exit_port : &Option<Port<ProcessExit>>) -> bool {
    let mut dead = false;
    match *exit_port {
        Some(ref p) => {
            match p.try_recv() {
                Some (exitstatus) => {
                    if (exitstatus.success()) {
                        dead = true;
                    }
                },
                _ => {}
            }
        },
        _ => {},
    };
    dead
}

trait Command {
    fn run(&mut self);
}

impl CmdProcess {
    fn new(command: &str, args: ~[~str]) -> Option<CmdProcess> {
        if (cmd_exists(command)) {
            Some(CmdProcess {
                command: command.to_owned(),
                args: args.to_owned(),
                exit_status: None,
            })
        }
        else { None }
    }
}

impl BackgroundProcess {
    fn new(command: &str, args: ~[~str]) -> Option<BackgroundProcess> {
        if (cmd_exists(command)) {
            Some(BackgroundProcess {
                command: command.to_owned(),
                args: args.to_owned(),
                exit_status: None,
                exit_port: None,
                kill_chan: None,
            })
        }
        else { None }
    }
}

impl Command for CmdProcess {
    fn run(&mut self) {
        self.exit_status = run::process_status(self.command, self.args);
    }
}

impl Command for BackgroundProcess {
    fn run(&mut self) {
        let (port, chan) : (Port<ProcessExit>, Chan<ProcessExit>)
                = Chan::new();
        let (killport, killchan) : (Port<int>, Chan<int>) = Chan::new();
        let command = self.command.to_owned();
        let args = self.args.to_owned();
        spawn(proc() {
            let options = ProcessOptions {
                env    : None,
                dir    : None,
                in_fd  : None,
                out_fd : None,
                err_fd : None,
            };
            let maybe_process = Process::new(command, args, options);
            match maybe_process {
                Some(mut process) => {
                    let signal = killport.recv();
                    let mut error = None;
                    match signal {
                        9 => {
                            io_error::cond.trap(|e: IoError| {
                                error = Some(e);
                                }).inside(|| {
                                    process.force_destroy()
                                })
                        }
                        15 => {
                            io_error::cond.trap(|e: IoError| {
                                error = Some(e);
                                }).inside(|| {
                                    process.force_destroy()
                                })
                        }
                        _ => {}
                    }
                    chan.try_send_deferred(process.finish());
                }
                None => {
                }
            }
        });
        self.exit_port = Some(port);
        self.kill_chan = Some(killchan);
    }

}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            history: ~[],
            processes: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let cmd_line = line.trim().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");
            self.kill_dead();
            match program {
                "" => {}
                _  => { self.push_hist(cmd_line) }
            }
            match program {
                ""        =>  { continue; }
                "exit"    =>  {
                    self.kill_all();
                    return;
                }
                "history" =>  { self.show_hist(); }
                "cd"      =>  { self.chdir(cmd_line); }
                _         =>  { self.run_cmdline(cmd_line); }
            }
        }
    }

    fn kill_dead(&mut self) {
        let mut dead : ~[uint];
        dead = ~[];
        let mut i = 0;
        for cmd in self.processes.iter() {
            if is_dead(&cmd.exit_port) {
                dead.push(i);
            }
            i += 1;
        }
        for &p in dead.iter() {
            self.processes.remove(p);
        }
    }

    fn kill_all(&mut self) {
        for p in self.processes.iter() {
            match p.kill_chan {
                Some(ref kill_channel) => {
                    kill_channel.try_send_deferred(15);
                }
                None => {}
            }

        }
    }

    fn push_hist(&mut self, cmd_line: &str) {
        &self.history.push(cmd_line.to_owned());
    }

    fn show_hist(&mut self) {
        println!("{:s}", self.get_hist());
    }

    fn get_hist(&mut self) -> ~str {
        let mut hist = ~"";
        for i in self.history.iter() {
            let s = i.to_owned();
            match hist {
                ~"" => { hist = s; }
                _   => { hist = hist + "\n" + s; }
            }
        }
        return hist
    }

    fn chdir(&mut self, cmd_line: &str) {
        let mut argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            argv.remove(0);
            let path = Path::new(argv[0]);
            os::change_dir(&path);
        }
    }

    fn run_cmdline(&mut self, cmd_line: &str) {
        let argv: ~[~str] =
            cmd_line.split(' ').filter_map(|x| if x != ""
                {
                    Some(x.to_owned())
                }
                else {
                    None
                }).to_owned_vec();
        if argv.len() > 0 {
            self.parse_process(argv);
        }
    }

    fn parse_process(&mut self, mut argv : ~[~str]) {
        let program: ~str = argv.remove(0);
        if argv.len() > 0 {
            let last = argv.last().to_owned();
            if last == ~"&" {
                argv.pop();
                self.make_bg_process(program, argv);
            }
            else {
                self.make_fg_process(program, argv);
            }
        }
        else {
            self.make_fg_process(program, argv);
        }
    }

    fn make_fg_process(&mut self, program : ~str, argv : ~[~str]) {
        match CmdProcess::new(program, argv) {
            Some(mut process) => { process.run(); }
            None              => { }
        }
    }

    fn make_bg_process(&mut self, program : ~str, argv : ~[~str]) {
        match BackgroundProcess::new(program, argv) {
            Some(process) => {self.add_process(~process);}
            None          => { }
        }
    }

    fn add_process(&mut self, mut process : ~BackgroundProcess) {
        &process.run();
        self.processes.push(process);
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                Some(cmd_str) => {cmd_str.to_owned()},
                None          => {~""}
        };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::new("").run_cmdline(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website <https://serde.rs/> for additional documentation and
//! usage examples.
//!
//! ## Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
//! attribute to automatically generate implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform the same speed as a handwritten serializer for the
//! specific selection of data structure and data format.
//!
//! ## Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
//! - [Postcard], a no\_std and embedded-systems friendly compact binary format.
//! - [CBOR], a Concise Binary Object Representation designed for small message
//!   size without the need for version negotiation.
//! - [YAML], a self-proclaimed human-friendly configuration language that ain't
//!   markup language.
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [RON], a Rusty Object Notation.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
//!   definition.
//! - [JSON5], a superset of JSON including some productions from ES5.
//! - [URL] query strings, in the x-www-form-urlencoded format.
//! - [Envy], a way to deserialize environment variables into Rust structs.
//!   *(deserialization only)*
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
//!   Rust structs. *(deserialization only)*
//! - [S-expressions], the textual representation of code and data used by the
//!   Lisp language family.
//! - [D-Bus]'s binary wire format.
//! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy serialization format.
//! - [DynamoDB Items], the format used by [rusoto_dynamodb] to transfer data to
//!   and from DynamoDB.
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Postcard]: https://github.com/jamesmunns/postcard
//! [CBOR]: https://github.com/enarx/ciborium
//! [YAML]: https://github.com/dtolnay/serde-yaml
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://github.com/toml-rs/toml
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [RON]: https://github.com/ron-rs/ron
//! [BSON]: https://github.com/mongodb/bson-rust
//! [Avro]: https://docs.rs/apache-avro
//! [JSON5]: https://github.com/callum-oakley/json5-rs
//! [URL]: https://docs.rs/serde_qs
//! [Envy]: https://github.com/softprops/envy
//! [Envy Store]: https://github.com/softprops/envy-store
//! [Cargo]: https://doc.rust-lang.org/cargo/reference/manifest.html
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html
//! [S-expressions]: https://github.com/rotty/lexpr-rs
//! [D-Bus]: https://docs.rs/zvariant
//! [FlexBuffers]: https://github.com/google/flatbuffers/tree/master/rust/flexbuffers
//! [DynamoDB Items]: https://docs.rs/serde_dynamo
//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb

////////////////////////////////////////////////////////////////////////////////

// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.147")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue:
//
//    https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(never_type))]
#![allow(unknown_lints, bare_trait_objects, deprecated)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy and clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
        unnested_or_patterns,
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
        semicolon_if_nothing_returned,
        // not available in our oldest supported compiler
        empty_enum,
        type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
        // integer and float ser/de requires these sorts of casts
        cast_possible_truncation,
        cast_possible_wrap,
        cast_sign_loss,
        // things are often more readable this way
        cast_lossless,
        module_name_repetitions,
        option_if_let_else,
        single_match_else,
        type_complexity,
        use_self,
        zero_prefixed_literal,
        // correctly used
        derive_partial_eq_without_eq,
        enum_glob_use,
        explicit_auto_deref,
        let_underscore_drop,
        map_err_ignore,
        new_without_default,
        result_unit_err,
        wildcard_imports,
        // not practical
        needless_pass_by_value,
        similar_names,
        too_many_lines,
        // preference
        doc_markdown,
        unseparated_literal_suffix,
        // false positive
        needless_doctest_main,
        // noisy
        missing_errors_doc,
        must_use_candidate,
    )
)]
// Rustc lints.
#![deny(missing_docs, unused_imports)]

////////////////////////////////////////////////////////////////////////////////

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

/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
    mod core {
        #[cfg(not(feature = "std"))]
        pub use core::*;
        #[cfg(feature = "std")]
        pub use std::*;
    }

    pub use self::core::{cmp, iter, mem, num, ptr, slice, str};
    pub use self::core::{f32, f64};
    pub use self::core::{i16, i32, i64, i8, isize};
    pub use self::core::{u16, u32, u64, u8, usize};

    pub use self::core::cell::{Cell, RefCell};
    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::num::Wrapping;
    pub use self::core::ops::Range;
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::borrow::{Cow, ToOwned};
    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::string::{String, ToString};
    #[cfg(feature = "std")]
    pub use std::string::{String, ToString};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::vec::Vec;
    #[cfg(feature = "std")]
    pub use std::vec::Vec;

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;
    #[cfg(feature = "std")]
    pub use std::boxed::Box;

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::{Rc, Weak as RcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::{Rc, Weak as RcWeak};

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::sync::{Arc, Weak as ArcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::{Arc, Weak as ArcWeak};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
    #[cfg(feature = "std")]
    pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CStr, CString, OsStr, OsString};
    #[cfg(feature = "std")]
    pub use std::hash::{BuildHasher, Hash};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::path::{Path, PathBuf};
    #[cfg(feature = "std")]
    pub use std::sync::{Mutex, RwLock};
    #[cfg(feature = "std")]
    pub use std::time::{SystemTime, UNIX_EPOCH};

    #[cfg(all(feature = "std", not(no_collections_bound), no_ops_bound))]
    pub use std::collections::Bound;

    #[cfg(not(no_core_reverse))]
    pub use self::core::cmp::Reverse;

    #[cfg(not(no_ops_bound))]
    pub use self::core::ops::Bound;

    #[cfg(not(no_range_inclusive))]
    pub use self::core::ops::RangeInclusive;

    #[cfg(all(feature = "std", not(no_std_atomic)))]
    pub use std::sync::atomic::{
        AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
        AtomicUsize, Ordering,
    };
    #[cfg(all(feature = "std", not(no_std_atomic64)))]
    pub use std::sync::atomic::{AtomicI64, AtomicU64};

    #[cfg(any(feature = "std", not(no_core_duration)))]
    pub use self::core::time::Duration;
}

// None of this crate's error handling needs the `From::from` error conversion
// performed implicitly by the `?` operator or the standard library's `try!`
// macro. This simplified macro gives a 5.5% improvement in compile time
// compared to standard `try!`, and 9% improvement compared to `?`.
macro_rules! try {
    ($expr:expr) => {
        match $expr {
            Ok(val) => val,
            Err(err) => return Err(err),
        }
    };
}

////////////////////////////////////////////////////////////////////////////////

#[macro_use]
mod macros;

#[macro_use]
mod integer128;

pub mod de;
pub mod ser;

#[doc(inline)]
pub use de::{Deserialize, Deserializer};
#[doc(inline)]
pub use ser::{Serialize, Serializer};

// Used by generated code and doc tests. Not public API.
#[doc(hidden)]
#[path = "private/mod.rs"]
pub mod __private;

#[allow(unused_imports)]
use self::__private as export;
#[allow(unused_imports)]
use self::__private as private;

#[path = "de/seed.rs"]
mod seed;

#[cfg(not(feature = "std"))]
mod std_error;

// Re-export #[derive(Serialize, Deserialize)].
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;

#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
mod actually_private {
    pub struct T;
}
<commit_msg>Update TOML link to a page that covers usage with serde<commit_after>//! # Serde
//!
//! Serde is a framework for ***ser***ializing and ***de***serializing Rust data
//! structures efficiently and generically.
//!
//! The Serde ecosystem consists of data structures that know how to serialize
//! and deserialize themselves along with data formats that know how to
//! serialize and deserialize other things. Serde provides the layer by which
//! these two groups interact with each other, allowing any supported data
//! structure to be serialized and deserialized using any supported data format.
//!
//! See the Serde website <https://serde.rs/> for additional documentation and
//! usage examples.
//!
//! ## Design
//!
//! Where many other languages rely on runtime reflection for serializing data,
//! Serde is instead built on Rust's powerful trait system. A data structure
//! that knows how to serialize and deserialize itself is one that implements
//! Serde's `Serialize` and `Deserialize` traits (or uses Serde's derive
//! attribute to automatically generate implementations at compile time). This
//! avoids any overhead of reflection or runtime type information. In fact in
//! many situations the interaction between data structure and data format can
//! be completely optimized away by the Rust compiler, leaving Serde
//! serialization to perform the same speed as a handwritten serializer for the
//! specific selection of data structure and data format.
//!
//! ## Data formats
//!
//! The following is a partial list of data formats that have been implemented
//! for Serde by the community.
//!
//! - [JSON], the ubiquitous JavaScript Object Notation used by many HTTP APIs.
//! - [Postcard], a no\_std and embedded-systems friendly compact binary format.
//! - [CBOR], a Concise Binary Object Representation designed for small message
//!   size without the need for version negotiation.
//! - [YAML], a self-proclaimed human-friendly configuration language that ain't
//!   markup language.
//! - [MessagePack], an efficient binary format that resembles a compact JSON.
//! - [TOML], a minimal configuration format used by [Cargo].
//! - [Pickle], a format common in the Python world.
//! - [RON], a Rusty Object Notation.
//! - [BSON], the data storage and network transfer format used by MongoDB.
//! - [Avro], a binary format used within Apache Hadoop, with support for schema
//!   definition.
//! - [JSON5], a superset of JSON including some productions from ES5.
//! - [URL] query strings, in the x-www-form-urlencoded format.
//! - [Envy], a way to deserialize environment variables into Rust structs.
//!   *(deserialization only)*
//! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into
//!   Rust structs. *(deserialization only)*
//! - [S-expressions], the textual representation of code and data used by the
//!   Lisp language family.
//! - [D-Bus]'s binary wire format.
//! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy serialization format.
//! - [DynamoDB Items], the format used by [rusoto_dynamodb] to transfer data to
//!   and from DynamoDB.
//!
//! [JSON]: https://github.com/serde-rs/json
//! [Postcard]: https://github.com/jamesmunns/postcard
//! [CBOR]: https://github.com/enarx/ciborium
//! [YAML]: https://github.com/dtolnay/serde-yaml
//! [MessagePack]: https://github.com/3Hren/msgpack-rust
//! [TOML]: https://docs.rs/toml
//! [Pickle]: https://github.com/birkenfeld/serde-pickle
//! [RON]: https://github.com/ron-rs/ron
//! [BSON]: https://github.com/mongodb/bson-rust
//! [Avro]: https://docs.rs/apache-avro
//! [JSON5]: https://github.com/callum-oakley/json5-rs
//! [URL]: https://docs.rs/serde_qs
//! [Envy]: https://github.com/softprops/envy
//! [Envy Store]: https://github.com/softprops/envy-store
//! [Cargo]: https://doc.rust-lang.org/cargo/reference/manifest.html
//! [AWS Parameter Store]: https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html
//! [S-expressions]: https://github.com/rotty/lexpr-rs
//! [D-Bus]: https://docs.rs/zvariant
//! [FlexBuffers]: https://github.com/google/flatbuffers/tree/master/rust/flexbuffers
//! [DynamoDB Items]: https://docs.rs/serde_dynamo
//! [rusoto_dynamodb]: https://docs.rs/rusoto_dynamodb

////////////////////////////////////////////////////////////////////////////////

// Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.147")]
// Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and
// discussion of these features please refer to this issue:
//
//    https://github.com/serde-rs/serde/issues/812
#![cfg_attr(feature = "unstable", feature(never_type))]
#![allow(unknown_lints, bare_trait_objects, deprecated)]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy and clippy_pedantic lints
#![cfg_attr(
    feature = "cargo-clippy",
    allow(
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704
        unnested_or_patterns,
        // clippy bug: https://github.com/rust-lang/rust-clippy/issues/7768
        semicolon_if_nothing_returned,
        // not available in our oldest supported compiler
        empty_enum,
        type_repetition_in_bounds, // https://github.com/rust-lang/rust-clippy/issues/8772
        // integer and float ser/de requires these sorts of casts
        cast_possible_truncation,
        cast_possible_wrap,
        cast_sign_loss,
        // things are often more readable this way
        cast_lossless,
        module_name_repetitions,
        option_if_let_else,
        single_match_else,
        type_complexity,
        use_self,
        zero_prefixed_literal,
        // correctly used
        derive_partial_eq_without_eq,
        enum_glob_use,
        explicit_auto_deref,
        let_underscore_drop,
        map_err_ignore,
        new_without_default,
        result_unit_err,
        wildcard_imports,
        // not practical
        needless_pass_by_value,
        similar_names,
        too_many_lines,
        // preference
        doc_markdown,
        unseparated_literal_suffix,
        // false positive
        needless_doctest_main,
        // noisy
        missing_errors_doc,
        must_use_candidate,
    )
)]
// Rustc lints.
#![deny(missing_docs, unused_imports)]

////////////////////////////////////////////////////////////////////////////////

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

/// A facade around all the types we need from the `std`, `core`, and `alloc`
/// crates. This avoids elaborate import wrangling having to happen in every
/// module.
mod lib {
    mod core {
        #[cfg(not(feature = "std"))]
        pub use core::*;
        #[cfg(feature = "std")]
        pub use std::*;
    }

    pub use self::core::{cmp, iter, mem, num, ptr, slice, str};
    pub use self::core::{f32, f64};
    pub use self::core::{i16, i32, i64, i8, isize};
    pub use self::core::{u16, u32, u64, u8, usize};

    pub use self::core::cell::{Cell, RefCell};
    pub use self::core::clone::{self, Clone};
    pub use self::core::convert::{self, From, Into};
    pub use self::core::default::{self, Default};
    pub use self::core::fmt::{self, Debug, Display};
    pub use self::core::marker::{self, PhantomData};
    pub use self::core::num::Wrapping;
    pub use self::core::ops::Range;
    pub use self::core::option::{self, Option};
    pub use self::core::result::{self, Result};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::borrow::{Cow, ToOwned};
    #[cfg(feature = "std")]
    pub use std::borrow::{Cow, ToOwned};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::string::{String, ToString};
    #[cfg(feature = "std")]
    pub use std::string::{String, ToString};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::vec::Vec;
    #[cfg(feature = "std")]
    pub use std::vec::Vec;

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::boxed::Box;
    #[cfg(feature = "std")]
    pub use std::boxed::Box;

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::rc::{Rc, Weak as RcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::rc::{Rc, Weak as RcWeak};

    #[cfg(all(feature = "rc", feature = "alloc", not(feature = "std")))]
    pub use alloc::sync::{Arc, Weak as ArcWeak};
    #[cfg(all(feature = "rc", feature = "std"))]
    pub use std::sync::{Arc, Weak as ArcWeak};

    #[cfg(all(feature = "alloc", not(feature = "std")))]
    pub use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
    #[cfg(feature = "std")]
    pub use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};

    #[cfg(feature = "std")]
    pub use std::{error, net};

    #[cfg(feature = "std")]
    pub use std::collections::{HashMap, HashSet};
    #[cfg(feature = "std")]
    pub use std::ffi::{CStr, CString, OsStr, OsString};
    #[cfg(feature = "std")]
    pub use std::hash::{BuildHasher, Hash};
    #[cfg(feature = "std")]
    pub use std::io::Write;
    #[cfg(feature = "std")]
    pub use std::path::{Path, PathBuf};
    #[cfg(feature = "std")]
    pub use std::sync::{Mutex, RwLock};
    #[cfg(feature = "std")]
    pub use std::time::{SystemTime, UNIX_EPOCH};

    #[cfg(all(feature = "std", not(no_collections_bound), no_ops_bound))]
    pub use std::collections::Bound;

    #[cfg(not(no_core_reverse))]
    pub use self::core::cmp::Reverse;

    #[cfg(not(no_ops_bound))]
    pub use self::core::ops::Bound;

    #[cfg(not(no_range_inclusive))]
    pub use self::core::ops::RangeInclusive;

    #[cfg(all(feature = "std", not(no_std_atomic)))]
    pub use std::sync::atomic::{
        AtomicBool, AtomicI16, AtomicI32, AtomicI8, AtomicIsize, AtomicU16, AtomicU32, AtomicU8,
        AtomicUsize, Ordering,
    };
    #[cfg(all(feature = "std", not(no_std_atomic64)))]
    pub use std::sync::atomic::{AtomicI64, AtomicU64};

    #[cfg(any(feature = "std", not(no_core_duration)))]
    pub use self::core::time::Duration;
}

// None of this crate's error handling needs the `From::from` error conversion
// performed implicitly by the `?` operator or the standard library's `try!`
// macro. This simplified macro gives a 5.5% improvement in compile time
// compared to standard `try!`, and 9% improvement compared to `?`.
macro_rules! try {
    ($expr:expr) => {
        match $expr {
            Ok(val) => val,
            Err(err) => return Err(err),
        }
    };
}

////////////////////////////////////////////////////////////////////////////////

#[macro_use]
mod macros;

#[macro_use]
mod integer128;

pub mod de;
pub mod ser;

#[doc(inline)]
pub use de::{Deserialize, Deserializer};
#[doc(inline)]
pub use ser::{Serialize, Serializer};

// Used by generated code and doc tests. Not public API.
#[doc(hidden)]
#[path = "private/mod.rs"]
pub mod __private;

#[allow(unused_imports)]
use self::__private as export;
#[allow(unused_imports)]
use self::__private as private;

#[path = "de/seed.rs"]
mod seed;

#[cfg(not(feature = "std"))]
mod std_error;

// Re-export #[derive(Serialize, Deserialize)].
//
// The reason re-exporting is not enabled by default is that disabling it would
// be annoying for crates that provide handwritten impls or data formats. They
// would need to disable default features and then explicitly re-enable std.
#[cfg(feature = "serde_derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "serde_derive")]
#[doc(hidden)]
pub use serde_derive::*;

#[cfg(all(not(no_serde_derive), any(feature = "std", feature = "alloc")))]
mod actually_private {
    pub struct T;
}
<|endoftext|>


<commit_before>use rand::XorShiftRng;
use player::Player;
use minimax::minimax;
use construct_field::construct_field;

#[test]
fn find_best_move() {
  let mut field = construct_field(
    "
    ........
    ........
    ...a....
    ..AaA...
    ...Aaa..
    ..A.A...
    ........
    ........
    "
  );
  let mut rng = XorShiftRng::new_unseeded();
  let pos1 = minimax(&mut field, Player::Red, &mut rng, 5);
  assert_eq!(pos1, Some(field.to_pos(5, 2)));
  let pos2 = minimax(&mut field, Player::Red, &mut rng, 6);
  assert_eq!(pos2, Some(field.to_pos(5, 2)));
  let pos3 = minimax(&mut field, Player::Red, &mut rng, 7);
  assert_eq!(pos3, Some(field.to_pos(5, 2)));
  let pos4 = minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos4, Some(field.to_pos(5, 2)));
}
<commit_msg>Correct test, fixes #5.<commit_after>use rand::XorShiftRng;
use player::Player;
use minimax::minimax;
use construct_field::construct_field;

#[test]
fn find_best_move() {
  // 8 is the minimum depth value to detect correct move in this test.
  // With depth 7 after 3 moves we might have this position:
  // ........
  // .....a..
  // ...a....
  // ..AaAAa.
  // ...Aaa?.
  // ..A.A?..
  // ........
  // ........
  // Question marks here are indicated trajectory that will be excluded
  // because it doesn't intersect any other trajectory with length 2.
  // Without this trajectory black player won't be able to find the escape.
  // So red player will think that he wins with move (5, 1).
  let mut field = construct_field(
    "
    ........
    ........
    ...a....
    ..AaA...
    ...Aaa..
    ..A.A...
    ........
    ........
    "
  );
  let mut rng = XorShiftRng::new_unseeded();
  let pos = minimax(&mut field, Player::Red, &mut rng, 8);
  assert_eq!(pos, Some(field.to_pos(5, 2)));
}
<|endoftext|>


<commit_before>use std::collections::{HashSet, VecDeque};
use plank_syntax::position::Spanned;
use ast::cfg::{Program, Function, Block, BlockId, BlockLink, BlockEnd, Instruction};
use CompileCtx;

fn function_block_chain(f: &Function) -> VecDeque<BlockId> {
    let mut blocks = VecDeque::new();
    let mut current = f.start_block;
    loop {
        blocks.push_back(current);
        match f.blocks[&current].link {
            BlockLink::Strong(next) |
            BlockLink::Weak(next) => current = next,
            BlockLink::None => break,
        }
    }
    blocks
}

fn report_unreachable(block: &Block, ctx: &mut CompileCtx) {
    if block.ops.is_empty() {
        return;
    }
    let mut span = Spanned::span(&block.ops[0]);
    for i in &block.ops {
        match *Spanned::value(i) {
            Instruction::StartStatement => {
                span = Spanned::span(i);
                break;
            }
            _ => {
                span = span.merge(Spanned::span(i));
            }
        }
    }
    ctx.reporter
        .warning("dead code detected", span)
        .span(span)
        .build();
}

fn analyze_function(f: &mut Function, ctx: &mut CompileCtx) {
    let mut blocks = function_block_chain(f);
    debug_assert_eq!(blocks.len(), f.blocks.len());
    let mut reachable = HashSet::new();
    let mut strong_reachable = None;
    let mut queue = VecDeque::new();
    queue.push_back(f.start_block);
    let mut follow_strong = false;
    while !queue.is_empty() {
        while let Some(block) = queue.pop_front() {
            if !reachable.contains(&block) {
                reachable.insert(block);
                let block = &f.blocks[&block];
                match block.end {
                    BlockEnd::Branch(_, a, b) => {
                        queue.push_back(a);
                        queue.push_back(b);
                    }
                    BlockEnd::Jump(next) => {
                        queue.push_back(next);
                    }
                    BlockEnd::Return(_) |
                    BlockEnd::Error => {}
                }
                if follow_strong {
                    if let BlockLink::Strong(next) = block.link {
                        queue.push_back(next);
                    }
                }
            }
        }
        if strong_reachable.is_none() {
            strong_reachable = Some(reachable.clone());
        }
        follow_strong = true;
        while let Some(block) = blocks.pop_front() {
            if !reachable.contains(&block) {
                report_unreachable(&f.blocks[&block], ctx);
                queue.push_back(block);
                break;
            }
        }
    }
    let strong_reachable = strong_reachable.unwrap();
    f.blocks.retain(|k, _| strong_reachable.contains(k));
}

pub(crate) fn remove_dead_code(program: &mut Program, ctx: &mut CompileCtx) {
    for (_, f)  in &mut program.functions {
        analyze_function(f, ctx);
    }
}
<commit_msg>report dead code after empty blocks<commit_after>use std::collections::{HashSet, VecDeque};
use plank_syntax::position::Spanned;
use ast::cfg::{Program, Function, Block, BlockId, BlockLink, BlockEnd, Instruction};
use CompileCtx;

fn function_block_chain(f: &Function) -> VecDeque<BlockId> {
    let mut blocks = VecDeque::new();
    let mut current = f.start_block;
    loop {
        blocks.push_back(current);
        match f.blocks[&current].link {
            BlockLink::Strong(next) |
            BlockLink::Weak(next) => current = next,
            BlockLink::None => break,
        }
    }
    blocks
}

fn report_unreachable(block: &Block, ctx: &mut CompileCtx) {
    let mut span = Spanned::span(&block.ops[0]);
    for i in &block.ops {
        match *Spanned::value(i) {
            Instruction::StartStatement => {
                span = Spanned::span(i);
                break;
            }
            _ => {
                span = span.merge(Spanned::span(i));
            }
        }
    }
    ctx.reporter
        .warning("dead code detected", span)
        .span(span)
        .build();
}

fn analyze_function(f: &mut Function, ctx: &mut CompileCtx) {
    let mut blocks = function_block_chain(f);
    debug_assert_eq!(blocks.len(), f.blocks.len());
    let mut reachable = HashSet::new();
    let mut strong_reachable = None;
    let mut queue = VecDeque::new();
    queue.push_back(f.start_block);
    let mut follow_strong = false;
    while !queue.is_empty() {
        while let Some(block) = queue.pop_front() {
            if !reachable.contains(&block) {
                reachable.insert(block);
                let block = &f.blocks[&block];
                match block.end {
                    BlockEnd::Branch(_, a, b) => {
                        queue.push_back(a);
                        queue.push_back(b);
                    }
                    BlockEnd::Jump(next) => {
                        queue.push_back(next);
                    }
                    BlockEnd::Return(_) |
                    BlockEnd::Error => {}
                }
                if follow_strong {
                    if let BlockLink::Strong(next) = block.link {
                        queue.push_back(next);
                    }
                }
            }
        }
        if strong_reachable.is_none() {
            strong_reachable = Some(reachable.clone());
        }
        follow_strong = true;
        while let Some(block) = blocks.pop_front() {
            if !reachable.contains(&block) && !f.blocks[&block].ops.is_empty() {
                report_unreachable(&f.blocks[&block], ctx);
                queue.push_back(block);
                break;
            }
        }
    }
    let strong_reachable = strong_reachable.unwrap();
    f.blocks.retain(|k, _| strong_reachable.contains(k));
}

pub(crate) fn remove_dead_code(program: &mut Program, ctx: &mut CompileCtx) {
    for (_, f)  in &mut program.functions {
        analyze_function(f, ctx);
    }
}
<|endoftext|>