<commit_before>use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::io::BufReader;
use std::cmp;
use std::str::FromStr;

extern crate modfile;
use modfile::ptmf;

extern crate rustc_serialize;
extern crate docopt;
use docopt::Docopt;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

static USAGE: &'static str = "
modtool.

Usage:
    modtool (-h | --help)
    modtool (-V | --version)
    modtool show [--show-summary] [--show-sample-info] [--show-sample-stats] [--show-pattern-info] <file>...
    modtool save <number> <filename> <file>

Options:
    -V, --version         Show version info.
    -h, --help            Show this text.

    --show-summary        Show summary info.
    --show-sample-info    Show info about samples.
    --show-sample-stats   Show sample statistics.
    --show-pattern-info   Show info about patterns.

    <number>              Select sample NUMBER to save.
    <filename>            Save selected sample to FILENAME.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: Vec<String>,
    flag_help: bool,
	flag_version: bool,

	cmd_show: bool,
	flag_show_summary: bool,
    flag_show_sample_info: bool,
	flag_show_sample_stats: bool,
	flag_show_pattern_info: bool,

	cmd_save: bool,
	arg_number: String,
	arg_filename: String
}

#[derive(Debug)]
struct Stats {
	pub min: u32,
	pub max: u32,
	pub sum: usize,
	pub avg: usize,
	pub num_values: u32
}

impl Stats {
	pub fn new() -> Stats {
		Stats{min: u32::max_value(), max: u32::min_value(), sum: 0, avg: 0, num_values: 0}
	}

	pub fn update(&mut self, val: u32) {
		self.min = cmp::min(self.min, val);
		self.max = cmp::max(self.max, val);
		self.sum += val as usize;

		self.num_values += 1;
	}

	pub fn done(&mut self) {
		self.avg = self.sum / (self.num_values as usize);
	}
}

fn show_summary(module: &ptmf::PTModule) {
	println!("Song summary");
	println!("\tSongname: {}", module.name);
	println!("\tLength: {}", module.length);
	let used_samples = module.sample_info.iter().filter(|si| si.length > 0);
	println!("\tNumber of samples with length > 0: {}", used_samples.count());
	println!("\tNumber of patterns: {}", module.patterns.len());
	println!("");
}

fn show_sample_info(module: &ptmf::PTModule) {
	let mut number = 1;
	for sample in module.sample_info.iter() {
		println!("Sample number {} details", number);
		println!("\tName: {}", sample.name);
		println!("\tLength: {}b", sample.length * 2);
		println!("\tFinetune: {}", sample.finetune);
		println!("\tVolume: {}", sample.volume);
		println!("\tRepeat start: {}b", sample.repeat_start * 2);
		println!("\tRepeat length: {}b", sample.repeat_length * 2);
		number += 1;
	}
	println!("");
}

fn show_sample_stats(module: &ptmf::PTModule) {
	let used_samples = module.sample_info.iter().filter(|si| si.length > 0);

	let mut len = Stats::new();
	let mut finetune = Stats::new();
	let mut volume = Stats::new();
	let mut repeat_start = Stats::new();
	let mut repeat_length = Stats::new();

	for sample in used_samples {
		let slen = sample.length as u32 * 2;
		let sfinetune = sample.finetune as u32;
		let svolume = sample.volume as u32;
		let srepeat_start = sample.repeat_start as u32 * 2;
		let srepeat_length = sample.repeat_length as u32 * 2;

		len.update(slen);
		finetune.update(sfinetune);
		volume.update(svolume);
		repeat_start.update(srepeat_start);
		repeat_length.update(srepeat_length);
	}

	len.done();
	finetune.done();
	volume.done();
	repeat_start.done();
	repeat_length.done();

	println!("Sample statistics");
	println!("\tLength min: {} max: {} avg: {}", len.min, len.max, len.avg);
	println!("\tFinetune min: {} max: {} avg: {}", finetune.min, finetune.max, finetune.avg);
	println!("\tVolume min: {} max: {} avg: {}", volume.min, volume.max, volume.avg);
	println!("\tRepeat start min: {} max: {} avg: {}", repeat_start.min, repeat_start.max, repeat_start.avg);
	println!("\tRepeat length min: {} max: {} avg: {}", repeat_length.min, repeat_length.max, repeat_length.avg);
	println!("");
}

fn show_pattern_info(module: &ptmf::PTModule) {

	println!("Pattern info");
	print!("\tPattern play order: ");
	let positions = &module.positions.data[0..module.length as usize];
	for pos in positions.iter() {
		print!("{} ",pos);
	}
	println!("");

	print!("\tUnused patterns: ");
	let num_patterns = module.patterns.len();
	for i in 0..num_patterns as u8 {
		if !positions.contains(&i) {
			print!("{} ",i);
		}
	}
	println!("");

	print!("\tEmpty patterns: ");
	for i in 0..module.patterns.len() {
		let mut empty = true;
		for row in &module.patterns[i].rows {
			for channel in &row.channels {
				if channel.period != 0 ||
					channel.sample_number != 0 ||
					channel.effect != 0 {
					empty = false;
				}
				if !empty {
					break;
				}
			}
			if !empty {
				break;
			}
		}
		if empty {
			print!("{} ",i);
		}
	}
	println!("");
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
//    println!("{:?}", args);

	if args.flag_version {
		println!("Version: {}", VERSION);
		return;
	}

	if args.arg_number.len() > 0 {
		let number = usize::from_str(&args.arg_number).unwrap();
		if number < 1 || number > 31 {
			println!("Invalid sample number '{}'", number);
			return;
		}
	}

	if args.cmd_show {
		for ref filename in args.arg_file {
			let file = match File::open(filename) {
				Ok(file) => file,
				Err(e) => {
					println!("Failed to open file: '{}' Error: '{}'", filename, e);
					continue
				}
			};

			let mut reader = BufReader::new(&file);
			let module = match ptmf::read_mod(&mut reader) {
				Ok(module) => module,
				Err(e) => {
					println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
					continue
				}
			};

			println!("Processing: {}", filename);

			if args.flag_show_summary {
				show_summary(&module);
			}

			if args.flag_show_sample_info {
				show_sample_info(&module);
			}

			if args.flag_show_sample_stats {
				show_sample_stats(&module);
			}

			if args.flag_show_pattern_info {
				show_pattern_info(&module);
			}
		}
	} else if args.cmd_save {
		let ref filename = args.arg_file[0];
		let file = match File::open(filename) {
			Ok(file) => file,
			Err(e) => {
				println!("Failed to open file: '{}' Error: '{}'", filename, e);
				return
			}
		};

		let mut reader = BufReader::new(&file);
		let module = match ptmf::read_mod(&mut reader) {
			Ok(module) => module,
			Err(e) => {
				println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
				return
			}
		};

		println!("Processing: {}", filename);

		let ref filename = args.arg_filename;
		let file = match File::create(filename) {
			Ok(file) => file,
			Err(e) => {
				println!("Failed to open file: '{}' Error: '{:?}'", filename, e);
				return
			}
		};

		let number = usize::from_str(&args.arg_number).unwrap() - 1;
		if number >= module.sample_data.len() {
			println!("Invalid sample number. Only {} samples available.", module.sample_data.len());
			return
		}

		let mut writer = BufWriter::new(&file);
		match writer.write_all(&module.sample_data[number]) {
			Ok(_) => (),
			Err(e) => {
				println!("Failed to write sample. Error: '{:?}'", e);
				return
			}
		}
	}

	println!("Done!");
}
<commit_msg>Restructured fn main()<commit_after>use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::io::BufReader;
use std::cmp;
use std::str::FromStr;

extern crate modfile;
use modfile::ptmf;

extern crate rustc_serialize;
extern crate docopt;
use docopt::Docopt;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

static USAGE: &'static str = "
modtool.

Usage:
    modtool (-h | --help)
    modtool (-V | --version)
    modtool show [--summary] [--sample-info] [--sample-stats] [--pattern-info] <file>...
    modtool save (--number=<number> | --all) <fileprefix> <file>

Options:
    -V, --version         Show version info.
    -h, --help            Show this text.

    --summary             Show summary info.
    --sample-info         Show info about samples.
    --sample-stats        Show sample statistics.
    --pattern-info        Show info about patterns.

    --all                 Save all samples.
    --number=<number>     Save only sample <number>.
    <fileprefix>          Use <fileprefix> as prefix to filenames when saving.
";

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: Vec<String>,
    flag_help: bool,
	flag_version: bool,

	cmd_show: bool,
	flag_summary: bool,
    flag_sample_info: bool,
	flag_sample_stats: bool,
	flag_pattern_info: bool,

	cmd_save: bool,
	flag_all: bool,
	flag_number: String,
	arg_fileprefix: String
}

#[derive(Debug)]
struct Stats {
	pub min: u32,
	pub max: u32,
	pub sum: usize,
	pub avg: usize,
	pub num_values: u32
}

impl Stats {
	pub fn new() -> Stats {
		Stats{min: u32::max_value(), max: u32::min_value(), sum: 0, avg: 0, num_values: 0}
	}

	pub fn update(&mut self, val: u32) {
		self.min = cmp::min(self.min, val);
		self.max = cmp::max(self.max, val);
		self.sum += val as usize;

		self.num_values += 1;
	}

	pub fn done(&mut self) {
		self.avg = self.sum / (self.num_values as usize);
	}
}

fn show_summary(module: &ptmf::PTModule) {
	println!("Song summary");
	println!("\tSongname: {}", module.name);
	println!("\tLength: {}", module.length);
	let used_samples = module.sample_info.iter().filter(|si| si.length > 0);
	println!("\tNumber of samples with length > 0: {}", used_samples.count());
	println!("\tNumber of patterns: {}", module.patterns.len());
	println!("");
}

fn show_sample_info(module: &ptmf::PTModule) {
	let mut number = 1;
	for sample in module.sample_info.iter() {
		println!("Sample number {} details", number);
		println!("\tName: {}", sample.name);
		println!("\tLength: {}b", sample.length * 2);
		println!("\tFinetune: {}", sample.finetune);
		println!("\tVolume: {}", sample.volume);
		println!("\tRepeat start: {}b", sample.repeat_start * 2);
		println!("\tRepeat length: {}b", sample.repeat_length * 2);
		number += 1;
	}
	println!("");
}

fn show_sample_stats(module: &ptmf::PTModule) {
	let used_samples = module.sample_info.iter().filter(|si| si.length > 0);

	let mut len = Stats::new();
	let mut finetune = Stats::new();
	let mut volume = Stats::new();
	let mut repeat_start = Stats::new();
	let mut repeat_length = Stats::new();

	for sample in used_samples {
		let slen = sample.length as u32 * 2;
		let sfinetune = sample.finetune as u32;
		let svolume = sample.volume as u32;
		let srepeat_start = sample.repeat_start as u32 * 2;
		let srepeat_length = sample.repeat_length as u32 * 2;

		len.update(slen);
		finetune.update(sfinetune);
		volume.update(svolume);
		repeat_start.update(srepeat_start);
		repeat_length.update(srepeat_length);
	}

	len.done();
	finetune.done();
	volume.done();
	repeat_start.done();
	repeat_length.done();

	println!("Sample statistics");
	println!("\tLength min: {} max: {} avg: {}", len.min, len.max, len.avg);
	println!("\tFinetune min: {} max: {} avg: {}", finetune.min, finetune.max, finetune.avg);
	println!("\tVolume min: {} max: {} avg: {}", volume.min, volume.max, volume.avg);
	println!("\tRepeat start min: {} max: {} avg: {}", repeat_start.min, repeat_start.max, repeat_start.avg);
	println!("\tRepeat length min: {} max: {} avg: {}", repeat_length.min, repeat_length.max, repeat_length.avg);
	println!("");
}

fn show_pattern_info(module: &ptmf::PTModule) {

	println!("Pattern info");
	print!("\tPattern play order: ");
	let positions = &module.positions.data[0..module.length as usize];
	for pos in positions.iter() {
		print!("{} ",pos);
	}
	println!("");

	print!("\tUnused patterns: ");
	let num_patterns = module.patterns.len();
	for i in 0..num_patterns as u8 {
		if !positions.contains(&i) {
			print!("{} ",i);
		}
	}
	println!("");

	print!("\tEmpty patterns: ");
	for i in 0..module.patterns.len() {
		let mut empty = true;
		for row in &module.patterns[i].rows {
			for channel in &row.channels {
				if channel.period != 0 ||
					channel.sample_number != 0 ||
					channel.effect != 0 {
					empty = false;
				}
				if !empty {
					break;
				}
			}
			if !empty {
				break;
			}
		}
		if empty {
			print!("{} ",i);
		}
	}
	println!("");
}

fn save_samples(module: &ptmf::PTModule,range: &Vec<usize>,prefix: &String) {
	for i in range {
		let filename = format!("{}_{}.raw",prefix,i+1);

		let file = match File::create(&filename) {
			Ok(file) => file,
			Err(e) => {
				println!("Failed to open file: '{}' Error: '{:?}'", filename, e);
				return
			}
		};

		let mut writer = BufWriter::new(&file);
		match writer.write_all(&module.sample_data[*i]) {
			Ok(_) => (),
			Err(e) => {
				println!("Failed to write sample {}. Error: '{:?}'", i, e);
			}
		}
	}
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());
//    println!("{:?}", args);

	if args.flag_version {
		println!("Version: {}", VERSION);
		return;
	}

	if args.flag_number.len() > 0 {
		let number = usize::from_str(&args.flag_number).unwrap();
		if number < 1 || number > 31 {
			println!("Invalid sample number '{}'", number);
			return;
		}
	}

	if args.cmd_show {
		for ref filename in args.arg_file {
			let file = match File::open(filename) {
				Ok(file) => file,
				Err(e) => {
					println!("Failed to open file: '{}' Error: '{}'", filename, e);
					continue
				}
			};

			let mut reader = BufReader::new(&file);
			let module = match ptmf::read_mod(&mut reader) {
				Ok(module) => module,
				Err(e) => {
					println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
					continue
				}
			};

			println!("Processing: {}", filename);

			if args.flag_summary {
				show_summary(&module);
			}

			if args.flag_sample_info {
				show_sample_info(&module);
			}

			if args.flag_sample_stats {
				show_sample_stats(&module);
			}

			if args.flag_pattern_info {
				show_pattern_info(&module);
			}
		}
	} else if args.cmd_save {
		let ref filename = args.arg_file[0];
		let file = match File::open(filename) {
			Ok(file) => file,
			Err(e) => {
				println!("Failed to open file: '{}' Error: '{}'", filename, e);
				return
			}
		};

		let mut reader = BufReader::new(&file);
		let module = match ptmf::read_mod(&mut reader) {
			Ok(module) => module,
			Err(e) => {
				println!("Failed to parse file: '{}' Error: '{:?}'", filename, e);
				return
			}
		};

		println!("Processing: {}", filename);

		let range = if args.flag_all {
			0..module.sample_data.len()
		} else {
			let number = usize::from_str(&args.flag_number).unwrap() - 1;
			if number >= module.sample_data.len() {
				println!("Invalid sample number. Only {} samples available.", module.sample_data.len());
				return
			}
			number..number+1
		};

		save_samples(&module,&(range.collect()),&args.arg_fileprefix);
	}

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


<commit_before>//! A 2D toy game written in Rust, using the ggez library.
#![deny(missing_docs)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

extern crate ggez;
extern crate itertools_num;
extern crate rand;

// Note: we need to load `geometry` first so the macro is available for
// the modules that come afterwards
#[macro_use]
mod geometry;
mod controllers;
mod resources;
mod view;
mod drawing;
mod game_state;
mod models;
mod util;

use controllers::{CollisionsController, InputController, TimeController};
use resources::Resources;
use game_state::GameState;
use geometry::Size;
use drawing::color;

use ggez::conf;
use ggez::graphics;
use ggez::event::{self, Keycode, Mod};
use ggez::{Context, ContextBuilder, GameResult};

/// This struct contains the application's state
pub struct ApplicationState {
    // Keep track of window focus to play/pause the game
    has_focus: bool,
    // Resources holds our loaded font, images and sounds
    resources: Resources,
    // Our game logic is controlled within the game_state
    game_state: GameState,
    // We control the game state with the passage of time
    time_controller: TimeController,
    // We handle input events with the input_controller
    input_controller: InputController,
}

impl ApplicationState {
    /// Simply creates a new application state
    fn new(ctx: &mut Context, game_state: GameState) -> GameResult<ApplicationState> {
        let app_state = ApplicationState {
            has_focus: true,
            resources: Resources::new(ctx),
            game_state: game_state,
            time_controller: TimeController::new(),
            input_controller: InputController::new(),
        };
        Ok(app_state)
    }

    /// This will be called when the game needs to be reset
    fn reset(&mut self) {
        // Reset time controller
        self.time_controller.reset();

        // Reset game state
        self.game_state.reset();

        // Play game start sound
        let _ = self.resources.game_start_sound.play();
    }
}

// We implement `ggez::event::EventHandler` trait on our application state - this is where we can
// listen for input and other events
impl event::EventHandler for ApplicationState {
    // This is called each time the game loop updates so we can update the game state
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        // Update game state, and check for collisions
        if self.has_focus {
            let duration = ggez::timer::get_delta(ctx);
            self.time_controller.update_seconds(
                duration,
                self.input_controller.actions(),
                &mut self.game_state,
                &self.resources,
            );
            CollisionsController::handle_collisions(self);
        }

        Ok(())
    }

    // This is called when ggez wants us to draw our game
    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        view::render_game(self, ctx)
    }

    // Listen for keyboard events
    fn key_down_event(&mut self, _ctx: &mut Context, keycode: Keycode, keymod: Mod, _repeat: bool) {
        // If we're displaying a message (waiting for user input) then hide it and reset the game
        if let Some(_) = self.game_state.message {
            self.reset();
        }
        self.input_controller.key_press(keycode, keymod);
    }
    fn key_up_event(&mut self, _ctx: &mut Context, keycode: Keycode, keymod: Mod, _repeat: bool) {
        self.input_controller.key_release(keycode, keymod);
    }

    // Listen for window focus to pause the game's execution
    fn focus_event(&mut self, _ctx: &mut Context, has_focus: bool) {
        self.has_focus = has_focus;
    }
}

fn main() {
    // Setup Rocket's Game State
    let game_size = Size::new(1024.0, 600.0);
    let game_state = GameState::new(game_size);

    // Create configuration for ggez using its ContextBuilder
    let cb = ContextBuilder::new("rocket", "ggez")
        .window_setup(conf::WindowSetup::default().title("Rocket!"))
        .window_mode(
            conf::WindowMode::default().dimensions(game_size.width as u32, game_size.height as u32),
        );

    // Create the rendering context and set the background color to black
    let ctx = &mut cb.build().unwrap();
    graphics::set_background_color(ctx, color::BLACK);

    // Load the application state and start the event loop
    let state = &mut ApplicationState::new(ctx, game_state).unwrap();
    if let Err(err) = event::run(ctx, state) {
        println!("Error encountered: {}", err);
    } else {
        println!("Exited cleanly, thanks for playing Rocket!");
    }
}
<commit_msg>Improve comments<commit_after>//! A 2D toy game written in Rust, using the ggez library.
#![deny(missing_docs)]
#![cfg_attr(feature = "clippy", feature(plugin))]
#![cfg_attr(feature = "clippy", plugin(clippy))]

extern crate ggez;
extern crate itertools_num;
extern crate rand;

// Note: we need to load `geometry` first so the macro is available for
// the modules that come afterwards
#[macro_use]
mod geometry;
mod controllers;
mod resources;
mod view;
mod drawing;
mod game_state;
mod models;
mod util;

use controllers::{CollisionsController, InputController, TimeController};
use resources::Resources;
use game_state::GameState;
use geometry::Size;
use drawing::color;

use ggez::conf;
use ggez::graphics;
use ggez::event::{self, Keycode, Mod};
use ggez::{Context, ContextBuilder, GameResult};

/// This struct contains the application's state
pub struct ApplicationState {
    // Keep track of window focus to play/pause the game
    has_focus: bool,
    // Resources holds our loaded font, images and sounds
    resources: Resources,
    // The game state contains all information needed to run the game
    game_state: GameState,
    // The time controller modifies the game state as time passes
    time_controller: TimeController,
    // The input controller keeps track of the actions that are triggered by the player
    input_controller: InputController,
}

impl ApplicationState {
    /// Simply creates a new application state
    fn new(ctx: &mut Context, game_state: GameState) -> GameResult<ApplicationState> {
        let app_state = ApplicationState {
            has_focus: true,
            resources: Resources::new(ctx),
            game_state: game_state,
            time_controller: TimeController::new(),
            input_controller: InputController::new(),
        };
        Ok(app_state)
    }

    /// This will be called when the game needs to be reset
    fn reset(&mut self) {
        // Reset time controller
        self.time_controller.reset();

        // Reset game state
        self.game_state.reset();

        // Play game start sound
        let _ = self.resources.game_start_sound.play();
    }
}

// We implement `ggez::event::EventHandler` trait on our application state - this is where we can
// listen for input and other events
impl event::EventHandler for ApplicationState {
    // This is called each time the game loop updates so we can update the game state
    fn update(&mut self, ctx: &mut Context) -> GameResult<()> {
        // Update game state, and check for collisions
        if self.has_focus {
            let duration = ggez::timer::get_delta(ctx);
            self.time_controller.update_seconds(
                duration,
                self.input_controller.actions(),
                &mut self.game_state,
                &self.resources,
            );
            CollisionsController::handle_collisions(self);
        }

        Ok(())
    }

    // This is called when ggez wants us to draw our game
    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        view::render_game(self, ctx)
    }

    // Listen for keyboard events
    fn key_down_event(&mut self, _ctx: &mut Context, keycode: Keycode, keymod: Mod, _repeat: bool) {
        // If we're displaying a message (waiting for user input) then hide it and reset the game
        if let Some(_) = self.game_state.message {
            self.reset();
        }
        self.input_controller.key_press(keycode, keymod);
    }
    fn key_up_event(&mut self, _ctx: &mut Context, keycode: Keycode, keymod: Mod, _repeat: bool) {
        self.input_controller.key_release(keycode, keymod);
    }

    // Listen for window focus to pause the game's execution
    fn focus_event(&mut self, _ctx: &mut Context, has_focus: bool) {
        self.has_focus = has_focus;
    }
}

fn main() {
    // Setup Rocket's Game State
    let game_size = Size::new(1024.0, 600.0);
    let game_state = GameState::new(game_size);

    // Create configuration for ggez using its ContextBuilder
    let cb = ContextBuilder::new("rocket", "ggez")
        .window_setup(conf::WindowSetup::default().title("Rocket!"))
        .window_mode(
            conf::WindowMode::default().dimensions(game_size.width as u32, game_size.height as u32),
        );

    // Create the rendering context and set the background color to black
    let ctx = &mut cb.build().unwrap();
    graphics::set_background_color(ctx, color::BLACK);

    // Load the application state and start the event loop
    let state = &mut ApplicationState::new(ctx, game_state).unwrap();
    if let Err(err) = event::run(ctx, state) {
        println!("Error encountered: {}", err);
    } else {
        println!("Exited cleanly, thanks for playing Rocket!");
    }
}
<|endoftext|>


<commit_before>extern crate rtlsdr;
extern crate num;

use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::complex::Complex;
use std::env;

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const BUF_SIZE: usize = 131072;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: i32 = 2048000;

fn main() {
    let sdr_index: i32 = env::args()
        .nth(1)
        .expect("Please specify the SDR index")
        .parse::<i32>()
        .unwrap();
    let fm_freq_mhz: f32 = env::args()
        .nth(2)
        .expect("Please specify a center frequency (MHz).")
        .parse::<f32>()
        .unwrap();

    let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
    let mut sdr = match init_sdr(sdr_index, fm_freq) {
        Ok(s) => s,
        Err(e) => return println!("Couldn't initialize SDR, {}", e),
    };

    loop {
        let bytes = match sdr.read_sync(BUF_SIZE) {
            Ok(b) => b,
            Err(e) => return println!("Couldn't read bytes from SDR, {}", e),
        };
        let iq_vec = read_samples(bytes);
        match iq_vec {
            // TODO: Here is where we would start demodulating. For now, just
            // leave it be.
            Some(iq) => println!("We got some bytes: {:?}", iq.get(0)),
            None => println!("No bytes. :("),
        }
    }
}

fn init_sdr(sdr_index: i32, fm_freq: u32) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn read_samples(bytes: Vec<u8>) -> Option<Vec<Complex<f32>>> {
    // The docs tell us that RTL-SDR sends us data in bytes alternating between
    // I and Q. I'm not normalizing here, but I might have to in the future.

    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        return None;

    }
    let mut iter = bytes.chunks(2);
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1].
    for iq in iter.next() {
        iq_vec.push(Complex::new((iq[0] as f32 - 127.5) / 127.5,
                                 (iq[1] as f32 - 127.5) / 127.5));
    }

    Some(iq_vec)
}
<commit_msg>Changing sample rate from i32 to u32<commit_after>extern crate rtlsdr;
extern crate num;

use rtlsdr::{RTLSDRDevice, RTLSDRError};
use num::complex::Complex;
use std::env;

// Make sure that the buffer size is radix-2, otherwise the read_sync function
// will fail with an error code of -8.
const BUF_SIZE: usize = 131072;

// Most other sample rates fail, but this one works for my particular device.
// I will investigate exactly what's happening here and generate a list of
// possible sample rates (if there are others besides this one).
const SAMPLE_RATE: u32 = 2048000;

fn main() {
    let sdr_index: i32 = env::args()
        .nth(1)
        .expect("Please specify the SDR index")
        .parse::<i32>()
        .unwrap();
    let fm_freq_mhz: f32 = env::args()
        .nth(2)
        .expect("Please specify a center frequency (MHz).")
        .parse::<f32>()
        .unwrap();

    let fm_freq: u32 = (fm_freq_mhz * 1e6) as u32;
    let mut sdr = match init_sdr(sdr_index, fm_freq) {
        Ok(s) => s,
        Err(e) => return println!("Couldn't initialize SDR, {}", e),
    };

    loop {
        let bytes = match sdr.read_sync(BUF_SIZE) {
            Ok(b) => b,
            Err(e) => return println!("Couldn't read bytes from SDR, {}", e),
        };
        let iq_vec = read_samples(bytes);
        match iq_vec {
            // TODO: Here is where we would start demodulating. For now, just
            // leave it be.
            Some(iq) => println!("We got some bytes: {:?}", iq.get(0)),
            None => println!("No bytes. :("),
        }
    }
}

fn init_sdr(sdr_index: i32, fm_freq: u32) -> Result<RTLSDRDevice, RTLSDRError> {
    let mut sdr = try!(rtlsdr::open(sdr_index));
    try!(sdr.set_center_freq(fm_freq));
    try!(sdr.set_sample_rate(SAMPLE_RATE));
    try!(sdr.reset_buffer());
    Ok(sdr)
}

fn read_samples(bytes: Vec<u8>) -> Option<Vec<Complex<f32>>> {
    // The docs tell us that RTL-SDR sends us data in bytes alternating between
    // I and Q. I'm not normalizing here, but I might have to in the future.

    // First, check that we've been given an even number of bytes. Not sure
    // what to do if we don't get I and Q.
    let bytes_len = bytes.len();
    if bytes_len % 2 != 0 {
        return None;

    }
    let mut iter = bytes.chunks(2);
    let mut iq_vec: Vec<Complex<f32>> = Vec::with_capacity(bytes_len / 2);

    // Write the values to the complex value and normalize from [0, 255] to
    // [-1, 1].
    for iq in iter.next() {
        iq_vec.push(Complex::new((iq[0] as f32 - 127.5) / 127.5,
                                 (iq[1] as f32 - 127.5) / 127.5));
    }

    Some(iq_vec)
}
<|endoftext|>


<commit_before>extern crate sdl2;
extern crate sdl2_sys;
extern crate rand;

use std::vec::Vec;
use std::borrow::Borrow;
use std::rc::Rc;
use std::marker::PhantomData;

use sdl2::pixels::Color;
use sdl2::surface::Surface;
use sdl2::video::{Window};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::render::Renderer;
use sdl2_sys::event::SDL_USEREVENT;

use rand::random;

// struct Tetris<F: Figure + Sized> {
//     lines: Vec<Vec<Option<TetrisCellColor>>>,
//     current_figure: Option<(Point, F)>
// }

#[derive(Clone, Copy, Debug)]
enum TetrisCellColor {
    Red, Orange, Yellow, Green, Blue, DeepBlue, Purple,
}

impl TetrisCellColor {
    fn get_sdl_color(&self) -> Color {
        match self {
            &TetrisCellColor::Red => Color::RGB(200, 0, 0),
            &TetrisCellColor::Orange => Color::RGB(180, 130, 0),
            &TetrisCellColor::Yellow => Color::RGB(180, 180, 0),
            &TetrisCellColor::Green => Color::RGB(0, 200, 0),
            &TetrisCellColor::Blue => Color::RGB(0, 180, 180),
            &TetrisCellColor::DeepBlue => Color::RGB(0, 0, 200),
            &TetrisCellColor::Purple => Color::RGB(180, 0, 180),
        }
    }
}

#[derive(PartialEq, Clone, Copy, Debug)]
struct Point(usize, usize);

#[derive(PartialEq, Clone, Copy, Debug)]
struct PointOffset(usize, usize);

trait Figure {
    fn new_by_top_left_corner(Point, TetrisCellColor) -> Figure;
    fn rotate_clockwise(self) -> (PointOffset, Figure);
    fn rotate_counterclockwise(self) -> (PointOffset, Figure);
    fn lower_edge<'a>(&'a self) -> &'a [usize];
    fn dimensions(&self) -> PointOffset;
    fn color(&self) -> TetrisCellColor;
}

trait CellScreen {
    fn reset(&mut self);
    fn set_cell(&mut self, Point, Option<TetrisCellColor>);
    fn dimensions(&self) -> PointOffset;
    fn layers<'a>(&'a self) -> Vec<(Point, PointOffset, &'a [Option<TetrisCellColor>])>;
    fn cell_size(&self) -> PointOffset;
    fn cell_spacing(&self) -> PointOffset;
    fn window_size(&self) -> PointOffset;
    fn global_offset(&self) -> PointOffset;
}

trait CellScreenRenderer {
    fn render_cell_screen(&self, renderer: &mut Renderer);
}

impl <C: CellScreen> CellScreenRenderer for C {
    fn render_cell_screen(&self, renderer: &mut Renderer) {
        let PointOffset(x_glob_offset, y_glob_offset) = self.global_offset();

        let PointOffset(x_max, y_max) = self.dimensions();
        let mut cells: Vec<Option<TetrisCellColor>> = Vec::with_capacity(x_max * y_max);

        let cell_size = self.cell_size();
        let cell_spacing = self.cell_spacing();
        let window_size = self.window_size();

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

        renderer.set_draw_color(Color::RGB(127, 127, 127));
        renderer.draw_rect(sdl2::rect::Rect::new_unwrap(
            x_glob_offset as i32,
            y_glob_offset as i32,
            (cell_size.0 * x_max) as u32,
            (cell_size.1 * y_max) as u32,
            ));

        for _ in 0 .. x_max * y_max {
            cells.push(None);
        }

        for layer_params in self.layers() {
            let (Point(layer_x0, layer_y0),
                 PointOffset(layer_width, layer_height),
                 layer_cells
                 ) = layer_params;

            assert!(layer_x0 + layer_width <= x_max);
            assert!(layer_y0 + layer_height <= y_max);

            let mut layer_cell_iter = layer_cells.iter();
            for y in layer_y0 .. layer_y0 + layer_height {
                for x in layer_x0 .. layer_x0 + layer_width {
                    cells[y * layer_width + x] = layer_cell_iter.next().unwrap().clone();
                    // println!("Updated (x={}, y={}), {} of {}, value={:?}",
                    //          x, y, y * layer_width + x, cells.len(),
                    //          cells[y * layer_width + x]);
                }
            }
        }

        let cells = cells;
        let mut cell_iter = cells.iter();

        for y in 0 .. y_max {
            for x in 0 .. x_max {
                let cell = cell_iter.next().unwrap();
                renderer.set_draw_color(match cell {
                    &None => Color::RGB(0, 0, 0),
                    &Some(ref cell) => cell.get_sdl_color(),
                });
                let rect = sdl2::rect::Rect::new_unwrap(
                    (x_glob_offset + x * cell_size.0 + cell_spacing.0) as i32,
                    (y_glob_offset + y * cell_size.1 + cell_spacing.1) as i32,
                    (cell_size.0 - cell_spacing.0 * 2) as u32,
                    (cell_size.1 - cell_spacing.1 * 2) as u32,
                    );
                renderer.fill_rect(rect);
            }
        }
    }
}

struct SimpleCellScreen {
    cells: [Option<TetrisCellColor>; 16 * 12],
    dim: PointOffset,
}

impl SimpleCellScreen {
    fn new() -> Self {
        SimpleCellScreen {
            cells: [None; 16 * 12],
            dim: PointOffset(16, 12),
        }
    }
}

impl CellScreen for SimpleCellScreen {
    fn reset(&mut self) {
        for cell in self.cells.iter_mut() {
            *cell = None;
        }
    }

    fn set_cell(&mut self, point: Point, cell: Option<TetrisCellColor>) {
        let dim = self.dimensions();
        self.cells[point.1 * dim.0 + point.0] = cell;
    }

    fn dimensions(&self) -> PointOffset {
        self.dim.clone()
    }

    fn layers<'a>(&'a self) -> Vec<(Point, PointOffset, &'a [Option<TetrisCellColor>])> {
        vec![(
            Point(0, 0),
            self.dim.clone(),
            &self.cells,
            )]
    }

    fn cell_size(&self) -> PointOffset {
        PointOffset(50, 50)
    }

    fn cell_spacing(&self) -> PointOffset {
        PointOffset(2, 2)
    }

    fn global_offset(&self) -> PointOffset {
        PointOffset(10, 10)
    }

    fn window_size(&self) -> PointOffset {
        let off = self.global_offset();
        let cs = self.cell_size();
        let dim = self.dimensions();
        PointOffset(
            (off.0 * 2 + cs.0 * dim.0) as usize,
            (off.1 * 2 + cs.1 * dim.1) as usize,
            )
    }
}

enum GameInputEvent {
    RotateClockwise,
    RotateCounterClockwise,
    MoveLeft,
    MoveRight,
    MoveDown,
    Timer,
    Start,
}

impl GameInputEvent {
    fn from_sdl_event(event: &Event) -> Option<Self> {
        match event {
            &Event::User {code: 0, ..} => Some(GameInputEvent::Timer),
            &Event::KeyDown {keycode: Some(ref keycode), ..} => match keycode {
                &Keycode::Left => Some(GameInputEvent::MoveLeft),
                &Keycode::Right => Some(GameInputEvent::MoveRight),
                &Keycode::Space => Some(GameInputEvent::MoveDown),
                &Keycode::Up => Some(GameInputEvent::RotateClockwise),
                _ => None,
            },
            _ => None,
        }
    }
}

trait Game {
    fn new(&sdl2::Sdl) -> Self;
    fn run(&mut self, &mut sdl2::EventPump, &mut Renderer);
    fn window_size(&self) -> (u32, u32);
}

struct RandomSquaresGame {
    cell_screen: SimpleCellScreen,
    counter: usize,
    video: sdl2::VideoSubsystem,
    timer: sdl2::TimerSubsystem,
    event: sdl2::EventSubsystem,
}

fn timer_event() -> Event {
    Event::User {
        code: 0,
        window_id: 0,
        timestamp: 0,
        type_: SDL_USEREVENT,
    }
}

fn is_timer_event(event: &Event) -> bool {
    if let &Event::User {code: 0, ..} = event { true } else { false }
}

impl Game for RandomSquaresGame {
    fn new(sdl: &sdl2::Sdl) -> Self {
        RandomSquaresGame {
            cell_screen: SimpleCellScreen::new(),
            counter: 0,
            video: sdl.video().unwrap(),
            timer: sdl.timer().unwrap(),
            event: sdl.event().unwrap(),
        }
    }

    fn window_size(&self) -> (u32, u32) {
        let ws = self.cell_screen.window_size();
        (ws.0 as u32, ws.1 as u32)
    }

    fn run(&mut self, event_pump: &mut sdl2::EventPump, renderer: &mut Renderer) {
        let event = self.event.clone();
        let timer = self.timer.clone();
        let timer = timer.add_timer(0, Box::new(move || {
            event.push_event(timer_event()).unwrap();
            500
        }));

        'game: loop {
            for event in event_pump.poll_iter() {
                match event {
                    Event::Quit {..} => break 'game,
                    Event::KeyDown {keycode: Some(Keycode::Q), ..} => break 'game,
                    Event::KeyDown {keycode: Some(Keycode::Escape), ..} => break 'game,
                    event => match GameInputEvent::from_sdl_event(&event) {
                        Some(event) => if !self.handle_event(event, renderer) { break 'game },
                        None => {},
                    },
                }
            }
        }
    }
}

impl RandomSquaresGame {
    fn handle_event(&mut self, event: GameInputEvent, renderer: &mut Renderer) -> bool {
        self.counter = self.counter + 1;
        let screen_dim = self.cell_screen.dimensions();
        let mut cell_screen = &mut self.cell_screen;
        let mut number = self.counter;

        for y in 0 .. screen_dim.1 {
            for x in 0 .. screen_dim.0 {
                cell_screen.set_cell(Point(x, y), match number % 7 {
                    0 => Some(TetrisCellColor::Red),
                    1 => Some(TetrisCellColor::Orange),
                    2 => Some(TetrisCellColor::Yellow),
                    3 => Some(TetrisCellColor::Green),
                    4 => Some(TetrisCellColor::Blue),
                    5 => Some(TetrisCellColor::DeepBlue),
                    6 => Some(TetrisCellColor::Purple),
                    _ => panic!("lolwut"),
                });
                number = number + 1;
            }
        }

        cell_screen.render_cell_screen(renderer);
        renderer.present();

        true
    }
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let event_subsystem = sdl_context.event().unwrap();

    let mut game = RandomSquaresGame::new(&sdl_context);
    let window_size = game.window_size();

    let window = sdl_context.video().unwrap().window("Tetris", window_size.0, window_size.1).build().unwrap();
    let window_id = window.id();

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

    game.run(&mut event_pump, &mut renderer);
}
<commit_msg>falling cube<commit_after>extern crate sdl2;
extern crate sdl2_sys;
extern crate rand;

use std::vec::Vec;
use std::borrow::Borrow;
use std::rc::Rc;
use std::marker::PhantomData;

use sdl2::pixels::Color;
use sdl2::surface::Surface;
use sdl2::video::{Window};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::render::Renderer;
use sdl2_sys::event::SDL_USEREVENT;

use rand::random;

const CELL_COUNT_X: usize = 9;
const CELL_COUNT_Y: usize = 16;

#[derive(Clone, Copy, Debug)]
enum TetrisCellColor {
    Red, Orange, Yellow, Green, Blue, DeepBlue, Purple,
}

impl rand::Rand for TetrisCellColor {
    fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        match rng.next_u32() % 7 {
            0 => TetrisCellColor::Red,
            1 => TetrisCellColor::Orange,
            2 => TetrisCellColor::Yellow,
            3 => TetrisCellColor::Green,
            4 => TetrisCellColor::Blue,
            5 => TetrisCellColor::DeepBlue,
            6 => TetrisCellColor::Purple,
            _ => panic!("lolwut"),
        }
    }
}

impl TetrisCellColor {
    fn get_sdl_color(&self) -> Color {
        match self {
            &TetrisCellColor::Red => Color::RGB(200, 0, 0),
            &TetrisCellColor::Orange => Color::RGB(180, 130, 0),
            &TetrisCellColor::Yellow => Color::RGB(180, 180, 0),
            &TetrisCellColor::Green => Color::RGB(0, 200, 0),
            &TetrisCellColor::Blue => Color::RGB(0, 180, 180),
            &TetrisCellColor::DeepBlue => Color::RGB(0, 0, 200),
            &TetrisCellColor::Purple => Color::RGB(180, 0, 180),
        }
    }
}

#[derive(PartialEq, Clone, Copy, Debug)]
struct Point(usize, usize);

#[derive(PartialEq, Clone, Copy, Debug)]
struct Dimensions(usize, usize);

#[derive(PartialEq, Clone, Copy, Debug)]
struct PointOffset(isize, isize);

trait CellScreen {
    fn reset(&mut self);
    fn set_cell(&mut self, Point, Option<TetrisCellColor>);
    fn dimensions(&self) -> Dimensions;
    fn layers<'a>(&'a self) -> Vec<(Point, Dimensions, &'a [Option<TetrisCellColor>])>;
    fn cell_size(&self) -> Dimensions;
    fn cell_spacing(&self) -> Dimensions;
    fn window_size(&self) -> Dimensions;
    fn global_offset(&self) -> Dimensions;
}

trait CellScreenRenderer {
    fn render_cell_screen(&self, renderer: &mut Renderer);
}

impl <C: CellScreen> CellScreenRenderer for C {
    fn render_cell_screen(&self, renderer: &mut Renderer) {
        let Dimensions(x_glob_offset, y_glob_offset) = self.global_offset();

        let Dimensions(x_max, y_max) = self.dimensions();
        let mut cells: Vec<Option<TetrisCellColor>> = Vec::with_capacity(x_max * y_max);

        let cell_size = self.cell_size();
        let cell_spacing = self.cell_spacing();
        let window_size = self.window_size();

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

        renderer.set_draw_color(Color::RGB(127, 127, 127));
        renderer.draw_rect(sdl2::rect::Rect::new_unwrap(
            x_glob_offset as i32,
            y_glob_offset as i32,
            (cell_size.0 * x_max) as u32,
            (cell_size.1 * y_max) as u32,
            ));

        for _ in 0 .. x_max * y_max {
            cells.push(None);
        }

        for layer_params in self.layers() {
            let (Point(layer_x0, layer_y0),
                 Dimensions(layer_width, layer_height),
                 layer_cells
                 ) = layer_params;

            assert!(layer_x0 + layer_width <= x_max);
            assert!(layer_y0 + layer_height <= y_max);

            let mut layer_cell_iter = layer_cells.iter();
            for y in layer_y0 .. layer_y0 + layer_height {
                for x in layer_x0 .. layer_x0 + layer_width {
                    cells[y * x_max + x] = layer_cell_iter.next().unwrap().clone();
                }
            }
        }

        let cells = cells;
        let mut cell_iter = cells.iter();

        for y in 0 .. y_max {
            for x in 0 .. x_max {
                let cell = cell_iter.next().unwrap();
                renderer.set_draw_color(match cell {
                    &None => Color::RGB(0, 0, 0),
                    &Some(ref cell) => cell.get_sdl_color(),
                });
                let rect = sdl2::rect::Rect::new_unwrap(
                    (x_glob_offset + x * cell_size.0 + cell_spacing.0) as i32,
                    (y_glob_offset + y * cell_size.1 + cell_spacing.1) as i32,
                    (cell_size.0 - cell_spacing.0 * 2) as u32,
                    (cell_size.1 - cell_spacing.1 * 2) as u32,
                    );
                renderer.fill_rect(rect);
            }
        }
    }
}

struct SimpleCellScreen {
    cells: [Option<TetrisCellColor>; CELL_COUNT_X * CELL_COUNT_Y],
    dim: Dimensions,
}

impl SimpleCellScreen {
    fn new() -> Self {
        SimpleCellScreen {
            cells: [None; CELL_COUNT_X * CELL_COUNT_Y],
            dim: Dimensions(CELL_COUNT_X, CELL_COUNT_Y),
        }
    }
}

impl CellScreen for SimpleCellScreen {
    fn reset(&mut self) {
        for cell in self.cells.iter_mut() {
            *cell = None;
        }
    }

    fn set_cell(&mut self, point: Point, cell: Option<TetrisCellColor>) {
        let dim = self.dimensions();
        self.cells[point.1 * dim.0 + point.0] = cell;
    }

    fn dimensions(&self) -> Dimensions {
        self.dim.clone()
    }

    fn layers<'a>(&'a self) -> Vec<(Point, Dimensions, &'a [Option<TetrisCellColor>])> {
        vec![(
            Point(0, 0),
            self.dim.clone(),
            &self.cells,
            )]
    }

    fn cell_size(&self) -> Dimensions {
        Dimensions(40, 40)
    }

    fn cell_spacing(&self) -> Dimensions {
        Dimensions(2, 2)
    }

    fn global_offset(&self) -> Dimensions {
        Dimensions(10, 10)
    }

    fn window_size(&self) -> Dimensions {
        let off = self.global_offset();
        let cs = self.cell_size();
        let dim = self.dimensions();
        Dimensions(
            (off.0 * 2 + cs.0 * dim.0) as usize,
            (off.1 * 2 + cs.1 * dim.1) as usize,
            )
    }
}

enum GameInputEvent {
    RotateClockwise,
    RotateCounterClockwise,
    MoveLeft,
    MoveRight,
    MoveDown,
    Timer,
    Start,
}

impl GameInputEvent {
    fn from_sdl_event(event: &Event) -> Option<Self> {
        match event {
            &Event::User {code: 0, ..} => Some(GameInputEvent::Timer),
            &Event::KeyDown {keycode: Some(ref keycode), ..} => match keycode {
                &Keycode::Left => Some(GameInputEvent::MoveLeft),
                &Keycode::Right => Some(GameInputEvent::MoveRight),
                &Keycode::Space => Some(GameInputEvent::MoveDown),
                &Keycode::Up => Some(GameInputEvent::RotateClockwise),
                _ => None,
            },
            _ => None,
        }
    }
}

trait Game {
    fn new(&sdl2::Sdl) -> Self;
    fn run(&mut self, &mut sdl2::EventPump, &mut Renderer);
    fn window_size(&self) -> (u32, u32);
}

struct RandomSquaresGame {
    cell_screen: SimpleCellScreen,
    counter: usize,
    video: sdl2::VideoSubsystem,
    timer: sdl2::TimerSubsystem,
    event: sdl2::EventSubsystem,
}

fn timer_event() -> Event {
    Event::User {
        code: 0,
        window_id: 0,
        timestamp: 0,
        type_: SDL_USEREVENT,
    }
}

fn is_timer_event(event: &Event) -> bool {
    if let &Event::User {code: 0, ..} = event { true } else { false }
}

impl Game for RandomSquaresGame {
    fn new(sdl: &sdl2::Sdl) -> Self {
        RandomSquaresGame {
            cell_screen: SimpleCellScreen::new(),
            counter: 0,
            video: sdl.video().unwrap(),
            timer: sdl.timer().unwrap(),
            event: sdl.event().unwrap(),
        }
    }

    fn window_size(&self) -> (u32, u32) {
        let ws = self.cell_screen.window_size();
        (ws.0 as u32, ws.1 as u32)
    }

    fn run(&mut self, event_pump: &mut sdl2::EventPump, renderer: &mut Renderer) {
        let event = self.event.clone();
        let timer = self.timer.clone();
        let timer = timer.add_timer(0, Box::new(move || {
            event.push_event(timer_event()).unwrap();
            500
        }));

        'game: loop {
            for event in event_pump.poll_iter() {
                match event {
                    Event::Quit {..} => break 'game,
                    Event::KeyDown {keycode: Some(Keycode::Q), ..} => break 'game,
                    Event::KeyDown {keycode: Some(Keycode::Escape), ..} => break 'game,
                    event => match GameInputEvent::from_sdl_event(&event) {
                        Some(event) => if !self.handle_event(event, renderer) { break 'game },
                        None => {},
                    },
                }
            }
        }
    }
}

impl RandomSquaresGame {
    fn handle_event(&mut self, event: GameInputEvent, renderer: &mut Renderer) -> bool {
        self.counter = self.counter + 1;
        let screen_dim = self.cell_screen.dimensions();
        let mut cell_screen = &mut self.cell_screen;
        let mut number = self.counter;

        for y in 0 .. screen_dim.1 {
            for x in 0 .. screen_dim.0 {
                cell_screen.set_cell(Point(x, y), match number % 7 {
                    0 => Some(TetrisCellColor::Red),
                    1 => Some(TetrisCellColor::Orange),
                    2 => Some(TetrisCellColor::Yellow),
                    3 => Some(TetrisCellColor::Green),
                    4 => Some(TetrisCellColor::Blue),
                    5 => Some(TetrisCellColor::DeepBlue),
                    6 => Some(TetrisCellColor::Purple),
                    _ => panic!("lolwut"),
                });
                number = number + 1;
            }
        }

        cell_screen.render_cell_screen(renderer);
        renderer.present();

        true
    }
}

struct TetrisCellScreen {
    cells: [Option<TetrisCellColor>; CELL_COUNT_X * CELL_COUNT_Y],
    dim: Dimensions,
    _figure: Option<(Point, TetrisCellColor, Figure)>,
    _figure_layer: Vec<Option<TetrisCellColor>>,
}

impl TetrisCellScreen {
    fn new() -> Self {
        TetrisCellScreen {
            cells: [None; CELL_COUNT_X * CELL_COUNT_Y],
            dim: Dimensions(CELL_COUNT_X, CELL_COUNT_Y),
            _figure: None,
            _figure_layer: Vec::new(),
        }
    }

    fn get_figure(&self) -> Option<(Point, TetrisCellColor, Figure)> {
        self._figure.clone()
    }

    fn set_figure(&mut self, point: Point, color: TetrisCellColor, figure: Figure) {
        match &self._figure {
            &Some((_, _, ref old_figure)) if old_figure != &figure => {},
            _ => {
                let bitmap = figure.bitmap();
                self._figure_layer.reserve(bitmap.len());
                self._figure_layer.truncate(bitmap.len());
                for flag in bitmap.iter() {
                    self._figure_layer.push(
                        if *flag { Some(color) } else { None });
                }
            },
        };

        self._figure = Some((point, color, figure));
    }
}

impl CellScreen for TetrisCellScreen {
    fn reset(&mut self) {
        for cell in self.cells.iter_mut() {
            *cell = None;
        }
        self._figure = None;
    }

    fn set_cell(&mut self, point: Point, cell: Option<TetrisCellColor>) {
        let dim = self.dimensions();
        self.cells[point.1 * dim.0 + point.0] = cell;
    }

    fn dimensions(&self) -> Dimensions {
        self.dim.clone()
    }

    fn layers<'a>(&'a self) -> Vec<(Point, Dimensions, &'a [Option<TetrisCellColor>])> {
        let mut layers = Vec::with_capacity(2);
        layers.push((
            Point(0, 0),
            self.dim.clone(),
            self.cells.as_ref()));
        if let Some((ref point, _, ref figure)) = self.get_figure() {
            layers.push((
                point.clone(),
                figure.dimensions(),
                &self._figure_layer));
        }
        layers
    }

    fn cell_size(&self) -> Dimensions {
        Dimensions(40, 40)
    }

    fn cell_spacing(&self) -> Dimensions {
        Dimensions(2, 2)
    }

    fn global_offset(&self) -> Dimensions {
        Dimensions(10, 10)
    }

    fn window_size(&self) -> Dimensions {
        let off = self.global_offset();
        let cs = self.cell_size();
        let dim = self.dimensions();
        Dimensions(
            (off.0 * 2 + cs.0 * dim.0) as usize,
            (off.1 * 2 + cs.1 * dim.1) as usize,
            )
    }
}

struct TetrisGame {
    cell_screen: TetrisCellScreen,
    dim: Dimensions,
    main_layer: [Option<TetrisCellColor>; CELL_COUNT_X * CELL_COUNT_Y],
    video: sdl2::VideoSubsystem,
    timer: sdl2::TimerSubsystem,
    event: sdl2::EventSubsystem,
}

impl Game for TetrisGame {
    fn new(sdl: &sdl2::Sdl) -> Self {
        TetrisGame {
            cell_screen: TetrisCellScreen::new(),
            dim: Dimensions(CELL_COUNT_X, CELL_COUNT_Y),
            main_layer: [None; CELL_COUNT_X * CELL_COUNT_Y],
            video: sdl.video().unwrap(),
            timer: sdl.timer().unwrap(),
            event: sdl.event().unwrap(),
        }
    }

    fn run(&mut self, event_pump: &mut sdl2::EventPump, renderer: &mut Renderer) {
        let event = self.event.clone();
        let timer = self.timer.clone();
        let timer = timer.add_timer(0, Box::new(move || {
            event.push_event(timer_event()).unwrap();
            1000
        }));

        'game: loop {
            for event in event_pump.poll_iter() {
                match event {
                    Event::Quit {..} => break 'game,
                    Event::KeyDown {keycode: Some(Keycode::Q), ..} => break 'game,
                    Event::KeyDown {keycode: Some(Keycode::Escape), ..} => break 'game,
                    event => match GameInputEvent::from_sdl_event(&event) {
                        Some(event) => if !self.handle_event(event, renderer) { break 'game },
                        None => {},
                    },
                }
            }
        }
    }

    fn window_size(&self) -> (u32, u32) {
        let ws = self.cell_screen.window_size();
        (ws.0 as u32, ws.1 as u32)
    }
}

impl TetrisGame {
    fn handle_event(&mut self, event: GameInputEvent, renderer: &mut Renderer) -> bool {
        match event {
            GameInputEvent::Timer => {
                let (point, color, figure) = match self.cell_screen.get_figure() {
                    None => {
                        let figure = rand::random::<Figure>();
                        let offset = figure.offset_from_top_center();
                        let dim = self.cell_screen.dimensions();
                        let point = Point(
                            (dim.0 as isize / 2 + offset.0) as usize,
                            offset.1 as usize,
                            );

                        (point, rand::random(), figure)
                    },
                    Some((old_point, color, figure)) => {
                        (Point(old_point.0, old_point.1 + 1), color, figure)
                    },
                };
                self.cell_screen.set_figure(point, color, figure);
            },
            _ => {},
        }

        self.cell_screen.render_cell_screen(renderer);
        renderer.present();

        true
    }
}

#[derive(Clone, PartialEq, Debug)]
enum Figure {
    Cube,
}

const CUBE_CELLS: &'static [bool] = &[
    true, true,
    true, true,
    ];

impl Figure {
    fn offset_from_top_center(&self) -> PointOffset {
        match self {
            &Figure::Cube => PointOffset(-1, 1),
        }
    }

    fn dimensions(&self) -> Dimensions {
        match self {
            &Figure::Cube => Dimensions(2, 2),
        }
    }

    fn bitmap(&self) -> &'static [bool] {
        match self {
            &Figure::Cube => CUBE_CELLS,
        }
    }
}

impl rand::Rand for Figure {
    fn rand<R: rand::Rng>(rng: &mut R) -> Self {
        match rng.next_u32() % 1 {
            0 => Figure::Cube,
            _ => panic!("lolwut"),
        }
    }
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let event_subsystem = sdl_context.event().unwrap();

    let mut game = TetrisGame::new(&sdl_context);
    let window_size = game.window_size();

    let window = sdl_context.video().unwrap().window("Tetris", window_size.0, window_size.1).build().unwrap();
    let window_id = window.id();

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

    game.run(&mut event_pump, &mut renderer);
}
<|endoftext|>


<commit_before>extern crate osmio;
extern crate image;
extern crate gif;
extern crate clap;

use clap::{Arg, App, AppSettings};

use std::fs;
use osmio::OSMReader;
use osmio::pbf::PBFReader;
use std::io::{Read, Write, BufReader, BufRead, BufWriter};
use std::collections::{HashMap, HashSet};

use gif::SetParameter;

type Frames = Vec<(u32, Vec<u32>)>;

struct ColourRamp {
    empty_colour: (u8, u8, u8),
    steps: Vec<(u32, (u8, u8, u8))>,
}

impl ColourRamp {
    fn new_from_filename(filename: &str) -> Self {
        let mut contents = String::new();
        let mut file = fs::File::open(filename).unwrap();
        file.read_to_string(&mut contents).expect("Couldn't read colour ramp file");
        Self::new_from_text(&contents)

    }
    fn new_from_text(source: &str) -> Self {
        let lines: Vec<_> = source.lines().collect();
        let empty_vec = lines[0].split(",").filter_map(|x| x.parse::<u8>().ok()).take(3).collect::<Vec<_>>();
        let empty = (empty_vec[0], empty_vec[1], empty_vec[2]);

        let mut steps = Vec::new();
        for line in lines.iter().skip(1) {
            let line = line.split(",").filter_map(|x| x.parse::<u32>().ok()).take(4).collect::<Vec<_>>();
            let age = line[0];
            let colour = (line[1] as u8, line[2] as u8, line[3] as u8);
            steps.push((age, colour));
        }

        if steps.len() > 254 {
            panic!("Too many steps");
        }

        ColourRamp{ empty_colour: empty, steps: steps }
    }

    fn palette(&self) -> Vec<u8> {
        let mut results = Vec::with_capacity((self.steps.len()+1)*3);
        results.push(self.empty_colour.0);
        results.push(self.empty_colour.1);
        results.push(self.empty_colour.2);

        for &(_, (r, g, b)) in self.steps.iter() {
            results.push(r);
            results.push(g);
            results.push(b);
        }

        results
    }

    fn index_for_age(&self, age: Option<u32>) -> u8 {
        let res = match age {
            None => 0,
            Some(age) => match self.steps.iter().position(|&(x, _)| x == age) {
                None => 0,
                Some(i) => (i+1) as u8,
            }
        };
        //println!("Age of {:?} got a res of {}", age, res);
        res
    }
}

fn read_pbf(filename: &str, height: u32, sec_per_frame: u32, bbox: &[f32; 4]) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut node_reader = PBFReader::new(file);
    let node_reader = node_reader.nodes();

    let mut results: HashMap<u32, HashSet<u32>> = HashMap::new();

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // 1st April 2005, midnight GMT. We presume no OSM editing before then.
    let osm_epoch = 1109635200;

    // FIXME use a btreemap?

    let mut first_frame_no = std::u32::MAX;
    let mut last_frame_no = 0;

    let mut num_nodes: u64 = 0;
    for node in node_reader {
        if let (Some(lat), Some(lon)) = (node.lat, node.lon) {
            if lat > top || lat < bottom || lon > right || lon < left {
                continue;
            }

            let timestamp = node.timestamp.to_epoch_number() as u64;
            if timestamp < osm_epoch {
                panic!("timestamp before epoch. Change code. {}", timestamp);
            }
            let offset = (timestamp - osm_epoch) as u32;
            // TODO double check that this rounds down
            let frame_no = offset / sec_per_frame;

            if frame_no < first_frame_no {
                first_frame_no = frame_no;
            }
            if frame_no > last_frame_no {
                last_frame_no = frame_no;
            }

            let pixel_idx = latlon_to_pixel_index(lat, lon, width, height, &bbox);
            results.entry(frame_no).or_insert(HashSet::new()).insert(pixel_idx);

            num_nodes += 1;
            if num_nodes % 10_000_000 == 0 {
                println!("Done {} nodes", num_nodes);
            }
        }
    }
    let num_frames = last_frame_no - first_frame_no + 1;
    println!("There are {} frames, which is {} sec", num_frames, num_frames as f32/30.);

    let mut sorted_results = Vec::with_capacity((last_frame_no-first_frame_no+1) as usize);

    for frame_no in 0..num_frames {
        match results.remove(&(frame_no+first_frame_no)) {
            None => { sorted_results.push((frame_no, Vec::with_capacity(0))) },
            Some(pixels) => {
                let pixels = pixels.into_iter().collect();
                sorted_results.push((frame_no, pixels));
            }
        }
    }

    sorted_results
}

fn write_frames(frames: Frames, filename: &str) {
    let mut file = BufWriter::new(fs::File::create(&filename).unwrap());
    for (frame_no, pixels) in frames.into_iter() {
        write!(file, "{},", frame_no).unwrap();
        for p in pixels {
            write!(file, "{},", p).unwrap();
        }
        write!(file, "\n").unwrap()
    }
}

fn read_frames(filename: &str) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut results = Frames::new();

    for line in file.lines() {
        let line = line.unwrap();
        let mut nums: Vec<u32> = line.split(",").filter_map(|s| s.parse().ok()).collect();
        let frame_no = nums.remove(0);
        let pixels = nums;
        results.push((frame_no, pixels))
    }

    results
}

fn latlon_to_pixel_index(lat: f32, lon: f32, width: u32, height: u32, bbox: &[f32; 4]) -> u32 {
    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    assert!(top > bottom);
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let lat = top - lat;
    let lon = lon - left;

    let x = ((lon/bbox_width)*(width as f32)) as u32;
    let y = ((lat/bbox_height)*(height as f32)) as u32;

    let i = y * width + x;

    assert!(i < width*height, "{}L{}, lat = {} lon = {} width = {} height = {} bbox = {:?} x = {} y = {} i = {}", file!(), line!(), lat, lon, width, height, bbox, x, y, i);

    i
}

fn create_equirectangular_map(frames: Frames, output_image_filename: &str, height: u32, bbox: &[f32; 4], colour_ramp: &ColourRamp) {
    let mut output_file = fs::File::create(output_image_filename).expect("Can't create image");

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // FIXME change width/height to u16?
    let mut encoder = gif::Encoder::new(&mut output_file, width as u16, height as u16, &[]).expect("Couldn't create encoder");
    encoder.set(gif::Repeat::Infinite).expect("Couldn't get inf repeat");

    // TODO have a global palette

    let mut image = vec![None; (width*height) as usize];

    for (frame_no, pixels) in frames.into_iter() {
        for i in pixels {
            // FIXME sometimes the value is invalid
            //assert!(i < width*height, "{} L{}, width = {} height = {} i = {}", file!(), line!(), width, height, i);
            if i < width*height {
                image[i as usize] = Some(frame_no);
            }
        }

        let mut pixels = Vec::with_capacity(image.len() * 4);
        for p in image.iter().cloned() {
            let index = colour_ramp.index_for_age(p.map(|t| frame_no - t));
            pixels.push(index);
        }

        let mut frame = gif::Frame::from_palette_pixels(width as u16, height as u16, &colour_ramp.palette(), pixels.as_mut_slice());
        // 30 fps, and delay is in units of 10ms.
        frame.delay = 100 / 30;

        encoder.write_frame(&frame).expect("Couldn't write frame");

        if frame_no % 30 == 0 {
            println!("Wrote frame {}", frame_no);
        }

    }

}

fn main() {
    let matches = App::new("osm-history-animation")
                          .arg(Arg::with_name("input").long("input").short("i")
                               .takes_value(true))
                          .arg(Arg::with_name("output") .long("output").short("o")
                               .takes_value(true))
                          .arg(Arg::with_name("height") .long("height").short("h")
                               .takes_value(true))
                          .arg(Arg::with_name("spf") .long("sec-per-frame").short("s")
                               .takes_value(true))
                          .arg(Arg::with_name("colour_ramp") .long("colour-ramp")
                               .takes_value(true))
                          .arg(Arg::with_name("save-intermediate").long("save-intermediate"))
                          .arg(Arg::with_name("load-intermediate").long("load-intermediate"))
                          .arg(Arg::with_name("bbox").long("bbox").takes_value(true).short("b"))
                          .setting(AppSettings::AllowLeadingHyphen)
                          .get_matches();

    let input_filename = matches.value_of("input").unwrap();
    let output_filename = matches.value_of("output").unwrap();
    let height: u32 = matches.value_of("height").unwrap().parse().unwrap();
    let frames_per_sec: u32 = matches.value_of("spf").unwrap().parse().unwrap();

    let bbox = match matches.value_of("bbox") {
        None => [-180., -90., 180., 90.],
        Some(text) => {
            let coords: Vec<f32> = text.split(",").map(|x| x.parse().unwrap() ).collect();
            [coords[0], coords[1], coords[2], coords[3]]
        }
    };

    let frames = if matches.is_present("load-intermediate") {
        println!("Reading frames from {}", input_filename);
        read_frames(&input_filename)
    } else {
        println!("Reading PBF file {}", input_filename);
        read_pbf(&input_filename, height, frames_per_sec, &bbox)
    };

    if matches.is_present("save-intermediate") {
        println!("Saving frame details to {}", output_filename);
        write_frames(frames, &output_filename);
    } else {
        let colour_ramp = ColourRamp::new_from_filename(matches.value_of("colour_ramp").unwrap());
        println!("Creating image {}", output_filename);
        create_equirectangular_map(frames, &output_filename, height, &bbox, &colour_ramp);
    }
    println!("\nFinished");
}
<commit_msg>global palette and magnitude based editing<commit_after>extern crate osmio;
extern crate image;
extern crate gif;
extern crate clap;

use clap::{Arg, App, AppSettings};

use std::fs;
use osmio::OSMReader;
use osmio::pbf::PBFReader;
use std::io::{Read, Write, BufReader, BufRead, BufWriter};
use std::collections::HashMap;

use gif::SetParameter;

// (frame_no, (pixel_index, num_changes))
type Frames = Vec<(u32, Vec<(u32, u16)>)>;

struct ColourRamp {
    empty_colour: (u8, u8, u8),
    steps: Vec<(u32, (u8, u8, u8))>,
}

impl ColourRamp {
    fn new_from_filename(filename: &str) -> Self {
        let mut contents = String::new();
        let mut file = fs::File::open(filename).unwrap();
        file.read_to_string(&mut contents).expect("Couldn't read colour ramp file");
        Self::new_from_text(&contents)

    }
    fn new_from_text(source: &str) -> Self {
        let lines: Vec<_> = source.lines().collect();
        let empty_vec = lines[0].split(",").filter_map(|x| x.parse::<u8>().ok()).take(3).collect::<Vec<_>>();
        let empty = (empty_vec[0], empty_vec[1], empty_vec[2]);

        let mut steps = Vec::new();
        for line in lines.iter().skip(1) {
            let line = line.split(",").filter_map(|x| x.parse::<u32>().ok()).take(4).collect::<Vec<_>>();
            let age = line[0];
            let colour = (line[1] as u8, line[2] as u8, line[3] as u8);
            steps.push((age, colour));
        }

        if steps.len() > 254 {
            panic!("Too many steps");
        }

        ColourRamp{ empty_colour: empty, steps: steps }
    }

    fn palette(&self) -> Vec<u8> {
        let mut results = Vec::with_capacity((self.steps.len()+1)*3);
        results.push(self.empty_colour.0);
        results.push(self.empty_colour.1);
        results.push(self.empty_colour.2);

        for &(_, (r, g, b)) in self.steps.iter() {
            results.push(r);
            results.push(g);
            results.push(b);
        }

        results
    }

    fn index_for_magnitude(&self, magnitude: Option<u32>) -> u8 {
        match magnitude {
            None => 0,
            Some(magnitude) => {
                if magnitude > 255 {
                    1
                } else {
                    (255 - magnitude) as u8
                }
            },
            //Some(age) => match self.steps.iter().position(|&(x, _)| x == age) {
            //    None => 0,
            //    Some(i) => (i+1) as u8,
            //}
        }
    }
}

fn read_pbf(filename: &str, height: u32, sec_per_frame: u32, bbox: &[f32; 4]) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut node_reader = PBFReader::new(file);
    let node_reader = node_reader.nodes();

    let mut results: HashMap<u32, HashMap<u32, u16>> = HashMap::new();

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // 1st April 2005, midnight GMT. We presume no OSM editing before then.
    let osm_epoch = 1109635200;

    // FIXME use a btreemap?

    let mut first_frame_no = std::u32::MAX;
    let mut last_frame_no = 0;

    let mut num_nodes: u64 = 0;
    for node in node_reader {
        if let (Some(lat), Some(lon)) = (node.lat, node.lon) {
            // FIXME should be able to do non-equals but it fails for point at south pole
            if lat >= top || lat <= bottom || lon >= right || lon <= left {
                continue;
            }

            let timestamp = node.timestamp.to_epoch_number() as u64;
            if timestamp < osm_epoch {
                panic!("timestamp before epoch. Change code. {}", timestamp);
            }
            let offset = (timestamp - osm_epoch) as u32;
            // TODO double check that this rounds down
            let frame_no = offset / sec_per_frame;

            if frame_no < first_frame_no {
                first_frame_no = frame_no;
            }
            if frame_no > last_frame_no {
                last_frame_no = frame_no;
            }

            let pixel_idx = latlon_to_pixel_index(lat, lon, width, height, &bbox);
            let curr_val = results.entry(frame_no).or_insert(HashMap::new()).entry(pixel_idx).or_insert(0);
            if *curr_val < std::u16::MAX {
                *curr_val += 1;
            }

            num_nodes += 1;
            if num_nodes % 50_000_000 == 0 {
                println!("Done {} million points", num_nodes/1_000_000);
            }
        }
    }
    println!("Done {} points", num_nodes);
    let num_frames = last_frame_no - first_frame_no + 1;
    println!("There are {} frames, which is {} sec", num_frames, num_frames as f32/30.);

    let mut sorted_results = Vec::with_capacity((last_frame_no-first_frame_no+1) as usize);

    for frame_no in 0..num_frames {
        match results.remove(&(frame_no+first_frame_no)) {
            None => { sorted_results.push((frame_no, Vec::with_capacity(0))) },
            Some(pixels) => {
                let pixels = pixels.into_iter().collect();
                sorted_results.push((frame_no, pixels));
            }
        }
    }

    sorted_results
}

fn write_frames(frames: Frames, filename: &str) {
    let mut file = BufWriter::new(fs::File::create(&filename).unwrap());
    for (frame_no, pixels) in frames.into_iter() {
        write!(file, "{}", frame_no).unwrap();
        for p in pixels {
            write!(file, ",{},{}", p.0, p.1).unwrap();
        }
        write!(file, "\n").unwrap()
    }
}

fn read_frames(filename: &str) -> Frames {
    let file = BufReader::new(fs::File::open(&filename).unwrap());
    let mut results = Frames::new();

    for line in file.lines() {
        let line = line.unwrap();
        let frame_no = line.split(",").nth(0).unwrap().parse().unwrap();
        let pixels: Vec<(u32, u16)> = line.split(",").skip(1).collect::<Vec<_>>().chunks(2).map(|pair| (pair[0].parse().unwrap(), pair[1].parse().unwrap())).collect();
        results.push((frame_no, pixels))
    }

    results
}

fn latlon_to_pixel_index(lat: f32, lon: f32, width: u32, height: u32, bbox: &[f32; 4]) -> u32 {
    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;

    let lat0 = top - lat;
    let lon0 = lon - left;

    let x = ((lon0/bbox_width)*(width as f32)) as u32;
    let y = ((lat0/bbox_height)*(height as f32)) as u32;

    let i = y * width + x;

    assert!(i < width*height, "{} L{}, lat = {} lon = {} width = {} height = {} bbox = {:?} x = {} y = {} i = {}", file!(), line!(), lat, lon, width, height, bbox, x, y, i);

    i
}

fn create_equirectangular_map(frames: Frames, output_image_filename: &str, height: u32, bbox: &[f32; 4], colour_ramp: &ColourRamp) {
    let mut output_file = fs::File::create(output_image_filename).expect("Can't create image");

    let left = bbox[0]; let bottom = bbox[1]; let right = bbox[2]; let top = bbox[3];
    let bbox_width = right - left;
    let bbox_height = top - bottom;
    let width = ((bbox_width / bbox_height) * (height as f32)) as u32;

    // FIXME change width/height to u16?
    let mut encoder = gif::Encoder::new(&mut output_file, width as u16, height as u16, &colour_ramp.palette()).expect("Couldn't create encoder");
    encoder.set(gif::Repeat::Infinite).expect("Couldn't get inf repeat");

    // TODO have a global palette

    let mut image = vec![None; (width*height) as usize];

    for (frame_no, pixels) in frames.into_iter() {

        for i in 0..image.len() {
            if image[i].is_some() && image[i].unwrap() > 0 {
                image[i] = image[i].map(|x| x-1);
            }
        }

        for (i, magnitude) in pixels {
            // FIXME sometimes the value is invalid
            //assert!(i < width*height, "{} L{}, width = {} height = {} i = {}", file!(), line!(), width, height, i);
            if i < width*height {
                image[i as usize] = Some(magnitude as u32);
            }
        }

        let mut pixels = Vec::with_capacity(image.len() * 4);
        for p in image.iter().cloned() {
            let index = colour_ramp.index_for_magnitude(p);
            pixels.push(index);
        }

        let mut frame = gif::Frame::from_indexed_pixels(width as u16, height as u16, pixels.as_mut_slice());
        // 30 fps, and delay is in units of 10ms.
        frame.delay = 100 / 30;

        encoder.write_frame(&frame).expect("Couldn't write frame");

        if frame_no % 30 == 0 {
            println!("Wrote frame {}", frame_no);
        }

    }

}

fn main() {
    let matches = App::new("osm-history-animation")
                          .arg(Arg::with_name("input").long("input").short("i")
                               .takes_value(true))
                          .arg(Arg::with_name("output") .long("output").short("o")
                               .takes_value(true))
                          .arg(Arg::with_name("height") .long("height").short("h")
                               .takes_value(true))
                          .arg(Arg::with_name("spf") .long("sec-per-frame").short("s")
                               .takes_value(true))
                          .arg(Arg::with_name("colour_ramp") .long("colour-ramp")
                               .takes_value(true))
                          .arg(Arg::with_name("save-intermediate").long("save-intermediate"))
                          .arg(Arg::with_name("load-intermediate").long("load-intermediate"))
                          .arg(Arg::with_name("bbox").long("bbox").takes_value(true).short("b"))
                          .setting(AppSettings::AllowLeadingHyphen)
                          .get_matches();

    let input_filename = matches.value_of("input").unwrap();
    let output_filename = matches.value_of("output").unwrap();
    let height: u32 = matches.value_of("height").unwrap().parse().unwrap();
    let frames_per_sec: u32 = matches.value_of("spf").unwrap().parse().unwrap();

    let bbox = match matches.value_of("bbox") {
        None => [-180., -90., 180., 90.],
        Some(text) => {
            let coords: Vec<f32> = text.split(",").map(|x| x.parse().unwrap() ).collect();
            [coords[0], coords[1], coords[2], coords[3]]
        }
    };

    let frames = if matches.is_present("load-intermediate") {
        println!("Reading frames from {}", input_filename);
        read_frames(&input_filename)
    } else {
        println!("Reading PBF file {}", input_filename);
        read_pbf(&input_filename, height, frames_per_sec, &bbox)
    };

    if matches.is_present("save-intermediate") {
        println!("Saving frame details to {}", output_filename);
        write_frames(frames, &output_filename);
    } else {
        let colour_ramp = ColourRamp::new_from_filename(matches.value_of("colour_ramp").unwrap());
        println!("Creating image {}", output_filename);
        create_equirectangular_map(frames, &output_filename, height, &bbox, &colour_ramp);
    }
    println!("\nFinished");
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

extern crate clap;
use clap::{Arg, App, SubCommand};
extern crate toml;

// extern crate hyper;
// extern crate hyper_rustls;
// use hyper::Client;
// use hyper::net::HttpsConnector;
// use hyper_rustls::TlsClient;
// use hyper::header::Authorization;
// use hyper::header::{Accept, qitem};
// use hyper::mime::{Mime, TopLevel, SubLevel};

extern crate reqwest;
use reqwest::header::{Authorization,Accept};

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

#[derive(Deserialize, Debug)]
struct Config {
    token: String,
    org: String,
    team: String,
    #[serde(default="default_endpoint")]
    endpoint: String,
    #[serde(default="default_home")]
    home: String,
    #[serde(default="default_gid")]
    gid: u64,
    #[serde(default="default_sh")]
    sh: String,
    group: Option<String>,
}

fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_gid() -> u64 { 2000 }
fn default_sh() -> String { String::from("/bin/bash") }

#[derive(Serialize, Deserialize, Debug)]
struct Team {
    id: u64,
    name: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Member {
    id: u64,
    login: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct PublicKey {
    id: u64,
    key: String,
}

#[derive(Debug)]
enum CliError {
    Serde(serde_json::Error),
    Reqwest(reqwest::Error),
    Io(std::io::Error)
}

impl From<serde_json::Error> for CliError {fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }}
impl From<reqwest::Error> for CliError {fn from(err: reqwest::Error) -> CliError { CliError::Reqwest(err) }}
impl From<std::io::Error> for CliError {fn from(err: std::io::Error) -> CliError { CliError::Io(err) }}

fn main() {

    let matches = App::new("ghteam-auth")
                      .version("0.1")
                      .author("Yasuyuki YAMADA <yasuyuki.ymd@gmail.com>")
                      .about("")
                      .arg(Arg::with_name("config")
                               .short("c")
                               .long("config")
                               .value_name("FILE")
                               .help("Sets a custom config file (toml)")
                               .takes_value(true))
                      .arg(Arg::with_name("v")
                               .short("v")
                               .multiple(true)
                               .help("Sets the level of verbosity"))
                      .subcommand(SubCommand::with_name("key")
                                             .about("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(true)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("pam")
                                             .about("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(false)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("passwd")
                                             .about("get passwd"))
                      .subcommand(SubCommand::with_name("shadow")
                                             .about("get shadow"))
                      .subcommand(SubCommand::with_name("group")
                                             .about("get group"))
                      .subcommand(SubCommand::with_name("refresh")
                                             .about("refresh cache"))
                      .get_matches();

    let config = matches.value_of("config").unwrap_or("/etc/ghteam-auth.conf");
    let mut file = File::open(config).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    let config = toml::from_str::<Config>(contents.as_str()).unwrap();

    // let client = Client::with_connector(HttpsConnector::new(TlsClient::new()));
    let client = reqwest::Client::new().unwrap();
    let client = GithubClient::new(client, config);

    if let Some(matches) = matches.subcommand_matches("key") {
        client.print_user_public_key(matches.value_of("USER").unwrap()).unwrap();
    } else if let Some(_) = matches.subcommand_matches("passwd") {
        client.get_passwd().unwrap();
    } else if let Some(_) = matches.subcommand_matches("shadow") {
        client.get_shadow().unwrap();
    } else if let Some(_) = matches.subcommand_matches("group") {
        client.get_group().unwrap();
    } else if let Some(_) = matches.subcommand_matches("pam") {
        match std::env::var("PAM_USER") {
            Ok(user) => {
                if client.check_pam(&user).unwrap() { std::process::exit(0); }
                else { std::process::exit(1) }
            }
            Err(e) => println!("couldn't interpret PAM_USER: {}", e),
        }
    }

}

struct GithubClient {
    // client: hyper::Client,
    client: reqwest::Client,
    conf: Config
}

impl GithubClient {
    fn new(client:reqwest::Client, conf:Config) -> GithubClient {
        GithubClient {client:client, conf:conf}
    }

    fn get_url_content(&self, url:&String) -> Result<String,CliError> {
        // println!("GET {}", url);
        let token = String::from("token ") + self.conf.token.clone().as_str();
        let res = self.client.get(url.as_str()).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        Ok(content)
    }

    fn print_user_public_key(&self, user:&str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user:&str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint.clone(),user);
        let content = self.get_url_content(&url);
        let keys = serde_json::from_str::<Vec<PublicKey>>(content?.as_str())?;
        Ok(keys.iter().map(|k|{k.key.clone()}).collect::<Vec<String>>().join("\n"))
    }

    fn check_pam(&self, user:&String) -> Result<bool, CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                if member.login==*user { return Ok(true) }
            }
        }
        Ok(false)
    }

    fn get_passwd(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_passwd_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_shadow(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_shadow_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_group(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            let members = self.get_members(team.id)?;
            println!("{}", self.create_group_line(&team.name, self.conf.gid, &members));
            Ok(())
        } else {
            Ok(())
        }
    }

    fn create_passwd_line(&self, member:&Member) -> String {
        format!("{login}:x:{uid}:{gid}:user@{org}:{home}:{sh}",
                login=member.login,
                uid=member.id,
                gid=self.conf.gid,
                org=self.conf.org,
                home=self.conf.home.replace("{}",member.login.as_str()),
                sh=self.conf.sh,
                )
    }

    fn create_shadow_line(&self, member:&Member) -> String {
        format!("{login}:!!:::::::", login=member.login )
    }

    fn create_group_line(&self, name:&String, id:u64, members:&Vec<Member>) -> String {
        format!("{name}:x:{id}:{members}", name=name, id=id,
                members=members.iter().map(|m|{m.login.clone()}).collect::<Vec<String>>().join(","))
    }

    fn get_teams(&self) -> Result<HashMap<String,Team>, CliError> {
        let url = format!("{}/orgs/{}/teams",self.conf.endpoint.clone(), self.conf.org.clone());
        let content = self.get_url_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(content.as_str())?;
        let mut team_map = HashMap::new();
        for team in teams { team_map.insert(team.name.clone(), team); }
        Ok(team_map)
    }

    fn get_members(&self, mid:u64) -> Result<Vec<Member>, CliError> {
        let url = format!("{}/teams/{}/members",self.conf.endpoint.clone(), mid);
        let content = self.get_url_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(content.as_str())?;
        Ok(members)
    }

}
<commit_msg>Remove unused import<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;

extern crate clap;
use clap::{Arg, App, SubCommand};
extern crate toml;

// extern crate hyper;
// extern crate hyper_rustls;
// use hyper::Client;
// use hyper::net::HttpsConnector;
// use hyper_rustls::TlsClient;
// use hyper::header::Authorization;
// use hyper::header::{Accept, qitem};
// use hyper::mime::{Mime, TopLevel, SubLevel};

extern crate reqwest;
use reqwest::header::Authorization;

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

#[derive(Deserialize, Debug)]
struct Config {
    token: String,
    org: String,
    team: String,
    #[serde(default="default_endpoint")]
    endpoint: String,
    #[serde(default="default_home")]
    home: String,
    #[serde(default="default_gid")]
    gid: u64,
    #[serde(default="default_sh")]
    sh: String,
    group: Option<String>,
}

fn default_endpoint() -> String { String::from("https://api.github.com") }
fn default_home() -> String { String::from("/home/{}") }
fn default_gid() -> u64 { 2000 }
fn default_sh() -> String { String::from("/bin/bash") }

#[derive(Serialize, Deserialize, Debug)]
struct Team {
    id: u64,
    name: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct Member {
    id: u64,
    login: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct PublicKey {
    id: u64,
    key: String,
}

#[derive(Debug)]
enum CliError {
    Serde(serde_json::Error),
    Reqwest(reqwest::Error),
    Io(std::io::Error)
}

impl From<serde_json::Error> for CliError {fn from(err: serde_json::Error) -> CliError { CliError::Serde(err) }}
impl From<reqwest::Error> for CliError {fn from(err: reqwest::Error) -> CliError { CliError::Reqwest(err) }}
impl From<std::io::Error> for CliError {fn from(err: std::io::Error) -> CliError { CliError::Io(err) }}

fn main() {

    let matches = App::new("ghteam-auth")
                      .version("0.1")
                      .author("Yasuyuki YAMADA <yasuyuki.ymd@gmail.com>")
                      .about("")
                      .arg(Arg::with_name("config")
                               .short("c")
                               .long("config")
                               .value_name("FILE")
                               .help("Sets a custom config file (toml)")
                               .takes_value(true))
                      .arg(Arg::with_name("v")
                               .short("v")
                               .multiple(true)
                               .help("Sets the level of verbosity"))
                      .subcommand(SubCommand::with_name("key")
                                             .about("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(true)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("pam")
                                             .about("get user public key")
                                             .arg(Arg::with_name("USER")
                                                      .required(false)
                                                      .index(1)
                                                      .help("user name")))
                      .subcommand(SubCommand::with_name("passwd")
                                             .about("get passwd"))
                      .subcommand(SubCommand::with_name("shadow")
                                             .about("get shadow"))
                      .subcommand(SubCommand::with_name("group")
                                             .about("get group"))
                      .subcommand(SubCommand::with_name("refresh")
                                             .about("refresh cache"))
                      .get_matches();

    let config = matches.value_of("config").unwrap_or("/etc/ghteam-auth.conf");
    let mut file = File::open(config).unwrap();
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();
    let config = toml::from_str::<Config>(contents.as_str()).unwrap();

    // let client = Client::with_connector(HttpsConnector::new(TlsClient::new()));
    let client = reqwest::Client::new().unwrap();
    let client = GithubClient::new(client, config);

    if let Some(matches) = matches.subcommand_matches("key") {
        client.print_user_public_key(matches.value_of("USER").unwrap()).unwrap();
    } else if let Some(_) = matches.subcommand_matches("passwd") {
        client.get_passwd().unwrap();
    } else if let Some(_) = matches.subcommand_matches("shadow") {
        client.get_shadow().unwrap();
    } else if let Some(_) = matches.subcommand_matches("group") {
        client.get_group().unwrap();
    } else if let Some(_) = matches.subcommand_matches("pam") {
        match std::env::var("PAM_USER") {
            Ok(user) => {
                if client.check_pam(&user).unwrap() { std::process::exit(0); }
                else { std::process::exit(1) }
            }
            Err(e) => println!("couldn't interpret PAM_USER: {}", e),
        }
    }

}

struct GithubClient {
    // client: hyper::Client,
    client: reqwest::Client,
    conf: Config
}

impl GithubClient {
    fn new(client:reqwest::Client, conf:Config) -> GithubClient {
        GithubClient {client:client, conf:conf}
    }

    fn get_url_content(&self, url:&String) -> Result<String,CliError> {
        // println!("GET {}", url);
        let token = String::from("token ") + self.conf.token.clone().as_str();
        let res = self.client.get(url.as_str()).header(Authorization(token)).send();
        let mut content = String::new();
        res?.read_to_string(&mut content)?;
        Ok(content)
    }

    fn print_user_public_key(&self, user:&str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user:&str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint.clone(),user);
        let content = self.get_url_content(&url);
        let keys = serde_json::from_str::<Vec<PublicKey>>(content?.as_str())?;
        Ok(keys.iter().map(|k|{k.key.clone()}).collect::<Vec<String>>().join("\n"))
    }

    fn check_pam(&self, user:&String) -> Result<bool, CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                if member.login==*user { return Ok(true) }
            }
        }
        Ok(false)
    }

    fn get_passwd(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_passwd_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_shadow(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            for member in self.get_members(team.id)? {
                println!("{}", self.create_shadow_line(&member));
            }
            Ok(())
        } else {
            Ok(())
        }
    }

    fn get_group(&self) -> Result<(), CliError> {
        let teams:HashMap<String,Team> = self.get_teams()?;
        if let Some(team) = teams.get(&self.conf.team.clone()) {
            let members = self.get_members(team.id)?;
            println!("{}", self.create_group_line(&team.name, self.conf.gid, &members));
            Ok(())
        } else {
            Ok(())
        }
    }

    fn create_passwd_line(&self, member:&Member) -> String {
        format!("{login}:x:{uid}:{gid}:user@{org}:{home}:{sh}",
                login=member.login,
                uid=member.id,
                gid=self.conf.gid,
                org=self.conf.org,
                home=self.conf.home.replace("{}",member.login.as_str()),
                sh=self.conf.sh,
                )
    }

    fn create_shadow_line(&self, member:&Member) -> String {
        format!("{login}:!!:::::::", login=member.login )
    }

    fn create_group_line(&self, name:&String, id:u64, members:&Vec<Member>) -> String {
        format!("{name}:x:{id}:{members}", name=name, id=id,
                members=members.iter().map(|m|{m.login.clone()}).collect::<Vec<String>>().join(","))
    }

    fn get_teams(&self) -> Result<HashMap<String,Team>, CliError> {
        let url = format!("{}/orgs/{}/teams",self.conf.endpoint.clone(), self.conf.org.clone());
        let content = self.get_url_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(content.as_str())?;
        let mut team_map = HashMap::new();
        for team in teams { team_map.insert(team.name.clone(), team); }
        Ok(team_map)
    }

    fn get_members(&self, mid:u64) -> Result<Vec<Member>, CliError> {
        let url = format!("{}/teams/{}/members",self.conf.endpoint.clone(), mid);
        let content = self.get_url_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(content.as_str())?;
        Ok(members)
    }

}
<|endoftext|>