<commit_before>// Copyright 2015-2016 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.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate cargo_metadata;
extern crate getopts;
extern crate serde_json as json;

use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

use getopts::{Matches, Options};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "version", "print rustfmt version and exit");
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    let mut is_package_arg = false;
    for arg in env::args().skip(2).take_while(|a| a != "--") {
        if arg.starts_with('-') {
            is_package_arg = arg.starts_with("--package");
        } else if !is_package_arg {
            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
            return FAILURE;
        } else {
            is_package_arg = false;
        }
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return FAILURE;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return SUCCESS;
    }

    if matches.opt_present("version") {
        return handle_command_status(get_version(verbosity), &opts);
    }

    let strategy = CargoFmtStrategy::from_matches(&matches);
    handle_command_status(format_crate(verbosity, &strategy), &opts)
}

macro_rules! print_usage {
    ($print:ident, $opts:ident, $reason:expr) => {{
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    }};
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<i32, io::Error>, opts: &getopts::Options) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(opts, &e.to_string());
            FAILURE
        }
        Ok(status) => status,
    }
}

fn get_version(verbosity: Verbosity) -> Result<i32, io::Error> {
    run_rustfmt(&HashSet::new(), &[String::from("--version")], verbosity)
}

fn format_crate(verbosity: Verbosity, strategy: &CargoFmtStrategy) -> Result<i32, io::Error> {
    let rustfmt_args = get_fmt_args();
    let targets = if rustfmt_args
        .iter()
        .any(|s| ["--print-config", "-h", "--help", "-V", "--version"].contains(&s.as_str()))
    {
        HashSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted
    run_rustfmt(&targets, &rustfmt_args, verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g. lib, bin, example, ...).
    kind: String,
    /// Rust edition for this target.
    edition: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
            edition: target.edition.clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format packages that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<HashSet<Target>, io::Error> {
    let mut targets = HashSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut HashSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut HashSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;
    let current_dir = env::current_dir()?.canonicalize()?;
    let current_dir_manifest = current_dir.join("Cargo.toml");
    let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
    let in_workspace_root = workspace_root_path == current_dir;

    for package in metadata.packages {
        if in_workspace_root || PathBuf::from(&package.manifest_path) == current_dir_manifest {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut HashSet<Target>,
    visited: &mut HashSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut HashSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: HashSet<&String> = HashSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut HashSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn run_rustfmt(
    targets: &HashSet<Target>,
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<i32, io::Error> {
    let by_edition: HashMap<_, _> = targets
        .iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{} ({})] {:?}", t.kind, t.edition, t.path)
            }
        })
        .map(|t| (&t.edition, vec![&t.path]))
        .collect();

    for (edition, files) in by_edition {
        let stdout = if verbosity == Verbosity::Quiet {
            std::process::Stdio::null()
        } else {
            std::process::Stdio::inherit()
        };

        if verbosity == Verbosity::Verbose {
            print!("rustfmt");
            print!(" --edition {}", edition);
            fmt_args.iter().for_each(|f| print!(" {}", f));
            files.iter().for_each(|f| print!(" {}", f.display()));
            println!();
        }

        let mut command = Command::new("rustfmt")
            .stdout(stdout)
            .args(files)
            .args(&["--edition", edition])
            .args(fmt_args)
            .spawn()
            .map_err(|e| match e.kind() {
                io::ErrorKind::NotFound => io::Error::new(
                    io::ErrorKind::Other,
                    "Could not run rustfmt, please make sure it is in your PATH.",
                ),
                _ => e,
            })?;

        let status = command.wait()?;
        if !status.success() {
            return Ok(status.code().unwrap_or(FAILURE));
        }
    }

    Ok(SUCCESS)
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    match cargo_metadata::metadata(manifest_path) {
        Ok(metadata) => Ok(metadata),
        Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())),
    }
}
<commit_msg>cargo-fmt: Fix splitting of targets across editions<commit_after>// Copyright 2015-2016 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.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate cargo_metadata;
extern crate getopts;
extern crate serde_json as json;

use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

use getopts::{Matches, Options};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "version", "print rustfmt version and exit");
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    let mut is_package_arg = false;
    for arg in env::args().skip(2).take_while(|a| a != "--") {
        if arg.starts_with('-') {
            is_package_arg = arg.starts_with("--package");
        } else if !is_package_arg {
            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
            return FAILURE;
        } else {
            is_package_arg = false;
        }
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return FAILURE;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return SUCCESS;
    }

    if matches.opt_present("version") {
        return handle_command_status(get_version(verbosity), &opts);
    }

    let strategy = CargoFmtStrategy::from_matches(&matches);
    handle_command_status(format_crate(verbosity, &strategy), &opts)
}

macro_rules! print_usage {
    ($print:ident, $opts:ident, $reason:expr) => {{
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    }};
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<i32, io::Error>, opts: &getopts::Options) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(opts, &e.to_string());
            FAILURE
        }
        Ok(status) => status,
    }
}

fn get_version(verbosity: Verbosity) -> Result<i32, io::Error> {
    run_rustfmt(&HashSet::new(), &[String::from("--version")], verbosity)
}

fn format_crate(verbosity: Verbosity, strategy: &CargoFmtStrategy) -> Result<i32, io::Error> {
    let rustfmt_args = get_fmt_args();
    let targets = if rustfmt_args
        .iter()
        .any(|s| ["--print-config", "-h", "--help", "-V", "--version"].contains(&s.as_str()))
    {
        HashSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted
    run_rustfmt(&targets, &rustfmt_args, verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g. lib, bin, example, ...).
    kind: String,
    /// Rust edition for this target.
    edition: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
            edition: target.edition.clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format packages that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<HashSet<Target>, io::Error> {
    let mut targets = HashSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut HashSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut HashSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;
    let current_dir = env::current_dir()?.canonicalize()?;
    let current_dir_manifest = current_dir.join("Cargo.toml");
    let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
    let in_workspace_root = workspace_root_path == current_dir;

    for package in metadata.packages {
        if in_workspace_root || PathBuf::from(&package.manifest_path) == current_dir_manifest {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut HashSet<Target>,
    visited: &mut HashSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut HashSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: HashSet<&String> = HashSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut HashSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn run_rustfmt(
    targets: &HashSet<Target>,
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<i32, io::Error> {
    let by_edition = targets
        .iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{} ({})] {:?}", t.kind, t.edition, t.path)
            }
        })
        .map(|t| (&t.edition, &t.path))
        .fold(HashMap::new(), |mut h, t| {
            h.entry(t.0).or_insert_with(Vec::new).push(t.1);
            h
        });

    for (edition, files) in by_edition {
        let stdout = if verbosity == Verbosity::Quiet {
            std::process::Stdio::null()
        } else {
            std::process::Stdio::inherit()
        };

        if verbosity == Verbosity::Verbose {
            print!("rustfmt");
            print!(" --edition {}", edition);
            fmt_args.iter().for_each(|f| print!(" {}", f));
            files.iter().for_each(|f| print!(" {}", f.display()));
            println!();
        }

        let mut command = Command::new("rustfmt")
            .stdout(stdout)
            .args(files)
            .args(&["--edition", edition])
            .args(fmt_args)
            .spawn()
            .map_err(|e| match e.kind() {
                io::ErrorKind::NotFound => io::Error::new(
                    io::ErrorKind::Other,
                    "Could not run rustfmt, please make sure it is in your PATH.",
                ),
                _ => e,
            })?;

        let status = command.wait()?;
        if !status.success() {
            return Ok(status.code().unwrap_or(FAILURE));
        }
    }

    Ok(SUCCESS)
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    match cargo_metadata::metadata(manifest_path) {
        Ok(metadata) => Ok(metadata),
        Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())),
    }
}
<|endoftext|>


<commit_before>extern crate orbital;

pub use std::collections::VecDeque;

mod editor;
pub use self::editor::*;

mod parse;
pub use self::parse::*;

mod key_state;
pub use self::key_state::*;

mod key;
pub use self::key::*;

mod prompt;
pub use self::prompt::*;

mod open;
pub use self::open::*;

mod redraw;
pub use self::redraw::*;

mod options;
pub use self::options::*;

mod position;
pub use self::position::*;

mod graphics;
pub use self::graphics::*;

mod selection;
pub use self::selection::*;

mod mode;
pub use self::mode::*;

mod movement;
pub use self::movement::*;

mod motion;
pub use self::motion::*;

mod cursor;
pub use self::cursor::*;

mod insert;
pub use self::insert::*;

mod delete;
pub use self::delete::*;

mod exec;
pub use self::exec::*;

pub mod invert;

fn main() {
    Editor::init();
}
<commit_msg>Fix compilation, login program is broken though<commit_after>extern crate orbital;

pub use std::collections::VecDeque;

mod editor;
pub use self::editor::*;

mod parse;
pub use self::parse::*;

mod key_state;
pub use self::key_state::*;

mod key;
pub use self::key::*;

mod prompt;
pub use self::prompt::*;

mod open;
pub use self::open::*;

mod redraw;
pub use self::redraw::*;

mod options;
pub use self::options::*;

mod position;
pub use self::position::*;

mod graphics;
pub use self::graphics::*;

mod selection;
pub use self::selection::*;

mod mode;
pub use self::mode::*;

mod movement;
pub use self::movement::*;

mod motion;
pub use self::motion::*;

mod cursor;
pub use self::cursor::*;

mod insert;
pub use self::insert::*;

mod delete;
pub use self::delete::*;

mod exec;
pub use self::exec::*;

pub mod invert;

#[no_mangle] pub fn main() {
    Editor::init();
}
<|endoftext|>


<commit_before>use redox::*;

#[derive(Copy, Clone)]
pub enum Mode {
    Insert,
    Normal,
}

pub struct Editor {
    url: String,
    file: Option<File>,
    string: String,
    offset: usize,
    scroll_x: isize,
    scroll_y: isize,
}

impl Editor {
    #[inline(never)]
    pub fn new() -> Self {
        Editor {
            url: String::new(),
            file: Option::None,
            string: String::new(),
            offset: 0,
            scroll_x: 0,
            scroll_y: 0,
        }
    }

    fn backspace(&mut self, window: &mut Window) {
         if self.offset > 0 {
             window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
             self.string = self.string[0 .. self.offset - 1].to_string() +
                 &self.string[self.offset .. self.string.len()];
             self.offset -= 1;
         }
    }

    fn delete(&mut self, window: &mut Window) {
        if self.offset < self.string.len() {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset + 1].to_string() +
                &self.string[self.offset + 1 .. self.string.len() - 1];
        }
    }

    fn up(&mut self) {
        let mut new_offset = 0;
        for i in 2..self.offset {
            match self.string.as_bytes()[self.offset - i] {
                0 => break,
                10 => {
                    new_offset = self.offset - i + 1;
                    break;
                }
                _ => (),
            }
        }
        self.offset = new_offset;
    }

    fn left(&mut self) {
        if self.offset > 0 {
            self.offset -= 1;
        }
    }

    fn right(&mut self) {
        if self.offset < self.string.len() {
            self.offset += 1;
        }
    }

    fn down(&mut self) {
        let mut new_offset = self.string.len();
        for i in self.offset..self.string.len() {
            match self.string.as_bytes()[i] {
                0 => break,
                10 => {
                    new_offset = i + 1;
                    break;
                }
                _ => (),
            }
        }
        self.offset = new_offset;
    }

    fn reload(&mut self, window: &mut Window) {
        window.set_title(&("Editor (".to_string() + &self.url + ")"));
        self.offset = 0;
        self.scroll_x = 0;
        self.scroll_y = 0;

        match self.file {
            Option::Some(ref mut file) => {
                file.seek(Seek::Start(0));
                let mut vec: Vec<u8> = Vec::new();
                file.read_to_end(&mut vec);
                self.string = unsafe { String::from_utf8_unchecked(vec) };
            },
            Option::None => self.string = String::new(),
        }
    }

    fn save(&mut self, window: &mut Window) {
        match self.file {
            Option::Some(ref mut file) => {
                window.set_title(&("Editor (".to_string() + &self.url + ") Saved"));
                file.seek(Seek::Start(0));
                file.write(&self.string.as_bytes());
                file.sync();
            }
            Option::None => {
                //TODO: Ask for file to save to
                window.set_title(&("Editor (".to_string() + &self.url + ") No Open File"));
            }
        }
    }

    fn draw_content(&mut self, window: &mut Window) {
        let mut redraw = false;

        {
            window.set([255, 255, 255, 255]);

            let scroll_x = self.scroll_x;
            let scroll_y = self.scroll_y;

            let mut offset = 0;

            let mut col = -scroll_x;
            let cols = window.width() as isize / 8;

            let mut row = -scroll_y;
            let rows = window.height() as isize / 16;

            for c in self.string.chars() {
                if offset == self.offset {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, '_', [128, 128, 128, 255]);
                    } else {
                        if col < 0 { //Too far to the left
                            self.scroll_x += col;
                        } else if col >= cols { //Too far to the right
                            self.scroll_x += cols - col + 1;
                        }
                        if row < 0 { //Too far up
                            self.scroll_y += row;
                        } else if row >= rows { //Too far down
                            self.scroll_y += rows - row + 1;
                        }

                        redraw = true;
                    }
                }

                if c == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, c, [0, 0, 0, 255]);
                    }
                    col += 1;
                }

                offset += 1;
            }

            if offset == self.offset {
                if col >= 0 && col < cols && row >= 0 && row < rows {
                    window.char(8 * col, 16 * row, '_', [128, 128, 128, 255]);
                } else {
                    if col < 0 { //Too far to the left
                        self.scroll_x += col;
                    } else if col >= cols { //Too far to the right
                        self.scroll_x += cols - col + 1;
                    }
                    if row < 0 { //Too far up
                        self.scroll_y += row;
                    } else if row >= rows { //Too far down
                        self.scroll_y += rows - row + 1;
                    }

                    redraw = true;
                }
            }

            window.sync();
        }

        if redraw {
            self.draw_content(window);
        }
    }

    fn main(&mut self, url: &str) {
        let mut window = Window::new((rand() % 400 + 50) as isize,
                                     (rand() % 300 + 50) as isize,
                                     576,
                                     400,
                                      &("Editor (".to_string() + url + ")"));

        self.url = url.to_string();
        self.file = Option::Some(File::open(&self.url));

        self.reload(&mut window);
        self.draw_content(&mut window);

        let mut mode = Mode::Normal;

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        use self::Mode::*;
                        match (mode, key_event.scancode) {
                            (Insert, K_ESC) => mode = Normal,
                            (Insert, K_BKSP) => self.backspace(&mut window),
                            (Insert, K_DEL) => self.delete(&mut window),
                            (_, K_F5) => self.reload(&mut window),
                            (_, K_F6) => self.save(&mut window),
                            (_, K_HOME) => self.offset = 0,
                            (_, K_UP) => self.up(),
                            (_, K_LEFT) => self.left(),
                            (_, K_RIGHT) => self.right(),
                            (_, K_END) => self.offset = self.string.len(),
                            (_, K_DOWN) => self.down(),
                            (m, _) => match (m, key_event.character) {
                                (Normal, 'i') => mode = Insert,
                                (Normal, 'h') => self.left(),
                                (Normal, 'l') => self.right(),
                                (Normal, 'k') => self.up(),
                                (Normal, 'j') => self.down(),
                                (Normal, 'G') => self.offset = self.string.len(),
                                (Normal, 'a') => {
                                    self.right();
                                    mode = Insert;
                                },
                                (Normal, 'x') => self.delete(&mut window),
                                (Normal, 'X') => self.backspace(&mut window),
                                (Insert, '\0') => (),
                                (Insert, _) => {
                                    window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
                                    self.string = self.string[0 .. self.offset].to_string() +
                                                  &key_event.character.to_string() +
                                                  &self.string[self.offset .. self.string.len()];
                                    self.offset += 1;
                                },
                                _ => {},
                            }
                        }

                        self.draw_content(&mut window);
                    }
                }
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Option::Some(arg) => Editor::new().main(&arg),
        Option::None => Editor::new().main("none://"),
    }
}
<commit_msg>Add undo functionality to the editor<commit_after>use redox::*;

#[derive(Copy, Clone)]
pub enum Mode {
    Insert,
    Normal,
}

pub struct Editor {
    url: String,
    file: Option<File>,
    string: String,
    offset: usize,
    scroll_x: isize,
    scroll_y: isize,
}

impl Editor {
    #[inline(never)]
    pub fn new() -> Self {
        Editor {
            url: String::new(),
            file: Option::None,
            string: String::new(),
            offset: 0,
            scroll_x: 0,
            scroll_y: 0,
        }
    }

    fn backspace(&mut self, window: &mut Window) {
         if self.offset > 0 {
             window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
             self.string = self.string[0 .. self.offset - 1].to_string() +
                 &self.string[self.offset .. self.string.len()];
             self.offset -= 1;
         }
    }

    fn delete(&mut self, window: &mut Window) {
        if self.offset < self.string.len() {
            window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
            self.string = self.string[0 .. self.offset + 1].to_string() +
                &self.string[self.offset + 1 .. self.string.len() - 1];
        }
    }

    fn up(&mut self) {
        let mut new_offset = 0;
        for i in 2..self.offset {
            match self.string.as_bytes()[self.offset - i] {
                0 => break,
                10 => {
                    new_offset = self.offset - i + 1;
                    break;
                }
                _ => (),
            }
        }
        self.offset = new_offset;
    }

    fn left(&mut self) {
        if self.offset > 0 {
            self.offset -= 1;
        }
    }

    fn right(&mut self) {
        if self.offset < self.string.len() {
            self.offset += 1;
        }
    }

    fn down(&mut self) {
        let mut new_offset = self.string.len();
        for i in self.offset..self.string.len() {
            match self.string.as_bytes()[i] {
                0 => break,
                10 => {
                    new_offset = i + 1;
                    break;
                }
                _ => (),
            }
        }
        self.offset = new_offset;
    }

    fn reload(&mut self, window: &mut Window) {
        window.set_title(&("Editor (".to_string() + &self.url + ")"));
        self.offset = 0;
        self.scroll_x = 0;
        self.scroll_y = 0;

        match self.file {
            Option::Some(ref mut file) => {
                file.seek(Seek::Start(0));
                let mut vec: Vec<u8> = Vec::new();
                file.read_to_end(&mut vec);
                self.string = unsafe { String::from_utf8_unchecked(vec) };
            },
            Option::None => self.string = String::new(),
        }
    }

    fn save(&mut self, window: &mut Window) {
        match self.file {
            Option::Some(ref mut file) => {
                window.set_title(&("Editor (".to_string() + &self.url + ") Saved"));
                file.seek(Seek::Start(0));
                file.write(&self.string.as_bytes());
                file.sync();
            }
            Option::None => {
                //TODO: Ask for file to save to
                window.set_title(&("Editor (".to_string() + &self.url + ") No Open File"));
            }
        }
    }

    fn draw_content(&mut self, window: &mut Window) {
        let mut redraw = false;

        {
            window.set([255, 255, 255, 255]);

            let scroll_x = self.scroll_x;
            let scroll_y = self.scroll_y;

            let mut offset = 0;

            let mut col = -scroll_x;
            let cols = window.width() as isize / 8;

            let mut row = -scroll_y;
            let rows = window.height() as isize / 16;

            for c in self.string.chars() {
                if offset == self.offset {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, '_', [128, 128, 128, 255]);
                    } else {
                        if col < 0 { //Too far to the left
                            self.scroll_x += col;
                        } else if col >= cols { //Too far to the right
                            self.scroll_x += cols - col + 1;
                        }
                        if row < 0 { //Too far up
                            self.scroll_y += row;
                        } else if row >= rows { //Too far down
                            self.scroll_y += rows - row + 1;
                        }

                        redraw = true;
                    }
                }

                if c == '\n' {
                    col = -scroll_x;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col >= 0 && col < cols && row >= 0 && row < rows {
                        window.char(8 * col, 16 * row, c, [0, 0, 0, 255]);
                    }
                    col += 1;
                }

                offset += 1;
            }

            if offset == self.offset {
                if col >= 0 && col < cols && row >= 0 && row < rows {
                    window.char(8 * col, 16 * row, '_', [128, 128, 128, 255]);
                } else {
                    if col < 0 { //Too far to the left
                        self.scroll_x += col;
                    } else if col >= cols { //Too far to the right
                        self.scroll_x += cols - col + 1;
                    }
                    if row < 0 { //Too far up
                        self.scroll_y += row;
                    } else if row >= rows { //Too far down
                        self.scroll_y += rows - row + 1;
                    }

                    redraw = true;
                }
            }

            window.sync();
        }

        if redraw {
            self.draw_content(window);
        }
    }

    fn main(&mut self, url: &str) {
        let mut window = Window::new((rand() % 400 + 50) as isize,
                                     (rand() % 300 + 50) as isize,
                                     576,
                                     400,
                                      &("Editor (".to_string() + url + ")"));

        self.url = url.to_string();
        self.file = Option::Some(File::open(&self.url));

        self.reload(&mut window);
        self.draw_content(&mut window);

        let mut mode = Mode::Normal;

        let mut last_change = String::new();

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        use self::Mode::*;
                        match (mode, key_event.scancode) {
                            (Insert, K_ESC) => {
                                mode = Normal;
                            },
                            (Insert, K_BKSP) => self.backspace(&mut window),
                            (Insert, K_DEL) => self.delete(&mut window),
                            (_, K_F5) => self.reload(&mut window),
                            (_, K_F6) => self.save(&mut window),
                            (_, K_HOME) => self.offset = 0,
                            (_, K_UP) => self.up(),
                            (_, K_LEFT) => self.left(),
                            (_, K_RIGHT) => self.right(),
                            (_, K_END) => self.offset = self.string.len(),
                            (_, K_DOWN) => self.down(),
                            (m, _) => match (m, key_event.character) {
                                (Normal, 'i') => {
                                    mode = Insert;
                                    last_change = self.string.clone();
                                },
                                (Normal, 'h') => self.left(),
                                (Normal, 'l') => self.right(),
                                (Normal, 'k') => self.up(),
                                (Normal, 'j') => self.down(),
                                (Normal, 'G') => self.offset = self.string.len(),
                                (Normal, 'a') => {
                                    self.right();
                                    mode = Insert;
                                    last_change = self.string.clone();
                                },
                                (Normal, 'x') => self.delete(&mut window),
                                (Normal, 'X') => self.backspace(&mut window),
                                (Normal, 'u') => {
                                    ::core::mem::swap(&mut last_change, &mut self.string);
                                },
                                (Insert, '\0') => (),
                                (Insert, _) => {
                                    window.set_title(&format!("{}{}{}","Editor (", &self.url, ") Changed"));
                                    self.string = self.string[0 .. self.offset].to_string() +
                                                  &key_event.character.to_string() +
                                                  &self.string[self.offset .. self.string.len()];
                                    self.offset += 1;
                                },
                                _ => {},
                            }
                        }

                        self.draw_content(&mut window);
                    }
                }
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Option::Some(arg) => Editor::new().main(&arg),
        Option::None => Editor::new().main("none://"),
    }
}
<|endoftext|>


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

// A Node reference is a direct index to an element of the pool.
type NodeRef = u32;

/// A B-tree data structure which nodes are allocated from a pool.
pub struct BTree<K, V> {
    index: NodeRef,
    unused1: PhantomData<K>,
    unused2: PhantomData<V>,
}

/// An enum representing a B-tree node.
/// Keys and values are required to implement Default.
enum Node<K, V> {
    Inner {
        size: u8,
        keys: [K; 7],
        nodes: [NodeRef; 8],
    },
    Leaf {
        size: u8,
        keys: [K; 7],
        values: [V; 7],
    },
}

/// Memory pool for nodes.
struct NodePool<K, V> {
    // The array containing the nodes.
    data: Vec<Node<K, V>>,

    // A free list
    freelist: Vec<NodeRef>,
}

impl<K: Default, V: Default> NodePool<K, V> {
    /// Create a new NodePool.
    pub fn new() -> NodePool<K, V> {
        NodePool {
            data: Vec::new(),
            freelist: Vec::new(),
        }
    }

    /// Get a B-tree node.
    pub fn get(&self, index: u32) -> Option<&Node<K, V>> {
        unimplemented!()
    }
}

impl<K: Default, V: Default> BTree<K, V> {
    /// Search for `key` and return a `Cursor` that either points at `key` or the position where it would be inserted.
    pub fn search(&mut self, key: K) -> Cursor<K, V> {
        unimplemented!()
    }
}

pub struct Cursor<'a, K: 'a, V: 'a> {
    pool: &'a mut NodePool<K, V>,
    height: usize,
    path: [(NodeRef, u8); 16],
}

impl<'a, K: Default, V: Default> Cursor<'a, K, V> {
    /// The key at the cursor position. Returns `None` when the cursor points off the end.
    pub fn key(&self) -> Option<K> {
        unimplemented!()
    }

    /// The value at the cursor position. Returns `None` when the cursor points off the end.
    pub fn value(&self) -> Option<&V> {
        unimplemented!()
    }

    /// Move to the next element.
    /// Returns `false` if that moves the cursor off the end.
    pub fn next(&mut self) -> bool {
        unimplemented!()
    }

    /// Move to the previous element.
    /// Returns `false` if this moves the cursor before the beginning.
    pub fn prev(&mut self) -> bool {
        unimplemented!()
    }

    /// Insert a `(key, value)` pair at the cursor position.
    /// It is an error to insert a key that would be out of order at this position.
    pub fn insert(&mut self, key: K, value: V) {
        unimplemented!()
    }

    /// Remove the current element.
    pub fn remove(&mut self) {
        unimplemented!()
    }
}
<commit_msg>[B-tree] Initial comment to describe the design choices.<commit_after>//! Generic B-Tree implementation.
//!
//! This module defines a `Btree<K, V>` type which provides similar functionality to
//! `BtreeMap<K, V>`, but with some important differences in the implementation:
//!
//! 1. Memory is allocated from a `NodePool<K, V>` instead of the global heap.
//! 2. The footprint of a BTree is only 4 bytes.
//! 3. A BTree doesn't implement `Drop`, leaving it to the pool to manage memory.
//!
//! The node pool is intended to be used as a LIFO allocator. After building up a larger data
//! structure with many list references, the whole thing can be discarded quickly by clearing the
//! pool.

use std::marker::PhantomData;

// A Node reference is a direct index to an element of the pool.
type NodeRef = u32;

/// A B-tree data structure which nodes are allocated from a pool.
pub struct BTree<K, V> {
    index: NodeRef,
    unused1: PhantomData<K>,
    unused2: PhantomData<V>,
}

/// An enum representing a B-tree node.
/// Keys and values are required to implement Default.
enum Node<K, V> {
    Inner {
        size: u8,
        keys: [K; 7],
        nodes: [NodeRef; 8],
    },
    Leaf {
        size: u8,
        keys: [K; 7],
        values: [V; 7],
    },
}

/// Memory pool for nodes.
struct NodePool<K, V> {
    // The array containing the nodes.
    data: Vec<Node<K, V>>,

    // A free list
    freelist: Vec<NodeRef>,
}

impl<K: Default, V: Default> NodePool<K, V> {
    /// Create a new NodePool.
    pub fn new() -> NodePool<K, V> {
        NodePool {
            data: Vec::new(),
            freelist: Vec::new(),
        }
    }

    /// Get a B-tree node.
    pub fn get(&self, index: u32) -> Option<&Node<K, V>> {
        unimplemented!()
    }
}

impl<K: Default, V: Default> BTree<K, V> {
    /// Search for `key` and return a `Cursor` that either points at `key` or the position where it would be inserted.
    pub fn search(&mut self, key: K) -> Cursor<K, V> {
        unimplemented!()
    }
}

pub struct Cursor<'a, K: 'a, V: 'a> {
    pool: &'a mut NodePool<K, V>,
    height: usize,
    path: [(NodeRef, u8); 16],
}

impl<'a, K: Default, V: Default> Cursor<'a, K, V> {
    /// The key at the cursor position. Returns `None` when the cursor points off the end.
    pub fn key(&self) -> Option<K> {
        unimplemented!()
    }

    /// The value at the cursor position. Returns `None` when the cursor points off the end.
    pub fn value(&self) -> Option<&V> {
        unimplemented!()
    }

    /// Move to the next element.
    /// Returns `false` if that moves the cursor off the end.
    pub fn next(&mut self) -> bool {
        unimplemented!()
    }

    /// Move to the previous element.
    /// Returns `false` if this moves the cursor before the beginning.
    pub fn prev(&mut self) -> bool {
        unimplemented!()
    }

    /// Insert a `(key, value)` pair at the cursor position.
    /// It is an error to insert a key that would be out of order at this position.
    pub fn insert(&mut self, key: K, value: V) {
        unimplemented!()
    }

    /// Remove the current element.
    pub fn remove(&mut self) {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>use position::Position;
use cppn::{Cppn, CppnNodeType};
use acyclic_network::NodeType;
use std::fmt::Debug;

/// Represents a node in the substrate. `T` stores additional information about that node.

pub struct Node<P, T>
    where P: Position,
          T: NodeType
{
    pub position: P,
    pub node_type: T,
}

pub struct Substrate<P, T>
    where P: Position,
          T: NodeType
{
    nodes: Vec<Node<P, T>>,
}

#[derive(Clone)]
pub struct Link<'a, P, T>
    where P: Position + 'a,
          T: NodeType + 'a
{
    pub source: &'a Node<P, T>,
    pub target: &'a Node<P, T>,
    pub source_idx: usize,
    pub target_idx: usize,
    pub outputs: Vec<f64>,
    pub distance: f64,
}

pub enum LinkMode {
    AbsolutePositions,
    AbsolutePositionsAndDistance,
    RelativePositionOfTarget,
}

impl<P, T> Substrate<P, T>
    where P: Position,
          T: NodeType
{
    pub fn new() -> Self {
        Substrate { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<P, T>] {
        &self.nodes
    }

    pub fn add_node(&mut self, position: P, node_type: T) {
        self.nodes.push(Node {
            position: position,
            node_type: node_type,
        });
    }

    /// Iterate over all produced links of Cppn.

    pub fn each_link<'a, N, L, EXTID, F>(&'a self,
                                         cppn: &'a mut Cppn<'a, N, L, EXTID>,
                                         max_distance: Option<f64>,
                                         mode: LinkMode,
                                         callback: &mut F)
        where N: CppnNodeType,
              L: Copy + Debug + Send + Sized + Into<f64> + 'a,
              EXTID: Copy + Debug + Send + Sized + Ord + 'a,
              F: FnMut(Link<'a, P, T>)
    {
        for (source_idx, source) in self.nodes.iter().enumerate() {
            // Reject invalid connections.
            if !source.node_type.accept_outgoing_links() {
                continue;
            }

            for (target_idx, target) in self.nodes.iter().enumerate() {
                // Reject invalid connections.
                if !target.node_type.accept_incoming_links() {
                    continue;
                }

                let distance = source.position.distance(&target.position);

                // reject a pair of nodes based on `max_distance`.
                if let Some(max_d) = max_distance {
                    if distance > max_d {
                        continue;
                    }
                }

                // Calculate the weight between source and target using the CPPN.

                let outputs_from_cppn = match mode {
                    LinkMode::AbsolutePositions => {
                        let inputs_to_cppn = [source.position.coords(), target.position.coords()];
                        cppn.calculate(&inputs_to_cppn)
                    }
                    LinkMode::AbsolutePositionsAndDistance => {
                        let distance_between: &[_] = &[distance];
                        let inputs_to_cppn = [source.position.coords(),
                                              target.position.coords(),
                                              distance_between];
                        cppn.calculate(&inputs_to_cppn)
                    }
                    LinkMode::RelativePositionOfTarget => {
                        let relative_position_of_target =
                            source.position.relative_position(&target.position);
                        let inputs_to_cppn = [source.position.coords(),
                                              relative_position_of_target.coords()];
                        cppn.calculate(&inputs_to_cppn)
                    }
                };

                let link = Link {
                    source: source,
                    target: target,
                    source_idx: source_idx,
                    target_idx: target_idx,
                    outputs: outputs_from_cppn,
                    distance: distance,
                };
                callback(link);
            }
        }
    }
}
<commit_msg>Introduce Layers<commit_after>use position::Position;
use cppn::{Cppn, CppnNodeType};
use acyclic_network::NodeType;
use std::fmt::Debug;

/// Represents a node in the substrate. `T` stores additional information about that node.
#[derive(Clone, Debug)]
pub struct Node<P, T>
    where P: Position,
          T: NodeType
{
    pub position: P,
    pub node_type: T,
}

#[derive(Clone, Debug)]
pub struct Layer<P, T>
    where P: Position,
          T: NodeType
{
    nodes: Vec<Node<P, T>>,
}

impl<P, T> Layer<P, T>
    where P: Position,
          T: NodeType
{
    pub fn new() -> Self {
        Layer { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<P, T>] {
        &self.nodes
    }

    pub fn add_node(&mut self, position: P, node_type: T) {
        self.nodes.push(Node {
            position: position,
            node_type: node_type,
        });
    }
}

#[derive(Clone)]
pub struct Link<'a, P, T>
    where P: Position + 'a,
          T: NodeType + 'a
{
    pub source: &'a Node<P, T>,
    pub target: &'a Node<P, T>,
    pub source_idx: usize,
    pub target_idx: usize,
    pub outputs: Vec<f64>,
    pub distance: f64,
}

#[derive(Clone, Debug)]
pub enum LinkMode {
    AbsolutePositions,
    AbsolutePositionsAndDistance,
    RelativePositionOfTarget,
}

#[derive(Clone, Debug)]
struct LayerLink {
    from_layer: usize,
    to_layer: usize,
    max_distance: Option<f64>,
}

#[derive(Clone, Debug)]
pub struct Substrate<P, T>
    where P: Position,
          T: NodeType
{
    layers: Vec<Layer<P, T>>,
    layer_links: Vec<LayerLink>,
}

impl<P, T> Substrate<P, T>
    where P: Position,
          T: NodeType
{
    pub fn new() -> Self {
        Substrate {
            layers: Vec::new(),
            layer_links: Vec::new(),
        }
    }

    pub fn layers(&self) -> &[Layer<P, T>] {
        &self.layers
    }

    pub fn add_layer(&mut self, layer: Layer<P, T>) -> usize {
        let layer_idx = self.layers.len();
        self.layers.push(layer);
        return layer_idx;
    }

    pub fn add_layer_link(&mut self,
                          from_layer: usize,
                          to_layer: usize,
                          max_distance: Option<f64>) {
        self.layer_links.push(LayerLink {
            from_layer: from_layer,
            to_layer: to_layer,
            max_distance: max_distance,
        });
    }

    /// Iterate over all produced links of Cppn.

    pub fn each_link<'a, N, L, EXTID, F>(&'a self,
                                         cppn: &'a mut Cppn<'a, N, L, EXTID>,
                                         mode: LinkMode,
                                         callback: &mut F)
        where N: CppnNodeType,
              L: Copy + Debug + Send + Sized + Into<f64> + 'a,
              EXTID: Copy + Debug + Send + Sized + Ord + 'a,
              F: FnMut(Link<'a, P, T>)
    {
        for layer_link in self.layer_links.iter() {
            for (source_idx, source) in self.layers[layer_link.from_layer]
                                            .nodes
                                            .iter()
                                            .enumerate() {
                // Reject invalid connections.
                if !source.node_type.accept_outgoing_links() {
                    continue;
                }

                for (target_idx, target) in self.layers[layer_link.to_layer]
                                                .nodes
                                                .iter()
                                                .enumerate() {
                    // Reject invalid connections.
                    if !target.node_type.accept_incoming_links() {
                        continue;
                    }

                    let distance = source.position.distance(&target.position);

                    // reject a pair of nodes based on `max_distance`.
                    if let Some(max_d) = layer_link.max_distance {
                        if distance > max_d {
                            continue;
                        }
                    }

                    // Calculate the weight between source and target using the CPPN.

                    let outputs_from_cppn = match mode {
                        LinkMode::AbsolutePositions => {
                            let inputs_to_cppn = [source.position.coords(),
                                                  target.position.coords()];
                            cppn.calculate(&inputs_to_cppn)
                        }
                        LinkMode::AbsolutePositionsAndDistance => {
                            let distance_between: &[_] = &[distance];
                            let inputs_to_cppn = [source.position.coords(),
                                                  target.position.coords(),
                                                  distance_between];
                            cppn.calculate(&inputs_to_cppn)
                        }
                        LinkMode::RelativePositionOfTarget => {
                            let relative_position_of_target =
                                source.position.relative_position(&target.position);
                            let inputs_to_cppn = [source.position.coords(),
                                                  relative_position_of_target.coords()];
                            cppn.calculate(&inputs_to_cppn)
                        }
                    };

                    let link = Link {
                        source: source,
                        target: target,
                        source_idx: source_idx,
                        target_idx: target_idx,
                        outputs: outputs_from_cppn,
                        distance: distance,
                    };
                    callback(link);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::command::Config;
use crate::error::Error;
use crate::page::{parse_page, DiffOp, Line, Page};
use crate::test::helper::empty_env;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

fn config(repo: &str, branch: Option<&str>, args: Vec<&str>) -> Config {
    let mut dir = env::current_dir().unwrap();
    dir.push(Path::new(".git"));
    let dir = fs::canonicalize(dir).unwrap();
    let mut a = Vec::new();
    for arg in args {
        a.push(arg.to_string());
    }
    Config {
        repo: repo.to_string(),
        branch: branch.map(|s| s.to_string()),
        git_dir: dir,
        args: a,
        stdout: false,
        pull_request: false,
        env: empty_env(),
    }
}

#[test]
fn parse_empty_args() {
    let c = config("https://github.com/user/repo.git", None, vec![]);
    match parse_page(&c).unwrap() {
        Page::Open => { /* OK */ }
        _ => assert!(false),
    }
}

#[test]
fn parse_file_or_dir() {
    for &(entry, relative) in &[
        (
            Path::new(".").join("README.md").as_path(),
            Path::new("README.md"),
        ),
        (Path::new("src"), Path::new("src")),
        (
            Path::new(".").join("src").join("main.rs").as_path(),
            Path::new("src").join("main.rs").as_path(),
        ),
        // Contains '..'
        (
            Path::new(".")
                .join("src")
                .join("..")
                .join("README.md")
                .as_path(),
            Path::new("README.md"),
        ),
        // Suffix '..'
        (
            Path::new(".").join("src").join("test").join("..").as_path(),
            Path::new("src"),
        ),
    ] {
        let c = config(
            "https://github.com/user/repo.git",
            None,
            vec![&entry.to_str().unwrap()],
        );
        match parse_page(&c).unwrap() {
            Page::FileOrDir {
                relative_path,
                hash,
                line: None,
            } => {
                assert_eq!(relative_path, relative.to_str().unwrap());
                assert!(!hash.is_empty());
            }
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
fn parse_file_single_line() {
    for &(ref file, ref expected) in &[
        (Path::new(".").join("README.md#21"), Some(Line::At(21))),
        (
            Path::new(".").join("src").join("main.rs#10"),
            Some(Line::At(10)),
        ),
        (PathBuf::from("LICENSE.txt"), None),
        (
            Path::new(".").join("src").join("..").join("README.md#21"),
            Some(Line::At(21)),
        ),
        (Path::new(".").join("README.md#L21"), Some(Line::At(21))),
    ] {
        let c = config(
            "https://github.com/user/repo.git",
            None,
            vec![&file.to_str().unwrap()],
        );
        match parse_page(&c).unwrap() {
            Page::FileOrDir { ref line, .. } => assert_eq!(line, expected, "input: {:?}", file),
            p => assert!(false, "Unexpected result: {:?}, input: {:?}", p, file),
        }
    }
}

#[test]
fn not_existing_file() {
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["not/existing/file.txt"],
    );
    assert!(parse_page(&c).is_err());
}

#[test]
fn file_at_specific_commit() {
    let c = config("https://github.com/user/repo.git", None, vec!["README.md"]);
    let p = parse_page(&c).unwrap();
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["README.md", "HEAD^"],
    );
    let p2 = parse_page(&c).unwrap();
    assert!(p != p2, format!("{:?} v.s. {:?}", p, p2));
}

#[test]
fn parse_commit_ref() {
    for &cm in &["HEAD", "HEAD~1", "HEAD^", "HEAD^^"] {
        let c = config("https://github.com/user/repo.git", None, vec![cm]);
        match parse_page(&c).unwrap() {
            Page::Commit { hash } => assert!(!hash.is_empty()),
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
#[cfg_attr(feature = "on-ci", ignore)]
fn parse_short_commit_hash() {
    for &(cm, expected) in &[
        ("499edbb", "499edbbbad4d8054e4a47e12944e5fb4a2ef7ec5"),
        (
            "bc869a14617a131fefe8fa1a3dcdeba0745880d5",
            "bc869a14617a131fefe8fa1a3dcdeba0745880d5",
        ),
    ] {
        let c = config("https://github.com/user/repo.git", None, vec![cm]);
        match parse_page(&c).unwrap() {
            Page::Commit { hash } => assert_eq!(hash, expected),
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
fn parse_diff_ref_name() {
    for &(arg, expected_op) in &[
        ("HEAD^..HEAD", DiffOp::TwoDots),
        ("HEAD^...HEAD", DiffOp::ThreeDots),
        ("master...HEAD", DiffOp::ThreeDots),
        ("master@{1month}..master@{1day}", DiffOp::TwoDots),
    ] {
        let c = config("https://github.com/user/repo.git", None, vec![arg]);
        match parse_page(&c).unwrap() {
            Page::Diff { lhs, rhs, op } => {
                assert!(!lhs.is_empty());
                assert!(!rhs.is_empty());
                assert_eq!(op, expected_op, "arg is {}", arg);
            }
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
#[cfg_attr(feature = "on-ci", ignore)]
fn parse_diff_revisions() {
    for &(arg, expected_op) in &[
        ("499edbb..bc869a1", DiffOp::TwoDots),
        ("499edbb...bc869a1", DiffOp::ThreeDots),
    ] {
        let c = config("https://github.com/user/repo.git", None, vec![arg]);
        match parse_page(&c).unwrap() {
            Page::Diff { lhs, rhs, op } => {
                assert_eq!(lhs, "499edbbbad4d8054e4a47e12944e5fb4a2ef7ec5");
                assert_eq!(rhs, "bc869a14617a131fefe8fa1a3dcdeba0745880d5");
                assert_eq!(op, expected_op, "arg is {}", arg);
            }
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
fn wrong_num_of_args() {
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["foo", "bar", "piyo", "blah"],
    );
    match parse_page(&c) {
        Err(Error::PageParseError { attempts, .. }) => {
            assert!(!attempts.is_empty());
            for err in attempts {
                match err {
                    Error::WrongNumberOfArgs { actual, .. } => assert_eq!(actual, 4),
                    err => assert!(false, "Unexpected error: {}", err),
                }
            }
        }
        v => assert!(false, "Unexpected success or error: {:?}", v),
    }
}

#[test]
fn unknown_diff() {
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["HEAD~114514..HEAD~114513"],
    );
    assert!(parse_page(&c).is_err());
}

#[test]
fn file_for_unknown_commit() {
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["README.md", "HEAD~114514"],
    );
    assert!(parse_page(&c).is_err());
}

#[test]
fn diff_lhs_or_rhs_empty() {
    for ref path in &[
        Path::new("..").join("foo.txt"),
        Path::new("foo").join(".."),
        PathBuf::from(".."),
    ] {
        let c = config(
            "https://github.com/user/repo.git",
            None,
            vec![path.to_str().unwrap()],
        );
        match parse_page(&c) {
            Ok(p @ Page::Diff { .. }) => assert!(false, "Unexpectedly parsed as diff: {:?}", p),
            _ => { /*ok*/ }
        }
    }
}

#[test]
fn issue_number() {
    let c = config("https://github.com/user/repo.git", None, vec!["#123"]);
    match parse_page(&c) {
        Ok(Page::Issue { number }) => assert_eq!(number, 123),
        v => assert!(false, "Unexpected result {:?}", v),
    }
}

#[test]
fn line_cannot_be_set_to_dir() {
    for arg in &["src#123", "src#12-23"] {
        let c = config("https://github.com/user/repo.git", None, vec![arg]);
        match parse_page(&c) {
            Err(Error::PageParseError { attempts, .. }) => assert!(
                attempts.iter().any(|err| match err {
                    Error::LineSpecifiedForDir(path) => format!("{:?}", path).contains("src"),
                    _ => false,
                }),
                "{:?} for {}",
                attempts,
                arg,
            ),
            v => assert!(false, "Unexpected result {:?} for {}", v, arg),
        }
    }
}

#[test]
fn parse_file_line_range() {
    for file in &[
        Path::new("README.md#1-2"),
        Path::new("README.md#L1-2"),
        Path::new("README.md#1-L2"),
        Path::new("README.md#L1-L2"),
    ] {
        let c = config(
            "https://github.com/user/repo.git",
            None,
            vec![&file.to_str().unwrap()],
        );
        match parse_page(&c).unwrap() {
            Page::FileOrDir { line, .. } => {
                assert_eq!(line, Some(Line::Range(1, 2)), "input: {:?}", file)
            }
            p => assert!(false, "Unexpected result: {:?}, input: {:?}", p, file),
        }
    }
}
<commit_msg>fix tests are broken for tag commits on CI<commit_after>use crate::command::Config;
use crate::error::Error;
use crate::page::{parse_page, DiffOp, Line, Page};
use crate::test::helper::empty_env;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};

fn config(repo: &str, branch: Option<&str>, args: Vec<&str>) -> Config {
    let mut dir = env::current_dir().unwrap();
    dir.push(Path::new(".git"));
    let dir = fs::canonicalize(dir).unwrap();
    let mut a = Vec::new();
    for arg in args {
        a.push(arg.to_string());
    }
    Config {
        repo: repo.to_string(),
        branch: branch.map(|s| s.to_string()),
        git_dir: dir,
        args: a,
        stdout: false,
        pull_request: false,
        env: empty_env(),
    }
}

#[test]
fn parse_empty_args() {
    let c = config("https://github.com/user/repo.git", None, vec![]);
    match parse_page(&c).unwrap() {
        Page::Open => { /* OK */ }
        _ => assert!(false),
    }
}

#[test]
fn parse_file_or_dir() {
    for &(entry, relative) in &[
        (
            Path::new(".").join("README.md").as_path(),
            Path::new("README.md"),
        ),
        (Path::new("src"), Path::new("src")),
        (
            Path::new(".").join("src").join("main.rs").as_path(),
            Path::new("src").join("main.rs").as_path(),
        ),
        // Contains '..'
        (
            Path::new(".")
                .join("src")
                .join("..")
                .join("README.md")
                .as_path(),
            Path::new("README.md"),
        ),
        // Suffix '..'
        (
            Path::new(".").join("src").join("test").join("..").as_path(),
            Path::new("src"),
        ),
    ] {
        let c = config(
            "https://github.com/user/repo.git",
            None,
            vec![&entry.to_str().unwrap()],
        );
        match parse_page(&c).unwrap() {
            Page::FileOrDir {
                relative_path,
                hash,
                line: None,
            } => {
                assert_eq!(relative_path, relative.to_str().unwrap());
                assert!(!hash.is_empty());
            }
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
fn parse_file_single_line() {
    for &(ref file, ref expected) in &[
        (Path::new(".").join("README.md#21"), Some(Line::At(21))),
        (
            Path::new(".").join("src").join("main.rs#10"),
            Some(Line::At(10)),
        ),
        (PathBuf::from("LICENSE.txt"), None),
        (
            Path::new(".").join("src").join("..").join("README.md#21"),
            Some(Line::At(21)),
        ),
        (Path::new(".").join("README.md#L21"), Some(Line::At(21))),
    ] {
        let c = config(
            "https://github.com/user/repo.git",
            None,
            vec![&file.to_str().unwrap()],
        );
        match parse_page(&c).unwrap() {
            Page::FileOrDir { ref line, .. } => assert_eq!(line, expected, "input: {:?}", file),
            p => assert!(false, "Unexpected result: {:?}, input: {:?}", p, file),
        }
    }
}

#[test]
fn not_existing_file() {
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["not/existing/file.txt"],
    );
    assert!(parse_page(&c).is_err());
}

#[test]
fn file_at_specific_commit() {
    let c = config("https://github.com/user/repo.git", None, vec!["README.md"]);
    let p = parse_page(&c).unwrap();
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["README.md", "HEAD^"],
    );
    let p2 = parse_page(&c).unwrap();
    assert!(p != p2, format!("{:?} v.s. {:?}", p, p2));
}

#[test]
fn parse_commit_ref() {
    for &cm in &["HEAD", "HEAD~1", "HEAD^", "HEAD^^"] {
        let c = config("https://github.com/user/repo.git", None, vec![cm]);
        match parse_page(&c).unwrap() {
            Page::Commit { hash } => assert!(!hash.is_empty(), "{} for {}", hash, cm),
            p => assert!(false, "Unexpected result: {:?} for {}", p, cm),
        }
    }
}

#[test]
#[cfg_attr(feature = "on-ci", ignore)]
fn parse_commit_branch_ref() {
    for spec in &["master", "master@{1month}"] {
        let c = config("https://github.com/user/repo.git", None, vec![spec]);
        match parse_page(&c).unwrap() {
            Page::Commit { hash } => assert!(!hash.is_empty(), "{} for {}", hash, spec),
            p => assert!(false, "Unexpected result: {:?} for {}", p, spec),
        }
    }
}

#[test]
#[cfg_attr(feature = "on-ci", ignore)]
fn parse_short_commit_hash() {
    for &(cm, expected) in &[
        ("499edbb", "499edbbbad4d8054e4a47e12944e5fb4a2ef7ec5"),
        (
            "bc869a14617a131fefe8fa1a3dcdeba0745880d5",
            "bc869a14617a131fefe8fa1a3dcdeba0745880d5",
        ),
    ] {
        let c = config("https://github.com/user/repo.git", None, vec![cm]);
        match parse_page(&c).unwrap() {
            Page::Commit { hash } => assert_eq!(hash, expected),
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
fn parse_diff_ref_name() {
    for &(arg, expected_op) in &[
        ("HEAD^..HEAD", DiffOp::TwoDots),
        ("HEAD^...HEAD", DiffOp::ThreeDots),
    ] {
        let c = config("https://github.com/user/repo.git", None, vec![arg]);
        match parse_page(&c).unwrap() {
            Page::Diff { lhs, rhs, op } => {
                assert!(!lhs.is_empty());
                assert!(!rhs.is_empty());
                assert_eq!(op, expected_op, "arg is {}", arg);
            }
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
#[cfg_attr(feature = "on-ci", ignore)]
fn parse_diff_branch_spec() {
    for &(arg, expected_op) in &[
        ("master...HEAD", DiffOp::ThreeDots),
        ("master@{1month}..master@{1day}", DiffOp::TwoDots),
    ] {
        let c = config("https://github.com/user/repo.git", None, vec![arg]);
        match parse_page(&c).unwrap() {
            Page::Diff { lhs, rhs, op } => {
                assert!(!lhs.is_empty());
                assert!(!rhs.is_empty());
                assert_eq!(op, expected_op, "arg is {}", arg);
            }
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
#[cfg_attr(feature = "on-ci", ignore)]
fn parse_diff_revisions() {
    for &(arg, expected_op) in &[
        ("499edbb..bc869a1", DiffOp::TwoDots),
        ("499edbb...bc869a1", DiffOp::ThreeDots),
    ] {
        let c = config("https://github.com/user/repo.git", None, vec![arg]);
        match parse_page(&c).unwrap() {
            Page::Diff { lhs, rhs, op } => {
                assert_eq!(lhs, "499edbbbad4d8054e4a47e12944e5fb4a2ef7ec5");
                assert_eq!(rhs, "bc869a14617a131fefe8fa1a3dcdeba0745880d5");
                assert_eq!(op, expected_op, "arg is {}", arg);
            }
            p => assert!(false, "Unexpected result: {:?}", p),
        }
    }
}

#[test]
fn wrong_num_of_args() {
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["foo", "bar", "piyo", "blah"],
    );
    match parse_page(&c) {
        Err(Error::PageParseError { attempts, .. }) => {
            assert!(!attempts.is_empty());
            for err in attempts {
                match err {
                    Error::WrongNumberOfArgs { actual, .. } => assert_eq!(actual, 4),
                    err => assert!(false, "Unexpected error: {}", err),
                }
            }
        }
        v => assert!(false, "Unexpected success or error: {:?}", v),
    }
}

#[test]
fn unknown_diff() {
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["HEAD~114514..HEAD~114513"],
    );
    assert!(parse_page(&c).is_err());
}

#[test]
fn file_for_unknown_commit() {
    let c = config(
        "https://github.com/user/repo.git",
        None,
        vec!["README.md", "HEAD~114514"],
    );
    assert!(parse_page(&c).is_err());
}

#[test]
fn diff_lhs_or_rhs_empty() {
    for ref path in &[
        Path::new("..").join("foo.txt"),
        Path::new("foo").join(".."),
        PathBuf::from(".."),
    ] {
        let c = config(
            "https://github.com/user/repo.git",
            None,
            vec![path.to_str().unwrap()],
        );
        match parse_page(&c) {
            Ok(p @ Page::Diff { .. }) => assert!(false, "Unexpectedly parsed as diff: {:?}", p),
            _ => { /*ok*/ }
        }
    }
}

#[test]
fn issue_number() {
    let c = config("https://github.com/user/repo.git", None, vec!["#123"]);
    match parse_page(&c) {
        Ok(Page::Issue { number }) => assert_eq!(number, 123),
        v => assert!(false, "Unexpected result {:?}", v),
    }
}

#[test]
fn line_cannot_be_set_to_dir() {
    for arg in &["src#123", "src#12-23"] {
        let c = config("https://github.com/user/repo.git", None, vec![arg]);
        match parse_page(&c) {
            Err(Error::PageParseError { attempts, .. }) => assert!(
                attempts.iter().any(|err| match err {
                    Error::LineSpecifiedForDir(path) => format!("{:?}", path).contains("src"),
                    _ => false,
                }),
                "{:?} for {}",
                attempts,
                arg,
            ),
            v => assert!(false, "Unexpected result {:?} for {}", v, arg),
        }
    }
}

#[test]
fn parse_file_line_range() {
    for file in &[
        Path::new("README.md#1-2"),
        Path::new("README.md#L1-2"),
        Path::new("README.md#1-L2"),
        Path::new("README.md#L1-L2"),
    ] {
        let c = config(
            "https://github.com/user/repo.git",
            None,
            vec![&file.to_str().unwrap()],
        );
        match parse_page(&c).unwrap() {
            Page::FileOrDir { line, .. } => {
                assert_eq!(line, Some(Line::Range(1, 2)), "input: {:?}", file)
            }
            p => assert!(false, "Unexpected result: {:?}, input: {:?}", p, file),
        }
    }
}
<|endoftext|>


<commit_before>
use vertex::{RawVertex, Vertex};
use edge::{RawEdge, Edge};
use graph::TraversableToVertex;
use path::{Path, Element};
use std::iter::Extend;

// use std::iter::Iterator;

// define a traversal as a series of stages

pub struct GraphQuery {
    // many paths
    pub paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<Vertex>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
            let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

    pub fn get_paths(&self) -> &Vec<Path> {
        &self.paths
    }
    pub fn push(&mut self, path:Path) {
        self.paths.push(path)
    }

    /*
    generic mapper for our queries
    future this may use worker threads to perform
    traversals
     */
    fn map<F: Fn(&Path) -> Vec<Element>>(&self, closure: F) -> GraphQuery  {
        let mut result = GraphQuery::empty(); // result
        for path in self.paths.iter() {
            let mut tmp = closure(&path);
            // let mut tmp2 = tmp.as_slice();
            // currently gets back a Vec<Path> but what if it gets Elements?
            let new_elements = path.permute(&tmp);
            result.paths.extend(new_elements);
        }
        result
    }

    pub fn outV(&self, labels: &[&str]) -> GraphQuery {
        // map can figure out the rest
        let f = |path: &Path| {
            //take the final element in the path
            let element = path.last().unwrap();

            let result : Vec<Element> = match element {
                &Element::Vertex(v) =>
                    v.outV(&labels).iter().map(|v| Element::Vertex(*v)).collect(),
                    // Vec::new(),
                &Element::Edge(ref e) =>
                    Vec::new()
            };
            // apply outV
            result
        };
        self.map(f)
    }

//    pub fn inV(&self) -> GraphQuery {
//        let g = GraphQuery::empty();
//        let f = |element: &Element| {
//            element.inV()
//        };
//        self.map(f)
//    }
}
<commit_msg>getting ready for filtering<commit_after>
use vertex::{RawVertex, Vertex};
use edge::{RawEdge, Edge};
use graph::TraversableToVertex;
use path::{Path, Element};
use std::iter::Extend;

// use std::iter::Iterator;

// define a traversal as a series of stages

pub struct GraphQuery {
    // many paths
    pub paths: Vec<Path>
}

impl GraphQuery {
    pub fn new(vertices: Vec<Vertex>) -> GraphQuery {
        // create a new path for each proxy, add the proxy
        let mut paths = Vec::new();
        for p in vertices {
            let mut path = Path::new(p);
            paths.push(path)
        }
        GraphQuery{paths:paths}
    }

    pub fn empty() -> GraphQuery {
        // return an empty graph query
        GraphQuery{paths:Vec::new()}
    }

    pub fn get_paths(&self) -> &Vec<Path> {
        &self.paths
    }
    pub fn push(&mut self, path:Path) {
        self.paths.push(path)
    }

    /*
    generic mapper for our queries
    future this may use worker threads to perform
    traversals

    TODO make sure that if nothing comes back we don't keep it in the path

     */
    fn map<F: Fn(&Path) -> Vec<Element>>(&self, closure: F) -> GraphQuery  {
        let mut result = GraphQuery::empty(); // result
        for path in self.paths.iter() {
            let mut tmp = closure(&path);
            // let mut tmp2 = tmp.as_slice();
            // currently gets back a Vec<Path> but what if it gets Elements?
            let new_elements = path.permute(&tmp);
            result.paths.extend(new_elements);
        }
        result
    }

    pub fn outV(&self, labels: &[&str]) -> GraphQuery {
        // map can figure out the rest
        let f = |path: &Path| {
            //take the final element in the path
            let element = path.last().unwrap();

            let result : Vec<Element> = match element {
                &Element::Vertex(v) =>
                    v.outV(&labels).iter().map(|v| Element::Vertex(*v)).collect(),
                    // Vec::new(),
                &Element::Edge(ref e) =>
                    Vec::new()
            };
            // apply outV
            result
        };
        self.map(f)
    }

    pub fn filter<F: Fn(&Path) -> bool>(&self, closure: F) -> GraphQuery {
        let gq = GraphQuery::empty();

        gq
    }

//    pub fn inV(&self) -> GraphQuery {
//        let g = GraphQuery::empty();
//        let f = |element: &Element| {
//            element.inV()
//        };
//        self.map(f)
//    }
}
<|endoftext|>


<commit_before>use super::types::CmdVal;

pub fn parse(s: &str) -> Option<CmdVal> {
    fn split_fn(ch: char) -> bool { ch.is_whitespace() };
    let words = s.split( split_fn );

    // TODO implement command parsing
    unimplemented!()
}
<commit_msg>Implement parse() except for option parsing.<commit_after>use std::iter::Peekable;
use std::str::FromStr;

use super::types::{CmdVal, OptionParam, RegisterParam, GoParam, NumNodes};
use super::super::game::{Position, Move, White, Black, fen_to_position,
                         MilliSec, NumPlies, NumMoves};

pub fn parse(s: &str) -> Option<CmdVal> {
    let mut words = s.words().peekable();

    let mut cmd_val: Option<CmdVal> = None;

    while cmd_val.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };

        cmd_val = match next_word {
            "uci" => Some(CmdVal::Uci),
            "debug" => parse_on_off(&mut words).map(|val| CmdVal::Debug(val)),
            "isready" => Some(CmdVal::IsReady),
            "setoption" => parse_option_val(&mut words).map(|val| CmdVal::SetOption(val)),
            "register" => parse_register_vec(&mut words).map(|val| CmdVal::Register(val)),
            "ucinewgame" => Some(CmdVal::UciNewGame),
            "position" => {
                let pos_opt = parse_position(&mut words);
                match parse_move_vec(&mut words) {
                    Some(moves) => Some(CmdVal::SetupPosition(pos_opt, moves)),
                    None => None,
                }
            },
            "go" => parse_go_param_vec(&mut words).map(|val| CmdVal::Go(val)),
            "stop" => Some(CmdVal::Stop),
            "ponderhit" => Some(CmdVal::PonderHit),
            "quit" => Some(CmdVal::Quit),
            _ => None,
        }
    }

    cmd_val
}

fn parse_on_off(words: &mut Iterator<&str>) -> Option<bool> {
    let mut ans = None;
    while ans.is_none() {
        let next_word_opt = words.next();
        let next_word = match next_word_opt {
            Some(val) => val,
            None => break,
        };
        ans = match next_word {
            "on" => Some(true),
            "off" => Some(false),
            _ => None,
        }
    }
    ans
}

fn parse_option_val<'a,T>(words: &mut T) -> Option<OptionParam>
where T: Iterator<&'a str> {
    // TODO parse options.
    Some(OptionParam::Dummy)
}

fn parse_register_vec<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Vec<RegisterParam>>
where T: Iterator<&'a str> {
    let mut res = Vec::<RegisterParam>::new();
    while let Some(next_word) = words.next() {
        let register_val = match next_word {
            "later" => Some(RegisterParam::Later),
            "name" => {
                let mut name_vec = Vec::<&str>::new();
                loop {
                    let curr_name = words.peek().and_then( |s| {
                        if ["late","name","code"].contains(s) { None }
                        else { Some(*s) }
                    });
                    match curr_name {
                        Some(val) => {
                            name_vec.push(val);
                            words.next();
                        },
                        None => break,
                    }
                }
                Some(RegisterParam::Name(name_vec.connect(" ")))
            },
            "code" => words.next().map( |x| RegisterParam::Code(x.to_string())),
            _ => None,
        };
        if let Some(val) = register_val {
            res.push(val);
        }
    }
    if res.is_empty() { None } else { Some(res) }
}

fn parse_position<'a,T>(words: &mut T) -> Option<Position>
where T: Iterator<&'a str> {
    let six_words: Vec<_> = words.by_ref().take(6).collect();
    fen_to_position(&*six_words.connect(" ")).ok()
}

fn parse_move_vec<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Vec<Move>>
where T: Iterator<&'a str> {
    let mut res = Vec::<Move>::new();
    while let Some(val) = words.peek().and_then(|val| FromStr::from_str(*val)) {
        res.push(val);
        words.next();
    }
    if res.is_empty() { None } else { Some(res) }
}

fn parse_go_param_vec<'a,T>(words: &mut Peekable<&'a str,T>) -> Option<Vec<GoParam>>
where T: Iterator<&'a str> {
    let mut res = Vec::<GoParam>::new();
    while let Some(next_word) = words.next() {
        match next_word {
            "search moves" => parse_move_vec(words).map(|x| GoParam::SearchMoves(x)),
            "ponder" => Some(GoParam::Ponder),
            "wtime"     => words.next().and_then(|s| s.parse::<u32>())
                                       .map(|x| GoParam::Time(White,MilliSec(x))),
            "btime"     => words.next().and_then(|s| s.parse::<u32>())
                                       .map(|x| GoParam::Time(Black,MilliSec(x))),
            "movestogo" => words.next().and_then(|s| s.parse::<u16>())
                                       .map(|x| GoParam::MovesToGo(NumMoves(x))),
            "depth"     => words.next().and_then(|s| s.parse::<u16>())
                                       .map(|x| GoParam::Depth(NumPlies(x))),
            "nodes"     => words.next().and_then(|s| s.parse::<u64>())
                                       .map(|x| GoParam::Nodes(NumNodes(x))),
            "mate"      => words.next().and_then(|s| s.parse::<u16>())
                                       .map(|x| GoParam::Mate(NumMoves(x))),
            "movetime"  => words.next().and_then(|s| s.parse::<u32>())
                                       .map(|x| GoParam::MoveTime(MilliSec(x))),
            "infinite" => Some(GoParam::Infinite),
            _ => None,
        }.map(|val| res.push(val));
    }
    if res.is_empty() { None } else { Some(res) }
}
<|endoftext|>