<commit_before>#![allow(non_snake_case)]

extern crate getopts;
extern crate jni;
extern crate rustc_serialize;

#[cfg(target_os = "macos")]
extern crate libc;

use getopts::Options;
use jni::JNI;
use jni::classpath::load_static_method;
use jni::consts::*;
use jni::ffi;
use jni::ffi::JNIEnv;
use jni::types as jni_types;
use jni::types::{Jclass, Jint};
use rustc_serialize::json;
use std::env;
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

#[cfg(target_os = "macos")]
use libc::{c_int};
#[cfg(target_os = "macos")]
use std::sync::mpsc::{channel, Receiver, Sender};
#[cfg(target_os = "macos")]
use std::thread;

#[derive(RustcDecodable)]
struct Config {
    jar: String,
    mainClass: String,
    vmArgs: Vec<String>
}

#[cfg(target_os = "macos")]
fn get_libjvm_path_os(path: &mut PathBuf) {
    path.push("lib");
    path.push("jli");
    path.push("libjli");
    path.set_extension("dylib");
}

#[cfg(target_os = "linux")]
fn get_libjvm_path_os(path: &mut PathBuf) {
    path.push("lib");
    path.push("amd64");
    path.push("server");
    path.push("libjvm");
    path.set_extension("so");
}

#[cfg(target_os = "windows")]
fn get_libjvm_path_os(path: &mut PathBuf) {
    path.push("bin");
    path.push("server");
    path.push("jvm");
    path.set_extension("dll");
}

fn get_libjvm_path(jre: &Path) -> PathBuf {
    let mut path = PathBuf::new();
    path.push(jre);
    get_libjvm_path_os(&mut path);
    path
}

fn init_jvm_arguments(jni: &mut JNI, config: &Config) {
    let num_args = config.vmArgs.len();

    jni.init_vm_args(num_args);

    for i in 0..num_args {
        let ref vm_arg = config.vmArgs[i];
        jni.push_vm_arg(i, &vm_arg);
    }
}

fn load_jvm(jni: &mut JNI, config: &Config) {
    // create & fill arguments
    init_jvm_arguments(jni, config);

    // load lib, create VM instance
    match jni.create_java_vm() {
        Err(err) => panic!(err),
        Ok(_) => {}
    };

    // attach to current thread
    match ffi::attach_current_thread(jni.get_jvm()) {
        (JNI_OK, _) => {},
        (_, _) => panic!("Could not attach JVM to thread")
    }
    println!("JVM attached to thread ...");
}

fn check_for_exceptions(env: &mut JNIEnv) {
    let throwable = ffi::exception_occured(env);
    if !jni_types::is_null(throwable) {
        ffi::exception_describe(env);
        ffi::exception_clear(env);
        panic!("Exception caught!");
    }
}

fn call_main(env: &mut JNIEnv, path_to_jar: &str, main_class_name: &str, args: &Vec<String>) {

    // do class-loader voodoo

    let (main_class, main_method) = load_static_method(env, path_to_jar, main_class_name);

    match (main_class, main_method) {
        (JNI_NULL, JNI_NULL) => {
            println!("Could not find {}.main()", main_class_name);
            return;
        },
        (_, _) => {}
    };

    // pass program arguments

    let java_lang_String:Jclass = ffi::find_class(env, "java/lang/String");
    check_for_exceptions(env);
    assert!(!jni_types::is_null(java_lang_String));

    let argc = args.len();

    let argv = ffi::new_object_array(env, argc as Jint, java_lang_String, JNI_NULL);
    check_for_exceptions(env);
    assert!(!jni_types::is_null(argv));

    for i in 0..argc {
        println!("Application argument: {}", &args[i]);
        let arg = ffi::new_string_utf(env, &args[i]);
        ffi::set_object_array_element(env, argv, i as Jint, arg);
    }

    // call main()
    ffi::call_static_void_method_a(env, main_class, main_method, &[argv]);

    println!("Quit from JVM ...");
}

fn read_config(path: &Path) -> Config {
    let mut f = match File::open(path) {
        Ok(f) => f,
        Err(_) => panic!("Could not open {}", path.display())
    };

    let mut content = String::new();

    if f.read_to_string(&mut content).is_err() {
        panic!("Error reading {}", path.display());
    }

    let config:Config = json::decode(&content).unwrap();

    println!("jar: {}", config.jar);
    println!("main class: {}", config.mainClass);

    for arg in config.vmArgs.iter() {
        println!("VM argument: {}", arg);
    }

    config
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
    //println!("-- {{args}}\tUnparsed arguments passed through to Java main() method.");
}

fn spawn_vm() {
    let args: Vec<String> = env::args().collect();

    let program = args[0].clone();
    //println!("application: {}", program);

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => {
            println!("{} Run {} --help to show options.", f.to_string(), program);
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    //let root_path = Path::new(&program).parent().unwrap();
    let root_path = env::current_dir().unwrap();
    println!("current directory: {}", root_path.display());

    // change working dir (MacOS: starts at parent folder of .app)
    if env::set_current_dir(&root_path).is_err() {
        panic!("Could not change working directory");
    }

    let libjvmpath = get_libjvm_path(root_path.join("jre").as_path());
    println!("JRE path: {}", libjvmpath.display());

    // read config JSON
    let config = read_config(root_path.join("config.json").as_path());

    let cp_path = Path::new(&config.jar);
    let class_path = format!("{}", cp_path.display());
    println!("class path: {}", class_path);

    println!("Loading JVM library ...");
    let mut jni:JNI = match JNI::new(&libjvmpath) {
        Err(error) => panic!(error),
        Ok(jni) => jni
    };

    println!("JNI initialized.");

    println!("Creating JVM instance ...");
    load_jvm(&mut jni, &config);

    println!("Invoking {}.main()", config.mainClass);
    let env:&mut JNIEnv = jni.get_env();
    call_main(env, &class_path, &config.mainClass, &matches.free);
}

#[cfg(target_os = "macos")]
#[link(name = "packrnative", kind = "static")]
#[link(name = "CoreFoundation", kind = "framework")]
#[link(name = "CoreServices", kind = "framework")]
extern {
    fn cfRunLoopRun(callback: extern fn(&Receiver<c_int>), signal:&Receiver<c_int>);
    fn cfRunLoopStop();
}

#[cfg(target_os = "macos")]
extern fn run_loop_callback(signal:&Receiver<c_int>) {
    match signal.try_recv() {
        Err(_) => {},
        Ok(_) => unsafe {
            cfRunLoopStop();
        }
    }
}

#[cfg(target_os = "macos")]
fn main() {

    let (tx, rx): (Sender<c_int>, Receiver<c_int>) = channel();
    let proc_tx = tx.clone();

    thread::spawn(move|| {
        spawn_vm();
        proc_tx.send(0).unwrap();
    });

    unsafe {
        cfRunLoopRun(run_loop_callback, &rx);
    }
}

#[cfg(not(target_os = "macos"))]
fn main() {
    spawn_vm();
}
<commit_msg>OS X: adjust root path to use executable folder (if started as .app).<commit_after>#![allow(non_snake_case)]

extern crate getopts;
extern crate jni;
extern crate rustc_serialize;

#[cfg(target_os = "macos")]
extern crate libc;

use getopts::Options;
use jni::JNI;
use jni::classpath::load_static_method;
use jni::consts::*;
use jni::ffi;
use jni::ffi::JNIEnv;
use jni::types as jni_types;
use jni::types::{Jclass, Jint};
use rustc_serialize::json;
use std::env;
use std::io::prelude::*;
use std::fs::File;
use std::path::{Path, PathBuf};

#[cfg(target_os = "macos")]
use libc::{c_int};
#[cfg(target_os = "macos")]
use std::sync::mpsc::{channel, Receiver, Sender};
#[cfg(target_os = "macos")]
use std::thread;

#[derive(RustcDecodable)]
struct Config {
    jar: String,
    mainClass: String,
    vmArgs: Vec<String>
}

#[cfg(target_os = "macos")]
fn get_root_path(program:&str) -> &Path {
    Path::new(program).parent().unwrap()
}

#[cfg(not(target_os = "macos"))]
fn get_root_path(program:&str) -> &Path {
    env::current_dir().unwrap()
}

#[cfg(target_os = "macos")]
fn get_libjvm_path_os(path: &mut PathBuf) {
    path.push("lib");
    path.push("jli");
    path.push("libjli");
    path.set_extension("dylib");
}

#[cfg(target_os = "linux")]
fn get_libjvm_path_os(path: &mut PathBuf) {
    path.push("lib");
    path.push("amd64");
    path.push("server");
    path.push("libjvm");
    path.set_extension("so");
}

#[cfg(target_os = "windows")]
fn get_libjvm_path_os(path: &mut PathBuf) {
    path.push("bin");
    path.push("server");
    path.push("jvm");
    path.set_extension("dll");
}

fn get_libjvm_path(jre: &Path) -> PathBuf {
    let mut path = PathBuf::new();
    path.push(jre);
    get_libjvm_path_os(&mut path);
    path
}

fn init_jvm_arguments(jni: &mut JNI, config: &Config) {
    let num_args = config.vmArgs.len();

    jni.init_vm_args(num_args);

    for i in 0..num_args {
        let ref vm_arg = config.vmArgs[i];
        jni.push_vm_arg(i, &vm_arg);
    }
}

fn load_jvm(jni: &mut JNI, config: &Config) {
    // create & fill arguments
    init_jvm_arguments(jni, config);

    // load lib, create VM instance
    match jni.create_java_vm() {
        Err(err) => panic!(err),
        Ok(_) => {}
    };

    // attach to current thread
    match ffi::attach_current_thread(jni.get_jvm()) {
        (JNI_OK, _) => {},
        (_, _) => panic!("Could not attach JVM to thread")
    }
    println!("JVM attached to thread ...");
}

fn check_for_exceptions(env: &mut JNIEnv) {
    let throwable = ffi::exception_occured(env);
    if !jni_types::is_null(throwable) {
        ffi::exception_describe(env);
        ffi::exception_clear(env);
        panic!("Exception caught!");
    }
}

fn call_main(env: &mut JNIEnv, path_to_jar: &str, main_class_name: &str, args: &Vec<String>) {

    // do class-loader voodoo

    let (main_class, main_method) = load_static_method(env, path_to_jar, main_class_name);

    match (main_class, main_method) {
        (JNI_NULL, JNI_NULL) => {
            println!("Could not find {}.main()", main_class_name);
            return;
        },
        (_, _) => {}
    };

    // pass program arguments

    let java_lang_String:Jclass = ffi::find_class(env, "java/lang/String");
    check_for_exceptions(env);
    assert!(!jni_types::is_null(java_lang_String));

    let argc = args.len();

    let argv = ffi::new_object_array(env, argc as Jint, java_lang_String, JNI_NULL);
    check_for_exceptions(env);
    assert!(!jni_types::is_null(argv));

    for i in 0..argc {
        println!("Application argument: {}", &args[i]);
        let arg = ffi::new_string_utf(env, &args[i]);
        ffi::set_object_array_element(env, argv, i as Jint, arg);
    }

    // call main()
    ffi::call_static_void_method_a(env, main_class, main_method, &[argv]);

    check_for_exceptions(env);

    println!("Quit from JVM ...");
}

fn read_config(path: &Path) -> Config {
    let mut f = match File::open(path) {
        Ok(f) => f,
        Err(_) => panic!("Could not open {}", path.display())
    };

    let mut content = String::new();

    if f.read_to_string(&mut content).is_err() {
        panic!("Error reading {}", path.display());
    }

    let config:Config = json::decode(&content).unwrap();

    println!("jar: {}", config.jar);
    println!("main class: {}", config.mainClass);

    for arg in config.vmArgs.iter() {
        println!("VM argument: {}", arg);
    }

    config
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
    //println!("-- {{args}}\tUnparsed arguments passed through to Java main() method.");
}

fn spawn_vm() {
    let args: Vec<String> = env::args().collect();

    let program = args[0].clone();
    println!("application: {}", program);

    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => {
            println!("{} Run {} --help to show options.", f.to_string(), program);
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let root_path = get_root_path(&program);
    println!("current directory: {}", root_path.display());

    // change working dir (MacOS: starts at parent folder of .app)
    if env::set_current_dir(&root_path).is_err() {
        panic!("Could not change working directory");
    }

    let libjvmpath = get_libjvm_path(root_path.join("jre").as_path());
    println!("JRE path: {}", libjvmpath.display());

    // read config JSON
    let config = read_config(root_path.join("config.json").as_path());

    let cp_path = Path::new(&config.jar);
    let class_path = format!("{}", cp_path.display());
    println!("class path: {}", class_path);

    println!("Loading JVM library ...");
    let mut jni:JNI = match JNI::new(&libjvmpath) {
        Err(error) => panic!(error),
        Ok(jni) => jni
    };

    println!("JNI initialized.");

    println!("Creating JVM instance ...");
    load_jvm(&mut jni, &config);

    println!("Invoking {}.main()", config.mainClass);
    let env:&mut JNIEnv = jni.get_env();
    call_main(env, &class_path, &config.mainClass, &matches.free);
}

#[cfg(target_os = "macos")]
#[link(name = "packrnative", kind = "static")]
#[link(name = "CoreFoundation", kind = "framework")]
#[link(name = "CoreServices", kind = "framework")]
extern {
    fn cfRunLoopRun(callback: extern fn(&Receiver<c_int>), signal:&Receiver<c_int>);
    fn cfRunLoopStop();
}

#[cfg(target_os = "macos")]
extern fn run_loop_callback(signal:&Receiver<c_int>) {
    match signal.try_recv() {
        Err(_) => {},
        Ok(_) => unsafe {
            cfRunLoopStop();
        }
    }
}

#[cfg(target_os = "macos")]
fn main() {

    let (tx, rx): (Sender<c_int>, Receiver<c_int>) = channel();
    let proc_tx = tx.clone();

    thread::spawn(move|| {
        spawn_vm();
        proc_tx.send(0).unwrap();
    });

    unsafe {
        cfRunLoopRun(run_loop_callback, &rx);
    }
}

#[cfg(not(target_os = "macos"))]
fn main() {
    spawn_vm();
}
<|endoftext|>


<commit_before>// Copyright © 2014, Canal TP and/or its affiliates. All rights reserved.
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.

#![feature(plugin, core, path)]

extern crate csv;
extern crate "rustc-serialize" as rustc_serialize;
extern crate curl;
extern crate docopt;
#[plugin] #[no_link] extern crate docopt_macros;

mod index;
mod bano;

fn index_bano(files: &[String]) {
    println!("purge and create Munin...");
    index::purge_and_create_munin().unwrap();
    println!("Munin purged and created.");

    for f in files.iter() {
        println!("importing {}...", f);
        let mut rdr = csv::Reader::from_file(&Path::new(&*f)).has_headers(false);
        let iter = rdr.decode().map(|r| { let b: bano::Bano = r.unwrap(); b.into_addr() });
        let nb = index::index(iter).unwrap();
        println!("importing {}: {} addresses added.", f, nb);
    }
}

fn to_json_string(s: &str) -> String {
    // TODO: escape string!
    s.to_string()
}

fn query(q: &str) -> Result<(), curl::ErrCode> {
    let query = format!(include_str!("../json/query.json"), query=&*to_json_string(q));
    println!("{}", query);
    let r = try! {
        curl::http::handle().post("http://localhost:9200/munin/_search?pretty", &*query)
            .exec()
    };
    println!("{}", r);
    Ok(())
}

fn geocode(lon: f64, lat: f64) -> Result<(), curl::ErrCode> {
    let query = format!(include_str!("../json/geocode.json"), lon=lon, lat=lat);
    println!("{}", query);
    let r = try! {
        curl::http::handle().post("http://localhost:9200/munin/addr/_search?pretty&size=1", &*query)
            .exec()
    };
    println!("{}", r);
    Ok(())
}

docopt!(Args derive Debug, "
Usage:
    munin index <bano-files>...
    munin query <query>
    munin geocode [--] <lon> <lat>
", arg_lon: Option<f64>, arg_lat: Option<f64>);

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    if args.cmd_index {
        index_bano(&*args.arg_bano_files);
    } else if args.cmd_query {
        query(&*args.arg_query).unwrap();
    } else if args.cmd_geocode {
        geocode(args.arg_lon.unwrap(), args.arg_lat.unwrap()).unwrap();
    } else {
        unreachable!();
    }

}
<commit_msg>fix query<commit_after>// Copyright © 2014, Canal TP and/or its affiliates. All rights reserved.
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.

#![feature(plugin, core, path)]

extern crate csv;
extern crate "rustc-serialize" as rustc_serialize;
extern crate curl;
extern crate docopt;
#[plugin] #[no_link] extern crate docopt_macros;

mod index;
mod bano;

fn index_bano(files: &[String]) {
    println!("purge and create Munin...");
    index::purge_and_create_munin().unwrap();
    println!("Munin purged and created.");

    for f in files.iter() {
        println!("importing {}...", f);
        let mut rdr = csv::Reader::from_file(&Path::new(&*f)).has_headers(false);
        let iter = rdr.decode().map(|r| { let b: bano::Bano = r.unwrap(); b.into_addr() });
        let nb = index::index(iter).unwrap();
        println!("importing {}: {} addresses added.", f, nb);
    }
}

fn to_json_string(s: &str) -> String {
    // TODO: escape string!
    let mut res = "\"".to_string();
    res.push_str(s);
    res.push_str("\"");
    res
}

fn query(q: &str) -> Result<(), curl::ErrCode> {
    let query = format!(include_str!("../json/query.json"), query=&*to_json_string(q));
    println!("{}", query);
    let r = try! {
        curl::http::handle().post("http://localhost:9200/munin/_search?pretty", &*query)
            .exec()
    };
    println!("{}", r);
    Ok(())
}

fn geocode(lon: f64, lat: f64) -> Result<(), curl::ErrCode> {
    let query = format!(include_str!("../json/geocode.json"), lon=lon, lat=lat);
    println!("{}", query);
    let r = try! {
        curl::http::handle().post("http://localhost:9200/munin/addr/_search?pretty&size=1", &*query)
            .exec()
    };
    println!("{}", r);
    Ok(())
}

docopt!(Args derive Debug, "
Usage:
    munin index <bano-files>...
    munin query <query>
    munin geocode [--] <lon> <lat>
", arg_lon: Option<f64>, arg_lat: Option<f64>);

fn main() {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());

    if args.cmd_index {
        index_bano(&*args.arg_bano_files);
    } else if args.cmd_query {
        query(&*args.arg_query).unwrap();
    } else if args.cmd_geocode {
        geocode(args.arg_lon.unwrap(), args.arg_lat.unwrap()).unwrap();
    } else {
        unreachable!();
    }

}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate assimp;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;

use assimp::Vector3D;

fn sort_points_by_y(points: &mut Vec<Point>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y() > points[j + 1].y() {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_ine(&mut self, i32, Point, Point, Point, Point, Color);
    fn triangle(&mut self, Point, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_ine(&mut self, y: i32, pa: Point, pb: Point, pc: Point, pd: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let grad1 = match (&pa.y()).cmp(&pb.y()) {
            Ordering::Equal => 1.,
            _ => (y - pa.y()) as f32 / (pb.y()- pa.y()) as f32
        };

        let grad2 = match (&pc.y()).cmp(&pd.y()) {
            Ordering::Equal => 1.,
            _ => (y - pc.y()) as f32 / (pd.y() - pc.y()) as f32
        };

        let sx = interpolate(pa.x() as f32, pb.x() as f32, grad1) as i32;
        let ex = interpolate(pc.x() as f32, pd.x() as f32, grad2) as i32;

        for x in sx..ex {
            self.draw_point(Point::new(x, y)).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn triangle(&mut self, p0: Point, p1: Point, p2: Point, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match (points[1].y() - points[0].y()).cmp(&0) {
            Ordering::Greater => (points[1].x() - points[0].x()) as f32 / (points[1].y() - points[0].y()) as f32,
            _ => 0.
        };

        let dp0p2 = match (points[2].y() - points[0].y()).cmp(&0) {
            Ordering::Greater => (points[2].x() - points[0].x()) as f32 / (points[2].y() - points[0].y()) as f32,
            _ => 0.
        };

        for y in points[0].y()..points[2].y() {
            if y < points[1].y() {
                if dp0p1 > dp0p2 {
                    self.process_scan_ine(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_ine(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_ine(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_ine(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn main() {
    let (width, height) = (600, 600);
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", width, height)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            for j in 0..3 {
                let v0 = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let v1 = match mesh.get_vertex(face[(j + 1) % 3]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let x0 = width as i32 - ((v0.x + 1.) * width as f32 / 2.) as i32;
                let y0 = height as i32 - ((v0.y + 1.) * height as f32 / 2.) as i32;
                let x1 = width as i32 - ((v1.x + 1.) * width as f32 / 2.) as i32;
                let y1 = height as i32 - ((v1.y + 1.) * height as f32 / 2.) as i32;

                renderer.line(Point::new(x0, y0), Point::new(x1, y1), Color::RGB(255, 255, 255));
            }
        }
    }

    renderer.triangle(Point::new(10, 10), Point::new(100, 30), Point::new(190, 160), Color::RGB(0, 255, 0));

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<commit_msg>Fill mesh vertex with light intensity<commit_after>extern crate sdl2;
extern crate assimp;
extern crate cgmath;

use assimp::Importer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::rect::Point;
use sdl2::render::Renderer;
use std::cmp::Ordering;
use cgmath::InnerSpace;
use cgmath::Vector3;
use cgmath::Zero;

use assimp::Vector3D;

fn sort_points_by_y(points: &mut Vec<Point>) {
    for _ in 0..(points.len() - 1) {
        for j in 0..(points.len() - 1) {
            if points[j].y() > points[j + 1].y() {
                points.swap(j, j + 1);
            }
        }
    }
}

fn clamp<N>(a: N, min: N, max: N) -> N where N: PartialOrd {
    if a < min { return min }
    if a > max { return max }
    a
}

fn interpolate(min: f32, max: f32, gradient: f32) -> f32 {
    min + (max - min) * clamp(gradient, 0., 1.)
}

fn get_line_points(start: Point, end: Point) -> Vec<Point> {
    let mut x0 = start.x();
    let mut y0 = start.y();
    let mut x1 = end.x();
    let mut y1 = end.y();

    let steep = (y1 - y0).abs() > (x1 - x0).abs();

    if steep {
        std::mem::swap(&mut x0, &mut y0);
        std::mem::swap(&mut x1, &mut y1);
    }

    let reverse = x0 > x1;

    if reverse {
        std::mem::swap(&mut x0, &mut x1);
        std::mem::swap(&mut y0, &mut y1);
    }

    let dx = x1 - x0;
    let dy = (y1 - y0).abs();

    let mut err = dx / 2;
    let mut y = y0;
    let ystep = match y0.cmp(&y1) {
        Ordering::Less => 1,
        _ => -1
    };

    let mut points: Vec<Point> = vec![];

    for x in x0..x1 {
        if steep {
            points.push(Point::new(y, x));
        } else {
            points.push(Point::new(x, y));
        }

        err -= dy;

        if err < 0 {
            y += ystep;
            err += dx;
        }
    }

    points
}

trait TinyRenderer {
    fn pixel(&mut self, Point, Color);
    fn line(&mut self, Point, Point, Color);
    fn process_scan_ine(&mut self, i32, Point, Point, Point, Point, Color);
    fn triangle(&mut self, Point, Point, Point, Color);
}

impl<'a> TinyRenderer for Renderer<'a> {
    fn pixel(&mut self, p: Point, c: Color) {
        let current_color = self.draw_color();

        self.set_draw_color(c);
        self.draw_point(p).unwrap();
        self.set_draw_color(current_color);
    }

    fn line(&mut self, start: Point, end: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let points = get_line_points(start, end);

        for p in 0..points.len() {
            self.draw_point(points[p]).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn process_scan_ine(&mut self, y: i32, pa: Point, pb: Point, pc: Point, pd: Point, c: Color) {
        let current_color = self.draw_color();
        self.set_draw_color(c);

        let grad1 = match (&pa.y()).cmp(&pb.y()) {
            Ordering::Equal => 1.,
            _ => (y - pa.y()) as f32 / (pb.y()- pa.y()) as f32
        };

        let grad2 = match (&pc.y()).cmp(&pd.y()) {
            Ordering::Equal => 1.,
            _ => (y - pc.y()) as f32 / (pd.y() - pc.y()) as f32
        };

        let sx = interpolate(pa.x() as f32, pb.x() as f32, grad1) as i32;
        let ex = interpolate(pc.x() as f32, pd.x() as f32, grad2) as i32;

        for x in sx..ex {
            self.draw_point(Point::new(x, y)).unwrap();
        }

        self.set_draw_color(current_color);
    }

    fn triangle(&mut self, p0: Point, p1: Point, p2: Point, c: Color) {
        let mut points = vec![p0, p1, p2];
        sort_points_by_y(&mut points);

        let dp0p1 = match (points[1].y() - points[0].y()).cmp(&0) {
            Ordering::Greater => (points[1].x() - points[0].x()) as f32 / (points[1].y() - points[0].y()) as f32,
            _ => 0.
        };

        let dp0p2 = match (points[2].y() - points[0].y()).cmp(&0) {
            Ordering::Greater => (points[2].x() - points[0].x()) as f32 / (points[2].y() - points[0].y()) as f32,
            _ => 0.
        };

        for y in points[0].y()..points[2].y() {
            if y < points[1].y() {
                if dp0p1 > dp0p2 {
                    self.process_scan_ine(y, points[0], points[2], points[0], points[1], c);
                } else {
                    self.process_scan_ine(y, points[0], points[1], points[0], points[2], c);
                }
            } else {
                if dp0p1 > dp0p2 {
                    self.process_scan_ine(y, points[0], points[2], points[1], points[2], c);
                } else {
                    self.process_scan_ine(y, points[1], points[2], points[0], points[2], c);
                }
            }
        }
    }
}

fn main() {
    let (width, height) = (700, 700);
    let importer = Importer::new();
    let scene = importer.read_file("resources/model.obj").unwrap();

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem.window("tinyrenderer-rs", width, height)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();

    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();

    let light_dir = Vector3::new(0., 0., -1.);

    for mesh in scene.mesh_iter() {
        for face in mesh.face_iter() {
            let mut screen_coords: [Point; 3] = [Point::new(0, 0); 3];
            let mut world_coords: [Vector3<f32>; 3] = [Vector3::zero(); 3];

            for j in 0..3 {
                let v = match mesh.get_vertex(face[j]) {
                    Some(x) => x,
                    None => Vector3D::new(0., 0., 0.)
                };

                let (p1, p2) = ((v.x + 1.) * width as f32 / 2., (v.y + 1.) * height as f32 / 2.);
                screen_coords[j as usize] = Point::new(p1 as i32, (height as f32 - p2) as i32);

                world_coords[j as usize] = v.into();
            }

            let n = (world_coords[2] - world_coords[0]).cross(world_coords[1] - world_coords[0]).normalize();
            let intensity = n.dot(light_dir);

            if intensity > 0.0 {
                renderer.triangle(
                    screen_coords[0],
                    screen_coords[1],
                    screen_coords[2],
                    Color::RGB(
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8,
                        (intensity * 255.) as u8
                    )
                );
            }
        }
    }

    renderer.present();

    let mut event_pump = sdl_context.event_pump().unwrap();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }
        //code here
    }
}
<|endoftext|>


<commit_before>#[derive(Clone, Copy, Debug)]
enum PBType {
    Integer64,
    String,
}

#[derive(Clone, Debug)]
struct PBField {
    name: String,
    tag: u8,
    field_type: PBType,
}

#[derive(Clone, Debug)]
struct PBMessage {
    name: String,
    fields: Vec<PBField>,
}

#[derive(Clone, Copy, Debug)]
enum PBWireType {
    VarInt,
    Fixed64,
    LengthDelim,
    Fixed32,
    Reserved,
}

struct TagValue<'a> {
    tag: u8,
    wire_type: PBWireType,
    value: &'a [u8],
}

#[derive(Clone)]
struct ParserPosition<'a> {
    slice: &'a [u8],
}

trait InitParserPosition<'a> {
    fn init(msg_slice: &'a [u8]) -> ParserPosition<'a>;
}

impl<'a> InitParserPosition<'a> for ParserPosition<'a> {
    fn init(msg_slice: &'a [u8]) -> ParserPosition<'a> {
        ParserPosition { slice: msg_slice }
    }
}

static IDX2WIRE_TYPE: &'static [PBWireType; 6] = &[PBWireType::VarInt,
                                                   PBWireType::Fixed64,
                                                   PBWireType::LengthDelim,
                                                   PBWireType::Reserved,
                                                   PBWireType::Reserved,
                                                   PBWireType::Fixed32];
#[derive(Clone, Copy, Debug)]
enum PBParseError {
    UnknownWireType(usize),
    BadVarInt,
    WireTypeNotHandled,
}

fn ParseWireType<'a>(wire_type: PBWireType,
                     pos: ParserPosition<'a>)
                     -> Result<(&'a [u8], ParserPosition<'a>), PBParseError> {
    let mut p = pos.clone();
    match wire_type {
        PBWireType::LengthDelim => {
            let offset = p.slice[1] as usize;
            let start = 2;
            let end = 2 + offset;
            let x = &p.slice[start..end];
            p.slice = &p.slice[end..];
            Ok((x, p))
        }
        PBWireType::VarInt => {
            let mut end: Option<usize> = None;
            for i in 1..p.slice.len() {
                if p.slice[i] >> 7 != 1 {
                    end = Some(i + 1);
                }
            }
            match end {
                Some(end_idx) => {
                    let x = &p.slice[1..end_idx];
                    p.slice = &p.slice[end_idx..];
                    Ok((x, p))
                }
                None => Err(PBParseError::BadVarInt),
            }

        }
        _ => Err(PBParseError::WireTypeNotHandled),
    }
}

fn PBParseNext<'a>(pos: ParserPosition<'a>)
                   -> Result<(TagValue<'a>, ParserPosition<'a>), PBParseError> {
    let mut p = pos.clone();

    let tag = p.slice[0] >> 3;
    let wire_type_idx = (p.slice[0] & 7) as usize;
    if wire_type_idx >= IDX2WIRE_TYPE.len() {
        return Err(PBParseError::UnknownWireType(wire_type_idx));
    }
    let wire_type = IDX2WIRE_TYPE[wire_type_idx];
    let (value, p) = try!(ParseWireType(wire_type, p));
    Ok((TagValue {
            value: value,
            tag: tag,
            wire_type: wire_type,
        },
        p.clone()))
}

use std::str;

#[derive(Debug)]
enum ReprError {
    InvalidWireAndSchemaType,
    Utf8Error(std::str::Utf8Error),
}

fn StringRepr<'a>(wire_type: PBWireType,
                  schema_type: PBType,
                  bytes: &'a [u8])
                  -> Result<String, ReprError> {
    match (wire_type, schema_type) {
        (PBWireType::LengthDelim, PBType::String) => {
            let x = str::from_utf8(bytes);
            match x {
                Ok(y) => Ok(String::from(y)),
                Err(y) => Err(ReprError::Utf8Error(y)),
            }
        }
        (PBWireType::VarInt, PBType::Integer64) => {
            match IntegerRepr(wire_type, schema_type, bytes) {
                Ok(i) => Ok(String::from(format!("{}", i))),
                Err(e) => Err(e),
            }
        }
        _ => Err(ReprError::InvalidWireAndSchemaType),
    }
}

fn IntegerRepr<'a>(wire_type: PBWireType,
                   schema_type: PBType,
                   bytes: &'a [u8])
                   -> Result<i64, ReprError> {

    extern crate num;
    match (wire_type, schema_type) {
        (PBWireType::VarInt, PBType::Integer64) => {
            let mut pos: u8 = 0;
            let mut res: i64 = 0;
            for b in bytes {
                // I'm assuming I have an endieness problem here?
                for i in 0..7 {
                    let bit_shift = 6 - i;
                    let pow_add = pos + 6 - i;
                    if ((b >> (6 - i)) & 1u8) == 1u8 {
                        res += num::pow(2, (pow_add) as usize);
                    }
                }
                pos += 7;
            }
            Ok(res)
        }
        _ => Err(ReprError::InvalidWireAndSchemaType),
    }
}

fn main() {
    /*
     * Sample ProtocolBuffer message for schema:
     *
     *     message Test2 {
     *       required string a = 1;
     *       required string b = 2;
     *       required int c = 3
     *     }
     *
     * with a = test, b = testing
     *
     * @see https://developers.google.com/protocol-buffers/docs/encoding
     */
    let msg = vec![0x12, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x0a, 0x04, 0x74, 0x65,
                   0x73, 0x74, 0x18, 0xac, 0x02];
    let msg_slice = msg.as_slice();

    let (mut x, mut pp) = PBParseNext(ParserPosition::init(msg_slice)).unwrap();

    print!("Tag   = {} {:?}\n", x.tag, x.wire_type);
    print!("Value = {}\n",
           StringRepr(x.wire_type, PBType::String, x.value).unwrap());

    let (x, pp) = PBParseNext(pp).unwrap();

    print!("Tag   = {} {:?}\n", x.tag, x.wire_type);
    print!("Value = {}\n",
           StringRepr(x.wire_type, PBType::String, x.value).unwrap());

    let (x, pp) = PBParseNext(pp).unwrap();

    print!("Tag   = {} {:?}\n", x.tag, x.wire_type);
    print!("Value = {}\n",
           StringRepr(x.wire_type, PBType::Integer64, x.value).unwrap());

}
<commit_msg>Keep comment up-to-date<commit_after>#[derive(Clone, Copy, Debug)]
enum PBType {
    Integer64,
    String,
}

#[derive(Clone, Debug)]
struct PBField {
    name: String,
    tag: u8,
    field_type: PBType,
}

#[derive(Clone, Debug)]
struct PBMessage {
    name: String,
    fields: Vec<PBField>,
}

#[derive(Clone, Copy, Debug)]
enum PBWireType {
    VarInt,
    Fixed64,
    LengthDelim,
    Fixed32,
    Reserved,
}

struct TagValue<'a> {
    tag: u8,
    wire_type: PBWireType,
    value: &'a [u8],
}

#[derive(Clone)]
struct ParserPosition<'a> {
    slice: &'a [u8],
}

trait InitParserPosition<'a> {
    fn init(msg_slice: &'a [u8]) -> ParserPosition<'a>;
}

impl<'a> InitParserPosition<'a> for ParserPosition<'a> {
    fn init(msg_slice: &'a [u8]) -> ParserPosition<'a> {
        ParserPosition { slice: msg_slice }
    }
}

static IDX2WIRE_TYPE: &'static [PBWireType; 6] = &[PBWireType::VarInt,
                                                   PBWireType::Fixed64,
                                                   PBWireType::LengthDelim,
                                                   PBWireType::Reserved,
                                                   PBWireType::Reserved,
                                                   PBWireType::Fixed32];
#[derive(Clone, Copy, Debug)]
enum PBParseError {
    UnknownWireType(usize),
    BadVarInt,
    WireTypeNotHandled,
}

fn ParseWireType<'a>(wire_type: PBWireType,
                     pos: ParserPosition<'a>)
                     -> Result<(&'a [u8], ParserPosition<'a>), PBParseError> {
    let mut p = pos.clone();
    match wire_type {
        PBWireType::LengthDelim => {
            let offset = p.slice[1] as usize;
            let start = 2;
            let end = 2 + offset;
            let x = &p.slice[start..end];
            p.slice = &p.slice[end..];
            Ok((x, p))
        }
        PBWireType::VarInt => {
            let mut end: Option<usize> = None;
            for i in 1..p.slice.len() {
                if p.slice[i] >> 7 != 1 {
                    end = Some(i + 1);
                }
            }
            match end {
                Some(end_idx) => {
                    let x = &p.slice[1..end_idx];
                    p.slice = &p.slice[end_idx..];
                    Ok((x, p))
                }
                None => Err(PBParseError::BadVarInt),
            }

        }
        _ => Err(PBParseError::WireTypeNotHandled),
    }
}

fn PBParseNext<'a>(pos: ParserPosition<'a>)
                   -> Result<(TagValue<'a>, ParserPosition<'a>), PBParseError> {
    let mut p = pos.clone();

    let tag = p.slice[0] >> 3;
    let wire_type_idx = (p.slice[0] & 7) as usize;
    if wire_type_idx >= IDX2WIRE_TYPE.len() {
        return Err(PBParseError::UnknownWireType(wire_type_idx));
    }
    let wire_type = IDX2WIRE_TYPE[wire_type_idx];
    let (value, p) = try!(ParseWireType(wire_type, p));
    Ok((TagValue {
            value: value,
            tag: tag,
            wire_type: wire_type,
        },
        p.clone()))
}

use std::str;

#[derive(Debug)]
enum ReprError {
    InvalidWireAndSchemaType,
    Utf8Error(std::str::Utf8Error),
}

fn StringRepr<'a>(wire_type: PBWireType,
                  schema_type: PBType,
                  bytes: &'a [u8])
                  -> Result<String, ReprError> {
    match (wire_type, schema_type) {
        (PBWireType::LengthDelim, PBType::String) => {
            let x = str::from_utf8(bytes);
            match x {
                Ok(y) => Ok(String::from(y)),
                Err(y) => Err(ReprError::Utf8Error(y)),
            }
        }
        (PBWireType::VarInt, PBType::Integer64) => {
            match IntegerRepr(wire_type, schema_type, bytes) {
                Ok(i) => Ok(String::from(format!("{}", i))),
                Err(e) => Err(e),
            }
        }
        _ => Err(ReprError::InvalidWireAndSchemaType),
    }
}

fn IntegerRepr<'a>(wire_type: PBWireType,
                   schema_type: PBType,
                   bytes: &'a [u8])
                   -> Result<i64, ReprError> {

    extern crate num;
    match (wire_type, schema_type) {
        (PBWireType::VarInt, PBType::Integer64) => {
            let mut pos: u8 = 0;
            let mut res: i64 = 0;
            for b in bytes {
                // I'm assuming I have an endieness problem here?
                for i in 0..7 {
                    let bit_shift = 6 - i;
                    let pow_add = pos + 6 - i;
                    if ((b >> (6 - i)) & 1u8) == 1u8 {
                        res += num::pow(2, (pow_add) as usize);
                    }
                }
                pos += 7;
            }
            Ok(res)
        }
        _ => Err(ReprError::InvalidWireAndSchemaType),
    }
}

fn main() {
    /*
     * Sample ProtocolBuffer message for schema:
     *
     *     message Test2 {
     *       required string a = 1;
     *       required string b = 2;
     *       required int c = 3
     *     }
     *
     * with a = test, b = testing, c = 300
     *
     * @see https://developers.google.com/protocol-buffers/docs/encoding
     */
    let msg = vec![0x12, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x0a, 0x04, 0x74, 0x65,
                   0x73, 0x74, 0x18, 0xac, 0x02];
    let msg_slice = msg.as_slice();

    let (mut x, mut pp) = PBParseNext(ParserPosition::init(msg_slice)).unwrap();

    print!("Tag   = {} {:?}\n", x.tag, x.wire_type);
    print!("Value = {}\n",
           StringRepr(x.wire_type, PBType::String, x.value).unwrap());

    let (x, pp) = PBParseNext(pp).unwrap();

    print!("Tag   = {} {:?}\n", x.tag, x.wire_type);
    print!("Value = {}\n",
           StringRepr(x.wire_type, PBType::String, x.value).unwrap());

    let (x, pp) = PBParseNext(pp).unwrap();

    print!("Tag   = {} {:?}\n", x.tag, x.wire_type);
    print!("Value = {}\n",
           StringRepr(x.wire_type, PBType::Integer64, x.value).unwrap());

}
<|endoftext|>


<commit_before>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

enum ItemType {
   Dir,
   File,
   Other,
}

struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
		}
	}
}
<commit_msg>Added another working example from DirEntry.file_name()<commit_after>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

enum ItemType {
   Dir,
   File,
   Other,
}

struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
		}
	}
*/

	// working example from:
	// https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
	if let Ok(entries) = fs::read_dir(idg_dir) {
		for entry in entries {
			if let Ok(entry) = entry {
			// Here, `entry` is a `DirEntry`.
				println!("{:?}", entry.file_name());
			}
		}
	}
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate toml;

extern crate rustc_serialize;
use rustc_serialize::json;

use std::io::{Read, Write};
use std::thread;

use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;

// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // TODO check that key actually fits in 8-bit int
    stacks: Vec<Vec<(i8,i64)>>,
    symbolSources: Vec<String>,
    version: u8,
}

fn main() {
    let address = "0.0.0.0:8080";

    println!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            let _ = req.read_to_string(&mut buffer);
            println!("DEBUG raw POST: {:?}", &buffer);
            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            println!("DEBUG decoded memoryMap: {:?}", decoded.memoryMap);
            println!("DEBUG decoded stacks: {:?}", decoded.stacks);
            println!("DEBUG decoded symbolSources: {:?}", decoded.symbolSources);
            println!("DEBUG decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");
            let symbols = client(symbol_url, decoded.memoryMap);
            let _ = res.write_all(symbols.as_bytes());

            res.end().unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>) -> String {
    let mut handles = vec![];
    for (debug_file, debug_id) in memory_map {
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);
        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {
            let c = Client::new();
            let mut res = c.get(&this_url).send().unwrap();
            let mut body = String::new();
            let _ = res.read_to_string(&mut body);

            (symbol_file, body)
        }));
    }

    let mut result = String::new();

    for handle in handles {
        let (symbol_file, body) = handle.join().unwrap();
        for c in format!("{:?} {:?}\n", symbol_file, body).chars() {
            result.push(c);
        }
    }

    result
}

fn get_config(value_name: &str) -> String {
    let toml = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<commit_msg>formatting, more comments<commit_after>extern crate hyper;
extern crate toml;

extern crate rustc_serialize;
use rustc_serialize::json;

use std::io::{Read, Write};
use std::thread;

use hyper::Client;
use hyper::server::{Server, Request, Response};
use hyper::status::StatusCode;

// required JSON keys are non-snakecase
#[allow(non_snake_case)]
#[derive(RustcDecodable)]
pub struct SymbolRequest {
    memoryMap: Vec<(String,String)>,
    // TODO check that key actually fits in 8-bit int
    stacks: Vec<Vec<(i8,i64)>>,
    symbolSources: Vec<String>,
    version: u8,
}

fn main() {
    let address = "0.0.0.0:8080";

    println!("Listening on {}", address);
    Server::http(address).unwrap().handle(server).unwrap();
}

/**
  * Receives single HTTP requests and demuxes to symbols file fetches from S3 bucket.
  */
fn server(mut req: Request, mut res: Response) {
    match req.method {
        hyper::Post => {
            let mut res = res.start().unwrap();

            let mut buffer = String::new();
            let _ = req.read_to_string(&mut buffer);
            println!("DEBUG raw POST: {:?}", &buffer);
            let decoded: SymbolRequest = json::decode(&buffer).unwrap();

            println!("DEBUG decoded memoryMap: {:?}", decoded.memoryMap);
            println!("DEBUG decoded stacks: {:?}", decoded.stacks);
            println!("DEBUG decoded symbolSources: {:?}", decoded.symbolSources);
            println!("DEBUG decoded version: {}", decoded.version);

            let symbol_url = get_config("symbol_urls.public");
            let symbols = client(symbol_url, decoded.memoryMap);
            let _ = res.write_all(symbols.as_bytes());

            res.end().unwrap();
        },
        _ => { *res.status_mut() = StatusCode::MethodNotAllowed },
    }
}

/**
  * Creates multiple client connections and aggregates result.
  */
fn client(url: String, memory_map: Vec<(String,String)>) -> String {
    let mut handles = vec![];
    for (debug_file, debug_id) in memory_map {
        let pdb = debug_file.find(".pdb").unwrap();
        let (symbol_name, _) = debug_file.split_at(pdb);
        let symbol_file = format!("{}.sym", symbol_name);
        let this_url = format!("{}/{}/{}/{}", url, debug_file, debug_id, symbol_file);

        // TODO decide min/max possible threads, possibly based on number of cores?
        handles.push(thread::spawn(move || {
            let c = Client::new();
            let mut res = c.get(&this_url).send().unwrap();
            let mut body = String::new();
            let _ = res.read_to_string(&mut body);

            (symbol_file, body)
        }));
    }

    let mut result = String::new();

    for handle in handles {
        let (symbol_file, body) = handle.join().unwrap();
        for c in format!("{:?} {:?}\n", symbol_file, body).chars() {
            result.push(c);
        }
    }

    result
}

fn get_config(value_name: &str) -> String {
    // TODO move to actual file, static str for the moment
    let toml = r#"
        [symbol_urls]
        public = "https://s3-us-west-2.amazonaws.com/org.mozilla.crash-stats.symbols-public/v1"
    "#;
    // TODO support multiple URLs
    let value: toml::Value = toml.parse().unwrap();

    value.lookup(value_name).unwrap().as_str().unwrap().to_string()
}
<|endoftext|>


<commit_before>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;
extern crate vitral;
extern crate serde;
extern crate calx_color;
#[macro_use]
extern crate calx_resource;
extern crate calx_grid;
extern crate world;

mod backend;
mod view;

use calx_color::color::*;
pub use euclid::{Point2D, Rect, Size2D};
pub use glium::{DisplayBuild, glutin};
pub use backend::Backend;
pub use calx_resource::{Loadable, Resource, ResourceCache, ResourceStore};
use world::{BrushBuilder, Frame};
use world::World;
use world::query;
use world::terrain;

fn init_brushes<V: Copy + Eq>(builder: &mut vitral::Builder<V>) {
    BrushBuilder::new(builder)
        .file("content/assets/floors.png")
        ////
        .tile(0, 0)
        .brush("blank_floor")
        ////
        .color(DARKGREEN)
        .tile(32, 0)
        .brush("grass")
        ////
        .color(DARKGREEN)
        .tile(64, 0)
        .brush("grass2")
        ////
        .color(SLATEGRAY)
        .tile(32, 0)
        .brush("ground")
        ////
        .color(ROYALBLUE)
        .tile(96, 0)
        .brush("water")
        ////
        .file("content/assets/portals.png")
        ////
        .color(LIGHTCYAN)
        .tile(0, 0)
        .tile(32, 0)
        .tile(64, 0)
        .tile(96, 0)
        .tile(128, 0)
        .tile(160, 0)
        .tile(192, 0)
        .tile(224, 0)
        .tile(256, 0)
        .tile(288, 0)
        .tile(320, 0)
        .tile(352, 0)
        .tile(384, 0)
        .brush("gate")
        ////
        .file("content/assets/props.png")
        ////
        .color(RED)
        .splat(32, 0, 32, 32)
        .brush("cursor")
        ////
        .color(SADDLEBROWN)
        .tile(160, 64)
        .color(GREEN)
        .tile(192, 64)
        .brush("tree")
        ////
        .file("content/assets/walls.png")
        ////
        .color(LIGHTSLATEGRAY)
        .wall(0, 0, 32, 0)
        .brush("wall")
        ////
        .file("content/assets/blobs.png")
        ////
        .color(DARKGOLDENROD)
        .blob(0, 0, 0, 32, 0, 64)
        .brush("rock");
}

fn draw_frame(context: &mut backend::Context, offset: Point2D<f32>, frame: &Frame) {
    for splat in frame.iter() {
        context.draw_image(splat.image, offset - splat.offset, splat.color);
    }
}

fn init_terrain() {
    use world::terrain::{Form, Kind, Tile};

    // Void, terrain 0 is special.
    Tile::insert_resource(0, Tile::new("blank_floor", Kind::Block, Form::Void));
    // "Level exit", a visible portal tile.
    Tile::insert_resource(1, Tile::new("gate", Kind::Ground, Form::Gate));
    Tile::insert_resource(2, Tile::new("ground", Kind::Ground, Form::Floor));
    Tile::insert_resource(3, Tile::new("grass", Kind::Ground, Form::Floor));
    Tile::insert_resource(4, Tile::new("water", Kind::Water, Form::Floor));
    Tile::insert_resource(5, Tile::new("tree", Kind::Block, Form::Prop));
    Tile::insert_resource(6, Tile::new("wall", Kind::Block, Form::Wall));
    Tile::insert_resource(7, Tile::new("rock", Kind::Block, Form::Blob));
}

pub fn main() {
    // Construct display and Vitral context.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    let mut backend = Backend::new(&display);

    let mut context: backend::Context;
    let mut builder = vitral::Builder::new();

    // Initialize game resources.
    init_brushes(&mut builder);
    init_terrain();

    context = builder.build(|img| backend.make_texture(&display, img));

    let font = context.default_font();

    // Initialize worldstate
    let world = World::new(1);

    // Run game.
    loop {
        context.begin_frame();

        let rect = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(640.0, 360.0));

        let cursor_pos = view::view_to_chart(context.mouse_pos());

        for chart_pos in view::cells_in_view_rect(rect) {
            let pos = view::chart_to_view(chart_pos);
            let mut t = query::terrain(&world, world::Location::new(pos.x as i8, pos.y as i8));

            if chart_pos == cursor_pos {
                t = terrain::Tile::get_resource(&5).unwrap();
            }

            draw_frame(&mut context, pos, &t.brush[0]);
        }

        context.draw_text(font,
                          Point2D::new(4.0, 20.0),
                          [1.0, 1.0, 1.0, 1.0],
                          "Hello, world!");

        if !backend.update(&display, &mut context) {
            return;
        }
    }
}
<commit_msg>Fix gate brush<commit_after>extern crate euclid;
#[macro_use]
extern crate glium;
extern crate image;
extern crate vitral;
extern crate serde;
extern crate calx_color;
#[macro_use]
extern crate calx_resource;
extern crate calx_grid;
extern crate world;

mod backend;
mod view;

use calx_color::color::*;
pub use euclid::{Point2D, Rect, Size2D};
pub use glium::{DisplayBuild, glutin};
pub use backend::Backend;
pub use calx_resource::{Loadable, Resource, ResourceCache, ResourceStore};
use world::{BrushBuilder, Frame};
use world::World;
use world::query;
use world::terrain;

fn init_brushes<V: Copy + Eq>(builder: &mut vitral::Builder<V>) {
    BrushBuilder::new(builder)
        .file("content/assets/floors.png")
        ////
        .tile(0, 0)
        .brush("blank_floor")
        ////
        .color(DARKGREEN)
        .tile(32, 0)
        .brush("grass")
        ////
        .color(DARKGREEN)
        .tile(64, 0)
        .brush("grass2")
        ////
        .color(SLATEGRAY)
        .tile(32, 0)
        .brush("ground")
        ////
        .color(ROYALBLUE)
        .tile(96, 0)
        .brush("water")
        ////
        .file("content/assets/portals.png")
        ////
        .color(LIGHTCYAN)
        .tile(0, 0)
        .frame()
        .tile(32, 0)
        .frame()
        .tile(64, 0)
        .frame()
        .tile(96, 0)
        .frame()
        .tile(128, 0)
        .frame()
        .tile(160, 0)
        .frame()
        .tile(192, 0)
        .frame()
        .tile(224, 0)
        .frame()
        .tile(256, 0)
        .frame()
        .tile(288, 0)
        .frame()
        .tile(320, 0)
        .frame()
        .tile(352, 0)
        .frame()
        .tile(384, 0)
        .brush("gate")
        ////
        .file("content/assets/props.png")
        ////
        .color(RED)
        .splat(32, 0, 32, 32)
        .brush("cursor")
        ////
        .color(SADDLEBROWN)
        .tile(160, 64)
        .color(GREEN)
        .tile(192, 64)
        .brush("tree")
        ////
        .file("content/assets/walls.png")
        ////
        .color(LIGHTSLATEGRAY)
        .wall(0, 0, 32, 0)
        .brush("wall")
        ////
        .file("content/assets/blobs.png")
        ////
        .color(DARKGOLDENROD)
        .blob(0, 0, 0, 32, 0, 64)
        .brush("rock");
}

fn draw_frame(context: &mut backend::Context, offset: Point2D<f32>, frame: &Frame) {
    for splat in frame.iter() {
        context.draw_image(splat.image, offset - splat.offset, splat.color);
    }
}

fn init_terrain() {
    use world::terrain::{Form, Kind, Tile};

    // Void, terrain 0 is special.
    Tile::insert_resource(0, Tile::new("blank_floor", Kind::Block, Form::Void));
    // "Level exit", a visible portal tile.
    Tile::insert_resource(1, Tile::new("gate", Kind::Ground, Form::Gate));
    Tile::insert_resource(2, Tile::new("ground", Kind::Ground, Form::Floor));
    Tile::insert_resource(3, Tile::new("grass", Kind::Ground, Form::Floor));
    Tile::insert_resource(4, Tile::new("water", Kind::Water, Form::Floor));
    Tile::insert_resource(5, Tile::new("tree", Kind::Block, Form::Prop));
    Tile::insert_resource(6, Tile::new("wall", Kind::Block, Form::Wall));
    Tile::insert_resource(7, Tile::new("rock", Kind::Block, Form::Blob));
}

pub fn main() {
    // Construct display and Vitral context.
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    let mut backend = Backend::new(&display);

    let mut context: backend::Context;
    let mut builder = vitral::Builder::new();

    // Initialize game resources.
    init_brushes(&mut builder);
    init_terrain();

    context = builder.build(|img| backend.make_texture(&display, img));

    let font = context.default_font();

    // Initialize worldstate
    let world = World::new(1);

    // Run game.
    loop {
        context.begin_frame();

        let rect = Rect::new(Point2D::new(0.0, 0.0), Size2D::new(640.0, 360.0));

        let cursor_pos = view::view_to_chart(context.mouse_pos());

        for chart_pos in view::cells_in_view_rect(rect) {
            let pos = view::chart_to_view(chart_pos);
            let mut t = query::terrain(&world, world::Location::new(pos.x as i8, pos.y as i8));

            if chart_pos == cursor_pos {
                t = terrain::Tile::get_resource(&5).unwrap();
            }

            draw_frame(&mut context, pos, &t.brush[0]);
        }

        context.draw_text(font,
                          Point2D::new(4.0, 20.0),
                          [1.0, 1.0, 1.0, 1.0],
                          "Hello, world!");

        if !backend.update(&display, &mut context) {
            return;
        }
    }
}
<|endoftext|>


<commit_before>#![feature(convert, plugin, rustc_private, std_misc)]
#![plugin(docopt_macros)]

extern crate cargo;
extern crate docopt;
extern crate graphviz;
extern crate rustc_serialize;

use cargo::core::{Resolve, SourceId, PackageId};
use graphviz as dot;
use std::borrow::{Cow};
use std::convert::Into;
use std::env;
use std::io;
use std::io::Write;
use std::fs::File;
use std::path::{Path, PathBuf, AsPath};

docopt!(Flags, "
Generate a graph of package dependencies in graphviz format

Usage: cargo dot [options]
       cargo dot --help

Options:
    -h, --help         Show this message
    -V, --version      Print version info and exit
    --lock-file=FILE   Specify location of input file, default \"Cargo.lock\"
    --dot-file=FILE    Output to file, default prints to stdout
    --source-labels    Use sources for the label instead of package names
");

fn main() {
    let mut argv: Vec<String> = env::args().collect();
    if argv.len() > 0 {
        argv[0] = "cargo".to_string();
    }
    let flags: Flags = Flags::docopt()
                             // cargo passes the exe name first, so we skip it
                             .argv(argv.into_iter())
                             .version(Some("0.2".to_string()))
                             .decode()
                             .unwrap_or_else(|e|
                                             e.exit());

    let dot_f_flag = if flags.flag_dot_file.is_empty() { None } else { Some(flags.flag_dot_file) };
    let source_labels = flags.flag_source_labels;

    let lock_path = unless_empty(flags.flag_lock_file, "Cargo.lock");
    let lock_path = Path::new(&lock_path);
    let lock_path_buf = absolutize(lock_path.to_path_buf());
    let lock_path = lock_path_buf.as_path();

    let proj_dir  = lock_path.parent().unwrap(); // TODO: check for None
    let src_id = SourceId::for_path(&proj_dir).unwrap();
    let resolved = cargo::ops::load_lockfile(&lock_path, &src_id).unwrap()
        .expect("Lock file not found.");

    let mut graph = Graph::with_root(resolved.root(), source_labels);
    graph.add_dependencies(&resolved);

    match dot_f_flag {
        None           => graph.render_to(&mut io::stdout()),
        Some(dot_file) => graph.render_to(&mut File::create(&Path::new(&dot_file)).unwrap())
    };
}

fn absolutize(pb: PathBuf) -> PathBuf {
    if pb.as_path().is_absolute() {
        pb
    } else {
        std::env::current_dir().unwrap().join(&pb.as_path()).clone()
    }
}

fn unless_empty(s: String, default: &str) -> String {
    if s.is_empty() {
        default.to_string()
    } else {
        s
    }
}

pub type Nd = usize;
pub type Ed = (usize, usize);
pub struct Graph<'a> {
    nodes: Vec<&'a PackageId>,
    edges: Vec<Ed>,
    source_labels: bool
}

impl<'a> Graph<'a> {
    pub fn with_root(root: &PackageId, source_labels: bool) -> Graph {
        Graph { nodes: vec![root], edges: vec![], source_labels: source_labels }
    }

    pub fn add_dependencies(&mut self, resolved: &'a Resolve) {
        for crat in resolved.iter() {
            match resolved.deps(crat) {
                Some(crate_deps) => {
                    let idl = self.find_or_add(crat);
                    for dep in crate_deps {
                        let idr = self.find_or_add(dep);
                        self.edges.push((idl, idr));
                    };
                },
                None => { }
            }
        }
    }

    fn find_or_add(&mut self, new: &'a PackageId) -> usize {
        for (i, id) in self.nodes.iter().enumerate() {
            if *id == new {
                return i
            }
        }
        self.nodes.push(new);
        self.nodes.len() - 1
    }

    pub fn render_to<W:Write>(&'a self, output: &mut W) {
        match dot::render(self, output) {
            Ok(_) => {},
            Err(e) => panic!("error rendering graph: {}", e)
        }
    }
}

impl<'a> dot::Labeller<'a, Nd, Ed> for Graph<'a> {
    fn graph_id(&self) -> dot::Id<'a> {
        dot::Id::new(self.nodes[0].name()).unwrap_or(dot::Id::new("dependencies").unwrap())
    }
    fn node_id(&self, n: &Nd) -> dot::Id {
        // unwrap is safe because N######## is a valid graphviz id
        dot::Id::new(format!("N{}", *n)).unwrap()
    }
    fn node_label(&'a self, i: &Nd) -> dot::LabelText<'a> {
        if !self.source_labels {
            dot::LabelText::LabelStr(self.nodes[*i].name().into())
        } else {
            dot::LabelText::LabelStr(self.nodes[*i].source_id().url().to_string().into())
        }
    }
}

impl<'a> dot::GraphWalk<'a, Nd, Ed> for Graph<'a> {
    fn nodes(&self) -> dot::Nodes<'a,Nd> {
        (0..self.nodes.len()).collect()
    }
    fn edges(&self) -> dot::Edges<Ed> {
        Cow::Borrowed(&self.edges[..])
    }
    fn source(&self, &(s, _): &Ed) -> Nd { s }
    fn target(&self, &(_, t): &Ed) -> Nd { t }
}
<commit_msg>upstream rust: features convert and std_misc no longer required<commit_after>#![feature(plugin, rustc_private)]
#![plugin(docopt_macros)]

extern crate cargo;
extern crate docopt;
extern crate graphviz;
extern crate rustc_serialize;

use cargo::core::{Resolve, SourceId, PackageId};
use graphviz as dot;
use std::borrow::{Cow};
use std::convert::Into;
use std::env;
use std::io;
use std::io::Write;
use std::fs::File;
use std::path::{Path, PathBuf, AsPath};

docopt!(Flags, "
Generate a graph of package dependencies in graphviz format

Usage: cargo dot [options]
       cargo dot --help

Options:
    -h, --help         Show this message
    -V, --version      Print version info and exit
    --lock-file=FILE   Specify location of input file, default \"Cargo.lock\"
    --dot-file=FILE    Output to file, default prints to stdout
    --source-labels    Use sources for the label instead of package names
");

fn main() {
    let mut argv: Vec<String> = env::args().collect();
    if argv.len() > 0 {
        argv[0] = "cargo".to_string();
    }
    let flags: Flags = Flags::docopt()
                             // cargo passes the exe name first, so we skip it
                             .argv(argv.into_iter())
                             .version(Some("0.2".to_string()))
                             .decode()
                             .unwrap_or_else(|e|
                                             e.exit());

    let dot_f_flag = if flags.flag_dot_file.is_empty() { None } else { Some(flags.flag_dot_file) };
    let source_labels = flags.flag_source_labels;

    let lock_path = unless_empty(flags.flag_lock_file, "Cargo.lock");
    let lock_path = Path::new(&lock_path);
    let lock_path_buf = absolutize(lock_path.to_path_buf());
    let lock_path = lock_path_buf.as_path();

    let proj_dir  = lock_path.parent().unwrap(); // TODO: check for None
    let src_id = SourceId::for_path(&proj_dir).unwrap();
    let resolved = cargo::ops::load_lockfile(&lock_path, &src_id).unwrap()
        .expect("Lock file not found.");

    let mut graph = Graph::with_root(resolved.root(), source_labels);
    graph.add_dependencies(&resolved);

    match dot_f_flag {
        None           => graph.render_to(&mut io::stdout()),
        Some(dot_file) => graph.render_to(&mut File::create(&Path::new(&dot_file)).unwrap())
    };
}

fn absolutize(pb: PathBuf) -> PathBuf {
    if pb.as_path().is_absolute() {
        pb
    } else {
        std::env::current_dir().unwrap().join(&pb.as_path()).clone()
    }
}

fn unless_empty(s: String, default: &str) -> String {
    if s.is_empty() {
        default.to_string()
    } else {
        s
    }
}

pub type Nd = usize;
pub type Ed = (usize, usize);
pub struct Graph<'a> {
    nodes: Vec<&'a PackageId>,
    edges: Vec<Ed>,
    source_labels: bool
}

impl<'a> Graph<'a> {
    pub fn with_root(root: &PackageId, source_labels: bool) -> Graph {
        Graph { nodes: vec![root], edges: vec![], source_labels: source_labels }
    }

    pub fn add_dependencies(&mut self, resolved: &'a Resolve) {
        for crat in resolved.iter() {
            match resolved.deps(crat) {
                Some(crate_deps) => {
                    let idl = self.find_or_add(crat);
                    for dep in crate_deps {
                        let idr = self.find_or_add(dep);
                        self.edges.push((idl, idr));
                    };
                },
                None => { }
            }
        }
    }

    fn find_or_add(&mut self, new: &'a PackageId) -> usize {
        for (i, id) in self.nodes.iter().enumerate() {
            if *id == new {
                return i
            }
        }
        self.nodes.push(new);
        self.nodes.len() - 1
    }

    pub fn render_to<W:Write>(&'a self, output: &mut W) {
        match dot::render(self, output) {
            Ok(_) => {},
            Err(e) => panic!("error rendering graph: {}", e)
        }
    }
}

impl<'a> dot::Labeller<'a, Nd, Ed> for Graph<'a> {
    fn graph_id(&self) -> dot::Id<'a> {
        dot::Id::new(self.nodes[0].name()).unwrap_or(dot::Id::new("dependencies").unwrap())
    }
    fn node_id(&self, n: &Nd) -> dot::Id {
        // unwrap is safe because N######## is a valid graphviz id
        dot::Id::new(format!("N{}", *n)).unwrap()
    }
    fn node_label(&'a self, i: &Nd) -> dot::LabelText<'a> {
        if !self.source_labels {
            dot::LabelText::LabelStr(self.nodes[*i].name().into())
        } else {
            dot::LabelText::LabelStr(self.nodes[*i].source_id().url().to_string().into())
        }
    }
}

impl<'a> dot::GraphWalk<'a, Nd, Ed> for Graph<'a> {
    fn nodes(&self) -> dot::Nodes<'a,Nd> {
        (0..self.nodes.len()).collect()
    }
    fn edges(&self) -> dot::Edges<Ed> {
        Cow::Borrowed(&self.edges[..])
    }
    fn source(&self, &(s, _): &Ed) -> Nd { s }
    fn target(&self, &(_, t): &Ed) -> Nd { t }
}
<|endoftext|>