<commit_before>#[macro_use]
extern crate conrod;
use conrod::{widget, Borderable, Colorable, Labelable, Positionable, Sizeable, Widget};
use conrod::backend::glium::glium;
use conrod::backend::glium::glium::{DisplayBuild, Surface};
use std::num::Wrapping;

// nb_live = number of live neighbour among the 8 surrounding cells
// Conway rules:
// * Cell survives if:
// < 2 => die
// == 2 => survive
// > 3 => die
// == 3 => survive
//
// * Cell is born if:
// == 3 become alive

fn conway_survives() -> Vec<usize> {
	vec![2,3]
}

fn conway_borns() -> Vec<usize> {
	vec![3]
}

#[derive(Debug)]
struct Board {
	width: usize,
	height: usize,
	data: Vec<bool>,
	survives_by_count: [bool; 10], // note that the center cell is included in the count, so index is #neighbor+1
	borns_by_count: [bool; 9],
}

impl Board {
	fn new( width: usize, height: usize, survives: &Vec<usize>, borns: &Vec<usize> ) -> Board {
		let mut survives_by_count = [false; 10];
		for count in survives.iter() {
			survives_by_count[count+1] = true; // center cell is included in the count, hence the +1
		}
		let mut borns_by_count = [false; 9];
		for count in borns.iter() {
			borns_by_count[count+0] = true;
		}

		Board {
			width: width,
			height: height,
			data: vec![true; width* height],
			survives_by_count: survives_by_count,
			borns_by_count: borns_by_count,
		}
	}

	fn get(&self, x: usize, y: usize) -> bool {
		assert!( x <= self.width  &&  y <= self.height );
		self.data[ y * self.width + x ]
	}

	fn set(&mut self, x: usize, y: usize, new_value: bool) {
		assert!( x <= self.width  &&  y <= self.height );
		self.data[ y * self.width + x ] = new_value;
	}

	fn advance_simulation(&mut self) {
//		println!("Begin simulation board={:?}", self);
		let mut next_board: Vec<bool> = Vec::with_capacity( self.data.len() );
		for y_test in 0..self.height {
			for x_test in 0..self.width {
				next_board.push( self.cell_next_state(x_test, y_test) );
			}
		}
		assert!( next_board.len() == self.data.len() );
		self.data = next_board;
//		println!("End simulation board={:?}", self);
	}

	fn cell_next_state(&self, x: usize, y: usize) -> bool {
		let nb_neighbor = self.count_neighbor(x,y);
		if self.get(x, y) {
			self.survives_by_count[nb_neighbor + 1]
		} else {
			self.borns_by_count[nb_neighbor]
		}
	}

	fn cell_alive(&self, x: usize, y: usize) -> usize {
		((x < self.width  &&  y < self.height)  &&  self.data[x + y*self.width]) as usize
	}

	fn count_neighbor( &self, x: usize, y: usize ) -> usize {
		let Wrapping(x_minus_1) = Wrapping(x) - Wrapping(1);
		let Wrapping(y_minus_1) = Wrapping(y) - Wrapping(1);
		self.cell_alive(x_minus_1, y_minus_1) + self.cell_alive(x, y_minus_1) + self.cell_alive(x+1, y_minus_1) +
		self.cell_alive(x_minus_1, y) + self.cell_alive(x+1, y) +
		self.cell_alive(x_minus_1, y+1) + self.cell_alive(x, y+1) + self.cell_alive(x+1, y+1)
	}

}

#[derive(Debug)]
struct AppState {
	board: Board,
	simulating: bool,
}

impl AppState {
	fn new() -> AppState {
		const BOARD_WIDTH: usize = 8;
		const BOARD_HEIGHT: usize = 8;

		AppState {
			board: Board::new(BOARD_WIDTH, BOARD_HEIGHT, &conway_survives(), &conway_borns()),
			simulating: false,
		}
	}
}

fn main() {
	const WIDTH: u32 = 400;
	const HEIGHT: u32 = 400;

	let mut app_state = AppState::new();
//	println!("Initial app_state={:?}", app_state);

	// Build the window.
	let display = glium::glutin::WindowBuilder::new()
		.with_vsync()
		.with_dimensions(WIDTH, HEIGHT)
		.with_title("Game of Life")
		.with_multisampling(4)
		.build_glium()
		.unwrap();

	// construct our `Ui`.
	let mut ui = conrod::UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build();

	// Generate the widget identifiers.
	widget_ids!(struct Ids {
		title,
		info,
		board,
		start_stop_button
	});
	let ids = Ids::new(ui.widget_id_generator());

	// Add a `Font` to the `Ui`'s `font::Map` from file.
	const FONT_PATH: &'static str =
		concat!(env!("CARGO_MANIFEST_DIR"), "/assets/fonts/NotoSans/NotoSans-Regular.ttf");
	ui.fonts.insert_from_file(FONT_PATH).unwrap();

	// A type used for converting `conrod::render::Primitives` into `Command`s that can be used
	// for drawing to the glium `Surface`.
	let mut renderer = conrod::backend::glium::Renderer::new(&display).unwrap();

	// The image map describing each of our widget->image mappings (in our case, none).
	let image_map = conrod::image::Map::<glium::texture::Texture2d>::new();

	// Poll events from the window.
	let mut last_update = std::time::Instant::now();
	let mut ui_needs_update = true;
	'main: loop {

		// We don't want to loop any faster than 60 FPS, so wait until it has been at least
		// 16ms since the last yield.
		let sixteen_ms = std::time::Duration::from_millis(16);
		let duration_since_last_update = std::time::Instant::now().duration_since(last_update);
		if duration_since_last_update < sixteen_ms {
			std::thread::sleep(sixteen_ms - duration_since_last_update);
		}

		// Collect all pending events.
		let mut events: Vec<_> = display.poll_events().collect();

		// If there are no events and the `Ui` does not need updating, wait for the next event.
		if events.is_empty() && !ui_needs_update {
			events.extend(display.wait_events().next());
		}

		// Reset the needs_update flag and time this update.
		ui_needs_update = false;
		last_update = std::time::Instant::now();

		// Handle all events.
		for event in events {

			// Use the `winit` backend feature to convert the winit event to a conrod one.
			if let Some(event) = conrod::backend::winit::convert(event.clone(), &display) {
				ui.handle_event(event);
				ui_needs_update = true;
			}

			match event {
				// Break from the loop upon `Escape`.
				glium::glutin::Event::KeyboardInput(_, _, Some(glium::glutin::VirtualKeyCode::Escape)) |
				glium::glutin::Event::Closed =>
					break 'main,
				_ => {},
			}
		}

		if app_state.simulating {
			app_state.board.advance_simulation();
		}

		// Instantiate all widgets in the GUI.
		{
			let ui = &mut ui.set_widgets();

			// "Hello World!" in the middle of the screen.
			widget::Text::new("Game of Life")
				.mid_top_of(ui.window)
				.color(conrod::color::WHITE)
				.font_size(32)
				.set(ids.title, ui);

			let start_stop_label = if app_state.simulating { "Pause simulation" } else { "Start simulation"};
			let start_stop_button = widget::Button::new()
				.label(start_stop_label)
				.down_from(ids.title, 5.0)
				.set(ids.start_stop_button, ui);
			for _press in start_stop_button {
				app_state.simulating = !app_state.simulating;
			}

			// A demonstration using widget_matrix to easily draw a matrix of any kind of widget.
			let (cols, rows) = (8, 8);
			let mut elements = widget::Matrix::new(cols, rows)
				.down(20.0)
				.w_h(260.0, 260.0)
				.set(ids.board, ui);

			// The `Matrix` widget returns an `Elements`, which can be used similar to an `Iterator`.
			while let Some(elem) = elements.next(ui) {
				let (col, row) = (elem.col, elem.row);

				// Color effect for fun.
				let (r, g, b, a) = (
					0.5 + (elem.col as f32 / cols as f32) / 2.0,
					0.75,
					1.0 - (elem.row as f32 / rows as f32) / 2.0,
					1.0
				);

				// We can use `Element`s to instantiate any kind of widget we like.
				// The `Element` does all of the positioning and sizing work for us.
				// Here, we use the `Element` to `set` a `Toggle` widget for us.
				let toggle = widget::Toggle::new(app_state.board.get(col, row))
					.rgba(r, g, b, a)
					.border(1.0);
				if let Some(new_value) = elem.set(toggle, ui).last() {
					app_state.board.set(col, row, new_value);
				}
			}

		}

		// Render the `Ui` and then display it on the screen.
		if let Some(primitives) = ui.draw_if_changed() {
			renderer.fill(&display, primitives, &image_map);
			let mut target = display.draw();
			target.clear_color(0.0, 0.0, 0.0, 1.0);
			renderer.draw(&display, &mut target, &image_map).unwrap();
			target.finish().unwrap();
		}
	}
}
<commit_msg>Update ui when simulation is active.<commit_after>#[macro_use]
extern crate conrod;
use conrod::{widget, Borderable, Colorable, Labelable, Positionable, Sizeable, Widget};
use conrod::backend::glium::glium;
use conrod::backend::glium::glium::{DisplayBuild, Surface};
use std::num::Wrapping;

// nb_live = number of live neighbour among the 8 surrounding cells
// Conway rules:
// * Cell survives if:
// < 2 => die
// == 2 => survive
// > 3 => die
// == 3 => survive
//
// * Cell is born if:
// == 3 become alive

fn conway_survives() -> Vec<usize> {
	vec![2,3]
}

fn conway_borns() -> Vec<usize> {
	vec![3]
}

#[derive(Debug)]
struct Board {
	width: usize,
	height: usize,
	data: Vec<bool>,
	survives_by_count: [bool; 10], // note that the center cell is included in the count, so index is #neighbor+1
	borns_by_count: [bool; 9],
}

impl Board {
	fn new( width: usize, height: usize, survives: &Vec<usize>, borns: &Vec<usize> ) -> Board {
		let mut survives_by_count = [false; 10];
		for count in survives.iter() {
			survives_by_count[count+1] = true; // center cell is included in the count, hence the +1
		}
		let mut borns_by_count = [false; 9];
		for count in borns.iter() {
			borns_by_count[count+0] = true;
		}

		Board {
			width: width,
			height: height,
			data: vec![true; width* height],
			survives_by_count: survives_by_count,
			borns_by_count: borns_by_count,
		}
	}

	fn get(&self, x: usize, y: usize) -> bool {
		assert!( x <= self.width  &&  y <= self.height );
		self.data[ y * self.width + x ]
	}

	fn set(&mut self, x: usize, y: usize, new_value: bool) {
		assert!( x <= self.width  &&  y <= self.height );
		self.data[ y * self.width + x ] = new_value;
	}

	fn advance_simulation(&mut self) {
//		println!("Begin simulation board={:?}", self);
		let mut next_board: Vec<bool> = Vec::with_capacity( self.data.len() );
		for y_test in 0..self.height {
			for x_test in 0..self.width {
				next_board.push( self.cell_next_state(x_test, y_test) );
			}
		}
		assert!( next_board.len() == self.data.len() );
		self.data = next_board;
//		println!("End simulation board={:?}", self);
	}

	fn cell_next_state(&self, x: usize, y: usize) -> bool {
		let nb_neighbor = self.count_neighbor(x,y);
		if self.get(x, y) {
			self.survives_by_count[nb_neighbor + 1]
		} else {
			self.borns_by_count[nb_neighbor]
		}
	}

	fn cell_alive(&self, x: usize, y: usize) -> usize {
		((x < self.width  &&  y < self.height)  &&  self.data[x + y*self.width]) as usize
	}

	fn count_neighbor( &self, x: usize, y: usize ) -> usize {
		let Wrapping(x_minus_1) = Wrapping(x) - Wrapping(1);
		let Wrapping(y_minus_1) = Wrapping(y) - Wrapping(1);
		self.cell_alive(x_minus_1, y_minus_1) + self.cell_alive(x, y_minus_1) + self.cell_alive(x+1, y_minus_1) +
		self.cell_alive(x_minus_1, y) + self.cell_alive(x+1, y) +
		self.cell_alive(x_minus_1, y+1) + self.cell_alive(x, y+1) + self.cell_alive(x+1, y+1)
	}

}

#[derive(Debug)]
struct AppState {
	board: Board,
	simulating: bool,
}

impl AppState {
	fn new() -> AppState {
		const BOARD_WIDTH: usize = 8;
		const BOARD_HEIGHT: usize = 8;

		AppState {
			board: Board::new(BOARD_WIDTH, BOARD_HEIGHT, &conway_survives(), &conway_borns()),
			simulating: false,
		}
	}
}

fn main() {
	const WIDTH: u32 = 400;
	const HEIGHT: u32 = 400;

	let mut app_state = AppState::new();
//	println!("Initial app_state={:?}", app_state);

	// Build the window.
	let display = glium::glutin::WindowBuilder::new()
		.with_vsync()
		.with_dimensions(WIDTH, HEIGHT)
		.with_title("Game of Life")
		.with_multisampling(4)
		.build_glium()
		.unwrap();

	// construct our `Ui`.
	let mut ui = conrod::UiBuilder::new([WIDTH as f64, HEIGHT as f64]).build();

	// Generate the widget identifiers.
	widget_ids!(struct Ids {
		title,
		info,
		board,
		start_stop_button
	});
	let ids = Ids::new(ui.widget_id_generator());

	// Add a `Font` to the `Ui`'s `font::Map` from file.
	const FONT_PATH: &'static str =
		concat!(env!("CARGO_MANIFEST_DIR"), "/assets/fonts/NotoSans/NotoSans-Regular.ttf");
	ui.fonts.insert_from_file(FONT_PATH).unwrap();

	// A type used for converting `conrod::render::Primitives` into `Command`s that can be used
	// for drawing to the glium `Surface`.
	let mut renderer = conrod::backend::glium::Renderer::new(&display).unwrap();

	// The image map describing each of our widget->image mappings (in our case, none).
	let image_map = conrod::image::Map::<glium::texture::Texture2d>::new();

	// Poll events from the window.
	let mut last_update = std::time::Instant::now();
	let mut ui_needs_update = true;
	'main: loop {

		// We don't want to loop any faster than 60 FPS, so wait until it has been at least
		// 16ms since the last yield.
		let sixteen_ms = std::time::Duration::from_millis(16);
		let duration_since_last_update = std::time::Instant::now().duration_since(last_update);
		if duration_since_last_update < sixteen_ms {
			std::thread::sleep(sixteen_ms - duration_since_last_update);
		}

		// Collect all pending events.
		let mut events: Vec<_> = display.poll_events().collect();

		// If there are no events and the `Ui` does not need updating, wait for the next event.
		if events.is_empty() && !ui_needs_update {
			events.extend(display.wait_events().next());
		}

		// Reset the needs_update flag and time this update.
		ui_needs_update = false;
		last_update = std::time::Instant::now();

		// Handle all events.
		for event in events {

			// Use the `winit` backend feature to convert the winit event to a conrod one.
			if let Some(event) = conrod::backend::winit::convert(event.clone(), &display) {
				ui.handle_event(event);
				ui_needs_update = true;
			}

			match event {
				// Break from the loop upon `Escape`.
				glium::glutin::Event::KeyboardInput(_, _, Some(glium::glutin::VirtualKeyCode::Escape)) |
				glium::glutin::Event::Closed =>
					break 'main,
				_ => {},
			}
		}

		if app_state.simulating {
			app_state.board.advance_simulation();
			ui_needs_update = true;
		}

		// Instantiate all widgets in the GUI.
		{
			let ui = &mut ui.set_widgets();

			// "Hello World!" in the middle of the screen.
			widget::Text::new("Game of Life")
				.mid_top_of(ui.window)
				.color(conrod::color::WHITE)
				.font_size(32)
				.set(ids.title, ui);

			let start_stop_label = if app_state.simulating { "Pause simulation" } else { "Start simulation"};
			let start_stop_button = widget::Button::new()
				.label(start_stop_label)
				.down_from(ids.title, 5.0)
				.set(ids.start_stop_button, ui);
			for _press in start_stop_button {
				app_state.simulating = !app_state.simulating;
			}

			// A demonstration using widget_matrix to easily draw a matrix of any kind of widget.
			let (cols, rows) = (8, 8);
			let mut elements = widget::Matrix::new(cols, rows)
				.down(20.0)
				.w_h(260.0, 260.0)
				.set(ids.board, ui);

			// The `Matrix` widget returns an `Elements`, which can be used similar to an `Iterator`.
			while let Some(elem) = elements.next(ui) {
				let (col, row) = (elem.col, elem.row);

				// Color effect for fun.
				let (r, g, b, a) = (
					0.5 + (elem.col as f32 / cols as f32) / 2.0,
					0.75,
					1.0 - (elem.row as f32 / rows as f32) / 2.0,
					1.0
				);

				// We can use `Element`s to instantiate any kind of widget we like.
				// The `Element` does all of the positioning and sizing work for us.
				// Here, we use the `Element` to `set` a `Toggle` widget for us.
				let toggle = widget::Toggle::new(app_state.board.get(col, row))
					.rgba(r, g, b, a)
					.border(1.0);
				if let Some(new_value) = elem.set(toggle, ui).last() {
					app_state.board.set(col, row, new_value);
				}
			}

		}

		// Render the `Ui` and then display it on the screen.
		if let Some(primitives) = ui.draw_if_changed() {
			renderer.fill(&display, primitives, &image_map);
			let mut target = display.draw();
			target.clear_color(0.0, 0.0, 0.0, 1.0);
			renderer.draw(&display, &mut target, &image_map).unwrap();
			target.finish().unwrap();
		}
	}
}
<|endoftext|>


<commit_before>extern mod std;
extern mod rfc4648;

use std::net::ip;
use std::net::tcp;
use std::uv_global_loop;

use core::io::{ReaderUtil, WriterUtil};
use core::task::{SingleThreaded, task};
use std::net::tcp::{TcpErrData, TcpNewConnection, TcpSocket};
use rfc4648::base64::{BASE64_STD, Base64Writer};

type KillChan = comm::Chan<Option<TcpErrData>>;
type ContChan = comm::Chan<()>;

fn main() {
    let iotask = uv_global_loop::get();

    let addr = "127.0.0.1";
    let port = 1337;

    let backlog = 128;
    let ip_addr = ip::get_addr(addr, iotask);
    let ip_addr = copy result::unwrap(ip_addr)[0];

    tcp::listen(ip_addr, port, backlog, iotask,
                on_established, on_new_connection);
}

fn on_established(_kill_ch: KillChan) {
    io::println("running at 127.0.0.1:1337");
}

fn on_new_connection(conn: TcpNewConnection, kill_ch: KillChan) {
    do comm::listen |cont_ch| {
        // Spawn new child which doesn't propagate errors to parent.
        do task().unlinked().sched_mode(SingleThreaded).spawn {
            accept(conn, kill_ch, cont_ch);
        }
        // Wait `tcp::accept(conn)' complete.
        cont_ch.recv();
    }
}

fn accept(conn: TcpNewConnection, kill_ch: KillChan, cont_ch: ContChan) {
    match tcp::accept(conn) {
        Ok(socket) => {
            cont_ch.send(());
            encode(socket);
        }
        Err(err_data) => {
            kill_ch.send(Some(err_data));
            cont_ch.send(());
        }
    }
}

fn encode(socket: TcpSocket) {
    let socket = tcp::socket_buf(socket);
    let writer = Base64Writer::new(BASE64_STD, &socket);
    let mut buf = [0, ..1024];

    while !socket.eof() {
        let nread = socket.read(buf, buf.len());
        writer.write(buf.view(0, nread));
    }
    writer.close();
}
<commit_msg>examples: Fix base64-tcp-server.rs to compile<commit_after>extern mod std;
extern mod rfc4648;

use std::net::ip;
use std::net::tcp;
use std::uv_global_loop;

use core::io::{ReaderUtil, WriterUtil};
use core::task::{SingleThreaded, task};
use std::net::tcp::{TcpErrData, TcpNewConnection, TcpSocket};
use rfc4648::base64::{BASE64_STD, Base64Writer};

use comm = core::oldcomm;

type KillChan = comm::Chan<Option<TcpErrData>>;
type ContChan = comm::Chan<()>;

fn main() {
    let iotask = uv_global_loop::get();

    let addr = "127.0.0.1";
    let port = 1337;

    let backlog = 128;
    let ip_addr = ip::get_addr(addr, iotask);
    let ip_addr = copy result::unwrap(ip_addr)[0];

    tcp::listen(ip_addr, port, backlog, iotask,
                on_established, on_new_connection);
}

fn on_established(_kill_ch: KillChan) {
    io::println("running at 127.0.0.1:1337");
}

fn on_new_connection(conn: TcpNewConnection, kill_ch: KillChan) {
    do comm::listen |cont_ch| {
        // Spawn new child which doesn't propagate errors to parent.
        do task().unlinked().sched_mode(SingleThreaded).spawn {
            accept(conn, kill_ch, cont_ch);
        }
        // Wait `tcp::accept(conn)' complete.
        cont_ch.recv();
    }
}

fn accept(conn: TcpNewConnection, kill_ch: KillChan, cont_ch: ContChan) {
    match tcp::accept(conn) {
        Ok(socket) => {
            cont_ch.send(());
            encode(socket);
        }
        Err(err_data) => {
            kill_ch.send(Some(err_data));
            cont_ch.send(());
        }
    }
}

fn encode(socket: TcpSocket) {
    let socket = tcp::socket_buf(socket);
    let writer = Base64Writer::new(BASE64_STD, &socket);
    let mut buf = [0, ..1024];

    while !socket.eof() {
        let nread = socket.read(buf, buf.len());
        writer.write(buf.view(0, nread));
    }
    writer.close();
}
<|endoftext|>


<commit_before>
pub use winapi::shared::d3d9::*;
pub use winapi::shared::d3d9types::*;
pub use winapi::shared::minwindef::*;
pub use winapi::shared::windef::{HWND, RECT};
pub use winapi::shared::winerror::{E_FAIL, S_OK};
pub use winapi::um::winnt::{HRESULT, LPCWSTR};
use fnv::FnvHashMap;

use util;
use d3dx;
use std;
use std::ptr::null_mut;
use shared_dx9::util::*;
use device_state::*;
use global_state::{GLOBAL_STATE, GLOBAL_STATE_LOCK, LoadedModState};
use types::interop;
use types::native_mod;

pub enum AsyncLoadState {
    NotStarted = 51,
    Pending,
    InProgress,
    Complete,
}

pub unsafe fn clear_loaded_mods(device: *mut IDirect3DDevice9) {
    let lock = GLOBAL_STATE_LOCK.lock();
    if let Err(_e) = lock {
        write_log_file("failed to lock global state to clear mod data");
        return;
    }

    // get device ref count prior to adding everything
    (*device).AddRef();
    let pre_rc = (*device).Release();

    let mods = GLOBAL_STATE.loaded_mods.take();
    let mut cnt = 0;
    mods.map(|mods| {
        for (_key, modvec) in mods.mods.into_iter() {
            for nmd in modvec {
                cnt += 1;
                if nmd.vb != null_mut() {
                    (*nmd.vb).Release();
                }
                if nmd.ib != null_mut() {
                    (*nmd.ib).Release();
                }
                if nmd.decl != null_mut() {
                    (*nmd.decl).Release();
                }

                for tex in nmd.textures.iter() {
                    if *tex != null_mut() {
                        let tex = *tex as *mut IDirect3DBaseTexture9;
                        (*tex).Release();
                    }
                }
            }
        }
    });
    GLOBAL_STATE.loaded_mods = None;

    (*device).AddRef();
    let post_rc = (*device).Release();
    let diff = pre_rc - post_rc;
    if (dev_state().d3d_resource_count as i64 - diff as i64) < 0 {
        write_log_file(&format!(
            "DOH resource count would go below zero (curr: {}, removed {}),",
            dev_state().d3d_resource_count, diff
        ));
    } else {
        dev_state().d3d_resource_count -= diff;
    }

    write_log_file(&format!("unloaded {} mods", cnt));
}

pub unsafe fn setup_mod_data(device: *mut IDirect3DDevice9, callbacks: interop::ManagedCallbacks) {
    clear_loaded_mods(device);

    let mod_count = (callbacks.GetModCount)();
    if mod_count <= 0 {
        return;
    }

    if device == null_mut() {
        return;
    }

    let lock = GLOBAL_STATE_LOCK.lock();
    if let Err(_e) = lock {
        write_log_file("failed to lock global state to setup mod data");
        return;
    }

    // need d3dx for textures
    GLOBAL_STATE.device = Some(device);
    if GLOBAL_STATE.d3dx_fn.is_none() {
        GLOBAL_STATE.d3dx_fn = d3dx::load_lib(&GLOBAL_STATE.mm_root)
            .map_err(|e| {
                write_log_file(&format!(
                    "failed to load d3dx: texture snapping not available: {:?}",
                    e
                ));
                e
            })
            .ok();
    }

    // get device ref count prior to adding everything
    (*device).AddRef();
    let pre_rc = (*device).Release();

    let mut loaded_mods: FnvHashMap<u32, Vec<native_mod::NativeModData>> =
        FnvHashMap::with_capacity_and_hasher((mod_count * 10) as usize, Default::default());
    // map of modname -> mod key, which can then be indexed into loaded mods.  used by
    // child mods to find the parent.
    let mut mods_by_name: FnvHashMap<String,u32> =
        FnvHashMap::with_capacity_and_hasher((mod_count * 10) as usize, Default::default());

    // temporary list of all mods that have been referenced as a parent by something
    use std::collections::HashSet;
    let mut all_parent_mods:HashSet<String> = HashSet::new();
    for midx in 0..mod_count {
        let mdat: *mut interop::ModData = (callbacks.GetModData)(midx);

        if mdat == null_mut() {
            write_log_file(&format!("null mod at index {}", midx));
            continue;
        }
        let mod_name = util::from_wide_str(&(*mdat).modName).unwrap_or_else(|_e| "".to_owned());
        let mod_name = mod_name.trim().to_owned();
        let parent_mods = util::from_wide_str(&(*mdat).parentModName).unwrap_or_else(|_e| "".to_owned());
        let parent_mods = parent_mods.trim();
        // check for an "or" list of parents
        let parent_mods:Vec<String> = native_mod::NativeModData::split_parent_string(&parent_mods);
        let (prims,verts) = if (*mdat).numbers.mod_type == (interop::ModType::Deletion as i32) {
            ((*mdat).numbers.ref_prim_count as u32,(*mdat).numbers.ref_vert_count as u32)
        } else {
            ((*mdat).numbers.prim_count as u32, (*mdat).numbers.vert_count as u32)
        };
        write_log_file(&format!("==> Initializing mod: name '{}', parents '{:?}', type {}, prims {}, verts {}",
            mod_name, parent_mods, (*mdat).numbers.mod_type, prims, verts));
        let mod_type = (*mdat).numbers.mod_type;
        if mod_type != interop::ModType::GPUReplacement as i32
            && mod_type != interop::ModType::GPUAdditive as i32
            && mod_type != interop::ModType::Deletion as i32
        {
            write_log_file(&format!(
                "Unsupported mod type: {}",
                (*mdat).numbers.mod_type
            ));
            continue;
        }

        // names are case insensitive
        let mod_name = mod_name.to_lowercase();
        let mut native_mod_data = native_mod::NativeModData {
            mod_data: (*mdat),
            vb_data: null_mut(),
            ib_data: null_mut(),
            decl_data: null_mut(),
            vb: null_mut(),
            ib: null_mut(),
            decl: null_mut(),
            textures: [null_mut(); 4],
            is_parent: false,
            parent_mod_names: parent_mods,
            last_frame_render: 0,
            name: mod_name.to_owned(),
        };

        // get mod key
        let mod_key = native_mod::NativeModData::mod_key(
            native_mod_data.mod_data.numbers.ref_vert_count as u32,
            native_mod_data.mod_data.numbers.ref_prim_count as u32,
        );

        // wrangle names
        if native_mod_data.parent_mod_names.len() > 0 {
            // lowercase these and make parent mod entries for them
            native_mod_data.parent_mod_names = native_mod_data.parent_mod_names.iter().map(|parent_mod| {
                let plwr = parent_mod.to_lowercase();
                all_parent_mods.insert(plwr.clone());
                plwr
            }).collect();
        }
        if !mod_name.is_empty() {
            if mods_by_name.contains_key(&mod_name) {
                write_log_file(&format!("error, duplicate mod name: ignoring dup: {}", mod_name));
            } else {
                mods_by_name.insert(mod_name, mod_key);
            }
        }
        //write_log_file(&format!("mod: {}, parents: {:?}", native_mod_data.name, native_mod_data.parent_mod_names));

        if (*mdat).numbers.mod_type == (interop::ModType::Deletion as i32) {
            loaded_mods.entry(mod_key).or_insert(vec![]).push(native_mod_data);
            // thats all we need to do for these.
            continue;
        }

        let decl_size = (*mdat).numbers.decl_size_bytes;
        // vertex declaration construct copies the vec bytes, so just keep a temp vector reference for the data
        let (decl_data, _decl_vec) = if decl_size > 0 {
            let mut decl_vec: Vec<u8> = Vec::with_capacity(decl_size as usize);
            let decl_data: *mut u8 = decl_vec.as_mut_ptr();
            (decl_data, Some(decl_vec))
        } else {
            (null_mut(), None)
        };

        let vb_size = (*mdat).numbers.prim_count * 3 * (*mdat).numbers.vert_size_bytes;
        let mut vb_data: *mut u8 = null_mut();

        // index buffers not currently supported
        let ib_size = 0; //mdat->indexCount * mdat->indexElemSizeBytes;
        let ib_data: *mut u8 = null_mut();

        // create vb
        let mut out_vb: *mut IDirect3DVertexBuffer9 = null_mut();
        let out_vb: *mut *mut IDirect3DVertexBuffer9 = &mut out_vb;
        let hr = (*device).CreateVertexBuffer(
            vb_size as UINT,
            D3DUSAGE_WRITEONLY,
            0,
            D3DPOOL_MANAGED,
            out_vb,
            null_mut(),
        );
        if hr != 0 {
            write_log_file(&format!(
                "failed to create vertex buffer for mod {}: HR {:x}",
                midx, hr
            ));
            return;
        }

        let vb = *out_vb;

        // lock vb to obtain write buffer
        let hr = (*vb).Lock(0, 0, std::mem::transmute(&mut vb_data), 0);
        if hr != 0 {
            write_log_file(&format!("failed to lock vertex buffer: {:x}", hr));
            return;
        }

        // fill all data buckets with managed code
        let ret = (callbacks.FillModData)(
            midx, decl_data, decl_size, vb_data, vb_size, ib_data, ib_size,
        );

        let hr = (*vb).Unlock();
        if hr != 0 {
            write_log_file(&format!("failed to unlock vertex buffer: {:x}", hr));
            (*vb).Release();
            return;
        }

        if ret != 0 {
            write_log_file(&format!("failed to fill mod data: {}", ret));
            (*vb).Release();
            return;
        }

        native_mod_data.vb = vb;

        // create vertex declaration
        let mut out_decl: *mut IDirect3DVertexDeclaration9 = null_mut();
        let pp_out_decl: *mut *mut IDirect3DVertexDeclaration9 = &mut out_decl;
        let hr =
            (*device).CreateVertexDeclaration(decl_data as *const D3DVERTEXELEMENT9, pp_out_decl);
        if hr != 0 {
            write_log_file(&format!("failed to create vertex declaration: {}", hr));
            (*vb).Release();
            return;
        }
        if out_decl == null_mut() {
            write_log_file("vertex declaration is null");
            (*vb).Release();
            return;
        }
        native_mod_data.decl = out_decl;

        let load_tex = |texpath:&[u16]| {
            let tex = util::from_wide_str(texpath).unwrap_or_else(|e| {
                write_log_file(&format!("failed to load texture: {:?}", e));
                "".to_owned()
            });
            let tex = tex.trim();

            let mut outtex = null_mut();
            if !tex.is_empty() {
                outtex = d3dx::load_texture(texpath.as_ptr()).map_err(|e| {
                    write_log_file(&format!("failed to load texture: {:?}", e));
                }).unwrap_or(null_mut());
                write_log_file(&format!("Loaded tex: {:?} {:x}", tex, outtex as u64));
            }
            outtex
        };
        native_mod_data.textures[0] = load_tex(&(*mdat).texPath0);
        native_mod_data.textures[1] = load_tex(&(*mdat).texPath1);
        native_mod_data.textures[2] = load_tex(&(*mdat).texPath2);
        native_mod_data.textures[3] = load_tex(&(*mdat).texPath3);

        loaded_mods.entry(mod_key).or_insert(vec![]).push(native_mod_data);

        write_log_file(&format!(
            "allocated vb/decl for mod data {}: {:?}",
            midx,
            (*mdat).numbers
        ));
    }

    // mark all parent mods as such, and also warn about any parents that didn't load
    let mut resolved_parents = 0;
    let num_parents = all_parent_mods.len();
    for parent in all_parent_mods {
        match mods_by_name.get(&parent) {
            None => write_log_file(&format!("error, mod referenced as parent failed to load: {}", parent)),
            Some(modkey) => {
                match loaded_mods.get_mut(modkey) {
                    None => write_log_file(&format!("error, mod referenced as parent was found, but no loaded: {}", parent)),
                    Some(nmdatavec) => {
                        for nmdata in nmdatavec.iter_mut() {
                            if nmdata.name == parent {
                                resolved_parents += 1;
                                nmdata.is_parent = true
                            }
                        }
                    }
                }
            }
        }
    }
    write_log_file(&format!("resolved {} of {} parent mods", resolved_parents, num_parents));

    // verify that all multi-mod cases have parent mod names set.
    for nmodv in loaded_mods.values() {
        if nmodv.len() <= 1 {
            continue
        }
        // in a multimod case, all mods must have parents, and the parents have to be different
        // names.
        let mut parent_names: HashSet<String> = HashSet::new();
        for nmod in nmodv.iter() {
            if nmod.parent_mod_names.is_empty() {
                write_log_file(&format!("Note: mod '{}' ({} prims,{} verts) has no parent \
mod but it overlaps with another mod.  Use the variant key to select this.",
                nmod.name, nmod.mod_data.numbers.prim_count, nmod.mod_data.numbers.vert_count));
            } else {
                nmod.parent_mod_names.iter().for_each(|parent_mod_name| {
                    parent_names.insert(parent_mod_name.to_string());
                });
            }

        }
        if nmodv.len() != parent_names.len() {
            write_log_file("Variants found:");
            for nmod in nmodv.iter() {
                write_log_file(&format!("  mod: {}, prims: {}, verts: {}, parents: {:?}",
                nmod.name, nmod.mod_data.numbers.prim_count, nmod.mod_data.numbers.vert_count,
                nmod.parent_mod_names));
            }
        }
    }

    // get new ref count
    (*device).AddRef();
    let post_rc = (*device).Release();
    let diff = post_rc - pre_rc;
    (*DEVICE_STATE).d3d_resource_count += diff;
    write_log_file(&format!(
        "mod loading added {} to device {:x} ref count, new count: {}",
        diff, device as u64, (*DEVICE_STATE).d3d_resource_count
    ));

    GLOBAL_STATE.loaded_mods = Some(LoadedModState {
        mods: loaded_mods,
        mods_by_name: mods_by_name,
        selected_variant: global_state::new_fnv_map(16),
    } );
}
<commit_msg>Generate a name for deletion mods<commit_after>
pub use winapi::shared::d3d9::*;
pub use winapi::shared::d3d9types::*;
pub use winapi::shared::minwindef::*;
pub use winapi::shared::windef::{HWND, RECT};
pub use winapi::shared::winerror::{E_FAIL, S_OK};
pub use winapi::um::winnt::{HRESULT, LPCWSTR};
use fnv::FnvHashMap;

use util;
use d3dx;
use std;
use std::ptr::null_mut;
use shared_dx9::util::*;
use device_state::*;
use global_state::{GLOBAL_STATE, GLOBAL_STATE_LOCK, LoadedModState};
use types::interop;
use types::native_mod;

pub enum AsyncLoadState {
    NotStarted = 51,
    Pending,
    InProgress,
    Complete,
}

pub unsafe fn clear_loaded_mods(device: *mut IDirect3DDevice9) {
    let lock = GLOBAL_STATE_LOCK.lock();
    if let Err(_e) = lock {
        write_log_file("failed to lock global state to clear mod data");
        return;
    }

    // get device ref count prior to adding everything
    (*device).AddRef();
    let pre_rc = (*device).Release();

    let mods = GLOBAL_STATE.loaded_mods.take();
    let mut cnt = 0;
    mods.map(|mods| {
        for (_key, modvec) in mods.mods.into_iter() {
            for nmd in modvec {
                cnt += 1;
                if nmd.vb != null_mut() {
                    (*nmd.vb).Release();
                }
                if nmd.ib != null_mut() {
                    (*nmd.ib).Release();
                }
                if nmd.decl != null_mut() {
                    (*nmd.decl).Release();
                }

                for tex in nmd.textures.iter() {
                    if *tex != null_mut() {
                        let tex = *tex as *mut IDirect3DBaseTexture9;
                        (*tex).Release();
                    }
                }
            }
        }
    });
    GLOBAL_STATE.loaded_mods = None;

    (*device).AddRef();
    let post_rc = (*device).Release();
    let diff = pre_rc - post_rc;
    if (dev_state().d3d_resource_count as i64 - diff as i64) < 0 {
        write_log_file(&format!(
            "DOH resource count would go below zero (curr: {}, removed {}),",
            dev_state().d3d_resource_count, diff
        ));
    } else {
        dev_state().d3d_resource_count -= diff;
    }

    write_log_file(&format!("unloaded {} mods", cnt));
}

pub unsafe fn setup_mod_data(device: *mut IDirect3DDevice9, callbacks: interop::ManagedCallbacks) {
    clear_loaded_mods(device);

    let mod_count = (callbacks.GetModCount)();
    if mod_count <= 0 {
        return;
    }

    if device == null_mut() {
        return;
    }

    let lock = GLOBAL_STATE_LOCK.lock();
    if let Err(_e) = lock {
        write_log_file("failed to lock global state to setup mod data");
        return;
    }

    let ml_start = std::time::SystemTime::now();

    // need d3dx for textures
    GLOBAL_STATE.device = Some(device);
    if GLOBAL_STATE.d3dx_fn.is_none() {
        GLOBAL_STATE.d3dx_fn = d3dx::load_lib(&GLOBAL_STATE.mm_root)
            .map_err(|e| {
                write_log_file(&format!(
                    "failed to load d3dx: texture snapping not available: {:?}",
                    e
                ));
                e
            })
            .ok();
    }

    // get device ref count prior to adding everything
    (*device).AddRef();
    let pre_rc = (*device).Release();

    let mut loaded_mods: FnvHashMap<u32, Vec<native_mod::NativeModData>> =
        FnvHashMap::with_capacity_and_hasher((mod_count * 10) as usize, Default::default());
    // map of modname -> mod key, which can then be indexed into loaded mods.  used by
    // child mods to find the parent.
    let mut mods_by_name: FnvHashMap<String,u32> =
        FnvHashMap::with_capacity_and_hasher((mod_count * 10) as usize, Default::default());

    // temporary list of all mods that have been referenced as a parent by something
    use std::collections::HashSet;
    let mut all_parent_mods:HashSet<String> = HashSet::new();
    for midx in 0..mod_count {
        let mdat: *mut interop::ModData = (callbacks.GetModData)(midx);

        if mdat == null_mut() {
            write_log_file(&format!("null mod at index {}", midx));
            continue;
        }
        let mod_name = util::from_wide_str(&(*mdat).modName).unwrap_or_else(|_e| "".to_owned());
        let mod_name = mod_name.trim().to_owned();
        let parent_mods = util::from_wide_str(&(*mdat).parentModName).unwrap_or_else(|_e| "".to_owned());
        let parent_mods = parent_mods.trim();
        // check for an "or" list of parents
        let parent_mods:Vec<String> = native_mod::NativeModData::split_parent_string(&parent_mods);
        let (prims,verts) = if (*mdat).numbers.mod_type == (interop::ModType::Deletion as i32) {
            ((*mdat).numbers.ref_prim_count as u32,(*mdat).numbers.ref_vert_count as u32)
        } else {
            ((*mdat).numbers.prim_count as u32, (*mdat).numbers.vert_count as u32)
        };
        write_log_file(&format!("==> Initializing mod: name '{}', parents '{:?}', type {}, prims {}, verts {}",
            mod_name, parent_mods, (*mdat).numbers.mod_type, prims, verts));
        let mod_type = (*mdat).numbers.mod_type;
        if mod_type != interop::ModType::GPUReplacement as i32
            && mod_type != interop::ModType::GPUAdditive as i32
            && mod_type != interop::ModType::Deletion as i32
        {
            write_log_file(&format!(
                "Unsupported mod type: {}",
                (*mdat).numbers.mod_type
            ));
            continue;
        }

        // names are case insensitive
        let mod_name = mod_name.to_lowercase();
        let mut native_mod_data = native_mod::NativeModData {
            mod_data: (*mdat),
            vb_data: null_mut(),
            ib_data: null_mut(),
            decl_data: null_mut(),
            vb: null_mut(),
            ib: null_mut(),
            decl: null_mut(),
            textures: [null_mut(); 4],
            is_parent: false,
            parent_mod_names: parent_mods,
            last_frame_render: 0,
            name: mod_name.to_owned(),
        };

        // get mod key
        let mod_key = native_mod::NativeModData::mod_key(
            native_mod_data.mod_data.numbers.ref_vert_count as u32,
            native_mod_data.mod_data.numbers.ref_prim_count as u32,
        );

        // wrangle names
        if native_mod_data.parent_mod_names.len() > 0 {
            // lowercase these and make parent mod entries for them
            native_mod_data.parent_mod_names = native_mod_data.parent_mod_names.iter().map(|parent_mod| {
                let plwr = parent_mod.to_lowercase();
                all_parent_mods.insert(plwr.clone());
                plwr
            }).collect();
        }

        let is_deletion_mod = (*mdat).numbers.mod_type == (interop::ModType::Deletion as i32);
        if !mod_name.is_empty() {
            // if it is a deletion mod, then there may be multiple mods with the same name
            // (one for each prim/vert combo that is deleted).  construct a new name that includes
            // the prim and vert count
            let mod_name = if is_deletion_mod {
                let new_mod_name = format!("{}_{}_{}", mod_name,
                    native_mod_data.mod_data.numbers.ref_prim_count,
                    native_mod_data.mod_data.numbers.ref_vert_count);
                write_log_file(&format!("using mod name {} for deletion mod: {}", new_mod_name, mod_name));
                new_mod_name
            } else {
                mod_name
            };

            if mods_by_name.contains_key(&mod_name) {
                write_log_file(&format!("error, duplicate mod name: ignoring dup: {}", mod_name));
            } else {
                mods_by_name.insert(mod_name, mod_key);
            }
        }
        //write_log_file(&format!("mod: {}, parents: {:?}", native_mod_data.name, native_mod_data.parent_mod_names));

        if is_deletion_mod {
            loaded_mods.entry(mod_key).or_insert(vec![]).push(native_mod_data);
            // thats all we need to do for these.
            continue;
        }

        let decl_size = (*mdat).numbers.decl_size_bytes;
        // vertex declaration construct copies the vec bytes, so just keep a temp vector reference for the data
        let (decl_data, _decl_vec) = if decl_size > 0 {
            let mut decl_vec: Vec<u8> = Vec::with_capacity(decl_size as usize);
            let decl_data: *mut u8 = decl_vec.as_mut_ptr();
            (decl_data, Some(decl_vec))
        } else {
            (null_mut(), None)
        };

        let vb_size = (*mdat).numbers.prim_count * 3 * (*mdat).numbers.vert_size_bytes;
        let mut vb_data: *mut u8 = null_mut();

        // index buffers not currently supported
        let ib_size = 0; //mdat->indexCount * mdat->indexElemSizeBytes;
        let ib_data: *mut u8 = null_mut();

        // create vb
        let mut out_vb: *mut IDirect3DVertexBuffer9 = null_mut();
        let out_vb: *mut *mut IDirect3DVertexBuffer9 = &mut out_vb;
        let hr = (*device).CreateVertexBuffer(
            vb_size as UINT,
            D3DUSAGE_WRITEONLY,
            0,
            D3DPOOL_MANAGED,
            out_vb,
            null_mut(),
        );
        if hr != 0 {
            write_log_file(&format!(
                "failed to create vertex buffer for mod {}: HR {:x}",
                midx, hr
            ));
            return;
        }

        let vb = *out_vb;

        // lock vb to obtain write buffer
        let hr = (*vb).Lock(0, 0, std::mem::transmute(&mut vb_data), 0);
        if hr != 0 {
            write_log_file(&format!("failed to lock vertex buffer: {:x}", hr));
            return;
        }

        // fill all data buckets with managed code
        let ret = (callbacks.FillModData)(
            midx, decl_data, decl_size, vb_data, vb_size, ib_data, ib_size,
        );

        let hr = (*vb).Unlock();
        if hr != 0 {
            write_log_file(&format!("failed to unlock vertex buffer: {:x}", hr));
            (*vb).Release();
            return;
        }

        if ret != 0 {
            write_log_file(&format!("failed to fill mod data: {}", ret));
            (*vb).Release();
            return;
        }

        native_mod_data.vb = vb;

        // create vertex declaration
        let mut out_decl: *mut IDirect3DVertexDeclaration9 = null_mut();
        let pp_out_decl: *mut *mut IDirect3DVertexDeclaration9 = &mut out_decl;
        let hr =
            (*device).CreateVertexDeclaration(decl_data as *const D3DVERTEXELEMENT9, pp_out_decl);
        if hr != 0 {
            write_log_file(&format!("failed to create vertex declaration: {}", hr));
            (*vb).Release();
            return;
        }
        if out_decl == null_mut() {
            write_log_file("vertex declaration is null");
            (*vb).Release();
            return;
        }
        native_mod_data.decl = out_decl;

        let load_tex = |texpath:&[u16]| {
            let tex = util::from_wide_str(texpath).unwrap_or_else(|e| {
                write_log_file(&format!("failed to load texture: {:?}", e));
                "".to_owned()
            });
            let tex = tex.trim();

            let mut outtex = null_mut();
            if !tex.is_empty() {
                outtex = d3dx::load_texture(texpath.as_ptr()).map_err(|e| {
                    write_log_file(&format!("failed to load texture: {:?}", e));
                }).unwrap_or(null_mut());
                write_log_file(&format!("Loaded tex: {:?} {:x}", tex, outtex as u64));
            }
            outtex
        };
        native_mod_data.textures[0] = load_tex(&(*mdat).texPath0);
        native_mod_data.textures[1] = load_tex(&(*mdat).texPath1);
        native_mod_data.textures[2] = load_tex(&(*mdat).texPath2);
        native_mod_data.textures[3] = load_tex(&(*mdat).texPath3);

        loaded_mods.entry(mod_key).or_insert(vec![]).push(native_mod_data);

        write_log_file(&format!(
            "allocated vb/decl for mod data {}: {:?}",
            midx,
            (*mdat).numbers
        ));
    }

    // mark all parent mods as such, and also warn about any parents that didn't load
    let mut resolved_parents = 0;
    let num_parents = all_parent_mods.len();
    for parent in all_parent_mods {
        match mods_by_name.get(&parent) {
            None => write_log_file(&format!("error, mod referenced as parent failed to load: {}", parent)),
            Some(modkey) => {
                match loaded_mods.get_mut(modkey) {
                    None => write_log_file(&format!("error, mod referenced as parent was found, but no loaded: {}", parent)),
                    Some(nmdatavec) => {
                        for nmdata in nmdatavec.iter_mut() {
                            if nmdata.name == parent {
                                resolved_parents += 1;
                                nmdata.is_parent = true
                            }
                        }
                    }
                }
            }
        }
    }
    write_log_file(&format!("resolved {} of {} parent mods", resolved_parents, num_parents));

    // verify that all multi-mod cases have parent mod names set.
    for nmodv in loaded_mods.values() {
        if nmodv.len() <= 1 {
            continue
        }
        // in a multimod case, all mods must have parents, and the parents have to be different
        // names.
        let mut parent_names: HashSet<String> = HashSet::new();
        for nmod in nmodv.iter() {
            if nmod.parent_mod_names.is_empty() {
                write_log_file(&format!("Note: mod '{}' ({} prims,{} verts) has no parent \
mod but it overlaps with another mod.  Use the variant key to select this.",
                nmod.name, nmod.mod_data.numbers.prim_count, nmod.mod_data.numbers.vert_count));
            } else {
                nmod.parent_mod_names.iter().for_each(|parent_mod_name| {
                    parent_names.insert(parent_mod_name.to_string());
                });
            }

        }
        if nmodv.len() != parent_names.len() {
            write_log_file("Variants found:");
            for nmod in nmodv.iter() {
                write_log_file(&format!("  mod: {}, prims: {}, verts: {}, parents: {:?}",
                nmod.name, nmod.mod_data.numbers.prim_count, nmod.mod_data.numbers.vert_count,
                nmod.parent_mod_names));
            }
        }
    }

    // get new ref count
    (*device).AddRef();
    let post_rc = (*device).Release();
    let diff = post_rc - pre_rc;
    (*DEVICE_STATE).d3d_resource_count += diff;
    write_log_file(&format!(
        "mod loading added {} to device {:x} ref count, new count: {}",
        diff, device as u64, (*DEVICE_STATE).d3d_resource_count
    ));

    let now = std::time::SystemTime::now();
    let elapsed = now.duration_since(ml_start);
    if let Ok(elapsed) = elapsed {
        write_log_file(&format!("mod load complete in {}ms", elapsed.as_millis()));
    };

    GLOBAL_STATE.loaded_mods = Some(LoadedModState {
        mods: loaded_mods,
        mods_by_name: mods_by_name,
        selected_variant: global_state::new_fnv_map(16),
    } );
}
<|endoftext|>


<commit_before>use mockito::{self, Matcher};
use providers::{azure, MetadataProvider};

#[test]
fn test_boot_checkin() {
    let fab_version = "/?comp=versions";
    let ver_body = r#"<?xml version="1.0" encoding="utf-8"?>
<Versions>
  <Preferred>
    <Version>2015-04-05</Version>
  </Preferred>
  <Supported>
    <Version>2015-04-05</Version>
    <Version>2012-11-30</Version>
    <Version>2012-09-15</Version>
    <Version>2012-05-15</Version>
    <Version>2011-12-31</Version>
    <Version>2011-10-15</Version>
    <Version>2011-08-31</Version>
    <Version>2011-04-07</Version>
    <Version>2010-12-15</Version>
    <Version>2010-28-10</Version>
  </Supported>
</Versions>"#;
    let m_version = mockito::mock("GET", fab_version)
        .with_body(ver_body)
        .with_status(200)
        .create();

    let fab_goalstate = "/machine/?comp=goalstate";
    let gs_body = r#"<?xml version="1.0" encoding="utf-8"?>
<GoalState xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="goalstate10.xsd">
  <Version>2012-11-30</Version>
  <Incarnation>1</Incarnation>
  <Machine>
    <ExpectedState>Started</ExpectedState>
    <StopRolesDeadlineHint>300000</StopRolesDeadlineHint>
    <LBProbePorts>
      <Port>16001</Port>
    </LBProbePorts>
    <ExpectHealthReport>FALSE</ExpectHealthReport>
  </Machine>
  <Container>
    <ContainerId>a511aa6d-29e7-4f53-8788-55655dfe848f</ContainerId>
    <RoleInstanceList>
      <RoleInstance>
        <InstanceId>f6cd1d7ef1644557b9059345e5ba890c.lars-test-1</InstanceId>
        <State>Started</State>
        <Configuration>
          <HostingEnvironmentConfig>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=config&type=hostingEnvironmentConfig&incarnation=1</HostingEnvironmentConfig>
          <SharedConfig>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=config&type=sharedConfig&incarnation=1</SharedConfig>
          <ExtensionsConfig>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=config&type=extensionsConfig&incarnation=1</ExtensionsConfig>
          <FullConfig>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=config&type=fullConfig&incarnation=1</FullConfig>
          <Certificates>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=certificates&incarnation=1</Certificates>
          <ConfigName>f6cd1d7ef1644557b9059345e5ba890c.0.f6cd1d7ef1644557b9059345e5ba890c.0.lars-test-1.1.xml</ConfigName>
        </Configuration>
      </RoleInstance>
    </RoleInstanceList>
  </Container>
</GoalState>
"#;
    let m_goalstate = mockito::mock("GET", fab_goalstate)
        .with_body(gs_body)
        .with_status(200)
        .create();

    let fab_health = "/machine/?comp=health";
    let m_health = mockito::mock("POST", fab_health)
        .match_header("content-type", Matcher::Regex("text/xml".to_string()))
        .match_header("x-ms-version", Matcher::Regex("2012-11-30".to_string()))
        .match_body(Matcher::Regex("<State>Ready</State>".to_string()))
        .with_status(200)
        .create();

    let provider = azure::Azure::try_new();
    let r = provider.unwrap().boot_checkin();

    m_version.assert();
    m_goalstate.assert();
    m_health.assert();
    r.unwrap();
}
<commit_msg>tests: refactor azure mocks<commit_after>use mockito::{self, Matcher};
use providers::{azure, MetadataProvider};

fn mock_fab_version() -> mockito::Mock {
    let fab_version = "/?comp=versions";
    let ver_body = r#"<?xml version="1.0" encoding="utf-8"?>
<Versions>
  <Preferred>
    <Version>2015-04-05</Version>
  </Preferred>
  <Supported>
    <Version>2015-04-05</Version>
    <Version>2012-11-30</Version>
    <Version>2012-09-15</Version>
    <Version>2012-05-15</Version>
    <Version>2011-12-31</Version>
    <Version>2011-10-15</Version>
    <Version>2011-08-31</Version>
    <Version>2011-04-07</Version>
    <Version>2010-12-15</Version>
    <Version>2010-28-10</Version>
  </Supported>
</Versions>"#;

    mockito::mock("GET", fab_version)
        .with_body(ver_body)
        .with_status(200)
        .create()
}

fn mock_goalstate() -> mockito::Mock {
    let fab_goalstate = "/machine/?comp=goalstate";
    let gs_body = r#"<?xml version="1.0" encoding="utf-8"?>
<GoalState xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="goalstate10.xsd">
  <Version>2012-11-30</Version>
  <Incarnation>1</Incarnation>
  <Machine>
    <ExpectedState>Started</ExpectedState>
    <StopRolesDeadlineHint>300000</StopRolesDeadlineHint>
    <LBProbePorts>
      <Port>16001</Port>
    </LBProbePorts>
    <ExpectHealthReport>FALSE</ExpectHealthReport>
  </Machine>
  <Container>
    <ContainerId>a511aa6d-29e7-4f53-8788-55655dfe848f</ContainerId>
    <RoleInstanceList>
      <RoleInstance>
        <InstanceId>f6cd1d7ef1644557b9059345e5ba890c.lars-test-1</InstanceId>
        <State>Started</State>
        <Configuration>
          <HostingEnvironmentConfig>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=config&type=hostingEnvironmentConfig&incarnation=1</HostingEnvironmentConfig>
          <SharedConfig>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=config&type=sharedConfig&incarnation=1</SharedConfig>
          <ExtensionsConfig>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=config&type=extensionsConfig&incarnation=1</ExtensionsConfig>
          <FullConfig>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=config&type=fullConfig&incarnation=1</FullConfig>
          <Certificates>http://100.115.176.3:80/machine/a511aa6d-29e7-4f53-8788-55655dfe848f/f6cd1d7ef1644557b9059345e5ba890c.lars%2Dtest%2D1?comp=certificates&incarnation=1</Certificates>
          <ConfigName>f6cd1d7ef1644557b9059345e5ba890c.0.f6cd1d7ef1644557b9059345e5ba890c.0.lars-test-1.1.xml</ConfigName>
        </Configuration>
      </RoleInstance>
    </RoleInstanceList>
  </Container>
</GoalState>
"#;

    mockito::mock("GET", fab_goalstate)
        .with_body(gs_body)
        .with_status(200)
        .create()
}

#[test]
fn test_boot_checkin() {
    let m_version = mock_fab_version();
    let m_goalstate = mock_goalstate();

    let fab_health = "/machine/?comp=health";
    let m_health = mockito::mock("POST", fab_health)
        .match_header("content-type", Matcher::Regex("text/xml".to_string()))
        .match_header("x-ms-version", Matcher::Regex("2012-11-30".to_string()))
        .match_body(Matcher::Regex("<State>Ready</State>".to_string()))
        .with_status(200)
        .create();

    let provider = azure::Azure::try_new();
    let r = provider.unwrap().boot_checkin();

    m_version.assert();
    m_goalstate.assert();
    m_health.assert();
    r.unwrap();
}
<|endoftext|>


<commit_before>use rocket::request::{FromForm, FormItems};

#[derive(Debug)]
pub struct StatementStructResult {
    pub sql: String,
}
pub struct WhereStructResult {
    pub sql: String,
    pub values: Vec<String>,
}

// My Results
type QueryOpResult = Result<&'static str, String>;
type StatementResult = Result<StatementStructResult, String>;
type WhereResult = Result<WhereStructResult, String>;

// TODO: Move there later
#[derive(Debug)]
pub struct Params {
    pub k: String,
    pub v: String,
}
// implement QueryString
#[derive(Debug)]
pub struct QueryString {
    pub query: Vec<Params>,
}

impl<'f> FromForm<'f> for QueryString {
    type Error = ();

    fn from_form(items: &mut FormItems<'f>, _: bool) -> Result<QueryString, ()> {
        let mut qs: QueryString = QueryString { query: Vec::new() };
        for (k, v) in items {
            qs.query.push(Params {
                k: k.to_string(),
                v: v.url_decode().unwrap(),
            });
        }
        Ok(qs)
    }
}

pub fn query_operator(qop: &str) -> QueryOpResult {
    match &qop[..] {
        "$eq" => Ok("="),
        "$ne" => Ok("!="),
        "$gt" => Ok(">"),
        "$lt" => Ok("<"),
        "$gte" => Ok(">="),
        "$lte" => Ok("<="),
        "$in" => Ok("IN"),
        "$nin" => Ok("NOT IN"),
        "$notnull" => Ok("IS NOT NULL"),
        "$null" => Ok("IS NULL"),
        _ => Err(format!("operator {} not found", qop)),
    }
}

fn collect_params(v: &Vec<Params>, collect_values: bool) -> Result<Vec<String>, String> {
    let mut pid: i32 = 0;
    v.iter()
        .filter(|param| !param.k.starts_with("_"))
        .map(|param| {
            pid = pid + 1;
            let result = match param.v.contains(".") {
                true => {
                    let value_splited = param.v.split(".").collect::<Vec<&str>>();
                    let operator = match query_operator(value_splited[0]) {
                        Ok(op) => op,
                        Err(e) => return Err(e),
                    };
                    (operator, value_splited[1])
                }
                _ => ("=", param.v.as_str()),
            };
            if collect_values {
                Ok(format!("{}", result.1))
            } else {
                // biggest workaround ever!
                let commons = ["pk", "id"];
                if commons.iter().any(|c| param.k.contains(c)) {
                    Ok(format!("{}::text{}${}", param.k, result.0, pid))
                } else {
                    Ok(format!("{}{}${}", param.k, result.0, pid))
                }
            }
        })
        .collect()
}

// generic function to process statements: _select, _groupby, _order, _count
fn process_statement<F>(
    qs: &QueryString,
    stm: &str,
    stm_default: &str,
    stm_fmt: &str,
    stm_fn: F,
) -> StatementResult
where
    F: Fn(&str) -> String,
{
    let mut statement_syntax: String = String::from(stm_default);
    let statement_params = qs.query.iter().find(|p| p.k == String::from(stm));
    let columns = match statement_params {
        Some(param) => stm_fn(&param.v),
        _ => String::from(""),
    };
    if columns != "" {
        statement_syntax = format!("{}", String::from(stm_fmt).replace("{}", &columns));
    }
    Ok(StatementStructResult { sql: statement_syntax })
}

// Get QueryString and return chunck WHERE statement with values
pub fn ext_where(qs: &QueryString) -> WhereResult {
    let where_syntax: String;
    let ref iter_params = qs.query;
    let where_values = match collect_params(iter_params, true) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string()),
    };
    let where_fields = match collect_params(iter_params, false) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string()),
    };

    if where_fields.len() > 1 {
        where_syntax = format!("WHERE {}", where_fields.join(" AND "));
    } else {
        where_syntax = format!("WHERE {}", where_fields.join(" "));
    }

    Ok(WhereStructResult {
        sql: where_syntax,
        values: where_values,
    })
}

// Get QueryString and return SELECT statement
pub fn ext_select(qs: &QueryString) -> StatementResult {
    Ok(
        process_statement(qs, "_select", "SELECT * FROM", "SELECT {} FROM", |x| {
            String::from(x)
        }).unwrap(),
    )
}

// Get QueryString and return COUNT clause statement
pub fn ext_count(qs: &QueryString) -> StatementResult {
    // FIXME: Need handle errors
    Ok(
        process_statement(qs, "_count", "", "SELECT COUNT({}) FROM", |x| {
            let vs = x.split(",").collect::<Vec<&str>>();
            let result = if vs.len() > 1 { "" } else { x };
            String::from(result)
        }).unwrap(),
    )
}

// Get QueryString and return chunk ORDER BY statement
pub fn ext_order(qs: &QueryString) -> StatementResult {
    process_statement(qs, "_order", "", "ORDER BY {}", |x| {
        let vspl = &x.split(",").collect::<Vec<&str>>();
        let od: Vec<String> = vspl.iter()
            .map(|param| {
                let mut s = String::new();
                s.push_str(param); // omg
                if s.starts_with("-") {
                    s.remove(0);
                    s.push_str(" DESC")
                }
                format!("{}", s)
            })
            .collect();
        format!("{}", od.join(","))
    })
}

// Get QueryString and return chunk GROUP BY statement
pub fn ext_groupby(qs: &QueryString) -> StatementResult {
    Ok(
        process_statement(qs, "_groupby", "", "GROUP BY {}", |x| String::from(x)).unwrap(),
    )
}

#[cfg(test)]
mod tests {
    use postgresql::commands::*;

    #[test]
    fn get_opetators() {
        use std::collections::HashMap;

        let mut test_cases = HashMap::new();
        test_cases.insert("$eq", "=");
        test_cases.insert("$ne", "!=");
        test_cases.insert("$gt", ">");
        test_cases.insert("$gte", ">=");
        test_cases.insert("$lt", "<");
        test_cases.insert("$lte", "<=");
        test_cases.insert("$in", "IN");
        test_cases.insert("$nin", "NOT IN");
        test_cases.insert("$notnull", "IS NOT NULL");
        test_cases.insert("$null", "IS NULL");

        for (op, expected) in &test_cases {
            match query_operator(&op.to_string()) {
                Ok(x) => assert_eq!(expected.to_string(), x),
                Err(e) => assert_eq!("", e),
            }
        }
    }

    #[test]
    fn get_opetators_error() {
        let invalid = "!tn".to_string();
        match query_operator(&invalid) {
            Ok(_) => println!("no result"),
            Err(e) => assert_eq!(format!("operator {} not found", invalid), e),
        }
    }

    #[test]
    fn where_by_request_one_querystring() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1".to_string());
        assert_eq!(result.values, vec!["5".to_string()])
    }

    #[test]
    fn where_by_request_with_orderby() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });
        hm.push(Params {
            k: "_order".to_string(),
            v: "user_id".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1".to_string());
        assert_eq!(result.values, vec!["5".to_string()])
    }

    #[test]
    fn where_by_request_n_querystring() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_operators() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "$ne.5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id!=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_invalid_operators() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "$nt.5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_where(&qs) {
            Err(e) => assert_eq!(e, "operator $nt not found"),
            Ok(_) => println!("no result"),
        }
    }

    #[test]
    fn select_by_request_one_column() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT name FROM");
    }

    #[test]
    fn select_by_request_n_column() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT name,age FROM");
    }

    #[test]
    fn select_by_request_n_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT * FROM");
    }

    #[test]
    fn count_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "SELECT COUNT(name) FROM");
    }

    #[test]
    fn count_by_request_all_fields() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "*".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "SELECT COUNT(*) FROM");
    }

    #[test]
    fn count_by_request_two_fields() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_count(&qs) {
            Err(e) => assert_eq!(e, "could not use more than one column in count function"),
            Ok(s) => assert_eq!(s.sql, ""),
        }
    }

    #[test]
    fn count_by_request_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name")
    }

    #[test]
    fn order_by_request_desc() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "-name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name DESC")
    }

    #[test]
    fn order_by_request_empty_params() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request_without_params() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "name".to_string(),
            v: "toby".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_order(&qs) {
            Ok(result) => assert_eq!(result.sql, ""),
            Err(e) => assert_eq!("error on params", e),
        };
    }

    #[test]
    fn order_by_request_multiples_columns() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name,age")
    }

    #[test]
    fn order_by_request_multiples_columns_with_orders() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name,-age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name,age DESC")
    }

    #[test]
    fn groupby_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_groupby".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_groupby(&qs).unwrap();
        assert_eq!(result.sql, "GROUP BY name")
    }

    #[test]
    fn groupby_by_request_empty_param() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: String::from("_groupby"),
            v: String::from(""),
        });

        let qs = QueryString { query: hm };
        let result = ext_groupby(&qs).unwrap();
        assert_eq!(result.sql, "")
    }
}
<commit_msg>Fix tests with ::text flag<commit_after>use rocket::request::{FromForm, FormItems};

#[derive(Debug)]
pub struct StatementStructResult {
    pub sql: String,
}
pub struct WhereStructResult {
    pub sql: String,
    pub values: Vec<String>,
}

// My Results
type QueryOpResult = Result<&'static str, String>;
type StatementResult = Result<StatementStructResult, String>;
type WhereResult = Result<WhereStructResult, String>;

// TODO: Move there later
#[derive(Debug)]
pub struct Params {
    pub k: String,
    pub v: String,
}
// implement QueryString
#[derive(Debug)]
pub struct QueryString {
    pub query: Vec<Params>,
}

impl<'f> FromForm<'f> for QueryString {
    type Error = ();

    fn from_form(items: &mut FormItems<'f>, _: bool) -> Result<QueryString, ()> {
        let mut qs: QueryString = QueryString { query: Vec::new() };
        for (k, v) in items {
            qs.query.push(Params {
                k: k.to_string(),
                v: v.url_decode().unwrap(),
            });
        }
        Ok(qs)
    }
}

pub fn query_operator(qop: &str) -> QueryOpResult {
    match &qop[..] {
        "$eq" => Ok("="),
        "$ne" => Ok("!="),
        "$gt" => Ok(">"),
        "$lt" => Ok("<"),
        "$gte" => Ok(">="),
        "$lte" => Ok("<="),
        "$in" => Ok("IN"),
        "$nin" => Ok("NOT IN"),
        "$notnull" => Ok("IS NOT NULL"),
        "$null" => Ok("IS NULL"),
        _ => Err(format!("operator {} not found", qop)),
    }
}

fn collect_params(v: &Vec<Params>, collect_values: bool) -> Result<Vec<String>, String> {
    let mut pid: i32 = 0;
    v.iter()
        .filter(|param| !param.k.starts_with("_"))
        .map(|param| {
            pid = pid + 1;
            let result = match param.v.contains(".") {
                true => {
                    let value_splited = param.v.split(".").collect::<Vec<&str>>();
                    let operator = match query_operator(value_splited[0]) {
                        Ok(op) => op,
                        Err(e) => return Err(e),
                    };
                    (operator, value_splited[1])
                }
                _ => ("=", param.v.as_str()),
            };
            if collect_values {
                Ok(format!("{}", result.1))
            } else {
                // biggest workaround ever!
                let commons = ["pk", "id"];
                if commons.iter().any(|c| param.k.contains(c)) {
                    Ok(format!("{}::text{}${}", param.k, result.0, pid))
                } else {
                    Ok(format!("{}{}${}", param.k, result.0, pid))
                }
            }
        })
        .collect()
}

// generic function to process statements: _select, _groupby, _order, _count
fn process_statement<F>(
    qs: &QueryString,
    stm: &str,
    stm_default: &str,
    stm_fmt: &str,
    stm_fn: F,
) -> StatementResult
where
    F: Fn(&str) -> String,
{
    let mut statement_syntax: String = String::from(stm_default);
    let statement_params = qs.query.iter().find(|p| p.k == String::from(stm));
    let columns = match statement_params {
        Some(param) => stm_fn(&param.v),
        _ => String::from(""),
    };
    if columns != "" {
        statement_syntax = format!("{}", String::from(stm_fmt).replace("{}", &columns));
    }
    Ok(StatementStructResult { sql: statement_syntax })
}

// Get QueryString and return chunck WHERE statement with values
pub fn ext_where(qs: &QueryString) -> WhereResult {
    let where_syntax: String;
    let ref iter_params = qs.query;
    let where_values = match collect_params(iter_params, true) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string()),
    };
    let where_fields = match collect_params(iter_params, false) {
        Ok(result) => result,
        Err(e) => return Err(e.to_string()),
    };

    if where_fields.len() > 1 {
        where_syntax = format!("WHERE {}", where_fields.join(" AND "));
    } else {
        where_syntax = format!("WHERE {}", where_fields.join(" "));
    }

    Ok(WhereStructResult {
        sql: where_syntax,
        values: where_values,
    })
}

// Get QueryString and return SELECT statement
pub fn ext_select(qs: &QueryString) -> StatementResult {
    Ok(
        process_statement(qs, "_select", "SELECT * FROM", "SELECT {} FROM", |x| {
            String::from(x)
        }).unwrap(),
    )
}

// Get QueryString and return COUNT clause statement
pub fn ext_count(qs: &QueryString) -> StatementResult {
    // FIXME: Need handle errors
    Ok(
        process_statement(qs, "_count", "", "SELECT COUNT({}) FROM", |x| {
            let vs = x.split(",").collect::<Vec<&str>>();
            let result = if vs.len() > 1 { "" } else { x };
            String::from(result)
        }).unwrap(),
    )
}

// Get QueryString and return chunk ORDER BY statement
pub fn ext_order(qs: &QueryString) -> StatementResult {
    process_statement(qs, "_order", "", "ORDER BY {}", |x| {
        let vspl = &x.split(",").collect::<Vec<&str>>();
        let od: Vec<String> = vspl.iter()
            .map(|param| {
                let mut s = String::new();
                s.push_str(param); // omg
                if s.starts_with("-") {
                    s.remove(0);
                    s.push_str(" DESC")
                }
                format!("{}", s)
            })
            .collect();
        format!("{}", od.join(","))
    })
}

// Get QueryString and return chunk GROUP BY statement
pub fn ext_groupby(qs: &QueryString) -> StatementResult {
    Ok(
        process_statement(qs, "_groupby", "", "GROUP BY {}", |x| String::from(x)).unwrap(),
    )
}

#[cfg(test)]
mod tests {
    use postgresql::commands::*;

    #[test]
    fn get_opetators() {
        use std::collections::HashMap;

        let mut test_cases = HashMap::new();
        test_cases.insert("$eq", "=");
        test_cases.insert("$ne", "!=");
        test_cases.insert("$gt", ">");
        test_cases.insert("$gte", ">=");
        test_cases.insert("$lt", "<");
        test_cases.insert("$lte", "<=");
        test_cases.insert("$in", "IN");
        test_cases.insert("$nin", "NOT IN");
        test_cases.insert("$notnull", "IS NOT NULL");
        test_cases.insert("$null", "IS NULL");

        for (op, expected) in &test_cases {
            match query_operator(&op.to_string()) {
                Ok(x) => assert_eq!(expected.to_string(), x),
                Err(e) => assert_eq!("", e),
            }
        }
    }

    #[test]
    fn get_opetators_error() {
        let invalid = "!tn".to_string();
        match query_operator(&invalid) {
            Ok(_) => println!("no result"),
            Err(e) => assert_eq!(format!("operator {} not found", invalid), e),
        }
    }

    #[test]
    fn where_by_request_one_querystring() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id::text=$1".to_string());
        assert_eq!(result.values, vec!["5".to_string()])
    }

    #[test]
    fn where_by_request_with_orderby() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });
        hm.push(Params {
            k: "_order".to_string(),
            v: "user_id".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id::text=$1".to_string());
        assert_eq!(result.values, vec!["5".to_string()])
    }

    #[test]
    fn where_by_request_n_querystring() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(result.sql, "WHERE user_id::text=$1 AND name=$2".to_string());
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_operators() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "$ne.5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_where(&qs).unwrap();
        assert_eq!(
            result.sql,
            "WHERE user_id::text!=$1 AND name=$2".to_string()
        );
        assert_eq!(result.values, vec!["5".to_string(), "goga".to_string()])
    }

    #[test]
    fn where_by_request_with_query_invalid_operators() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "user_id".to_string(),
            v: "$nt.5".to_string(),
        });
        hm.push(Params {
            k: "name".to_string(),
            v: "goga".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_where(&qs) {
            Err(e) => assert_eq!(e, "operator $nt not found"),
            Ok(_) => println!("no result"),
        }
    }

    #[test]
    fn select_by_request_one_column() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT name FROM");
    }

    #[test]
    fn select_by_request_n_column() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT name,age FROM");
    }

    #[test]
    fn select_by_request_n_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_select".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_select(&qs).unwrap();
        assert_eq!(result.sql, "SELECT * FROM");
    }

    #[test]
    fn count_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "SELECT COUNT(name) FROM");
    }

    #[test]
    fn count_by_request_all_fields() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "*".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "SELECT COUNT(*) FROM");
    }

    #[test]
    fn count_by_request_two_fields() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_count(&qs) {
            Err(e) => assert_eq!(e, "could not use more than one column in count function"),
            Ok(s) => assert_eq!(s.sql, ""),
        }
    }

    #[test]
    fn count_by_request_empty_value() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_count".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_count(&qs).unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name")
    }

    #[test]
    fn order_by_request_desc() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "-name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name DESC")
    }

    #[test]
    fn order_by_request_empty_params() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "")
    }

    #[test]
    fn order_by_request_without_params() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "name".to_string(),
            v: "toby".to_string(),
        });

        let qs = QueryString { query: hm };
        match ext_order(&qs) {
            Ok(result) => assert_eq!(result.sql, ""),
            Err(e) => assert_eq!("error on params", e),
        };
    }

    #[test]
    fn order_by_request_multiples_columns() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name,age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name,age")
    }

    #[test]
    fn order_by_request_multiples_columns_with_orders() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_order".to_string(),
            v: "name,-age".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_order(&qs).unwrap();
        assert_eq!(result.sql, "ORDER BY name,age DESC")
    }

    #[test]
    fn groupby_by_request() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: "_groupby".to_string(),
            v: "name".to_string(),
        });

        let qs = QueryString { query: hm };
        let result = ext_groupby(&qs).unwrap();
        assert_eq!(result.sql, "GROUP BY name")
    }

    #[test]
    fn groupby_by_request_empty_param() {
        let mut hm = Vec::new();
        hm.push(Params {
            k: String::from("_groupby"),
            v: String::from(""),
        });

        let qs = QueryString { query: hm };
        let result = ext_groupby(&qs).unwrap();
        assert_eq!(result.sql, "")
    }
}
<|endoftext|>


<commit_before>extern crate rusqlite;
extern crate serde_json;

use super::std::result::Result;

fn get_last_note_for_app(app_id: u32, conn: &rusqlite::Connection) -> u32 {
    let query = format!("SELECT note_id from notifications where app_id = {}
         order by note_id desc limit 1",
                        app_id);

    match conn.query_row(&query, &[], |row| row.get(0)) {
        Ok(entry) =>  entry,
        Err(_) => 0
    }
}

pub fn populate_app_notes(config_json: serde_json::Value, conn: &rusqlite::Connection)
    -> Vec<(u32, serde_json::Value)> {

    let mut app_notes: Vec<(u32, serde_json::Value)> = Vec::new();

    let app_iter = config_json
        .get("applications")
        .unwrap()
        .as_array()
        .expect("applications value is not an array")
        .iter();

    for app in app_iter {
        for (_, app_details) in app.as_object().unwrap().iter() {
            let newest_note =
                get_last_note_for_app(
                    app_details
                    .get("app_id")
                    .unwrap()
                    .as_u64()
                    .unwrap() as u32,
                    &conn
            );
            app_notes.push((newest_note, app_details.clone()));
        }
    }

    app_notes
}

pub fn get_newest_alerts_for_app<X, Y>(newest_note: u32,
                               app_id: u32,
                               conn: &rusqlite::Connection)
                               -> Vec<Result<(X, Y), rusqlite::Error>>
    where X: rusqlite::types::FromSql,
          Y: rusqlite::types::FromSql
{
    let mut stmt =
        conn.prepare(
            &format!(
                "SELECT note_id, encoded_data from notifications
                where app_id = {} and note_id > {} order by note_id",
                app_id,
                newest_note
            )
        ).expect("Could not prepare SQL select statement.");

    let note_iter = stmt.query_map(&[], |row| (row.get(0), row.get(1)))
        .expect("Could not retrieve query_map results");

    note_iter.collect()
}
<commit_msg>fix lackluster style (or made worse) for get_newest_alerts()<commit_after>extern crate rusqlite;
extern crate serde_json;

use super::std::result::Result;

fn get_last_note_for_app(app_id: u32, conn: &rusqlite::Connection) -> u32 {
    let query = format!("SELECT note_id from notifications where app_id = {}
         order by note_id desc limit 1",
                        app_id);

    match conn.query_row(&query, &[], |row| row.get(0)) {
        Ok(entry) =>  entry,
        Err(_) => 0
    }
}

pub fn populate_app_notes(config_json: serde_json::Value, conn: &rusqlite::Connection)
    -> Vec<(u32, serde_json::Value)> {

    let mut app_notes: Vec<(u32, serde_json::Value)> = Vec::new();

    let app_iter = config_json
        .get("applications")
        .unwrap()
        .as_array()
        .expect("applications value is not an array")
        .iter();

    for app in app_iter {
        for (_, app_details) in app.as_object().unwrap().iter() {
            let newest_note =
                get_last_note_for_app(
                    app_details
                    .get("app_id")
                    .unwrap()
                    .as_u64()
                    .unwrap() as u32,
                    &conn
            );
            app_notes.push((newest_note, app_details.clone()));
        }
    }

    app_notes
}

pub fn get_newest_alerts_for_app<X, Y>(
    newest_note: u32,
    app_id: u32,
    conn: &rusqlite::Connection
    ) -> Vec<Result<(X, Y), rusqlite::Error>>
    where X: rusqlite::types::FromSql,
          Y: rusqlite::types::FromSql
{
    let mut stmt =
        conn.prepare(
            &format!(
                "SELECT note_id, encoded_data from notifications
                where app_id = {} and note_id > {} order by note_id",
                app_id,
                newest_note
            )
        ).expect("Could not prepare SQL select statement.");

    let note_iter = stmt.query_map(&[], |row| (row.get(0), row.get(1)))
        .expect("Could not retrieve query_map results");

    note_iter.collect()
}
<|endoftext|>


<commit_before>// The 'std' crates should always be implicitly public,
// without having to pass any compiler arguments

// run-pass

#![feature(public_private_dependencies)]
#![deny(exported_private_dependencies)]

pub struct PublicType {
    pub field: Option<u8>
}

fn main() {}
<commit_msg>Remove feature from test<commit_after>// The 'std' crates should always be implicitly public,
// without having to pass any compiler arguments

// run-pass

#![deny(exported_private_dependencies)]

pub struct PublicType {
    pub field: Option<u8>
}

fn main() {}
<|endoftext|>


<commit_before>/// Opaque type representing the C struct.
pub enum RsvgFilterContext {}
<commit_msg>Add FilterContext<commit_after>use std::collections::HashMap;
use std::{mem, ptr};

use cairo;
use cairo_sys::cairo_surface_t;
use glib::translate::{FromGlibPtrBorrow, FromGlibPtrFull, ToGlibPtr};
use glib_sys::*;
use libc::c_char;

use bbox::RsvgBbox;
use drawing_ctx::{self, RsvgDrawingCtx};
use filters::{IRect, RsvgFilterPrimitive};
use state::RsvgState;
use util::utf8_cstr;

// Required by the C code until all filters are ported to Rust.
pub enum RsvgFilter {}

// Required by the C code until all filters are ported to Rust.
// Keep this in sync with
// ../../librsvg/librsvg/filters/common.h:_RsvgFilterPrimitiveOutput
#[repr(C)]
struct RsvgFilterPrimitiveOutput {
    surface: *mut cairo_surface_t,
    bounds: IRect,
}

// Required by the C code until all filters are ported to Rust.
// Keep this in sync with
// ../../librsvg/librsvg/filters/common.h:_RsvgFilterContext
#[repr(C)]
pub struct RsvgFilterContext {
    width: i32,
    height: i32,
    filter: *mut RsvgFilter,
    results: *mut GHashTable,
    source_surface: *mut cairo_surface_t,
    bg_surface: *mut cairo_surface_t,
    lastresult: RsvgFilterPrimitiveOutput,
    affine: cairo::Matrix,
    paffine: cairo::Matrix,
    channelmap: [i32; 4],
    ctx: *mut RsvgDrawingCtx,
}

/// The filter rendering context.
pub struct FilterContext {
    // TODO: remove when all filters are ported to Rust.
    /// The C struct passed to C filters.
    c_struct: RsvgFilterContext,

    /// The source graphic surface.
    source_surface: cairo::ImageSurface,
    /// Output of the last filter primitive.
    last_result: Option<cairo::ImageSurface>,
    /// Surfaces of the previous filter primitives by name.
    previous_results: HashMap<String, cairo::ImageSurface>,
}

impl FilterContext {
    /// Creates a new `FilterContext`.
    #[inline]
    pub fn new(
        filter: *mut RsvgFilter,
        source_surface: cairo::ImageSurface,
        ctx: *mut RsvgDrawingCtx,
        bbox: RsvgBbox,
        channelmap: [i32; 4],
    ) -> Self {
        extern "C" {
            fn rsvg_filter_fix_coordinate_system(
                ctx: *mut RsvgFilterContext,
                state: *mut RsvgState,
                bbox: *mut RsvgBbox, // Actually *const.
            );

            fn rsvg_filter_free_pair(value: gpointer);

            fn rsvg_filter_primitive_get_bounds(
                primitive: *mut RsvgFilterPrimitive,
                ctx: *mut RsvgFilterContext, // Actually *const.
            ) -> IRect;
        }

        let mut rv = Self {
            c_struct: RsvgFilterContext {
                filter,
                results: unsafe {
                    g_hash_table_new_full(
                        Some(g_str_hash),
                        Some(g_str_equal),
                        Some(g_free),
                        Some(rsvg_filter_free_pair),
                    )
                },
                source_surface: source_surface.to_glib_full(),
                bg_surface: ptr::null_mut(),
                lastresult: RsvgFilterPrimitiveOutput {
                    surface: source_surface.to_glib_full(),

                    // Initialized by rsvg_filter_primitive_get_bounds().
                    bounds: unsafe { mem::uninitialized() },
                },

                channelmap,
                ctx,

                // This stuff is initialized by rsvg_filter_fix_coordinate_system().
                width: unsafe { mem::uninitialized() },
                height: unsafe { mem::uninitialized() },
                affine: unsafe { mem::uninitialized() },
                paffine: unsafe { mem::uninitialized() },
            },

            source_surface,
            last_result: None,
            previous_results: HashMap::new(),
        };

        unsafe {
            rsvg_filter_fix_coordinate_system(
                &mut rv.c_struct,
                drawing_ctx::get_current_state_ptr(ctx),
                &bbox as *const RsvgBbox as *mut RsvgBbox,
            )
        };

        rv.c_struct.lastresult.bounds =
            unsafe { rsvg_filter_primitive_get_bounds(ptr::null_mut(), &mut rv.c_struct) };

        rv
    }

    /// Returns a pointer to the raw C struct.
    #[inline]
    pub fn get_raw(&self) -> *const RsvgFilterContext {
        &self.c_struct
    }

    /// Returns a mutable pointer to the raw C struct.
    #[inline]
    pub fn get_raw_mut(&mut self) -> *mut RsvgFilterContext {
        &mut self.c_struct
    }

    /// Refreshes the Rust fields from the C struct fields that could get modified from within the
    /// filter code.
    pub fn refresh_from_c(&mut self) {
        self.last_result = Some(unsafe {
            cairo::ImageSurface::from_glib_borrow(self.c_struct.lastresult.surface)
        });

        // Update the previous results map.
        unsafe {
            let mut iter = mem::uninitialized();
            g_hash_table_iter_init(&mut iter, self.c_struct.results);

            let mut key: *const c_char = mem::uninitialized();
            let mut value: *const RsvgFilterPrimitiveOutput = mem::uninitialized();
            while g_hash_table_iter_next(
                &mut iter,
                &mut key as *mut _ as *mut gpointer,
                &mut value as *mut _ as *mut gpointer,
            ) != 0
            {
                if !self.previous_results.contains_key(utf8_cstr(key)) {
                    self.previous_results.insert(
                        utf8_cstr(key).to_owned(),
                        cairo::ImageSurface::from_glib_borrow((*value).surface),
                    );
                }
            }
        }
    }

    /// Returns the surface corresponding to the last filter primitive's result.
    #[inline]
    pub fn last_result(&self) -> Option<cairo::ImageSurface> {
        self.last_result.clone()
    }

    /// Returns the surface corresponding to the source graphic.
    #[inline]
    pub fn source_graphic(&self) -> cairo::ImageSurface {
        self.source_surface.clone()
    }

    /// Returns the surface corresponding to the background image snapshot.
    #[inline]
    pub fn background_image(&self) -> cairo::ImageSurface {
        unimplemented!()
    }

    /// Returns the surface corresponding to the result of the given filter primitive.
    #[inline]
    pub fn filter_result(&self, name: &str) -> Option<cairo::ImageSurface> {
        self.previous_results.get(name).cloned()
    }

    /// Converts this `FilterContext` into the surface corresponding to the result of the filter
    /// chain.
    #[inline]
    pub fn into_result(self) -> cairo::ImageSurface {
        self.last_result
            .clone()
            .unwrap_or_else(|| self.source_surface.clone())
    }
}

impl Drop for FilterContext {
    fn drop(&mut self) {
        unsafe {
            drop(cairo::Surface::from_glib_full(self.c_struct.source_surface));
            drop(cairo::Surface::from_glib_full(
                self.c_struct.lastresult.surface,
            ));
            g_hash_table_destroy(self.c_struct.results);
            if !self.c_struct.bg_surface.is_null() {
                drop(cairo::Surface::from_glib_full(self.c_struct.bg_surface));
            }
        }
    }
}
<|endoftext|>