<commit_before>#[cfg(test)]
extern crate assert_cli;
extern crate boxcars;
extern crate failure;
extern crate globset;
extern crate rayon;
extern crate serde_json;
#[macro_use]
extern crate structopt;

use boxcars::{CrcCheck, NetworkParse, ParserBuilder, Replay};
use failure::{err_msg, Error, ResultExt};
use globset::Glob;
use rayon::prelude::*;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
use std::io::{self, BufWriter};
use std::path::Path;
use structopt::StructOpt;

#[derive(StructOpt, Debug, Clone, PartialEq)]
#[structopt(
    name = "rrrocket",
    about = "Parses Rocket League replay files and outputs JSON with decoded information"
)]
struct Opt {
    #[structopt(
        short = "c",
        long = "crc-check",
        help = "forces a crc check for corruption even when replay was successfully parsed"
    )]
    crc: bool,

    #[structopt(
        short = "n",
        long = "network-parse",
        help = "parses the network data of a replay instead of skipping it"
    )]
    body: bool,

    #[structopt(
        short = "m",
        long = "multiple",
        help = "parse multiple replays, instead of writing JSON to stdout, write to a sibling JSON file"
    )]
    multiple: bool,

    #[structopt(
        long = "dry-run",
        help = "parses but does not write JSON output"
    )]
    dry_run: bool,

    #[structopt(help = "Rocket League replay files")]
    input: Vec<String>,
}

fn read_file(input: &str) -> Result<Vec<u8>, Error> {
    let mut f = File::open(input)
        .with_context(|_e| format!("Could not open rocket league file: {}", input))?;
    let mut buffer = vec![];
    f.read_to_end(&mut buffer)
        .with_context(|_e| format!("Could not read rocket league file: {}", input))?;
    Ok(buffer)
}

fn parse_replay<'a>(opt: &Opt, data: &'a [u8]) -> Result<Replay<'a>, Error> {
    ParserBuilder::new(&data[..])
        .with_crc_check(if opt.crc {
            CrcCheck::Always
        } else {
            CrcCheck::OnError
        }).with_network_parse(if opt.body {
            NetworkParse::Always
        } else {
            NetworkParse::Never
        }).parse()
}

/// Each file argument that we get could be a directory so we need to expand that directory and
/// find all the *.replay files. File arguments turn into single element vectors.
fn expand_paths(files: &[String]) -> Result<Vec<Vec<String>>, Error> {
    let glob = Glob::new("*.replay")?.compile_matcher();

    files
        .iter()
        .map(|x| {
            let p = Path::new(x);
            if p.is_dir() {
                // If the commandline argument is a directory we look for all files that match
                // *.replay. A file that does not match the pattern because of an error reading the
                // directory / file will not be filtered and will cause the error to bubble up. In
                // the future, we could get smart and ignore directories / files we don't have
                // permission that wouldn't match the pattern anyways
                let files: Result<Vec<_>, _> = p
                    .read_dir()?
                    .filter_map(|entry| {
                        match entry {
                            Ok(y) => {
                                if glob.is_match(y.path()) {
                                    // Force UTF-8. There is a special place in the fourth circle
                                    // of inferno for people who rename their rocket league replays
                                    // to not contain UTF-8. We won't panic, but will cause an
                                    // error when the file is attempted to be read.
                                    Some(Ok(y.path().to_string_lossy().into_owned()))
                                } else {
                                    None
                                }
                            }
                            Err(e) => Some(Err(e)),
                        }
                    }).collect();
                Ok(files?)
            } else {
                Ok(vec![x.clone()])
            }
        }).collect()
}

fn parse_multiple_replays(opt: &Opt) -> Result<(), Error> {
    let res: Result<Vec<()>, Error> = expand_paths(&opt.input)?
        .into_iter()
        .flat_map(|x| x)
        .collect::<Vec<_>>()
        .par_iter()
        .map(|file| {
            let data = read_file(file)?;
            let replay = parse_replay(opt, &data[..])
                .with_context(|_e| format!("Could not parse: {}", file))?;

            if !opt.dry_run {
                let outfile = format!("{}.json", file);
                let fout = OpenOptions::new()
                    .write(true)
                    .create(true)
                    .truncate(true)
                    .open(&outfile)
                    .with_context(|_e| format!("Could not open json output file: {}", outfile))?;

                let mut writer = BufWriter::new(fout);
                serde_json::to_writer(&mut writer, &replay)
                    .with_context(|_e| format!("Could not serialize replay {}", file))?;
            }
            Ok(())
        }).collect();
    res?;
    Ok(())
}

fn run() -> Result<(), Error> {
    let opt = Opt::from_args();
    if opt.multiple {
        parse_multiple_replays(&opt)
    } else if opt.input.len() != 1 {
        Err(err_msg(
            "Expected one input file if --multiple is not specified",
        ))
    } else {
        let file = &opt.input[0];
        let data = read_file(file)?;
        let replay = parse_replay(&opt, &data[..]).context("Could not parse replay")?;
        if !opt.dry_run {
            serde_json::to_writer(&mut io::stdout(), &replay)
                .context("Could not serialize replay")?;
        }
        Ok(())
    }
}

fn main() {
    if let Err(ref e) = run() {
        let mut stderr = io::stderr();
        for fail in e.causes() {
            let _ = writeln!(stderr, "{}", fail);
        }

        ::std::process::exit(1);
    }
}

#[cfg(test)]
mod tests {
    use assert_cli::Assert;
    use std::io::Write;

    #[test]
    fn test_error_output() {
        let mut w = Vec::new();
        writeln!(
            &mut w,
            "Could not open rocket league file: assets/fuzz-string-too-long.replay"
        ).unwrap();

        Assert::cargo_binary("rrrocket")
            .with_args(&[
                "-n",
                "-c",
                "--dry-run",
                "assets/fuzz-string-too-long.replay",
            ]).fails_with(1)
            .stderr()
            .contains(String::from_utf8(w).unwrap())
            .unwrap();
    }

    #[test]
    fn test_error_output2() {
        let mut w = Vec::new();
        writeln!(
            &mut w,
            "Could not parse: ../assets/fuzz-string-too-long.replay"
        ).unwrap();
        writeln!(
            &mut w,
            "Crc mismatch. Expected 3765941959 but received 1825689991"
        ).unwrap();

        Assert::cargo_binary("rrrocket")
            .with_args(&[
                "-n",
                "-c",
                "--dry-run",
                "-m",
                "../assets/fuzz-string-too-long.replay",
            ]).fails_with(1)
            .stderr()
            .contains(String::from_utf8(w).unwrap())
            .unwrap();
    }
}
<commit_msg>Fixup code warnings<commit_after>#[cfg(test)]
extern crate assert_cli;
extern crate boxcars;
extern crate failure;
extern crate globset;
extern crate rayon;
extern crate serde_json;
extern crate structopt;

use boxcars::{CrcCheck, NetworkParse, ParserBuilder, Replay};
use failure::{err_msg, Error, ResultExt};
use globset::Glob;
use rayon::prelude::*;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
use std::io::{self, BufWriter};
use std::path::Path;
use structopt::StructOpt;

#[derive(StructOpt, Debug, Clone, PartialEq)]
#[structopt(
    name = "rrrocket",
    about = "Parses Rocket League replay files and outputs JSON with decoded information"
)]
struct Opt {
    #[structopt(
        short = "c",
        long = "crc-check",
        help = "forces a crc check for corruption even when replay was successfully parsed"
    )]
    crc: bool,

    #[structopt(
        short = "n",
        long = "network-parse",
        help = "parses the network data of a replay instead of skipping it"
    )]
    body: bool,

    #[structopt(
        short = "m",
        long = "multiple",
        help = "parse multiple replays, instead of writing JSON to stdout, write to a sibling JSON file"
    )]
    multiple: bool,

    #[structopt(
        long = "dry-run",
        help = "parses but does not write JSON output"
    )]
    dry_run: bool,

    #[structopt(help = "Rocket League replay files")]
    input: Vec<String>,
}

fn read_file(input: &str) -> Result<Vec<u8>, Error> {
    let mut f = File::open(input)
        .with_context(|_e| format!("Could not open rocket league file: {}", input))?;
    let mut buffer = vec![];
    f.read_to_end(&mut buffer)
        .with_context(|_e| format!("Could not read rocket league file: {}", input))?;
    Ok(buffer)
}

fn parse_replay<'a>(opt: &Opt, data: &'a [u8]) -> Result<Replay<'a>, Error> {
    ParserBuilder::new(&data[..])
        .with_crc_check(if opt.crc {
            CrcCheck::Always
        } else {
            CrcCheck::OnError
        }).with_network_parse(if opt.body {
            NetworkParse::Always
        } else {
            NetworkParse::Never
        }).parse()
}

/// Each file argument that we get could be a directory so we need to expand that directory and
/// find all the *.replay files. File arguments turn into single element vectors.
fn expand_paths(files: &[String]) -> Result<Vec<Vec<String>>, Error> {
    let glob = Glob::new("*.replay")?.compile_matcher();

    files
        .iter()
        .map(|x| {
            let p = Path::new(x);
            if p.is_dir() {
                // If the commandline argument is a directory we look for all files that match
                // *.replay. A file that does not match the pattern because of an error reading the
                // directory / file will not be filtered and will cause the error to bubble up. In
                // the future, we could get smart and ignore directories / files we don't have
                // permission that wouldn't match the pattern anyways
                let files: Result<Vec<_>, _> = p
                    .read_dir()?
                    .filter_map(|entry| {
                        match entry {
                            Ok(y) => {
                                if glob.is_match(y.path()) {
                                    // Force UTF-8. There is a special place in the fourth circle
                                    // of inferno for people who rename their rocket league replays
                                    // to not contain UTF-8. We won't panic, but will cause an
                                    // error when the file is attempted to be read.
                                    Some(Ok(y.path().to_string_lossy().into_owned()))
                                } else {
                                    None
                                }
                            }
                            Err(e) => Some(Err(e)),
                        }
                    }).collect();
                Ok(files?)
            } else {
                Ok(vec![x.clone()])
            }
        }).collect()
}

fn parse_multiple_replays(opt: &Opt) -> Result<(), Error> {
    let res: Result<Vec<()>, Error> = expand_paths(&opt.input)?
        .into_iter()
        .flat_map(|x| x)
        .collect::<Vec<_>>()
        .par_iter()
        .map(|file| {
            let data = read_file(file)?;
            let replay = parse_replay(opt, &data[..])
                .with_context(|_e| format!("Could not parse: {}", file))?;

            if !opt.dry_run {
                let outfile = format!("{}.json", file);
                let fout = OpenOptions::new()
                    .write(true)
                    .create(true)
                    .truncate(true)
                    .open(&outfile)
                    .with_context(|_e| format!("Could not open json output file: {}", outfile))?;

                let mut writer = BufWriter::new(fout);
                serde_json::to_writer(&mut writer, &replay)
                    .with_context(|_e| format!("Could not serialize replay {}", file))?;
            }
            Ok(())
        }).collect();
    res?;
    Ok(())
}

fn run() -> Result<(), Error> {
    let opt = Opt::from_args();
    if opt.multiple {
        parse_multiple_replays(&opt)
    } else if opt.input.len() != 1 {
        Err(err_msg(
            "Expected one input file if --multiple is not specified",
        ))
    } else {
        let file = &opt.input[0];
        let data = read_file(file)?;
        let replay = parse_replay(&opt, &data[..]).context("Could not parse replay")?;
        if !opt.dry_run {
            serde_json::to_writer(&mut io::stdout(), &replay)
                .context("Could not serialize replay")?;
        }
        Ok(())
    }
}

fn main() {
    if let Err(ref e) = run() {
        let mut stderr = io::stderr();
        for fail in e.iter_chain() {
            let _ = writeln!(stderr, "{}", fail);
        }

        ::std::process::exit(1);
    }
}

#[cfg(test)]
mod tests {
    use assert_cli::Assert;
    use std::io::Write;

    #[test]
    fn test_error_output() {
        let mut w = Vec::new();
        writeln!(
            &mut w,
            "Could not open rocket league file: assets/fuzz-string-too-long.replay"
        ).unwrap();

        Assert::cargo_binary("rrrocket")
            .with_args(&[
                "-n",
                "-c",
                "--dry-run",
                "assets/fuzz-string-too-long.replay",
            ]).fails_with(1)
            .stderr()
            .contains(String::from_utf8(w).unwrap())
            .unwrap();
    }

    #[test]
    fn test_error_output2() {
        let mut w = Vec::new();
        writeln!(
            &mut w,
            "Could not parse: ../assets/fuzz-string-too-long.replay"
        ).unwrap();
        writeln!(
            &mut w,
            "Crc mismatch. Expected 3765941959 but received 1825689991"
        ).unwrap();

        Assert::cargo_binary("rrrocket")
            .with_args(&[
                "-n",
                "-c",
                "--dry-run",
                "-m",
                "../assets/fuzz-string-too-long.replay",
            ]).fails_with(1)
            .stderr()
            .contains(String::from_utf8(w).unwrap())
            .unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]
extern crate iron;
extern crate time;

use iron::prelude::*;
use iron::{Handler, AroundMiddleware};
use iron::response::modifiers::{Status, Body};
use iron::status;

use std::io::net::ip::Ipv4Addr;

enum LoggerMode {
    Silent,
    Tiny,
    Large
}

struct Logger {
    mode: LoggerMode
}

struct LoggerHandler<H: Handler> { logger: Logger, handler: H }

impl Logger {
    fn new(mode: LoggerMode) -> Logger {
        Logger { mode: mode }
    }

    fn log(&self, req: &Request, res: Result<&Response, &IronError>, time: u64) {
        match self.mode {
            Silent => {},
            Tiny => println!("Req: {}\nRes: {}\nTook: {}", req, res, time),
            Large => println!("Request: {}\nResponse: {}\nResponse-Time: {}", req, res, time)
        }
    }
}

impl<H: Handler> Handler for LoggerHandler<H> {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let entry = ::time::precise_time_ns();
        let res = self.handler.call(req);
        self.logger.log(req, res.as_ref(), ::time::precise_time_ns() - entry);
        res
    }
}

impl AroundMiddleware for Logger {
    fn around(self, handler: Box<Handler + Send + Sync>) -> Box<Handler + Send + Sync> {
        box LoggerHandler {
            logger: self,
            handler: handler
        } as Box<Handler + Send + Sync>
    }
}

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::new()
           .set(Status(status::Ok))
           .set(Body("Hello World!")))
}

fn main() {
    let tiny = Iron::new(Logger::new(Tiny).around(box hello_world));
    let silent = Iron::new(Logger::new(Silent).around(box hello_world));
    let large = Iron::new(Logger::new(Large).around(box hello_world));

    tiny.listen(Ipv4Addr(127, 0, 0, 1), 2000);
    silent.listen(Ipv4Addr(127, 0, 0, 1), 3000);
    large.listen(Ipv4Addr(127, 0, 0, 1), 4000);

    println!("Servers listening on 2000, 3000, and 4000");
}

<commit_msg>(fix) enum namespacing.<commit_after>#![feature(globs)]
extern crate iron;
extern crate time;

use iron::prelude::*;
use iron::{Handler, AroundMiddleware};
use iron::response::modifiers::{Status, Body};
use iron::status;

use std::io::net::ip::Ipv4Addr;

enum LoggerMode {
    Silent,
    Tiny,
    Large
}

struct Logger {
    mode: LoggerMode
}

struct LoggerHandler<H: Handler> { logger: Logger, handler: H }

impl Logger {
    fn new(mode: LoggerMode) -> Logger {
        Logger { mode: mode }
    }

    fn log(&self, req: &Request, res: Result<&Response, &IronError>, time: u64) {
        match self.mode {
            LoggerMode::Silent => {},
            LoggerMode::Tiny => println!("Req: {}\nRes: {}\nTook: {}", req, res, time),
            LoggerMode::Large => println!("Request: {}\nResponse: {}\nResponse-Time: {}", req, res, time)
        }
    }
}

impl<H: Handler> Handler for LoggerHandler<H> {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let entry = ::time::precise_time_ns();
        let res = self.handler.call(req);
        self.logger.log(req, res.as_ref(), ::time::precise_time_ns() - entry);
        res
    }
}

impl AroundMiddleware for Logger {
    fn around(self, handler: Box<Handler + Send + Sync>) -> Box<Handler + Send + Sync> {
        box LoggerHandler {
            logger: self,
            handler: handler
        } as Box<Handler + Send + Sync>
    }
}

fn hello_world(_: &mut Request) -> IronResult<Response> {
    Ok(Response::new()
           .set(Status(status::Ok))
           .set(Body("Hello World!")))
}

fn main() {
    let tiny = Iron::new(Logger::new(LoggerMode::Tiny).around(box hello_world));
    let silent = Iron::new(Logger::new(LoggerMode::Silent).around(box hello_world));
    let large = Iron::new(Logger::new(LoggerMode::Large).around(box hello_world));

    tiny.listen(Ipv4Addr(127, 0, 0, 1), 2000);
    silent.listen(Ipv4Addr(127, 0, 0, 1), 3000);
    large.listen(Ipv4Addr(127, 0, 0, 1), 4000);

    println!("Servers listening on 2000, 3000, and 4000");
}

<|endoftext|>


<commit_before>extern crate rustty;

use rustty::{
    Terminal,
    Event,
};

const BLOCK: char = '\u{25AA}';

fn main() {
    let mut term = Terminal::new().unwrap();
    let mut radius = 10u32;
    'main: loop {
        while let Some(Event::Key(ch)) = term.get_event(0).unwrap() {
            match ch {
                'q' => break 'main,
                '+' => radius = radius.saturating_add(1),
                '-' => radius = radius.saturating_sub(1),
                _ => {},
            }
        }

        let (cols, rows) = term.size();
        let (cols, rows) = (cols as isize, (rows - 3) as isize);

        let (a, b) = (cols / 2, rows / 2);

        for i in 0..cols*rows {
            let y = i as isize / cols;
            let x = i as isize % cols;

            let mut cell = &mut term[(x as usize, y as usize)];

            if ((x - a).pow(2)/4 + (y - b).pow(2)) <= radius.pow(2) as isize {
                cell.set_ch(BLOCK);
            } else {
                cell.set_ch(' ');
            }
        }
        term.swap_buffers().unwrap();
    }
}
<commit_msg>Added UI for circle<commit_after>extern crate rustty;

use rustty::{
    Terminal,
    Event,
};

const BLOCK: char = '\u{25AA}';
const BUFF_ALIGN: usize = 35;

fn write_word(term: &mut Terminal, row: usize, word: String) {

    let cols = term.cols() as usize;

    for (idx, ch) in word.chars().enumerate() {

        let x = cols - BUFF_ALIGN;

        let mut cell = &mut term[(x as usize + idx, row)];
        cell.set_ch(ch);
    }
}

fn main() {
    let mut term = Terminal::new().unwrap();
    let mut radius = 10u32;
    'main: loop {
        while let Some(Event::Key(ch)) = term.get_event(0).unwrap() {
            match ch {
                'q' => break 'main,
                '+' => radius = radius.saturating_add(1),
                '-' => radius = radius.saturating_sub(1),
                _ => {},
            }
        }

        let (cols, rows) = term.size();
        let (cols, rows) = (cols as isize, (rows - 4) as isize);

        let (a, b) = (cols / 2, rows / 2);

        for i in 0..cols*rows {
            let y = i as isize / cols;
            let x = i as isize % cols;

            let mut cell = &mut term[(x as usize, y as usize)];

            if ((x - a).pow(2)/4 + (y - b).pow(2)) <= radius.pow(2) as isize {
                cell.set_ch(BLOCK);
            } else {
                cell.set_ch(' ');
            }
        }

        let i = cols*rows;
        let y = i as isize / cols;
        write_word(&mut term, y as usize, "+ -> Increase Radius".to_string());
        write_word(&mut term, (y+1) as usize, "- -> Decrease Radius".to_string());
        write_word(&mut term, (y+2) as usize, "q -> Quit".to_string());
        term.swap_buffers().unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate blurz;

static BATTERY_SERVICE_UUID: &'static str = "0000180f-0000-1000-8000-00805f9b34fb";

use std::time::Duration;
use std::thread;

use blurz::bluetooth_adapter::BluetoothAdapter as BTAdapter;
use blurz::bluetooth_device::BluetoothDevice as BTDevice;
use blurz::bluetooth_gatt_service::BluetoothGATTService as BTGATTService;
use blurz::bluetooth_gatt_characteristic::BluetoothGATTCharacteristic as BTGATTCharacteristic;

fn error(error: String) {
    println!("{}", error);
    std::process::exit(1);
}

fn main() {
    let adapter: BTAdapter = match BTAdapter::init() {
        Ok(a) => a,
        Err(e) => return error(e),
    };
    match adapter.start_discovery() {
        Ok(_) => println!("Start discovery"),
        Err(e) => return error(e),
    }
    let devices = adapter.get_device_list();
    if devices.is_empty() {
        println!("No device found");
        match adapter.stop_discovery() {
            Ok(_) => println!("Stop discovery"),
            Err(e) => return error(e),
        }
    }
    println!("{} device(s) found", devices.len());
    let mut device: BTDevice = BTDevice::create_device("".to_string());
    'device_loop: for d in devices {
        device = BTDevice::create_device(d.clone());
        println!("{} {:?}", device.get_object_path(), device.get_alias());
        let uuids = match device.get_uuids() {
            Ok(u) => u,
            Err(e) => return error(e),
        };
        println!("{:?}", uuids);
        'uuid_loop: for uuid in uuids {
            if uuid == BATTERY_SERVICE_UUID {
                println!("{:?} has battery service!", device.get_alias());
                if !device.is_connected().unwrap() {
                    println!("connect device...");
                    match device.connect() {
                        Ok(_) => println!("connected!"),
                        Err(e) => return error(e),
                    }
                }
                break 'device_loop;
            }
        }
        println!("");
    }
    adapter.stop_discovery();
    println!("wait for it!!");
    // We need to wait a bit after calling connect to safely
    // get the gatt services
    thread::sleep(Duration::from_millis(1000));
    let services = match device.get_gatt_services() {
        Ok(s) => s,
        Err(e) => return error(e),
    };
    for service in services {
        let s = BTGATTService::new(service.clone());
        println!("{:?}", s);
        let characteristics = match s.get_characteristics() {
            Ok(c) => c,
            Err(e) => return error(e),
        };
        for characteristic in characteristics {
            let c = BTGATTCharacteristic::new(characteristic.clone());
            println!("{:?}", c);
            println!("Value: {:?}", c.read_value());
        }
    }
    device.disconnect();
}
<commit_msg>Add Descriptor to test2<commit_after>extern crate blurz;

static BATTERY_SERVICE_UUID: &'static str = "0000180f-0000-1000-8000-00805f9b34fb";

use std::time::Duration;
use std::thread;

use blurz::bluetooth_adapter::BluetoothAdapter as BTAdapter;
use blurz::bluetooth_device::BluetoothDevice as BTDevice;
use blurz::bluetooth_gatt_service::BluetoothGATTService as BTGATTService;
use blurz::bluetooth_gatt_characteristic::BluetoothGATTCharacteristic as BTGATTCharacteristic;
use blurz::bluetooth_gatt_descriptor::BluetoothGATTDescriptor as BTGATTDescriptor;

fn error(error: String) {
    println!("{}", error);
    std::process::exit(1);
}

fn main() {
    let adapter: BTAdapter = match BTAdapter::init() {
        Ok(a) => a,
        Err(e) => return error(e),
    };
    match adapter.start_discovery() {
        Ok(_) => println!("Start discovery"),
        Err(e) => return error(e),
    }
    let devices = adapter.get_device_list();
    if devices.is_empty() {
        println!("No device found");
        match adapter.stop_discovery() {
            Ok(_) => println!("Stop discovery"),
            Err(e) => return error(e),
        }
    }
    println!("{} device(s) found", devices.len());
    let mut device: BTDevice = BTDevice::create_device("".to_string());
    'device_loop: for d in devices {
        device = BTDevice::create_device(d.clone());
        println!("{} {:?}", device.get_object_path(), device.get_alias());
        let uuids = match device.get_uuids() {
            Ok(u) => u,
            Err(e) => return error(e),
        };
        println!("{:?}", uuids);
        'uuid_loop: for uuid in uuids {
            if uuid == BATTERY_SERVICE_UUID {
                println!("{:?} has battery service!", device.get_alias());
                if !device.is_connected().unwrap() {
                    println!("connect device...");
                    match device.connect() {
                        Ok(_) => println!("connected!"),
                        Err(e) => return error(e),
                    }
                }
                break 'device_loop;
            }
        }
        println!("");
    }
    adapter.stop_discovery();
    println!("wait for it!!");
    // We need to wait a bit after calling connect to safely
    // get the gatt services
    thread::sleep(Duration::from_millis(1000));
    let services = match device.get_gatt_services() {
        Ok(s) => s,
        Err(e) => return error(e),
    };
    for service in services {
        let s = BTGATTService::new(service.clone());
        println!("{:?}", s);
        let characteristics = match s.get_characteristics() {
            Ok(c) => c,
            Err(e) => return error(e),
        };
        for characteristic in characteristics {
            let c = BTGATTCharacteristic::new(characteristic.clone());
            println!("{:?}", c);
            println!("Value: {:?} == {:?}", c.read_value(), c.get_value());
            let descriptors = match c.get_descriptors() {
                Ok(d) => d,
                Err(e) => return error(e),
            };
            for descriptor in descriptors {
                let d = BTGATTDescriptor::new(descriptor.clone());
                println!("{:?}", d);
                println!("Value: {:?} == {:?}", d.read_value(), d.get_value());
            }

        }
    }
    device.disconnect();
}
<|endoftext|>


<commit_before>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

extern crate "twitter-api" as twitter;
extern crate "rustc-serialize" as rustc_serialize;
extern crate "oauth-client" as oauth;

use std::io::{File, Open, Read, Write, stdio};
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const PATH: &'static str = "./tweet.conf";

#[derive(Show, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read() -> Option<Config> {
        let path = Path::new(PATH);
        let mut file = match File::open_mode(&path, Open, Read) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self) {
        let path = Path::new(PATH);
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = file.write_line(json::encode(self).as_slice());
    }
}

fn console_input(prompt: &str) -> String {
    print!("{}\n\t", prompt);
    let line = stdio::stdin().read_line().unwrap();
    line.trim().to_string()
}

fn main() {
    let conf = match Config::read() {
        Some(c) => c,
        None => {
            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, pin.as_slice());

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };
            c.write();
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::tweet(&consumer, &access, status.as_slice());
}

<commit_msg>update to rustc 1.0.0-dev (70b13a7c7 2015-01-25 00:49:41 +0000)<commit_after>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

extern crate "twitter-api" as twitter;
extern crate "rustc-serialize" as rustc_serialize;
extern crate "oauth-client" as oauth;

use std::io::{File, Open, Read, Write, stdio};
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const PATH: &'static str = "./tweet.conf";

#[derive(Show, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read() -> Option<Config> {
        let path = Path::new(PATH);
        let mut file = match File::open_mode(&path, Open, Read) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self) {
        let path = Path::new(PATH);
        let mut file = match File::open_mode(&path, Open, Write) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = file.write_line(&json::encode(self).unwrap()[]);
    }
}

fn console_input(prompt: &str) -> String {
    print!("{}\n\t", prompt);
    let line = stdio::stdin().read_line().unwrap();
    line.trim().to_string()
}

fn main() {
    let conf = match Config::read() {
        Some(c) => c,
        None => {
            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, pin.as_slice());

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };
            c.write();
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::tweet(&consumer, &access, status.as_slice());
}

<|endoftext|>


<commit_before>extern crate lodepng;
use std::path::Path;

fn main() {
    let path = &Path::new("write_test.png");

    let image = [255, 0, 0,   0, 255, 0,
                 0, 0, 255,   0, 99, 99];

    // encode_file takes the path to the image, a u8 array,
    // the width, the height, the color mode, and the bit depth
    if let Err(e) = lodepng::encode_file(path, &image, 2, 2, lodepng::LCT_RGB, 8) {
        panic!("failed to write png: {:?}", e);
    }

    println!("Written to {}", path.display());
}
<commit_msg>Fixed type<commit_after>extern crate lodepng;
use std::path::Path;

fn main() {
    let path = &Path::new("write_test.png");

    let image = [255u8, 0, 0,   0, 255, 0,
                 0, 0, 255,   0, 99, 99];

    // encode_file takes the path to the image, a u8 array,
    // the width, the height, the color mode, and the bit depth
    if let Err(e) = lodepng::encode_file(path, &image, 2, 2, lodepng::LCT_RGB, 8) {
        panic!("failed to write png: {:?}", e);
    }

    println!("Written to {}", path.display());
}
<|endoftext|>


<commit_before>extern crate egg_mode;

mod common;

fn main() {
    let config = common::Config::load();
    let tweet_id = 766678057788829697;

    println!("");
    println!("Load up an individual tweet:");
    let status = egg_mode::tweet::show(tweet_id, &config.con_token, &config.access_token).unwrap().response;
    common::print_tweet(&status);

    println!("");
    println!("Loading retweets of an individual tweet:");
    for rt in &egg_mode::tweet::retweets_of(tweet_id, 5, &config.con_token, &config.access_token).unwrap().response {
        println!("{} (@{})", rt.user.name, rt.user.screen_name);
    }

    println!("");
    println!("Loading the user's home timeline:");
    let mut home = egg_mode::tweet::home_timeline(&config.con_token, &config.access_token).with_page_size(5);
    for status in &home.start().unwrap().response {
        common::print_tweet(&status);
        println!("");
    }

    println!("");
    println!("Loading the user's mentions timeline:");
    let mut home = egg_mode::tweet::mentions_timeline(&config.con_token, &config.access_token).with_page_size(5);
    for status in &home.start().unwrap().response {
        common::print_tweet(&status);
        println!("");
    }
}
<commit_msg>add user_timeline to examples/tweets<commit_after>extern crate egg_mode;

mod common;

fn main() {
    let config = common::Config::load();
    let tweet_id = 766678057788829697;

    println!("");
    println!("Load up an individual tweet:");
    let status = egg_mode::tweet::show(tweet_id, &config.con_token, &config.access_token).unwrap().response;
    common::print_tweet(&status);

    println!("");
    println!("Loading retweets of an individual tweet:");
    for rt in &egg_mode::tweet::retweets_of(tweet_id, 5, &config.con_token, &config.access_token).unwrap().response {
        println!("{} (@{})", rt.user.name, rt.user.screen_name);
    }

    println!("");
    println!("Loading the user's home timeline:");
    let mut home = egg_mode::tweet::home_timeline(&config.con_token, &config.access_token).with_page_size(5);
    for status in &home.start().unwrap().response {
        common::print_tweet(&status);
        println!("");
    }

    println!("");
    println!("Loading the user's mentions timeline:");
    let mut home = egg_mode::tweet::mentions_timeline(&config.con_token, &config.access_token).with_page_size(5);
    for status in &home.start().unwrap().response {
        common::print_tweet(&status);
        println!("");
    }

    println!("");
    println!("Loading the user's timeline:");
    let mut home = egg_mode::tweet::user_timeline(config.user_id, true, true,
                                                  &config.con_token, &config.access_token).with_page_size(5);
    for status in &home.start().unwrap().response {
        common::print_tweet(&status);
        println!("");
    }
}
<|endoftext|>


<commit_before>use super::utils::{LspPositionConversion, TupleToPosition};
use crate::{
    compiler::{
        ast_to_hir::AstToHir,
        cst::{CstDb, CstKind},
        hir::{self, Body, Expression, HirDb, Lambda},
    },
    database::Database,
    input::Input,
};
use im::HashSet;
use lsp_types::{
    DocumentHighlight, DocumentHighlightKind, DocumentHighlightParams, Location, ReferenceParams,
    TextDocumentPositionParams,
};

pub fn find_references(db: &Database, params: ReferenceParams) -> Option<Vec<Location>> {
    let position = params.text_document_position;
    let references = find(db, position.clone(), params.context.include_declaration)?
        .into_iter()
        .map(|it| Location {
            uri: position.text_document.uri.clone(),
            range: it.range,
        })
        .collect();
    Some(references)
}

pub fn find_document_highlights(
    db: &Database,
    params: DocumentHighlightParams,
) -> Option<Vec<DocumentHighlight>> {
    find(db, params.text_document_position_params, true)
}

fn find(
    db: &Database,
    params: TextDocumentPositionParams,
    include_declaration: bool,
) -> Option<Vec<DocumentHighlight>> {
    let input: Input = params.text_document.uri.clone().into();
    let position = params.position;
    let offset = db.offset_from_lsp(input.clone(), position.line, position.character);

    let origin_cst = db.find_cst_by_offset(input.clone(), offset);
    match origin_cst.kind {
        CstKind::Identifier { .. } => {}
        _ => return None,
    }

    let origin_hir_id = db.cst_to_hir_id(input, origin_cst.id)?;
    Some(db.references(origin_hir_id, include_declaration))
}

#[salsa::query_group(ReferencesDbStorage)]
pub trait ReferencesDb: HirDb + LspPositionConversion {
    fn references(&self, id: hir::Id, include_declaration: bool) -> Vec<DocumentHighlight>;
}

fn references(
    db: &dyn ReferencesDb,
    id: hir::Id,
    include_declaration: bool,
) -> Vec<DocumentHighlight> {
    let (hir, _) = db.hir(id.input.clone()).unwrap();

    let mut context = Context::new(db, id, include_declaration);
    context.visit_body(hir.as_ref());
    context.references
}

struct Context<'a> {
    db: &'a dyn ReferencesDb,
    id: hir::Id,
    include_declaration: bool,
    discovered_references: HashSet<hir::Id>,
    references: Vec<DocumentHighlight>,
}
impl<'a> Context<'a> {
    fn new(db: &'a dyn ReferencesDb, id: hir::Id, include_declaration: bool) -> Self {
        Self {
            db,
            id,
            include_declaration,
            discovered_references: HashSet::new(),
            references: vec![],
        }
    }

    fn visit_body(&mut self, body: &Body) {
        if body.identifiers.contains_key(&self.id) {
            self.add_reference(self.id.clone(), DocumentHighlightKind::WRITE);
        }
        for (id, expression) in &body.expressions {
            self.visit_expression(id.to_owned(), expression);
        }
    }
    fn visit_ids(&mut self, ids: &[hir::Id]) {
        for id in ids {
            self.visit_id(id.to_owned());
        }
    }
    fn visit_id(&mut self, id: hir::Id) {
        let expression = match self.db.find_expression(id.to_owned()) {
            Some(expression) => expression,
            None => return, // Generated code
        };
        self.visit_expression(id, &expression);
    }
    fn visit_expression(&mut self, id: hir::Id, expression: &Expression) {
        match expression {
            Expression::Int(_) => {}
            Expression::Text(_) => {}
            Expression::Reference(target) => {
                if target == &self.id {
                    self.add_reference(id, DocumentHighlightKind::READ);
                }
            }
            Expression::Symbol(_) => {}
            Expression::Struct(entries) => {
                for (key_id, value_id) in entries {
                    self.visit_id(key_id.to_owned());
                    self.visit_id(value_id.to_owned());
                }
            }
            Expression::Lambda(Lambda { body, .. }) => {
                // We don't need to visit the parameters: They can only be the
                // declaration of an identifier and don't reference it any other
                // way. Therfore, we already visit them in [visit_body].
                self.visit_body(body);
            }
            Expression::Call {
                function,
                arguments,
            } => {
                if function == &self.id {
                    self.add_reference(id, DocumentHighlightKind::READ);
                }
                self.visit_ids(arguments);
            }
            Expression::Builtin(_) => {}
            Expression::Needs { .. } => {}
            Expression::Error { child, .. } => {
                if let Some(child) = child {
                    self.visit_id(child.clone());
                }
            }
        }
    }

    fn add_reference(&mut self, id: hir::Id, kind: DocumentHighlightKind) {
        if id == self.id && !self.include_declaration {
            return;
        }

        if self.discovered_references.contains(&id) {
            return;
        }
        self.discovered_references.insert(id.clone());

        let span = self.db.hir_id_to_span(id.clone()).unwrap();
        self.references.push(DocumentHighlight {
            range: lsp_types::Range {
                start: self
                    .db
                    .offset_to_lsp(id.input.clone(), span.start)
                    .to_position(),
                end: self.db.offset_to_lsp(id.input, span.end).to_position(),
            },
            kind: Some(kind),
        });
    }
}
<commit_msg>Allow finding references to Symbols<commit_after>use super::utils::{LspPositionConversion, TupleToPosition};
use crate::{
    compiler::{
        ast_to_hir::AstToHir,
        cst::{CstDb, CstKind},
        hir::{self, Body, Expression, HirDb, Lambda},
    },
    database::Database,
    input::Input,
};
use im::HashSet;
use lsp_types::{
    DocumentHighlight, DocumentHighlightKind, DocumentHighlightParams, Location, ReferenceParams,
    TextDocumentPositionParams,
};

pub fn find_references(db: &Database, params: ReferenceParams) -> Option<Vec<Location>> {
    let position = params.text_document_position;
    let references = find(db, position.clone(), params.context.include_declaration)?
        .into_iter()
        .map(|it| Location {
            uri: position.text_document.uri.clone(),
            range: it.range,
        })
        .collect();
    Some(references)
}

pub fn find_document_highlights(
    db: &Database,
    params: DocumentHighlightParams,
) -> Option<Vec<DocumentHighlight>> {
    find(db, params.text_document_position_params, true)
}

fn find(
    db: &Database,
    params: TextDocumentPositionParams,
    include_declaration: bool,
) -> Option<Vec<DocumentHighlight>> {
    let input: Input = params.text_document.uri.clone().into();
    let position = params.position;
    let offset = db.offset_from_lsp(input.clone(), position.line, position.character);

    let origin_cst = db.find_cst_by_offset(input.clone(), offset);
    let query = match origin_cst.kind {
        CstKind::Identifier { .. } => ReferenceQuery::Id(db.cst_to_hir_id(input, origin_cst.id)?),
        CstKind::Symbol(symbol) => ReferenceQuery::Symbol(input, symbol),
        _ => return None,
    };

    Some(db.references(query, include_declaration))
}

#[salsa::query_group(ReferencesDbStorage)]
pub trait ReferencesDb: HirDb + LspPositionConversion {
    fn references(
        &self,
        query: ReferenceQuery,
        include_declaration: bool,
    ) -> Vec<DocumentHighlight>;
}

fn references(
    db: &dyn ReferencesDb,
    query: ReferenceQuery,
    include_declaration: bool,
) -> Vec<DocumentHighlight> {
    // TODO: search all files
    let input = match &query {
        ReferenceQuery::Id(id) => id.input.clone(),
        ReferenceQuery::Symbol(input, _) => input.to_owned(),
    };
    let (hir, _) = db.hir(input).unwrap();

    let mut context = Context::new(db, query, include_declaration);
    context.visit_body(hir.as_ref());
    context.references
}

struct Context<'a> {
    db: &'a dyn ReferencesDb,
    query: ReferenceQuery,
    include_declaration: bool,
    discovered_references: HashSet<hir::Id>,
    references: Vec<DocumentHighlight>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ReferenceQuery {
    Id(hir::Id),
    Symbol(Input, String),
}
impl<'a> Context<'a> {
    fn new(db: &'a dyn ReferencesDb, query: ReferenceQuery, include_declaration: bool) -> Self {
        Self {
            db,
            query,
            include_declaration,
            discovered_references: HashSet::new(),
            references: vec![],
        }
    }

    fn visit_body(&mut self, body: &Body) {
        if let ReferenceQuery::Id(id) = &self.query {
            if body.identifiers.contains_key(&id) {
                self.add_reference(id.clone(), DocumentHighlightKind::WRITE);
            }
        }
        for (id, expression) in &body.expressions {
            self.visit_expression(id.to_owned(), expression);
        }
    }
    fn visit_ids(&mut self, ids: &[hir::Id]) {
        for id in ids {
            self.visit_id(id.to_owned());
        }
    }
    fn visit_id(&mut self, id: hir::Id) {
        let expression = match self.db.find_expression(id.to_owned()) {
            Some(expression) => expression,
            None => return, // Generated code
        };
        self.visit_expression(id, &expression);
    }
    fn visit_expression(&mut self, id: hir::Id, expression: &Expression) {
        match expression {
            Expression::Int(_) => {}
            Expression::Text(_) => {}
            Expression::Reference(target) => {
                if let ReferenceQuery::Id(target_id) = &self.query {
                    if target == target_id {
                        self.add_reference(id, DocumentHighlightKind::READ);
                    }
                }
            }
            Expression::Symbol(symbol) => {
                if let ReferenceQuery::Symbol(_, target) = &self.query {
                    if symbol == target {
                        self.add_reference(id, DocumentHighlightKind::READ);
                    }
                }
            }
            Expression::Struct(entries) => {
                for (key_id, value_id) in entries {
                    self.visit_id(key_id.to_owned());
                    self.visit_id(value_id.to_owned());
                }
            }
            Expression::Lambda(Lambda { body, .. }) => {
                // We don't need to visit the parameters: They can only be the
                // declaration of an identifier and don't reference it any other
                // way. Therfore, we already visit them in [visit_body].
                self.visit_body(body);
            }
            Expression::Call {
                function,
                arguments,
            } => {
                if let ReferenceQuery::Id(target_id) = &self.query {
                    if function == target_id {
                        self.add_reference(id, DocumentHighlightKind::READ);
                    }
                }
                self.visit_ids(arguments);
            }
            Expression::Builtin(_) => {}
            Expression::Needs { .. } => {}
            Expression::Error { child, .. } => {
                if let Some(child) = child {
                    self.visit_id(child.clone());
                }
            }
        }
    }

    fn add_reference(&mut self, id: hir::Id, kind: DocumentHighlightKind) {
        if let ReferenceQuery::Id(target_id) = &self.query {
            if &id == target_id && !self.include_declaration {
                return;
            }
        }

        if self.discovered_references.contains(&id) {
            return;
        }
        self.discovered_references.insert(id.clone());

        let span = self.db.hir_id_to_span(id.clone()).unwrap();
        self.references.push(DocumentHighlight {
            range: lsp_types::Range {
                start: self
                    .db
                    .offset_to_lsp(id.input.clone(), span.start)
                    .to_position(),
                end: self.db.offset_to_lsp(id.input, span.end).to_position(),
            },
            kind: Some(kind),
        });
    }
}
<|endoftext|>


<commit_before>/*!
 * Helpers for headers
 */

pub mod tags;

/**
 * Utility helpers for header data
 */
pub mod data {
    use std::ops::Deref;
    use storage::file::header::data::FileHeaderData as FHD;

    /**
     * Get an URL from a header, whereas the header has to have the following format:
     *
     *   { ..., "URL": "<URL>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_url_from_header(header: &FHD) -> Option<String> {
        get_named_text_from_header("URL", header)
    }

    /**
     * Get an NAME from a header, whereas the header has to have the following format:
     *
     *   { ..., "NAME": "<NAME>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_name_from_header(header: &FHD) -> Option<String> {
        get_named_text_from_header("NAME", header)
    }

    /**
     * Get a named field from the header, which has to be of this format
     *
     *   { ..., "<name of field>": "<content as string>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_named_text_from_header(name: &'static str, header: &FHD) -> Option<String> {
        match header {
            &FHD::Map{keys: ref ks} => {
                let mut keys : Vec<FHD> = ks.clone();
                keys.iter().find(|k| {
                    match k.deref() {
                        &FHD::Key{name: ref n, value: _} => n == name,
                        _ => false
                    }
                }).and_then(|urlkey| {
                    match urlkey.deref().clone() {
                        FHD::Key{name: ref n, value: ref v} => {
                            match v.deref().clone() {
                                FHD::Text(s) => Some(s),
                                _ => {
                                    warn!("Malformed Header Data: Expected Text, found non-Text");
                                    debug!("    in {}", n);
                                    None
                                },
                            }
                        }
                        _ => {
                            warn!("Malformed Header Data: Expected Text, found non-Text");
                            None
                        },
                    }
                })
            },
            _ => {
                warn!("Malformed Header Data: Expected Map, found non-Map");
                None
            }
        }
    }

}

<commit_msg>Remove unneeded Keyword "mut" and unneeded variable<commit_after>/*!
 * Helpers for headers
 */

pub mod tags;

/**
 * Utility helpers for header data
 */
pub mod data {
    use std::ops::Deref;
    use storage::file::header::data::FileHeaderData as FHD;

    /**
     * Get an URL from a header, whereas the header has to have the following format:
     *
     *   { ..., "URL": "<URL>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_url_from_header(header: &FHD) -> Option<String> {
        get_named_text_from_header("URL", header)
    }

    /**
     * Get an NAME from a header, whereas the header has to have the following format:
     *
     *   { ..., "NAME": "<NAME>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_name_from_header(header: &FHD) -> Option<String> {
        get_named_text_from_header("NAME", header)
    }

    /**
     * Get a named field from the header, which has to be of this format
     *
     *   { ..., "<name of field>": "<content as string>", ... }
     *
     * Does no spec verification.
     */
    pub fn get_named_text_from_header(name: &'static str, header: &FHD) -> Option<String> {
        match header {
            &FHD::Map{keys: ref ks} => {
                ks.clone()
                    .iter()
                    .find(|k| {
                        match k.deref() {
                            &FHD::Key{name: ref n, value: _} => n == name,
                            _ => false
                        }
                }).and_then(|urlkey| {
                    match urlkey.deref().clone() {
                        FHD::Key{name: ref n, value: ref v} => {
                            match v.deref().clone() {
                                FHD::Text(s) => Some(s),
                                _ => {
                                    warn!("Malformed Header Data: Expected Text, found non-Text");
                                    debug!("    in {}", n);
                                    None
                                },
                            }
                        }
                        _ => {
                            warn!("Malformed Header Data: Expected Text, found non-Text");
                            None
                        },
                    }
                })
            },
            _ => {
                warn!("Malformed Header Data: Expected Map, found non-Map");
                None
            }
        }
    }

}

<|endoftext|>


<commit_before>//
// base64n.rs - new base64 module
//
// The Base64 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//      0 A            17 R            34 i            51 z
//      1 B            18 S            35 j            52 0
//      2 C            19 T            36 k            53 1
//      3 D            20 U            37 l            54 2
//      4 E            21 V            38 m            55 3
//      5 F            22 W            39 n            56 4
//      6 G            23 X            40 o            57 5
//      7 H            24 Y            41 p            58 6
//      8 I            25 Z            42 q            59 7
//      9 J            26 a            43 r            60 8
//     10 K            27 b            44 s            61 9
//     11 L            28 c            45 t            62 +
//     12 M            29 d            46 u            63 /
//     13 N            30 e            47 v
//     14 O            31 f            48 w         (pad) =
//     15 P            32 g            49 x
//     16 Q            33 h            50 y
//
// The "URL and Filename safe" Base 64 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A            17 R            34 i            51 z
//     1 B            18 S            35 j            52 0
//     2 C            19 T            36 k            53 1
//     3 D            20 U            37 l            54 2
//     4 E            21 V            38 m            55 3
//     5 F            22 W            39 n            56 4
//     6 G            23 X            40 o            57 5
//     7 H            24 Y            41 p            58 6
//     8 I            25 Z            42 q            59 7
//     9 J            26 a            43 r            60 8
//    10 K            27 b            44 s            61 9
//    11 L            28 c            45 t            62 - (minus)
//    12 M            29 d            46 u            63 _ (underline)
//    13 N            30 e            47 v
//    14 O            31 f            48 w
//    15 P            32 g            49 x
//    16 Q            33 h            50 y         (pad) =
//

use std;

import vec::len;

const PAD: u8 = 61u8;

iface enc {
    fn encode(dst: [mutable u8], src: [u8]);
    fn encode_u(dst: [mutable u8], src: [u8]);
    fn encode_bytes(src: [u8]) -> [u8];
    fn encode_bytes_u(src: [u8]) -> [u8];
    fn encode_str(src: str) -> str;
    fn encode_str_u(src: str) -> str;
    // FIXME `decode` and `decode_u` should return desired length of `dst`
    fn decode(dst: [mutable u8], src: [u8]);
    fn decode_u(dst: [mutable u8], src: [u8]);
    fn decode_bytes(src: [u8]) -> [u8];
    fn decode_bytes_u(src: [u8]) -> [u8];
}

fn mk() -> enc {
    type _enc = {table: [u8], table_u: [u8],
                 decode_map: [u8], decode_map_u: [u8]};

    impl of enc for _enc {
        fn encode(dst: [mutable u8], src: [u8]) {
            b64encode(self.table, dst, src);
        }
        fn encode_u(dst: [mutable u8], src: [u8]) {
            b64encode(self.table_u, dst, src);
        }
        fn encode_bytes(src: [u8]) -> [u8] {
            let dst_length = encoded_len(len(src));
            let dst = vec::to_mut(vec::from_elem(dst_length, 0u8));
            self.encode(dst, src);
            vec::from_mut(dst)
        }
        fn encode_bytes_u(src: [u8]) -> [u8] {
            let dst_length = encoded_len(len(src));
            let dst = vec::to_mut(vec::from_elem(dst_length, 0u8));
            self.encode_u(dst, src);
            vec::from_mut(dst)
        }
        fn encode_str(src: str) -> str {
            let src = str::bytes(src);
            str::from_bytes(self.encode_bytes(src))
        }
        fn encode_str_u(src: str) -> str {
            let src = str::bytes(src);
            str::from_bytes(self.encode_bytes_u(src))
        }
        fn decode(dst: [mutable u8], src: [u8]) {
            b64decode(self.decode_map, dst, src);
        }
        fn decode_u(dst: [mutable u8], src: [u8]) {
            b64decode(self.decode_map_u, dst, src);
        }
        fn decode_bytes(src: [u8]) -> [u8] { [] }
        fn decode_bytes_u(src: [u8]) -> [u8] { [] }
    }

    let table = vec::to_mut(vec::from_elem(64u, 0u8)), i = 0u8;
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(97u8, 123u8) { |j| table[i] = j; i += 1u8; }
    u8::range(48u8, 58u8)  { |j| table[i] = j; i += 1u8; }
    table[i] = 43u8; table[i + 1u8] = 47u8;

    let table_u = table;
    table_u[i] = 45u8; table_u[i + 1u8] = 95u8;

    let decode_map = vec::to_mut(vec::from_elem(256u, 0xff_u8));
    let decode_map_u = vec::to_mut(vec::from_elem(256u, 0xff_u8));

    i = 0u8;
    while i < 64u8 {
        decode_map[table[i]] = i as u8;
        i += 1u8;
    }

    i = 0u8;
    while i < 64u8 {
        decode_map_u[table_u[i]] = i as u8;
        i += 1u8;
    }

    {table: vec::from_mut(table),
     table_u: vec::from_mut(table_u),
     decode_map: vec::from_mut(decode_map),
     decode_map_u: vec::from_mut(decode_map_u)} as enc
}

fn encoded_len(src_length: uint) -> uint {
    (src_length + 2u) / 3u * 4u
}

fn decoded_len(src_length: uint) -> uint {
    src_length / 4u * 3u
}

fn b64encode(table: [u8], dst: [mutable u8], src: [u8]) {
    if len(src) == 0u {
        ret;
    }

    let src_length = len(src);
    let dst_length = len(dst);
    let dst_curr = 0u;
    let src_curr = 0u;

    if dst_length % 4u != 0u {
        fail "dst's length should be divisible by 4";
    }

    while src_length > 0u {
        dst[dst_curr + 0u] = 0u8;
        dst[dst_curr + 1u] = 0u8;
        dst[dst_curr + 2u] = 0u8;
        dst[dst_curr + 3u] = 0u8;

        if src_length == 1u {
            dst[dst_curr + 0u] |= (src[src_curr + 0u]) >> 2u8;
            dst[dst_curr + 1u] |= (src[src_curr + 0u] << 4u8) & 0x3f_u8;
        } else if src_length == 2u {
            dst[dst_curr + 0u] |= (src[src_curr + 0u]) >> 2u8;
            dst[dst_curr + 1u] |= (src[src_curr + 0u] << 4u8) & 0x3f_u8;
            dst[dst_curr + 1u] |= (src[src_curr + 1u] >> 4u8);
            dst[dst_curr + 2u] |= (src[src_curr + 1u] << 2u8) & 0x3f_u8;
        } else {
            dst[dst_curr + 0u] |= (src[src_curr + 0u]) >> 2u8;
            dst[dst_curr + 1u] |= (src[src_curr + 0u] << 4u8) & 0x3f_u8;
            dst[dst_curr + 1u] |= (src[src_curr + 1u] >> 4u8);
            dst[dst_curr + 2u] |= (src[src_curr + 1u] << 2u8) & 0x3f_u8;
            dst[dst_curr + 2u] |= (src[src_curr + 2u] >> 6u8);
            dst[dst_curr + 3u] |= (src[src_curr + 2u]) & 0x3f_u8;
        }

        dst[dst_curr + 0u] = table[dst[dst_curr + 0u]];
        dst[dst_curr + 1u] = table[dst[dst_curr + 1u]];
        dst[dst_curr + 2u] = table[dst[dst_curr + 2u]];
        dst[dst_curr + 3u] = table[dst[dst_curr + 3u]];

        if src_length < 3u {
            dst[dst_curr + 3u] = PAD;
            if src_length < 2u {
                dst[dst_curr + 2u] = PAD;
            }
            break;
        }

        src_length -= 3u;
        src_curr += 3u;
        dst_curr += 4u;
    }
}

fn b64decode(decode_map: [u8], dst: [mutable u8], src: [u8]) {
    // FIXME write
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_encode_bytes() {
        let src = [102u8, 111u8, 111u8, 98u8, 97u8, 114u8];
        let enc = mk();
        let res = enc.encode_bytes(src);
        assert res == [90u8, 109u8, 57u8, 118u8, 89u8, 109u8, 70u8, 121u8];
    }
    #[test]
    fn test_encode_str() {
        let src = "foobar";
        let enc = mk();
        let res = enc.encode_str(src);
        assert res == "Zm9vYmFy";
    }
    #[test]
    fn test_encode_bytes_u() {
        let src = [102u8, 111u8, 111u8, 98u8, 97u8, 63u8];
        let enc = mk();
        let res = enc.encode_bytes_u(src);
        assert res == [90u8, 109u8, 57u8, 118u8, 89u8, 109u8, 69u8, 95u8];
    }
    #[test]
    fn test_encode_str_u() {
        let src = "fooba?";
        let enc = mk();
        let res = enc.encode_str_u(src);
        assert res == "Zm9vYmE_";
    }
}
<commit_msg>base64n: use explicit syntax for mutable values<commit_after>//
// base64n.rs - new base64 module
//
// The Base64 Alphabet
//
//  Value Encoding  Value Encoding  Value Encoding  Value Encoding
//      0 A            17 R            34 i            51 z
//      1 B            18 S            35 j            52 0
//      2 C            19 T            36 k            53 1
//      3 D            20 U            37 l            54 2
//      4 E            21 V            38 m            55 3
//      5 F            22 W            39 n            56 4
//      6 G            23 X            40 o            57 5
//      7 H            24 Y            41 p            58 6
//      8 I            25 Z            42 q            59 7
//      9 J            26 a            43 r            60 8
//     10 K            27 b            44 s            61 9
//     11 L            28 c            45 t            62 +
//     12 M            29 d            46 u            63 /
//     13 N            30 e            47 v
//     14 O            31 f            48 w         (pad) =
//     15 P            32 g            49 x
//     16 Q            33 h            50 y
//
// The "URL and Filename safe" Base 64 Alphabet
//
// Value Encoding  Value Encoding  Value Encoding  Value Encoding
//     0 A            17 R            34 i            51 z
//     1 B            18 S            35 j            52 0
//     2 C            19 T            36 k            53 1
//     3 D            20 U            37 l            54 2
//     4 E            21 V            38 m            55 3
//     5 F            22 W            39 n            56 4
//     6 G            23 X            40 o            57 5
//     7 H            24 Y            41 p            58 6
//     8 I            25 Z            42 q            59 7
//     9 J            26 a            43 r            60 8
//    10 K            27 b            44 s            61 9
//    11 L            28 c            45 t            62 - (minus)
//    12 M            29 d            46 u            63 _ (underline)
//    13 N            30 e            47 v
//    14 O            31 f            48 w
//    15 P            32 g            49 x
//    16 Q            33 h            50 y         (pad) =
//

use std;

import vec::len;

const PAD: u8 = 61u8;

iface enc {
    fn encode(dst: [mutable u8], src: [u8]);
    fn encode_u(dst: [mutable u8], src: [u8]);
    fn encode_bytes(src: [u8]) -> [u8];
    fn encode_bytes_u(src: [u8]) -> [u8];
    fn encode_str(src: str) -> str;
    fn encode_str_u(src: str) -> str;
    // FIXME `decode` and `decode_u` should return desired length of `dst`
    fn decode(dst: [mutable u8], src: [u8]);
    fn decode_u(dst: [mutable u8], src: [u8]);
    fn decode_bytes(src: [u8]) -> [u8];
    fn decode_bytes_u(src: [u8]) -> [u8];
}

fn mk() -> enc {
    type _enc = {table: [u8], table_u: [u8],
                 decode_map: [u8], decode_map_u: [u8]};

    impl of enc for _enc {
        fn encode(dst: [mutable u8], src: [u8]) {
            b64encode(self.table, dst, src);
        }
        fn encode_u(dst: [mutable u8], src: [u8]) {
            b64encode(self.table_u, dst, src);
        }
        fn encode_bytes(src: [u8]) -> [u8] {
            let dst_length = encoded_len(len(src));
            let dst = vec::to_mut(vec::from_elem(dst_length, 0u8));
            self.encode(dst, src);
            vec::from_mut(dst)
        }
        fn encode_bytes_u(src: [u8]) -> [u8] {
            let dst_length = encoded_len(len(src));
            let dst = vec::to_mut(vec::from_elem(dst_length, 0u8));
            self.encode_u(dst, src);
            vec::from_mut(dst)
        }
        fn encode_str(src: str) -> str {
            let src = str::bytes(src);
            str::from_bytes(self.encode_bytes(src))
        }
        fn encode_str_u(src: str) -> str {
            let src = str::bytes(src);
            str::from_bytes(self.encode_bytes_u(src))
        }
        fn decode(dst: [mutable u8], src: [u8]) {
            b64decode(self.decode_map, dst, src);
        }
        fn decode_u(dst: [mutable u8], src: [u8]) {
            b64decode(self.decode_map_u, dst, src);
        }
        fn decode_bytes(src: [u8]) -> [u8] { [] }
        fn decode_bytes_u(src: [u8]) -> [u8] { [] }
    }

    let mut i = 0u8;
    let table = vec::to_mut(vec::from_elem(64u, 0u8));
    u8::range(65u8, 91u8)  { |j| table[i] = j; i += 1u8; }
    u8::range(97u8, 123u8) { |j| table[i] = j; i += 1u8; }
    u8::range(48u8, 58u8)  { |j| table[i] = j; i += 1u8; }
    table[i] = 43u8; table[i + 1u8] = 47u8;

    let table_u = table;
    table_u[i] = 45u8; table_u[i + 1u8] = 95u8;

    let decode_map = vec::to_mut(vec::from_elem(256u, 0xff_u8));
    let decode_map_u = vec::to_mut(vec::from_elem(256u, 0xff_u8));

    i = 0u8;
    while i < 64u8 {
        decode_map[table[i]] = i as u8;
        i += 1u8;
    }

    i = 0u8;
    while i < 64u8 {
        decode_map_u[table_u[i]] = i as u8;
        i += 1u8;
    }

    {table: vec::from_mut(table),
     table_u: vec::from_mut(table_u),
     decode_map: vec::from_mut(decode_map),
     decode_map_u: vec::from_mut(decode_map_u)} as enc
}

fn encoded_len(src_length: uint) -> uint {
    (src_length + 2u) / 3u * 4u
}

fn decoded_len(src_length: uint) -> uint {
    src_length / 4u * 3u
}

fn b64encode(table: [u8], dst: [mutable u8], src: [u8]) {
    if len(src) == 0u {
        ret;
    }

    let mut src_length = len(src);
    let mut dst_length = len(dst);
    let mut dst_curr = 0u;
    let mut src_curr = 0u;

    if dst_length % 4u != 0u {
        fail "dst's length should be divisible by 4";
    }

    while src_length > 0u {
        dst[dst_curr + 0u] = 0u8;
        dst[dst_curr + 1u] = 0u8;
        dst[dst_curr + 2u] = 0u8;
        dst[dst_curr + 3u] = 0u8;

        if src_length == 1u {
            dst[dst_curr + 0u] |= (src[src_curr + 0u]) >> 2u8;
            dst[dst_curr + 1u] |= (src[src_curr + 0u] << 4u8) & 0x3f_u8;
        } else if src_length == 2u {
            dst[dst_curr + 0u] |= (src[src_curr + 0u]) >> 2u8;
            dst[dst_curr + 1u] |= (src[src_curr + 0u] << 4u8) & 0x3f_u8;
            dst[dst_curr + 1u] |= (src[src_curr + 1u] >> 4u8);
            dst[dst_curr + 2u] |= (src[src_curr + 1u] << 2u8) & 0x3f_u8;
        } else {
            dst[dst_curr + 0u] |= (src[src_curr + 0u]) >> 2u8;
            dst[dst_curr + 1u] |= (src[src_curr + 0u] << 4u8) & 0x3f_u8;
            dst[dst_curr + 1u] |= (src[src_curr + 1u] >> 4u8);
            dst[dst_curr + 2u] |= (src[src_curr + 1u] << 2u8) & 0x3f_u8;
            dst[dst_curr + 2u] |= (src[src_curr + 2u] >> 6u8);
            dst[dst_curr + 3u] |= (src[src_curr + 2u]) & 0x3f_u8;
        }

        dst[dst_curr + 0u] = table[dst[dst_curr + 0u]];
        dst[dst_curr + 1u] = table[dst[dst_curr + 1u]];
        dst[dst_curr + 2u] = table[dst[dst_curr + 2u]];
        dst[dst_curr + 3u] = table[dst[dst_curr + 3u]];

        if src_length < 3u {
            dst[dst_curr + 3u] = PAD;
            if src_length < 2u {
                dst[dst_curr + 2u] = PAD;
            }
            break;
        }

        src_length -= 3u;
        src_curr += 3u;
        dst_curr += 4u;
    }
}

fn b64decode(decode_map: [u8], dst: [mutable u8], src: [u8]) {
    // FIXME write
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_encode_bytes() {
        let src = [102u8, 111u8, 111u8, 98u8, 97u8, 114u8];
        let enc = mk();
        let res = enc.encode_bytes(src);
        assert res == [90u8, 109u8, 57u8, 118u8, 89u8, 109u8, 70u8, 121u8];
    }
    #[test]
    fn test_encode_str() {
        let src = "foobar";
        let enc = mk();
        let res = enc.encode_str(src);
        assert res == "Zm9vYmFy";
    }
    #[test]
    fn test_encode_bytes_u() {
        let src = [102u8, 111u8, 111u8, 98u8, 97u8, 63u8];
        let enc = mk();
        let res = enc.encode_bytes_u(src);
        assert res == [90u8, 109u8, 57u8, 118u8, 89u8, 109u8, 69u8, 95u8];
    }
    #[test]
    fn test_encode_str_u() {
        let src = "fooba?";
        let enc = mk();
        let res = enc.encode_str_u(src);
        assert res == "Zm9vYmE_";
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap};
use std::collections::hash_map::Entry;

use hash::*;
use math::*;
use stopwatch::Stopwatch;

use ecs::Entity;
use super::bounding_volume::*;
// use debug_draw;

/// A collision processor that partitions the space into a regular grid.
///
/// # TODO
///
/// - Do something to configure the size of the grid.
#[derive(Debug)]
#[allow(raw_pointer_derive)]
pub struct GridCollisionSystem {
    pub grid: HashMap<GridCell, Vec<(Entity, *const BoundVolume)>, FnvHashState>,

    /// This should be a HashSet, but HashSet doesn't have a way to get at entries directly.
    pub collisions: HashMap<(Entity, Entity), (), FnvHashState>,
    pub cell_size: f32,
}

impl Clone for GridCollisionSystem {
    /// `GridCollisionSystem` doesn't have any real state between frames, it's only used to reuse
    /// the grid's allocated memory between frames. Therefore to clone it we just invoke
    /// `GridCollisionSystem::new()`.
    fn clone(&self) -> Self {
        GridCollisionSystem::new()
    }
}

impl GridCollisionSystem {
    pub fn new() -> GridCollisionSystem {
        GridCollisionSystem {
            grid: HashMap::default(),
            collisions: HashMap::default(),
            cell_size: 1.0,
        }
    }

    pub fn update(&mut self, bvh_manager: &BoundingVolumeManager) {
        let _stopwatch = Stopwatch::new("Grid Collision System");

        // // Debug draw the grid.
        // for i in -50..50 {
        //     let offset = i as f32;
        //     debug_draw::line(
        //         Point::new(offset * self.cell_size, -50.0 * self.cell_size, 0.0),
        //         Point::new(offset * self.cell_size,  50.0 * self.cell_size, 0.0));
        //     debug_draw::line(
        //         Point::new(-50.0 * self.cell_size, offset * self.cell_size, 0.0),
        //         Point::new( 50.0 * self.cell_size, offset * self.cell_size, 0.0));
        // }

        self.collisions.clear();

        for bvh in bvh_manager.components() {
            let entity = bvh.entity;

            // Retrieve the AABB at the root of the BVH.
            let aabb = bvh.aabb;

            let min_cell = self.world_to_grid(aabb.min);
            let max_cell = self.world_to_grid(aabb.max);

            // Iterate over all grid cells that the AABB touches. Test the BVH against any entities
            // that have already been placed in that cell, then add the BVH to the cell, creating
            // new cells as necessary.
            for test_cell in min_cell.iter_to(max_cell) {

                if let Some(mut cell) = self.grid.get_mut(&test_cell) {
                    // Check against other volumes.
                    for (other_entity, other_bvh) in cell.iter().cloned() {
                        let other_bvh = unsafe { &*other_bvh };
                        let collision_pair = (entity, other_entity);

                        // Check if the collision has already been detected before running the
                        // collision test since it's potentially very expensive. We get the entry
                        // directly, that way we only have to do one hash lookup.
                        match self.collisions.entry(collision_pair) {
                            Entry::Vacant(vacant_entry) => {
                                // Collision hasn't already been detected, so do the test.
                                if bvh.test(other_bvh) {
                                    // Woo, we have a collison.
                                    vacant_entry.insert(());
                                }
                            },
                            _ => {},
                        }
                    }

                    // Add to existing cell.
                    cell.push((entity, bvh));
                    continue;
                }
                // else
                {
                    let cell = vec![(entity, bvh as *const _)];
                    self.grid.insert(test_cell, cell);
                }
            }
        }

        // Clear out grid contents from previous frame, start each frame with an empty grid an
        // rebuilt it rather than trying to update the grid as objects move.
        for (_, mut cell) in &mut self.grid {
            cell.clear();
        }
    }

    /// Converts a point in world space to its grid cell.
    fn world_to_grid(&self, point: Point) -> GridCell {
        GridCell {
            x: (point.x / self.cell_size).floor() as GridCoord,
            y: (point.y / self.cell_size).floor() as GridCoord,
            z: (point.z / self.cell_size).floor() as GridCoord,
        }
    }
}

/// A wrapper type around a triple of coordinates that uniquely identify a grid cell.
///
/// # Details
///
/// Grid cells are axis-aligned cubes of a regular sice. The coordinates of a grid cell are its min
/// value. This was chosen because of how it simplifies the calculation to find the cell for a
/// given point (`(point / cell_size).floor()`).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GridCell {
    pub x: GridCoord,
    pub y: GridCoord,
    pub z: GridCoord,
}

pub type GridCoord = i16;

impl GridCell {
    pub fn new(x: GridCoord, y: GridCoord, z: GridCoord) -> GridCell {
        GridCell {
            x: x,
            y: y,
            z: z,
        }
    }

    pub fn iter_to(&self, dest: GridCell) -> GridIter {
        // assert!(self < dest, "start point for grid iter must be less that end point, or use iter_from()");

        GridIter {
            from: *self,
            to:   dest,
            next: *self,
        }
    }
}

pub struct GridIter {
    from: GridCell,
    to:   GridCell,
    next: GridCell,
}

impl Iterator for GridIter {
    type Item = GridCell;

    fn next(&mut self) -> Option<GridCell> {
        let from = self.from;
        let to = self.to;
        let mut next = self.next;

        if next.z >= to.z {
            next.z = from.z;
            if next.y >= to.y {
                next.y = from.y;
                if next.x >= to.x {
                    return None;
                } else {
                    next.x += 1;
                }
            } else {
                next.y += 1;
            }
        } else {
            next.z += 1;
        }

        ::std::mem::swap(&mut self.next, &mut next);
        Some(next)
    }
}
<commit_msg>Separate Broadphase and Narrowphase Testing<commit_after>use std::collections::{HashMap};
use std::collections::hash_map::Entry;

use hash::*;
use math::*;
use stopwatch::Stopwatch;

use ecs::Entity;
use super::bounding_volume::*;
// use debug_draw;

/// A collision processor that partitions the space into a regular grid.
///
/// # TODO
///
/// - Do something to configure the size of the grid.
#[derive(Debug)]
#[allow(raw_pointer_derive)]
pub struct GridCollisionSystem {
    pub grid: HashMap<GridCell, Vec<(Entity, *const BoundVolume)>, FnvHashState>,

    /// This should be a HashSet, but HashSet doesn't have a way to get at entries directly.
    pub collisions: HashMap<(Entity, Entity), (), FnvHashState>,
    pub cell_size: f32,

    candidate_collisions: Vec<(*const BoundVolume, *const BoundVolume)>,
}

impl Clone for GridCollisionSystem {
    /// `GridCollisionSystem` doesn't have any real state between frames, it's only used to reuse
    /// the grid's allocated memory between frames. Therefore to clone it we just invoke
    /// `GridCollisionSystem::new()`.
    fn clone(&self) -> Self {
        GridCollisionSystem::new()
    }
}

impl GridCollisionSystem {
    pub fn new() -> GridCollisionSystem {
        GridCollisionSystem {
            grid: HashMap::default(),
            collisions: HashMap::default(),
            cell_size: 1.0,

            candidate_collisions: Vec::new(),
        }
    }

    pub fn update(&mut self, bvh_manager: &BoundingVolumeManager) {
        let _stopwatch = Stopwatch::new("Grid Collision System");

        // // Debug draw the grid.
        // for i in -50..50 {
        //     let offset = i as f32;
        //     debug_draw::line(
        //         Point::new(offset * self.cell_size, -50.0 * self.cell_size, 0.0),
        //         Point::new(offset * self.cell_size,  50.0 * self.cell_size, 0.0));
        //     debug_draw::line(
        //         Point::new(-50.0 * self.cell_size, offset * self.cell_size, 0.0),
        //         Point::new( 50.0 * self.cell_size, offset * self.cell_size, 0.0));
        // }

        self.collisions.clear();

        self.do_broadphase(bvh_manager);
        self.do_narrowphase();

        // Clear out grid contents from previous frame, start each frame with an empty grid and
        // rebuild it rather than trying to update the grid as objects move.
        for (_, mut cell) in &mut self.grid {
            cell.clear();
        }
    }

    fn do_broadphase(&mut self, bvh_manager: &BoundingVolumeManager) {
        let _stopwatch = Stopwatch::new("Broadphase Testing (Grid Based)");
        for bvh in bvh_manager.components() {
            let entity = bvh.entity;

            // Retrieve the AABB at the root of the BVH.
            let aabb = bvh.aabb;

            let min_cell = self.world_to_grid(aabb.min);
            let max_cell = self.world_to_grid(aabb.max);

            // Iterate over all grid cells that the AABB touches. Test the BVH against any entities
            // that have already been placed in that cell, then add the BVH to the cell, creating
            // new cells as necessary.
            for test_cell in min_cell.iter_to(max_cell) {

                if let Some(mut cell) = self.grid.get_mut(&test_cell) {
                    // Check against other volumes.
                    for (_, other_bvh) in cell.iter().cloned() {
                        self.candidate_collisions.push((bvh as *const _, other_bvh));
                    }

                    // Add to existing cell.
                    cell.push((entity, bvh));
                    continue;
                }
                // else
                {
                    let cell = vec![(entity, bvh as *const _)];
                    self.grid.insert(test_cell, cell);
                }
            }
        }
    }

    fn do_narrowphase(&mut self) {
        let _stopwatch = Stopwatch::new("Narrowphase Testing");
        for (bvh, other_bvh) in self.candidate_collisions.drain(0..) {
            let bvh = unsafe { &*bvh };
            let other_bvh = unsafe { &*other_bvh };
            let collision_pair = (bvh.entity, other_bvh.entity);

            // Check if the collision has already been detected before running the
            // collision test since it's potentially very expensive. We get the entry
            // directly, that way we only have to do one hash lookup.
            match self.collisions.entry(collision_pair) {
                Entry::Vacant(vacant_entry) => {
                    // Collision hasn't already been detected, so do the test.
                    if bvh.test(other_bvh) {
                        // Woo, we have a collison.
                        vacant_entry.insert(());
                    }
                },
                _ => {},
            }
        }
    }

    /// Converts a point in world space to its grid cell.
    fn world_to_grid(&self, point: Point) -> GridCell {
        GridCell {
            x: (point.x / self.cell_size).floor() as GridCoord,
            y: (point.y / self.cell_size).floor() as GridCoord,
            z: (point.z / self.cell_size).floor() as GridCoord,
        }
    }
}

/// A wrapper type around a triple of coordinates that uniquely identify a grid cell.
///
/// # Details
///
/// Grid cells are axis-aligned cubes of a regular sice. The coordinates of a grid cell are its min
/// value. This was chosen because of how it simplifies the calculation to find the cell for a
/// given point (`(point / cell_size).floor()`).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct GridCell {
    pub x: GridCoord,
    pub y: GridCoord,
    pub z: GridCoord,
}

// TODO: Using i16 for the grid coordinate makes the hash lookups substantially faster, but it means
//       we'll have to take extra care when mapping world coordinates to grid coordinates. Points
//       outside the representable range should be wrapped around. This will technically lead to
//       more grid collisions, but extras will be culled quickly by the AABB test so it shouldn't
//       be more of a performance hit than what we gained from converting to using i16s.
pub type GridCoord = i16;

impl GridCell {
    pub fn new(x: GridCoord, y: GridCoord, z: GridCoord) -> GridCell {
        GridCell {
            x: x,
            y: y,
            z: z,
        }
    }

    pub fn iter_to(&self, dest: GridCell) -> GridIter {
        // assert!(self < dest, "start point for grid iter must be less that end point, or use iter_from()");

        GridIter {
            from: *self,
            to:   dest,
            next: *self,
        }
    }
}

pub struct GridIter {
    from: GridCell,
    to:   GridCell,
    next: GridCell,
}

impl Iterator for GridIter {
    type Item = GridCell;

    fn next(&mut self) -> Option<GridCell> {
        let from = self.from;
        let to = self.to;
        let mut next = self.next;

        if next.z >= to.z {
            next.z = from.z;
            if next.y >= to.y {
                next.y = from.y;
                if next.x >= to.x {
                    return None;
                } else {
                    next.x += 1;
                }
            } else {
                next.y += 1;
            }
        } else {
            next.z += 1;
        }

        ::std::mem::swap(&mut self.next, &mut next);
        Some(next)
    }
}
<|endoftext|>