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

#![feature(box_syntax)]
#![feature(box_patterns)]
#![feature(rustc_private)]
#![feature(collections)]
#![feature(exit_status)]
#![feature(str_char)]

// TODO we're going to allocate a whole bunch of temp Strings, is it worth
// keeping some scratch mem for this and running our own StrPool?
// TODO for lint violations of names, emit a refactor script

#[macro_use]
extern crate log;

extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate syntax;

extern crate strings;

use rustc::session::Session;
use rustc::session::config::{self, Input};
use rustc_driver::{driver, CompilerCalls, Compilation};

use syntax::ast;
use syntax::codemap::CodeMap;
use syntax::diagnostics;
use syntax::visit;

use std::path::PathBuf;
use std::collections::HashMap;

use changes::ChangeSet;
use visitor::FmtVisitor;

mod changes;
mod visitor;
mod functions;
mod missed_spans;
mod lists;
mod utils;
mod types;
mod expr;
mod imports;

const IDEAL_WIDTH: usize = 80;
const LEEWAY: usize = 5;
const MAX_WIDTH: usize = 100;
const MIN_STRING: usize = 10;
const TAB_SPACES: usize = 4;
const FN_BRACE_STYLE: BraceStyle = BraceStyle::SameLineWhere;
const FN_RETURN_INDENT: ReturnIndent = ReturnIndent::WithArgs;
// When we get scoped annotations, we should have rustfmt::skip.
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";

#[derive(Copy, Clone)]
pub enum WriteMode {
    Overwrite,
    // str is the extension of the new file
    NewFile(&'static str),
    // Write the output to stdout.
    Display,
    // Return the result as a mapping from filenames to StringBuffers.
    Return(&'static Fn(HashMap<String, String>)),
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum BraceStyle {
    AlwaysNextLine,
    PreferSameLine,
    // Prefer same line except where there is a where clause, in which case force
    // the brace to the next line.
    SameLineWhere,
}

// How to indent a function's return type.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum ReturnIndent {
    // Aligned with the arguments
    WithArgs,
    // Aligned with the where clause
    WithWhereClause,
}

// Formatting which depends on the AST.
fn fmt_ast<'a>(krate: &ast::Crate, codemap: &'a CodeMap) -> ChangeSet<'a> {
    let mut visitor = FmtVisitor::from_codemap(codemap);
    visit::walk_crate(&mut visitor, krate);
    let files = codemap.files.borrow();
    if let Some(last) = files.last() {
        visitor.format_missing(last.end_pos);
    }

    visitor.changes
}

// Formatting done on a char by char or line by line basis.
// TODO warn on TODOs and FIXMEs without an issue number
// TODO warn on bad license
// TODO other stuff for parity with make tidy
fn fmt_lines(changes: &mut ChangeSet) {
    let mut truncate_todo = Vec::new();

    // Iterate over the chars in the change set.
    for (f, text) in changes.text() {
        let mut trims = vec![];
        let mut last_wspace: Option<usize> = None;
        let mut line_len = 0;
        let mut cur_line = 1;
        let mut newline_count = 0;
        for (c, b) in text.chars() {
            if c == '\n' { // TOOD test for \r too
                // Check for (and record) trailing whitespace.
                if let Some(lw) = last_wspace {
                    trims.push((cur_line, lw, b));
                    line_len -= b - lw;
                }
                // Check for any line width errors we couldn't correct.
                if line_len > MAX_WIDTH {
                    // TODO store the error rather than reporting immediately.
                    println!("Rustfmt couldn't fix (sorry). {}:{}: line longer than {} characters",
                             f, cur_line, MAX_WIDTH);
                }
                line_len = 0;
                cur_line += 1;
                newline_count += 1;
                last_wspace = None;
            } else {
                newline_count = 0;
                line_len += 1;
                if c.is_whitespace() {
                    if last_wspace.is_none() {
                        last_wspace = Some(b);
                    }
                } else {
                    last_wspace = None;
                }
            }
        }

        if newline_count > 1 {
            debug!("track truncate: {} {} {}", f, text.len, newline_count);
            truncate_todo.push((f, text.len - newline_count + 1))
        }

        for &(l, _, _) in trims.iter() {
            // TODO store the error rather than reporting immediately.
            println!("Rustfmt left trailing whitespace at {}:{} (sorry)", f, l);
        }
    }

    for (f, l) in truncate_todo {
        // This unsafe block and the ridiculous dance with the cast is because
        // the borrow checker thinks the first borrow of changes lasts for the
        // whole function.
        unsafe {
            (*(changes as *const ChangeSet as *mut ChangeSet)).get_mut(f).truncate(l);
        }
    }
}

struct RustFmtCalls {
    input_path: Option<PathBuf>,
    write_mode: WriteMode,
}

impl<'a> CompilerCalls<'a> for RustFmtCalls {
    fn early_callback(&mut self,
                      _: &getopts::Matches,
                      _: &diagnostics::registry::Registry)
                      -> Compilation {
        Compilation::Continue
    }

    fn some_input(&mut self,
                  input: Input,
                  input_path: Option<PathBuf>)
                  -> (Input, Option<PathBuf>) {
        match input_path {
            Some(ref ip) => self.input_path = Some(ip.clone()),
            _ => {
                // FIXME should handle string input and write to stdout or something
                panic!("No input path");
            }
        }
        (input, input_path)
    }

    fn no_input(&mut self,
                _: &getopts::Matches,
                _: &config::Options,
                _: &Option<PathBuf>,
                _: &Option<PathBuf>,
                _: &diagnostics::registry::Registry)
                -> Option<(Input, Option<PathBuf>)> {
        panic!("No input supplied to RustFmt");
    }

    fn late_callback(&mut self,
                     _: &getopts::Matches,
                     _: &Session,
                     _: &Input,
                     _: &Option<PathBuf>,
                     _: &Option<PathBuf>)
                     -> Compilation {
        Compilation::Continue
    }

    fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
        let write_mode = self.write_mode;
        let mut control = driver::CompileController::basic();
        control.after_parse.stop = Compilation::Stop;
        control.after_parse.callback = box move |state| {
            let krate = state.krate.unwrap();
            let codemap = state.session.codemap();
            let mut changes = fmt_ast(krate, codemap);
            // For some reason, the codemap does not include terminating newlines
            // so we must add one on for each file. This is sad.
            changes.append_newlines();
            fmt_lines(&mut changes);

            // FIXME(#5) Should be user specified whether to show or replace.
            let result = changes.write_all_files(write_mode);

            match result {
                Err(msg) => println!("Error writing files: {}", msg),
                Ok(result) => {
                    if let WriteMode::Return(callback) = write_mode {
                        callback(result);
                    }
                }
            }
        };

        control
    }
}

fn run(args: Vec<String>, write_mode: WriteMode) {
    let mut call_ctxt = RustFmtCalls { input_path: None, write_mode: write_mode };
    rustc_driver::run_compiler(&args, &mut call_ctxt);
}

fn main() {
    let args: Vec<_> = std::env::args().collect();
    //run(args, WriteMode::Display);
    run(args, WriteMode::Overwrite);
    std::env::set_exit_status(0);

    // TODO unit tests
    // let fmt = ListFormatting {
    //     tactic: ListTactic::Horizontal,
    //     separator: ",",
    //     trailing_separator: SeparatorTactic::Vertical,
    //     indent: 2,
    //     h_width: 80,
    //     v_width: 100,
    // };
    // let inputs = vec![(format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new())];
    // let s = write_list(&inputs, &fmt);
    // println!("  {}", s);
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::fs;
    use std::io::Read;
    use super::*;
    use super::run;

    // For now, the only supported regression tests are idempotent tests - the input and
    // output must match exactly.
    // FIXME(#28) would be good to check for error messages and fail on them, or at least report.
    #[test]
    fn idempotent_tests() {
        println!("Idempotent tests:");
        unsafe { FAILURES = 0; }

        // Get all files in the tests/idem directory
        let files = fs::read_dir("tests/idem").unwrap();
        // For each file, run rustfmt and collect the output
        let mut count = 0;
        for entry in files {
            let path = entry.unwrap().path();
            let file_name = path.to_str().unwrap();
            println!("Testing '{}'...", file_name);
            run(vec!["rustfmt".to_string(), file_name.to_string()], WriteMode::Return(HANDLE_RESULT));
            count += 1;
        }
        // And also dogfood ourselves!
        println!("Testing 'src/mod.rs'...");
        run(vec!["rustfmt".to_string(), "src/mod.rs".to_string()], WriteMode::Return(HANDLE_RESULT));
        count += 1;

        // Display results
        let fails = unsafe { FAILURES };
        println!("Ran {} idempotent tests; {} failures.", count, fails);
        assert!(fails == 0, "{} idempotent tests failed", fails);
    }

    // 'global' used by sys_tests and handle_result.
    static mut FAILURES: i32 = 0;
    // Ick, just needed to get a &'static to handle_result.
    static HANDLE_RESULT: &'static Fn(HashMap<String, String>) = &handle_result;

    // Compare output to input.
    fn handle_result(result: HashMap<String, String>) {
        let mut fails = 0;

        for file_name in result.keys() {
            let mut f = fs::File::open(file_name).unwrap();
            let mut text = String::new();
            f.read_to_string(&mut text).unwrap();
            if result[file_name] != text {
                fails += 1;
                println!("Mismatch in {}.", file_name);
                println!("{}", result[file_name]);
            }
        }

        if fails > 0 {
            unsafe {
                FAILURES += 1;
            }
        }
    }
}
<commit_msg>Fix warnings in `cargo test`<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(box_syntax)]
#![feature(box_patterns)]
#![feature(rustc_private)]
#![feature(collections)]
#![feature(str_char)]

#![cfg_attr(not(test), feature(exit_status))]

// TODO we're going to allocate a whole bunch of temp Strings, is it worth
// keeping some scratch mem for this and running our own StrPool?
// TODO for lint violations of names, emit a refactor script

#[macro_use]
extern crate log;

extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate syntax;

extern crate strings;

use rustc::session::Session;
use rustc::session::config::{self, Input};
use rustc_driver::{driver, CompilerCalls, Compilation};

use syntax::ast;
use syntax::codemap::CodeMap;
use syntax::diagnostics;
use syntax::visit;

use std::path::PathBuf;
use std::collections::HashMap;

use changes::ChangeSet;
use visitor::FmtVisitor;

mod changes;
mod visitor;
mod functions;
mod missed_spans;
mod lists;
mod utils;
mod types;
mod expr;
mod imports;

const IDEAL_WIDTH: usize = 80;
const LEEWAY: usize = 5;
const MAX_WIDTH: usize = 100;
const MIN_STRING: usize = 10;
const TAB_SPACES: usize = 4;
const FN_BRACE_STYLE: BraceStyle = BraceStyle::SameLineWhere;
const FN_RETURN_INDENT: ReturnIndent = ReturnIndent::WithArgs;
// When we get scoped annotations, we should have rustfmt::skip.
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";

#[derive(Copy, Clone)]
pub enum WriteMode {
    Overwrite,
    // str is the extension of the new file
    NewFile(&'static str),
    // Write the output to stdout.
    Display,
    // Return the result as a mapping from filenames to StringBuffers.
    Return(&'static Fn(HashMap<String, String>)),
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum BraceStyle {
    AlwaysNextLine,
    PreferSameLine,
    // Prefer same line except where there is a where clause, in which case force
    // the brace to the next line.
    SameLineWhere,
}

// How to indent a function's return type.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
enum ReturnIndent {
    // Aligned with the arguments
    WithArgs,
    // Aligned with the where clause
    WithWhereClause,
}

// Formatting which depends on the AST.
fn fmt_ast<'a>(krate: &ast::Crate, codemap: &'a CodeMap) -> ChangeSet<'a> {
    let mut visitor = FmtVisitor::from_codemap(codemap);
    visit::walk_crate(&mut visitor, krate);
    let files = codemap.files.borrow();
    if let Some(last) = files.last() {
        visitor.format_missing(last.end_pos);
    }

    visitor.changes
}

// Formatting done on a char by char or line by line basis.
// TODO warn on TODOs and FIXMEs without an issue number
// TODO warn on bad license
// TODO other stuff for parity with make tidy
fn fmt_lines(changes: &mut ChangeSet) {
    let mut truncate_todo = Vec::new();

    // Iterate over the chars in the change set.
    for (f, text) in changes.text() {
        let mut trims = vec![];
        let mut last_wspace: Option<usize> = None;
        let mut line_len = 0;
        let mut cur_line = 1;
        let mut newline_count = 0;
        for (c, b) in text.chars() {
            if c == '\n' { // TOOD test for \r too
                // Check for (and record) trailing whitespace.
                if let Some(lw) = last_wspace {
                    trims.push((cur_line, lw, b));
                    line_len -= b - lw;
                }
                // Check for any line width errors we couldn't correct.
                if line_len > MAX_WIDTH {
                    // TODO store the error rather than reporting immediately.
                    println!("Rustfmt couldn't fix (sorry). {}:{}: line longer than {} characters",
                             f, cur_line, MAX_WIDTH);
                }
                line_len = 0;
                cur_line += 1;
                newline_count += 1;
                last_wspace = None;
            } else {
                newline_count = 0;
                line_len += 1;
                if c.is_whitespace() {
                    if last_wspace.is_none() {
                        last_wspace = Some(b);
                    }
                } else {
                    last_wspace = None;
                }
            }
        }

        if newline_count > 1 {
            debug!("track truncate: {} {} {}", f, text.len, newline_count);
            truncate_todo.push((f, text.len - newline_count + 1))
        }

        for &(l, _, _) in trims.iter() {
            // TODO store the error rather than reporting immediately.
            println!("Rustfmt left trailing whitespace at {}:{} (sorry)", f, l);
        }
    }

    for (f, l) in truncate_todo {
        // This unsafe block and the ridiculous dance with the cast is because
        // the borrow checker thinks the first borrow of changes lasts for the
        // whole function.
        unsafe {
            (*(changes as *const ChangeSet as *mut ChangeSet)).get_mut(f).truncate(l);
        }
    }
}

struct RustFmtCalls {
    input_path: Option<PathBuf>,
    write_mode: WriteMode,
}

impl<'a> CompilerCalls<'a> for RustFmtCalls {
    fn early_callback(&mut self,
                      _: &getopts::Matches,
                      _: &diagnostics::registry::Registry)
                      -> Compilation {
        Compilation::Continue
    }

    fn some_input(&mut self,
                  input: Input,
                  input_path: Option<PathBuf>)
                  -> (Input, Option<PathBuf>) {
        match input_path {
            Some(ref ip) => self.input_path = Some(ip.clone()),
            _ => {
                // FIXME should handle string input and write to stdout or something
                panic!("No input path");
            }
        }
        (input, input_path)
    }

    fn no_input(&mut self,
                _: &getopts::Matches,
                _: &config::Options,
                _: &Option<PathBuf>,
                _: &Option<PathBuf>,
                _: &diagnostics::registry::Registry)
                -> Option<(Input, Option<PathBuf>)> {
        panic!("No input supplied to RustFmt");
    }

    fn late_callback(&mut self,
                     _: &getopts::Matches,
                     _: &Session,
                     _: &Input,
                     _: &Option<PathBuf>,
                     _: &Option<PathBuf>)
                     -> Compilation {
        Compilation::Continue
    }

    fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
        let write_mode = self.write_mode;
        let mut control = driver::CompileController::basic();
        control.after_parse.stop = Compilation::Stop;
        control.after_parse.callback = box move |state| {
            let krate = state.krate.unwrap();
            let codemap = state.session.codemap();
            let mut changes = fmt_ast(krate, codemap);
            // For some reason, the codemap does not include terminating newlines
            // so we must add one on for each file. This is sad.
            changes.append_newlines();
            fmt_lines(&mut changes);

            // FIXME(#5) Should be user specified whether to show or replace.
            let result = changes.write_all_files(write_mode);

            match result {
                Err(msg) => println!("Error writing files: {}", msg),
                Ok(result) => {
                    if let WriteMode::Return(callback) = write_mode {
                        callback(result);
                    }
                }
            }
        };

        control
    }
}

fn run(args: Vec<String>, write_mode: WriteMode) {
    let mut call_ctxt = RustFmtCalls { input_path: None, write_mode: write_mode };
    rustc_driver::run_compiler(&args, &mut call_ctxt);
}

#[cfg(not(test))]
fn main() {
    let args: Vec<_> = std::env::args().collect();
    //run(args, WriteMode::Display);
    run(args, WriteMode::Overwrite);
    std::env::set_exit_status(0);

    // TODO unit tests
    // let fmt = ListFormatting {
    //     tactic: ListTactic::Horizontal,
    //     separator: ",",
    //     trailing_separator: SeparatorTactic::Vertical,
    //     indent: 2,
    //     h_width: 80,
    //     v_width: 100,
    // };
    // let inputs = vec![(format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new()),
    //                   (format!("foo"), String::new())];
    // let s = write_list(&inputs, &fmt);
    // println!("  {}", s);
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use std::fs;
    use std::io::Read;
    use super::*;
    use super::run;

    // For now, the only supported regression tests are idempotent tests - the input and
    // output must match exactly.
    // FIXME(#28) would be good to check for error messages and fail on them, or at least report.
    #[test]
    fn idempotent_tests() {
        println!("Idempotent tests:");
        unsafe { FAILURES = 0; }

        // Get all files in the tests/idem directory
        let files = fs::read_dir("tests/idem").unwrap();
        // For each file, run rustfmt and collect the output
        let mut count = 0;
        for entry in files {
            let path = entry.unwrap().path();
            let file_name = path.to_str().unwrap();
            println!("Testing '{}'...", file_name);
            run(vec!["rustfmt".to_string(), file_name.to_string()], WriteMode::Return(HANDLE_RESULT));
            count += 1;
        }
        // And also dogfood ourselves!
        println!("Testing 'src/mod.rs'...");
        run(vec!["rustfmt".to_string(), "src/mod.rs".to_string()], WriteMode::Return(HANDLE_RESULT));
        count += 1;

        // Display results
        let fails = unsafe { FAILURES };
        println!("Ran {} idempotent tests; {} failures.", count, fails);
        assert!(fails == 0, "{} idempotent tests failed", fails);
    }

    // 'global' used by sys_tests and handle_result.
    static mut FAILURES: i32 = 0;
    // Ick, just needed to get a &'static to handle_result.
    static HANDLE_RESULT: &'static Fn(HashMap<String, String>) = &handle_result;

    // Compare output to input.
    fn handle_result(result: HashMap<String, String>) {
        let mut fails = 0;

        for file_name in result.keys() {
            let mut f = fs::File::open(file_name).unwrap();
            let mut text = String::new();
            f.read_to_string(&mut text).unwrap();
            if result[file_name] != text {
                fails += 1;
                println!("Mismatch in {}.", file_name);
                println!("{}", result[file_name]);
            }
        }

        if fails > 0 {
            unsafe {
                FAILURES += 1;
            }
        }
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::{CStr, CString};
use std::fmt;
use std::ptr;
use super::error::SBError;
use super::platform::SBPlatform;
use super::stream::SBStream;
use super::target::SBTarget;
use sys;

/// Creates [`SBTarget`]s, provides access to them and manages
/// the overall debugging experience.
///
/// # Initialization and Teardown
///
/// LLDB must be initialized before the functionality is used. This
/// is done with `SBDebugger::initialize()`:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
/// ```
///
/// Similarly, it must be terminated after you are done using it:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
/// // Use LLDB functionality ...
/// SBDebugger::terminate();
/// ```
///
/// Once you've initialized LLDB, you're ready to create an instance
/// of `SBDebugger`:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
///
/// let debugger = SBDebugger::create(false);
/// // ... configure the debugger if needed ...
/// // ... create a target and do stuff ...
///
/// SBDebugger::terminate();
/// ```
///
/// # Configuration
///
/// ## Async Mode
///
/// While it is best to use LLDB in asynchronous mode, it does offer a
/// synchronous mode, which can be easier to use for quick experiments
/// or scripts.
///
/// In synchronous mode, calls to the LLDB API do not return until the
/// underlying action has been completed. This means that the thread
/// from which you call LLDB will be blocked during that time, so this
/// is not an ideal way to use LLDB for building interactive tools
/// or a new user interface.
///
/// In asynchronous mode, calls to the LLDB API will return immediately
/// without waiting for the action to complete. This means that actions
/// like launching a target, continuing the execution of a process and
/// so on won't be completed immediately and you must process events
/// to see what the results of an action are.
///
/// Synchronous mode can be enabled by using [`set_async`] and passing it
/// a `false` value. You can see if you're in asynchronous mode or not
/// by calling [`async`].
///
/// # Target Management
///
/// The `SBDebugger` instance tracks the various targets that are
/// currently known to the debugger.
///
/// Typically, you create a target with [`create_target`],
/// [`create_target_simple`] or one of the related methods.
///
/// Sometimes, you'll want to create a target without an associated
/// executable. A common use case for this is to attach to a process
/// by name or process ID where you don't know the executable in advance.
/// The most convenient way to do this is:
///
/// ```
/// # use lldb::SBDebugger;
/// # SBDebugger::initialize();
/// let debugger = SBDebugger::create(false);
/// if let Some(target) = debugger.create_target_simple("") {
///     println!("Got a target: {:?}", target);
///     // Now, maybe we'd like to attach to something.
/// }
/// # SBDebugger::terminate();
/// ```
///
/// You can iterate over these targets which have been created by
/// using [`targets`]:
///
/// ```no_run
/// # use lldb::{SBDebugger, SBTarget};
/// # fn look_at_targets(debugger: SBDebugger) {
/// // Iterate over the targets...
/// for target in debugger.targets() {
///     println!("Hello {:?}!", target);
/// }
/// // Or collect them into a vector!
/// let targets = debugger.targets().collect::<Vec<SBTarget>>();
/// # }
/// ```
///
/// # Platform Management
///
/// ...
///
/// [`SBTarget`]: struct.SBTarget.html
/// [`set_async`]: #method.set_async
/// [`async`]: #method.async
/// [`create_target`]: #method.create_target
/// [`create_target_simple`]: #method.create_target_simple
/// [`targets`]: #method.targets
pub struct SBDebugger {
    /// The underlying raw `SBDebuggerRef`.
    pub raw: sys::SBDebuggerRef,
}

impl SBDebugger {
    /// Initialize LLDB.
    ///
    /// This should be called before LLDB functionality is used.
    pub fn initialize() {
        unsafe { sys::SBDebuggerInitialize() };
    }

    /// Tear down LLDB.
    ///
    /// This should be called once the application no longer needs
    /// to use LLDB functionality. Typically, this is called as the
    /// application exits.
    pub fn terminate() {
        unsafe { sys::SBDebuggerTerminate() };
    }

    /// Create a new instance of `SBDebugger`.
    ///
    /// If `source_init_files` is `true`, then `~/.lldbinit` will
    /// be processed.
    pub fn create(source_init_files: bool) -> SBDebugger {
        SBDebugger { raw: unsafe { sys::SBDebuggerCreate2(source_init_files as u8) } }
    }

    /// Get whether or not the debugger is in async mode.
    ///
    /// When in async mode, the debugger returns immediately when
    /// stepping or continuing without waiting for the process
    /// to change state.
    pub fn async(&self) -> bool {
        unsafe { sys::SBDebuggerGetAsync(self.raw) != 0 }
    }

    /// Set the debugger to be in async mode or not.
    ///
    /// When in async mode, the debugger returns immediately when
    /// stepping or continuing without waiting for the process
    /// to change state.
    pub fn set_async(&mut self, async: bool) {
        unsafe { sys::SBDebuggerSetAsync(self.raw, async as u8) }
    }

    /// Get the LLDB version string.
    pub fn version() -> String {
        unsafe {
            match CStr::from_ptr(sys::SBDebuggerGetVersionString()).to_str() {
                Ok(s) => s.to_owned(),
                _ => panic!("No version string?"),
            }
        }
    }

    /// Create a target.
    ///
    /// The executable name may be an empty string to create
    /// an empty target.
    pub fn create_target(&self,
                         executable: &str,
                         target_triple: Option<&str>,
                         platform_name: Option<&str>,
                         add_dependent_modules: bool)
                         -> Result<SBTarget, SBError> {
        let executable = CString::new(executable).unwrap();
        let target_triple = target_triple.map(|s| CString::new(s).unwrap());
        let platform_name = platform_name.map(|s| CString::new(s).unwrap());
        let error = SBError::new();
        let target = unsafe {
            sys::SBDebuggerCreateTarget(self.raw,
                                        executable.as_ptr(),
                                        target_triple.map_or(ptr::null(), |s| s.as_ptr()),
                                        platform_name.map_or(ptr::null(), |s| s.as_ptr()),
                                        add_dependent_modules as u8,
                                        error.raw)
        };
        if error.is_success() {
            Ok(SBTarget::wrap(target))
        } else {
            Err(error)
        }
    }

    /// Create a target from just an executable name.
    ///
    /// The executable name may be an empty string to create
    /// an empty target.
    ///
    /// Using [`create_target`] is preferred in most cases as
    /// that provides access to an `SBError` to inform the caller
    /// about what might have gone wrong.
    pub fn create_target_simple(&self, executable: &str) -> Option<SBTarget> {
        let executable = CString::new(executable).unwrap();
        SBTarget::maybe_wrap(unsafe { sys::SBDebuggerCreateTarget2(self.raw, executable.as_ptr()) })
    }

    /// Get an iterator over the [targets] known to this debugger instance.
    ///
    /// [targets]: struct.SBTarget.html
    pub fn targets(&self) -> SBDebuggerTargetIter {
        SBDebuggerTargetIter {
            debugger: self,
            idx: 0,
        }
    }

    /// Get the currently selected [`SBPlatform`].
    ///
    /// [`SBPlatform`]: struct.SBPlatform.html
    pub fn selected_platform(&self) -> SBPlatform {
        unsafe { SBPlatform { raw: sys::SBDebuggerGetSelectedPlatform(self.raw) } }
    }

    /// Set the selected [`SBPlatform`].
    ///
    /// [`SBPlatform`]: struct.SBPlatform.html
    pub fn set_selected_platform(&mut self, platform: &SBPlatform) {
        unsafe { sys::SBDebuggerSetSelectedPlatform(self.raw, platform.raw) };
    }
}

/// Iterate over the [targets] known to a [debugger].
///
/// [targets]: struct.SBTarget.html
/// [debugger]: struct.SBDebugger.html
pub struct SBDebuggerTargetIter<'d> {
    debugger: &'d SBDebugger,
    idx: usize,
}

impl<'d> Iterator for SBDebuggerTargetIter<'d> {
    type Item = SBTarget;

    fn next(&mut self) -> Option<SBTarget> {
        if self.idx < unsafe { sys::SBDebuggerGetNumTargets(self.debugger.raw) as usize } {
            let r = Some(SBTarget {
                             raw: unsafe {
                                 sys::SBDebuggerGetTargetAtIndex(self.debugger.raw, self.idx as u32)
                             },
                         });
            self.idx += 1;
            r
        } else {
            None
        }
    }
}

impl fmt::Debug for SBDebugger {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBDebuggerGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBDebugger {{ {} }}", stream.data())
    }
}

impl Drop for SBDebugger {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBDebugger(self.raw) };
    }
}

impl ::juniper::Context for SBDebugger {}

#[cfg(feature = "graphql")]
graphql_object!(SBDebugger: SBDebugger | &self | {
    field targets() -> Vec<SBTarget> {
        self.targets().collect()
    }

    field selected_platform() -> SBPlatform {
        self.selected_platform()
    }
});

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

    #[test]
    fn it_works() {
        assert!(!SBDebugger::version().is_empty());
    }
}
<commit_msg>Bind SBDebugger's selected target.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::{CStr, CString};
use std::fmt;
use std::ptr;
use super::error::SBError;
use super::platform::SBPlatform;
use super::stream::SBStream;
use super::target::SBTarget;
use sys;

/// Creates [`SBTarget`]s, provides access to them and manages
/// the overall debugging experience.
///
/// # Initialization and Teardown
///
/// LLDB must be initialized before the functionality is used. This
/// is done with `SBDebugger::initialize()`:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
/// ```
///
/// Similarly, it must be terminated after you are done using it:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
/// // Use LLDB functionality ...
/// SBDebugger::terminate();
/// ```
///
/// Once you've initialized LLDB, you're ready to create an instance
/// of `SBDebugger`:
///
/// ```
/// use lldb::SBDebugger;
///
/// SBDebugger::initialize();
///
/// let debugger = SBDebugger::create(false);
/// // ... configure the debugger if needed ...
/// // ... create a target and do stuff ...
///
/// SBDebugger::terminate();
/// ```
///
/// # Configuration
///
/// ## Async Mode
///
/// While it is best to use LLDB in asynchronous mode, it does offer a
/// synchronous mode, which can be easier to use for quick experiments
/// or scripts.
///
/// In synchronous mode, calls to the LLDB API do not return until the
/// underlying action has been completed. This means that the thread
/// from which you call LLDB will be blocked during that time, so this
/// is not an ideal way to use LLDB for building interactive tools
/// or a new user interface.
///
/// In asynchronous mode, calls to the LLDB API will return immediately
/// without waiting for the action to complete. This means that actions
/// like launching a target, continuing the execution of a process and
/// so on won't be completed immediately and you must process events
/// to see what the results of an action are.
///
/// Synchronous mode can be enabled by using [`set_async`] and passing it
/// a `false` value. You can see if you're in asynchronous mode or not
/// by calling [`async`].
///
/// # Target Management
///
/// The `SBDebugger` instance tracks the various targets that are
/// currently known to the debugger.
///
/// Typically, you create a target with [`create_target`],
/// [`create_target_simple`] or one of the related methods.
///
/// Sometimes, you'll want to create a target without an associated
/// executable. A common use case for this is to attach to a process
/// by name or process ID where you don't know the executable in advance.
/// The most convenient way to do this is:
///
/// ```
/// # use lldb::SBDebugger;
/// # SBDebugger::initialize();
/// let debugger = SBDebugger::create(false);
/// if let Some(target) = debugger.create_target_simple("") {
///     println!("Got a target: {:?}", target);
///     // Now, maybe we'd like to attach to something.
/// }
/// # SBDebugger::terminate();
/// ```
///
/// You can iterate over these targets which have been created by
/// using [`targets`]:
///
/// ```no_run
/// # use lldb::{SBDebugger, SBTarget};
/// # fn look_at_targets(debugger: SBDebugger) {
/// // Iterate over the targets...
/// for target in debugger.targets() {
///     println!("Hello {:?}!", target);
/// }
/// // Or collect them into a vector!
/// let targets = debugger.targets().collect::<Vec<SBTarget>>();
/// # }
/// ```
///
/// # Platform Management
///
/// ...
///
/// [`SBTarget`]: struct.SBTarget.html
/// [`set_async`]: #method.set_async
/// [`async`]: #method.async
/// [`create_target`]: #method.create_target
/// [`create_target_simple`]: #method.create_target_simple
/// [`targets`]: #method.targets
pub struct SBDebugger {
    /// The underlying raw `SBDebuggerRef`.
    pub raw: sys::SBDebuggerRef,
}

impl SBDebugger {
    /// Initialize LLDB.
    ///
    /// This should be called before LLDB functionality is used.
    pub fn initialize() {
        unsafe { sys::SBDebuggerInitialize() };
    }

    /// Tear down LLDB.
    ///
    /// This should be called once the application no longer needs
    /// to use LLDB functionality. Typically, this is called as the
    /// application exits.
    pub fn terminate() {
        unsafe { sys::SBDebuggerTerminate() };
    }

    /// Create a new instance of `SBDebugger`.
    ///
    /// If `source_init_files` is `true`, then `~/.lldbinit` will
    /// be processed.
    pub fn create(source_init_files: bool) -> SBDebugger {
        SBDebugger { raw: unsafe { sys::SBDebuggerCreate2(source_init_files as u8) } }
    }

    /// Get whether or not the debugger is in async mode.
    ///
    /// When in async mode, the debugger returns immediately when
    /// stepping or continuing without waiting for the process
    /// to change state.
    pub fn async(&self) -> bool {
        unsafe { sys::SBDebuggerGetAsync(self.raw) != 0 }
    }

    /// Set the debugger to be in async mode or not.
    ///
    /// When in async mode, the debugger returns immediately when
    /// stepping or continuing without waiting for the process
    /// to change state.
    pub fn set_async(&mut self, async: bool) {
        unsafe { sys::SBDebuggerSetAsync(self.raw, async as u8) }
    }

    /// Get the LLDB version string.
    pub fn version() -> String {
        unsafe {
            match CStr::from_ptr(sys::SBDebuggerGetVersionString()).to_str() {
                Ok(s) => s.to_owned(),
                _ => panic!("No version string?"),
            }
        }
    }

    /// Create a target.
    ///
    /// The executable name may be an empty string to create
    /// an empty target.
    pub fn create_target(&self,
                         executable: &str,
                         target_triple: Option<&str>,
                         platform_name: Option<&str>,
                         add_dependent_modules: bool)
                         -> Result<SBTarget, SBError> {
        let executable = CString::new(executable).unwrap();
        let target_triple = target_triple.map(|s| CString::new(s).unwrap());
        let platform_name = platform_name.map(|s| CString::new(s).unwrap());
        let error = SBError::new();
        let target = unsafe {
            sys::SBDebuggerCreateTarget(self.raw,
                                        executable.as_ptr(),
                                        target_triple.map_or(ptr::null(), |s| s.as_ptr()),
                                        platform_name.map_or(ptr::null(), |s| s.as_ptr()),
                                        add_dependent_modules as u8,
                                        error.raw)
        };
        if error.is_success() {
            Ok(SBTarget::wrap(target))
        } else {
            Err(error)
        }
    }

    /// Create a target from just an executable name.
    ///
    /// The executable name may be an empty string to create
    /// an empty target.
    ///
    /// Using [`create_target`] is preferred in most cases as
    /// that provides access to an `SBError` to inform the caller
    /// about what might have gone wrong.
    pub fn create_target_simple(&self, executable: &str) -> Option<SBTarget> {
        let executable = CString::new(executable).unwrap();
        SBTarget::maybe_wrap(unsafe { sys::SBDebuggerCreateTarget2(self.raw, executable.as_ptr()) })
    }

    /// Get an iterator over the [targets] known to this debugger instance.
    ///
    /// [targets]: struct.SBTarget.html
    pub fn targets(&self) -> SBDebuggerTargetIter {
        SBDebuggerTargetIter {
            debugger: self,
            idx: 0,
        }
    }

    /// Get the currently selected [`SBTarget`].
    ///
    /// [SBTarget]: struct.SBTarget.html
    pub fn selected_target(&self) -> Option<SBTarget> {
        SBTarget::maybe_wrap(unsafe { sys::SBDebuggerGetSelectedTarget(self.raw) })
    }

    /// Set the selected [`SBTarget`].
    ///
    /// [SBTarget]: struct.SBTarget.html
    pub fn set_selected_target(&mut self, target: &SBTarget) {
        unsafe { sys::SBDebuggerSetSelectedTarget(self.raw, target.raw) };
    }

    /// Get the currently selected [`SBPlatform`].
    ///
    /// [`SBPlatform`]: struct.SBPlatform.html
    pub fn selected_platform(&self) -> SBPlatform {
        unsafe { SBPlatform { raw: sys::SBDebuggerGetSelectedPlatform(self.raw) } }
    }

    /// Set the selected [`SBPlatform`].
    ///
    /// [`SBPlatform`]: struct.SBPlatform.html
    pub fn set_selected_platform(&mut self, platform: &SBPlatform) {
        unsafe { sys::SBDebuggerSetSelectedPlatform(self.raw, platform.raw) };
    }
}

/// Iterate over the [targets] known to a [debugger].
///
/// [targets]: struct.SBTarget.html
/// [debugger]: struct.SBDebugger.html
pub struct SBDebuggerTargetIter<'d> {
    debugger: &'d SBDebugger,
    idx: usize,
}

impl<'d> Iterator for SBDebuggerTargetIter<'d> {
    type Item = SBTarget;

    fn next(&mut self) -> Option<SBTarget> {
        if self.idx < unsafe { sys::SBDebuggerGetNumTargets(self.debugger.raw) as usize } {
            let r = Some(SBTarget {
                             raw: unsafe {
                                 sys::SBDebuggerGetTargetAtIndex(self.debugger.raw, self.idx as u32)
                             },
                         });
            self.idx += 1;
            r
        } else {
            None
        }
    }
}

impl fmt::Debug for SBDebugger {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let stream = SBStream::new();
        unsafe { sys::SBDebuggerGetDescription(self.raw, stream.raw) };
        write!(fmt, "SBDebugger {{ {} }}", stream.data())
    }
}

impl Drop for SBDebugger {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBDebugger(self.raw) };
    }
}

impl ::juniper::Context for SBDebugger {}

#[cfg(feature = "graphql")]
graphql_object!(SBDebugger: SBDebugger | &self | {
    field targets() -> Vec<SBTarget> {
        self.targets().collect()
    }

    field selected_target() -> Option<SBTarget> {
        self.selected_target()
    }

    field selected_platform() -> SBPlatform {
        self.selected_platform()
    }
});

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

    #[test]
    fn it_works() {
        assert!(!SBDebugger::version().is_empty());
    }
}
<|endoftext|>


<commit_before>use crate::ignore::{Ignore, IgnoreGit, IgnoreVcs};
use crate::pipeline::{PipelineFork, PipelineInfo};
use crossbeam_channel::{Receiver, Sender};
use std::fs;
use std::path::PathBuf;
use std::time::{Duration, Instant};

// ---------------------------------------------------------------------------------------------------------------------
// PathInfo
// ---------------------------------------------------------------------------------------------------------------------

#[derive(Debug, Clone)]
pub struct PathInfo {
    pub path: PathBuf,
}

// ---------------------------------------------------------------------------------------------------------------------
// PipelineFinder
// ---------------------------------------------------------------------------------------------------------------------

pub struct PipelineFinder {
    pub is_recursive: bool,
    pub follow_symlink: bool,
    pub skip_vcs: bool,
    pub skip_gitignore: bool,
    pub skip_hgignore: bool,
    pub skip_ambignore: bool,
    pub print_skipped: bool,
    pub find_parent_ignore: bool,
    pub infos: Vec<String>,
    pub errors: Vec<String>,
    time_beg: Instant,
    time_bsy: Duration,
    seq_no: usize,
    current_tx: usize,
    ignore_vcs: IgnoreVcs,
    ignore_git: Vec<IgnoreGit>,
}

impl PipelineFinder {
    pub fn new() -> Self {
        PipelineFinder {
            is_recursive: true,
            follow_symlink: true,
            skip_vcs: true,
            skip_gitignore: true,
            skip_hgignore: true,
            skip_ambignore: true,
            print_skipped: false,
            find_parent_ignore: true,
            infos: Vec::new(),
            errors: Vec::new(),
            time_beg: Instant::now(),
            time_bsy: Duration::new(0, 0),
            seq_no: 0,
            current_tx: 0,
            ignore_vcs: IgnoreVcs::new(),
            ignore_git: Vec::new(),
        }
    }

    fn find_path(&mut self, base: PathBuf, tx: &Vec<Sender<PipelineInfo<PathInfo>>>, is_symlink: bool) {
        let attr = match fs::metadata(&base) {
            Ok(x) => x,
            Err(e) => {
                if !is_symlink {
                    self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                }
                return;
            }
        };

        if attr.is_file() {
            if attr.len() != 0 {
                self.send_path(base, &tx);
            }
        } else {
            let reader = match fs::read_dir(&base) {
                Ok(x) => x,
                Err(e) => {
                    self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                    return;
                }
            };

            let gitignore_exist = self.push_gitignore(&base);

            for i in reader {
                match i {
                    Ok(entry) => {
                        let file_type = match entry.file_type() {
                            Ok(x) => x,
                            Err(e) => {
                                self.errors.push(format!("Error: {}", e));
                                continue;
                            }
                        };
                        if file_type.is_file() {
                            self.send_path(entry.path(), &tx);
                        } else {
                            let find_dir = file_type.is_dir() & self.is_recursive;
                            let find_symlink = file_type.is_symlink() & self.is_recursive & self.follow_symlink;
                            if (find_dir | find_symlink) & self.check_path(&entry.path(), true) {
                                self.find_path(entry.path(), &tx, find_symlink);
                            }
                        }
                    }
                    Err(e) => self.errors.push(format!("Error: {}", e)),
                };
            }

            self.pop_gitignore(gitignore_exist)
        }
    }

    fn send_path(&mut self, path: PathBuf, tx: &Vec<Sender<PipelineInfo<PathInfo>>>) {
        if self.check_path(&path, false) {
            let _ = tx[self.current_tx].send(PipelineInfo::SeqDat(self.seq_no, PathInfo { path: path }));
            self.seq_no += 1;
            self.current_tx = if self.current_tx == tx.len() - 1 {
                0
            } else {
                self.current_tx + 1
            };
        }
    }

    fn push_gitignore(&mut self, path: &PathBuf) -> bool {
        if !self.skip_gitignore {
            return false;
        }

        let reader = fs::read_dir(&path).unwrap();
        for i in reader {
            match i {
                Ok(entry) => {
                    if entry.path().ends_with(".gitignore") {
                        self.ignore_git.push(IgnoreGit::new(&entry.path()));
                        return true;
                    }
                }
                Err(e) => self.errors.push(format!("Error: {}", e)),
            }
        }
        false
    }

    fn pop_gitignore(&mut self, exist: bool) {
        if exist {
            let _ = self.ignore_git.pop();
        }
    }

    fn check_path(&mut self, path: &PathBuf, is_dir: bool) -> bool {
        let ok_vcs = if self.skip_vcs {
            !self.ignore_vcs.is_ignore(&path, is_dir)
        } else {
            true
        };

        let ok_git = if self.skip_gitignore && !self.ignore_git.is_empty() {
            !self.ignore_git.last().unwrap().is_ignore(&path, is_dir)
        } else {
            true
        };

        if !ok_vcs & self.print_skipped {
            self.infos.push(format!("Skipped: {:?} ( vcs file )\n", path));
        }

        if !ok_git & self.print_skipped {
            self.infos.push(format!("Skipped: {:?} ( .gitignore )\n", path));
        }

        ok_vcs && ok_git
    }

    fn set_default_gitignore(&mut self, base: &PathBuf) -> PathBuf {
        if !self.skip_gitignore {
            return base.clone();
        }
        if !self.find_parent_ignore {
            return base.clone();
        }

        let base_abs = match base.canonicalize() {
            Ok(x) => x,
            Err(e) => {
                self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                return base.clone();
            }
        };

        let mut parent = base_abs.parent();
        while parent.is_some() {
            if self.push_gitignore(&PathBuf::from(parent.unwrap())) {
                self.infos.push(format!(
                    "Found .gitignore at the parent directory: {:?}\n",
                    parent.unwrap()
                ));
                return base_abs.clone();
            }
            parent = parent.unwrap().parent();
        }

        return base.clone();
    }
}

impl PipelineFork<PathBuf, PathInfo> for PipelineFinder {
    fn setup(&mut self, id: usize, rx: Receiver<PipelineInfo<PathBuf>>, tx: Vec<Sender<PipelineInfo<PathInfo>>>) {
        self.infos = Vec::new();
        self.errors = Vec::new();
        let mut seq_beg_arrived = false;

        loop {
            match rx.recv() {
                Ok(PipelineInfo::SeqDat(_, p)) => {
                    watch_time!(self.time_bsy, {
                        let p = self.set_default_gitignore(&p);
                        self.find_path(p, &tx, false);
                    });
                }

                Ok(PipelineInfo::SeqBeg(x)) => {
                    if !seq_beg_arrived {
                        self.seq_no = x;
                        self.time_beg = Instant::now();

                        for tx in &tx {
                            let _ = tx.send(PipelineInfo::SeqBeg(x));
                        }

                        seq_beg_arrived = true;
                    }
                }

                Ok(PipelineInfo::SeqEnd(_)) => {
                    for i in &self.infos {
                        let _ = tx[0].send(PipelineInfo::MsgInfo(id, i.clone()));
                    }
                    for e in &self.errors {
                        let _ = tx[0].send(PipelineInfo::MsgErr(id, e.clone()));
                    }

                    let _ = tx[0].send(PipelineInfo::MsgTime(id, self.time_bsy, self.time_beg.elapsed()));

                    for tx in &tx {
                        let _ = tx.send(PipelineInfo::SeqEnd(self.seq_no));
                    }

                    break;
                }

                Ok(PipelineInfo::MsgInfo(i, e)) => {
                    let _ = tx[0].send(PipelineInfo::MsgInfo(i, e));
                }
                Ok(PipelineInfo::MsgErr(i, e)) => {
                    let _ = tx[0].send(PipelineInfo::MsgErr(i, e));
                }
                Ok(PipelineInfo::MsgTime(i, t0, t1)) => {
                    let _ = tx[0].send(PipelineInfo::MsgTime(i, t0, t1));
                }
                Err(_) => break,
            }
        }
    }
}

// ---------------------------------------------------------------------------------------------------------------------
// Test
// ---------------------------------------------------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;
    use crate::pipeline::{PipelineFork, PipelineInfo};
    use crossbeam_channel::unbounded;
    use std::path::PathBuf;
    use std::thread;

    fn test<T: 'static + PipelineFork<PathBuf, PathInfo> + Send>(mut finder: T, path: String) -> Vec<PathInfo> {
        let (in_tx, in_rx) = unbounded();
        let (out_tx, out_rx) = unbounded();
        thread::spawn(move || {
            finder.setup(0, in_rx, vec![out_tx]);
        });
        let _ = in_tx.send(PipelineInfo::SeqBeg(0));
        let _ = in_tx.send(PipelineInfo::SeqDat(0, PathBuf::from(path)));
        let _ = in_tx.send(PipelineInfo::SeqEnd(1));

        let mut ret = Vec::new();
        loop {
            match out_rx.recv().unwrap() {
                PipelineInfo::SeqDat(_, x) => ret.push(x),
                PipelineInfo::SeqEnd(_) => break,
                _ => (),
            }
        }

        ret
    }

    #[test]
    fn pipeline_finder_default() {
        let finder = PipelineFinder::new();
        let ret = test(finder, "./".to_string());

        assert!(ret.iter().any(|x| x.path == PathBuf::from("./Cargo.toml")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambr.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambs.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/console.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/lib.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/matcher.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/util.rs")));
        assert!(!ret.iter().any(|x| x.path == PathBuf::from("./.git/config")));
    }

    #[test]
    fn pipeline_finder_not_skip_vcs() {
        let mut finder = PipelineFinder::new();
        finder.skip_vcs = false;
        let ret = test(finder, "./".to_string());

        assert!(ret.iter().any(|x| x.path == PathBuf::from("./Cargo.toml")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambr.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambs.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/console.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/lib.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/matcher.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/util.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./.git/config")));
    }
}
<commit_msg>Create a dummy .git/config file if it doesn't exist<commit_after>use crate::ignore::{Ignore, IgnoreGit, IgnoreVcs};
use crate::pipeline::{PipelineFork, PipelineInfo};
use crossbeam_channel::{Receiver, Sender};
use std::fs;
use std::path::PathBuf;
use std::time::{Duration, Instant};

// ---------------------------------------------------------------------------------------------------------------------
// PathInfo
// ---------------------------------------------------------------------------------------------------------------------

#[derive(Debug, Clone)]
pub struct PathInfo {
    pub path: PathBuf,
}

// ---------------------------------------------------------------------------------------------------------------------
// PipelineFinder
// ---------------------------------------------------------------------------------------------------------------------

pub struct PipelineFinder {
    pub is_recursive: bool,
    pub follow_symlink: bool,
    pub skip_vcs: bool,
    pub skip_gitignore: bool,
    pub skip_hgignore: bool,
    pub skip_ambignore: bool,
    pub print_skipped: bool,
    pub find_parent_ignore: bool,
    pub infos: Vec<String>,
    pub errors: Vec<String>,
    time_beg: Instant,
    time_bsy: Duration,
    seq_no: usize,
    current_tx: usize,
    ignore_vcs: IgnoreVcs,
    ignore_git: Vec<IgnoreGit>,
}

impl PipelineFinder {
    pub fn new() -> Self {
        PipelineFinder {
            is_recursive: true,
            follow_symlink: true,
            skip_vcs: true,
            skip_gitignore: true,
            skip_hgignore: true,
            skip_ambignore: true,
            print_skipped: false,
            find_parent_ignore: true,
            infos: Vec::new(),
            errors: Vec::new(),
            time_beg: Instant::now(),
            time_bsy: Duration::new(0, 0),
            seq_no: 0,
            current_tx: 0,
            ignore_vcs: IgnoreVcs::new(),
            ignore_git: Vec::new(),
        }
    }

    fn find_path(&mut self, base: PathBuf, tx: &Vec<Sender<PipelineInfo<PathInfo>>>, is_symlink: bool) {
        let attr = match fs::metadata(&base) {
            Ok(x) => x,
            Err(e) => {
                if !is_symlink {
                    self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                }
                return;
            }
        };

        if attr.is_file() {
            if attr.len() != 0 {
                self.send_path(base, &tx);
            }
        } else {
            let reader = match fs::read_dir(&base) {
                Ok(x) => x,
                Err(e) => {
                    self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                    return;
                }
            };

            let gitignore_exist = self.push_gitignore(&base);

            for i in reader {
                match i {
                    Ok(entry) => {
                        let file_type = match entry.file_type() {
                            Ok(x) => x,
                            Err(e) => {
                                self.errors.push(format!("Error: {}", e));
                                continue;
                            }
                        };
                        if file_type.is_file() {
                            self.send_path(entry.path(), &tx);
                        } else {
                            let find_dir = file_type.is_dir() & self.is_recursive;
                            let find_symlink = file_type.is_symlink() & self.is_recursive & self.follow_symlink;
                            if (find_dir | find_symlink) & self.check_path(&entry.path(), true) {
                                self.find_path(entry.path(), &tx, find_symlink);
                            }
                        }
                    }
                    Err(e) => self.errors.push(format!("Error: {}", e)),
                };
            }

            self.pop_gitignore(gitignore_exist)
        }
    }

    fn send_path(&mut self, path: PathBuf, tx: &Vec<Sender<PipelineInfo<PathInfo>>>) {
        if self.check_path(&path, false) {
            let _ = tx[self.current_tx].send(PipelineInfo::SeqDat(self.seq_no, PathInfo { path: path }));
            self.seq_no += 1;
            self.current_tx = if self.current_tx == tx.len() - 1 {
                0
            } else {
                self.current_tx + 1
            };
        }
    }

    fn push_gitignore(&mut self, path: &PathBuf) -> bool {
        if !self.skip_gitignore {
            return false;
        }

        let reader = fs::read_dir(&path).unwrap();
        for i in reader {
            match i {
                Ok(entry) => {
                    if entry.path().ends_with(".gitignore") {
                        self.ignore_git.push(IgnoreGit::new(&entry.path()));
                        return true;
                    }
                }
                Err(e) => self.errors.push(format!("Error: {}", e)),
            }
        }
        false
    }

    fn pop_gitignore(&mut self, exist: bool) {
        if exist {
            let _ = self.ignore_git.pop();
        }
    }

    fn check_path(&mut self, path: &PathBuf, is_dir: bool) -> bool {
        let ok_vcs = if self.skip_vcs {
            !self.ignore_vcs.is_ignore(&path, is_dir)
        } else {
            true
        };

        let ok_git = if self.skip_gitignore && !self.ignore_git.is_empty() {
            !self.ignore_git.last().unwrap().is_ignore(&path, is_dir)
        } else {
            true
        };

        if !ok_vcs & self.print_skipped {
            self.infos.push(format!("Skipped: {:?} ( vcs file )\n", path));
        }

        if !ok_git & self.print_skipped {
            self.infos.push(format!("Skipped: {:?} ( .gitignore )\n", path));
        }

        ok_vcs && ok_git
    }

    fn set_default_gitignore(&mut self, base: &PathBuf) -> PathBuf {
        if !self.skip_gitignore {
            return base.clone();
        }
        if !self.find_parent_ignore {
            return base.clone();
        }

        let base_abs = match base.canonicalize() {
            Ok(x) => x,
            Err(e) => {
                self.errors.push(format!("Error: {} @ {}", e, base.to_str().unwrap()));
                return base.clone();
            }
        };

        let mut parent = base_abs.parent();
        while parent.is_some() {
            if self.push_gitignore(&PathBuf::from(parent.unwrap())) {
                self.infos.push(format!(
                    "Found .gitignore at the parent directory: {:?}\n",
                    parent.unwrap()
                ));
                return base_abs.clone();
            }
            parent = parent.unwrap().parent();
        }

        return base.clone();
    }
}

impl PipelineFork<PathBuf, PathInfo> for PipelineFinder {
    fn setup(&mut self, id: usize, rx: Receiver<PipelineInfo<PathBuf>>, tx: Vec<Sender<PipelineInfo<PathInfo>>>) {
        self.infos = Vec::new();
        self.errors = Vec::new();
        let mut seq_beg_arrived = false;

        loop {
            match rx.recv() {
                Ok(PipelineInfo::SeqDat(_, p)) => {
                    watch_time!(self.time_bsy, {
                        let p = self.set_default_gitignore(&p);
                        self.find_path(p, &tx, false);
                    });
                }

                Ok(PipelineInfo::SeqBeg(x)) => {
                    if !seq_beg_arrived {
                        self.seq_no = x;
                        self.time_beg = Instant::now();

                        for tx in &tx {
                            let _ = tx.send(PipelineInfo::SeqBeg(x));
                        }

                        seq_beg_arrived = true;
                    }
                }

                Ok(PipelineInfo::SeqEnd(_)) => {
                    for i in &self.infos {
                        let _ = tx[0].send(PipelineInfo::MsgInfo(id, i.clone()));
                    }
                    for e in &self.errors {
                        let _ = tx[0].send(PipelineInfo::MsgErr(id, e.clone()));
                    }

                    let _ = tx[0].send(PipelineInfo::MsgTime(id, self.time_bsy, self.time_beg.elapsed()));

                    for tx in &tx {
                        let _ = tx.send(PipelineInfo::SeqEnd(self.seq_no));
                    }

                    break;
                }

                Ok(PipelineInfo::MsgInfo(i, e)) => {
                    let _ = tx[0].send(PipelineInfo::MsgInfo(i, e));
                }
                Ok(PipelineInfo::MsgErr(i, e)) => {
                    let _ = tx[0].send(PipelineInfo::MsgErr(i, e));
                }
                Ok(PipelineInfo::MsgTime(i, t0, t1)) => {
                    let _ = tx[0].send(PipelineInfo::MsgTime(i, t0, t1));
                }
                Err(_) => break,
            }
        }
    }
}

// ---------------------------------------------------------------------------------------------------------------------
// Test
// ---------------------------------------------------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;
    use crate::pipeline::{PipelineFork, PipelineInfo};
    use crossbeam_channel::unbounded;
    use std::path::{Path,PathBuf};
    use std::thread;

    fn test<T: 'static + PipelineFork<PathBuf, PathInfo> + Send>(mut finder: T, path: String) -> Vec<PathInfo> {
        let (in_tx, in_rx) = unbounded();
        let (out_tx, out_rx) = unbounded();
        thread::spawn(move || {
            finder.setup(0, in_rx, vec![out_tx]);
        });
        let _ = in_tx.send(PipelineInfo::SeqBeg(0));
        let _ = in_tx.send(PipelineInfo::SeqDat(0, PathBuf::from(path)));
        let _ = in_tx.send(PipelineInfo::SeqEnd(1));

        let mut ret = Vec::new();
        loop {
            match out_rx.recv().unwrap() {
                PipelineInfo::SeqDat(_, x) => ret.push(x),
                PipelineInfo::SeqEnd(_) => break,
                _ => (),
            }
        }

        ret
    }

    #[test]
    fn pipeline_finder_default() {
        if !Path::new("./.git/config").exists() {
            fs::create_dir_all("./.git").unwrap();
            fs::File::create("./.git/config").unwrap();
        }

        let finder = PipelineFinder::new();
        let ret = test(finder, "./".to_string());

        assert!(ret.iter().any(|x| x.path == PathBuf::from("./Cargo.toml")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambr.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambs.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/console.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/lib.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/matcher.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/util.rs")));
        assert!(!ret.iter().any(|x| x.path == PathBuf::from("./.git/config")));
    }

    #[test]
    fn pipeline_finder_not_skip_vcs() {
        if !Path::new("./.git/config").exists() {
            fs::create_dir_all("./.git").unwrap();
            fs::File::create("./.git/config").unwrap();
        }

        let mut finder = PipelineFinder::new();
        finder.skip_vcs = false;
        let ret = test(finder, "./".to_string());

        assert!(ret.iter().any(|x| x.path == PathBuf::from("./Cargo.toml")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambr.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/ambs.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/console.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/lib.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/matcher.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./src/util.rs")));
        assert!(ret.iter().any(|x| x.path == PathBuf::from("./.git/config")));
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate atty;

use self::super::Size;
use self::libc::{c_ulong, c_ushort, STDOUT_FILENO};
use self::libc::ioctl;

#[cfg(not(target_os = "macos"))]
const TIOCGWINSZ: c_ulong = 0x00005413;

#[cfg(target_os = "macos")]
const TIOCGWINSZ: c_ulong = 0x40087468;

/// A representation of the size of the current terminal
#[repr(C)]
#[derive(Debug)]
pub struct UnixSize {
    /// number of rows
    pub rows: c_ushort,
    /// number of columns
    pub cols: c_ushort,
    x: c_ushort,
    y: c_ushort,
}

/// Gets the current terminal size
pub fn get() -> Option<Size> {
    // http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc
    if atty::isnt() {
        return None;
    }
    let us = UnixSize {
        rows: 0,
        cols: 0,
        x: 0,
        y: 0,
    };
    let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &us) };
    if r == 0 {
        Some(Size {
            rows: us.rows,
            cols: us.cols,
        })
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use std::process::{Command, Output, Stdio};
    use super::super::Size;
    use super::get;

    #[cfg(target_os = "macos")]
    fn stty_size() -> Output {
        Command::new("stty")
            .arg("-f")
            .arg("/dev/stderr")
            .arg("size")
            .stderr(Stdio::inherit())
            .output()
            .unwrap()
    }

    #[cfg(not(target_os = "macos"))]
    fn stty_size() -> Output {
        Command::new("stty")
            .arg("-F")
            .arg("/dev/stderr")
            .arg("size")
            .stderr(Stdio::inherit())
            .output()
            .unwrap()
    }

    #[test]
    fn test_shell() {
        let output = stty_size();
        assert!(output.status.success());
        let stdout = String::from_utf8(output.stdout).unwrap();
        let mut data = stdout.split_whitespace();
        let rs = data.next().unwrap().parse::<u16>().unwrap();
        let cs = data.next().unwrap().parse::<u16>().unwrap();
        if let Some(Size { rows, cols }) = get() {
            assert_eq!(rows, rs);
            assert_eq!(cols, cs);
        }
    }
}
<commit_msg>Use TIOCGWINSZ from libc.<commit_after>extern crate libc;
extern crate atty;

use self::super::Size;
use self::libc::{c_ushort, STDOUT_FILENO, TIOCGWINSZ};
use self::libc::ioctl;

/// A representation of the size of the current terminal
#[repr(C)]
#[derive(Debug)]
pub struct UnixSize {
    /// number of rows
    pub rows: c_ushort,
    /// number of columns
    pub cols: c_ushort,
    x: c_ushort,
    y: c_ushort,
}

/// Gets the current terminal size
pub fn get() -> Option<Size> {
    // http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc
    if atty::isnt() {
        return None;
    }
    let us = UnixSize {
        rows: 0,
        cols: 0,
        x: 0,
        y: 0,
    };
    let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &us) };
    if r == 0 {
        Some(Size {
            rows: us.rows,
            cols: us.cols,
        })
    } else {
        None
    }
}

#[cfg(test)]
mod tests {
    use std::process::{Command, Output, Stdio};
    use super::super::Size;
    use super::get;

    #[cfg(target_os = "macos")]
    fn stty_size() -> Output {
        Command::new("stty")
            .arg("-f")
            .arg("/dev/stderr")
            .arg("size")
            .stderr(Stdio::inherit())
            .output()
            .unwrap()
    }

    #[cfg(not(target_os = "macos"))]
    fn stty_size() -> Output {
        Command::new("stty")
            .arg("-F")
            .arg("/dev/stderr")
            .arg("size")
            .stderr(Stdio::inherit())
            .output()
            .unwrap()
    }

    #[test]
    fn test_shell() {
        let output = stty_size();
        assert!(output.status.success());
        let stdout = String::from_utf8(output.stdout).unwrap();
        let mut data = stdout.split_whitespace();
        let rs = data.next().unwrap().parse::<u16>().unwrap();
        let cs = data.next().unwrap().parse::<u16>().unwrap();
        if let Some(Size { rows, cols }) = get() {
            assert_eq!(rows, rs);
            assert_eq!(cols, cs);
        }
    }
}
<|endoftext|>


<commit_before>use memory::{Memory, pack_u16, high_byte, low_byte};
use extensions::Incrementor;
use cpu::{Register, Flags, CarryFlag, HalfCarryFlag, ZeroFlag, SubtractFlag};

/// Add the value of two registers and store it in the first register
pub fn add(first: &mut Register<u8>, second: &Register<u8>, freg: &mut Register<Flags>) {
    debug!("add: {} {}", first.read(), second.read());
    let new_value = first.read() + second.read();
    first.write(new_value);

    let mut flags = Flags::empty();
    if (new_value < first.read() || new_value < second.read()) {
        // Carry
        flags = flags | CarryFlag
    }
    freg.write(flags);
}

/// Load the value from one register into another
pub fn ld_reg_to_reg(target: &mut Register<u8>, source: &Register<u8>) {
    debug!("ld_reg_to_reg: {}", source.read());
    let val = source.read();
    target.write(val);
}

/// Loads the memory pointed to by the next two bytes into a register
pub fn ld_immediate(mem: &Memory, pc: &mut Register<u16>, reg: &mut Register<u8>) {
    let val = mem.read_byte(pc.read());
    debug!("ld_next_byte_to_reg: {} {}", pc.read(), val);
    pc.increment();
    reg.write(val);
}

/// Loads the next two bytes into the passed in registers
pub fn ld_next_two_byte_into_reg_pair(mem: &Memory, pc: &mut Register<u16>,
                                 hb: &mut Register<u8>, lb: &mut Register<u8>) {
    let val = mem.read_word(pc.read());
    pc.increment();
    pc.increment();

    hb.write(high_byte(val));
    lb.write(low_byte(val));
}

/// Writes the passed in value to memory at the address pointed to by combined address parameters
pub fn write_value_to_memory_at_address(mem: &mut Memory, val: u8, addr_msb: u8, addr_lsb: u8) {
   let addr = ((addr_msb as uint) << 8) + addr_lsb as uint;
   mem.write_byte(addr as u16, val);
}

/// Increments the pair of registers as if they represent a 16-bit value
pub fn increment_register_pair(msb: &mut Register<u8>,lsb: &mut Register<u8>) {
    let incremented_val = ((msb.read() as uint) << 8) + lsb.read() as uint + 1;
    msb.write(high_byte(incremented_val as u16));
    lsb.write(low_byte(incremented_val as u16));
}

/// Increment register by 1
/// Set ZeroFlag if result is 0
/// Set HalfCarryFlag if there is a carry from bit 3
pub fn increment_register(reg: &mut Register<u8>, freg: &mut Register<Flags>) {
    let val = reg.read();
    let mut flags = Flags::empty();

    if (val == 0x0F) {
        flags = HalfCarryFlag;
    }
    reg.increment();

    if (reg.read() == 0) {
        flags = flags | ZeroFlag;
    }
    freg.write(flags);
}

/// Decrement register by 1
/// Set ZeroFlag if result is 0
/// Set SubtractFlag
/// Set HalfCarryFlag if there is no borrow from bit 4
pub fn decrement_register(reg: &mut Register<u8>, freg: &mut Register<Flags>) {
    let val = reg.read();
    let mut flags = SubtractFlag;

    if ((val & 0x0F) > 0) {
        flags = flags | HalfCarryFlag;
    }

    reg.decrement();

    if (reg.read() == 0x00) {
        flags = flags | ZeroFlag;
    }
    freg.write(flags);
}

/// Rotate register left
/// Set ZeroFlag if result is zero
/// Set CarryFlag if bit 7 is 1
pub fn rotate_left_with_carry(reg: &mut Register<u8>, freg: &mut Register<Flags>) {
    let val = reg.read();

    if (val == 0) {
        freg.write(ZeroFlag);
        return;
    }

    if (val & 0x80 != 0) {
        freg.write(CarryFlag);
    }

    reg.write(val << 1);
}

/// Write sp to address with value of next two bytes
pub fn write_sp_to_address_immediate(mem: &mut Memory, pc: &mut Register<u16>, sp: &Register<u16>){
    let addr = mem.read_word(pc.read());
    pc.increment();
    pc.increment();

    println!("Writing {} to {}", sp.read(), addr);
    mem.write_word(addr, sp.read());
}

/// Performs no operation and consumes a cycle
pub fn nop() {
    println!("nop");
}

#[test]
fn test_add_register_pair_to_register_pair() {
    let mut rega = Register::new(0x11);
    let mut regb = Register::new(0x11);

    let mut reg1 = Register::new(0x11);
    let mut reg2 = Register::new(0x11);

    let mut freg = Register::new(ZeroFlag);

    // Basic add make sure ZeroFlag isn't affected
    add_register_pair_to_register_pair(&mut rega, &mut regb, reg1, reg2, &mut freg);

    assert!(pack_u16(rega.read(), regb.read()) == 0x2222);
    assert!(freg.read() == ZeroFlag);

    rega.write(0xAB);
    regb.write(0xFE);
    reg1.write(0x12);
    reg2.write(0x12);

    // Carry from bit 11
    add_register_pair_to_register_pair(&mut rega, &mut regb, reg1, reg2, &mut freg);

}

#[test]
fn test_write_stack_pointer_to_address_immediate() {
    let mut sp = Register::new(0xBEEF);
    let mut pc = Register::new(0x111);
    let mut mem = Memory::new(65647);

    mem.write_byte(0x111, 0xAD);
    mem.write_byte(0x112, 0xDE);

    write_sp_to_address_immediate(&mut mem, &mut pc, &sp);
    assert!(pc.read() == 0x113);
    assert!(mem.read_word(0xDEAD) == 0xBEEF);
}

#[test]
fn test_rotate_left_with_carry() {
    let mut reg = Register::new(0x0F);
    let mut freg = Register::new(Flags::empty());

    rotate_left_with_carry(&mut reg, &mut freg);

    // Rotate should happen
    assert!(reg.read() == 0x1E);
    assert!(freg.read() == Flags::empty());

    let mut regb = Register::new(0x00);

    rotate_left_with_carry(&mut regb, &mut freg);

    // Zero should return zero with ZeroFlag
    assert!(regb.read() == 0x00);
    assert!(freg.read() == ZeroFlag);

    let mut regc = Register::new(0xFF);

    rotate_left_with_carry(&mut regc, &mut freg);

    // Carry should get set
    assert!(regc.read() == 0xFE);
    assert!(freg.read() == CarryFlag);
}

#[test]
fn test_decrement_register() {
    let mut reg = Register::new(1);
    let mut freg = Register::new(Flags::empty());

    decrement_register(&mut reg, &mut freg);

    assert!(reg.read() == 0);
    assert!(freg.read() == ZeroFlag | SubtractFlag | HalfCarryFlag);

    reg.write(0xF1);
    freg.write(Flags::empty());

    decrement_register(&mut reg, &mut freg);

    assert!(reg.read() == 0xF0);
    assert!(freg.read() == SubtractFlag | HalfCarryFlag);

    reg.write(0xF0);
    freg.write(Flags::empty());

    decrement_register(&mut reg, &mut freg);

    assert!(reg.read() == 0xEF);
    assert!(freg.read() == SubtractFlag);
}

#[test]
fn test_increment_register() {
    let mut reg = Register::new(1);
    let mut freg = Register::new(Flags::empty());

    increment_register(&mut reg, &mut freg);

    assert!(reg.read() == 2);
    assert!(freg.read() == Flags::empty());

    let mut regb = Register::new(0x0F);

    increment_register(&mut regb, &mut freg);

    assert!(regb.read() == 0x10);
    assert!(freg.read() == HalfCarryFlag);

    let mut regc = Register::new(0xFF);
    freg.write(Flags::empty());

    increment_register(&mut regc, &mut freg);

    assert!(regc.read() == 0x00);
    assert!(freg.read() == ZeroFlag);
}

#[test]
fn test_add_reg_with_reg() {
    let mut first = Register::new(5);
    let mut second = Register::new(9);
    let mut flags = Register::new(Flags::empty());

    add(&mut first, &second, &mut flags);
    assert!(first.read() == 14);
    assert!(flags.read() == Flags::empty());

    let mut a = Register::new(0xFA);
    let mut b = Register::new(0x07);

    add(&mut a, &b, &mut flags);

    assert!(a.read() == 0x01);
    assert!(flags.read().contains(CarryFlag));
}

#[test]
fn test_ld_immediate() {
    let mut mem = Memory::new(65536);
    let mut pc = Register::new(11);
    let mut reg = Register::new(0);

    mem.write_byte(11, 0xFA);

    ld_immediate(&mem, &mut pc, &mut reg);
    assert!(reg.read() == 0xFA);
    assert!(pc.read() == 12);

}

#[test]
fn test_ld_reg_to_reg() {
    let mut target = Register::new(5);
    let mut source = Register::new(10);

    ld_reg_to_reg(&mut target, &source);

    assert!(target.read() == 10);
    assert!(source.read() == 10);
}

#[test]
fn test_ld_next_two_byte_into_reg_pair() {
    let mut mem = Memory::new(65536);
    let mut pc = Register::new(11);
    let mut reg = Register::new(0);
    let mut reg2 = Register::new(0);

    mem.write_word(11, 0xDEAB);

    ld_next_two_byte_into_reg_pair(&mem, &mut pc, &mut reg, &mut reg2);
    assert!(pc.read() == 13);
    assert!(reg.read() == 0xDE);
    assert!(reg2.read() == 0xAB);
}

#[test]
fn test_write_value_to_memory_at_address() {
    let mut mem = Memory::new(65536);
    let mut msb = 0xFF;
    let mut lsb = 0x11;
    let val = 100;

    write_value_to_memory_at_address(&mut mem, val, msb, lsb);

    assert!(mem.read_byte(0xFF11) == val, "Memory does match what was written");
}

#[test]
fn test_increment_register_pair() {
    let mut msb = Register::new(0x11);
    let mut lsb = Register::new(0x11);

    increment_register_pair(&mut msb, &mut lsb);

    assert!(msb.read() == 0x11);
    assert!(lsb.read() == 0x12);

    let mut msb_2 = Register::new(0x10);
    let mut lsb_2 = Register::new(0xFF);

    increment_register_pair(&mut msb_2, &mut lsb_2);

    assert!(msb_2.read() == 0x11);
    assert!(lsb_2.read() == 0x00);
}
<commit_msg>Add method for adding two 16-bit registers<commit_after>use memory::{Memory, pack_u16, high_byte, low_byte, low_nibble, high_nibble};
use extensions::Incrementor;
use cpu::{Register, Flags, CarryFlag, HalfCarryFlag, ZeroFlag, SubtractFlag};

/// Add the value of two registers and store it in the first register
pub fn add(first: &mut Register<u8>, second: &Register<u8>, freg: &mut Register<Flags>) {
    debug!("add: {} {}", first.read(), second.read());
    let new_value = first.read() + second.read();
    first.write(new_value);

    let mut flags = Flags::empty();
    if (new_value < first.read() || new_value < second.read()) {
        // Carry
        flags = flags | CarryFlag
    }
    freg.write(flags);
}

/// Load the value from one register into another
pub fn ld_reg_to_reg(target: &mut Register<u8>, source: &Register<u8>) {
    debug!("ld_reg_to_reg: {}", source.read());
    let val = source.read();
    target.write(val);
}

/// Loads the memory pointed to by the next two bytes into a register
pub fn ld_immediate(mem: &Memory, pc: &mut Register<u16>, reg: &mut Register<u8>) {
    let val = mem.read_byte(pc.read());
    debug!("ld_next_byte_to_reg: {} {}", pc.read(), val);
    pc.increment();
    reg.write(val);
}

/// Loads the next two bytes into the passed in registers
pub fn ld_next_two_byte_into_reg_pair(mem: &Memory, pc: &mut Register<u16>,
                                 hb: &mut Register<u8>, lb: &mut Register<u8>) {
    let val = mem.read_word(pc.read());
    pc.increment();
    pc.increment();

    hb.write(high_byte(val));
    lb.write(low_byte(val));
}

/// Writes the passed in value to memory at the address pointed to by combined address parameters
pub fn write_value_to_memory_at_address(mem: &mut Memory, val: u8, addr_msb: u8, addr_lsb: u8) {
   let addr = ((addr_msb as uint) << 8) + addr_lsb as uint;
   mem.write_byte(addr as u16, val);
}

/// Increments the pair of registers as if they represent a 16-bit value
pub fn increment_register_pair(msb: &mut Register<u8>,lsb: &mut Register<u8>) {
    let incremented_val = ((msb.read() as uint) << 8) + lsb.read() as uint + 1;
    msb.write(high_byte(incremented_val as u16));
    lsb.write(low_byte(incremented_val as u16));
}

/// Increment register by 1
/// Set ZeroFlag if result is 0
/// Set HalfCarryFlag if there is a carry from bit 3
pub fn increment_register(reg: &mut Register<u8>, freg: &mut Register<Flags>) {
    let val = reg.read();
    let mut flags = Flags::empty();

    if (val == 0x0F) {
        flags = HalfCarryFlag;
    }
    reg.increment();

    if (reg.read() == 0) {
        flags = flags | ZeroFlag;
    }
    freg.write(flags);
}

/// Decrement register by 1
/// Set ZeroFlag if result is 0
/// Set SubtractFlag
/// Set HalfCarryFlag if there is no borrow from bit 4
pub fn decrement_register(reg: &mut Register<u8>, freg: &mut Register<Flags>) {
    let val = reg.read();
    let mut flags = SubtractFlag;

    if ((val & 0x0F) > 0) {
        flags = flags | HalfCarryFlag;
    }

    reg.decrement();

    if (reg.read() == 0x00) {
        flags = flags | ZeroFlag;
    }
    freg.write(flags);
}

/// Rotate register left
/// Set ZeroFlag if result is zero
/// Set CarryFlag if bit 7 is 1
pub fn rotate_left_with_carry(reg: &mut Register<u8>, freg: &mut Register<Flags>) {
    let val = reg.read();

    if (val == 0) {
        freg.write(ZeroFlag);
        return;
    }

    if (val & 0x80 != 0) {
        freg.write(CarryFlag);
    }

    reg.write(val << 1);
}

/// Write sp to address with value of next two bytes
pub fn write_sp_to_address_immediate(mem: &mut Memory, pc: &mut Register<u16>, sp: &Register<u16>){
    let addr = mem.read_word(pc.read());
    pc.increment();
    pc.increment();

    println!("Writing {} to {}", sp.read(), addr);
    mem.write_word(addr, sp.read());
}

/// Performs no operation and consumes a cycle
pub fn nop() {
    println!("nop");
}

pub fn add_register_pair_to_register_pair(rega: &mut Register<u8>, regb: &mut Register<u8>, reg1: &Register<u8>, reg2: &Register<u8>, freg: &mut Register<Flags>) {
    let first = pack_u16(rega.read(), regb.read());
    let second = pack_u16(reg1.read(), reg2.read());

    let sum = first + second;

    // Reset subtract flag, leave ZeroFlag alone
    let mut flags = freg.read();

    if (high_nibble(rega.read()) + high_nibble(reg1.read()) > 15) {
        flags = flags | CarryFlag
    }

    if (low_nibble(rega.read()) + low_nibble(reg1.read()) > 15) {
        flags = flags | HalfCarryFlag;
    }

    rega.write(high_byte(sum));
    regb.write(low_byte(sum));
    freg.write(flags);
}

#[test]
fn test_add_register_pair_to_register_pair() {
    let mut rega = Register::new(0x11);
    let mut regb = Register::new(0x11);

    let mut reg1 = Register::new(0x11);
    let mut reg2 = Register::new(0x11);

    let mut freg = Register::new(ZeroFlag);

    // Basic add make sure ZeroFlag isn't affected
    add_register_pair_to_register_pair(&mut rega, &mut regb, &reg1, &reg2, &mut freg);

    assert!(pack_u16(rega.read(), regb.read()) == 0x2222);
    assert!(freg.read() == ZeroFlag);

    rega.write(0xF1);
    regb.write(0xAB);
    reg1.write(0x12);
    reg2.write(0x12);

    // Carry from bit 11
    add_register_pair_to_register_pair(&mut rega, &mut regb, &reg1, &reg2, &mut freg);

    assert!(pack_u16(rega.read(), regb.read()) == 0x03BD);
    assert!(freg.read() == ZeroFlag | CarryFlag);

    rega.write(0x1E);
    regb.write(0xAB);
    reg1.write(0x12);
    reg2.write(0x12);
    freg.write(Flags::empty());

    // Carry from bit 11
    add_register_pair_to_register_pair(&mut rega, &mut regb, &reg1, &reg2, &mut freg);

    assert!(pack_u16(rega.read(), regb.read()) == 0x30BD);
    assert!(freg.read() == HalfCarryFlag);

}

#[test]
fn test_write_stack_pointer_to_address_immediate() {
    let mut sp = Register::new(0xBEEF);
    let mut pc = Register::new(0x111);
    let mut mem = Memory::new(65647);

    mem.write_byte(0x111, 0xAD);
    mem.write_byte(0x112, 0xDE);

    write_sp_to_address_immediate(&mut mem, &mut pc, &sp);
    assert!(pc.read() == 0x113);
    assert!(mem.read_word(0xDEAD) == 0xBEEF);
}

#[test]
fn test_rotate_left_with_carry() {
    let mut reg = Register::new(0x0F);
    let mut freg = Register::new(Flags::empty());

    rotate_left_with_carry(&mut reg, &mut freg);

    // Rotate should happen
    assert!(reg.read() == 0x1E);
    assert!(freg.read() == Flags::empty());

    let mut regb = Register::new(0x00);

    rotate_left_with_carry(&mut regb, &mut freg);

    // Zero should return zero with ZeroFlag
    assert!(regb.read() == 0x00);
    assert!(freg.read() == ZeroFlag);

    let mut regc = Register::new(0xFF);

    rotate_left_with_carry(&mut regc, &mut freg);

    // Carry should get set
    assert!(regc.read() == 0xFE);
    assert!(freg.read() == CarryFlag);
}

#[test]
fn test_decrement_register() {
    let mut reg = Register::new(1);
    let mut freg = Register::new(Flags::empty());

    decrement_register(&mut reg, &mut freg);

    assert!(reg.read() == 0);
    assert!(freg.read() == ZeroFlag | SubtractFlag | HalfCarryFlag);

    reg.write(0xF1);
    freg.write(Flags::empty());

    decrement_register(&mut reg, &mut freg);

    assert!(reg.read() == 0xF0);
    assert!(freg.read() == SubtractFlag | HalfCarryFlag);

    reg.write(0xF0);
    freg.write(Flags::empty());

    decrement_register(&mut reg, &mut freg);

    assert!(reg.read() == 0xEF);
    assert!(freg.read() == SubtractFlag);
}

#[test]
fn test_increment_register() {
    let mut reg = Register::new(1);
    let mut freg = Register::new(Flags::empty());

    increment_register(&mut reg, &mut freg);

    assert!(reg.read() == 2);
    assert!(freg.read() == Flags::empty());

    let mut regb = Register::new(0x0F);

    increment_register(&mut regb, &mut freg);

    assert!(regb.read() == 0x10);
    assert!(freg.read() == HalfCarryFlag);

    let mut regc = Register::new(0xFF);
    freg.write(Flags::empty());

    increment_register(&mut regc, &mut freg);

    assert!(regc.read() == 0x00);
    assert!(freg.read() == ZeroFlag);
}

#[test]
fn test_add_reg_with_reg() {
    let mut first = Register::new(5);
    let mut second = Register::new(9);
    let mut flags = Register::new(Flags::empty());

    add(&mut first, &second, &mut flags);
    assert!(first.read() == 14);
    assert!(flags.read() == Flags::empty());

    let mut a = Register::new(0xFA);
    let mut b = Register::new(0x07);

    add(&mut a, &b, &mut flags);

    assert!(a.read() == 0x01);
    assert!(flags.read().contains(CarryFlag));
}

#[test]
fn test_ld_immediate() {
    let mut mem = Memory::new(65536);
    let mut pc = Register::new(11);
    let mut reg = Register::new(0);

    mem.write_byte(11, 0xFA);

    ld_immediate(&mem, &mut pc, &mut reg);
    assert!(reg.read() == 0xFA);
    assert!(pc.read() == 12);

}

#[test]
fn test_ld_reg_to_reg() {
    let mut target = Register::new(5);
    let mut source = Register::new(10);

    ld_reg_to_reg(&mut target, &source);

    assert!(target.read() == 10);
    assert!(source.read() == 10);
}

#[test]
fn test_ld_next_two_byte_into_reg_pair() {
    let mut mem = Memory::new(65536);
    let mut pc = Register::new(11);
    let mut reg = Register::new(0);
    let mut reg2 = Register::new(0);

    mem.write_word(11, 0xDEAB);

    ld_next_two_byte_into_reg_pair(&mem, &mut pc, &mut reg, &mut reg2);
    assert!(pc.read() == 13);
    assert!(reg.read() == 0xDE);
    assert!(reg2.read() == 0xAB);
}

#[test]
fn test_write_value_to_memory_at_address() {
    let mut mem = Memory::new(65536);
    let mut msb = 0xFF;
    let mut lsb = 0x11;
    let val = 100;

    write_value_to_memory_at_address(&mut mem, val, msb, lsb);

    assert!(mem.read_byte(0xFF11) == val, "Memory does match what was written");
}

#[test]
fn test_increment_register_pair() {
    let mut msb = Register::new(0x11);
    let mut lsb = Register::new(0x11);

    increment_register_pair(&mut msb, &mut lsb);

    assert!(msb.read() == 0x11);
    assert!(lsb.read() == 0x12);

    let mut msb_2 = Register::new(0x10);
    let mut lsb_2 = Register::new(0xFF);

    increment_register_pair(&mut msb_2, &mut lsb_2);

    assert!(msb_2.read() == 0x11);
    assert!(lsb_2.read() == 0x00);
}
<|endoftext|>