<commit_before>use std::marker::PhantomData;
use std::ptr;

// We should use {u32,u64}::BYTES when they are stable;
const U32_BYTES: usize = 4;
const U64_BYTES: usize = 8;

macro_rules! number_stream(
    ($name:ident, $number_type:ty, $bytes_in_type:expr) => (
#[allow(raw_pointer_derive)]
#[derive(Debug,Copy,Clone)]
struct $name<'a> {
    start: *const $number_type,
    end: *const $number_type,
    marker: PhantomData<&'a ()>
}

impl<'a> $name<'a> {
    fn new(bytes: &'a [u8]) -> ($name<'a>, &'a [u8]) {
        $name::with_stride(bytes, 1)
    }

    // Stride is a grouping of sequential numbers
    //
    // 0 1 2 3 4 5 6 7
    // -------------      We have 7 bytes
    // --- --- --- X      Each number takes 2 bytes
    // --- --- XXX X      With a stride of 2
    //
    // Only four bytes will be consumed, the rest returned
    fn with_stride(bytes: &'a [u8], stride: usize) -> ($name<'a>, &'a [u8]) {
        let n_numbers_in_bytes = bytes.len() / $bytes_in_type;
        let n_strides_in_numbers = n_numbers_in_bytes / stride;
        let total_numbers = n_strides_in_numbers * stride;

        let (mine, theirs) = bytes.split_at(total_numbers * $bytes_in_type);

        let start = mine.as_ptr() as *const $number_type;
        let end = unsafe { start.offset(total_numbers as isize) };

        let me = $name {
            start: start,
            end: end,
            marker: PhantomData,
        };

        (me, theirs)
    }
}

impl<'a> Iterator for $name<'a> {
    type Item = $number_type;

    fn next(&mut self) -> Option<$number_type> {
        if self.start >= self.end { return None }

        let v: $number_type = unsafe { ptr::read(self.start) };

        self.start = unsafe { self.start.offset(1) };
        Some(v)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let cnt = self.count();
        (cnt, Some(cnt))
    }

    fn count(self) -> usize() {
        let total_bytes = self.end as usize - self.start as usize;
        total_bytes / $bytes_in_type
    }
}
));

number_stream!(U32FromBytes, u32, U32_BYTES);
number_stream!(U64FromBytes, u64, U64_BYTES);

/// Converts a slice of bytes into an iterator of numbers.
///
/// The data is always treated as little endian. Only complete ranges
/// of bytes are parsed as the number, any left-over bytes are returned.
// FIXME: Probably doesn't work on big endian machines.
pub trait NumberStreams {
    /// Reads u32s from the bytes
    fn u32_stream(&self) -> (U32FromBytes, &[u8]);
    /// Reads u32s from the bytes, there will always be a multiple of `stride` numbers
    fn u32_stream_with_stride(&self, stride: usize) -> (U32FromBytes, &[u8]);
    /// Reads u64s from the bytes
    fn u64_stream(&self) -> (U64FromBytes, &[u8]);
    /// Reads u64s from the bytes, there will always be a multiple of `stride` numbers
    fn u64_stream_with_stride(&self, stride: usize) -> (U64FromBytes, &[u8]);
}

impl<'a> NumberStreams for [u8] {
    fn u32_stream(&self) -> (U32FromBytes, &[u8]) {
        U32FromBytes::new(self)
    }
    fn u32_stream_with_stride(&self, stride: usize) -> (U32FromBytes, &[u8]) {
        U32FromBytes::with_stride(self, stride)
    }
    fn u64_stream(&self) -> (U64FromBytes, &[u8]) {
        U64FromBytes::new(self)
    }
    fn u64_stream_with_stride(&self, stride: usize) -> (U64FromBytes, &[u8]) {
        U64FromBytes::with_stride(self, stride)
    }
}

#[cfg(test)]
mod test {
    use ::std::slice;
    use super::{U32_BYTES,U64_BYTES};
    use super::NumberStreams;

    fn u32_slice_as_u8(values: &[u32]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U32_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u32_from_bytes() {
        let orig_values: &[u32] = &[0,1];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u32_from_bytes_with_leftovers() {
        let orig_values: &[u32] = &[0,1];
        let mut as_u8: Vec<_> = u32_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = as_u8.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    #[test]
    fn can_read_u32_from_bytes_with_a_stride() {
        let orig_values: &[u32] = &[0,1,2];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u32_stream_with_stride(2);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..2]);

        let (iter, rest) = rest.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[2..]);
        assert!(rest.is_empty());
    }

    fn u64_slice_as_u8(values: &[u64]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U64_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u64_from_bytes() {
        let orig_values: &[u64] = &[0,1];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u64_from_bytes_with_leftovers() {
        let orig_values: &[u64] = &[0,1];
        let mut as_u8: Vec<_> = u64_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = as_u8.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    #[test]
    fn can_read_u64_from_bytes_with_a_stride() {
        let orig_values: &[u64] = &[0,1,2];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u64_stream_with_stride(2);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..2]);

        let (iter, rest) = rest.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[2..]);
        assert!(rest.is_empty());
    }
}
<commit_msg>raw_pointer_derive lint has been removed<commit_after>use std::marker::PhantomData;
use std::ptr;

// We should use {u32,u64}::BYTES when they are stable;
const U32_BYTES: usize = 4;
const U64_BYTES: usize = 8;

macro_rules! number_stream(
    ($name:ident, $number_type:ty, $bytes_in_type:expr) => (
#[derive(Debug,Copy,Clone)]
struct $name<'a> {
    start: *const $number_type,
    end: *const $number_type,
    marker: PhantomData<&'a ()>
}

impl<'a> $name<'a> {
    fn new(bytes: &'a [u8]) -> ($name<'a>, &'a [u8]) {
        $name::with_stride(bytes, 1)
    }

    // Stride is a grouping of sequential numbers
    //
    // 0 1 2 3 4 5 6 7
    // -------------      We have 7 bytes
    // --- --- --- X      Each number takes 2 bytes
    // --- --- XXX X      With a stride of 2
    //
    // Only four bytes will be consumed, the rest returned
    fn with_stride(bytes: &'a [u8], stride: usize) -> ($name<'a>, &'a [u8]) {
        let n_numbers_in_bytes = bytes.len() / $bytes_in_type;
        let n_strides_in_numbers = n_numbers_in_bytes / stride;
        let total_numbers = n_strides_in_numbers * stride;

        let (mine, theirs) = bytes.split_at(total_numbers * $bytes_in_type);

        let start = mine.as_ptr() as *const $number_type;
        let end = unsafe { start.offset(total_numbers as isize) };

        let me = $name {
            start: start,
            end: end,
            marker: PhantomData,
        };

        (me, theirs)
    }
}

impl<'a> Iterator for $name<'a> {
    type Item = $number_type;

    fn next(&mut self) -> Option<$number_type> {
        if self.start >= self.end { return None }

        let v: $number_type = unsafe { ptr::read(self.start) };

        self.start = unsafe { self.start.offset(1) };
        Some(v)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let cnt = self.count();
        (cnt, Some(cnt))
    }

    fn count(self) -> usize() {
        let total_bytes = self.end as usize - self.start as usize;
        total_bytes / $bytes_in_type
    }
}
));

number_stream!(U32FromBytes, u32, U32_BYTES);
number_stream!(U64FromBytes, u64, U64_BYTES);

/// Converts a slice of bytes into an iterator of numbers.
///
/// The data is always treated as little endian. Only complete ranges
/// of bytes are parsed as the number, any left-over bytes are returned.
// FIXME: Probably doesn't work on big endian machines.
pub trait NumberStreams {
    /// Reads u32s from the bytes
    fn u32_stream(&self) -> (U32FromBytes, &[u8]);
    /// Reads u32s from the bytes, there will always be a multiple of `stride` numbers
    fn u32_stream_with_stride(&self, stride: usize) -> (U32FromBytes, &[u8]);
    /// Reads u64s from the bytes
    fn u64_stream(&self) -> (U64FromBytes, &[u8]);
    /// Reads u64s from the bytes, there will always be a multiple of `stride` numbers
    fn u64_stream_with_stride(&self, stride: usize) -> (U64FromBytes, &[u8]);
}

impl<'a> NumberStreams for [u8] {
    fn u32_stream(&self) -> (U32FromBytes, &[u8]) {
        U32FromBytes::new(self)
    }
    fn u32_stream_with_stride(&self, stride: usize) -> (U32FromBytes, &[u8]) {
        U32FromBytes::with_stride(self, stride)
    }
    fn u64_stream(&self) -> (U64FromBytes, &[u8]) {
        U64FromBytes::new(self)
    }
    fn u64_stream_with_stride(&self, stride: usize) -> (U64FromBytes, &[u8]) {
        U64FromBytes::with_stride(self, stride)
    }
}

#[cfg(test)]
mod test {
    use ::std::slice;
    use super::{U32_BYTES,U64_BYTES};
    use super::NumberStreams;

    fn u32_slice_as_u8(values: &[u32]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U32_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u32_from_bytes() {
        let orig_values: &[u32] = &[0,1];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u32_from_bytes_with_leftovers() {
        let orig_values: &[u32] = &[0,1];
        let mut as_u8: Vec<_> = u32_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = as_u8.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    #[test]
    fn can_read_u32_from_bytes_with_a_stride() {
        let orig_values: &[u32] = &[0,1,2];
        let as_u8 = u32_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u32_stream_with_stride(2);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..2]);

        let (iter, rest) = rest.u32_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[2..]);
        assert!(rest.is_empty());
    }

    fn u64_slice_as_u8(values: &[u64]) -> &[u8] {
        unsafe {
            slice::from_raw_parts(
                values.as_ptr() as *const u8,
                values.len() * U64_BYTES,
            )
        }
    }

    #[test]
    fn can_read_u64_from_bytes() {
        let orig_values: &[u64] = &[0,1];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert!(rest.is_empty());
    }

    #[test]
    fn can_read_u64_from_bytes_with_leftovers() {
        let orig_values: &[u64] = &[0,1];
        let mut as_u8: Vec<_> = u64_slice_as_u8(orig_values).into();
        as_u8.push(42);

        let (iter, rest) = as_u8.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..]);
        assert_eq!(rest, [42]);
    }

    #[test]
    fn can_read_u64_from_bytes_with_a_stride() {
        let orig_values: &[u64] = &[0,1,2];
        let as_u8 = u64_slice_as_u8(orig_values);

        let (iter, rest) = as_u8.u64_stream_with_stride(2);
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[..2]);

        let (iter, rest) = rest.u64_stream();
        let values: Vec<_> = iter.collect();

        assert_eq!(&values[..], &orig_values[2..]);
        assert!(rest.is_empty());
    }
}
<|endoftext|>


<commit_before>//! # cli
//!
//! Handles the command line arguments and executes the runner.
//!

#[cfg(test)]
#[path = "./cli_test.rs"]
mod cli_test;

use config;
use ci_info;
use clap::{App, Arg, ArgMatches, SubCommand};
use descriptor;
use environment;
use logger;
use runner;
use types::{CliArgs, GlobalConfig};
use version;

static NAME: &str = "make";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static AUTHOR: &str = env!("CARGO_PKG_AUTHORS");
static DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
static DEFAULT_TOML: &str = "Makefile.toml";
static DEFAULT_LOG_LEVEL: &str = "info";
static DEFAULT_TASK_NAME: &str = "default";

fn run(cli_args: CliArgs, global_config: &GlobalConfig) {
    logger::init(&cli_args.log_level);

    info!("cargo-{} {}", &NAME, &VERSION);
    debug!("Written By {}", &AUTHOR);

    debug!("Cli Args {:#?}", &cli_args);
    debug!("Global Configuration {:#?}", &global_config);

    // only run check for updates if we are not in a CI env and user didn't ask to skip the check
    if !cli_args.disable_check_for_updates && !ci_info::is_ci()
        && version::should_check(&global_config)
    {
        version::check();
    }

    let cwd = match cli_args.cwd {
        Some(ref value) => Some(value.as_ref()),
        None => None,
    };
    environment::setup_cwd(cwd);

    let build_file = &cli_args.build_file;
    let task = &cli_args.task;

    info!("Using Build File: {}", &build_file);
    info!("Task: {}", &task);

    let env = cli_args.env.clone();

    let config = descriptor::load(&build_file, env, cli_args.experimental);

    let env_info = environment::setup_env(&config, &task);

    if cli_args.list_all_steps {
        descriptor::list_steps(&config);
    } else if cli_args.print_only {
        runner::print(&config, &task, cli_args.disable_workspace);
    } else {
        runner::run(config, &task, env_info, cli_args.disable_workspace);
    }
}

/// Handles the command line arguments and executes the runner.
fn run_for_args(matches: ArgMatches, global_config: &GlobalConfig) {
    match matches.subcommand_matches(NAME) {
        Some(cmd_matches) => {
            let mut cli_args = CliArgs::new();

            cli_args.env = cmd_matches.values_of_lossy("env");

            cli_args.build_file = cmd_matches
                .value_of("makefile")
                .unwrap_or(&DEFAULT_TOML)
                .to_string();

            cli_args.cwd = match cmd_matches.value_of("cwd") {
                Some(value) => Some(value.to_string()),
                None => None,
            };

            cli_args.log_level = if cmd_matches.is_present("v") {
                "verbose".to_string()
            } else {
                cmd_matches
                    .value_of("loglevel")
                    .unwrap_or(&DEFAULT_LOG_LEVEL)
                    .to_string()
            };

            cli_args.disable_check_for_updates =
                cmd_matches.is_present("disable-check-for-updates");
            cli_args.experimental = cmd_matches.is_present("experimental");
            cli_args.print_only = cmd_matches.is_present("print-steps");
            cli_args.disable_workspace = cmd_matches.is_present("no-workspace");
            cli_args.list_all_steps = cmd_matches.is_present("list-steps");

            let task = cmd_matches.value_of("task").unwrap_or(&DEFAULT_TASK_NAME);
            cli_args.task = cmd_matches.value_of("TASK").unwrap_or(task).to_string();

            run(cli_args, global_config);
        }
        None => panic!("cargo-{} not invoked via cargo command.", NAME),
    }
}

fn create_cli<'a, 'b>(global_config: &'a GlobalConfig) -> App<'a, 'b> {
    let default_task_name = match global_config.default_task_name {
        Some(ref value) => value.as_str().clone(),
        None => &DEFAULT_TASK_NAME,
    };
    let default_log_level = match global_config.log_level {
        Some(ref value) => value.as_str().clone(),
        None => &DEFAULT_LOG_LEVEL,
    };

    App::new("cargo").bin_name("cargo").subcommand(
        SubCommand::with_name(NAME)
            .version(VERSION)
            .author(AUTHOR)
            .about(DESCRIPTION)
            .arg(
                Arg::with_name("makefile")
                    .long("--makefile")
                    .value_name("FILE")
                    .help("The optional toml file containing the tasks definitions")
                    .default_value(&DEFAULT_TOML),
            )
            .arg(
                Arg::with_name("task")
                    .short("-t")
                    .long("--task")
                    .value_name("TASK")
                    .help(
                        "The task name to execute \
                         (can omit the flag if the task name is the last argument)",
                    )
                    .default_value(default_task_name),
            )
            .arg(
                Arg::with_name("cwd")
                    .long("--cwd")
                    .value_name("DIRECTORY")
                    .help(
                        "Will set the current working directory. \
                         The search for the makefile will be from this directory if defined.",
                    ),
            )
            .arg(Arg::with_name("no-workspace").long("--no-workspace").help(
                "Disable workspace support (tasks are triggered on workspace and not on members)",
            ))
            .arg(
                Arg::with_name("env")
                    .long("--env")
                    .short("-e")
                    .value_name("ENV")
                    .multiple(true)
                    .takes_value(true)
                    .number_of_values(1)
                    .help("Set environment variables"),
            )
            .arg(
                Arg::from_usage("-l, --loglevel=[LOG LEVEL] 'The log level'")
                    .possible_values(&["verbose", "info", "error"])
                    .default_value(default_log_level),
            )
            .arg(
                Arg::with_name("v")
                    .short("-v")
                    .long("--verbose")
                    .help("Sets the log level to verbose (shorthand for --loglevel verbose)"),
            )
            .arg(
                Arg::with_name("experimental")
                    .long("--experimental")
                    .help("Allows access unsupported experimental predefined tasks."),
            )
            .arg(
                Arg::with_name("disable-check-for-updates")
                    .long("--disable-check-for-updates")
                    .help("Disables the update check during startup"),
            )
            .arg(Arg::with_name("print-steps").long("--print-steps").help(
                "Only prints the steps of the build in the order they will \
                 be invoked but without invoking them",
            ))
            .arg(
                Arg::with_name("list-steps")
                    .long("--list-all-steps")
                    .help("Lists all known steps"),
            )
            .arg(Arg::with_name("TASK")),
    )
}

/// Handles the command line arguments and executes the runner.
pub(crate) fn run_cli() {
    let global_config = config::load();

    let app = create_cli(&global_config);

    let matches = app.get_matches();

    run_for_args(matches, &global_config);
}
<commit_msg>ensure defaults (#64)<commit_after>//! # cli
//!
//! Handles the command line arguments and executes the runner.
//!

#[cfg(test)]
#[path = "./cli_test.rs"]
mod cli_test;

use config;
use ci_info;
use clap::{App, Arg, ArgMatches, SubCommand};
use descriptor;
use environment;
use logger;
use runner;
use types::{CliArgs, GlobalConfig};
use version;

static NAME: &str = "make";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static AUTHOR: &str = env!("CARGO_PKG_AUTHORS");
static DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
static DEFAULT_TOML: &str = "Makefile.toml";
static DEFAULT_LOG_LEVEL: &str = "info";
static DEFAULT_TASK_NAME: &str = "default";

fn run(cli_args: CliArgs, global_config: &GlobalConfig) {
    logger::init(&cli_args.log_level);

    info!("cargo-{} {}", &NAME, &VERSION);
    debug!("Written By {}", &AUTHOR);

    debug!("Cli Args {:#?}", &cli_args);
    debug!("Global Configuration {:#?}", &global_config);

    // only run check for updates if we are not in a CI env and user didn't ask to skip the check
    if !cli_args.disable_check_for_updates && !ci_info::is_ci()
        && version::should_check(&global_config)
    {
        version::check();
    }

    let cwd = match cli_args.cwd {
        Some(ref value) => Some(value.as_ref()),
        None => None,
    };
    environment::setup_cwd(cwd);

    let build_file = &cli_args.build_file;
    let task = &cli_args.task;

    info!("Using Build File: {}", &build_file);
    info!("Task: {}", &task);

    let env = cli_args.env.clone();

    let config = descriptor::load(&build_file, env, cli_args.experimental);

    let env_info = environment::setup_env(&config, &task);

    if cli_args.list_all_steps {
        descriptor::list_steps(&config);
    } else if cli_args.print_only {
        runner::print(&config, &task, cli_args.disable_workspace);
    } else {
        runner::run(config, &task, env_info, cli_args.disable_workspace);
    }
}

/// Handles the command line arguments and executes the runner.
fn run_for_args(matches: ArgMatches, global_config: &GlobalConfig) {
    match matches.subcommand_matches(NAME) {
        Some(cmd_matches) => {
            let mut cli_args = CliArgs::new();

            cli_args.env = cmd_matches.values_of_lossy("env");

            cli_args.build_file = cmd_matches
                .value_of("makefile")
                .unwrap_or(&DEFAULT_TOML)
                .to_string();

            cli_args.cwd = match cmd_matches.value_of("cwd") {
                Some(value) => Some(value.to_string()),
                None => None,
            };

            let default_log_level = match global_config.log_level {
                Some(ref value) => value.as_str().clone(),
                None => &DEFAULT_LOG_LEVEL,
            };
            cli_args.log_level = if cmd_matches.is_present("v") {
                "verbose".to_string()
            } else {
                cmd_matches
                    .value_of("loglevel")
                    .unwrap_or(default_log_level)
                    .to_string()
            };

            cli_args.disable_check_for_updates =
                cmd_matches.is_present("disable-check-for-updates");
            cli_args.experimental = cmd_matches.is_present("experimental");
            cli_args.print_only = cmd_matches.is_present("print-steps");
            cli_args.disable_workspace = cmd_matches.is_present("no-workspace");
            cli_args.list_all_steps = cmd_matches.is_present("list-steps");

            let default_task_name = match global_config.default_task_name {
                Some(ref value) => value.as_str().clone(),
                None => &DEFAULT_TASK_NAME,
            };
            let task = cmd_matches.value_of("task").unwrap_or(default_task_name);
            cli_args.task = cmd_matches.value_of("TASK").unwrap_or(task).to_string();

            run(cli_args, global_config);
        }
        None => panic!("cargo-{} not invoked via cargo command.", NAME),
    }
}

fn create_cli<'a, 'b>(global_config: &'a GlobalConfig) -> App<'a, 'b> {
    let default_task_name = match global_config.default_task_name {
        Some(ref value) => value.as_str().clone(),
        None => &DEFAULT_TASK_NAME,
    };
    let default_log_level = match global_config.log_level {
        Some(ref value) => value.as_str().clone(),
        None => &DEFAULT_LOG_LEVEL,
    };

    App::new("cargo").bin_name("cargo").subcommand(
        SubCommand::with_name(NAME)
            .version(VERSION)
            .author(AUTHOR)
            .about(DESCRIPTION)
            .arg(
                Arg::with_name("makefile")
                    .long("--makefile")
                    .value_name("FILE")
                    .help("The optional toml file containing the tasks definitions")
                    .default_value(&DEFAULT_TOML),
            )
            .arg(
                Arg::with_name("task")
                    .short("-t")
                    .long("--task")
                    .value_name("TASK")
                    .help(
                        "The task name to execute \
                         (can omit the flag if the task name is the last argument)",
                    )
                    .default_value(default_task_name),
            )
            .arg(
                Arg::with_name("cwd")
                    .long("--cwd")
                    .value_name("DIRECTORY")
                    .help(
                        "Will set the current working directory. \
                         The search for the makefile will be from this directory if defined.",
                    ),
            )
            .arg(Arg::with_name("no-workspace").long("--no-workspace").help(
                "Disable workspace support (tasks are triggered on workspace and not on members)",
            ))
            .arg(
                Arg::with_name("env")
                    .long("--env")
                    .short("-e")
                    .value_name("ENV")
                    .multiple(true)
                    .takes_value(true)
                    .number_of_values(1)
                    .help("Set environment variables"),
            )
            .arg(
                Arg::from_usage("-l, --loglevel=[LOG LEVEL] 'The log level'")
                    .possible_values(&["verbose", "info", "error"])
                    .default_value(default_log_level),
            )
            .arg(
                Arg::with_name("v")
                    .short("-v")
                    .long("--verbose")
                    .help("Sets the log level to verbose (shorthand for --loglevel verbose)"),
            )
            .arg(
                Arg::with_name("experimental")
                    .long("--experimental")
                    .help("Allows access unsupported experimental predefined tasks."),
            )
            .arg(
                Arg::with_name("disable-check-for-updates")
                    .long("--disable-check-for-updates")
                    .help("Disables the update check during startup"),
            )
            .arg(Arg::with_name("print-steps").long("--print-steps").help(
                "Only prints the steps of the build in the order they will \
                 be invoked but without invoking them",
            ))
            .arg(
                Arg::with_name("list-steps")
                    .long("--list-all-steps")
                    .help("Lists all known steps"),
            )
            .arg(Arg::with_name("TASK")),
    )
}

/// Handles the command line arguments and executes the runner.
pub(crate) fn run_cli() {
    let global_config = config::load();

    let app = create_cli(&global_config);

    let matches = app.get_matches();

    run_for_args(matches, &global_config);
}
<|endoftext|>


<commit_before>use std::fmt;
use super::interconnect::Interconnect;
use super::reg_status::RegStatus;

pub struct Cpu {
    reg_a: u8,
    reg_x: u8,
    reg_y: u8,
    reg_pc: u16,
    reg_s: u8,
    reg_status: RegStatus,

    instr_pc: u16,
    opcode: u8,
    time: u8,  // cycle of opcode we're executing next
    fetch: u8, // in the real 6502 this would sit on the data bus
}

impl Default for Cpu {
    fn default() -> Cpu {
        Cpu{
            reg_a: 0,
            reg_x: 0,
            reg_y: 0,
            reg_pc: 0xc000, // TODO - this should possibly start at the reset vector
            reg_s: 0xfd, // TODO - this should start at ff, probably wrong because of the reset
            reg_status: 0x24.into(),

            instr_pc: 0,
            opcode: 0,
            time: 0,
            fetch: 0,
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let rs: u8 = self.reg_status.clone().into();
        write!(
            f,
            "A: {:02X} X: {:02X} Y: {:02X} P: {:02X} SP: {:02X}",
            self.reg_a,
            self.reg_x,
            self.reg_y,
            rs,
            self.reg_s)
    }
}

impl Cpu {
    pub fn run(&mut self, interconnect: &mut Interconnect) {
        loop {
            self.execute_cycle(interconnect);
        }
    }

    fn execute_cycle(&mut self, interconnect: &mut Interconnect) {
        self.time += 1;
        if self.time == 1 {
            // T1 - All instructions
            self.instr_pc = self.reg_pc;
            self.opcode = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return
        }

        if self.opcode == 0x4c && self.time == 2 {
            // T2 - JMP
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.opcode == 0x4c && self.time == 3 {
            // T3 - JMP
            let pch = interconnect.read_byte(self.reg_pc);
            self.reg_pc = ((pch as u16) << 8) | (self.fetch as u16);
            println!("{:04X}  {:02X} {:02X} {:02X}  JMP ${:04X}     {:?}", self.instr_pc, self.opcode, self.fetch, pch, self.reg_pc, self);
            self.time = 0;
            return;
        }

        if self.opcode == 0xa2 && self.time == 2 {
            // T2 - LDX Immediate
            let value = interconnect.read_byte(self.reg_pc);
            self.reg_x = value;
            self.reg_pc += 1;
            if value == 0 {
                self.reg_status.zero = true;
            }
            if value & (1 << 7) != 0 {
                self.reg_status.negative = true;
            }
            println!("{:04X}  {:02X} {:02X}     LDX #${:02X}      {:?}", self.instr_pc, self.opcode, self.reg_x, self.reg_x, self);
            self.time = 0;
            return;
        }

        if self.opcode == 0x86 && self.time == 2 {
            // T2 - STX Zero Page
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.opcode == 0x86 && self.time == 3 {
            interconnect.write_byte(self.fetch as u16, self.reg_x);
            println!("{:04X}  {:02X} {:02X}     STX ${:02X} = {:02X}  {:?}", self.instr_pc, self.opcode, self.fetch, self.fetch, self.reg_x, self);
            self.time = 0;
            return;
        }

        if self.opcode == 0x20 && self.time == 2{
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.opcode == 0x20 && self.time == 3{
            // internal operation (predecrement S?)
            return;
        }
        if self.opcode == 0x20 && self.time == 4{
            let byte = (self.reg_pc >> 8) as u8;
            self.push_byte(interconnect, byte);
            return;
        }
        if self.opcode == 0x20 && self.time == 5{
            let byte = self.reg_pc as u8;
            self.push_byte(interconnect, byte);
            return;
        }
        if self.opcode == 0x20 && self.time == 6{
            let pch = interconnect.read_byte(self.reg_pc);
            self.reg_pc = ((pch as u16) << 8) | (self.fetch as u16);
            println!("{:04X}  {:02X} {:02X} {:02X}   JSR ${:04X}    {:?}", self.instr_pc, self.opcode, self.fetch, pch, self.reg_pc, self);
            self.time = 0;
            return;
        }

        if self.opcode == 0xea && self.time == 2 {
            println!("{:04X}  {:02X}         NOP          {:?}", self.instr_pc, self.opcode, self);
            self.time = 0;
            return;
        }

        if self.opcode == 0x38 && self.time == 2 {
            self.reg_status.carry = true;
            println!("{:04X}  {:02X}         SEC          {:?}", self.instr_pc, self.opcode, self);
            self.time = 0;
            return;
        }

        panic!("Unmatched opcode/time pair {:x}/{}", self.opcode, self.time);
    }

    fn push_byte(&mut self, interconnect: &mut Interconnect, val: u8) {
        interconnect.write_byte(self.reg_s as u16, val);
        self.reg_s -= 1;
    }
}
<commit_msg>Implement more instructions, generalize branching<commit_after>use std::fmt;
use super::interconnect::Interconnect;
use super::reg_status::RegStatus;

pub struct Cpu {
    reg_a: u8,
    reg_x: u8,
    reg_y: u8,
    reg_pc: u16,
    reg_s: u8,
    reg_status: RegStatus,

    instr_pc: u16,
    opcode: u8,
    time: u8,  // cycle of opcode we're executing next
    fetch: u8, // in the real 6502 this would sit on the data bus
}

impl Default for Cpu {
    fn default() -> Cpu {
        Cpu{
            reg_a: 0,
            reg_x: 0,
            reg_y: 0,
            reg_pc: 0xc000, // TODO - this should possibly start at the reset vector
            reg_s: 0xfd, // TODO - this should start at ff, probably wrong because of the reset
            reg_status: 0x24.into(),

            instr_pc: 0,
            opcode: 0,
            time: 0,
            fetch: 0,
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let rs: u8 = self.reg_status.clone().into();
        write!(
            f,
            "A: {:02X} X: {:02X} Y: {:02X} P: {:02X} SP: {:02X}",
            self.reg_a,
            self.reg_x,
            self.reg_y,
            rs,
            self.reg_s)
    }
}

impl Cpu {
    pub fn run(&mut self, interconnect: &mut Interconnect) {
        loop {
            self.execute_cycle(interconnect);
        }
    }

    fn execute_cycle(&mut self, interconnect: &mut Interconnect) {
        self.time += 1;
        if self.time == 1 {
            // T1 - All instructions
            self.instr_pc = self.reg_pc;
            self.opcode = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return
        }

        if self.opcode == 0x4c && self.time == 2 {
            // T2 - JMP
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.opcode == 0x4c && self.time == 3 {
            // T3 - JMP
            let pch = interconnect.read_byte(self.reg_pc);
            self.reg_pc = ((pch as u16) << 8) | (self.fetch as u16);
            println!("{:04X}  {:02X} {:02X} {:02X}   JMP ${:04X}     {:?}", self.instr_pc, self.opcode, self.fetch, pch, self.reg_pc, self);
            self.time = 0;
            return;
        }

        // LDX
        if self.opcode == 0xa2 && self.time == 2 {
            // T2 - LDX Immediate
            let value = interconnect.read_byte(self.reg_pc);
            self.reg_x = value;
            self.reg_pc += 1;
            self.reg_status.zero = value == 0;
            self.reg_status.negative = (value & (1 << 7)) != 0;

            println!("{:04X}  {:02X} {:02X}      LDX #${:02X}      {:?}", self.instr_pc, self.opcode, self.reg_x, self.reg_x, self);
            self.time = 0;
            return;
        }

        // LDA
        if self.opcode == 0xa9 && self.time == 2 {
            let value = interconnect.read_byte(self.reg_pc);
            self.reg_a = value;
            self.reg_pc += 1;
            self.reg_status.zero = value == 0;
            self.reg_status.negative = (value & (1 << 7)) != 0;

            println!("{:04X}  {:02X} {:02X}      LDA #${:02X}      {:?}", self.instr_pc, self.opcode, self.reg_a, self.reg_a, self);
            self.time = 0;
            return;
        }

        if self.opcode == 0x86 && self.time == 2 {
            // T2 - STX Zero Page
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.opcode == 0x86 && self.time == 3 {
            interconnect.write_byte(self.fetch as u16, self.reg_x);
            println!("{:04X}  {:02X} {:02X}      STX ${:02X} = {:02X}  {:?}", self.instr_pc, self.opcode, self.fetch, self.fetch, self.reg_x, self);
            self.time = 0;
            return;
        }

        // JSR
        if self.opcode == 0x20 && self.time == 2{
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.opcode == 0x20 && self.time == 3{
            // internal operation (predecrement S?)
            return;
        }
        if self.opcode == 0x20 && self.time == 4{
            let byte = (self.reg_pc >> 8) as u8;
            self.push_byte(interconnect, byte);
            return;
        }
        if self.opcode == 0x20 && self.time == 5{
            let byte = self.reg_pc as u8;
            self.push_byte(interconnect, byte);
            return;
        }
        if self.opcode == 0x20 && self.time == 6{
            let pch = interconnect.read_byte(self.reg_pc);
            self.reg_pc = ((pch as u16) << 8) | (self.fetch as u16);
            println!("{:04X}  {:02X} {:02X} {:02X}   JSR ${:04X}    {:?}", self.instr_pc, self.opcode, self.fetch, pch, self.reg_pc, self);
            self.time = 0;
            return;
        }

        // NOP
        if self.opcode == 0xea && self.time == 2 {
            println!("{:04X}  {:02X}         NOP          {:?}", self.instr_pc, self.opcode, self);
            self.time = 0;
            return;
        }
        // SEC
        if self.opcode == 0x38 && self.time == 2 {
            self.reg_status.carry = true;
            println!("{:04X}  {:02X}         SEC          {:?}", self.instr_pc, self.opcode, self);
            self.time = 0;
            return;
        }
        // CLC
        if self.opcode == 0x18 && self.time == 2 {
            self.reg_status.carry = false;
            println!("{:04X}  {:02X}         SEC          {:?}", self.instr_pc, self.opcode, self);
            self.time = 0;
            return;
        }

        // Relative branch - based on reg_status values
        if self.is_branch(self.opcode) && self.time == 2 {
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.is_branch(self.opcode) && self.time == 3 {
            if self.take_branch(self.opcode) {
                // TODO - this operation should take 2 cycles
                // we should increment the low byte of pc in this cycle
                // and increment the high bytes in the next if necessary
                self.reg_pc += self.fetch as u16;
            } else {
            println!("{:04X}  {:02X} {:02X}      {} ${:04X}    {:?}", self.instr_pc, self.opcode, self.fetch, self.opcode_name(self.opcode), self.reg_pc + self.fetch as u16, self);
            self.time = 0;
            }
            return;
        }
        if self.is_branch(self.opcode) && self.time == 4 {
            // TODO - we should increment the high order byte of pc here if the
            // low order addition overflowed, and we should run for 5 cycles if
            // that happens
            println!("{:04X}  {:02X} {:02X}      {} ${:04X}    {:?}", self.instr_pc, self.opcode, self.fetch, self.opcode_name(self.opcode), self.reg_pc, self);
            self.time = 0;
            return;
        }
        if self.is_branch(self.opcode) && self.time == 5 {
        }

        panic!("Unmatched opcode/time pair {:x}/{}", self.opcode, self.time);
    }

    fn push_byte(&mut self, interconnect: &mut Interconnect, val: u8) {
        interconnect.write_byte(self.reg_s as u16, val);
        self.reg_s -= 1;
    }

    fn is_branch(&self, opcode: u8) -> bool {
        opcode & 16 == 16 && !opcode & 15 == 15
    }
    fn take_branch(&self, opcode: u8) -> bool {
        match opcode {
            0xb0 => self.reg_status.carry,
            0x90 => !self.reg_status.carry,
            0xd0 => !self.reg_status.zero,
            0xf0 => self.reg_status.zero,
            _ => panic!("Unrecognised branch instruction {:02X}", opcode),
        }
    }

    fn opcode_name(&self, opcode: u8) -> &'static str {
        match opcode {
            0xb0 => "BCS",
            0x90 => "BCC",
            0xd0 => "BNE",
            0xf0 => "BEQ",
            _ => panic!("Unrecognised instruction {:02X}", opcode),
        }
    }
}
<|endoftext|>


<commit_before>use num::integer::Integer;
use memory::Memory;
use memory::low_nibble;
use memory::high_nibble;
use extensions::Incrementor;
use ops::{mod};
use std::num::One;

pub struct Cpu<'a> {
    reg: Registers,
    mem: &'a mut Memory
}

impl<'a> Cpu<'a> {
    pub fn new(memory: &'a mut Memory) -> Cpu<'a> {
        return Cpu{reg: Registers::new(), mem: memory}
    }

    /// Execute a cycle on the cpu
    pub fn tick(&mut self) {
        let instr = self.fetch_instruction();

        match instr {
            0x00 => ops::nop(),
            0x01 => ops::ld_next_two_byte_into_reg_pair(self.mem, &mut self.reg.pc, &mut self.reg.b, &mut self.reg.c),
            0x02 => ops::write_value_to_memory_at_address(self.mem, self.reg.a.read(), self.reg.b.read(), self.reg.c.read()),
            0x03 => ops::increment_register_pair(&mut self.reg.b, &mut self.reg.c),
            0x04 => ops::increment_register(&mut self.reg.b, &mut self.reg.f),
            0x05 => ops::decrement_register(&mut self.reg.b, &mut self.reg.f),
            0x06 => ops::ld_immediate(self.mem, &mut self.reg.pc, &mut self.reg.b),
            0x07 => ops::rotate_left_with_carry(&mut self.reg.a, &mut self.reg.f),
            0x08 => ops::write_sp_to_address_immediate(self.mem, &mut self.reg.pc, &self.reg.sp),
            0x09 => ops::add_register_pair_to_register_pair(&mut self.reg.h, &mut self.reg.l, &self.reg.b, &self.reg.c, &mut self.reg.f),
            0x0A => ops::ld_a_from_reg_pair_as_address(self.mem, &mut self.reg.a, &mut self.reg.b, &mut self.reg.c),
            0x0B => ops::decrement_register_pair(&mut self.reg.b, &mut self.reg.c),
            0x0C => ops::increment_register(&mut self.reg.c, &mut self.reg.f),
            0x0D => ops::decrement_register(&mut self.reg.c, &mut self.reg.f),
            0x0E => ops::ld_immediate(self.mem, &mut self.reg.pc, &mut self.reg.c),
            0x0F => ops::rotate_right_with_carry(&mut self.reg.a, &mut self.reg.f),
            _ => return
        }
    }

    /// Fetches the instruction pointed to by the program counter
    /// and increments the pc by 1
    fn fetch_instruction(&mut self) -> u8 {
        let instr = self.mem.read_byte(self.reg.pc.val);
        self.reg.pc.increment();
        return instr;
    }
}

struct Registers {
    a: Register<u8>, b: Register<u8>, c: Register<u8>,
    d: Register<u8>, e: Register<u8>, f: Register<Flags>,
    h: Register<u8>, l: Register<u8>, // 8-bit registers

    pc: Register<u16>, sp: Register<u16>, // 16-bit registers
    m: Register<u16>, t: Register<u16> // clock
}

impl Registers {
    fn new() -> Registers {
        return Registers{
            a: Register::new(0),
            b: Register::new(0),
            c: Register::new(0),
            d: Register::new(0),
            e: Register::new(0),
            f: Register::new(Flags::empty()),
            h: Register::new(0),
            l: Register::new(0),

            pc: Register::new(0x100),
            sp: Register::new(0xFFFE),

            m: Register::new(0),
            t: Register::new(0)
        }
    }
}

pub struct Register<T: Copy> {
    val: T
}

impl<T: Copy> Register<T> {
    pub fn new(i: T) -> Register<T> {
        return Register { val: i };
    }

    pub fn read(&self) -> T {
        return self.val;
    }

    pub fn write(&mut self, i: T) {
        self.val = i;
    }
}

impl<T: Copy + Unsigned>  Register<T> {
    pub fn increment(&mut self) {
        let i = self.val;
        self.write(i + One::one());
    }

    pub fn decrement(&mut self) {
        let i = self.val;
        self.write(i - One::one());
    }
}

bitflags! {
    flags Flags: u8 {
        const ZeroFlag       = 0b10000000,
        const SubtractFlag   = 0b01000000,
        const HalfCarryFlag  = 0b00100000,
        const CarryFlag      = 0b00010000,
    }
}

#[test]
fn test_Register_new() {
    let reg: Register<u8> = Register::new(10);
    assert!(reg.val == 10);
}

#[test]
fn test_Register_read() {
    let reg: Register<u32> = Register::new(5);
    assert!(reg.read() == 5);
}

#[test]
fn test_Register_write() {
    let mut reg: Register<u16> = Register::new(483);

    reg.write(5);
    assert!(reg.val == 5);
}

#[test]
fn test_Register_increment() {
    let mut reg: Register<u16> = Register::new(483);

    reg.increment();
    assert!(reg.val == 484);

}

#[test]
fn test_Register_decrement() {
    let mut reg: Register<u16> = Register::new(401);

    reg.decrement();
    assert!(reg.val == 400);

}

#[test]
fn test_Registers_new() {
    let a = Registers::new();
    assert!(a.pc.read() == 0x100);
    assert!(a.sp.read() == 0xFFFE);
}
<commit_msg>Add 0x10-0x15 opcodes<commit_after>use num::integer::Integer;
use memory::Memory;
use memory::low_nibble;
use memory::high_nibble;
use extensions::Incrementor;
use ops::{mod};
use std::num::One;

pub struct Cpu<'a> {
    reg: Registers,
    mem: &'a mut Memory
}

impl<'a> Cpu<'a> {
    pub fn new(memory: &'a mut Memory) -> Cpu<'a> {
        return Cpu{reg: Registers::new(), mem: memory}
    }

    /// Execute a cycle on the cpu
    pub fn tick(&mut self) {
        let instr = self.fetch_instruction();

        match instr {
            0x00 => ops::nop(), // NOP
            0x01 => ops::ld_next_two_byte_into_reg_pair(self.mem, &mut self.reg.pc, &mut self.reg.b, &mut self.reg.c), // LD BC, nn
            0x02 => ops::write_value_to_memory_at_address(self.mem, self.reg.a.read(), self.reg.b.read(), self.reg.c.read()), // LD (BC), A
            0x03 => ops::increment_register_pair(&mut self.reg.b, &mut self.reg.c), // INC BC
            0x04 => ops::increment_register(&mut self.reg.b, &mut self.reg.f), // INC B
            0x05 => ops::decrement_register(&mut self.reg.b, &mut self.reg.f), // DEC B
            0x06 => ops::ld_immediate(self.mem, &mut self.reg.pc, &mut self.reg.b), // LD B, n
            0x07 => ops::rotate_left_with_carry(&mut self.reg.a, &mut self.reg.f), // RLC A
            0x08 => ops::write_sp_to_address_immediate(self.mem, &mut self.reg.pc, &self.reg.sp), // LD (nn), SP
            0x09 => ops::add_register_pair_to_register_pair(&mut self.reg.h, &mut self.reg.l, &self.reg.b, &self.reg.c, &mut self.reg.f), // ADD HL, BC
            0x0A => ops::ld_a_from_reg_pair_as_address(self.mem, &mut self.reg.a, &mut self.reg.b, &mut self.reg.c), // LD A, (BC)
            0x0B => ops::decrement_register_pair(&mut self.reg.b, &mut self.reg.c), // DEC BC
            0x0C => ops::increment_register(&mut self.reg.c, &mut self.reg.f), // INC C
            0x0D => ops::decrement_register(&mut self.reg.c, &mut self.reg.f), // DEC C
            0x0E => ops::ld_immediate(self.mem, &mut self.reg.pc, &mut self.reg.c), // LD C, n
            0x0F => ops::rotate_right_with_carry(&mut self.reg.a, &mut self.reg.f), // RRC A
            0x10 => return, // STOP
            0x11 => ops::ld_next_two_byte_into_reg_pair(self.mem, &mut self.reg.pc, &mut self.reg.d, &mut self.reg.e), // LD DE, nn
            0x12 => ops::write_value_to_memory_at_address(self.mem, self.reg.a.read(), self.reg.d.read(), self.reg.e.read()), // LD (DE), A
            0x13 => ops::increment_register_pair(&mut self.reg.d, &mut self.reg.e), // INC DE
            0x14 => ops::increment_register(&mut self.reg.d, &mut self.reg.f), // INC D
            0x15 => ops::decrement_register(&mut self.reg.d, &mut self.reg.f), // DEC D
            _ => return
        }
    }

    /// Fetches the instruction pointed to by the program counter
    /// and increments the pc by 1
    fn fetch_instruction(&mut self) -> u8 {
        let instr = self.mem.read_byte(self.reg.pc.val);
        self.reg.pc.increment();
        return instr;
    }
}

struct Registers {
    a: Register<u8>, b: Register<u8>, c: Register<u8>,
    d: Register<u8>, e: Register<u8>, f: Register<Flags>,
    h: Register<u8>, l: Register<u8>, // 8-bit registers

    pc: Register<u16>, sp: Register<u16>, // 16-bit registers
    m: Register<u16>, t: Register<u16> // clock
}

impl Registers {
    fn new() -> Registers {
        return Registers{
            a: Register::new(0),
            b: Register::new(0),
            c: Register::new(0),
            d: Register::new(0),
            e: Register::new(0),
            f: Register::new(Flags::empty()),
            h: Register::new(0),
            l: Register::new(0),

            pc: Register::new(0x100),
            sp: Register::new(0xFFFE),

            m: Register::new(0),
            t: Register::new(0)
        }
    }
}

pub struct Register<T: Copy> {
    val: T
}

impl<T: Copy> Register<T> {
    pub fn new(i: T) -> Register<T> {
        return Register { val: i };
    }

    pub fn read(&self) -> T {
        return self.val;
    }

    pub fn write(&mut self, i: T) {
        self.val = i;
    }
}

impl<T: Copy + Unsigned>  Register<T> {
    pub fn increment(&mut self) {
        let i = self.val;
        self.write(i + One::one());
    }

    pub fn decrement(&mut self) {
        let i = self.val;
        self.write(i - One::one());
    }
}

bitflags! {
    flags Flags: u8 {
        const ZeroFlag       = 0b10000000,
        const SubtractFlag   = 0b01000000,
        const HalfCarryFlag  = 0b00100000,
        const CarryFlag      = 0b00010000,
    }
}

#[test]
fn test_Register_new() {
    let reg: Register<u8> = Register::new(10);
    assert!(reg.val == 10);
}

#[test]
fn test_Register_read() {
    let reg: Register<u32> = Register::new(5);
    assert!(reg.read() == 5);
}

#[test]
fn test_Register_write() {
    let mut reg: Register<u16> = Register::new(483);

    reg.write(5);
    assert!(reg.val == 5);
}

#[test]
fn test_Register_increment() {
    let mut reg: Register<u16> = Register::new(483);

    reg.increment();
    assert!(reg.val == 484);

}

#[test]
fn test_Register_decrement() {
    let mut reg: Register<u16> = Register::new(401);

    reg.decrement();
    assert!(reg.val == 400);

}

#[test]
fn test_Registers_new() {
    let a = Registers::new();
    assert!(a.pc.read() == 0x100);
    assert!(a.sp.read() == 0xFFFE);
}
<|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.

//! # Node Builder
//!
//! ```
//! use commands::parser::builder::*;
//!
//! let mut tree = CommandTree::new();
//! tree.command(Command::new("again")
//!                  .hidden(false)
//!                  .parameter(Parameter::new("test")
//!                                 .required(false)
//!                                 .help("This is just a test parameter.")
//!                                 .finalize())
//!                  .finalize());
//! ```

use std::rc::Rc;
use super::nodes::*;

/// Indicate the type of parameter, so that the correct class and node
/// structures are created.
#[derive(Clone, Copy, PartialEq)]
pub enum ParameterKind {
    /// This parameter is a `FlagParameter`.
    Flag,
    /// This parameter is a `NamedParameter`.
    Named,
    /// This parameter is a `SimpleParameter`.
    Simple,
}

/// Store a command tree while populating it. This can be used
/// to construct a `RootNode` to be used with the `Parser`.
pub struct CommandTree {
    commands: Vec<Command>,
}

impl CommandTree {
    /// Create a new `CommandTree`.
    pub fn new() -> Self {
        CommandTree { commands: vec![] }
    }

    /// Add a `Command` to the `CommandTree`.
    pub fn command(&mut self, command: Command) {
        self.commands.push(command);
    }

    fn build_parameter(self, parameter: Parameter) -> Rc<Node> {
        match parameter.parameter_kind {
            ParameterKind::Flag => Rc::new(self.build_flag_parameter(parameter)),
            ParameterKind::Named => Rc::new(self.build_named_parameter(parameter)),
            ParameterKind::Simple => Rc::new(self.build_simple_parameter(parameter)),
        }
    }

    fn build_flag_parameter(self, parameter: Parameter) -> FlagParameterNode {
        FlagParameterNode::new(&*parameter.name,
                               parameter.help_text,
                               parameter.hidden,
                               parameter.priority,
                               vec![],
                               parameter.repeatable,
                               None,
                               parameter.required)
    }

    fn build_named_parameter(self, parameter: Parameter) -> NamedParameterNode {
        NamedParameterNode::new(&*parameter.name,
                                parameter.help_text,
                                parameter.hidden,
                                parameter.priority,
                                vec![],
                                parameter.repeatable,
                                None,
                                parameter.required)
    }

    fn build_simple_parameter(self, parameter: Parameter) -> SimpleParameterNode {
        SimpleParameterNode::new(&*parameter.name,
                                 parameter.help_text,
                                 parameter.hidden,
                                 parameter.priority,
                                 vec![],
                                 parameter.repeatable,
                                 None,
                                 parameter.required)
    }
}

/// Description of a command to be added to the `CommandTree`.
#[derive(Clone)]
pub struct Command {
    hidden: bool,
    priority: i32,
    name: String,
    help_text: Option<String>,
    parameters: Vec<Parameter>,
    wrapped_root: Option<String>,
}

impl Command {
    /// Construct a default (blank) command with the given `name`.
    pub fn new(name: &str) -> Self {
        Command {
            hidden: false,
            priority: PRIORITY_DEFAULT,
            name: name.to_string(),
            help_text: None,
            parameters: vec![],
            wrapped_root: None,
        }
    }

    /// Mark the command as hidden. Hidden commands will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(&mut self, hidden: bool) -> &mut Self {
        self.hidden = hidden;
        self
    }

    /// Give the command a priority. This is used when sorting
    /// out conflicts during matching and completion.
    pub fn priority(&mut self, priority: i32) -> &mut Self {
        self.priority = priority;
        self
    }

    /// Supply help text for the command.
    pub fn help(&mut self, help_text: &str) -> &mut Self {
        self.help_text = Some(help_text.to_string());
        self
    }

    /// Add a `Parameter` to the command.
    pub fn parameter(&mut self, parameter: Parameter) -> &mut Self {
        self.parameters.push(parameter);
        self
    }

    /// Create a `WrapperNode` instead of a `CommandNode`. The
    /// `wrapped_root` signifies the path to the command that should
    /// be wrapped by this command.
    pub fn wraps(&mut self, wrapped_root: String) -> &mut Self {
        self.wrapped_root = Some(wrapped_root);
        self
    }

    /// Return an instance of `Command` that can be passed to the
    /// `CommandTree`. This is used to terminate the series of construction
    /// methods used to initialize and configure the command.
    pub fn finalize(&self) -> Self {
        self.clone()
    }
}

/// Description of a parameter to be added to the `Command`.
#[derive(Clone)]
pub struct Parameter {
    hidden: bool,
    priority: i32,
    name: String,
    repeatable: bool,
    aliases: Vec<String>,
    help_text: Option<String>,
    required: bool,
    parameter_kind: ParameterKind,
}

impl Parameter {
    /// Construct a default (blank) parameter with the given `name`.
    pub fn new(name: &str) -> Self {
        Parameter {
            hidden: false,
            priority: PRIORITY_PARAMETER,
            name: name.to_string(),
            repeatable: false,
            aliases: vec![],
            help_text: None,
            required: false,
            parameter_kind: ParameterKind::Simple,
        }
    }

    /// Mark the parameter as hidden. Hidden parameters will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(&mut self, hidden: bool) -> &mut Self {
        self.hidden = hidden;
        self
    }

    /// Give the parameter a priority. This is used when sorting
    /// out conflicts during matching and completion.
    pub fn priority(&mut self, priority: i32) -> &mut Self {
        self.priority = priority;
        self
    }

    /// Establish whether or not this parameter is repeatable.
    /// Repeated parameters produce a vector of values and can
    /// be given multiple times within a single command invocation.
    pub fn repeatable(&mut self, repeatable: bool) -> &mut Self {
        self.repeatable = repeatable;
        self
    }

    /// Add an alias that this parameter can use.
    pub fn alias(&mut self, alias: &str) -> &mut Self {
        self.aliases.push(alias.to_string());
        self
    }

    /// Supply the help text for the parameter.
    pub fn help(&mut self, help_text: &str) -> &mut Self {
        self.help_text = Some(help_text.to_string());
        self
    }

    /// Establish whether or not this parameter is required.
    pub fn required(&mut self, required: bool) -> &mut Self {
        self.required = required;
        self
    }

    /// Set which type of `ParameterNode` is supposed to be created
    /// to represent this parameter.
    ///
    /// If `kind` is `ParameterKind::Flag`, then the `priority` of
    /// this parameter is altered to be `PRIORITY_DEFAULT` due to
    /// how conflicts must be resolved in parsing flag and simple
    /// parameters.
    pub fn kind(&mut self, kind: ParameterKind) -> &mut Self {
        self.parameter_kind = kind;
        if kind == ParameterKind::Flag {
            self.priority = PRIORITY_DEFAULT;
        }
        self
    }

    /// Return an instance of `Parameter` that can be passed to the
    /// `Command`. This is used to terminate the series of construction
    /// methods used to initialize and configure the parameter.
    pub fn finalize(&self) -> Self {
        self.clone()
    }
}
<commit_msg>Progress on building the command tree.<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.

//! # Node Builder
//!
//! ```
//! use commands::parser::builder::*;
//!
//! let mut tree = CommandTree::new();
//! tree.command(Command::new("again")
//!                  .hidden(false)
//!                  .parameter(Parameter::new("test")
//!                                 .required(false)
//!                                 .help("This is just a test parameter.")
//!                                 .finalize())
//!                  .finalize());
//! ```

use std::rc::Rc;
use super::nodes::*;

/// Indicate the type of parameter, so that the correct class and node
/// structures are created.
#[derive(Clone, Copy, PartialEq)]
pub enum ParameterKind {
    /// This parameter is a `FlagParameter`.
    Flag,
    /// This parameter is a `NamedParameter`.
    Named,
    /// This parameter is a `SimpleParameter`.
    Simple,
}

/// Store a command tree while populating it. This can be used
/// to construct a `RootNode` to be used with the `Parser`.
pub struct CommandTree {
    commands: Vec<Command>,
}

impl CommandTree {
    /// Create a new `CommandTree`.
    pub fn new() -> Self {
        CommandTree { commands: vec![] }
    }

    /// Add a `Command` to the `CommandTree`.
    pub fn command(&mut self, command: Command) {
        self.commands.push(command);
    }

    /// Construct the `CommandTree` and produce a `RootNode`.
    pub fn finalize(&self) -> Rc<RootNode> {
        let mut successors: Vec<Rc<Node>> = vec![];
        for c in &self.commands {
            successors.push(self.build_command(c));
        }
        RootNode::new(successors)
    }

    fn build_command(&self, command: &Command) -> Rc<Node> {
        let mut parameters: Vec<Rc<ParameterNode>> = vec![];
        let mut successors: Vec<Rc<Node>> = vec![];
        for parameter in &command.parameters {
            match parameter.parameter_kind {
                ParameterKind::Flag => {
                    self.build_flag_parameter(parameter, &mut parameters, &mut successors);
                }
                ParameterKind::Named => {
                    self.build_named_parameter(parameter, &mut parameters, &mut successors);
                }
                ParameterKind::Simple => {
                    self.build_simple_parameter(parameter, &mut parameters, &mut successors);
                }
            };
        }
        let c = CommandNode::new(&*command.name,
                                 command.help_text.clone(),
                                 command.hidden,
                                 command.priority,
                                 successors,
                                 None,
                                 parameters);
        Rc::new(c)
    }

    fn build_flag_parameter(&self,
                            parameter: &Parameter,
                            parameters: &mut Vec<Rc<ParameterNode>>,
                            successors: &mut Vec<Rc<Node>>) {
        let p = FlagParameterNode::new(&*parameter.name,
                                       parameter.help_text.clone(),
                                       parameter.hidden,
                                       parameter.priority.unwrap_or(PRIORITY_DEFAULT),
                                       vec![],
                                       parameter.repeatable,
                                       None,
                                       parameter.required);
        let fp = Rc::new(p);
        parameters.push(fp.clone());
        successors.push(fp);
    }

    fn build_named_parameter(&self,
                             parameter: &Parameter,
                             parameters: &mut Vec<Rc<ParameterNode>>,
                             successors: &mut Vec<Rc<Node>>) {
        let p = NamedParameterNode::new(&*parameter.name,
                                        parameter.help_text.clone(),
                                        parameter.hidden,
                                        parameter.priority.unwrap_or(PRIORITY_PARAMETER),
                                        vec![],
                                        parameter.repeatable,
                                        None,
                                        parameter.required);
        let np = Rc::new(p);
        parameters.push(np.clone());
        successors.push(np);
    }

    fn build_simple_parameter(&self,
                              parameter: &Parameter,
                              parameters: &mut Vec<Rc<ParameterNode>>,
                              successors: &mut Vec<Rc<Node>>) {
        let p = SimpleParameterNode::new(&*parameter.name,
                                         parameter.help_text.clone(),
                                         parameter.hidden,
                                         parameter.priority.unwrap_or(PRIORITY_PARAMETER),
                                         vec![],
                                         parameter.repeatable,
                                         None,
                                         parameter.required);
        let sp = Rc::new(p);
        parameters.push(sp.clone());
        successors.push(sp);
    }
}

/// Description of a command to be added to the `CommandTree`.
#[derive(Clone)]
pub struct Command {
    hidden: bool,
    priority: i32,
    name: String,
    help_text: Option<String>,
    parameters: Vec<Parameter>,
    wrapped_root: Option<String>,
}

impl Command {
    /// Construct a default (blank) command with the given `name`.
    pub fn new(name: &str) -> Self {
        Command {
            hidden: false,
            priority: PRIORITY_DEFAULT,
            name: name.to_string(),
            help_text: None,
            parameters: vec![],
            wrapped_root: None,
        }
    }

    /// Mark the command as hidden. Hidden commands will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(&mut self, hidden: bool) -> &mut Self {
        self.hidden = hidden;
        self
    }

    /// Give the command a priority. This is used when sorting
    /// out conflicts during matching and completion.
    pub fn priority(&mut self, priority: i32) -> &mut Self {
        self.priority = priority;
        self
    }

    /// Supply help text for the command.
    pub fn help(&mut self, help_text: &str) -> &mut Self {
        self.help_text = Some(help_text.to_string());
        self
    }

    /// Add a `Parameter` to the command.
    pub fn parameter(&mut self, parameter: Parameter) -> &mut Self {
        self.parameters.push(parameter);
        self
    }

    /// Create a `WrapperNode` instead of a `CommandNode`. The
    /// `wrapped_root` signifies the path to the command that should
    /// be wrapped by this command.
    pub fn wraps(&mut self, wrapped_root: String) -> &mut Self {
        self.wrapped_root = Some(wrapped_root);
        self
    }

    /// Return an instance of `Command` that can be passed to the
    /// `CommandTree`. This is used to terminate the series of construction
    /// methods used to initialize and configure the command.
    pub fn finalize(&self) -> Self {
        self.clone()
    }
}

/// Description of a parameter to be added to the `Command`.
#[derive(Clone)]
pub struct Parameter {
    hidden: bool,
    priority: Option<i32>,
    name: String,
    repeatable: bool,
    aliases: Vec<String>,
    help_text: Option<String>,
    required: bool,
    parameter_kind: ParameterKind,
}

impl Parameter {
    /// Construct a default (blank) parameter with the given `name`.
    pub fn new(name: &str) -> Self {
        Parameter {
            hidden: false,
            priority: None,
            name: name.to_string(),
            repeatable: false,
            aliases: vec![],
            help_text: None,
            required: false,
            parameter_kind: ParameterKind::Simple,
        }
    }

    /// Mark the parameter as hidden. Hidden parameters will match
    /// within the parser, but are not listed during completion.
    pub fn hidden(&mut self, hidden: bool) -> &mut Self {
        self.hidden = hidden;
        self
    }

    /// Give the parameter a priority. This is used when sorting
    /// out conflicts during matching and completion.
    ///
    /// The `priority` of a `Parameter` defaults to `PRIORITY_PARAMETER`
    /// except for when the `kind` is `ParameterKind::Flag` in which
    /// case, the default will be `PRIORITY_DEFAULT`.
    pub fn priority(&mut self, priority: i32) -> &mut Self {
        self.priority = Some(priority);
        self
    }

    /// Establish whether or not this parameter is repeatable.
    /// Repeated parameters produce a vector of values and can
    /// be given multiple times within a single command invocation.
    pub fn repeatable(&mut self, repeatable: bool) -> &mut Self {
        self.repeatable = repeatable;
        self
    }

    /// Add an alias that this parameter can use.
    pub fn alias(&mut self, alias: &str) -> &mut Self {
        self.aliases.push(alias.to_string());
        self
    }

    /// Supply the help text for the parameter.
    pub fn help(&mut self, help_text: &str) -> &mut Self {
        self.help_text = Some(help_text.to_string());
        self
    }

    /// Establish whether or not this parameter is required.
    pub fn required(&mut self, required: bool) -> &mut Self {
        self.required = required;
        self
    }

    /// Set which type of `ParameterNode` is supposed to be created
    /// to represent this parameter.
    pub fn kind(&mut self, kind: ParameterKind) -> &mut Self {
        self.parameter_kind = kind;
        self
    }

    /// Return an instance of `Parameter` that can be passed to the
    /// `Command`. This is used to terminate the series of construction
    /// methods used to initialize and configure the parameter.
    pub fn finalize(&self) -> Self {
        self.clone()
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// 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.
//

//! DHT node table implementation based on Kademlia.
//!
//! See [original paper](http://pdos.csail.mit.edu/%7Epetar/papers/maymounkov-kademlia-lncs.pdf)
//! for details. The most essential difference is that when k-bucket is full,
//! no RPC call is done. It is up to upper-level code to ensure proper clean up
//! using `pop_oldest` call.

use std::cmp;
use std::fmt::Debug;
use std::collections::VecDeque;

use super::GenericId;
use super::GenericNodeTable;
use super::Node;

// TODO(divius): make public?
static BUCKET_SIZE: usize = 32;
static DEFAULT_HASH_SIZE: usize = 64;

/// Kademlia node table.
///
/// Keeps nodes in a number of k-buckets (equal to bit size of ID in a system,
/// usually 160), where N-th k-bucket contains nodes with distance
/// from 2^N to 2^(N+1) from our node.
///
/// methods may panic if distance between two ids is greater than the
/// `hash_size`.
pub struct KNodeTable<TId, TAddr> {
    this_id: TId,
    hash_size: usize,
    // TODO(divius): convert to more appropriate data structure
    buckets: Vec<KBucket<TId, TAddr>>,
}

/// K-bucket - structure for keeping last nodes in Kademlia.
struct KBucket<TId, TAddr> {
    data: VecDeque<Node<TId, TAddr>>,
    size: usize,
}

impl<TId, TAddr> KNodeTable<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug {
    /// Create a new node table.
    ///
    /// `this_id` -- ID of the current node (used to calculate metrics).
    pub fn new(this_id: TId) -> KNodeTable<TId, TAddr> {
        KNodeTable::new_with_details(this_id, BUCKET_SIZE, DEFAULT_HASH_SIZE)
    }

    pub fn new_with_details(this_id: TId, bucket_size: usize,
                    hash_size: usize) -> KNodeTable<TId, TAddr> {
        KNodeTable {
            this_id: this_id,
            hash_size: hash_size,
            buckets: (0..hash_size).map(
                              |_| KBucket::new(bucket_size)).collect(),
        }
    }

    #[inline]
    fn distance(id1: &TId, id2: &TId) -> TId {
        id1.bitxor(id2)
    }

    fn bucket_number(&self, id: &TId) -> usize {
        let diff = KNodeTable::<TId, TAddr>::distance(&self.this_id, id);
        debug_assert!(!diff.is_zero());
        let res = diff.bits() - 1;
        if res >= self.hash_size {
            panic!(format!("Distance between IDs {:?} and {:?} is {:?}, which is \
                    greater than the hash size ({:?})",
                    id, self.this_id, res, self.hash_size));
        }
        debug!("ID {:?} relative to own ID {:?} falls into bucket {:?}",
               id, self.this_id, res);
        res
    }
}

impl<TId, TAddr> GenericNodeTable<TId, TAddr> for KNodeTable<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug + Sync + Send {
    fn random_id(&self) -> TId {
        TId::gen(self.hash_size)
    }

    fn update(&mut self, node: &Node<TId, TAddr>) -> bool {
        assert!(node.id != self.this_id);
        let bucket = self.bucket_number(&node.id);
        self.buckets[bucket].update(node)
    }

    fn find(&self, id: &TId, count: usize) -> Vec<Node<TId, TAddr>> {
        debug_assert!(count > 0);
        assert!(*id != self.this_id);
        let bucket = self.bucket_number(id);
        self.buckets[bucket].find(id, count)
    }

    fn pop_oldest(&mut self) -> Vec<Node<TId, TAddr>> {
        // For every full k-bucket, pop the last.
        // TODO(divius): TTL expiration?
        self.buckets.iter_mut()
            .filter(|b| { !b.data.is_empty() && b.size == b.data.len() })
            .map(|b| b.data.pop_front().unwrap())
            .collect()
    }
}

impl<TId, TAddr> KBucket<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug {
    pub fn new(k: usize) -> KBucket<TId, TAddr> {
        assert!(k > 0);
        KBucket {
            data: VecDeque::new(),
            size: k
        }
    }

    pub fn update(&mut self, node: &Node<TId, TAddr>) -> bool {
        if self.data.iter().any(|x| x.id == node.id) {
            self.update_position(node.clone());
            debug!("Promoted node {:?} to the top of kbucket", node);
            true
        }
        else if self.data.len() == self.size {
            debug!("Not adding new node {:?} to kbucket - no space left", node);
            false
        }
        else {
            self.data.push_back(node.clone());
            debug!("Added new node {:?} to kbucket", node);
            true
        }
    }

    pub fn find(&self, id: &TId, count: usize) -> Vec<Node<TId, TAddr>> {
        let sort_fn = |a: &Node<TId, TAddr>, b: &Node<TId, TAddr>| {
            KNodeTable::<TId, TAddr>::distance(id, &a.id)
                .cmp(&KNodeTable::<TId, TAddr>::distance(id, &b.id))
        };
        let mut data_copy: Vec<_> = self.data.iter().map(|n| n.clone()).collect();
        data_copy.sort_by(sort_fn);
        data_copy[0..cmp::min(count, data_copy.len())].to_vec()
    }

    fn update_position(&mut self, node: Node<TId, TAddr>) {
        // TODO(divius): 1. optimize, 2. make it less ugly
        let mut new_data = VecDeque::with_capacity(self.data.len());
        new_data.extend(self.data.iter()
                        .filter(|x| x.id != node.id)
                        .map(|x| x.clone()));
        new_data.push_back(node.clone());
        self.data = new_data;
    }
}

#[cfg(test)]
mod test {
    use std::net;

    use super::super::GenericNodeTable;
    use super::super::Node;

    use super::DEFAULT_HASH_SIZE;
    use super::KBucket;
    use super::KNodeTable;

    use super::super::utils::test;
    type TestsIdType = test::IdType;
    use super::super::base::GenericId;

    fn prepare(count: u8) -> KBucket<TestsIdType, net::SocketAddr> {
        KBucket {
            data: (0..count).map(|i| test::new_node(test::make_id(i))).collect(),
            size: 3,
        }
    }

    fn assert_node_list_eq(expected: &[&Node<TestsIdType, net::SocketAddr>], actual: &Vec<Node<TestsIdType, net::SocketAddr>>) {
        let act: Vec<TestsIdType> = actual.iter()
            .map(|n| n.id.clone()).collect();
        let exp: Vec<TestsIdType> = expected.iter()
            .map(|n| n.id.clone()).collect();
        assert_eq!(exp, act);
    }

    #[test]
    fn test_nodetable_new() {
        let n = KNodeTable::<u64, ()>::new(42);
        assert_eq!(DEFAULT_HASH_SIZE, n.buckets.len());
    }

    #[test]
    fn test_nodetable_bucket_number() {
        let n = KNodeTable::<u64, ()>::new(42);
        let id = 41;
        // 42 xor 41 == 3
        assert_eq!(1, n.bucket_number(&id));
    }

    #[test]
    fn test_nodetable_pop_oldest() {
        let mut n = KNodeTable::<TestsIdType, net::SocketAddr>::new_with_details(
            test::make_id(42), 2, DEFAULT_HASH_SIZE);
        n.update(&test::new_node(test::make_id(41)));
        n.update(&test::new_node(test::make_id(43)));
        n.update(&test::new_node(test::make_id(40)));
        assert_eq!(0, n.buckets[2].data.len());
        assert_eq!(2, n.buckets[1].data.len());
        assert_eq!(1, n.buckets[0].data.len());
        let nodes = n.pop_oldest();
        assert_eq!(1, nodes.len());
        assert_eq!(test::make_id(41), nodes[0].id);
        assert_eq!(0, n.buckets[2].data.len());
        assert_eq!(1, n.buckets[1].data.len());
        assert_eq!(1, n.buckets[0].data.len());
        assert_eq!(test::make_id(40), n.buckets[1].data[0].id);
    }

    #[test]
    fn test_nodetable_find() {
        let n = KNodeTable {
            buckets: vec![prepare(1), prepare(3), prepare(1)],
            this_id: test::make_id(0),
            hash_size: DEFAULT_HASH_SIZE,
        };
        // 0 xor 3 = 3, 1 xor 3 = 2, 2 xor 3 = 1
        let id = test::make_id(3);
        assert_node_list_eq(&[&n.buckets[1].data[2]],
                            &n.find(&id, 1));
    }

    #[test]
    #[should_panic(expected = "greater than the hash size")]
    fn test_nodetable_find_overflow() {
        let mut id1 = Vec::with_capacity(DEFAULT_HASH_SIZE/8);
        let mut id2 = Vec::with_capacity(DEFAULT_HASH_SIZE/8);
        id1.push(0);
        id2.push(255);
        for _ in 0..(DEFAULT_HASH_SIZE/8) {
            id1.push(0);
            id2.push(0);
        }
        let n = KNodeTable::<_, ()>::new(id1);
        n.find(&id2, 1);
    }

    #[test]
    fn test_nodetable_update() {
        let mut n = KNodeTable::new_with_details(
            test::make_id(42), 1, DEFAULT_HASH_SIZE);
        let node = test::new_node(test::make_id(41));
        n.update(&node);
        assert_eq!(1, n.buckets[1].data.len());
        n.update(&node);
        assert_eq!(1, n.buckets[1].data.len());
    }

    #[test]
    fn test_nodetable_random_id() {
        let n = KNodeTable::<u64, ()>::new_with_details(
            42, 1, DEFAULT_HASH_SIZE);
        for _ in 0..100 {
            assert!(n.random_id().bits() <= DEFAULT_HASH_SIZE);
        }
        assert!(n.random_id() != n.random_id());
    }

    #[test]
    fn test_kbucket_new() {
        let b = KBucket::<TestsIdType, net::SocketAddr>::new(3);
        assert_eq!(0, b.data.len());
        assert_eq!(3, b.size);
    }

    #[test]
    fn test_kbucket_update_unknown() {
        let mut b = prepare(1);
        let node = test::new_node(test::make_id(42));
        assert!(b.update(&node));
        assert_eq!(2, b.data.len());
        assert_eq!(node.id, b.data[1].id);
    }

    #[test]
    fn test_kbucket_update_known() {
        let mut b = prepare(2);
        let node = test::new_node(test::make_id(0));
        assert!(b.update(&node));
        assert_eq!(2, b.data.len());
        assert_eq!(node.id, b.data[1].id);
    }

    #[test]
    fn test_kbucket_update_conflict() {
        let mut b = prepare(3);  // 3 is size
        let node = test::new_node(test::make_id(42));
        assert!(!b.update(&node))
    }

    #[test]
    fn test_kbucket_find() {
        let b = prepare(3);
        // Nodes with ID's 0, 1, 2; assume our ID is also 2 (impossible IRL)
        let id = test::make_id(2);
        // 0 xor 2 = 2, 1 xor 2 = 3, 2 xor 2 = 0
        assert_node_list_eq(&[&b.data[2]], &b.find(&id, 1));
        assert_node_list_eq(&[&b.data[2], &b.data[0]], &b.find(&id, 2));
    }

    #[test]
    fn test_kbucket_find_too_much() {
        let b = prepare(3);
        // Nodes with ID's 0, 1, 2; assume our ID is also 2 (impossible IRL)
        let id = test::make_id(2);
        // 0 xor 2 = 2, 1 xor 2 = 3, 2 xor 2 = 0
        assert_node_list_eq(&[&b.data[2], &b.data[0], &b.data[1]],
                            &b.find(&id, 100));
    }
}
<commit_msg>Make KBucket public, and make KNodeTable return references on them.<commit_after>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// 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.
//

//! DHT node table implementation based on Kademlia.
//!
//! See [original paper](http://pdos.csail.mit.edu/%7Epetar/papers/maymounkov-kademlia-lncs.pdf)
//! for details. The most essential difference is that when k-bucket is full,
//! no RPC call is done. It is up to upper-level code to ensure proper clean up
//! using `pop_oldest` call.

use std::cmp;
use std::fmt::Debug;
use std::collections::VecDeque;

use super::GenericId;
use super::GenericNodeTable;
use super::Node;

// TODO(divius): make public?
static BUCKET_SIZE: usize = 32;
static DEFAULT_HASH_SIZE: usize = 64;

/// Kademlia node table.
///
/// Keeps nodes in a number of k-buckets (equal to bit size of ID in a system,
/// usually 160), where N-th k-bucket contains nodes with distance
/// from 2^N to 2^(N+1) from our node.
///
/// methods may panic if distance between two ids is greater than the
/// `hash_size`.
pub struct KNodeTable<TId, TAddr> {
    this_id: TId,
    hash_size: usize,
    // TODO(divius): convert to more appropriate data structure
    buckets: Vec<KBucket<TId, TAddr>>,
}

/// K-bucket - structure for keeping last nodes in Kademlia.
pub struct KBucket<TId, TAddr> {
    data: VecDeque<Node<TId, TAddr>>,
    size: usize,
}

impl<TId, TAddr> KNodeTable<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug {
    /// Create a new node table.
    ///
    /// `this_id` -- ID of the current node (used to calculate metrics).
    pub fn new(this_id: TId) -> KNodeTable<TId, TAddr> {
        KNodeTable::new_with_details(this_id, BUCKET_SIZE, DEFAULT_HASH_SIZE)
    }

    pub fn new_with_details(this_id: TId, bucket_size: usize,
                    hash_size: usize) -> KNodeTable<TId, TAddr> {
        KNodeTable {
            this_id: this_id,
            hash_size: hash_size,
            buckets: (0..hash_size).map(
                              |_| KBucket::new(bucket_size)).collect(),
        }
    }

    pub fn buckets(&self) -> &Vec<KBucket<TId, TAddr>> {
        &self.buckets
    }

    #[inline]
    fn distance(id1: &TId, id2: &TId) -> TId {
        id1.bitxor(id2)
    }

    fn bucket_number(&self, id: &TId) -> usize {
        let diff = KNodeTable::<TId, TAddr>::distance(&self.this_id, id);
        debug_assert!(!diff.is_zero());
        let res = diff.bits() - 1;
        if res >= self.hash_size {
            panic!(format!("Distance between IDs {:?} and {:?} is {:?}, which is \
                    greater than the hash size ({:?})",
                    id, self.this_id, res, self.hash_size));
        }
        debug!("ID {:?} relative to own ID {:?} falls into bucket {:?}",
               id, self.this_id, res);
        res
    }
}

impl<TId, TAddr> GenericNodeTable<TId, TAddr> for KNodeTable<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug + Sync + Send {
    fn random_id(&self) -> TId {
        TId::gen(self.hash_size)
    }

    fn update(&mut self, node: &Node<TId, TAddr>) -> bool {
        assert!(node.id != self.this_id);
        let bucket = self.bucket_number(&node.id);
        self.buckets[bucket].update(node)
    }

    fn find(&self, id: &TId, count: usize) -> Vec<Node<TId, TAddr>> {
        debug_assert!(count > 0);
        assert!(*id != self.this_id);
        let bucket = self.bucket_number(id);
        self.buckets[bucket].find(id, count)
    }

    fn pop_oldest(&mut self) -> Vec<Node<TId, TAddr>> {
        // For every full k-bucket, pop the last.
        // TODO(divius): TTL expiration?
        self.buckets.iter_mut()
            .filter(|b| { !b.data.is_empty() && b.size == b.data.len() })
            .map(|b| b.data.pop_front().unwrap())
            .collect()
    }
}

impl<TId, TAddr> KBucket<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug {
    pub fn new(k: usize) -> KBucket<TId, TAddr> {
        assert!(k > 0);
        KBucket {
            data: VecDeque::new(),
            size: k
        }
    }

    pub fn update(&mut self, node: &Node<TId, TAddr>) -> bool {
        if self.data.iter().any(|x| x.id == node.id) {
            self.update_position(node.clone());
            debug!("Promoted node {:?} to the top of kbucket", node);
            true
        }
        else if self.data.len() == self.size {
            debug!("Not adding new node {:?} to kbucket - no space left", node);
            false
        }
        else {
            self.data.push_back(node.clone());
            debug!("Added new node {:?} to kbucket", node);
            true
        }
    }

    pub fn find(&self, id: &TId, count: usize) -> Vec<Node<TId, TAddr>> {
        let sort_fn = |a: &Node<TId, TAddr>, b: &Node<TId, TAddr>| {
            KNodeTable::<TId, TAddr>::distance(id, &a.id)
                .cmp(&KNodeTable::<TId, TAddr>::distance(id, &b.id))
        };
        let mut data_copy: Vec<_> = self.data.iter().map(|n| n.clone()).collect();
        data_copy.sort_by(sort_fn);
        data_copy[0..cmp::min(count, data_copy.len())].to_vec()
    }

    pub fn data(&self) -> &VecDeque<Node<TId, TAddr>> {
        &self.data
    }
    pub fn size(&self) -> usize {
        self.size
    }

    fn update_position(&mut self, node: Node<TId, TAddr>) {
        // TODO(divius): 1. optimize, 2. make it less ugly
        let mut new_data = VecDeque::with_capacity(self.data.len());
        new_data.extend(self.data.iter()
                        .filter(|x| x.id != node.id)
                        .map(|x| x.clone()));
        new_data.push_back(node.clone());
        self.data = new_data;
    }
}

#[cfg(test)]
mod test {
    use std::net;

    use super::super::GenericNodeTable;
    use super::super::Node;

    use super::DEFAULT_HASH_SIZE;
    use super::KBucket;
    use super::KNodeTable;

    use super::super::utils::test;
    type TestsIdType = test::IdType;
    use super::super::base::GenericId;

    fn prepare(count: u8) -> KBucket<TestsIdType, net::SocketAddr> {
        KBucket {
            data: (0..count).map(|i| test::new_node(test::make_id(i))).collect(),
            size: 3,
        }
    }

    fn assert_node_list_eq(expected: &[&Node<TestsIdType, net::SocketAddr>], actual: &Vec<Node<TestsIdType, net::SocketAddr>>) {
        let act: Vec<TestsIdType> = actual.iter()
            .map(|n| n.id.clone()).collect();
        let exp: Vec<TestsIdType> = expected.iter()
            .map(|n| n.id.clone()).collect();
        assert_eq!(exp, act);
    }

    #[test]
    fn test_nodetable_new() {
        let n = KNodeTable::<u64, ()>::new(42);
        assert_eq!(DEFAULT_HASH_SIZE, n.buckets.len());
    }

    #[test]
    fn test_nodetable_bucket_number() {
        let n = KNodeTable::<u64, ()>::new(42);
        let id = 41;
        // 42 xor 41 == 3
        assert_eq!(1, n.bucket_number(&id));
    }

    #[test]
    fn test_nodetable_pop_oldest() {
        let mut n = KNodeTable::<TestsIdType, net::SocketAddr>::new_with_details(
            test::make_id(42), 2, DEFAULT_HASH_SIZE);
        let mut lengths = vec![0; n.hash_size];

        n.update(&test::new_node(test::make_id(41)));
        n.update(&test::new_node(test::make_id(43)));
        n.update(&test::new_node(test::make_id(40)));
        lengths[0] = 1;
        lengths[1] = 2;
        assert_eq!(n.buckets().iter().map(|b| b.data.len()).collect::<Vec<_>>(), lengths);

        let nodes = n.pop_oldest();
        assert_eq!(1, nodes.len());
        assert_eq!(test::make_id(41), nodes[0].id);
        lengths[1] = 1;
        assert_eq!(n.buckets().iter().map(|b| b.data.len()).collect::<Vec<_>>(), lengths);
        assert_eq!(test::make_id(40), n.buckets[1].data[0].id);
    }

    #[test]
    fn test_nodetable_find() {
        let n = KNodeTable {
            buckets: vec![prepare(1), prepare(3), prepare(1)],
            this_id: test::make_id(0),
            hash_size: DEFAULT_HASH_SIZE,
        };
        // 0 xor 3 = 3, 1 xor 3 = 2, 2 xor 3 = 1
        let id = test::make_id(3);
        assert_node_list_eq(&[&n.buckets[1].data[2]],
                            &n.find(&id, 1));
    }

    #[test]
    #[should_panic(expected = "greater than the hash size")]
    fn test_nodetable_find_overflow() {
        let mut id1 = Vec::with_capacity(DEFAULT_HASH_SIZE/8);
        let mut id2 = Vec::with_capacity(DEFAULT_HASH_SIZE/8);
        id1.push(0);
        id2.push(255);
        for _ in 0..(DEFAULT_HASH_SIZE/8) {
            id1.push(0);
            id2.push(0);
        }
        let n = KNodeTable::<_, ()>::new(id1);
        n.find(&id2, 1);
    }

    #[test]
    fn test_nodetable_update() {
        let mut n = KNodeTable::new_with_details(
            test::make_id(42), 1, DEFAULT_HASH_SIZE);
        let node = test::new_node(test::make_id(41));
        n.update(&node);
        assert_eq!(1, n.buckets[1].data.len());
        n.update(&node);
        assert_eq!(1, n.buckets[1].data.len());
    }

    #[test]
    fn test_nodetable_random_id() {
        let n = KNodeTable::<u64, ()>::new_with_details(
            42, 1, DEFAULT_HASH_SIZE);
        for _ in 0..100 {
            assert!(n.random_id().bits() <= DEFAULT_HASH_SIZE);
        }
        assert!(n.random_id() != n.random_id());
    }

    #[test]
    fn test_kbucket_new() {
        let b = KBucket::<TestsIdType, net::SocketAddr>::new(3);
        assert_eq!(0, b.data.len());
        assert_eq!(3, b.size);
    }

    #[test]
    fn test_kbucket_update_unknown() {
        let mut b = prepare(1);
        let node = test::new_node(test::make_id(42));
        assert!(b.update(&node));
        assert_eq!(2, b.data.len());
        assert_eq!(node.id, b.data[1].id);
    }

    #[test]
    fn test_kbucket_update_known() {
        let mut b = prepare(2);
        let node = test::new_node(test::make_id(0));
        assert!(b.update(&node));
        assert_eq!(2, b.data.len());
        assert_eq!(node.id, b.data[1].id);
    }

    #[test]
    fn test_kbucket_update_conflict() {
        let mut b = prepare(3);  // 3 is size
        let node = test::new_node(test::make_id(42));
        assert!(!b.update(&node))
    }

    #[test]
    fn test_kbucket_find() {
        let b = prepare(3);
        // Nodes with ID's 0, 1, 2; assume our ID is also 2 (impossible IRL)
        let id = test::make_id(2);
        // 0 xor 2 = 2, 1 xor 2 = 3, 2 xor 2 = 0
        assert_node_list_eq(&[&b.data[2]], &b.find(&id, 1));
        assert_node_list_eq(&[&b.data[2], &b.data[0]], &b.find(&id, 2));
    }

    #[test]
    fn test_kbucket_find_too_much() {
        let b = prepare(3);
        // Nodes with ID's 0, 1, 2; assume our ID is also 2 (impossible IRL)
        let id = test::make_id(2);
        // 0 xor 2 = 2, 1 xor 2 = 3, 2 xor 2 = 0
        assert_node_list_eq(&[&b.data[2], &b.data[0], &b.data[1]],
                            &b.find(&id, 100));
    }
}
<|endoftext|>