<commit_before>use vga::{VGA};

pub use vga::Color;

// Defines the abstration of a window
#[derive(Copy, Clone)]
pub struct Window {
    height: usize,
    width: usize,
    pos: (usize, usize),
    cursor: (usize, usize), // position relative to the window
    vga: VGA,
}

impl Window {
    // TODO: fix this constructor
    pub fn new(w: usize, h: usize, pos: (usize, usize)) -> Window {
        Window {height: h, width: w, pos: pos, cursor: pos, vga: VGA::get_vga()}
    }

    // clear the screen
    pub fn clear_screen() {
        let mut buff = VGA::get_vga();
        buff.set_fg_color(Color::White);
        buff.set_bg_color(Color::Black);
        buff.clear_screen();
    }

    // paint the window
    pub fn paint(& mut self) {
        self.vga.fill_rect(self.pos, self.height, self.width);
    }

    // draw the character at the cursor relative to the corner of window
    pub fn put_char(& mut self, ch: char) {
        // check bounds
        let (cr, cc) = self.cursor;
        if cr < self.height && cc < self.width {
            self.vga.put_char(ch);
        }
    }

    pub fn put_str(& mut self, s: &str) {
        use core::str::StrExt;

        for ch in s.bytes() {
            // draw char
            self.put_char(ch as char);

            // move cursor
            let (cr, cc) = self.cursor;
            let next_cursor = if cc + 1 >= self.width {
                    (cr + 1, 0)
                } else {
                    (cr, cc + 1)
                };

            self.set_cursor(next_cursor);
        }
    }

    pub fn set_fg_color(& mut self, color: Color) {
        self.vga.set_fg_color(color);
    }

    pub fn set_bg_color(& mut self, color: Color) {
        self.vga.set_bg_color(color);
    }

    pub fn set_cursor(& mut self, pos: (usize, usize)) {
        self.cursor = pos;

        let (row,col) = self.pos;
        let (cr, cc) = self.cursor;

        self.vga.set_cursor((row+cr, col+cc));
    }
}
<commit_msg>Removed comment<commit_after>use vga::{VGA};

pub use vga::Color;

// Defines the abstration of a window
#[derive(Copy, Clone)]
pub struct Window {
    height: usize,
    width: usize,
    pos: (usize, usize),
    cursor: (usize, usize), // position relative to the window
    vga: VGA,
}

impl Window {
    pub fn new(w: usize, h: usize, pos: (usize, usize)) -> Window {
        Window {height: h, width: w, pos: pos, cursor: pos, vga: VGA::get_vga()}
    }

    // clear the screen
    pub fn clear_screen() {
        let mut buff = VGA::get_vga();
        buff.set_fg_color(Color::White);
        buff.set_bg_color(Color::Black);
        buff.clear_screen();
    }

    // paint the window
    pub fn paint(& mut self) {
        self.vga.fill_rect(self.pos, self.height, self.width);
    }

    // draw the character at the cursor relative to the corner of window
    pub fn put_char(& mut self, ch: char) {
        // check bounds
        let (cr, cc) = self.cursor;
        if cr < self.height && cc < self.width {
            self.vga.put_char(ch);
        }
    }

    pub fn put_str(& mut self, s: &str) {
        use core::str::StrExt;

        for ch in s.bytes() {
            // draw char
            self.put_char(ch as char);

            // move cursor
            let (cr, cc) = self.cursor;
            let next_cursor = if cc + 1 >= self.width {
                    (cr + 1, 0)
                } else {
                    (cr, cc + 1)
                };

            self.set_cursor(next_cursor);
        }
    }

    pub fn set_fg_color(& mut self, color: Color) {
        self.vga.set_fg_color(color);
    }

    pub fn set_bg_color(& mut self, color: Color) {
        self.vga.set_bg_color(color);
    }

    pub fn set_cursor(& mut self, pos: (usize, usize)) {
        self.cursor = pos;

        let (row,col) = self.pos;
        let (cr, cc) = self.cursor;

        self.vga.set_cursor((row+cr, col+cc));
    }
}
<|endoftext|>


<commit_before>use super::Position;
use super::Range;
use std::str::from_utf8;

pub struct GapBuffer {
    data: Vec<u8>,
    gap_start: usize,
    gap_length: usize,
}

pub fn new(mut data: String) -> GapBuffer {
    let mut bytes = data.into_bytes();
    let capacity = bytes.capacity();
    let gap_start = bytes.len();
    let gap_length = capacity - gap_start;
    unsafe {
        bytes.set_len(capacity);
    }
    GapBuffer{ data: bytes, gap_start: gap_start, gap_length: gap_length }
}

impl GapBuffer {
    // TODO: Return an optional error.
    pub fn insert(&mut self, data: &str, position: &Position) {
        // Ensure we have the capacity to insert this data.
        if data.len() > self.gap_length {
            // TODO: Move gap to the end before resizing buffer.
            self.data.reserve(data.len());
            let capacity = self.data.capacity();
            self.gap_length = capacity - self.gap_start;
            unsafe {
                self.data.set_len(capacity);
            }
        }

        let offset = match self.find_offset(position) {
            Some(o) => o,
            None => return,
        };

        self.move_gap(offset);
        self.write_to_gap(data);
    }

    pub fn to_string(&self) -> String {
        from_utf8(&self.data[..self.gap_start]).unwrap().to_string() + from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap()
    }

    // Maps a position to its offset equivalent in the data.
    fn find_offset(&self, position: &Position) -> Option<usize> {
        let first_half = from_utf8(&self.data[0..self.gap_start]).unwrap();
        let mut line = 0;
        let mut line_offset = 0;

        for char_index in first_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We haven't reached the position yet, so we'll move on to the other half.
        let second_half = from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap();
        for char_index in second_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(self.gap_start + self.gap_length + offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        None
    }

    fn move_gap(&mut self, offset: usize) {
        if offset < self.gap_start {
            for index in (offset..self.gap_start) {
                self.data[index + self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        } else if offset > self.gap_start {
            for index in (self.gap_start+self.gap_length..offset) {
                self.data[index-self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        }

        self.gap_start = offset;
    }

    fn write_to_gap(&mut self, data: &str) {
        for byte in data.bytes() {
            self.data[self.gap_start] = byte;
            self.gap_start+=1;
            self.gap_length-=1;
        }
    }
}

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

    #[test]
    fn insert_works() {
        let mut gb = new("This is a test.\nPlease be gentle.".to_string());
        gb.insert(" very", &Position { line: 1, offset: 9 });
        assert_eq!(gb.to_string(), "This is a test.\nPlease be very gentle.");
    }
}
<commit_msg>Update gap buffer to handle insertions at the end.<commit_after>use super::Position;
use super::Range;
use std::str::from_utf8;

pub struct GapBuffer {
    data: Vec<u8>,
    gap_start: usize,
    gap_length: usize,
}

pub fn new(mut data: String) -> GapBuffer {
    let mut bytes = data.into_bytes();
    let capacity = bytes.capacity();
    let gap_start = bytes.len();
    let gap_length = capacity - gap_start;
    unsafe {
        bytes.set_len(capacity);
    }
    GapBuffer{ data: bytes, gap_start: gap_start, gap_length: gap_length }
}

impl GapBuffer {
    // TODO: Return an optional error.
    pub fn insert(&mut self, data: &str, position: &Position) {
        // Ensure we have the capacity to insert this data.
        if data.len() > self.gap_length {
            // TODO: Move gap to the end before resizing buffer.
            self.data.reserve(data.len());
            let capacity = self.data.capacity();
            self.gap_length = capacity - self.gap_start;
            unsafe {
                self.data.set_len(capacity);
            }
        }

        let offset = match self.find_offset(position) {
            Some(o) => o,
            None => return,
        };

        self.move_gap(offset);
        self.write_to_gap(data);
    }

    pub fn to_string(&self) -> String {
        from_utf8(&self.data[..self.gap_start]).unwrap().to_string() + from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap()
    }

    // Maps a position to its offset equivalent in the data.
    fn find_offset(&self, position: &Position) -> Option<usize> {
        let first_half = from_utf8(&self.data[..self.gap_start]).unwrap();
        let mut line = 0;
        let mut line_offset = 0;

        for char_index in first_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        // We didn't find the position *within* the first half, but it could
        // be right after it, which means it's right at the start of the gap.
        if line == position.line && line_offset == position.offset {
            return Some(self.gap_start);
        }

        // We haven't reached the position yet, so we'll move on to the other half.
        let second_half = from_utf8(&self.data[self.gap_start+self.gap_length..]).unwrap();
        for char_index in second_half.char_indices() {
            let (offset, character) = char_index;

            // Check to see if we've found the position yet.
            if line == position.line && line_offset == position.offset {
                return Some(self.gap_start + self.gap_length + offset);
            }

            // Advance the line and offset characters.
            if character == '\n' {
                line+=1;
                line_offset = 0;
            } else {
                line_offset+=1;
            }
        }

        None
    }

    fn move_gap(&mut self, offset: usize) {
        if offset < self.gap_start {
            for index in (offset..self.gap_start) {
                self.data[index + self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        } else if offset > self.gap_start {
            for index in (self.gap_start+self.gap_length..offset) {
                self.data[index-self.gap_length] = self.data[index];
                self.data[index] = 0;
            }
        }

        self.gap_start = offset;
    }

    fn write_to_gap(&mut self, data: &str) {
        for byte in data.bytes() {
            self.data[self.gap_start] = byte;
            self.gap_start+=1;
            self.gap_length-=1;
        }
    }
}

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

    #[test]
    fn insert_works() {
        let mut gb = new("This is a test.\nPlease be gentle.".to_string());
        gb.insert(" very", &Position { line: 1, offset: 9 });
        assert_eq!(gb.to_string(), "This is a test.\nPlease be very gentle.");
    }

    #[test]
    fn inserting_at_the_end_works() {
        let mut gb = new("This is a test.".to_string());
        gb.insert(" Seriously.", &Position { line: 0, offset: 15 });
        assert_eq!(gb.to_string(), "This is a test. Seriously.");
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;
use std::io;
use std::num;
use std::process::{Output, ExitStatus};
use std::str;
use std::string;

use core::TargetKind;

use curl;
use git2;
use semver;
use serde_json;
use toml;
use registry;

error_chain! {
    types {
        CargoError, CargoErrorKind, CargoResultExt, CargoResult;
    }

    links {
        CrateRegistry(registry::Error, registry::ErrorKind);
    }

    foreign_links {
        ParseSemver(semver::ReqParseError);
        Semver(semver::SemVerError);
        Io(io::Error);
        SerdeJson(serde_json::Error);
        TomlSer(toml::ser::Error);
        TomlDe(toml::de::Error);
        ParseInt(num::ParseIntError);
        ParseBool(str::ParseBoolError);
        Parse(string::ParseError);
        Git(git2::Error);
        Curl(curl::Error);
    }

    errors {
        Internal(err: Box<CargoErrorKind>) {
            description(err.description())
            display("{}", *err)
        }
        ProcessErrorKind(proc_err: ProcessError) {
            description(&proc_err.desc)
            display("{}", &proc_err.desc)
        }
        CargoTestErrorKind(test_err: CargoTestError) {
            description(&test_err.desc)
            display("{}", &test_err.desc)
        }
        HttpNot200(code: u32, url: String) {
            description("failed to get a 200 response")
            display("failed to get 200 response from `{}`, got {}", url, code)
        }
    }
}

impl CargoError {
    pub fn into_internal(self) -> Self {
        CargoError(CargoErrorKind::Internal(Box::new(self.0)), self.1)
    }

    fn is_human(&self) -> bool {
        match &self.0 {
            &CargoErrorKind::Msg(_) => true,
            &CargoErrorKind::TomlSer(_) => true,
            &CargoErrorKind::TomlDe(_) => true,
            &CargoErrorKind::Curl(_) => true,
            &CargoErrorKind::HttpNot200(..) => true,
            &CargoErrorKind::ProcessErrorKind(_) => true,
            &CargoErrorKind::CrateRegistry(_) |
            &CargoErrorKind::ParseSemver(_) |
            &CargoErrorKind::Semver(_) |
            &CargoErrorKind::Io(_) |
            &CargoErrorKind::SerdeJson(_) |
            &CargoErrorKind::ParseInt(_) |
            &CargoErrorKind::ParseBool(_) |
            &CargoErrorKind::Parse(_) |
            &CargoErrorKind::Git(_) |
            &CargoErrorKind::Internal(_) |
            &CargoErrorKind::CargoTestErrorKind(_) => false
        }
    }
}

// =============================================================================
// Process errors
#[derive(Debug)]
pub struct ProcessError {
    pub desc: String,
    pub exit: Option<ExitStatus>,
    pub output: Option<Output>,
}

// =============================================================================
// Cargo test errors.

/// Error when testcases fail
#[derive(Debug)]
pub struct CargoTestError {
    pub test: Test,
    pub desc: String,
    pub exit: Option<ExitStatus>,
    pub causes: Vec<ProcessError>,
}

#[derive(Debug)]
pub enum Test {
    Multiple,
    Doc,
    UnitTest(TargetKind, String)
}

impl CargoTestError {
    pub fn new(test: Test, errors: Vec<ProcessError>) -> Self {
        if errors.is_empty() {
            panic!("Cannot create CargoTestError from empty Vec")
        }
        let desc = errors.iter().map(|error| error.desc.clone())
                                .collect::<Vec<String>>()
                                .join("\n");
        CargoTestError {
            test: test,
            desc: desc,
            exit: errors[0].exit,
            causes: errors,
        }
    }

    pub fn hint(&self) -> String {
        match &self.test {
            &Test::UnitTest(ref kind, ref name) => {
                match *kind {
                    TargetKind::Bench => format!("test failed, to rerun pass '--bench {}'", name),
                    TargetKind::Bin => format!("test failed, to rerun pass '--bin {}'", name),
                    TargetKind::Lib(_) => "test failed, to rerun pass '--lib'".into(),
                    TargetKind::Test => format!("test failed, to rerun pass '--test {}'", name),
                    TargetKind::ExampleBin | TargetKind::ExampleLib(_) =>
                        format!("test failed, to rerun pass '--example {}", name),
                    _ => "test failed.".into()
                }
            },
            &Test::Doc => "test failed, to rerun pass '--doc'".into(),
            _ => "test failed.".into()
        }
    }
}

// =============================================================================
// CLI errors

pub type CliResult = Result<(), CliError>;

#[derive(Debug)]
pub struct CliError {
    pub error: Option<CargoError>,
    pub unknown: bool,
    pub exit_code: i32
}

impl Error for CliError {
    fn description(&self) -> &str {
        self.error.as_ref().map(|e| e.description())
            .unwrap_or("unknown cli error")
    }

    fn cause(&self) -> Option<&Error> {
        self.error.as_ref().and_then(|e| e.cause())
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref error) = self.error {
            error.fmt(f)
        } else {
            self.description().fmt(f)
        }
    }
}

impl CliError {
    pub fn new(error: CargoError, code: i32) -> CliError {
        let human = &error.is_human();
        CliError { error: Some(error), exit_code: code, unknown: !human }
    }

    pub fn code(code: i32) -> CliError {
        CliError { error: None, exit_code: code, unknown: false }
    }
}

impl From<CargoError> for CliError {
    fn from(err: CargoError) -> CliError {
        CliError::new(err, 101)
    }
}

// =============================================================================
// Construction helpers

pub fn process_error(msg: &str,
                     status: Option<&ExitStatus>,
                     output: Option<&Output>) -> ProcessError
{
    let exit = match status {
        Some(s) => status_to_string(s),
        None => "never executed".to_string(),
    };
    let mut desc = format!("{} ({})", &msg, exit);

    if let Some(out) = output {
        match str::from_utf8(&out.stdout) {
            Ok(s) if !s.trim().is_empty() => {
                desc.push_str("\n--- stdout\n");
                desc.push_str(s);
            }
            Ok(..) | Err(..) => {}
        }
        match str::from_utf8(&out.stderr) {
            Ok(s) if !s.trim().is_empty() => {
                desc.push_str("\n--- stderr\n");
                desc.push_str(s);
            }
            Ok(..) | Err(..) => {}
        }
    }

    return ProcessError {
        desc: desc,
        exit: status.cloned(),
        output: output.cloned(),
    };

    #[cfg(unix)]
    fn status_to_string(status: &ExitStatus) -> String {
        use std::os::unix::process::*;
        use libc;

        if let Some(signal) = status.signal() {
            let name = match signal as libc::c_int {
                libc::SIGABRT => ", SIGABRT: process abort signal",
                libc::SIGALRM => ", SIGALRM: alarm clock",
                libc::SIGFPE => ", SIGFPE: erroneous arithmetic operation",
                libc::SIGHUP => ", SIGHUP: hangup",
                libc::SIGILL => ", SIGILL: illegal instruction",
                libc::SIGINT => ", SIGINT: terminal interrupt signal",
                libc::SIGKILL => ", SIGKILL: kill",
                libc::SIGPIPE => ", SIGPIPE: write on a pipe with no one to read",
                libc::SIGQUIT => ", SIGQUIT: terminal quite signal",
                libc::SIGSEGV => ", SIGSEGV: invalid memory reference",
                libc::SIGTERM => ", SIGTERM: termination signal",
                libc::SIGBUS => ", SIGBUS: access to undefined memory",
                #[cfg(not(target_os = "haiku"))]
                libc::SIGSYS => ", SIGSYS: bad system call",
                libc::SIGTRAP => ", SIGTRAP: trace/breakpoint trap",
                _ => "",
            };
            format!("signal: {}{}", signal, name)
        } else {
            status.to_string()
        }
    }

    #[cfg(windows)]
    fn status_to_string(status: &ExitStatus) -> String {
        status.to_string()
    }
}

pub fn internal<S: fmt::Display>(error: S) -> CargoError {
    _internal(&error)
}

fn _internal(error: &fmt::Display) -> CargoError {
    CargoError::from_kind(error.to_string().into()).into_internal()
}
<commit_msg>Auto merge of #4201 - alexcrichton:more-human, r=matklad<commit_after>use std::error::Error;
use std::fmt;
use std::io;
use std::num;
use std::process::{Output, ExitStatus};
use std::str;
use std::string;

use core::TargetKind;

use curl;
use git2;
use semver;
use serde_json;
use toml;
use registry;

error_chain! {
    types {
        CargoError, CargoErrorKind, CargoResultExt, CargoResult;
    }

    links {
        CrateRegistry(registry::Error, registry::ErrorKind);
    }

    foreign_links {
        ParseSemver(semver::ReqParseError);
        Semver(semver::SemVerError);
        Io(io::Error);
        SerdeJson(serde_json::Error);
        TomlSer(toml::ser::Error);
        TomlDe(toml::de::Error);
        ParseInt(num::ParseIntError);
        ParseBool(str::ParseBoolError);
        Parse(string::ParseError);
        Git(git2::Error);
        Curl(curl::Error);
    }

    errors {
        Internal(err: Box<CargoErrorKind>) {
            description(err.description())
            display("{}", *err)
        }
        ProcessErrorKind(proc_err: ProcessError) {
            description(&proc_err.desc)
            display("{}", &proc_err.desc)
        }
        CargoTestErrorKind(test_err: CargoTestError) {
            description(&test_err.desc)
            display("{}", &test_err.desc)
        }
        HttpNot200(code: u32, url: String) {
            description("failed to get a 200 response")
            display("failed to get 200 response from `{}`, got {}", url, code)
        }
    }
}

impl CargoError {
    pub fn into_internal(self) -> Self {
        CargoError(CargoErrorKind::Internal(Box::new(self.0)), self.1)
    }

    fn is_human(&self) -> bool {
        match &self.0 {
            &CargoErrorKind::Msg(_) => true,
            &CargoErrorKind::TomlSer(_) => true,
            &CargoErrorKind::TomlDe(_) => true,
            &CargoErrorKind::Curl(_) => true,
            &CargoErrorKind::HttpNot200(..) => true,
            &CargoErrorKind::ProcessErrorKind(_) => true,
            &CargoErrorKind::CrateRegistry(_) => true,
            &CargoErrorKind::ParseSemver(_) |
            &CargoErrorKind::Semver(_) |
            &CargoErrorKind::Io(_) |
            &CargoErrorKind::SerdeJson(_) |
            &CargoErrorKind::ParseInt(_) |
            &CargoErrorKind::ParseBool(_) |
            &CargoErrorKind::Parse(_) |
            &CargoErrorKind::Git(_) |
            &CargoErrorKind::Internal(_) |
            &CargoErrorKind::CargoTestErrorKind(_) => false
        }
    }
}

// =============================================================================
// Process errors
#[derive(Debug)]
pub struct ProcessError {
    pub desc: String,
    pub exit: Option<ExitStatus>,
    pub output: Option<Output>,
}

// =============================================================================
// Cargo test errors.

/// Error when testcases fail
#[derive(Debug)]
pub struct CargoTestError {
    pub test: Test,
    pub desc: String,
    pub exit: Option<ExitStatus>,
    pub causes: Vec<ProcessError>,
}

#[derive(Debug)]
pub enum Test {
    Multiple,
    Doc,
    UnitTest(TargetKind, String)
}

impl CargoTestError {
    pub fn new(test: Test, errors: Vec<ProcessError>) -> Self {
        if errors.is_empty() {
            panic!("Cannot create CargoTestError from empty Vec")
        }
        let desc = errors.iter().map(|error| error.desc.clone())
                                .collect::<Vec<String>>()
                                .join("\n");
        CargoTestError {
            test: test,
            desc: desc,
            exit: errors[0].exit,
            causes: errors,
        }
    }

    pub fn hint(&self) -> String {
        match &self.test {
            &Test::UnitTest(ref kind, ref name) => {
                match *kind {
                    TargetKind::Bench => format!("test failed, to rerun pass '--bench {}'", name),
                    TargetKind::Bin => format!("test failed, to rerun pass '--bin {}'", name),
                    TargetKind::Lib(_) => "test failed, to rerun pass '--lib'".into(),
                    TargetKind::Test => format!("test failed, to rerun pass '--test {}'", name),
                    TargetKind::ExampleBin | TargetKind::ExampleLib(_) =>
                        format!("test failed, to rerun pass '--example {}", name),
                    _ => "test failed.".into()
                }
            },
            &Test::Doc => "test failed, to rerun pass '--doc'".into(),
            _ => "test failed.".into()
        }
    }
}

// =============================================================================
// CLI errors

pub type CliResult = Result<(), CliError>;

#[derive(Debug)]
pub struct CliError {
    pub error: Option<CargoError>,
    pub unknown: bool,
    pub exit_code: i32
}

impl Error for CliError {
    fn description(&self) -> &str {
        self.error.as_ref().map(|e| e.description())
            .unwrap_or("unknown cli error")
    }

    fn cause(&self) -> Option<&Error> {
        self.error.as_ref().and_then(|e| e.cause())
    }
}

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref error) = self.error {
            error.fmt(f)
        } else {
            self.description().fmt(f)
        }
    }
}

impl CliError {
    pub fn new(error: CargoError, code: i32) -> CliError {
        let human = &error.is_human();
        CliError { error: Some(error), exit_code: code, unknown: !human }
    }

    pub fn code(code: i32) -> CliError {
        CliError { error: None, exit_code: code, unknown: false }
    }
}

impl From<CargoError> for CliError {
    fn from(err: CargoError) -> CliError {
        CliError::new(err, 101)
    }
}

// =============================================================================
// Construction helpers

pub fn process_error(msg: &str,
                     status: Option<&ExitStatus>,
                     output: Option<&Output>) -> ProcessError
{
    let exit = match status {
        Some(s) => status_to_string(s),
        None => "never executed".to_string(),
    };
    let mut desc = format!("{} ({})", &msg, exit);

    if let Some(out) = output {
        match str::from_utf8(&out.stdout) {
            Ok(s) if !s.trim().is_empty() => {
                desc.push_str("\n--- stdout\n");
                desc.push_str(s);
            }
            Ok(..) | Err(..) => {}
        }
        match str::from_utf8(&out.stderr) {
            Ok(s) if !s.trim().is_empty() => {
                desc.push_str("\n--- stderr\n");
                desc.push_str(s);
            }
            Ok(..) | Err(..) => {}
        }
    }

    return ProcessError {
        desc: desc,
        exit: status.cloned(),
        output: output.cloned(),
    };

    #[cfg(unix)]
    fn status_to_string(status: &ExitStatus) -> String {
        use std::os::unix::process::*;
        use libc;

        if let Some(signal) = status.signal() {
            let name = match signal as libc::c_int {
                libc::SIGABRT => ", SIGABRT: process abort signal",
                libc::SIGALRM => ", SIGALRM: alarm clock",
                libc::SIGFPE => ", SIGFPE: erroneous arithmetic operation",
                libc::SIGHUP => ", SIGHUP: hangup",
                libc::SIGILL => ", SIGILL: illegal instruction",
                libc::SIGINT => ", SIGINT: terminal interrupt signal",
                libc::SIGKILL => ", SIGKILL: kill",
                libc::SIGPIPE => ", SIGPIPE: write on a pipe with no one to read",
                libc::SIGQUIT => ", SIGQUIT: terminal quite signal",
                libc::SIGSEGV => ", SIGSEGV: invalid memory reference",
                libc::SIGTERM => ", SIGTERM: termination signal",
                libc::SIGBUS => ", SIGBUS: access to undefined memory",
                #[cfg(not(target_os = "haiku"))]
                libc::SIGSYS => ", SIGSYS: bad system call",
                libc::SIGTRAP => ", SIGTRAP: trace/breakpoint trap",
                _ => "",
            };
            format!("signal: {}{}", signal, name)
        } else {
            status.to_string()
        }
    }

    #[cfg(windows)]
    fn status_to_string(status: &ExitStatus) -> String {
        status.to_string()
    }
}

pub fn internal<S: fmt::Display>(error: S) -> CargoError {
    _internal(&error)
}

fn _internal(error: &fmt::Display) -> CargoError {
    CargoError::from_kind(error.to_string().into()).into_internal()
}
<|endoftext|>


<commit_before>#[legacy_modes];

/*!

An implementation of the Graph500 Breadth First Search problem in Rust.

*/

extern mod std;
use std::arc;
use std::time;
use std::map;
use std::map::Map;
use std::map::HashMap;
use std::deque;
use std::deque::Deque;
use std::par;
use io::WriterUtil;
use comm::*;
use int::abs;

type node_id = i64;
type graph = ~[~[node_id]];
type bfs_result = ~[node_id];

fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] {
    let r = rand::xorshift();

    fn choose_edge(i: node_id, j: node_id, scale: uint, r: rand::Rng)
        -> (node_id, node_id) {

        let A = 0.57;
        let B = 0.19;
        let C = 0.19;

        if scale == 0u {
            (i, j)
        }
        else {
            let i = i * 2i64;
            let j = j * 2i64;
            let scale = scale - 1u;

            let x = r.gen_float();

            if x < A {
                choose_edge(i, j, scale, r)
            }
            else {
                let x = x - A;
                if x < B {
                    choose_edge(i + 1i64, j, scale, r)
                }
                else {
                    let x = x - B;
                    if x < C {
                        choose_edge(i, j + 1i64, scale, r)
                    }
                    else {
                        choose_edge(i + 1i64, j + 1i64, scale, r)
                    }
                }
            }
        }
    }

    do vec::from_fn((1u << scale) * edgefactor) |_i| {
        choose_edge(0i64, 0i64, scale, r)
    }
}

fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph {
    let graph = do vec::from_fn(N) |_i| {
        map::HashMap::<node_id, ()>()
    };

    do vec::each(edges) |e| {
        match *e {
            (i, j) => {
                map::set_add(graph[i], j);
                map::set_add(graph[j], i);
            }
        }
        true
    }

    do graph.map() |v| {
        map::vec_from_set(*v)
    }
}

fn gen_search_keys(graph: graph, n: uint) -> ~[node_id] {
    let keys = map::HashMap::<node_id, ()>();
    let r = rand::Rng();

    while keys.size() < n {
        let k = r.gen_uint_range(0u, graph.len());

        if graph[k].len() > 0u && vec::any(graph[k], |i| {
            *i != k as node_id
        }) {
            map::set_add(keys, k as node_id);
        }
    }
    map::vec_from_set(keys)
}

/**
 * Returns a vector of all the parents in the BFS tree rooted at key.
 *
 * Nodes that are unreachable have a parent of -1.
 */
fn bfs(graph: graph, key: node_id) -> bfs_result {
    let marks : ~[mut node_id]
        = vec::to_mut(vec::from_elem(vec::len(graph), -1i64));

    let Q = deque::create();

    Q.add_back(key);
    marks[key] = key;

    while Q.size() > 0u {
        let t = Q.pop_front();

        do graph[t].each() |k| {
            if marks[*k] == -1i64 {
                marks[*k] = t;
                Q.add_back(*k);
            }
            true
        };
    }

    vec::from_mut(marks)
}

/**
 * Another version of the bfs function.
 *
 * This one uses the same algorithm as the parallel one, just without
 * using the parallel vector operators.
 */
fn bfs2(graph: graph, key: node_id) -> bfs_result {
    // This works by doing functional updates of a color vector.

    enum color {
        white,
        // node_id marks which node turned this gray/black.
        // the node id later becomes the parent.
        gray(node_id),
        black(node_id)
    };

    let mut colors = do vec::from_fn(graph.len()) |i| {
        if i as node_id == key {
            gray(key)
        }
        else {
            white
        }
    };

    fn is_gray(c: &color) -> bool {
        match *c {
          gray(_) => { true }
          _ => { false }
        }
    }

    let mut i = 0u;
    while vec::any(colors, is_gray) {
        // Do the BFS.
        log(info, fmt!("PBFS iteration %?", i));
        i += 1u;
        colors = do colors.mapi() |i, c| {
            let c : color = *c;
            match c {
              white => {
                let i = i as node_id;

                let neighbors = graph[i];

                let mut color = white;

                do neighbors.each() |k| {
                    if is_gray(&colors[*k]) {
                        color = gray(*k);
                        false
                    }
                    else { true }
                };

                color
              }
              gray(parent) => { black(parent) }
              black(parent) => { black(parent) }
            }
        }
    }

    // Convert the results.
    do vec::map(colors) |c| {
        match *c {
          white => { -1i64 }
          black(parent) => { parent }
          _ => { fail ~"Found remaining gray nodes in BFS" }
        }
    }
}

/// A parallel version of the bfs function.
fn pbfs(&&graph: arc::ARC<graph>, key: node_id) -> bfs_result {
    // This works by doing functional updates of a color vector.

    enum color {
        white,
        // node_id marks which node turned this gray/black.
        // the node id later becomes the parent.
        gray(node_id),
        black(node_id)
    };

    let graph_vec = arc::get(&graph); // FIXME #3387 requires this temp
    let mut colors = do vec::from_fn(graph_vec.len()) |i| {
        if i as node_id == key {
            gray(key)
        }
        else {
            white
        }
    };

    #[inline(always)]
    fn is_gray(c: &color) -> bool {
        match *c {
          gray(_) => { true }
          _ => { false }
        }
    }

    let mut i = 0u;
    while par::any(colors, is_gray) {
        // Do the BFS.
        log(info, fmt!("PBFS iteration %?", i));
        i += 1u;
        let old_len = colors.len();

        let color = arc::ARC(colors);

        let color_vec = arc::get(&color); // FIXME #3387 requires this temp
        colors = do par::mapi_factory(*color_vec) {
            let colors = arc::clone(&color);
            let graph = arc::clone(&graph);
            fn~(i: uint, c: color) -> color {
                let c : color = c;
                let colors = arc::get(&colors);
                let graph = arc::get(&graph);
                match c {
                  white => {
                    let i = i as node_id;

                    let neighbors = graph[i];

                    let mut color = white;

                    do neighbors.each() |k| {
                        if is_gray(colors[*k]) {
                            color = gray(*k);
                            false
                        }
                        else { true }
                    };
                    color
                  }
                  gray(parent) => { black(parent) }
                  black(parent) => { black(parent) }
                }
            }
        };
        assert(colors.len() == old_len);
    }

    // Convert the results.
    do par::map(colors) |c| {
        match *c {
          white => { -1i64 }
          black(parent) => { parent }
          _ => { fail ~"Found remaining gray nodes in BFS" }
        }
    }
}

/// Performs at least some of the validation in the Graph500 spec.
fn validate(edges: ~[(node_id, node_id)],
            root: node_id, tree: bfs_result) -> bool {
    // There are 5 things to test. Below is code for each of them.

    // 1. The BFS tree is a tree and does not contain cycles.
    //
    // We do this by iterating over the tree, and tracing each of the
    // parent chains back to the root. While we do this, we also
    // compute the levels for each node.

    log(info, ~"Verifying tree structure...");

    let mut status = true;
    let level = do tree.map() |parent| {
        let mut parent = *parent;
        let mut path = ~[];

        if parent == -1i64 {
            // This node was not in the tree.
            -1
        }
        else {
            while parent != root {
                if vec::contains(path, &parent) {
                    status = false;
                }

                path.push(parent);
                parent = tree[parent];
            }

            // The length of the path back to the root is the current
            // level.
            path.len() as int
        }
    };

    if !status { return status }

    // 2. Each tree edge connects vertices whose BFS levels differ by
    //    exactly one.

    log(info, ~"Verifying tree edges...");

    let status = do tree.alli() |k, parent| {
        if *parent != root && *parent != -1i64 {
            level[*parent] == level[k] - 1
        }
        else {
            true
        }
    };

    if !status { return status }

    // 3. Every edge in the input list has vertices with levels that
    //    differ by at most one or that both are not in the BFS tree.

    log(info, ~"Verifying graph edges...");

    let status = do edges.all() |e| {
        let (u, v) = *e;

        abs(level[u] - level[v]) <= 1
    };

    if !status { return status }

    // 4. The BFS tree spans an entire connected component's vertices.

    // This is harder. We'll skip it for now...

    // 5. A node and its parent are joined by an edge of the original
    //    graph.

    log(info, ~"Verifying tree and graph edges...");

    let status = do par::alli(tree) |u, v| {
        let u = u as node_id;
        if v == -1i64 || u == root {
            true
        }
        else {
            edges.contains(&(u, v)) || edges.contains(&(v, u))
        }
    };

    if !status { return status }

    // If we get through here, all the tests passed!
    true
}

fn main(++args: ~[~str]) {
    let args = if os::getenv(~"RUST_BENCH").is_some() {
        ~[~"", ~"15", ~"48"]
    } else if args.len() <= 1u {
        ~[~"", ~"10", ~"16"]
    } else {
        args
    };

    let scale = uint::from_str(args[1]).get();
    let num_keys = uint::from_str(args[2]).get();
    let do_validate = false;
    let do_sequential = true;

    let start = time::precise_time_s();
    let edges = make_edges(scale, 16u);
    let stop = time::precise_time_s();

    io::stdout().write_line(fmt!("Generated %? edges in %? seconds.",
                                 vec::len(edges), stop - start));

    let start = time::precise_time_s();
    let graph = make_graph(1u << scale, edges);
    let stop = time::precise_time_s();

    let mut total_edges = 0u;
    vec::each(graph, |edges| { total_edges += edges.len(); true });

    io::stdout().write_line(fmt!("Generated graph with %? edges in %? seconds.",
                                 total_edges / 2u,
                                 stop - start));

    let mut total_seq = 0.0;
    let mut total_par = 0.0;

    let graph_arc = arc::ARC(copy graph);

    do gen_search_keys(graph, num_keys).map() |root| {
        io::stdout().write_line(~"");
        io::stdout().write_line(fmt!("Search key: %?", root));

        if do_sequential {
            let start = time::precise_time_s();
            let bfs_tree = bfs(graph, *root);
            let stop = time::precise_time_s();

            //total_seq += stop - start;

            io::stdout().write_line(
                fmt!("Sequential BFS completed in %? seconds.",
                     stop - start));

            if do_validate {
                let start = time::precise_time_s();
                assert(validate(edges, *root, bfs_tree));
                let stop = time::precise_time_s();

                io::stdout().write_line(
                    fmt!("Validation completed in %? seconds.",
                         stop - start));
            }

            let start = time::precise_time_s();
            let bfs_tree = bfs2(graph, *root);
            let stop = time::precise_time_s();

            total_seq += stop - start;

            io::stdout().write_line(
                fmt!("Alternate Sequential BFS completed in %? seconds.",
                     stop - start));

            if do_validate {
                let start = time::precise_time_s();
                assert(validate(edges, *root, bfs_tree));
                let stop = time::precise_time_s();

                io::stdout().write_line(
                    fmt!("Validation completed in %? seconds.",
                         stop - start));
            }
        }

        let start = time::precise_time_s();
        let bfs_tree = pbfs(graph_arc, *root);
        let stop = time::precise_time_s();

        total_par += stop - start;

        io::stdout().write_line(fmt!("Parallel BFS completed in %? seconds.",
                                     stop - start));

        if do_validate {
            let start = time::precise_time_s();
            assert(validate(edges, *root, bfs_tree));
            let stop = time::precise_time_s();

            io::stdout().write_line(fmt!("Validation completed in %? seconds.",
                                         stop - start));
        }
    };

    io::stdout().write_line(~"");
    io::stdout().write_line(
        fmt!("Total sequential: %? \t Total Parallel: %? \t Speedup: %?x",
             total_seq, total_par, total_seq / total_par));
}
<commit_msg>Fix graph500-bfs<commit_after>#[legacy_modes];

/*!

An implementation of the Graph500 Breadth First Search problem in Rust.

*/

extern mod std;
use std::arc;
use std::time;
use std::map;
use std::map::Map;
use std::map::HashMap;
use std::deque;
use std::deque::Deque;
use std::par;
use io::WriterUtil;
use comm::*;
use int::abs;

type node_id = i64;
type graph = ~[~[node_id]];
type bfs_result = ~[node_id];

fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] {
    let r = rand::xorshift();

    fn choose_edge(i: node_id, j: node_id, scale: uint, r: rand::Rng)
        -> (node_id, node_id) {

        let A = 0.57;
        let B = 0.19;
        let C = 0.19;

        if scale == 0u {
            (i, j)
        }
        else {
            let i = i * 2i64;
            let j = j * 2i64;
            let scale = scale - 1u;

            let x = r.gen_float();

            if x < A {
                choose_edge(i, j, scale, r)
            }
            else {
                let x = x - A;
                if x < B {
                    choose_edge(i + 1i64, j, scale, r)
                }
                else {
                    let x = x - B;
                    if x < C {
                        choose_edge(i, j + 1i64, scale, r)
                    }
                    else {
                        choose_edge(i + 1i64, j + 1i64, scale, r)
                    }
                }
            }
        }
    }

    do vec::from_fn((1u << scale) * edgefactor) |_i| {
        choose_edge(0i64, 0i64, scale, r)
    }
}

fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph {
    let graph = do vec::from_fn(N) |_i| {
        map::HashMap::<node_id, ()>()
    };

    do vec::each(edges) |e| {
        match *e {
            (i, j) => {
                map::set_add(graph[i], j);
                map::set_add(graph[j], i);
            }
        }
        true
    }

    do graph.map() |v| {
        map::vec_from_set(*v)
    }
}

fn gen_search_keys(graph: graph, n: uint) -> ~[node_id] {
    let keys = map::HashMap::<node_id, ()>();
    let r = rand::Rng();

    while keys.size() < n {
        let k = r.gen_uint_range(0u, graph.len());

        if graph[k].len() > 0u && vec::any(graph[k], |i| {
            *i != k as node_id
        }) {
            map::set_add(keys, k as node_id);
        }
    }
    map::vec_from_set(keys)
}

/**
 * Returns a vector of all the parents in the BFS tree rooted at key.
 *
 * Nodes that are unreachable have a parent of -1.
 */
fn bfs(graph: graph, key: node_id) -> bfs_result {
    let marks : ~[mut node_id]
        = vec::to_mut(vec::from_elem(vec::len(graph), -1i64));

    let Q = deque::create();

    Q.add_back(key);
    marks[key] = key;

    while Q.size() > 0u {
        let t = Q.pop_front();

        do graph[t].each() |k| {
            if marks[*k] == -1i64 {
                marks[*k] = t;
                Q.add_back(*k);
            }
            true
        };
    }

    vec::from_mut(marks)
}

/**
 * Another version of the bfs function.
 *
 * This one uses the same algorithm as the parallel one, just without
 * using the parallel vector operators.
 */
fn bfs2(graph: graph, key: node_id) -> bfs_result {
    // This works by doing functional updates of a color vector.

    enum color {
        white,
        // node_id marks which node turned this gray/black.
        // the node id later becomes the parent.
        gray(node_id),
        black(node_id)
    };

    let mut colors = do vec::from_fn(graph.len()) |i| {
        if i as node_id == key {
            gray(key)
        }
        else {
            white
        }
    };

    fn is_gray(c: &color) -> bool {
        match *c {
          gray(_) => { true }
          _ => { false }
        }
    }

    let mut i = 0u;
    while vec::any(colors, is_gray) {
        // Do the BFS.
        log(info, fmt!("PBFS iteration %?", i));
        i += 1u;
        colors = do colors.mapi() |i, c| {
            let c : color = *c;
            match c {
              white => {
                let i = i as node_id;

                let neighbors = graph[i];

                let mut color = white;

                do neighbors.each() |k| {
                    if is_gray(&colors[*k]) {
                        color = gray(*k);
                        false
                    }
                    else { true }
                };

                color
              }
              gray(parent) => { black(parent) }
              black(parent) => { black(parent) }
            }
        }
    }

    // Convert the results.
    do vec::map(colors) |c| {
        match *c {
          white => { -1i64 }
          black(parent) => { parent }
          _ => { fail ~"Found remaining gray nodes in BFS" }
        }
    }
}

/// A parallel version of the bfs function.
fn pbfs(&&graph: arc::ARC<graph>, key: node_id) -> bfs_result {
    // This works by doing functional updates of a color vector.

    enum color {
        white,
        // node_id marks which node turned this gray/black.
        // the node id later becomes the parent.
        gray(node_id),
        black(node_id)
    };

    let graph_vec = arc::get(&graph); // FIXME #3387 requires this temp
    let mut colors = do vec::from_fn(graph_vec.len()) |i| {
        if i as node_id == key {
            gray(key)
        }
        else {
            white
        }
    };

    #[inline(always)]
    fn is_gray(c: &color) -> bool {
        match *c {
          gray(_) => { true }
          _ => { false }
        }
    }

    let mut i = 0;
    while par::any(colors, is_gray) {
        // Do the BFS.
        log(info, fmt!("PBFS iteration %?", i));
        i += 1;
        let old_len = colors.len();

        let color = arc::ARC(colors);

        let color_vec = arc::get(&color); // FIXME #3387 requires this temp
        colors = do par::mapi_factory(*color_vec) {
            let colors = arc::clone(&color);
            let graph = arc::clone(&graph);
            fn~(i: uint, c: color) -> color {
                let c : color = c;
                let colors = arc::get(&colors);
                let graph = arc::get(&graph);
                match c {
                  white => {
                    let i = i as node_id;

                    let neighbors = graph[i];

                    let mut color = white;

                    do neighbors.each() |k| {
                        if is_gray(&colors[*k]) {
                            color = gray(*k);
                            false
                        }
                        else { true }
                    };
                    color
                  }
                  gray(parent) => { black(parent) }
                  black(parent) => { black(parent) }
                }
            }
        };
        assert(colors.len() == old_len);
    }

    // Convert the results.
    do par::map(colors) |c| {
        match *c {
          white => { -1i64 }
          black(parent) => { parent }
          _ => { fail ~"Found remaining gray nodes in BFS" }
        }
    }
}

/// Performs at least some of the validation in the Graph500 spec.
fn validate(edges: ~[(node_id, node_id)],
            root: node_id, tree: bfs_result) -> bool {
    // There are 5 things to test. Below is code for each of them.

    // 1. The BFS tree is a tree and does not contain cycles.
    //
    // We do this by iterating over the tree, and tracing each of the
    // parent chains back to the root. While we do this, we also
    // compute the levels for each node.

    log(info, ~"Verifying tree structure...");

    let mut status = true;
    let level = do tree.map() |parent| {
        let mut parent = *parent;
        let mut path = ~[];

        if parent == -1i64 {
            // This node was not in the tree.
            -1
        }
        else {
            while parent != root {
                if vec::contains(path, &parent) {
                    status = false;
                }

                path.push(parent);
                parent = tree[parent];
            }

            // The length of the path back to the root is the current
            // level.
            path.len() as int
        }
    };

    if !status { return status }

    // 2. Each tree edge connects vertices whose BFS levels differ by
    //    exactly one.

    log(info, ~"Verifying tree edges...");

    let status = do tree.alli() |k, parent| {
        if *parent != root && *parent != -1i64 {
            level[*parent] == level[k] - 1
        }
        else {
            true
        }
    };

    if !status { return status }

    // 3. Every edge in the input list has vertices with levels that
    //    differ by at most one or that both are not in the BFS tree.

    log(info, ~"Verifying graph edges...");

    let status = do edges.all() |e| {
        let (u, v) = *e;

        abs(level[u] - level[v]) <= 1
    };

    if !status { return status }

    // 4. The BFS tree spans an entire connected component's vertices.

    // This is harder. We'll skip it for now...

    // 5. A node and its parent are joined by an edge of the original
    //    graph.

    log(info, ~"Verifying tree and graph edges...");

    let status = do par::alli(tree) |u, v| {
        let u = u as node_id;
        if *v == -1i64 || u == root {
            true
        }
        else {
            edges.contains(&(u, *v)) || edges.contains(&(*v, u))
        }
    };

    if !status { return status }

    // If we get through here, all the tests passed!
    true
}

fn main(++args: ~[~str]) {
    let args = if os::getenv(~"RUST_BENCH").is_some() {
        ~[~"", ~"15", ~"48"]
    } else if args.len() <= 1u {
        ~[~"", ~"10", ~"16"]
    } else {
        args
    };

    let scale = uint::from_str(args[1]).get();
    let num_keys = uint::from_str(args[2]).get();
    let do_validate = false;
    let do_sequential = true;

    let start = time::precise_time_s();
    let edges = make_edges(scale, 16u);
    let stop = time::precise_time_s();

    io::stdout().write_line(fmt!("Generated %? edges in %? seconds.",
                                 vec::len(edges), stop - start));

    let start = time::precise_time_s();
    let graph = make_graph(1u << scale, edges);
    let stop = time::precise_time_s();

    let mut total_edges = 0u;
    vec::each(graph, |edges| { total_edges += edges.len(); true });

    io::stdout().write_line(fmt!("Generated graph with %? edges in %? seconds.",
                                 total_edges / 2u,
                                 stop - start));

    let mut total_seq = 0.0;
    let mut total_par = 0.0;

    let graph_arc = arc::ARC(copy graph);

    do gen_search_keys(graph, num_keys).map() |root| {
        io::stdout().write_line(~"");
        io::stdout().write_line(fmt!("Search key: %?", root));

        if do_sequential {
            let start = time::precise_time_s();
            let bfs_tree = bfs(graph, *root);
            let stop = time::precise_time_s();

            //total_seq += stop - start;

            io::stdout().write_line(
                fmt!("Sequential BFS completed in %? seconds.",
                     stop - start));

            if do_validate {
                let start = time::precise_time_s();
                assert(validate(edges, *root, bfs_tree));
                let stop = time::precise_time_s();

                io::stdout().write_line(
                    fmt!("Validation completed in %? seconds.",
                         stop - start));
            }

            let start = time::precise_time_s();
            let bfs_tree = bfs2(graph, *root);
            let stop = time::precise_time_s();

            total_seq += stop - start;

            io::stdout().write_line(
                fmt!("Alternate Sequential BFS completed in %? seconds.",
                     stop - start));

            if do_validate {
                let start = time::precise_time_s();
                assert(validate(edges, *root, bfs_tree));
                let stop = time::precise_time_s();

                io::stdout().write_line(
                    fmt!("Validation completed in %? seconds.",
                         stop - start));
            }
        }

        let start = time::precise_time_s();
        let bfs_tree = pbfs(graph_arc, *root);
        let stop = time::precise_time_s();

        total_par += stop - start;

        io::stdout().write_line(fmt!("Parallel BFS completed in %? seconds.",
                                     stop - start));

        if do_validate {
            let start = time::precise_time_s();
            assert(validate(edges, *root, bfs_tree));
            let stop = time::precise_time_s();

            io::stdout().write_line(fmt!("Validation completed in %? seconds.",
                                         stop - start));
        }
    };

    io::stdout().write_line(~"");
    io::stdout().write_line(
        fmt!("Total sequential: %? \t Total Parallel: %? \t Speedup: %?x",
             total_seq, total_par, total_seq / total_par));
}
<|endoftext|>


<commit_before>use super::simplex_vertex::SimplexVertex;
use super::super::common::math::vec_distance;
use super::super::common::Vec2;

pub struct Simplex {
    pub m_v1: SimplexVertex,
    pub m_v2: SimplexVertex,
    pub m_v3: SimplexVertex,
    pub m_count: i32
}

impl Simplex {
    // TODO implement
    // pub fn read_cache()

    // TODO implement
    // pub fn write_cache()

    // TODO implement {
    // pub fn get_search_direction() -> Vec2

    // TODO implement
    // pub fn get_closest_point() -> Vec2

    pub fn get_witness_points(&self) -> (Vec2, Vec2) {
        match self.m_count {
            0 => {
                assert!(false);
                return (Vec2::zero(), Vec2::zero());
            },
            1 => {
                return (self.m_v1.w_a, self.m_v1.w_b);
            },
            2 => {
                return (self.m_v1.a * self.m_v1.w_a + self.m_v2.a * self.m_v2.w_a,
                    self.m_v1.a * self.m_v1.w_b + self.m_v2.a * self.m_v2.w_b)
            },
            3 => {
                let p_a = self.m_v1.a * self.m_v1.w_a + self.m_v2.a * self.m_v2.w_a + self.m_v3.a * self.m_v3.w_a;
                return (p_a, p_a)
            },
            _ => {
                assert!(false);
                return (Vec2::zero(), Vec2::zero());
            }
        }
    }

    pub fn get_metric(&self) -> f32 {
        match self.m_count {
            0 => {
                assert!(false);
                return 0.0;
            },
            1 => 0.0,
            2 => {
                return vec_distance(self.m_v1.w, self.m_v2.w);
            },
            3 => {
                return Vec2::cross_vec(self.m_v2.w - self.m_v1.w, self.m_v3.w - self.m_v1.w);
            },
            _ => {
                assert!(false);
                return 0.0;
            }
        }
    }

    // TODO implement
    pub fn solve_2() {

    }

    // TODO implement
    pub fn solve_3() {

    }
}
<commit_msg>Adding get_closest_point to simplex<commit_after>use super::simplex_vertex::SimplexVertex;
use super::super::common::math::vec_distance;
use super::super::common::Vec2;

pub struct Simplex {
    pub m_v1: SimplexVertex,
    pub m_v2: SimplexVertex,
    pub m_v3: SimplexVertex,
    pub m_count: i32
}

impl Simplex {
    // TODO implement
    // pub fn read_cache()

    // TODO implement
    // pub fn write_cache()

    // TODO implement {
    // pub fn get_search_direction() -> Vec2

    pub fn get_closest_point(&self) -> Vec2 {
        match self.m_count {
            0 => {
                assert!(false);
                return Vec2::zero();
            },
            1 => {
                return self.m_v1.w;
            },
            2 => {
                return self.m_v1.a * self.m_v1.w + self.m_v2.a * self.m_v2.w;
            },
            3 => {
                return Vec2::zero();
            },
            _ => {
                assert!(false);
                return Vec2::zero();
            }
        }
    }

    pub fn get_witness_points(&self) -> (Vec2, Vec2) {
        match self.m_count {
            0 => {
                assert!(false);
                return (Vec2::zero(), Vec2::zero());
            },
            1 => {
                return (self.m_v1.w_a, self.m_v1.w_b);
            },
            2 => {
                return (self.m_v1.a * self.m_v1.w_a + self.m_v2.a * self.m_v2.w_a,
                    self.m_v1.a * self.m_v1.w_b + self.m_v2.a * self.m_v2.w_b)
            },
            3 => {
                let p_a = self.m_v1.a * self.m_v1.w_a + self.m_v2.a * self.m_v2.w_a + self.m_v3.a * self.m_v3.w_a;
                return (p_a, p_a)
            },
            _ => {
                assert!(false);
                return (Vec2::zero(), Vec2::zero());
            }
        }
    }

    pub fn get_metric(&self) -> f32 {
        match self.m_count {
            0 => {
                assert!(false);
                return 0.0;
            },
            1 => 0.0,
            2 => {
                return vec_distance(self.m_v1.w, self.m_v2.w);
            },
            3 => {
                return Vec2::cross_vec(self.m_v2.w - self.m_v1.w, self.m_v3.w - self.m_v1.w);
            },
            _ => {
                assert!(false);
                return 0.0;
            }
        }
    }

    // TODO implement
    pub fn solve_2() {

    }

    // TODO implement
    pub fn solve_3() {

    }
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::process::Command;
use std::env;

fn debug() -> bool {
    match env::var("DEBUG") {
        Ok(s) => s == "true",
        Err(_) => false
    }
}

fn mode() -> &'static str {
    if debug() { "Debug" } else { "Release" }
}

#[cfg(unix)]
fn object_path(libname: &str) -> String {
    format!("build/{}/obj.target/{}/src/{}.o", mode(), libname, libname)
}

#[cfg(windows)]
fn object_path(libname: &str) -> String {
    format!("build\\{}\\obj\\{}\\{}.obj", mode(), libname, libname)
}

#[cfg(unix)]
const NPM_COMMAND : &'static str = "npm";

#[cfg(windows)]
const NPM_COMMAND : &'static str = "npm.cmd";

fn build_object_file() {
    // Ensure that all package.json dependencies and dev dependencies are installed.
    Command::new(NPM_COMMAND).arg("install").status().ok()
        .expect(r#"failed to run "npm install" for neon-sys"#);

    // Run the package.json `configure` script, which invokes `node-gyp configure` from the local node_modules.
    Command::new(NPM_COMMAND).arg("run").arg(if debug() { "configure-debug" } else { "configure-release" }).status().ok().unwrap();

    // Run the package.json `build` script, which invokes `node-gyp build` from the local node_modules.
    Command::new(NPM_COMMAND).arg("run").arg(if debug() { "build-debug" } else { "build-release" }).status().ok().unwrap();
}

fn link_library() {
    // Link the built object file into a static library.
    gcc::Config::new()
        .object(object_path("neon"))
        .compile("libneon.a");
}

fn main() {
    // 1. Build the object file from source using node-gyp.
    build_object_file();

    // 2. Link the library from the object file using gcc.
    link_library();
}
<commit_msg>Run `npm` with `--silent` to prevent it from stalling on Windows<commit_after>extern crate gcc;

use std::process::Command;
use std::env;

fn debug() -> bool {
    match env::var("DEBUG") {
        Ok(s) => s == "true",
        Err(_) => false
    }
}

fn mode() -> &'static str {
    if debug() { "Debug" } else { "Release" }
}

#[cfg(unix)]
fn object_path(libname: &str) -> String {
    format!("build/{}/obj.target/{}/src/{}.o", mode(), libname, libname)
}

#[cfg(windows)]
fn object_path(libname: &str) -> String {
    format!("build\\{}\\obj\\{}\\{}.obj", mode(), libname, libname)
}

#[cfg(unix)]
const NPM_COMMAND : &'static str = "npm";

#[cfg(windows)]
const NPM_COMMAND : &'static str = "npm.cmd";

fn build_object_file() {
    // Ensure that all package.json dependencies and dev dependencies are installed.
    Command::new(NPM_COMMAND).args(&["install", "--silent"]).status().ok()
        .expect(r#"failed to run "npm install" for neon-sys"#);

    // Run the package.json `configure` script, which invokes `node-gyp configure` from the local node_modules.
    Command::new(NPM_COMMAND).args(&["run", "--silent"]).arg(if debug() { "configure-debug" } else { "configure-release" }).status().ok().unwrap();

    // Run the package.json `build` script, which invokes `node-gyp build` from the local node_modules.
    Command::new(NPM_COMMAND).args(&["run", "--silent"]).arg(if debug() { "build-debug" } else { "build-release" }).status().ok().unwrap();
}

fn link_library() {
    // Link the built object file into a static library.
    gcc::Config::new()
        .object(object_path("neon"))
        .compile("libneon.a");
}

fn main() {
    // 1. Build the object file from source using node-gyp.
    build_object_file();

    // 2. Link the library from the object file using gcc.
    link_library();
}
<|endoftext|>


<commit_before>/// `mbe` (short for Macro By Example) crate contains code for handling
/// `macro_rules` macros. It uses `TokenTree` (from `ra_tt` package) as the
/// interface, although it contains some code to bridge `SyntaxNode`s and
/// `TokenTree`s as well!

macro_rules! impl_froms {
    ($e:ident: $($v:ident), *) => {
        $(
            impl From<$v> for $e {
                fn from(it: $v) -> $e {
                    $e::$v(it)
                }
            }
        )*
    }
}

mod tt_cursor;
mod mbe_parser;
mod mbe_expander;
mod syntax_bridge;

use ra_syntax::SmolStr;

pub use tt::{Delimiter, Punct};

pub use crate::syntax_bridge::ast_to_token_tree;

/// This struct contains AST for a single `macro_rules` defenition. What might
/// be very confusing is that AST has almost exactly the same shape as
/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident`
/// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
#[derive(Debug)]
pub struct MacroRules {
    pub(crate) rules: Vec<Rule>,
}

impl MacroRules {
    pub fn parse(tt: &tt::Subtree) -> Option<MacroRules> {
        mbe_parser::parse(tt)
    }
    pub fn expand(&self, tt: &tt::Subtree) -> Option<tt::Subtree> {
        mbe_expander::exapnd(self, tt)
    }
}

#[derive(Debug)]
pub(crate) struct Rule {
    pub(crate) lhs: Subtree,
    pub(crate) rhs: Subtree,
}

#[derive(Debug)]
pub(crate) enum TokenTree {
    Leaf(Leaf),
    Subtree(Subtree),
    Repeat(Repeat),
}
impl_froms!(TokenTree: Leaf, Subtree, Repeat);

#[derive(Debug)]
pub(crate) enum Leaf {
    Literal(Literal),
    Punct(Punct),
    Ident(Ident),
    Var(Var),
}
impl_froms!(Leaf: Literal, Punct, Ident, Var);

#[derive(Debug)]
pub(crate) struct Subtree {
    pub(crate) delimiter: Delimiter,
    pub(crate) token_trees: Vec<TokenTree>,
}

#[derive(Debug)]
pub(crate) struct Repeat {
    pub(crate) subtree: Subtree,
    pub(crate) kind: RepeatKind,
    pub(crate) separator: Option<char>,
}

#[derive(Debug)]
pub(crate) enum RepeatKind {
    ZeroOrMore,
    OneOrMore,
    ZeroOrOne,
}

#[derive(Debug)]
pub(crate) struct Literal {
    pub(crate) text: SmolStr,
}

#[derive(Debug)]
pub(crate) struct Ident {
    pub(crate) text: SmolStr,
}

#[derive(Debug)]
pub(crate) struct Var {
    pub(crate) text: SmolStr,
    pub(crate) kind: Option<SmolStr>,
}

#[cfg(test)]
mod tests {
    use ra_syntax::{ast, AstNode};

    use super::*;

    // Good first issue (although a slightly chellegning one):
    //
    // * Pick a random test from here
    //   https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
    // * Port the test to rust and add it to this module
    // * Make it pass :-)

    #[test]
    fn test_convert_tt() {
        let macro_definition = r#"
macro_rules! impl_froms {
    ($e:ident: $($v:ident),*) => {
        $(
            impl From<$v> for $e {
                fn from(it: $v) -> $e {
                    $e::$v(it)
                }
            }
        )*
    }
}
"#;

        let macro_invocation = r#"
impl_froms!(TokenTree: Leaf, Subtree);
"#;

        let source_file = ast::SourceFile::parse(macro_definition);
        let macro_definition = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let source_file = ast::SourceFile::parse(macro_invocation);
        let macro_invocation = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
        let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
        let rules = crate::MacroRules::parse(&definition_tt).unwrap();
        let expansion = rules.expand(&invocation_tt).unwrap();
        assert_eq!(
        expansion.to_string(),
        "impl From < Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree :: Leaf (it)}} \
         impl From < Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree :: Subtree (it)}}"
    )
    }

    #[test]
    fn test_fail_match_pattern_by_token() {
        let macro_definition = r#"
        macro_rules! foo {
            ($ i:ident) => (
                mod $ i {}
            );
            (= $ i:ident) => (
                fn $ i() {}
            );
            (+ $ i:ident) => (
                struct $ i;
            )
        }
"#;

        let macro_invocation = r#"
foo! {   foo }
"#;

        let source_file = ast::SourceFile::parse(macro_definition);
        let macro_definition = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let source_file = ast::SourceFile::parse(macro_invocation);
        let macro_invocation = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
        let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
        let rules = crate::MacroRules::parse(&definition_tt).unwrap();
        let expansion = rules.expand(&invocation_tt).unwrap();
        assert_eq!(expansion.to_string(), "mod foo {}")
    }

}
<commit_msg>Fill out test a little more<commit_after>/// `mbe` (short for Macro By Example) crate contains code for handling
/// `macro_rules` macros. It uses `TokenTree` (from `ra_tt` package) as the
/// interface, although it contains some code to bridge `SyntaxNode`s and
/// `TokenTree`s as well!

macro_rules! impl_froms {
    ($e:ident: $($v:ident), *) => {
        $(
            impl From<$v> for $e {
                fn from(it: $v) -> $e {
                    $e::$v(it)
                }
            }
        )*
    }
}

mod tt_cursor;
mod mbe_parser;
mod mbe_expander;
mod syntax_bridge;

use ra_syntax::SmolStr;

pub use tt::{Delimiter, Punct};

pub use crate::syntax_bridge::ast_to_token_tree;

/// This struct contains AST for a single `macro_rules` defenition. What might
/// be very confusing is that AST has almost exactly the same shape as
/// `tt::TokenTree`, but there's a crucial difference: in macro rules, `$ident`
/// and `$()*` have special meaning (see `Var` and `Repeat` data structures)
#[derive(Debug)]
pub struct MacroRules {
    pub(crate) rules: Vec<Rule>,
}

impl MacroRules {
    pub fn parse(tt: &tt::Subtree) -> Option<MacroRules> {
        mbe_parser::parse(tt)
    }
    pub fn expand(&self, tt: &tt::Subtree) -> Option<tt::Subtree> {
        mbe_expander::exapnd(self, tt)
    }
}

#[derive(Debug)]
pub(crate) struct Rule {
    pub(crate) lhs: Subtree,
    pub(crate) rhs: Subtree,
}

#[derive(Debug)]
pub(crate) enum TokenTree {
    Leaf(Leaf),
    Subtree(Subtree),
    Repeat(Repeat),
}
impl_froms!(TokenTree: Leaf, Subtree, Repeat);

#[derive(Debug)]
pub(crate) enum Leaf {
    Literal(Literal),
    Punct(Punct),
    Ident(Ident),
    Var(Var),
}
impl_froms!(Leaf: Literal, Punct, Ident, Var);

#[derive(Debug)]
pub(crate) struct Subtree {
    pub(crate) delimiter: Delimiter,
    pub(crate) token_trees: Vec<TokenTree>,
}

#[derive(Debug)]
pub(crate) struct Repeat {
    pub(crate) subtree: Subtree,
    pub(crate) kind: RepeatKind,
    pub(crate) separator: Option<char>,
}

#[derive(Debug)]
pub(crate) enum RepeatKind {
    ZeroOrMore,
    OneOrMore,
    ZeroOrOne,
}

#[derive(Debug)]
pub(crate) struct Literal {
    pub(crate) text: SmolStr,
}

#[derive(Debug)]
pub(crate) struct Ident {
    pub(crate) text: SmolStr,
}

#[derive(Debug)]
pub(crate) struct Var {
    pub(crate) text: SmolStr,
    pub(crate) kind: Option<SmolStr>,
}

#[cfg(test)]
mod tests {
    use ra_syntax::{ast, AstNode};

    use super::*;

    // Good first issue (although a slightly chellegning one):
    //
    // * Pick a random test from here
    //   https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt
    // * Port the test to rust and add it to this module
    // * Make it pass :-)

    #[test]
    fn test_convert_tt() {
        let macro_definition = r#"
macro_rules! impl_froms {
    ($e:ident: $($v:ident),*) => {
        $(
            impl From<$v> for $e {
                fn from(it: $v) -> $e {
                    $e::$v(it)
                }
            }
        )*
    }
}
"#;

        let macro_invocation = r#"
impl_froms!(TokenTree: Leaf, Subtree);
"#;

        let source_file = ast::SourceFile::parse(macro_definition);
        let macro_definition = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let source_file = ast::SourceFile::parse(macro_invocation);
        let macro_invocation = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
        let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();
        let rules = crate::MacroRules::parse(&definition_tt).unwrap();
        let expansion = rules.expand(&invocation_tt).unwrap();
        assert_eq!(
        expansion.to_string(),
        "impl From < Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree :: Leaf (it)}} \
         impl From < Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree :: Subtree (it)}}"
    )
    }

    fn assert_expansion(rules: &MacroRules, invocation: &str, expansion: &str) {
        let source_file = ast::SourceFile::parse(invocation);
        let macro_invocation = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let invocation_tt = ast_to_token_tree(macro_invocation.token_tree().unwrap()).unwrap();

        let expaned = rules.expand(&invocation_tt).unwrap();
        assert_eq!(expaned.to_string(), expansion);
    }

    #[test]
    fn test_fail_match_pattern_by_token() {
        let macro_definition = r#"
        macro_rules! foo {
            ($ i:ident) => (
                mod $ i {}
            );
            (= $ i:ident) => (
                fn $ i() {}
            );
            (+ $ i:ident) => (
                struct $ i;
            )
        }
"#;

        let source_file = ast::SourceFile::parse(macro_definition);
        let macro_definition = source_file
            .syntax()
            .descendants()
            .find_map(ast::MacroCall::cast)
            .unwrap();

        let definition_tt = ast_to_token_tree(macro_definition.token_tree().unwrap()).unwrap();
        let rules = crate::MacroRules::parse(&definition_tt).unwrap();

        assert_expansion(&rules, "foo! { foo }", "mod foo {}");
        assert_expansion(&rules, "foo! { = bar }", "fn bar () {}");
        assert_expansion(&rules, "foo! { + Baz }", "struct Baz ;");
    }

}
<|endoftext|>


<commit_before>//! Object safe interface for file watching and reading.
use std::fmt;

use paths::{AbsPath, AbsPathBuf};

/// A set of files on the file system.
#[derive(Debug, Clone)]
pub enum Entry {
    /// The `Entry` is represented by a raw set of files.
    Files(Vec<AbsPathBuf>),
    /// The `Entry` is represented by `Directories`.
    Directories(Directories),
}

/// Specifies a set of files on the file system.
///
/// A file is included if:
///   * it has included extension
///   * it is under an `include` path
///   * it is not under `exclude` path
///
/// If many include/exclude paths match, the longest one wins.
///
/// If a path is in both `include` and `exclude`, the `exclude` one wins.
#[derive(Debug, Clone, Default)]
pub struct Directories {
    pub extensions: Vec<String>,
    pub include: Vec<AbsPathBuf>,
    pub exclude: Vec<AbsPathBuf>,
}

/// [`Handle`]'s configuration.
#[derive(Debug)]
pub struct Config {
    /// Version number to associate progress updates to the right config
    /// version.
    pub version: u32,
    /// Set of initially loaded files.
    pub load: Vec<Entry>,
    /// Index of watched entries in `load`.
    ///
    /// If a path in a watched entry is modified,the [`Handle`] should notify it.
    pub watch: Vec<usize>,
}

/// Message about an action taken by a [`Handle`].
pub enum Message {
    /// Indicate a gradual progress.
    ///
    /// This is supposed to be the number of loaded files.
    Progress { n_total: usize, n_done: usize, config_version: u32 },
    /// The handle loaded the following files' content.
    Loaded { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },
}

/// Type that will receive [`Messages`](Message) from a [`Handle`].
pub type Sender = Box<dyn Fn(Message) + Send>;

/// Interface for reading and watching files.
pub trait Handle: fmt::Debug {
    /// Spawn a new handle with the given `sender`.
    fn spawn(sender: Sender) -> Self
    where
        Self: Sized;

    /// Set this handle's configuration.
    fn set_config(&mut self, config: Config);

    /// The file's content at `path` has been modified, and should be reloaded.
    fn invalidate(&mut self, path: AbsPathBuf);

    /// Load the content of the given file, returning [`None`] if it does not
    /// exists.
    fn load_sync(&mut self, path: &AbsPath) -> Option<Vec<u8>>;
}

impl Entry {
    /// Returns:
    /// ```text
    /// Entry::Directories(Directories {
    ///     extensions: ["rs"],
    ///     include: [base],
    ///     exclude: [base/.git],
    /// })
    /// ```
    pub fn rs_files_recursively(base: AbsPathBuf) -> Entry {
        Entry::Directories(dirs(base, &[".git"]))
    }

    /// Returns:
    /// ```text
    /// Entry::Directories(Directories {
    ///     extensions: ["rs"],
    ///     include: [base],
    ///     exclude: [base/.git, base/target],
    /// })
    /// ```
    pub fn local_cargo_package(base: AbsPathBuf) -> Entry {
        Entry::Directories(dirs(base, &[".git", "target"]))
    }

    /// Returns:
    /// ```text
    /// Entry::Directories(Directories {
    ///     extensions: ["rs"],
    ///     include: [base],
    ///     exclude: [base/.git, /tests, /examples, /benches],
    /// })
    /// ```
    pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry {
        Entry::Directories(dirs(base, &[".git", "/tests", "/examples", "/benches"]))
    }

    /// Returns `true` if `path` is included in `self`.
    ///
    /// See [`Directories::contains_file`].
    pub fn contains_file(&self, path: &AbsPath) -> bool {
        match self {
            Entry::Files(files) => files.iter().any(|it| it == path),
            Entry::Directories(dirs) => dirs.contains_file(path),
        }
    }

    /// Returns `true` if `path` is included in `self`.
    ///
    /// - If `self` is `Entry::Files`, returns `false`
    /// - Else, see [`Directories::contains_dir`].
    pub fn contains_dir(&self, path: &AbsPath) -> bool {
        match self {
            Entry::Files(_) => false,
            Entry::Directories(dirs) => dirs.contains_dir(path),
        }
    }
}

impl Directories {
    /// Returns `true` if `path` is included in `self`.
    pub fn contains_file(&self, path: &AbsPath) -> bool {
        let ext = path.extension().unwrap_or_default();
        self.extensions.iter().any(|it| it.as_str() == ext) && self.includes_path(path)
    }

    /// Returns `true` if `path` is included in `self`.
    ///
    /// Since `path` is supposed to be a directory, this will not take extension
    /// into account.
    pub fn contains_dir(&self, path: &AbsPath) -> bool {
        self.includes_path(path)
    }

    /// Returns `true` if `path` is included in `self`.
    ///
    /// It is included if
    ///   - An element in `self.include` is a prefix of `path`.
    ///   - This path is longer than any element in `self.exclude` that is a prefix
    ///     of `path`. In case of equality, exclusion wins.
    fn includes_path(&self, path: &AbsPath) -> bool {
        let mut include: Option<&AbsPathBuf> = None;
        for incl in &self.include {
            if path.starts_with(incl) {
                include = Some(match include {
                    Some(prev) if prev.starts_with(incl) => prev,
                    _ => incl,
                })
            }
        }
        let include = match include {
            Some(it) => it,
            None => return false,
        };
        for excl in &self.exclude {
            if path.starts_with(excl) && excl.starts_with(include) {
                return false;
            }
        }
        true
    }
}

/// Returns :
/// ```text
/// Directories {
///     extensions: ["rs"],
///     include: [base],
///     exclude: [base/<exclude>],
/// }
/// ```
fn dirs(base: AbsPathBuf, exclude: &[&str]) -> Directories {
    let exclude = exclude.iter().map(|it| base.join(it)).collect::<Vec<_>>();
    Directories { extensions: vec!["rs".to_string()], include: vec![base], exclude }
}

impl fmt::Debug for Message {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Message::Loaded { files } => {
                f.debug_struct("Loaded").field("n_files", &files.len()).finish()
            }
            Message::Progress { n_total, n_done, config_version } => f
                .debug_struct("Progress")
                .field("n_total", n_total)
                .field("n_done", n_done)
                .field("config_version", config_version)
                .finish(),
        }
    }
}

#[test]
fn handle_is_object_safe() {
    fn _assert(_: &dyn Handle) {}
}
<commit_msg>Refactor: use iterator methods over `for` loops<commit_after>//! Object safe interface for file watching and reading.
use std::fmt;

use paths::{AbsPath, AbsPathBuf};

/// A set of files on the file system.
#[derive(Debug, Clone)]
pub enum Entry {
    /// The `Entry` is represented by a raw set of files.
    Files(Vec<AbsPathBuf>),
    /// The `Entry` is represented by `Directories`.
    Directories(Directories),
}

/// Specifies a set of files on the file system.
///
/// A file is included if:
///   * it has included extension
///   * it is under an `include` path
///   * it is not under `exclude` path
///
/// If many include/exclude paths match, the longest one wins.
///
/// If a path is in both `include` and `exclude`, the `exclude` one wins.
#[derive(Debug, Clone, Default)]
pub struct Directories {
    pub extensions: Vec<String>,
    pub include: Vec<AbsPathBuf>,
    pub exclude: Vec<AbsPathBuf>,
}

/// [`Handle`]'s configuration.
#[derive(Debug)]
pub struct Config {
    /// Version number to associate progress updates to the right config
    /// version.
    pub version: u32,
    /// Set of initially loaded files.
    pub load: Vec<Entry>,
    /// Index of watched entries in `load`.
    ///
    /// If a path in a watched entry is modified,the [`Handle`] should notify it.
    pub watch: Vec<usize>,
}

/// Message about an action taken by a [`Handle`].
pub enum Message {
    /// Indicate a gradual progress.
    ///
    /// This is supposed to be the number of loaded files.
    Progress { n_total: usize, n_done: usize, config_version: u32 },
    /// The handle loaded the following files' content.
    Loaded { files: Vec<(AbsPathBuf, Option<Vec<u8>>)> },
}

/// Type that will receive [`Messages`](Message) from a [`Handle`].
pub type Sender = Box<dyn Fn(Message) + Send>;

/// Interface for reading and watching files.
pub trait Handle: fmt::Debug {
    /// Spawn a new handle with the given `sender`.
    fn spawn(sender: Sender) -> Self
    where
        Self: Sized;

    /// Set this handle's configuration.
    fn set_config(&mut self, config: Config);

    /// The file's content at `path` has been modified, and should be reloaded.
    fn invalidate(&mut self, path: AbsPathBuf);

    /// Load the content of the given file, returning [`None`] if it does not
    /// exists.
    fn load_sync(&mut self, path: &AbsPath) -> Option<Vec<u8>>;
}

impl Entry {
    /// Returns:
    /// ```text
    /// Entry::Directories(Directories {
    ///     extensions: ["rs"],
    ///     include: [base],
    ///     exclude: [base/.git],
    /// })
    /// ```
    pub fn rs_files_recursively(base: AbsPathBuf) -> Entry {
        Entry::Directories(dirs(base, &[".git"]))
    }

    /// Returns:
    /// ```text
    /// Entry::Directories(Directories {
    ///     extensions: ["rs"],
    ///     include: [base],
    ///     exclude: [base/.git, base/target],
    /// })
    /// ```
    pub fn local_cargo_package(base: AbsPathBuf) -> Entry {
        Entry::Directories(dirs(base, &[".git", "target"]))
    }

    /// Returns:
    /// ```text
    /// Entry::Directories(Directories {
    ///     extensions: ["rs"],
    ///     include: [base],
    ///     exclude: [base/.git, /tests, /examples, /benches],
    /// })
    /// ```
    pub fn cargo_package_dependency(base: AbsPathBuf) -> Entry {
        Entry::Directories(dirs(base, &[".git", "/tests", "/examples", "/benches"]))
    }

    /// Returns `true` if `path` is included in `self`.
    ///
    /// See [`Directories::contains_file`].
    pub fn contains_file(&self, path: &AbsPath) -> bool {
        match self {
            Entry::Files(files) => files.iter().any(|it| it == path),
            Entry::Directories(dirs) => dirs.contains_file(path),
        }
    }

    /// Returns `true` if `path` is included in `self`.
    ///
    /// - If `self` is `Entry::Files`, returns `false`
    /// - Else, see [`Directories::contains_dir`].
    pub fn contains_dir(&self, path: &AbsPath) -> bool {
        match self {
            Entry::Files(_) => false,
            Entry::Directories(dirs) => dirs.contains_dir(path),
        }
    }
}

impl Directories {
    /// Returns `true` if `path` is included in `self`.
    pub fn contains_file(&self, path: &AbsPath) -> bool {
        let ext = path.extension().unwrap_or_default();
        self.extensions.iter().any(|it| it.as_str() == ext) && self.includes_path(path)
    }

    /// Returns `true` if `path` is included in `self`.
    ///
    /// Since `path` is supposed to be a directory, this will not take extension
    /// into account.
    pub fn contains_dir(&self, path: &AbsPath) -> bool {
        self.includes_path(path)
    }

    /// Returns `true` if `path` is included in `self`.
    ///
    /// It is included if
    ///   - An element in `self.include` is a prefix of `path`.
    ///   - This path is longer than any element in `self.exclude` that is a prefix
    ///     of `path`. In case of equality, exclusion wins.
    fn includes_path(&self, path: &AbsPath) -> bool {
        let include = self.include.iter().fold(None::<&AbsPathBuf>, |include, incl| {
            if !path.starts_with(incl) {
                return include;
            }

            Some(match include {
                Some(prev) if prev.starts_with(incl) => prev,
                _ => incl,
            })
        });

        let include = match include {
            Some(it) => it,
            None => return false,
        };

        !self.exclude.iter().any(|excl| path.starts_with(excl) && excl.starts_with(include))
    }
}

/// Returns :
/// ```text
/// Directories {
///     extensions: ["rs"],
///     include: [base],
///     exclude: [base/<exclude>],
/// }
/// ```
fn dirs(base: AbsPathBuf, exclude: &[&str]) -> Directories {
    let exclude = exclude.iter().map(|it| base.join(it)).collect::<Vec<_>>();
    Directories { extensions: vec!["rs".to_string()], include: vec![base], exclude }
}

impl fmt::Debug for Message {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Message::Loaded { files } => {
                f.debug_struct("Loaded").field("n_files", &files.len()).finish()
            }
            Message::Progress { n_total, n_done, config_version } => f
                .debug_struct("Progress")
                .field("n_total", n_total)
                .field("n_done", n_done)
                .field("config_version", config_version)
                .finish(),
        }
    }
}

#[test]
fn handle_is_object_safe() {
    fn _assert(_: &dyn Handle) {}
}
<|endoftext|>


<commit_before>/// Render some nice human-readable asciidoc files
use crate::collect_docs::{Field, Struct, Type, TypeName};
use std::io::{Result, Write};

pub trait ToAdoc {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()>;
}

impl ToAdoc for Struct {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        writeln!(w, "= {}", self.name)?;
        writeln!(w)?;
        writeln!(w, "{}", self.docs)?;
        writeln!(w)?;
        writeln!(w, ".Fields")?;
        writeln!(w)?;

        for field in &self.fields {
            field.write_adoc(w)?;
        }

        Ok(())
    }
}

impl ToAdoc for Field {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        write!(w, "* `{}`", self.name)?;
        if self.required {
            writeln!(w, " _(required)_")?;
        } else {
            writeln!(w, " _(optional)_")?;
        }
        writeln!(w, "+")?;
        write!(w, "Type: `")?;
        self.r#type.write_adoc(w)?;
        writeln!(w, "`")?;

        let docs = self.docs.replace("\n\n", "\n+\n");
        if !docs.is_empty() {
            writeln!(w, "+")?;
            writeln!(w, "{}", docs)?;
        }

        Ok(())
    }
}

impl ToAdoc for Type {
    fn write_adoc(&self, mut w: &mut dyn Write) -> Result<()> {
        match self {
            Type::Flat(name) => name.write_adoc(w),
            Type::Nested {
                container_name,
                nested,
            } => {
                container_name.write_adoc(&mut w)?;
                write!(w, "<")?;
                let mut first = true;
                for t in nested {
                    if first {
                        first = false;
                    } else {
                        write!(w, ", ")?;
                    }
                    {
                        t.write_adoc(w)?;
                    }
                }
                write!(w, ">")?;
                Ok(())
            }
        }
    }
}

impl ToAdoc for TypeName {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        match self {
            TypeName::Primitive(name) => {
                let name = match name.as_str() {
                    "BTreeMap" => "Map",
                    "HashMap" => "Map",
                    n => n,
                };
                write!(w, "{}", name)
            }
            TypeName::Link(name) => write!(w, "<<{}>>", name),
        }
    }
}
<commit_msg>Annotate generated docs<commit_after>/// Render some nice human-readable asciidoc files
use crate::collect_docs::{Field, Struct, Type, TypeName};
use std::io::{Result, Write};

pub trait ToAdoc {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()>;
}

impl ToAdoc for Struct {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        writeln!(w, "// Do not edit this file directly!")?;
        writeln!(
            w,
            "// It was generated using derive-collect-docs and will be updated automatically."
        )?;
        writeln!(w)?;
        writeln!(w, "= {}", self.name)?;
        writeln!(w)?;
        writeln!(w, "{}", self.docs)?;
        writeln!(w)?;
        writeln!(w, ".Fields")?;
        writeln!(w)?;

        for field in &self.fields {
            field.write_adoc(w)?;
        }

        Ok(())
    }
}

impl ToAdoc for Field {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        write!(w, "* `{}`", self.name)?;
        if self.required {
            writeln!(w, " _(required)_")?;
        } else {
            writeln!(w, " _(optional)_")?;
        }
        writeln!(w, "+")?;
        write!(w, "Type: `")?;
        self.r#type.write_adoc(w)?;
        writeln!(w, "`")?;

        let docs = self.docs.replace("\n\n", "\n+\n");
        if !docs.is_empty() {
            writeln!(w, "+")?;
            writeln!(w, "{}", docs)?;
        }

        Ok(())
    }
}

impl ToAdoc for Type {
    fn write_adoc(&self, mut w: &mut dyn Write) -> Result<()> {
        match self {
            Type::Flat(name) => name.write_adoc(w),
            Type::Nested {
                container_name,
                nested,
            } => {
                container_name.write_adoc(&mut w)?;
                write!(w, "<")?;
                let mut first = true;
                for t in nested {
                    if first {
                        first = false;
                    } else {
                        write!(w, ", ")?;
                    }
                    {
                        t.write_adoc(w)?;
                    }
                }
                write!(w, ">")?;
                Ok(())
            }
        }
    }
}

impl ToAdoc for TypeName {
    fn write_adoc(&self, w: &mut dyn Write) -> Result<()> {
        match self {
            TypeName::Primitive(name) => {
                let name = match name.as_str() {
                    "BTreeMap" => "Map",
                    "HashMap" => "Map",
                    n => n,
                };
                write!(w, "{}", name)
            }
            TypeName::Link(name) => write!(w, "<<{}>>", name),
        }
    }
}
<|endoftext|>