<commit_before>#![feature(unicode)]
#![feature(path_ext)]

extern crate toml;
extern crate getopts;
extern crate rustc_serialize;
extern crate unicode;

use std::path::{PathBuf, Path};
use std::fs;
use std::fs::{File, PathExt};
use std::io::{Read, Write};
use std::collections::HashMap;
use std::process::{Command, Stdio};
use std::env;
use getopts::Options;

static DEPOT_TOML_NAME:           &'static str = "Depot.toml";
static DEPENDENCIES_TOML_NAME:    &'static str = "Dependencies.toml";
static DEFAULT_DEPOT_NAME:        &'static str = "depot";
static CARGO_NAME:                &'static str = "cargoproject";
static CARGO_PROJECT_TYPE:        &'static str = "lib";

static CARGO_DEFAULT_OPT_LEVEL:           &'static str = "3";
static CARGO_DEFAULT_DEBUG_FLAG:          &'static str = "false";
static CARGO_DEFAULT_DEBUG_ASSERTIONS:    &'static str = "false";

// Depot.toml
#[derive(RustcDecodable, RustcEncodable, Debug)]
struct DepotManifest {
  depot: DepotProject,
  settings: DepotProfile
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct DepotProject {
  out_dir: Option<String>,
  dirs: Vec<String>
}

#[derive(RustcDecodable, RustcEncodable, Clone, Default, Debug)]
pub struct DepotProfile {
    opt_level: u32,
    // codegen_units: Option<u32>, // Is this something we want passed?
    debug: bool,
    debug_assertions: bool,
}

// Dependencies.toml
#[derive(RustcDecodable, RustcEncodable, Debug)]
struct DependencyManifest {
  dependencies: Option<HashMap<String, Dependency>>,
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
enum Dependency {
  Simple(String),
  Detailed(DetailedDependency)
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, Default)]
struct DetailedDependency {
  version: Option<String>,
  path: Option<String>,
  git: Option<String>,
  branch: Option<String>,
  tag: Option<String>,
  rev: Option<String>,
  features: Option<Vec<String>>,
  optional: Option<bool>,
  default_features: Option<bool>,
}

struct DependencyConflict {
  name: String,
  manifest_a: String,
  manifest_b: String,
  version_a: String,
  version_b: String,
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {

  let args: Vec<String> = env::args().collect();
  let program = args[0].clone();

  let mut opts = Options::new();
  opts.optmulti("d", "dir", "directory that contains a Dependency.toml", "DIR");
  opts.optopt("o", "out-dir", "directory that contains the output libraries", "OUTDIR");
  opts.optopt("", "opt-level", "optimize dependencies with possible levels 0-3", "OPTLEVEL");
  opts.optflag("", "debug", "passes -g and/or enables the debug configuration for the compiler");
  opts.optflag("", "debug-assertions", "enables debug assertions");
  opts.optflag("h", "help", "print this help menu");

  let matches = opts.parse(&args[1 ..]).unwrap();
  if matches.opt_present("h") {
    print_usage(&program, opts);
    return;
  }

  let current_dir = env::current_dir().unwrap();

  let mut depot_manifest: DepotManifest;
  let mut working_dir: PathBuf;

  // if the operator passed some dir args
  if matches.opt_present("d") {
    depot_manifest = DepotManifest {
      depot: DepotProject {
        dirs: matches.opt_strs("d"),
        out_dir: Some(matches.opt_str("o").unwrap_or(current_dir.join(DEFAULT_DEPOT_NAME).to_string_lossy().into_owned()))
      },
      settings: DepotProfile {
        opt_level: matches.opt_str("opt-level").unwrap_or(CARGO_DEFAULT_OPT_LEVEL.to_string()).parse().unwrap(),
        debug: matches.opt_str("debug").unwrap_or(CARGO_DEFAULT_DEBUG_FLAG.to_string()).parse().unwrap(),
        debug_assertions: matches.opt_str("debug-assertions").unwrap_or(CARGO_DEFAULT_DEBUG_ASSERTIONS.to_string()).parse().unwrap()
      }
    };
    working_dir = current_dir;

  // else if no args, we check the current directory for a depot config toml
  } else if matches.free.is_empty() {
    let depot_toml_path = current_dir.clone().join(DEPOT_TOML_NAME);
    depot_manifest = parse_depot_toml(&depot_toml_path);
    working_dir = current_dir;

  // else the operator should have passed a path to a depot config toml
  } else {
    let depot_toml_path = PathBuf::from(matches.free[0].clone());
    depot_manifest = parse_depot_toml(&depot_toml_path);
    working_dir = depot_toml_path.clone();
    working_dir.pop();
  };

  let mut dep_toml_dirs = Vec::new();
  for string in depot_manifest.depot.dirs.iter() {
    dep_toml_dirs.push(PathBuf::from(string));
  }

  // Get the Dependency.tomls
  let mut dependency_tomls: Vec<PathBuf> = Vec::with_capacity(dep_toml_dirs.len());

  //TODO: Make this search subdirectories too
  for dir in dep_toml_dirs.iter() {
    let dependencies_toml = dir.clone().join(DEPENDENCIES_TOML_NAME);

    if dependencies_toml.exists() && dependencies_toml.is_file() {
      dependency_tomls.push(dependencies_toml);
      println!("Found {} in {:?}", DEPENDENCIES_TOML_NAME, dir);
    }
  }

  let mut toml_manifests = HashMap::new();

  // Extract the manifests from the tomls
  for toml_path in dependency_tomls.iter() {
    let mut toml_file = File::open(toml_path).unwrap();

    let mut toml_text = String::new();
    toml_file.read_to_string(&mut toml_text).unwrap();

    let root = parse(&toml_text, toml_path);
    let toml_manifest: DependencyManifest = toml::decode(toml::Value::Table(root)).unwrap();

    let dir_name = toml_path.parent().unwrap().file_name().unwrap().to_str().unwrap().to_string();
    toml_manifests.insert(dir_name, toml_manifest);
  }

  let mut conflicts = Vec::new();

  // Wow, this is ugly!
  // I should probably feel ashamed of myself!
  'a_manifest: for (manifest_name_a, manifest_a) in toml_manifests.iter() {
    if manifest_a.dependencies.is_none() { continue }
    'a_dep: for (dep_name_a, dep_a) in manifest_a.dependencies.as_ref().unwrap().iter() {
      'b_manifest: for (manifest_name_b, manifest_b) in toml_manifests.iter() {
        if manifest_b.dependencies.is_none() { continue }
        'b_dep: for (dep_name_b, dep_b) in manifest_b.dependencies.as_ref().unwrap().iter() {
          if manifest_name_a == manifest_name_b {
            continue 'a_manifest
          }
          if dep_name_a == dep_name_b {
            let version_a = get_version(dep_a);
            let version_b = get_version(dep_b);

            if version_a != version_b {
              conflicts.push(
                DependencyConflict {
                  name: dep_name_a.clone(),
                  manifest_a: manifest_name_a.clone(),
                  manifest_b: manifest_name_b.clone(),
                  version_a: version_a.clone(),
                  version_b: version_b.clone(),
                }
              );
            }
          }
        }
      }
    }
  }

  // Fix the hashmap ordering
  for conflict in conflicts.iter_mut() {
    if conflict.manifest_a > conflict.manifest_b {

      let tmp = conflict.manifest_a.clone();
      conflict.manifest_a = conflict.manifest_b.clone();
      conflict.manifest_b = tmp.clone();

      let tmp = conflict.version_a.clone();
      conflict.version_a = conflict.version_b.clone();
      conflict.version_b = tmp.clone();
    }
  }
  conflicts.sort_by(|a, b|
    a.manifest_a.cmp(&b.manifest_a)
  );

  for conflict in conflicts.iter() {
    // Display the conflict to the operator
    println!(
      "ERROR: Version mismatch: {} {}, while {} {}.",
      format!("\"{}\"", conflict.manifest_a),

      if conflict.version_a == "".to_string() {
        format!("uses the latest available version of {}", conflict.name)
      } else {
        format!("requires {} of {}", conflict.version_a, conflict.name)
      },

      format!("\"{}\"", conflict.manifest_b),

      if conflict.version_b == "".to_string() {
        format!("uses the latest available version of {}", conflict.name)
      } else {
        format!("requires {} of {}", conflict.version_b, conflict.name)
      }
    );
  }

  if conflicts.len() != 0 {
    println!("You may be able to resolve these conflicts by modifying their respective \"{}\"\'s.", DEPENDENCIES_TOML_NAME);
    panic!();
  }

  let mut final_manifest = DependencyManifest { dependencies: Some(HashMap::new()) };
  for (_, manifest) in toml_manifests.iter() {
    if manifest.dependencies.is_none() {
      continue
    }
    for (dep_name, dep) in manifest.dependencies.as_ref().unwrap().iter() {
      final_manifest.dependencies.as_mut().unwrap().insert(dep_name.clone(), dep.clone());
    }
  }

  let cargo_toml_text =
format!("#ATTENTION: This file is automatically generated. Don't modify it unless your life is terrible, or you wish it to be so.
[package]
name = \"{cargo_project_name}\"
version = \"0.0.1\"
authors = [ \"automatically generated\" ]

[lib]
name = \"{cargo_project_name}\"
crate_type = [\"{crate_type}\"]
plugin = true

[profile.dev]
opt-level = {opt_level}
debug = {debug}
debug_assertions = {debug_assertions}

{dependencies}
",
cargo_project_name = CARGO_NAME,
opt_level = depot_manifest.settings.opt_level,
debug = depot_manifest.settings.debug,
debug_assertions = depot_manifest.settings.debug_assertions,
dependencies = toml::encode_str(&final_manifest),
crate_type = CARGO_PROJECT_TYPE);

  let out_dir = match &depot_manifest.depot.out_dir {
    &Some(ref string) => PathBuf::from(string),
    &None => PathBuf::from(working_dir),
  };

  let cargo_project_name = CARGO_NAME;
  let hidden_cargo_dir_name = ".".to_string() + &cargo_project_name;
  let cargo_dir = out_dir.join(&hidden_cargo_dir_name);

  let cargo_toml_path = cargo_dir.join("Cargo.toml");

  let cargo_deps = cargo_dir.join("target").join("debug").join("deps");
  let cargo_native = cargo_dir.join("target").join("debug").join("native");

  let depot_deps = out_dir.join("deps");
  let depot_native = out_dir.join("native");

  // if it exists already
  if cargo_toml_path.exists() && cargo_toml_path.is_file() {

    println!("Creating new Cargo.toml: {:?}", cargo_toml_path);
    let mut cargo_toml_file = File::create(&cargo_toml_path).unwrap();
    cargo_toml_file.write_all(cargo_toml_text.as_bytes()).unwrap();
    cargo_toml_file.flush().unwrap();

    //move dep and native folders from the depot dir to the cargo project dir, for updating
    fs::rename(&depot_deps, &cargo_deps).unwrap();
    fs::rename(&depot_native, &cargo_native).unwrap();

    Command::new("cargo")
      .arg("build")
      .current_dir(&cargo_dir)
      .stdout(Stdio::inherit())
      .stderr(Stdio::inherit())
      .output().unwrap_or_else(|e| {
        panic!("failed to run cargo: {}", e)
      });

    //move dep and native folders BACK to the depot dir, for easy referencing
    fs::rename(&cargo_deps, &depot_deps).unwrap();
    fs::rename(&cargo_native, &depot_native).unwrap();

    // Done!
  } else {
    Command::new("cargo")
      .arg("new")
      .arg(&cargo_project_name)
      .current_dir(&out_dir)
      .stdout(Stdio::inherit())
      .stderr(Stdio::inherit())
      .output().unwrap_or_else(|e| {
      panic!("failed to run cargo: {}", e)
    });

    fs::rename(out_dir.join(&cargo_project_name), out_dir.join(&hidden_cargo_dir_name)).unwrap();

    let mut cargo_toml_file = File::create(&cargo_toml_path).unwrap();
    cargo_toml_file.write_all(cargo_toml_text.as_bytes()).unwrap();
    cargo_toml_file.flush().unwrap();

    Command::new("cargo")
      .arg("build")
      .stdout(Stdio::inherit())
      .stderr(Stdio::inherit())
      .current_dir(&cargo_dir)
      .output().unwrap_or_else(|e| {
        panic!("failed to run cargo: {}", e)
      });

    //move dep and native folders from the cargo project dir to the depot dir, for easier referencing
    fs::rename(&cargo_deps, &depot_deps).unwrap();
    fs::rename(&cargo_native, &depot_native).unwrap();

  // Done!
  }
  println!("Build complete.");

}

fn get_version(d: &Dependency) -> String {
  match d {
    &Dependency::Simple(ref version) => {
      version.clone()
    }
    &Dependency::Detailed(ref details) => {
      match details.version {
        Some(ref version) => version.clone(),
        None => "".to_string()
      }
    }
  }
}

fn parse_depot_toml(depot_toml_path: &Path) -> DepotManifest{

  let mut toml_file = File::open(depot_toml_path).unwrap();

  let mut toml_text = String::new();
  toml_file.read_to_string(&mut toml_text).unwrap();

  let root = parse(&toml_text, depot_toml_path);
  let toml_manifest: DepotManifest = toml::decode(toml::Value::Table(root)).unwrap();
  toml_manifest
}

pub fn parse(toml: &str, file: &Path) -> toml::Table {
  let mut parser = toml::Parser::new(&toml);
  match parser.parse() {
    Some(toml) => return toml,
    None => {}
  }
  let mut error_str = format!("could not parse input TOML\n");
  for error in parser.errors.iter() {
    let (loline, locol) = parser.to_linecol(error.lo);
    let (hiline, hicol) = parser.to_linecol(error.hi);
    error_str.push_str(
      &format!("{}:{}:{}{} {}\n",
        file.display(),
        loline + 1,
        locol + 1,
        if loline != hiline || locol != hicol {
          format!("-{}:{}", hiline + 1, hicol + 1)
        } else {
          "".to_string()
        },
        error.desc
      )
    );
  }
  panic!("{}", error_str);
}<commit_msg>api change: --dir -> --in-dir<commit_after>#![feature(unicode)]
#![feature(path_ext)]

extern crate toml;
extern crate getopts;
extern crate rustc_serialize;
extern crate unicode;

use std::path::{PathBuf, Path};
use std::fs;
use std::fs::{File, PathExt};
use std::io::{Read, Write};
use std::collections::HashMap;
use std::process::{Command, Stdio};
use std::env;
use getopts::Options;

static DEPOT_TOML_NAME:           &'static str = "Depot.toml";
static DEPENDENCIES_TOML_NAME:    &'static str = "Dependencies.toml";
static DEFAULT_DEPOT_NAME:        &'static str = "depot";
static CARGO_NAME:                &'static str = "cargoproject";
static CARGO_PROJECT_TYPE:        &'static str = "lib";

static CARGO_DEFAULT_OPT_LEVEL:           &'static str = "3";
static CARGO_DEFAULT_DEBUG_FLAG:          &'static str = "false";
static CARGO_DEFAULT_DEBUG_ASSERTIONS:    &'static str = "false";

// Depot.toml
#[derive(RustcDecodable, RustcEncodable, Debug)]
struct DepotManifest {
  depot: DepotProject,
  settings: DepotProfile
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
struct DepotProject {
  out_dir: Option<String>,
  dirs: Vec<String>
}

#[derive(RustcDecodable, RustcEncodable, Clone, Default, Debug)]
pub struct DepotProfile {
    opt_level: u32,
    // codegen_units: Option<u32>, // Is this something we want passed?
    debug: bool,
    debug_assertions: bool,
}

// Dependencies.toml
#[derive(RustcDecodable, RustcEncodable, Debug)]
struct DependencyManifest {
  dependencies: Option<HashMap<String, Dependency>>,
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug)]
enum Dependency {
  Simple(String),
  Detailed(DetailedDependency)
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, Default)]
struct DetailedDependency {
  version: Option<String>,
  path: Option<String>,
  git: Option<String>,
  branch: Option<String>,
  tag: Option<String>,
  rev: Option<String>,
  features: Option<Vec<String>>,
  optional: Option<bool>,
  default_features: Option<bool>,
}

struct DependencyConflict {
  name: String,
  manifest_a: String,
  manifest_b: String,
  version_a: String,
  version_b: String,
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {

  let args: Vec<String> = env::args().collect();
  let program = args[0].clone();

  let mut opts = Options::new();
  opts.optmulti("i", "in-dir", "directory that contains a Dependencies.toml", "INDIR");
  opts.optopt("o", "out-dir", "directory that contains the output libraries", "OUTDIR");
  opts.optopt("", "opt-level", "optimize dependencies with possible levels 0-3", "OPTLEVEL");
  opts.optflag("", "debug", "passes -g and/or enables the debug configuration for the compiler");
  opts.optflag("", "debug-assertions", "enables debug assertions");
  opts.optflag("h", "help", "print this help menu");

  let matches = opts.parse(&args[1 ..]).unwrap();
  if matches.opt_present("h") {
    print_usage(&program, opts);
    return;
  }

  let current_dir = env::current_dir().unwrap();

  let mut depot_manifest: DepotManifest;
  let mut working_dir: PathBuf;

  // if the operator passed some dir args
  if matches.opt_present("i") {
    depot_manifest = DepotManifest {
      depot: DepotProject {
        dirs: matches.opt_strs("i"),
        out_dir: Some(matches.opt_str("o").unwrap_or(current_dir.join(DEFAULT_DEPOT_NAME).to_string_lossy().into_owned()))
      },
      settings: DepotProfile {
        opt_level: matches.opt_str("opt-level").unwrap_or(CARGO_DEFAULT_OPT_LEVEL.to_string()).parse().unwrap(),
        debug: matches.opt_str("debug").unwrap_or(CARGO_DEFAULT_DEBUG_FLAG.to_string()).parse().unwrap(),
        debug_assertions: matches.opt_str("debug-assertions").unwrap_or(CARGO_DEFAULT_DEBUG_ASSERTIONS.to_string()).parse().unwrap()
      }
    };
    working_dir = current_dir;

  // else if no args, we check the current directory for a depot config toml
  } else if matches.free.is_empty() {
    let depot_toml_path = current_dir.clone().join(DEPOT_TOML_NAME);
    depot_manifest = parse_depot_toml(&depot_toml_path);
    working_dir = current_dir;

  // else the operator should have passed a path to a depot config toml
  } else {
    let depot_toml_path = PathBuf::from(matches.free[0].clone());
    depot_manifest = parse_depot_toml(&depot_toml_path);
    working_dir = depot_toml_path.clone();
    working_dir.pop();
  };

  let mut dep_toml_dirs = Vec::new();
  for string in depot_manifest.depot.dirs.iter() {
    dep_toml_dirs.push(PathBuf::from(string));
  }

  // Get the Dependency.tomls
  let mut dependency_tomls: Vec<PathBuf> = Vec::with_capacity(dep_toml_dirs.len());

  //TODO: Make this search subdirectories too
  for dir in dep_toml_dirs.iter() {
    let dependencies_toml = dir.clone().join(DEPENDENCIES_TOML_NAME);

    if dependencies_toml.exists() && dependencies_toml.is_file() {
      dependency_tomls.push(dependencies_toml);
      println!("Found {} in {:?}", DEPENDENCIES_TOML_NAME, dir);
    }
  }

  let mut toml_manifests = HashMap::new();

  // Extract the manifests from the tomls
  for toml_path in dependency_tomls.iter() {
    let mut toml_file = File::open(toml_path).unwrap();

    let mut toml_text = String::new();
    toml_file.read_to_string(&mut toml_text).unwrap();

    let root = parse(&toml_text, toml_path);
    let toml_manifest: DependencyManifest = toml::decode(toml::Value::Table(root)).unwrap();

    let dir_name = toml_path.parent().unwrap().file_name().unwrap().to_str().unwrap().to_string();
    toml_manifests.insert(dir_name, toml_manifest);
  }

  let mut conflicts = Vec::new();

  // Wow, this is ugly!
  // I should probably feel ashamed of myself!
  'a_manifest: for (manifest_name_a, manifest_a) in toml_manifests.iter() {
    if manifest_a.dependencies.is_none() { continue }
    'a_dep: for (dep_name_a, dep_a) in manifest_a.dependencies.as_ref().unwrap().iter() {
      'b_manifest: for (manifest_name_b, manifest_b) in toml_manifests.iter() {
        if manifest_b.dependencies.is_none() { continue }
        'b_dep: for (dep_name_b, dep_b) in manifest_b.dependencies.as_ref().unwrap().iter() {
          if manifest_name_a == manifest_name_b {
            continue 'a_manifest
          }
          if dep_name_a == dep_name_b {
            let version_a = get_version(dep_a);
            let version_b = get_version(dep_b);

            if version_a != version_b {
              conflicts.push(
                DependencyConflict {
                  name: dep_name_a.clone(),
                  manifest_a: manifest_name_a.clone(),
                  manifest_b: manifest_name_b.clone(),
                  version_a: version_a.clone(),
                  version_b: version_b.clone(),
                }
              );
            }
          }
        }
      }
    }
  }

  // Fix the hashmap ordering
  for conflict in conflicts.iter_mut() {
    if conflict.manifest_a > conflict.manifest_b {

      let tmp = conflict.manifest_a.clone();
      conflict.manifest_a = conflict.manifest_b.clone();
      conflict.manifest_b = tmp.clone();

      let tmp = conflict.version_a.clone();
      conflict.version_a = conflict.version_b.clone();
      conflict.version_b = tmp.clone();
    }
  }
  conflicts.sort_by(|a, b|
    a.manifest_a.cmp(&b.manifest_a)
  );

  for conflict in conflicts.iter() {
    // Display the conflict to the operator
    println!(
      "ERROR: Version mismatch: {} {}, while {} {}.",
      format!("\"{}\"", conflict.manifest_a),

      if conflict.version_a == "".to_string() {
        format!("uses the latest available version of {}", conflict.name)
      } else {
        format!("requires {} of {}", conflict.version_a, conflict.name)
      },

      format!("\"{}\"", conflict.manifest_b),

      if conflict.version_b == "".to_string() {
        format!("uses the latest available version of {}", conflict.name)
      } else {
        format!("requires {} of {}", conflict.version_b, conflict.name)
      }
    );
  }

  if conflicts.len() != 0 {
    println!("You may be able to resolve these conflicts by modifying their respective \"{}\"\'s.", DEPENDENCIES_TOML_NAME);
    panic!();
  }

  let mut final_manifest = DependencyManifest { dependencies: Some(HashMap::new()) };
  for (_, manifest) in toml_manifests.iter() {
    if manifest.dependencies.is_none() {
      continue
    }
    for (dep_name, dep) in manifest.dependencies.as_ref().unwrap().iter() {
      final_manifest.dependencies.as_mut().unwrap().insert(dep_name.clone(), dep.clone());
    }
  }

  let cargo_toml_text =
format!("#ATTENTION: This file is automatically generated. Don't modify it unless your life is terrible, or you wish it to be so.
[package]
name = \"{cargo_project_name}\"
version = \"0.0.1\"
authors = [ \"automatically generated\" ]

[lib]
name = \"{cargo_project_name}\"
crate_type = [\"{crate_type}\"]
plugin = true

[profile.dev]
opt-level = {opt_level}
debug = {debug}
debug_assertions = {debug_assertions}

{dependencies}
",
cargo_project_name = CARGO_NAME,
opt_level = depot_manifest.settings.opt_level,
debug = depot_manifest.settings.debug,
debug_assertions = depot_manifest.settings.debug_assertions,
dependencies = toml::encode_str(&final_manifest),
crate_type = CARGO_PROJECT_TYPE);

  let out_dir = match &depot_manifest.depot.out_dir {
    &Some(ref string) => PathBuf::from(string),
    &None => PathBuf::from(working_dir),
  };

  let cargo_project_name = CARGO_NAME;
  let hidden_cargo_dir_name = ".".to_string() + &cargo_project_name;
  let cargo_dir = out_dir.join(&hidden_cargo_dir_name);

  let cargo_toml_path = cargo_dir.join("Cargo.toml");

  let cargo_deps = cargo_dir.join("target").join("debug").join("deps");
  let cargo_native = cargo_dir.join("target").join("debug").join("native");

  let depot_deps = out_dir.join("deps");
  let depot_native = out_dir.join("native");

  // if it exists already
  if cargo_toml_path.exists() && cargo_toml_path.is_file() {

    println!("Creating new Cargo.toml: {:?}", cargo_toml_path);
    let mut cargo_toml_file = File::create(&cargo_toml_path).unwrap();
    cargo_toml_file.write_all(cargo_toml_text.as_bytes()).unwrap();
    cargo_toml_file.flush().unwrap();

    //move dep and native folders from the depot dir to the cargo project dir, for updating
    fs::rename(&depot_deps, &cargo_deps).unwrap();
    fs::rename(&depot_native, &cargo_native).unwrap();

    Command::new("cargo")
      .arg("build")
      .current_dir(&cargo_dir)
      .stdout(Stdio::inherit())
      .stderr(Stdio::inherit())
      .output().unwrap_or_else(|e| {
        panic!("failed to run cargo: {}", e)
      });

    //move dep and native folders BACK to the depot dir, for easy referencing
    fs::rename(&cargo_deps, &depot_deps).unwrap();
    fs::rename(&cargo_native, &depot_native).unwrap();

    // Done!
  } else {
    Command::new("cargo")
      .arg("new")
      .arg(&cargo_project_name)
      .current_dir(&out_dir)
      .stdout(Stdio::inherit())
      .stderr(Stdio::inherit())
      .output().unwrap_or_else(|e| {
      panic!("failed to run cargo: {}", e)
    });

    fs::rename(out_dir.join(&cargo_project_name), out_dir.join(&hidden_cargo_dir_name)).unwrap();

    let mut cargo_toml_file = File::create(&cargo_toml_path).unwrap();
    cargo_toml_file.write_all(cargo_toml_text.as_bytes()).unwrap();
    cargo_toml_file.flush().unwrap();

    Command::new("cargo")
      .arg("build")
      .stdout(Stdio::inherit())
      .stderr(Stdio::inherit())
      .current_dir(&cargo_dir)
      .output().unwrap_or_else(|e| {
        panic!("failed to run cargo: {}", e)
      });

    //move dep and native folders from the cargo project dir to the depot dir, for easier referencing
    fs::rename(&cargo_deps, &depot_deps).unwrap();
    fs::rename(&cargo_native, &depot_native).unwrap();

  // Done!
  }
  println!("Build complete.");

}

fn get_version(d: &Dependency) -> String {
  match d {
    &Dependency::Simple(ref version) => {
      version.clone()
    }
    &Dependency::Detailed(ref details) => {
      match details.version {
        Some(ref version) => version.clone(),
        None => "".to_string()
      }
    }
  }
}

fn parse_depot_toml(depot_toml_path: &Path) -> DepotManifest{

  let mut toml_file = File::open(depot_toml_path).unwrap();

  let mut toml_text = String::new();
  toml_file.read_to_string(&mut toml_text).unwrap();

  let root = parse(&toml_text, depot_toml_path);
  let toml_manifest: DepotManifest = toml::decode(toml::Value::Table(root)).unwrap();
  toml_manifest
}

pub fn parse(toml: &str, file: &Path) -> toml::Table {
  let mut parser = toml::Parser::new(&toml);
  match parser.parse() {
    Some(toml) => return toml,
    None => {}
  }
  let mut error_str = format!("could not parse input TOML\n");
  for error in parser.errors.iter() {
    let (loline, locol) = parser.to_linecol(error.lo);
    let (hiline, hicol) = parser.to_linecol(error.hi);
    error_str.push_str(
      &format!("{}:{}:{}{} {}\n",
        file.display(),
        loline + 1,
        locol + 1,
        if loline != hiline || locol != hicol {
          format!("-{}:{}", hiline + 1, hicol + 1)
        } else {
          "".to_string()
        },
        error.desc
      )
    );
  }
  panic!("{}", error_str);
}<|endoftext|>


<commit_before>mod vm;
mod command;
mod parse;
mod program;

use vm::VM;
use program::Program;
use std::io::Write;
use std::env;
use std::path::Path;
use std::fs::File;
use std::io::prelude::*;

fn main() {
    let vm = VM::new();
    let program = Program::new();
    match env::args().nth(1) {
        None => repl(vm, program),
        Some(arg) => interpreter(arg, vm, program),
    }
}

fn repl (mut vm: VM, mut program: Program) -> () {
    loop {
        print!("{}", if program.is_seeking {"... "} else {"bf> "});
        std::io::stdout().flush().unwrap();

        let mut line = String::new();
        let commands = match std::io::stdin().read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => parse::parse(&line),
            Err(error) => panic!(error),
        };
        program.append(&commands);
        program.execute(&mut vm);
    }
}

fn interpreter(arg: String, mut vm: VM, mut program: Program) -> () {
    let path = Path::new(&arg);
    let mut contents = String::new();
    File::open(&path)
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();

    program.append(&parse::parse(&contents));
    program.execute(&mut vm);
}
<commit_msg>Simplify qualification with use statement<commit_after>mod vm;
mod command;
mod parse;
mod program;

use vm::VM;
use program::Program;
use parse::parse;
use std::io::Write;
use std::env;
use std::path::Path;
use std::fs::File;
use std::io::prelude::*;

fn main() {
    let vm = VM::new();
    let program = Program::new();
    match env::args().nth(1) {
        None => repl(vm, program),
        Some(arg) => interpreter(arg, vm, program),
    }
}

fn repl (mut vm: VM, mut program: Program) -> () {
    loop {
        print!("{}", if program.is_seeking {"... "} else {"bf> "});
        std::io::stdout().flush().unwrap();

        let mut line = String::new();
        let commands = match std::io::stdin().read_line(&mut line) {
            Ok(0) => break,
            Ok(_) => parse(&line),
            Err(error) => panic!(error),
        };
        program.append(&commands);
        program.execute(&mut vm);
    }
}

fn interpreter(arg: String, mut vm: VM, mut program: Program) -> () {
    let path = Path::new(&arg);
    let mut contents = String::new();
    File::open(&path)
        .unwrap()
        .read_to_string(&mut contents)
        .unwrap();

    program.append(&parse(&contents));
    program.execute(&mut vm);
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
extern crate osmpbfreader;
extern crate postgis;
#[macro_use] extern crate postgres;
#[macro_use] extern crate postgres_derive;

use osmpbfreader::OsmPbfReader;
use osmpbfreader::objects::{OsmId, OsmObj};
use postgis::ewkb::AsEwkbPoint;
use postgis::twkb::Point;
use postgres::{Connection, TlsMode};
use std::fs::File;

#[derive(Debug, ToSql, FromSql)]
#[postgres(name = "point_type")]
enum Type {
    #[postgres(name = "amenity")]
    Amenity,
    #[postgres(name = "shop")]
    Shop,
}

struct Types(Type, String);

fn main() {
    let matches = clap_app!(myapp =>
        (about: "Import points from OSM")
        (@arg db: -d --("database-url") +takes_value +required env("DATABASE_URL") "Sets a database URL")
        (@arg input: +required "Sets the input file to use")
    ).get_matches();

    let database_url = matches.value_of("db").unwrap();
    let conn = Connection::connect(database_url, TlsMode::None).unwrap();

    let add_point = conn.prepare(
        "INSERT INTO points (id, location, type, subtype, name, email, phone, website, opening_hours, operator) \
        VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)"
    ).unwrap();

    let add_tag = conn.prepare(
        "INSERT INTO tags (point_id, key, value) VALUES ($1, $2, $3)"
    ).unwrap();

    let file_path = matches.value_of("input").unwrap();
    let file = File::open(file_path).unwrap();

    let mut pbf = OsmPbfReader::new(&file);

    for obj in pbf.iter().map(Result::unwrap) {
        if !obj.is_node() {
            continue;
        }

        let types_option = get_types(&obj);

        if types_option.is_none() {
            continue;
        }

        let id = get_object_id(&obj);
        let tags = obj.tags();
        let types = types_option.unwrap();
        let location = Point {
            x: obj.node().unwrap().lat(),
            y: obj.node().unwrap().lon(),
        };

        add_point.execute(&[
            &id, &location.as_ewkb(), &types.0, &types.1, &tags.get("name"), &tags.get("email"),
            &tags.get("phone"), &tags.get("website"), &tags.get("opening_hours"), &tags.get("operator")
        ]).unwrap();

        for tag in obj.tags().iter() {
            match tag.0.as_ref() {
                "amenity" | "shop" => continue,
                "created_by" | "name" | "source" => continue,
                "email" | "phone" | "website" => continue,
                "opening_hours" | "operator" => continue,
                _ => ()
            }

            add_tag.execute(&[&id, &tag.0, &tag.1]).unwrap();
        }
    }
}

fn get_object_id(obj: &OsmObj) -> i64 {
    match obj.id() {
        OsmId::Node(id) => id.0,
        OsmId::Way(id) => id.0,
        OsmId::Relation(id) => id.0,
    }
}

fn get_types(obj: &OsmObj) -> Option<Types> {
    let tags = obj.tags();

    if tags.contains_key("amenity") {
        let types = Types(Type::Amenity, tags.get("amenity").unwrap().clone());
        return Some(types);
    }

    if tags.contains_key("shop") {
        let types = Types(Type::Shop, tags.get("shop").unwrap().clone());
        return Some(types);
    }

    None
}
<commit_msg>Use upsert<commit_after>#[macro_use] extern crate clap;
extern crate osmpbfreader;
extern crate postgis;
#[macro_use] extern crate postgres;
#[macro_use] extern crate postgres_derive;

use osmpbfreader::OsmPbfReader;
use osmpbfreader::objects::{OsmId, OsmObj};
use postgis::ewkb::AsEwkbPoint;
use postgis::twkb::Point;
use postgres::{Connection, TlsMode};
use std::fs::File;

#[derive(Debug, ToSql, FromSql)]
#[postgres(name = "point_type")]
enum Type {
    #[postgres(name = "amenity")]
    Amenity,
    #[postgres(name = "shop")]
    Shop,
}

struct Types(Type, String);

fn main() {
    let matches = clap_app!(myapp =>
        (about: "Import points from OSM")
        (@arg db: -d --("database-url") +takes_value +required env("DATABASE_URL") "Sets a database URL")
        (@arg input: +required "Sets the input file to use")
    ).get_matches();

    let database_url = matches.value_of("db").unwrap();
    let conn = Connection::connect(database_url, TlsMode::None).unwrap();

    let add_point = conn.prepare(
        "INSERT INTO points (id, location, type, subtype, name, email, phone, website, opening_hours, operator) \
        VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) \
        ON CONFLICT (id) DO \
        UPDATE SET (location, type, subtype, name, email, phone, website, opening_hours, operator) = \
        (excluded.location, excluded.type, excluded.subtype, excluded.name, excluded.email, excluded.phone, \
        excluded.website, excluded.opening_hours, excluded.operator)"
    ).unwrap();

    let add_tag = conn.prepare(
        "INSERT INTO tags (point_id, key, value) VALUES ($1, $2, $3) \
        ON CONFLICT (point_id, key) DO UPDATE SET value = excluded.value"
    ).unwrap();

    let file_path = matches.value_of("input").unwrap();
    let file = File::open(file_path).unwrap();

    let mut pbf = OsmPbfReader::new(&file);

    for obj in pbf.iter().map(Result::unwrap) {
        if !obj.is_node() {
            continue;
        }

        let types_option = get_types(&obj);

        if types_option.is_none() {
            continue;
        }

        let id = get_object_id(&obj);
        let tags = obj.tags();
        let types = types_option.unwrap();
        let location = Point {
            x: obj.node().unwrap().lat(),
            y: obj.node().unwrap().lon(),
        };

        add_point.execute(&[
            &id, &location.as_ewkb(), &types.0, &types.1, &tags.get("name"), &tags.get("email"),
            &tags.get("phone"), &tags.get("website"), &tags.get("opening_hours"), &tags.get("operator")
        ]).unwrap();

        for tag in obj.tags().iter() {
            match tag.0.as_ref() {
                "amenity" | "shop" => continue,
                "created_by" | "name" | "source" => continue,
                "email" | "phone" | "website" => continue,
                "opening_hours" | "operator" => continue,
                _ => ()
            }

            add_tag.execute(&[&id, &tag.0, &tag.1]).unwrap();
        }
    }
}

fn get_object_id(obj: &OsmObj) -> i64 {
    match obj.id() {
        OsmId::Node(id) => id.0,
        OsmId::Way(id) => id.0,
        OsmId::Relation(id) => id.0,
    }
}

fn get_types(obj: &OsmObj) -> Option<Types> {
    let tags = obj.tags();

    if tags.contains_key("amenity") {
        let types = Types(Type::Amenity, tags.get("amenity").unwrap().clone());
        return Some(types);
    }

    if tags.contains_key("shop") {
        let types = Types(Type::Shop, tags.get("shop").unwrap().clone());
        return Some(types);
    }

    None
}
<|endoftext|>


<commit_before>extern crate regex;
extern crate irc;

mod starred_message;

use irc::client::prelude::*;
use std::default::Default;
use starred_message::StarredMessage;

fn main() {
	let server = IrcServer::from_config(Config{
		owners   : Some(vec!["nabijaczleweli".to_string()]),
		nickname : Some("NabBot".to_string()),
		username : Some("NabBot".to_string()),
		realname : Some("наб's IRC bot".to_string()),
		server   : Some("chat.freenode.net".to_string()),
		use_ssl  : Some(true),
		channels : Some(vec!["#loungecpp".to_string()]),
		user_info: Some("наб's IRC bot".to_string()),
		..Default::default()
	}).unwrap();
	server.identify().unwrap();

	for message in server.iter() {
		if let Ok(message) = message {
			let sender = message.get_source_nickname().map(String::from);

			match Command::from_message_io(Ok(message)) {
				Ok(Command::JOIN(_, _, _))        => println!("I'm in"),
				Ok(Command::PRIVMSG(target, msg)) => {
					let to_self = target == "NabBot";

					if (to_self && msg == "Navaer") || msg == "Navaer, NabBot" {
						server.send_quit("Mára mesta").unwrap();
					} else if to_self && msg.starts_with("add ")  {
						println!("{:?}", StarredMessage::from_message_content(&msg[4..], sender));
					}
				}
				_ => (),
			}
		}
	}
}
<commit_msg>Process and store messages<commit_after>extern crate regex;
extern crate irc;

mod starred_message;

use irc::client::prelude::*;
use std::default::Default;
use starred_message::StarredMessage;

fn main() {
	let server = IrcServer::from_config(Config{
		owners   : Some(vec!["nabijaczleweli".to_string()]),
		nickname : Some("NabBot".to_string()),
		username : Some("NabBot".to_string()),
		realname : Some("наб's IRC bot".to_string()),
		server   : Some("chat.freenode.net".to_string()),
		use_ssl  : Some(true),
		channels : Some(vec!["#loungecpp".to_string()]),
		user_info: Some("наб's IRC bot".to_string()),
		..Default::default()
	}).unwrap();
	server.identify().unwrap();

	let mut starred: Vec<StarredMessage> = Vec::new();

	for message in server.iter() {
		if let Ok(message) = message {
			let sender = message.get_source_nickname().map(String::from);

			match Command::from_message_io(Ok(message)) {
				Ok(Command::JOIN(_, _, _))        => println!("I'm in"),
				Ok(Command::PRIVMSG(target, msg)) => {
					let to_self = target == "NabBot";

					if (to_self && msg == "Navaer") || msg == "Navaer, NabBot" {
						server.send_quit("Mára mesta").unwrap();
					} else if to_self && msg.starts_with("add ") {
						if let Some(star_message) = StarredMessage::from_message_content(&msg[4..], sender) {
							if match starred.iter_mut().find(|fmsg| (&fmsg.sender, &fmsg.message) == (&star_message.sender, &star_message.message)) {
								Some(ref mut existing_message) => {
									existing_message.stars += 1;
									existing_message.starrers.extend(star_message.starrers.clone());
									false
								},
								None => true,
							} {
								starred.push(star_message);  // Can't do it in match arm because it'd borrow starred as &mut twice
							}
						}
					}
				}
				_ => (),
			}
		}
	}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate ecs;

use ecs::{World, BuildData, DataHelper, EntityIter, ModifyData, Process, System};
use ecs::system::{EntityProcess, EntitySystem};
use std::io;

#[derive(Clone, Debug, PartialEq)]
pub struct WorldMap {
    pub width: usize,
    pub height: usize,
    pub map: Vec<char>,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Position {
    pub x: usize,
    pub y: usize,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Velocity {
    pub dx: usize,
    pub dy: usize,
}

pub struct MotionProcess;

impl System for MotionProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for MotionProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
            let mut position = data.position[e];
            let mut velocity = data.velocity[e];
            // only move 1 space per update
            if velocity.dx > 0 {
                if position.x > 0 {
                    position.x += 1;
                }
                velocity.dx -= 1;
            }
            if velocity.dy > 0 {
                if position.y > 0 {
                    position.y += 1;
                }
                velocity.dy -= 1;
            }
            data.position[e] = position;
        }
    }
}

pub struct CommandProcess(pub String);

impl System for CommandProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for CommandProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {

        let mut commands: Vec<&str> = self.0.split_whitespace()
            .rev().collect();
        let mut dx = 0;
        let mut dy = 0;
        while let Some(word) = commands.pop() {
            match word {
                "left" | "l" => {
                    if let Some(val) = commands.pop() {
                        if dx > 0 {
                            dx -= val.parse::<usize>().unwrap_or(1);
                        }
                    }
                },
                "right" | "r" => {
                    if let Some(val) = commands.pop() {
                        if dx < usize::max_value() {
                            dx += val.parse::<usize>().unwrap_or(1);
                        }
                    }
                },
                "up" | "u" => {
                    if let Some(val) = commands.pop() {
                        if dy < usize::max_value() {
                            dy += val.parse::<usize>().unwrap_or(1);
                        }
                    }
                },
                "down" | "d" => {
                    if let Some(val) = commands.pop() {
                        if dy > 0 {
                            dy -= val.parse::<usize>().unwrap_or(1);
                        }
                    }
                },
                _ => {},
            }
        }
        for e in entities {
            let mut velocity = data.velocity[e];
            velocity.dx += dx;
            velocity.dy += dy;
        }
    }
}

pub struct RenderView;

impl System for RenderView {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for RenderView {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
            let ref world_map = data.world_map[e];
            let height = world_map.height;
            let width = world_map.width;
            for i in 0..height {
                for j in 0..width {
                    print!("{}", world_map.map[i * width + j]);
                    if j == width - 1 {
                        println!("");
                    }
                }
            }
        }
    }
}

components! {
    struct WorldComponents {
        #[hot] position: Position,
        #[hot] velocity: Velocity,
        #[hot] world_map: WorldMap,
    }
}

systems! {
    struct WorldSystems<WorldComponents, ()> {
        active: {
            motion: EntitySystem<MotionProcess> = EntitySystem::new(
                MotionProcess,
                aspect!(<WorldComponents> all: [position, velocity])
            ),
            render: EntitySystem<RenderView> = EntitySystem::new(
                RenderView,
                aspect!(<WorldComponents> all: [world_map])
            ),
            command: EntitySystem<CommandProcess> = EntitySystem::new(
                CommandProcess("idle".to_string()),
                aspect!(<WorldComponents> all: [velocity]),
            ),
        },
        passive: {}
    }
}

fn main() {
    let mut world = World::<WorldSystems>::new();
    let entity = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        data.position.add(&entity, Position { x: 0, y: 0 });
        data.velocity.add(&entity, Velocity { dx: 0, dy: 0 });
    });
    let world_map = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        let map_matrix = vec![
            '🌲', '🌲', '🌲', '🌳', '🌲', '🌲', '🌲', '🌲', '🌲', '🌲',
            '🌲',  '_',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '🏠',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲', '🌲', '🌲', '🌳', '🌲', '🌲', '🌲', '🌲', '🌲', '🌲'
        ];
        data.world_map.add(&entity, WorldMap { width: 10, height: 10, map: map_matrix });
    });

    loop {
        let mut input = String::new();
        if let Ok(_) = io::stdin().read_line(&mut input) {
            world.systems.command.0 = input;
        }
        world.update();
    }
}
<commit_msg>Update player can move around simple map. 😀<commit_after>#[macro_use]
extern crate ecs;

use ecs::{World, BuildData, DataHelper, EntityIter, ModifyData, Process, System};
use ecs::system::{EntityProcess, EntitySystem};
use std::io;

#[derive(Clone, Debug, PartialEq)]
pub struct WorldMap {
    pub width: usize,
    pub height: usize,
    pub map: Vec<char>,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Player {
    pub avatar: char,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Position {
    pub x: i64,
    pub y: i64,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Velocity {
    pub dx: i64,
    pub dy: i64,
}

pub struct MotionProcess;

impl System for MotionProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for MotionProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        println!("Motion {}", entities.clone().count());
        for e in entities {
            let mut position = data.position[e];
            let velocity = data.velocity[e];
            position.x += velocity.dx;
            position.y += velocity.dy;
            data.position[e] = position;
            println!("{:?}", position);
        }
    }
}

pub struct CommandProcess(pub String);

impl System for CommandProcess {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for CommandProcess {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {

        let mut commands: Vec<&str> = self.0.split_whitespace()
            .rev().collect();
        let mut dx = 0;
        let mut dy = 0;
        while let Some(word) = commands.pop() {
            match word {
                "left" | "l" => {
                    if let Some(val) = commands.pop() {
                        dx -= val.parse::<i64>().unwrap_or(1);
                    } else {
                        dx -= 1;
                    }
                },
                "right" | "r" => {
                    if let Some(val) = commands.pop() {
                        dx += val.parse::<i64>().unwrap_or(1);
                    } else {
                        dx += 1;
                    }
                },
                "up" | "u" => {
                    if let Some(val) = commands.pop() {
                        dy += val.parse::<i64>().unwrap_or(1);
                    } else {
                        dy += 1;
                    }
                },
                "down" | "d" => {
                    if let Some(val) = commands.pop() {
                        dy -= val.parse::<i64>().unwrap_or(1);
                    } else {
                        dy -= 1;
                    }
                },
                _ => {},
            }
        }
        for e in entities {
            let mut velocity = data.velocity[e];
            velocity.dx += dx;
            velocity.dy += dy;
            data.velocity[e] = velocity;
            println!("{:?}", velocity);
        }
    }
}

pub struct RenderView;

impl System for RenderView {
    type Components = WorldComponents;
    type Services = ();
}

impl EntityProcess for RenderView {
    fn process(&mut self,
               entities: EntityIter<WorldComponents>,
               data: &mut DataHelper<WorldComponents, ()>) {
        for e in entities {
            let ref world_map = data.world_map[e];
            let ref position = data.position[e];
            let ref player = data.player[e];
            let height = world_map.height;
            let width = world_map.width;
            for i in 0..height {
                for j in 0..width {
                    if i == position.x as usize && j == position.y as usize {
                        print!("{}", player.avatar);
                    } else {
                        print!("{}", world_map.map[i * width + j]);
                    }
                    if j == width - 1 {
                        println!("");
                    }
                }
            }
        }
    }
}

components! {
    struct WorldComponents {
        #[hot] player: Player,
        #[hot] position: Position,
        #[hot] velocity: Velocity,
        #[hot] world_map: WorldMap,
    }
}

systems! {
    struct WorldSystems<WorldComponents, ()> {
        active: {
            motion: EntitySystem<MotionProcess> = EntitySystem::new(
                MotionProcess,
                aspect!(<WorldComponents> all: [position, velocity]),
            ),
            render: EntitySystem<RenderView> = EntitySystem::new(
                RenderView,
                aspect!(<WorldComponents> all: [world_map, position]),
            ),
            command: EntitySystem<CommandProcess> = EntitySystem::new(
                CommandProcess("idle".to_string()),
                aspect!(<WorldComponents> all: [velocity]),
            ),
        },
        passive: {}
    }
}

fn main() {
    let mut world = World::<WorldSystems>::new();
    let entity = world.create_entity(|entity: BuildData<WorldComponents>,
                                      data: &mut WorldComponents| {
        data.position.add(&entity, Position { x: 0, y: 0 });
        data.velocity.add(&entity, Velocity { dx: 0, dy: 0 });
        data.player.add(&entity, Player { avatar: '😀' });
        let map_matrix = vec![
            '🌲', '🌲', '🌲', '🌳', '🌲', '🌲', '🌲', '🌲', '🌲', '🌲',
            '🌲',  '_',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '🏠',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲',  '.',  '.',  '.',  '.',  '.',  '.',  '.',  '.', '🌲',
            '🌲', '🌲', '🌲', '🌳', '🌲', '🌲', '🌲', '🌲', '🌲', '🌲'
        ];
        data.world_map.add(&entity, WorldMap { width: 10, height: 10, map: map_matrix });
    });

    loop {
        let mut input = String::new();
        if let Ok(_) = io::stdin().read_line(&mut input) {
            world.systems.command.0 = input;
            world.update();
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::cmp::min;

struct Board {
    width: usize,
    height: usize,
    queens: Vec<(usize, usize)>
}

impl Board {
    fn display(&self) {
        let mut squares = vec![vec![false; self.height]; self.width];

        for queen in &self.queens {
            let &(qi, qj) = queen;
            squares[qi][qj] = true;
        }

        for row in squares {
            let mut line = String::from("");
            for square in row {
                match square {
                    true => line += "Q ",
                    false => line += ". "
                }
            }
            println!("{}", line);
        }
    }
}

fn incorrect(board : &Board) -> bool {
    for queen in &board.queens {
        let &(qi, qj) = queen;
        for other_queen in &board.queens {
            let &(oi, oj) = other_queen;
            let h_diff = max(oi, qi) - min(oi, qi);
            let v_diff = max(oj, qj) - min(oj, qj);

            if oi == qi && oj == qj {
                continue;
            } else if oi == qi || oj == qj || h_diff == v_diff {
                return true;
            }
        }
    }

    return false;
}

fn correct(board : &Board, queen_number: usize) -> bool {
    if board.queens.len() == queen_number {
        return true;
    } else {
        return false;
    }
}

fn followup(board : &Board) -> Vec<Board> {
    return vec![];
}

fn backtrack(board : &Board) {

}

fn main() {
    let queens = vec![(1, 1), (2, 3)];
    let board = Board { width: 8, height: 8, queens: queens };
    board.display();
}
<commit_msg>Complete the backtrack algorithm.<commit_after>use std::cmp::max;
use std::cmp::min;

struct Board {
    width: usize,
    height: usize,
    queens: Vec<(usize, usize)>
}

impl Board {
    fn new(board: &Board) -> Board {
        return Board {
            width: board.width,
            height: board.height,
            queens: board.queens.to_vec()
        }
    }

    fn display(&self) {
        let mut squares = vec![vec![false; self.height]; self.width];

        for queen in &self.queens {
            let &(qi, qj) = queen;
            squares[qi][qj] = true;
        }

        for row in squares {
            let mut line = String::from("");
            for square in row {
                match square {
                    true => line += "Q ",
                    false => line += ". "
                }
            }
            println!("{}", line);
        }
    }
}

struct BoardGenerator {
    initial_board: Board,
    i: usize,
    j: usize
}

impl BoardGenerator {
    fn from(board: Board) -> BoardGenerator {
        return BoardGenerator {
            initial_board: board,
            i: 0,
            j: 0
        }
    }

    fn next(&mut self) -> Option<Board> {
        self.j += 1;

        if self.j >= self.initial_board.height {
            self.i += 1;
            self.j = 0;
        }

        if self.i >= self.initial_board.width {
            return None;
        }

        match self.initial_board.queens.binary_search(&(self.i, self.j)) {
            Ok(_) => return self.next(),
            Err(idx) => {
                let mut next_board = Board::new(&self.initial_board);
                next_board.queens.insert(idx, (self.i, self.j));
                return Some(next_board);
            }
        }
    }
}

fn incorrect(board : &Board) -> bool {
    for queen in &board.queens {
        let &(qi, qj) = queen;
        for other_queen in &board.queens {
            let &(oi, oj) = other_queen;
            let h_diff = max(oi, qi) - min(oi, qi);
            let v_diff = max(oj, qj) - min(oj, qj);

            if oi == qi && oj == qj {
                continue;
            } else if oi == qi || oj == qj || h_diff == v_diff {
                return true;
            }
        }
    }

    return false;
}

fn correct(board : &Board, queen_number: usize) -> bool {
    if board.queens.len() == queen_number {
        return true;
    } else {
        return false;
    }
}

fn backtrack(board : Board, queen_requirement: usize) -> Option<Board> {
    if incorrect(&board) { return None; }
    if correct(&board, queen_requirement) { return Some(board) }

    let mut generator = BoardGenerator::from(board);
    while let Some(next_board) = generator.next() {
        if let Some(solution) = backtrack(next_board, queen_requirement) {
            return Some(solution);
        }
    }

    return None;
}

fn main() {
    let board = Board { width: 8, height: 8, queens: vec![] };
    if let Some(solution) = backtrack(board, 8) {
        solution.display();
    } else {
        println!("No solution found.")
    }
}
<|endoftext|>


<commit_before>extern crate glob;
extern crate rustc_serialize;

use std::collections::{HashMap, HashSet, hash_map};
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::process::Command;
use std::fs::metadata;

const MAX_REV_DEP_COUNT: usize = 100;

#[derive(RustcDecodable)]
#[allow(dead_code)]
struct CrateInfo {
    name: String,
    vers: String,
    deps: Vec<DepInfo>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

#[derive(RustcDecodable)]
#[allow(dead_code)]
struct DepInfo {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>
}

// shallowly download the index, if necessary
fn fetch_index() {
    if metadata(std::path::PathBuf::from("crates.io-index")).is_ok() {
        return
    }

    Command::new("git")
        .arg("clone")
        .arg("--depth").arg("1")
        .arg("https://github.com/rust-lang/crates.io-index")
        .spawn()
        .unwrap()
        .wait()
        .unwrap();
}

fn main() {
    fetch_index();

    let mut opts = glob::MatchOptions::new();
    opts.require_literal_leading_dot = true;

    let mut crates = vec![];
    let mut edges = vec![];
    let mut interacts = HashSet::new();
    let mut rev_dep_count = HashMap::new();

    let index_paths1 = glob::glob_with("crates.io-index/*/*/*", &opts).unwrap();

    let index_paths2 = glob::glob_with("crates.io-index/[12]/*", &opts).unwrap();

    for path in index_paths1.chain(index_paths2) {
        let path = path.unwrap();

        let file = File::open(&path).unwrap();
        let last_line = BufReader::new(file).lines().last().unwrap().unwrap();
        let crate_info: CrateInfo = rustc_serialize::json::decode(&*last_line).unwrap();

        crates.push(crate_info.name.clone());

        let mut deps = crate_info.deps.iter()
            // remove dev dependencies
            .filter(|d| d.kind.as_ref().map_or(true, |s| &**s != "dev"))
            // we only need the name
            .map(|d| &d.name)
            .collect::<Vec<_>>();

        // it has dependencies, it links into the package ecosystem, yay!
        if !deps.is_empty() {
            interacts.insert(crate_info.name.clone());
        }

        // remove any duplicates
        deps.sort();
        deps.dedup();

        // register all the dependencies
        for &dep_name in deps.iter() {
            interacts.insert(dep_name.clone());
            edges.push((crate_info.name.clone(), dep_name.clone()));

            let count = match rev_dep_count.entry(dep_name.clone()) {
                hash_map::Entry::Occupied(o) => o.into_mut(),
                hash_map::Entry::Vacant(v) => v.insert(0)
            };
            *count += 1;
        }
    }

    crates.retain(|name| // interacts.contains(name) && // done externally
                  rev_dep_count.get(name).map_or(true, |n| *n <= MAX_REV_DEP_COUNT));
    edges.retain(|&(ref source, ref target)|
                 rev_dep_count.get(source).map_or(true, |n| *n <= MAX_REV_DEP_COUNT) &&
                 rev_dep_count.get(target).map_or(true, |n| *n <= MAX_REV_DEP_COUNT));

    // it would be nice to use the `graphviz` crate, but that doesn't
    // seem to allow attaching arbitrary attributes at the moment.
    println!("digraph cratesio {{");
    for krate in crates.iter() {
        let count = rev_dep_count.get(krate).map_or(0, |n| *n);
        println!("  {ident}[label=\"{name}\" href=\"https://crates.io/crates/{name}\" fontsize={size}]",
                 ident = krate.replace("-", "_"),
                 name = krate,
                 size = 14.0 + count as f64 / 2.0);
    }
    for &(ref source, ref target) in edges.iter() {
        println!("  {} -> {}", source.replace("-", "_"), target.replace("-", "_"))
    }

    println!("}}");
}
<commit_msg>Use `Path` instead of `PathBuf`<commit_after>extern crate glob;
extern crate rustc_serialize;

use std::collections::{HashMap, HashSet, hash_map};
use std::io::prelude::*;
use std::io::BufReader;
use std::fs::File;
use std::process::Command;
use std::fs::metadata;

const MAX_REV_DEP_COUNT: usize = 100;

#[derive(RustcDecodable)]
#[allow(dead_code)]
struct CrateInfo {
    name: String,
    vers: String,
    deps: Vec<DepInfo>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

#[derive(RustcDecodable)]
#[allow(dead_code)]
struct DepInfo {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>
}

// shallowly download the index, if necessary
fn fetch_index() {
    if metadata("crates.io-index").is_ok() {
        return
    }

    Command::new("git")
        .arg("clone")
        .arg("--depth").arg("1")
        .arg("https://github.com/rust-lang/crates.io-index")
        .spawn()
        .unwrap()
        .wait()
        .unwrap();
}

fn main() {
    fetch_index();

    let mut opts = glob::MatchOptions::new();
    opts.require_literal_leading_dot = true;

    let mut crates = vec![];
    let mut edges = vec![];
    let mut interacts = HashSet::new();
    let mut rev_dep_count = HashMap::new();

    let index_paths1 = glob::glob_with("crates.io-index/*/*/*", &opts).unwrap();

    let index_paths2 = glob::glob_with("crates.io-index/[12]/*", &opts).unwrap();

    for path in index_paths1.chain(index_paths2) {
        let path = path.unwrap();

        let file = File::open(&path).unwrap();
        let last_line = BufReader::new(file).lines().last().unwrap().unwrap();
        let crate_info: CrateInfo = rustc_serialize::json::decode(&*last_line).unwrap();

        crates.push(crate_info.name.clone());

        let mut deps = crate_info.deps.iter()
            // remove dev dependencies
            .filter(|d| d.kind.as_ref().map_or(true, |s| &**s != "dev"))
            // we only need the name
            .map(|d| &d.name)
            .collect::<Vec<_>>();

        // it has dependencies, it links into the package ecosystem, yay!
        if !deps.is_empty() {
            interacts.insert(crate_info.name.clone());
        }

        // remove any duplicates
        deps.sort();
        deps.dedup();

        // register all the dependencies
        for &dep_name in deps.iter() {
            interacts.insert(dep_name.clone());
            edges.push((crate_info.name.clone(), dep_name.clone()));

            let count = match rev_dep_count.entry(dep_name.clone()) {
                hash_map::Entry::Occupied(o) => o.into_mut(),
                hash_map::Entry::Vacant(v) => v.insert(0)
            };
            *count += 1;
        }
    }

    crates.retain(|name| // interacts.contains(name) && // done externally
                  rev_dep_count.get(name).map_or(true, |n| *n <= MAX_REV_DEP_COUNT));
    edges.retain(|&(ref source, ref target)|
                 rev_dep_count.get(source).map_or(true, |n| *n <= MAX_REV_DEP_COUNT) &&
                 rev_dep_count.get(target).map_or(true, |n| *n <= MAX_REV_DEP_COUNT));

    // it would be nice to use the `graphviz` crate, but that doesn't
    // seem to allow attaching arbitrary attributes at the moment.
    println!("digraph cratesio {{");
    for krate in crates.iter() {
        let count = rev_dep_count.get(krate).map_or(0, |n| *n);
        println!("  {ident}[label=\"{name}\" href=\"https://crates.io/crates/{name}\" fontsize={size}]",
                 ident = krate.replace("-", "_"),
                 name = krate,
                 size = 14.0 + count as f64 / 2.0);
    }
    for &(ref source, ref target) in edges.iter() {
        println!("  {} -> {}", source.replace("-", "_"), target.replace("-", "_"))
    }

    println!("}}");
}
<|endoftext|>


<commit_before>extern crate piston_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

use piston_window::Transformed;

mod game;
mod screen;
mod object;
mod events;

fn main() {
    let mut game = game::Game::new();
    game.run();
}
<commit_msg>Unused import has been removed<commit_after>extern crate piston_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

mod game;
mod screen;
mod object;
mod events;

fn main() {
    let mut game = game::Game::new();
    game.run();
}
<|endoftext|>


<commit_before>#![feature(advanced_slice_patterns, slice_patterns)]

extern crate git_together;

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

use git_together::GitTogether;
use git_together::author::AuthorParser;
use git_together::errors::*;
use git_together::git::{Config, GitConfig};

fn main() {
  run(|| {
    let all_args: Vec<_> = env::args().skip(1).collect();
    let args: Vec<&str> = all_args.iter().map(String::as_ref).collect();

    match args.as_slice() {
      &["with"] => {
        let mut gt = git_together()?;

        gt.set_active(&[])?;
        let authors = gt.all_authors()?;
        let mut sorted: Vec<_> = authors.iter().collect();
        sorted.sort_by(|a, b| a.0.cmp(b.0));

        for (initials, author) in sorted {
          println!("{}: {}", initials, author);
        }
      }
      &["with", ref inits..] => {
        let mut gt = git_together()?;

        let authors = gt.set_active(inits)?;
        for author in authors {
          println!("{}", author);
        }
      }
      &[sub_cmd, ref rest..] if ["commit", "merge", "revert"]
        .contains(&sub_cmd) => {
        let mut gt = git_together()?;

        if sub_cmd == "merge" {
          env::set_var("GIT_TOGETHER_NO_SIGNOFF", "1");
        }

        let mut cmd = Command::new("git");
        let cmd = cmd.arg(sub_cmd).args(rest);

        let signoff = gt.signoff(cmd)?;
        let status = signoff.status()
          .chain_err(|| "failed to execute process")?;
        if status.success() {
          gt.rotate_active()?;
        }
      }
      args => {
        Command::new("git").args(args)
          .status()
          .chain_err(|| "failed to execute process")?;
      }
    };

    Ok(())
  })
}

fn git_together() -> Result<GitTogether<GitConfig>> {
  let mut config = GitConfig::new("git-together")?;
  config.auto_include();

  let domain = config.get("domain")?;
  let author_parser = AuthorParser { domain: domain };

  Ok(GitTogether::new(config, author_parser))
}

fn run<F>(f: F)
  where F: Fn() -> Result<()>
{
  if let Err(error) = f() {
    for error in error.iter() {
      println!("{}", error);
    }
    std::process::exit(1);
  }
}
<commit_msg>deref slice match in main<commit_after>#![feature(advanced_slice_patterns, slice_patterns)]

extern crate git_together;

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

use git_together::GitTogether;
use git_together::author::AuthorParser;
use git_together::errors::*;
use git_together::git::{Config, GitConfig};

fn main() {
  run(|| {
    let all_args: Vec<_> = env::args().skip(1).collect();
    let args: Vec<&str> = all_args.iter().map(String::as_ref).collect();

    match *args.as_slice() {
      ["with"] => {
        let mut gt = git_together()?;

        gt.set_active(&[])?;
        let authors = gt.all_authors()?;
        let mut sorted: Vec<_> = authors.iter().collect();
        sorted.sort_by(|a, b| a.0.cmp(b.0));

        for (initials, author) in sorted {
          println!("{}: {}", initials, author);
        }
      }
      ["with", ref inits..] => {
        let mut gt = git_together()?;

        let authors = gt.set_active(inits)?;
        for author in authors {
          println!("{}", author);
        }
      }
      [sub_cmd, ref rest..] if ["commit", "merge", "revert"]
        .contains(&sub_cmd) => {
        let mut gt = git_together()?;

        if sub_cmd == "merge" {
          env::set_var("GIT_TOGETHER_NO_SIGNOFF", "1");
        }

        let mut cmd = Command::new("git");
        let cmd = cmd.arg(sub_cmd).args(rest);

        let signoff = gt.signoff(cmd)?;
        let status = signoff.status()
          .chain_err(|| "failed to execute process")?;
        if status.success() {
          gt.rotate_active()?;
        }
      }
      [ref args..] => {
        Command::new("git").args(args)
          .status()
          .chain_err(|| "failed to execute process")?;
      }
    };

    Ok(())
  })
}

fn git_together() -> Result<GitTogether<GitConfig>> {
  let mut config = GitConfig::new("git-together")?;
  config.auto_include();

  let domain = config.get("domain")?;
  let author_parser = AuthorParser { domain: domain };

  Ok(GitTogether::new(config, author_parser))
}

fn run<F>(f: F)
  where F: Fn() -> Result<()>
{
  if let Err(error) = f() {
    for error in error.iter() {
      println!("{}", error);
    }
    std::process::exit(1);
  }
}
<|endoftext|>


<commit_before>// TODO: data xrefs

use super::*;
use zydis;

fn analyze_operand_xrefs(
    // used to determine valid addresses
    layout: &ModuleLayout,
    // used to detect RIP-relative addressing
    pc: zydis::enums::register::Register,
    // used to compute relative addresses
    rva: Rva,
    // used to compute relative addresses
    insn: &zydis::ffi::DecodedInstruction,
    // the operand to inspect
    op: &zydis::ffi::DecodedOperand,
) -> Result<Option<Rva>, Error> {
    match op.ty {
        zydis::enums::OperandType::Unused => Err(Error::NotImplemented("xref from unused register")),
        zydis::enums::OperandType::Register => {
            // like: CALL rbx
            // TODO: for now, don't index unresolved indirect branches
            Ok(None)
        }
        zydis::enums::OperandType::Memory => {
            // like: .text:0000000180001041 FF 15 D1 78 07 00      call    cs:__imp_RtlVirtualUnwind_0
            //           0x0000000000001041:                       call    [0x0000000000079980]
            if pc == op.mem.base && op.mem.disp.has_displacement && op.mem.scale == 0 {
                // RIP-relative
                // this is the default encoding on x64.
                // tools like IDA automatically compute and display the target.
                // CALL [RIP + 0x401000]
                if let zydis::enums::register::Register::NONE = op.mem.index {
                    let target =
                        (rva as i64
                        // TODO: cast from rva (u64) to i64 is lossy.
                        + op.mem.disp.displacement
                        + i64::from(insn.length)) as Rva;

                    if layout.is_rva_valid(target) {
                        Ok(Some(target))
                    } else {
                        // TODO: record this anomaly somewhere.
                        warn!("problem: invalid xref target: memory not in sections");
                        Ok(None)
                    }
                } else {
                    // unsupported
                    // like: CALL [RIP + 4*RCX + 0x401000] ??
                    println!("CALL [RIP + 4*RCX + 0x401000] ??");
                    Err(Error::NotImplemented("xref from RIP-relative, non-zero index memory"))
                }
            } else if op.mem.base == zydis::enums::register::Register::NONE {
                // like: CALL [0x401000] ??
                println!("TODO: other OperandType::Memory branch");
                Err(Error::NotImplemented("xref from non-RIP-relative memory"))
            } else {
                // like: CALL [rbx]
                // like: CALL [rbx + 0x10]
                // TODO: for now, don't index unresolved indirect branches
                Ok(None)
            }
        }
        zydis::enums::OperandType::Pointer => {
            println!("TOEO: operand: pointer");
            Err(Error::NotImplemented("xref from pointer"))
        }
        zydis::enums::OperandType::Immediate => {
            if !op.imm.is_relative {
                println!("TODO: absolute immediate operand");
                Err(Error::NotImplemented("xref from absolute immediate"))
            } else {
                let imm = if op.imm.is_signed {
                    u64_i64(op.imm.value)
                } else {
                    op.imm.value as i64
                };

                // TODO: cast from rva (u64) to i64 is lossy.
                let dst = (rva as i64 + imm + i64::from(insn.length)) as Rva;
                if layout.is_rva_valid(dst) {
                    Ok(Some(dst))
                } else {
                    // TODO: record this anomaly somewhere.
                    warn!("problem: invalid xref target: relative immediate not in sections");
                    Ok(None)
                }
            }
        }
    }
}

pub fn analyze_insn_xrefs(
    layout: &ModuleLayout,
    pc: zydis::enums::register::Register,
    rva: Rva,
    insn: &zydis::ffi::DecodedInstruction,
) -> Result<Vec<Xref>, Error> {
    match insn.mnemonic {
        // see InstructionCategory
        // syscall, sysexit, sysret
        // vmcall, vmmcall
        zydis::enums::mnemonic::Mnemonic::CALL => {
            // a CALL always has an operand, so assume this is ok.
            let op = Workspace::get_first_operand(insn).unwrap();

            let fallthrough = Xref {
                src: rva,
                dst: rva + u64::from(insn.length),
                typ: XrefType::Fallthrough,
            };

            match analyze_operand_xrefs(layout, pc, rva, insn, op)? {
                // TODO: fallthrough is not guaranteed if the function is noret
                Some(dst) => Ok(vec![Xref { src: rva, dst: dst, typ: XrefType::Call }, fallthrough]),
                None => Ok(vec![fallthrough]),
            }
        }
        zydis::enums::mnemonic::Mnemonic::RET
        | zydis::enums::mnemonic::Mnemonic::IRET
        | zydis::enums::mnemonic::Mnemonic::IRETD
        | zydis::enums::mnemonic::Mnemonic::IRETQ => Ok(vec![]),
        zydis::enums::mnemonic::Mnemonic::JMP => {
            // a JMP always has an operand, so assume this is ok.
            let op = Workspace::get_first_operand(insn).unwrap();

            match analyze_operand_xrefs(layout, pc, rva, insn, op)? {
                Some(dst) => Ok(vec![Xref { src: rva, dst: dst, typ: XrefType::UnconditionalJump }]),
                None => Ok(vec![]),
            }
        }
        zydis::enums::mnemonic::Mnemonic::JB
        | zydis::enums::mnemonic::Mnemonic::JBE
        | zydis::enums::mnemonic::Mnemonic::JCXZ
        | zydis::enums::mnemonic::Mnemonic::JECXZ
        | zydis::enums::mnemonic::Mnemonic::JKNZD
        | zydis::enums::mnemonic::Mnemonic::JKZD
        | zydis::enums::mnemonic::Mnemonic::JL
        | zydis::enums::mnemonic::Mnemonic::JLE
        | zydis::enums::mnemonic::Mnemonic::JNB
        | zydis::enums::mnemonic::Mnemonic::JNBE
        | zydis::enums::mnemonic::Mnemonic::JNL
        | zydis::enums::mnemonic::Mnemonic::JNLE
        | zydis::enums::mnemonic::Mnemonic::JNO
        | zydis::enums::mnemonic::Mnemonic::JNP
        | zydis::enums::mnemonic::Mnemonic::JNS
        | zydis::enums::mnemonic::Mnemonic::JNZ
        | zydis::enums::mnemonic::Mnemonic::JO
        | zydis::enums::mnemonic::Mnemonic::JP
        | zydis::enums::mnemonic::Mnemonic::JRCXZ
        | zydis::enums::mnemonic::Mnemonic::JS
        | zydis::enums::mnemonic::Mnemonic::JZ => {
            // a J* always has an operand, so assume this is ok.
            let op = Workspace::get_first_operand(insn).unwrap();

            let fallthrough = Xref {
                src: rva,
                dst: rva + u64::from(insn.length),
                typ: XrefType::Fallthrough,
            };

            match analyze_operand_xrefs(layout, pc, rva, insn, op)? {
                Some(dst) => Ok(vec![
                    Xref { src: rva, dst: dst, typ: XrefType::ConditionalJump, },
                    fallthrough,
                ]),
                None => Ok(vec![fallthrough]),
            }
        }
        zydis::enums::mnemonic::Mnemonic::CMOVB
        | zydis::enums::mnemonic::Mnemonic::CMOVBE
        | zydis::enums::mnemonic::Mnemonic::CMOVL
        | zydis::enums::mnemonic::Mnemonic::CMOVLE
        | zydis::enums::mnemonic::Mnemonic::CMOVNB
        | zydis::enums::mnemonic::Mnemonic::CMOVNBE
        | zydis::enums::mnemonic::Mnemonic::CMOVNL
        | zydis::enums::mnemonic::Mnemonic::CMOVNLE
        | zydis::enums::mnemonic::Mnemonic::CMOVNO
        | zydis::enums::mnemonic::Mnemonic::CMOVNP
        | zydis::enums::mnemonic::Mnemonic::CMOVNS
        | zydis::enums::mnemonic::Mnemonic::CMOVNZ
        | zydis::enums::mnemonic::Mnemonic::CMOVO
        | zydis::enums::mnemonic::Mnemonic::CMOVP
        | zydis::enums::mnemonic::Mnemonic::CMOVS
        | zydis::enums::mnemonic::Mnemonic::CMOVZ => Ok(vec![
            Xref {
                src: rva,
                dst: rva + u64::from(insn.length),
                typ: XrefType::Fallthrough
            },
            Xref {
                src: rva,
                dst: rva + u64::from(insn.length),
                typ: XrefType::ConditionalMove
            },
        ]),
        _ => Ok(vec![Xref {
            src: rva,
            dst: rva + u64::from(insn.length),
            typ: XrefType::Fallthrough,
        }]),
    }
}

<commit_msg>analysis: tweak log levels<commit_after>// TODO: data xrefs

use super::*;
use zydis;

fn analyze_operand_xrefs(
    // used to determine valid addresses
    layout: &ModuleLayout,
    // used to detect RIP-relative addressing
    pc: zydis::enums::register::Register,
    // used to compute relative addresses
    rva: Rva,
    // used to compute relative addresses
    insn: &zydis::ffi::DecodedInstruction,
    // the operand to inspect
    op: &zydis::ffi::DecodedOperand,
) -> Result<Option<Rva>, Error> {
    match op.ty {
        zydis::enums::OperandType::Unused => Err(Error::NotImplemented("xref from unused register")),
        zydis::enums::OperandType::Register => {
            // like: CALL rbx
            // TODO: for now, don't index unresolved indirect branches
            Ok(None)
        }
        zydis::enums::OperandType::Memory => {
            // like: .text:0000000180001041 FF 15 D1 78 07 00      call    cs:__imp_RtlVirtualUnwind_0
            //           0x0000000000001041:                       call    [0x0000000000079980]
            if pc == op.mem.base && op.mem.disp.has_displacement && op.mem.scale == 0 {
                // RIP-relative
                // this is the default encoding on x64.
                // tools like IDA automatically compute and display the target.
                // CALL [RIP + 0x401000]
                if let zydis::enums::register::Register::NONE = op.mem.index {
                    let target =
                        (rva as i64
                        // TODO: cast from rva (u64) to i64 is lossy.
                        + op.mem.disp.displacement
                        + i64::from(insn.length)) as Rva;

                    if layout.is_rva_valid(target) {
                        Ok(Some(target))
                    } else {
                        // TODO: record this anomaly somewhere.
                        warn!("problem: invalid xref target: memory not in sections");
                        Ok(None)
                    }
                } else {
                    // unsupported
                    // like: CALL [RIP + 4*RCX + 0x401000] ??
                    println!("CALL [RIP + 4*RCX + 0x401000] ??");
                    Err(Error::NotImplemented("xref from RIP-relative, non-zero index memory"))
                }
            } else if op.mem.base == zydis::enums::register::Register::NONE {
                // like: CALL [0x401000] ??
                println!("TODO: other OperandType::Memory branch");
                Err(Error::NotImplemented("xref from non-RIP-relative memory"))
            } else {
                // like: CALL [rbx]
                // like: CALL [rbx + 0x10]
                // TODO: for now, don't index unresolved indirect branches
                Ok(None)
            }
        }
        zydis::enums::OperandType::Pointer => {
            println!("TODO: operand: pointer");
            Err(Error::NotImplemented("xref from pointer"))
        }
        zydis::enums::OperandType::Immediate => {
            if !op.imm.is_relative {
                println!("TODO: absolute immediate operand");
                Err(Error::NotImplemented("xref from absolute immediate"))
            } else {
                let imm = if op.imm.is_signed {
                    u64_i64(op.imm.value)
                } else {
                    op.imm.value as i64
                };

                // TODO: cast from rva (u64) to i64 is lossy.
                let dst = (rva as i64 + imm + i64::from(insn.length)) as Rva;
                if layout.is_rva_valid(dst) {
                    Ok(Some(dst))
                } else {
                    // TODO: record this anomaly somewhere.
                    debug!("problem: invalid xref target: relative immediate not in sections");
                    Ok(None)
                }
            }
        }
    }
}

pub fn analyze_insn_xrefs(
    layout: &ModuleLayout,
    pc: zydis::enums::register::Register,
    rva: Rva,
    insn: &zydis::ffi::DecodedInstruction,
) -> Result<Vec<Xref>, Error> {
    match insn.mnemonic {
        // see InstructionCategory
        // syscall, sysexit, sysret
        // vmcall, vmmcall
        zydis::enums::mnemonic::Mnemonic::CALL => {
            // a CALL always has an operand, so assume this is ok.
            let op = Workspace::get_first_operand(insn).unwrap();

            let fallthrough = Xref {
                src: rva,
                dst: rva + u64::from(insn.length),
                typ: XrefType::Fallthrough,
            };

            match analyze_operand_xrefs(layout, pc, rva, insn, op)? {
                // TODO: fallthrough is not guaranteed if the function is noret
                Some(dst) => Ok(vec![Xref { src: rva, dst: dst, typ: XrefType::Call }, fallthrough]),
                None => Ok(vec![fallthrough]),
            }
        }
        zydis::enums::mnemonic::Mnemonic::RET
        | zydis::enums::mnemonic::Mnemonic::IRET
        | zydis::enums::mnemonic::Mnemonic::IRETD
        | zydis::enums::mnemonic::Mnemonic::IRETQ => Ok(vec![]),
        zydis::enums::mnemonic::Mnemonic::JMP => {
            // a JMP always has an operand, so assume this is ok.
            let op = Workspace::get_first_operand(insn).unwrap();

            match analyze_operand_xrefs(layout, pc, rva, insn, op)? {
                Some(dst) => Ok(vec![Xref { src: rva, dst: dst, typ: XrefType::UnconditionalJump }]),
                None => Ok(vec![]),
            }
        }
        zydis::enums::mnemonic::Mnemonic::JB
        | zydis::enums::mnemonic::Mnemonic::JBE
        | zydis::enums::mnemonic::Mnemonic::JCXZ
        | zydis::enums::mnemonic::Mnemonic::JECXZ
        | zydis::enums::mnemonic::Mnemonic::JKNZD
        | zydis::enums::mnemonic::Mnemonic::JKZD
        | zydis::enums::mnemonic::Mnemonic::JL
        | zydis::enums::mnemonic::Mnemonic::JLE
        | zydis::enums::mnemonic::Mnemonic::JNB
        | zydis::enums::mnemonic::Mnemonic::JNBE
        | zydis::enums::mnemonic::Mnemonic::JNL
        | zydis::enums::mnemonic::Mnemonic::JNLE
        | zydis::enums::mnemonic::Mnemonic::JNO
        | zydis::enums::mnemonic::Mnemonic::JNP
        | zydis::enums::mnemonic::Mnemonic::JNS
        | zydis::enums::mnemonic::Mnemonic::JNZ
        | zydis::enums::mnemonic::Mnemonic::JO
        | zydis::enums::mnemonic::Mnemonic::JP
        | zydis::enums::mnemonic::Mnemonic::JRCXZ
        | zydis::enums::mnemonic::Mnemonic::JS
        | zydis::enums::mnemonic::Mnemonic::JZ => {
            // a J* always has an operand, so assume this is ok.
            let op = Workspace::get_first_operand(insn).unwrap();

            let fallthrough = Xref {
                src: rva,
                dst: rva + u64::from(insn.length),
                typ: XrefType::Fallthrough,
            };

            match analyze_operand_xrefs(layout, pc, rva, insn, op)? {
                Some(dst) => Ok(vec![
                    Xref { src: rva, dst: dst, typ: XrefType::ConditionalJump, },
                    fallthrough,
                ]),
                None => Ok(vec![fallthrough]),
            }
        }
        zydis::enums::mnemonic::Mnemonic::CMOVB
        | zydis::enums::mnemonic::Mnemonic::CMOVBE
        | zydis::enums::mnemonic::Mnemonic::CMOVL
        | zydis::enums::mnemonic::Mnemonic::CMOVLE
        | zydis::enums::mnemonic::Mnemonic::CMOVNB
        | zydis::enums::mnemonic::Mnemonic::CMOVNBE
        | zydis::enums::mnemonic::Mnemonic::CMOVNL
        | zydis::enums::mnemonic::Mnemonic::CMOVNLE
        | zydis::enums::mnemonic::Mnemonic::CMOVNO
        | zydis::enums::mnemonic::Mnemonic::CMOVNP
        | zydis::enums::mnemonic::Mnemonic::CMOVNS
        | zydis::enums::mnemonic::Mnemonic::CMOVNZ
        | zydis::enums::mnemonic::Mnemonic::CMOVO
        | zydis::enums::mnemonic::Mnemonic::CMOVP
        | zydis::enums::mnemonic::Mnemonic::CMOVS
        | zydis::enums::mnemonic::Mnemonic::CMOVZ => Ok(vec![
            Xref {
                src: rva,
                dst: rva + u64::from(insn.length),
                typ: XrefType::Fallthrough
            },
            Xref {
                src: rva,
                dst: rva + u64::from(insn.length),
                typ: XrefType::ConditionalMove
            },
        ]),
        _ => Ok(vec![Xref {
            src: rva,
            dst: rva + u64::from(insn.length),
            typ: XrefType::Fallthrough,
        }]),
    }
}

<|endoftext|>


<commit_before>
extern crate ndarray;
extern crate ndarray_linalg as linalg;

use ndarray::prelude::*;
use linalg::Matrix;

fn main() {
    let a = arr2(&[[3.0, 1.0, 1.0], [1.0, 3.0, 1.0], [1.0, 1.0, 3.0]]);
    println!("|a|_1 = {:?}", &a.norm_1());
    println!("|a|_1 = {:?}", &a.norm_i());
    println!("|a|_1 = {:?}", &a.norm_f());
}
<commit_msg>Restore master:src/bin/main.rs<commit_after>
extern crate ndarray;
extern crate ndarray_linalg as linalg;

use ndarray::prelude::*;
use linalg::SquareMatrix;

fn main() {
    let a = arr2(&[[3.0, 1.0, 1.0], [1.0, 3.0, 1.0], [1.0, 1.0, 3.0]]);
    let (e, vecs) = a.clone().eigh().unwrap();
    println!("eigenvalues = \n{:?}", e);
    println!("V = \n{:?}", vecs);
    let av = a.dot(&vecs);
    println!("AV = \n{:?}", av);
}
<|endoftext|>