<commit_before>use crate::net::{network_delay, network_poll};
use futures::pin_mut;
use futures::task::{waker_ref, ArcWake, FutureObj, SpawnError};
use smoltcp::time::{Duration, Instant};
use std::future::Future;
use std::sync::{
	atomic::{AtomicBool, Ordering},
	Arc, Mutex,
};
use std::task::{Context, Poll};

/// A thread handle type
type Tid = u32;

extern "C" {
	fn sys_getpid() -> u32;
	fn sys_yield();
	fn sys_wakeup_task(tid: Tid);
	fn sys_set_network_polling_mode(value: bool);
}

extern "Rust" {
	fn sys_block_current_task_with_timeout(timeout: Option<u64>);
}

thread_local! {
	static CURRENT_THREAD_NOTIFY: Arc<ThreadNotify> = {
		Arc::new(ThreadNotify::new())
	}
}

lazy_static! {
	static ref EXECUTOR: Mutex<SmoltcpExecutor> = Mutex::new(SmoltcpExecutor::new());
}

struct SmoltcpExecutor {
	pool: Vec<FutureObj<'static, ()>>,
}

impl SmoltcpExecutor {
	pub const fn new() -> Self {
		Self { pool: Vec::new() }
	}

	fn spawn_obj(&mut self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
		self.pool.push(future);
		Ok(())
	}
}

struct ThreadNotify {
	/// The (single) executor thread.
	thread: Tid,
	/// A flag to ensure a wakeup is not "forgotten" before the next `block_current_task`
	unparked: AtomicBool,
}

impl ThreadNotify {
	pub fn new() -> Self {
		Self {
			thread: unsafe { sys_getpid() },
			unparked: AtomicBool::new(false),
		}
	}
}

impl Drop for ThreadNotify {
	fn drop(&mut self) {
		println!("Dropping ThreadNotify!");
	}
}

impl ArcWake for ThreadNotify {
	fn wake_by_ref(arc_self: &Arc<Self>) {
		// Make sure the wakeup is remembered until the next `park()`.
		let unparked = arc_self.unparked.swap(true, Ordering::Relaxed);
		if !unparked {
			unsafe {
				sys_wakeup_task(arc_self.thread);
			}
		}
	}
}

// Set up and run a basic single-threaded spawner loop, invoking `f` on each
// turn.
fn run_until<T, F: FnMut(&mut Context<'_>) -> Poll<T>>(
	mut f: F,
	timeout: Option<Duration>,
) -> Result<T, ()> {
	unsafe {
		sys_set_network_polling_mode(true);
	}
	let start = Instant::now();

	CURRENT_THREAD_NOTIFY.with(|thread_notify| {
		let waker = waker_ref(thread_notify);
		let mut cx = Context::from_waker(&waker);
		loop {
			if let Poll::Ready(t) = f(&mut cx) {
				unsafe {
					sys_set_network_polling_mode(false);
				}
				return Ok(t);
			}

			let now = Instant::now();

			if let Some(duration) = timeout {
				if now >= start + duration {
					unsafe {
						sys_set_network_polling_mode(false);
					}
					return Err(());
				}
			} else {
				let delay = network_delay(now).map(|d| d.total_millis());

				if delay.is_none() || delay.unwrap() > 100 {
					let unparked = thread_notify.unparked.swap(false, Ordering::Acquire);
					if !unparked {
						unsafe {
							sys_set_network_polling_mode(false);
							sys_block_current_task_with_timeout(delay);
							sys_yield();
							sys_set_network_polling_mode(true);
						}
						thread_notify.unparked.store(false, Ordering::Release);
						network_poll(&mut cx, Instant::now());
					}
				} else {
					network_poll(&mut cx, now);
				}
			}
		}
	})
}

pub fn block_on<F: Future>(f: F, timeout: Option<Duration>) -> Result<F::Output, ()> {
	pin_mut!(f);
	run_until(|cx| f.as_mut().poll(cx), timeout)
}

pub fn spawn<F: Future<Output = ()> + std::marker::Send + 'static>(f: F) -> Result<(), SpawnError> {
	EXECUTOR
		.lock()
		.unwrap()
		.spawn_obj(FutureObj::from(Box::new(f)))
}
<commit_msg>Migrate from futures' ArcWake to std's Wake<commit_after>use crate::net::{network_delay, network_poll};
use futures::pin_mut;
use futures::task::{FutureObj, SpawnError};
use smoltcp::time::{Duration, Instant};
use std::future::Future;
use std::sync::{
	atomic::{AtomicBool, Ordering},
	Arc, Mutex,
};
use std::task::{Context, Poll, Wake};

/// A thread handle type
type Tid = u32;

extern "C" {
	fn sys_getpid() -> u32;
	fn sys_yield();
	fn sys_wakeup_task(tid: Tid);
	fn sys_set_network_polling_mode(value: bool);
}

extern "Rust" {
	fn sys_block_current_task_with_timeout(timeout: Option<u64>);
}

thread_local! {
	static CURRENT_THREAD_NOTIFY: Arc<ThreadNotify> = {
		Arc::new(ThreadNotify::new())
	}
}

lazy_static! {
	static ref EXECUTOR: Mutex<SmoltcpExecutor> = Mutex::new(SmoltcpExecutor::new());
}

struct SmoltcpExecutor {
	pool: Vec<FutureObj<'static, ()>>,
}

impl SmoltcpExecutor {
	pub const fn new() -> Self {
		Self { pool: Vec::new() }
	}

	fn spawn_obj(&mut self, future: FutureObj<'static, ()>) -> Result<(), SpawnError> {
		self.pool.push(future);
		Ok(())
	}
}

struct ThreadNotify {
	/// The (single) executor thread.
	thread: Tid,
	/// A flag to ensure a wakeup is not "forgotten" before the next `block_current_task`
	unparked: AtomicBool,
}

impl ThreadNotify {
	pub fn new() -> Self {
		Self {
			thread: unsafe { sys_getpid() },
			unparked: AtomicBool::new(false),
		}
	}
}

impl Drop for ThreadNotify {
	fn drop(&mut self) {
		println!("Dropping ThreadNotify!");
	}
}

impl Wake for ThreadNotify {
	fn wake(self: Arc<Self>) {
		self.wake_by_ref()
	}

	fn wake_by_ref(self: &Arc<Self>) {
		// Make sure the wakeup is remembered until the next `park()`.
		let unparked = self.unparked.swap(true, Ordering::Relaxed);
		if !unparked {
			unsafe {
				sys_wakeup_task(self.thread);
			}
		}
	}
}

// Set up and run a basic single-threaded spawner loop, invoking `f` on each
// turn.
fn run_until<T, F: FnMut(&mut Context<'_>) -> Poll<T>>(
	mut f: F,
	timeout: Option<Duration>,
) -> Result<T, ()> {
	unsafe {
		sys_set_network_polling_mode(true);
	}
	let start = Instant::now();

	CURRENT_THREAD_NOTIFY.with(|thread_notify| {
		let waker = thread_notify.clone().into();
		let mut cx = Context::from_waker(&waker);
		loop {
			if let Poll::Ready(t) = f(&mut cx) {
				unsafe {
					sys_set_network_polling_mode(false);
				}
				return Ok(t);
			}

			let now = Instant::now();

			if let Some(duration) = timeout {
				if now >= start + duration {
					unsafe {
						sys_set_network_polling_mode(false);
					}
					return Err(());
				}
			} else {
				let delay = network_delay(now).map(|d| d.total_millis());

				if delay.is_none() || delay.unwrap() > 100 {
					let unparked = thread_notify.unparked.swap(false, Ordering::Acquire);
					if !unparked {
						unsafe {
							sys_set_network_polling_mode(false);
							sys_block_current_task_with_timeout(delay);
							sys_yield();
							sys_set_network_polling_mode(true);
						}
						thread_notify.unparked.store(false, Ordering::Release);
						network_poll(&mut cx, Instant::now());
					}
				} else {
					network_poll(&mut cx, now);
				}
			}
		}
	})
}

pub fn block_on<F: Future>(f: F, timeout: Option<Duration>) -> Result<F::Output, ()> {
	pin_mut!(f);
	run_until(|cx| f.as_mut().poll(cx), timeout)
}

pub fn spawn<F: Future<Output = ()> + std::marker::Send + 'static>(f: F) -> Result<(), SpawnError> {
	EXECUTOR
		.lock()
		.unwrap()
		.spawn_obj(FutureObj::from(Box::new(f)))
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{collections::HashMap,
          env,
          fs::{canonicalize,
               create_dir_all,
               File,
               OpenOptions},
          io::{BufRead,
               BufReader,
               Write},
          path::Path};

use crate::hcore::package::PackageIdent;
use handlebars::Handlebars;

use crate::{common::ui::{Status,
                         UIWriter,
                         UI},
            error::Result};

const FULL_PLAN_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/full_template_plan.sh"));
const MINIMAL_PLAN_TEMPLATE: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"),
                                                         "/static/minimal_template_plan.sh"));
const FULL_PLAN_PS1_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/full_template_plan.ps1"));
const MINIMAL_PLAN_PS1_TEMPLATE: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"),
                                                             "/static/minimal_template_plan.ps1"));
const DEFAULT_TOML_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/template_default.toml"));
const GITIGNORE_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/template_gitignore"));
const README_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/template_README.md"));

const DEFAULT_PKG_VERSION: &str = "0.1.0";

#[allow(clippy::too_many_arguments)]
pub fn start(ui: &mut UI,
             origin: String,
             minimal: bool,
             scaffolding_ident: Option<PackageIdent>,
             maybe_name: Option<String>)
             -> Result<()> {
    ui.begin("Constructing a cozy habitat for your app...")?;
    ui.br()?;

    let (root, name) = match maybe_name {
        Some(name) => (name.clone(), name.clone()),
        // The name of the current working directory.
        None => {
            ("habitat".into(),
             canonicalize(".").ok()
                              .and_then(|path| {
                                  path.components().last().and_then(|val| {
                                                              // Type gymnastics!
                                                              val.as_os_str()
                                                                 .to_os_string()
                                                                 .into_string()
                                                                 .ok()
                                                          })
                              })
                              .unwrap_or_else(|| "unnamed".into()))
        }
    };

    // Build out the variables passed.
    let handlebars = Handlebars::new();
    let mut data = HashMap::new();
    data.insert("pkg_name".to_string(), name);
    data.insert("pkg_origin".to_string(), origin);
    data.insert("pkg_version".to_string(), DEFAULT_PKG_VERSION.to_string());

    if let Some(ident) = scaffolding_ident {
        data.insert("scaffolding_ident".to_string(), ident.to_string());
    }

    // Add all environment variables that start with "pkg_" as variables in
    // the template.
    for (key, value) in env::vars() {
        if key.starts_with("pkg_") {
            data.insert(key, value);
        }
    }

    // We want to render the configured variables.
    if cfg!(windows) {
        let rendered_plan = if minimal {
            handlebars.template_render(MINIMAL_PLAN_PS1_TEMPLATE, &data)?
        } else {
            handlebars.template_render(FULL_PLAN_PS1_TEMPLATE, &data)?
        };
        create_with_template(ui, &format!("{}/plan.ps1", root), &rendered_plan)?;
    } else {
        let rendered_plan = if minimal {
            handlebars.template_render(MINIMAL_PLAN_TEMPLATE, &data)?
        } else {
            handlebars.template_render(FULL_PLAN_TEMPLATE, &data)?
        };
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    }
    ui.para("`plan.sh` is the foundation of your new habitat. It contains metadata, \
             dependencies, and tasks.")?;
    let rendered_default_toml = handlebars.template_render(DEFAULT_TOML_TEMPLATE, &data)?;
    create_with_template(ui,
                         &format!("{}/default.toml", root),
                         &rendered_default_toml)?;
    ui.para("`default.toml` contains default values for `cfg` prefixed variables.")?;

    let rendered_readme_md = handlebars.template_render(README_TEMPLATE, &data)?;
    create_with_template(ui, &format!("{}/README.md", root), &rendered_readme_md)?;
    ui.para("`README.md` contains a basic README document which you should update.")?;

    let config_path = format!("{}/config/", root);
    if Path::new(&config_path).exists() {
        ui.status(Status::Using,
                  format!("existing directory: {}", config_path))?;
    } else {
        ui.status(Status::Creating, format!("directory: {}", config_path))?;
        create_dir_all(&config_path)?;
    }
    ui.para("`/config/` contains configuration files for your app.")?;

    let hooks_path = format!("{}/hooks/", root);
    if Path::new(&hooks_path).exists() {
        ui.status(Status::Using, format!("existing directory: {}", hooks_path))?;
    } else {
        ui.status(Status::Creating, format!("directory: {}", hooks_path))?;
        create_dir_all(&hooks_path)?;
    }
    ui.para("`/hooks/` contains automation hooks into your habitat.")?;

    ui.para(
        "For more information on any of the files: \
         https://www.habitat.sh/docs/reference/plan-syntax/",
    )?;

    render_ignorefile(ui, &root)?;

    ui.end("An abode for your code is initialized!")?;
    Ok(())
}

fn render_ignorefile(ui: &mut UI, root: &str) -> Result<()> {
    let parent = format!("{}/..", root);
    let expanded = canonicalize(&parent)?;
    let current_path = Path::new(&expanded);

    if is_git_managed(&current_path) {
        let target = format!("{}/.gitignore", parent);
        let target_path = Path::new(&target);

        if !target_path.exists() {
            create_with_template(ui, &target, GITIGNORE_TEMPLATE)?
        } else {
            let file = OpenOptions::new().read(true)
                                         .append(true)
                                         .open(target_path)?;

            let entries: Vec<String> =
                BufReader::new(&file).lines()
                                     .map(|l| l.expect("Failed to parse line"))
                                     .collect();

            let mut appended = 0;

            for line in GITIGNORE_TEMPLATE.lines() {
                let s = line.to_string();

                if !entries.contains(&s) {
                    writeln!(&file, "{}", s)?;
                    appended += 1;
                }
            }

            ui.status(Status::Using,
                      format!("existing file: {} ({} lines appended)", &target, appended))?;
        }
    }
    Ok(())
}

fn is_git_managed(path: &Path) -> bool {
    path.join(".git").is_dir()
    || path.parent()
           .map_or(false, |parent| is_git_managed(&parent))
}

fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> {
    let path = Path::new(&location);
    if path.exists() {
        // If the user has already configured a file overwriting would be impolite.
        ui.status(Status::Using, format!("existing file: {}", location))?;
    } else {
        ui.status(Status::Creating, format!("file: {}", location))?;
        // If the directory doesn't exist we need to make it.
        if let Some(directory) = path.parent() {
            create_dir_all(directory)?;
        }
        // Create and then render the template with Handlebars
        File::create(path).and_then(|mut file| file.write(template.as_bytes()))?;
    }
    Ok(())
}
<commit_msg>[PR Feedback] Rename bash templates<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{collections::HashMap,
          env,
          fs::{canonicalize,
               create_dir_all,
               File,
               OpenOptions},
          io::{BufRead,
               BufReader,
               Write},
          path::Path};

use crate::hcore::package::PackageIdent;
use handlebars::Handlebars;

use crate::{common::ui::{Status,
                         UIWriter,
                         UI},
            error::Result};

const FULL_PLAN_SH_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/full_template_plan.sh"));
const MINIMAL_PLAN_SH_TEMPLATE: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"),
                                                            "/static/minimal_template_plan.sh"));
const FULL_PLAN_PS1_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/full_template_plan.ps1"));
const MINIMAL_PLAN_PS1_TEMPLATE: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"),
                                                             "/static/minimal_template_plan.ps1"));
const DEFAULT_TOML_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/template_default.toml"));
const GITIGNORE_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/template_gitignore"));
const README_TEMPLATE: &str =
    include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/static/template_README.md"));

const DEFAULT_PKG_VERSION: &str = "0.1.0";

#[allow(clippy::too_many_arguments)]
pub fn start(ui: &mut UI,
             origin: String,
             minimal: bool,
             scaffolding_ident: Option<PackageIdent>,
             maybe_name: Option<String>)
             -> Result<()> {
    ui.begin("Constructing a cozy habitat for your app...")?;
    ui.br()?;

    let (root, name) = match maybe_name {
        Some(name) => (name.clone(), name.clone()),
        // The name of the current working directory.
        None => {
            ("habitat".into(),
             canonicalize(".").ok()
                              .and_then(|path| {
                                  path.components().last().and_then(|val| {
                                                              // Type gymnastics!
                                                              val.as_os_str()
                                                                 .to_os_string()
                                                                 .into_string()
                                                                 .ok()
                                                          })
                              })
                              .unwrap_or_else(|| "unnamed".into()))
        }
    };

    // Build out the variables passed.
    let handlebars = Handlebars::new();
    let mut data = HashMap::new();
    data.insert("pkg_name".to_string(), name);
    data.insert("pkg_origin".to_string(), origin);
    data.insert("pkg_version".to_string(), DEFAULT_PKG_VERSION.to_string());

    if let Some(ident) = scaffolding_ident {
        data.insert("scaffolding_ident".to_string(), ident.to_string());
    }

    // Add all environment variables that start with "pkg_" as variables in
    // the template.
    for (key, value) in env::vars() {
        if key.starts_with("pkg_") {
            data.insert(key, value);
        }
    }

    // We want to render the configured variables.
    if cfg!(windows) {
        let rendered_plan = if minimal {
            handlebars.template_render(MINIMAL_PLAN_PS1_TEMPLATE, &data)?
        } else {
            handlebars.template_render(FULL_PLAN_PS1_TEMPLATE, &data)?
        };
        create_with_template(ui, &format!("{}/plan.ps1", root), &rendered_plan)?;
    } else {
        let rendered_plan = if minimal {
            handlebars.template_render(MINIMAL_PLAN_SH_TEMPLATE, &data)?
        } else {
            handlebars.template_render(FULL_PLAN_SH_TEMPLATE, &data)?
        };
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    }
    ui.para("`plan.sh` is the foundation of your new habitat. It contains metadata, \
             dependencies, and tasks.")?;
    let rendered_default_toml = handlebars.template_render(DEFAULT_TOML_TEMPLATE, &data)?;
    create_with_template(ui,
                         &format!("{}/default.toml", root),
                         &rendered_default_toml)?;
    ui.para("`default.toml` contains default values for `cfg` prefixed variables.")?;

    let rendered_readme_md = handlebars.template_render(README_TEMPLATE, &data)?;
    create_with_template(ui, &format!("{}/README.md", root), &rendered_readme_md)?;
    ui.para("`README.md` contains a basic README document which you should update.")?;

    let config_path = format!("{}/config/", root);
    if Path::new(&config_path).exists() {
        ui.status(Status::Using,
                  format!("existing directory: {}", config_path))?;
    } else {
        ui.status(Status::Creating, format!("directory: {}", config_path))?;
        create_dir_all(&config_path)?;
    }
    ui.para("`/config/` contains configuration files for your app.")?;

    let hooks_path = format!("{}/hooks/", root);
    if Path::new(&hooks_path).exists() {
        ui.status(Status::Using, format!("existing directory: {}", hooks_path))?;
    } else {
        ui.status(Status::Creating, format!("directory: {}", hooks_path))?;
        create_dir_all(&hooks_path)?;
    }
    ui.para("`/hooks/` contains automation hooks into your habitat.")?;

    ui.para(
        "For more information on any of the files: \
         https://www.habitat.sh/docs/reference/plan-syntax/",
    )?;

    render_ignorefile(ui, &root)?;

    ui.end("An abode for your code is initialized!")?;
    Ok(())
}

fn render_ignorefile(ui: &mut UI, root: &str) -> Result<()> {
    let parent = format!("{}/..", root);
    let expanded = canonicalize(&parent)?;
    let current_path = Path::new(&expanded);

    if is_git_managed(&current_path) {
        let target = format!("{}/.gitignore", parent);
        let target_path = Path::new(&target);

        if !target_path.exists() {
            create_with_template(ui, &target, GITIGNORE_TEMPLATE)?
        } else {
            let file = OpenOptions::new().read(true)
                                         .append(true)
                                         .open(target_path)?;

            let entries: Vec<String> =
                BufReader::new(&file).lines()
                                     .map(|l| l.expect("Failed to parse line"))
                                     .collect();

            let mut appended = 0;

            for line in GITIGNORE_TEMPLATE.lines() {
                let s = line.to_string();

                if !entries.contains(&s) {
                    writeln!(&file, "{}", s)?;
                    appended += 1;
                }
            }

            ui.status(Status::Using,
                      format!("existing file: {} ({} lines appended)", &target, appended))?;
        }
    }
    Ok(())
}

fn is_git_managed(path: &Path) -> bool {
    path.join(".git").is_dir()
    || path.parent()
           .map_or(false, |parent| is_git_managed(&parent))
}

fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> {
    let path = Path::new(&location);
    if path.exists() {
        // If the user has already configured a file overwriting would be impolite.
        ui.status(Status::Using, format!("existing file: {}", location))?;
    } else {
        ui.status(Status::Creating, format!("file: {}", location))?;
        // If the directory doesn't exist we need to make it.
        if let Some(directory) = path.parent() {
            create_dir_all(directory)?;
        }
        // Create and then render the template with Handlebars
        File::create(path).and_then(|mut file| file.write(template.as_bytes()))?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>extern crate nom;

use std::str;
use nom::{
    is_digit,
    is_hex_digit,
};

fn is_ws(c: char) -> bool {
    let u = c as u32;
    u == 0x20 || u == 0x9 || u == 0xD || u == 0xA
}

fn is_anon(c: char) -> bool {
    c == '[' || c == ']' || is_ws(c)
}

fn is_digit_c(c: char) -> bool {
    is_digit(c as u8)
}

#[derive(PartialEq, Debug)]
pub enum Mantissa<'a> {
    IntegerDecimal {
        integer_part:  &'a str,
        decimal_point: &'a str,
        decimal_part:  &'a str,
    },
    Decimal {
        decimal_point: &'a str,
        decimal_part:  &'a str,
    },
    Integer {
        integer_part: &'a str,
    },
}
#[derive(PartialEq, Debug)]
pub struct Double<'a> {
    sign:     Option<&'a str>,
    mantissa: Mantissa<'a>,
    exponent: Exponent<'a>,
}
/* [21] DOUBLE */
named!(pub double<&str, Double>, do_parse!(
    sign:     opt!(alt!(tag!("+") | tag!("-"))) >>
    mantissa: alt!(
        do_parse!(
            integer_part:  take_while1_s!(is_digit_c) >>
            decimal_point: tag!(".")                  >>
            decimal_part:  take_while_s!(is_digit_c)  >>
            (Mantissa::IntegerDecimal{
                integer_part:  integer_part,
                decimal_point: decimal_point,
                decimal_part:  decimal_part,
            })
        ) |
        do_parse!(
            decimal_point: tag!(".")                  >>
            decimal_part:  take_while1_s!(is_digit_c) >>
            (Mantissa::Decimal{
                decimal_point: decimal_point,
                decimal_part:  decimal_part,
            })
        ) |
        do_parse!(
            integer_part: take_while1_s!(is_digit_c) >>
            (Mantissa::Integer{
                integer_part: integer_part,
            })
        )
    ) >>
    exponent: exponent >>
    (Double{
        sign:     sign,
        mantissa: mantissa,
        exponent: exponent,
    })
));

#[derive(PartialEq, Debug)]
pub struct Exponent<'a> {
    exponent_symbol: &'a str,
    sign:            Option<&'a str>,
    exponent_number: &'a str,
}

/* [154s] EXPONENT */
named!(pub exponent<&str, Exponent>, do_parse!(
    exponent_symbol: alt!(tag!("e") | tag!("E"))       >>
    sign:            opt!(alt!(tag!("+") | tag!("-"))) >>
    exponent_number: take_while1_s!(is_digit_c)        >>
    (Exponent{
        exponent_symbol: exponent_symbol,
        sign:            sign,
        exponent_number: exponent_number,
    })
));

/* [161s] WS */
named!(pub ws<&str, &str>, take_while_s!(is_ws));

/* [162s] ANON */
named!(pub anon<&str, &str>, verify!(
    take_while_s!(is_anon),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '['
            } else if idx == len - 1 {
                c == ']'
            } else {
                is_ws(c)
            }
        })
    }
));

/* [170s] PERCENT */
named!(pub percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

#[cfg(test)]
mod test {
    use super::*;
    use nom::IResult;

    #[test]
    fn double_normal_test() {
        let input    = "-1234.5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("-"),
            mantissa: Mantissa::IntegerDecimal {
                integer_part:  "1234",
                decimal_point: ".",
                decimal_part:  "5678",
            },
            exponent: Exponent {
                exponent_symbol: "e",
                sign:            Some("-"),
                exponent_number: "0123456789",
            },
        });
        assert_eq!(double(input), expected);

        let input    = "-.5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("-"),
            mantissa: Mantissa::Decimal {
                decimal_point: ".",
                decimal_part:  "5678",
            },
            exponent: Exponent {
                exponent_symbol: "e",
                sign:            Some("-"),
                exponent_number: "0123456789",
            },
        });
        assert_eq!(double(input), expected);

        let input    = "+5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("+"),
            mantissa: Mantissa::Integer {
                integer_part: "5678",
            },
            exponent: Exponent {
                exponent_symbol: "e",
                sign:            Some("-"),
                exponent_number: "0123456789",
            },
        });
        assert_eq!(double(input), expected);
    }

    #[test]
    fn exponent_normal_test() {
        let input    = "e-0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "e",
            sign:            Some("-"),
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);

        let input    = "E+0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "E",
            sign:            Some("+"),
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);

        let input    = "e0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "e",
            sign:            None,
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);
    }

    #[test]
    fn ws_test() {
        assert_eq!(ws("   a"), IResult::Done("a", "   "));
    }

    #[test]
    fn anon_test() {
        assert_eq!(anon("[ ]a"), IResult::Done("a", "[ ]"));
    }

    #[test]
    fn percent_test() {
        assert_eq!(percent("%2Abc"), IResult::Done("bc", "%2A"));
    }
}
<commit_msg>Implement DECIMAL<commit_after>extern crate nom;

use std::str;
use nom::{
    is_digit,
    is_hex_digit,
};

fn is_ws(c: char) -> bool {
    let u = c as u32;
    u == 0x20 || u == 0x9 || u == 0xD || u == 0xA
}

fn is_anon(c: char) -> bool {
    c == '[' || c == ']' || is_ws(c)
}

fn is_digit_c(c: char) -> bool {
    is_digit(c as u8)
}

#[derive(PartialEq, Debug)]
pub struct Decimal<'a> {
    sign:          Option<&'a str>,
    integer_part:  &'a str,
    decimal_point: &'a str,
    decimal_part:  &'a str,
}
/* [20] DECIMAL */
named!(pub decimal<&str, Decimal>, do_parse!(
    sign:          opt!(alt!(tag!("+") | tag!("-"))) >>
    integer_part:  take_while_s!(is_digit_c)         >>
    decimal_point: tag!(".")                         >>
    decimal_part:  take_while1_s!(is_digit_c)        >>
    (Decimal{
        sign:          sign,
        integer_part:  integer_part,
        decimal_point: decimal_point,
        decimal_part:  decimal_part,
    })
));

#[derive(PartialEq, Debug)]
pub enum Mantissa<'a> {
    IntegerDecimal {
        integer_part:  &'a str,
        decimal_point: &'a str,
        decimal_part:  &'a str,
    },
    Decimal {
        decimal_point: &'a str,
        decimal_part:  &'a str,
    },
    Integer {
        integer_part: &'a str,
    },
}
#[derive(PartialEq, Debug)]
pub struct Double<'a> {
    sign:     Option<&'a str>,
    mantissa: Mantissa<'a>,
    exponent: Exponent<'a>,
}
/* [21] DOUBLE */
named!(pub double<&str, Double>, do_parse!(
    sign:     opt!(alt!(tag!("+") | tag!("-"))) >>
    mantissa: alt!(
        do_parse!(
            integer_part:  take_while1_s!(is_digit_c) >>
            decimal_point: tag!(".")                  >>
            decimal_part:  take_while_s!(is_digit_c)  >>
            (Mantissa::IntegerDecimal{
                integer_part:  integer_part,
                decimal_point: decimal_point,
                decimal_part:  decimal_part,
            })
        ) |
        do_parse!(
            decimal_point: tag!(".")                  >>
            decimal_part:  take_while1_s!(is_digit_c) >>
            (Mantissa::Decimal{
                decimal_point: decimal_point,
                decimal_part:  decimal_part,
            })
        ) |
        do_parse!(
            integer_part: take_while1_s!(is_digit_c) >>
            (Mantissa::Integer{
                integer_part: integer_part,
            })
        )
    ) >>
    exponent: exponent >>
    (Double{
        sign:     sign,
        mantissa: mantissa,
        exponent: exponent,
    })
));

#[derive(PartialEq, Debug)]
pub struct Exponent<'a> {
    exponent_symbol: &'a str,
    sign:            Option<&'a str>,
    exponent_number: &'a str,
}

/* [154s] EXPONENT */
named!(pub exponent<&str, Exponent>, do_parse!(
    exponent_symbol: alt!(tag!("e") | tag!("E"))       >>
    sign:            opt!(alt!(tag!("+") | tag!("-"))) >>
    exponent_number: take_while1_s!(is_digit_c)        >>
    (Exponent{
        exponent_symbol: exponent_symbol,
        sign:            sign,
        exponent_number: exponent_number,
    })
));

/* [161s] WS */
named!(pub ws<&str, &str>, take_while_s!(is_ws));

/* [162s] ANON */
named!(pub anon<&str, &str>, verify!(
    take_while_s!(is_anon),
    |val:&str| {
        let len = val.char_indices().count();
        val.char_indices().all(|(idx, c)| {
            if idx == 0 {
                c == '['
            } else if idx == len - 1 {
                c == ']'
            } else {
                is_ws(c)
            }
        })
    }
));

/* [170s] PERCENT */
named!(pub percent<&str, &str>, verify!(
    take_s!(3),
    |val:&str| {
        let bytes = val.as_bytes();
        bytes[0] == 0x25 && is_hex_digit(bytes[1]) && is_hex_digit(bytes[2])
    }
));

#[cfg(test)]
mod test {
    use super::*;
    use nom::IResult;

    #[test]
    fn decimal_normal_test() {
        let input    = "-1234.5678rest";
        let expected = IResult::Done("rest", Decimal{
            sign:          Some("-"),
            integer_part:  "1234",
            decimal_point: ".",
            decimal_part:  "5678",
        });
        assert_eq!(decimal(input), expected);
    }

    #[test]
    fn double_normal_test() {
        let input    = "-1234.5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("-"),
            mantissa: Mantissa::IntegerDecimal {
                integer_part:  "1234",
                decimal_point: ".",
                decimal_part:  "5678",
            },
            exponent: Exponent {
                exponent_symbol: "e",
                sign:            Some("-"),
                exponent_number: "0123456789",
            },
        });
        assert_eq!(double(input), expected);

        let input    = "-.5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("-"),
            mantissa: Mantissa::Decimal {
                decimal_point: ".",
                decimal_part:  "5678",
            },
            exponent: Exponent {
                exponent_symbol: "e",
                sign:            Some("-"),
                exponent_number: "0123456789",
            },
        });
        assert_eq!(double(input), expected);

        let input    = "+5678e-0123456789rest";
        let expected = IResult::Done("rest", Double{
            sign:     Some("+"),
            mantissa: Mantissa::Integer {
                integer_part: "5678",
            },
            exponent: Exponent {
                exponent_symbol: "e",
                sign:            Some("-"),
                exponent_number: "0123456789",
            },
        });
        assert_eq!(double(input), expected);
    }

    #[test]
    fn exponent_normal_test() {
        let input    = "e-0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "e",
            sign:            Some("-"),
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);

        let input    = "E+0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "E",
            sign:            Some("+"),
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);

        let input    = "e0123456789rest";
        let expected = IResult::Done("rest", Exponent{
            exponent_symbol: "e",
            sign:            None,
            exponent_number: "0123456789",
        });
        assert_eq!(exponent(input), expected);
    }

    #[test]
    fn ws_test() {
        assert_eq!(ws("   a"), IResult::Done("a", "   "));
    }

    #[test]
    fn anon_test() {
        assert_eq!(anon("[ ]a"), IResult::Done("a", "[ ]"));
    }

    #[test]
    fn percent_test() {
        assert_eq!(percent("%2Abc"), IResult::Done("bc", "%2A"));
    }
}
<|endoftext|>


<commit_before>use cgmath;
use character::controls::CharacterInputState;
use game::constants::ASPECT_RATIO;
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{Dimensions, load_texture};
use graphics::camera::CameraInputState;
use shaders::{Position, Projection, static_element_pipeline, VertexData};
use specs;
use specs::{Fetch, ReadStorage, WriteStorage};
use terrain_object::terrain_objects::TerrainObjects;

pub mod terrain_objects;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/static_element.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/static_element.f.glsl");

#[derive(Debug, Clone)]
pub struct TerrainObjectDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  offset_delta: Position,
}

impl TerrainObjectDrawable {
  pub fn new(position: cgmath::Point2<f32>) -> TerrainObjectDrawable {
    let view = Dimensions::get_view_matrix();
    TerrainObjectDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(75.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position: Position::new([position.x, position.y]),
      previous_position: Position::new([0.0, 0.0]),
      offset_delta: Position::new([0.0, 0.0]),
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new([ci.x_movement - self.previous_position.position[0], ci.y_movement - self.previous_position.position[1]]);

    self.previous_position = Position::new([
      ci.x_movement,
      ci.y_movement
    ]);

    self.position = Position::new([
      self.position.position[0] + offset_delta.position[0],
      self.position.position[1] + offset_delta.position[1],
    ]);
  }
}

impl specs::Component for TerrainObjectDrawable {
  type Storage = specs::VecStorage<TerrainObjectDrawable>;
}

pub struct TerrainObjectDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, static_element_pipeline::Data<R>>,
}

impl<R: gfx::Resources> TerrainObjectDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> TerrainObjectDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-120.0, -120.0, 0.0], [0.0, 1.0]),
        VertexData::new([120.0, -120.0, 0.0], [1.0, 1.0]),
        VertexData::new([120.0, 120.0, 0.0], [1.0, 0.0]),
        VertexData::new([-120.0, -120.0, 0.0], [0.0, 1.0]),
        VertexData::new([120.0, 120.0, 0.0], [1.0, 0.0]),
        VertexData::new([-120.0, 120.0, 0.0], [0.0, 0.0]),
      ];

    let house_bytes = &include_bytes!("../../assets/maps/house.png")[..];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, ());

    let terrain_object_texture = load_texture(factory, house_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              static_element_pipeline::new())
      .unwrap();

    let pipeline_data = static_element_pipeline::Data {
      vbuf: vertex_buf,
      position_cb: factory.create_constant_buffer(1),
      projection_cb: factory.create_constant_buffer(1),
      static_element_sheet: (terrain_object_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    TerrainObjectDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
    }
  }

  pub fn draw<C>(&self,
                 drawable: &TerrainObjectDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::System<'a> for PreDrawSystem {
  type SystemData = (ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     WriteStorage<'a, TerrainObjects>,
                     Fetch<'a, Dimensions>);

  fn run(&mut self, (camera_input, character_input, mut terrain_objects, dim): Self::SystemData) {
    use specs::Join;

    for (camera, ci, obj) in (&camera_input, &character_input, &mut terrain_objects).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for o in &mut obj.objects {
        o.update(&world_to_clip, ci);
      }
    }
  }
}
<commit_msg>Add index data to terrain objects<commit_after>use cgmath;
use character::controls::CharacterInputState;
use game::constants::ASPECT_RATIO;
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{Dimensions, load_texture};
use graphics::camera::CameraInputState;
use shaders::{Position, Projection, static_element_pipeline, VertexData};
use specs;
use specs::{Fetch, ReadStorage, WriteStorage};
use terrain_object::terrain_objects::TerrainObjects;

pub mod terrain_objects;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/static_element.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/static_element.f.glsl");

#[derive(Debug, Clone)]
pub struct TerrainObjectDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  offset_delta: Position,
}

impl TerrainObjectDrawable {
  pub fn new(position: cgmath::Point2<f32>) -> TerrainObjectDrawable {
    let view = Dimensions::get_view_matrix();
    TerrainObjectDrawable {
      projection: Projection {
        model: view.into(),
        view: view.into(),
        proj: cgmath::perspective(cgmath::Deg(75.0f32), ASPECT_RATIO, 0.1, 4000.0).into(),
      },
      position: Position::new([position.x, position.y]),
      previous_position: Position::new([0.0, 0.0]),
      offset_delta: Position::new([0.0, 0.0]),
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new([ci.x_movement - self.previous_position.position[0], ci.y_movement - self.previous_position.position[1]]);

    self.previous_position = Position::new([
      ci.x_movement,
      ci.y_movement
    ]);

    self.position = Position::new([
      self.position.position[0] + offset_delta.position[0],
      self.position.position[1] + offset_delta.position[1],
    ]);
  }
}

impl specs::Component for TerrainObjectDrawable {
  type Storage = specs::VecStorage<TerrainObjectDrawable>;
}

pub struct TerrainObjectDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, static_element_pipeline::Data<R>>,
}

impl<R: gfx::Resources> TerrainObjectDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> TerrainObjectDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let vertex_data: Vec<VertexData> =
      vec![
        VertexData::new([-120.0, -120.0, 0.0], [0.0, 1.0]),
        VertexData::new([120.0, -120.0, 0.0], [1.0, 1.0]),
        VertexData::new([120.0, 120.0, 0.0], [1.0, 0.0]),
        VertexData::new([-120.0, 120.0, 0.0], [0.0, 0.0]),
      ];

    let index_data: [u16; 6] = [0, 1, 2, 2, 3, 0];

    let house_bytes = &include_bytes!("../../assets/maps/house.png")[..];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data, &index_data[..]);

    let terrain_object_texture = load_texture(factory, house_bytes).unwrap();

    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              static_element_pipeline::new())
      .unwrap();

    let pipeline_data = static_element_pipeline::Data {
      vbuf: vertex_buf,
      position_cb: factory.create_constant_buffer(1),
      projection_cb: factory.create_constant_buffer(1),
      static_element_sheet: (terrain_object_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    TerrainObjectDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
    }
  }

  pub fn draw<C>(&self,
                 drawable: &TerrainObjectDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::System<'a> for PreDrawSystem {
  type SystemData = (ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     WriteStorage<'a, TerrainObjects>,
                     Fetch<'a, Dimensions>);

  fn run(&mut self, (camera_input, character_input, mut terrain_objects, dim): Self::SystemData) {
    use specs::Join;

    for (camera, ci, obj) in (&camera_input, &character_input, &mut terrain_objects).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for o in &mut obj.objects {
        o.update(&world_to_clip, ci);
      }
    }
  }
}
<|endoftext|>


<commit_before>use std::collections::LinkedList;
use std::mem;
use std::thread;
use std::time::{Duration, Instant};

use glium::backend::glutin_backend::GlutinFacade;
use glium::buffer::Content;
use glium::glutin::{ElementState, Event, VirtualKeyCode as KeyCode};
use glium::{self, Surface, VertexBuffer};

use graphics_gl::{TextBlitter, Vert2};
use input::Input;
use units::V2;

static BASIC_VRT: &'static str = include_str!("shaders/basic.v.glsl");
static BASIC_FRG: &'static str = include_str!("shaders/basic.f.glsl");

static MAX_VERTS: usize = 256;

/// Represents a mouse-input sample from some brush
struct ControlPoint {
    screen_xy: V2,
}

pub struct Engine {
    is_running: bool,

    context:    GlutinFacade,
    controller: Input,
}

impl Engine {
    pub fn new(gl_ctx: GlutinFacade) -> Engine {
        Engine {
            is_running: true,

            context:    gl_ctx,
            controller: Input::new(),
        }
    }

    pub fn run(&mut self) {
        let target_fps_ms = Duration::from_millis(1000 / 120); // TODO: const fn?
        let game_start_at = Instant::now();

        let mut frame_start_at;
        let mut elapsed_time;

        // draw a basic shape using standard shader
        let shape = vec![
            // face 1
            Vert2 { pos: [ 1.0,  0.0, 0.0], color: [1.0, 0.0, 0.0] },
            Vert2 { pos: [ 0.0,  0.0, 0.0], color: [1.0, 0.0, 0.0] },
            Vert2 { pos: [ 0.0, -1.0, 0.0], color: [1.0, 0.0, 0.0] },
        ];

        let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
        let mut vbuf = glium::VertexBuffer::empty_dynamic(&self.context, MAX_VERTS)
            .ok().expect("could not alloc vbuf");

        let program = match glium::Program::from_source(&self.context, BASIC_VRT, BASIC_FRG, None) {
            Ok(program) => program,
            Err(msg) => panic!("could not load shader: {}", msg),
        };

        // current cursor state
        let mut cursor_x = 0;
        let mut cursor_y = 0;

        // control point buffers
        let mut input_buffers = vec![];
        let mut input_samples = LinkedList::new();
        let mut cursor_commit = true;
        let mut cursor_down   = false;

        // text renedring
        let text_blitter = TextBlitter::new(&mut self.context);
        let mut text_count  = 0;
        let mut frame_count = 0;
        let mut text_scale  = 0.0;

        while self.is_running {
            // cut new frame
            frame_start_at = Instant::now();
            self.controller.begin_new_frame();

            // process platform events
            for evt in self.context.poll_events() {
                match evt {
                    Event::Closed => self.is_running = false,
                    Event::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                        self.controller.key_down_event(key);
                    },

                    Event::KeyboardInput(ElementState::Released, _, Some(key)) => {
                        self.controller.key_up_event(key);
                    },

                    Event::MouseInput(ElementState::Pressed,  _)  => {
                        cursor_down = true;
                        cursor_commit = false;
                    },

                    Event::MouseInput(ElementState::Released, _)  => cursor_down = false,

                    Event::MouseMoved(x,y) => { cursor_x = x; cursor_y = y },

                    _ => (),
                }
            }

            // TODO: (?) deduplicate input against last input?
            // store user input into control point buffers
            let (wx, wy) = Engine::world_to_unit(cursor_x as f64, cursor_y as f64);
            if cursor_down {
                input_samples.push_front(ControlPoint {
                    screen_xy: V2(cursor_x as i64, cursor_y as i64),
                });
            } else if !cursor_down && !cursor_commit {
                // swap the input buffer with a fresh one
                let mut input_buf = LinkedList::new();
                mem::swap(&mut input_samples, &mut input_buf);

                // commit the dirty one to heap
                input_buffers.push(input_buf);
                cursor_commit = true;
            }

            if self.controller.was_key_pressed(KeyCode::Escape) {
                self.is_running = false;
            }

            if self.controller.was_key_pressed(KeyCode::Up) {
                text_scale += 0.05;
            } else if self.controller.was_key_pressed(KeyCode::Down) {
                text_scale -= 0.05;
            }

            // composite frame
            let mut target = self.context.draw();
            target.clear_color(0.05, 0.05, 0.05, 1.0);

            let tri_params = glium::DrawParameters {
                .. Default::default()
            };

            let mut time_ms = 0.0;
            let time = Instant::now().duration_since(game_start_at);
            time_ms += time.as_secs() as f64 * 1000.0;
            time_ms += time.subsec_nanos() as f64 * 0.001 * 0.001;

            frame_count += 1;
            if frame_count > 10 {
                frame_count = 0;
                text_count = (text_count + 1) % 0xFF;
            }

            // TODO: helper for this
            // strlen =>  (char width * text length) * scale
            let text_out = format!("debug mode 0x{:02X}", text_count);

            // the text size is
            // (why /128 and not /256 ???)
            // char width: 16 * (aspect correction) / 128
            // * num chars
            // * scale of text
            //
            let strlen =
                ((16.0 * (720.0 / 1280.0)) / 128.0)
                * text_out.len() as f32
                * text_scale;

                // ((16.0 / 128.0) * text_out.len() as f32) * text_scale;
            text_blitter.draw(&text_out[..], text_scale, (1.0 - strlen, 1.0), &mut target);

            // draw control points
            {
                // vbuf.invalidate();
                let mut writer = vbuf.map_write();
                writer.set(0, Vert2 { pos: [-1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(1, Vert2 { pos: [-1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(2, Vert2 { pos: [ 1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });

                writer.set(3, Vert2 { pos: [ 1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(4, Vert2 { pos: [ 1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(5, Vert2 { pos: [-1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
            }

            // for each path draw control point there
            for path in input_buffers.iter() {
                // inflate each control point to six verts
                for point in path.iter() {
                    let (wx, wy) = Engine::world_to_unit(point.screen_xy.0 as f64,
                                                         point.screen_xy.1 as f64);

                    let path_uni = uniform! {
                        ofs:   [wx as f32, wy as f32, 0.0f32],
                        scale: 0.05f32,
                        timer: time_ms as f32 * 0.001,
                    };

                    target.draw(&vbuf, &indices, &program, &path_uni, &tri_params)
                        .ok().expect("could not blit cursor example");
                }
            }

            // draw cursor
            let cursor_uni = uniform! {
                ofs:   [wx as f32, wy as f32, 0.0f32],
                scale: 0.15f32,
                timer: time_ms as f32 * 0.001,
            };

            {
                vbuf.invalidate();
                let mut writer = vbuf.map_write();
                for (idx, vert) in shape.iter().enumerate() {
                    println!("draw {} {:?}", idx, vert);
                    writer.set(idx, *vert);
                }
            }

            target.draw(&vbuf, &indices, &program, &cursor_uni, &tri_params)
                .ok().expect("could not blit cursor example");

            target.finish()
                .ok().expect("could not render frame");

            // sleep for a bit if we made our deadline
            elapsed_time = frame_start_at.elapsed();
            let sleep_time = if elapsed_time > target_fps_ms {
                Duration::from_millis(0)
            } else { target_fps_ms - elapsed_time };

            thread::sleep(sleep_time);
        }
    }

    fn world_to_unit(x: f64, y: f64) -> (f64, f64) {
        let adj_x = x / 640.0;
        let adj_y = y / 360.0;
        ( (adj_x - 1.0), -(adj_y - 1.0) )
    }
}
<commit_msg>don't reuse vertex buffer for cursor<commit_after>use std::collections::LinkedList;
use std::mem;
use std::thread;
use std::time::{Duration, Instant};

use glium::backend::glutin_backend::GlutinFacade;
use glium::buffer::Content;
use glium::glutin::{ElementState, Event, VirtualKeyCode as KeyCode};
use glium::{self, Surface, VertexBuffer};

use graphics_gl::{TextBlitter, Vert2};
use input::Input;
use units::V2;

static BASIC_VRT: &'static str = include_str!("shaders/basic.v.glsl");
static BASIC_FRG: &'static str = include_str!("shaders/basic.f.glsl");

static MAX_VERTS: usize = 256;

/// Represents a mouse-input sample from some brush
struct ControlPoint {
    screen_xy: V2,
}

pub struct Engine {
    is_running: bool,

    context:    GlutinFacade,
    controller: Input,
}

impl Engine {
    pub fn new(gl_ctx: GlutinFacade) -> Engine {
        Engine {
            is_running: true,

            context:    gl_ctx,
            controller: Input::new(),
        }
    }

    pub fn run(&mut self) {
        let target_fps_ms = Duration::from_millis(1000 / 120); // TODO: const fn?
        let game_start_at = Instant::now();

        let mut frame_start_at;
        let mut elapsed_time;

        // draw a basic shape using standard shader
        let shape = vec![
            // face 1
            Vert2 { pos: [ 1.0,  0.0, 0.0], color: [1.0, 0.0, 0.0] },
            Vert2 { pos: [ 0.0,  0.0, 0.0], color: [1.0, 0.0, 0.0] },
            Vert2 { pos: [ 0.0, -1.0, 0.0], color: [1.0, 0.0, 0.0] },
        ];

        let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);

        let mut vbuf_cursor = glium::VertexBuffer::new(&self.context, &shape[..])
            .ok().expect("could not alloc vbuf");

        let mut vbuf_points = glium::VertexBuffer::empty_dynamic(&self.context, MAX_VERTS)
            .ok().expect("could not alloc vbuf");

        let program = match glium::Program::from_source(&self.context, BASIC_VRT, BASIC_FRG, None) {
            Ok(program) => program,
            Err(msg) => panic!("could not load shader: {}", msg),
        };

        // current cursor state
        let mut cursor_x = 0;
        let mut cursor_y = 0;

        // control point buffers
        let mut input_buffers = vec![];
        let mut input_samples = LinkedList::new();
        let mut cursor_commit = true;
        let mut cursor_down   = false;

        // text renedring
        let text_blitter = TextBlitter::new(&mut self.context);
        let mut text_count  = 0;
        let mut frame_count = 0;
        let mut text_scale  = 0.0;

        while self.is_running {
            // cut new frame
            frame_start_at = Instant::now();
            self.controller.begin_new_frame();

            // process platform events
            for evt in self.context.poll_events() {
                match evt {
                    Event::Closed => self.is_running = false,
                    Event::KeyboardInput(ElementState::Pressed, _, Some(key)) => {
                        self.controller.key_down_event(key);
                    },

                    Event::KeyboardInput(ElementState::Released, _, Some(key)) => {
                        self.controller.key_up_event(key);
                    },

                    Event::MouseInput(ElementState::Pressed,  _)  => {
                        cursor_down = true;
                        cursor_commit = false;
                    },

                    Event::MouseInput(ElementState::Released, _)  => cursor_down = false,

                    Event::MouseMoved(x,y) => { cursor_x = x; cursor_y = y },

                    _ => (),
                }
            }

            // TODO: (?) deduplicate input against last input?
            // store user input into control point buffers
            let (wx, wy) = Engine::world_to_unit(cursor_x as f64, cursor_y as f64);
            if cursor_down {
                input_samples.push_front(ControlPoint {
                    screen_xy: V2(cursor_x as i64, cursor_y as i64),
                });
            } else if !cursor_down && !cursor_commit {
                // swap the input buffer with a fresh one
                let mut input_buf = LinkedList::new();
                mem::swap(&mut input_samples, &mut input_buf);

                // commit the dirty one to heap
                input_buffers.push(input_buf);
                cursor_commit = true;
            }

            if self.controller.was_key_pressed(KeyCode::Escape) {
                self.is_running = false;
            }

            if self.controller.was_key_pressed(KeyCode::Up) {
                text_scale += 0.05;
            } else if self.controller.was_key_pressed(KeyCode::Down) {
                text_scale -= 0.05;
            }

            // composite frame
            let mut target = self.context.draw();
            target.clear_color(0.05, 0.05, 0.05, 1.0);

            let tri_params = glium::DrawParameters {
                .. Default::default()
            };

            let mut time_ms = 0.0;
            let time = Instant::now().duration_since(game_start_at);
            time_ms += time.as_secs() as f64 * 1000.0;
            time_ms += time.subsec_nanos() as f64 * 0.001 * 0.001;

            frame_count += 1;
            if frame_count > 10 {
                frame_count = 0;
                text_count = (text_count + 1) % 0xFF;
            }

            // TODO: helper for this
            // strlen =>  (char width * text length) * scale
            let text_out = format!("debug mode 0x{:02X}", text_count);

            // the text size is
            // (why /128 and not /256 ???)
            // char width: 16 * (aspect correction) / 128
            // * num chars
            // * scale of text
            //
            let strlen =
                ((16.0 * (720.0 / 1280.0)) / 128.0)
                * text_out.len() as f32
                * text_scale;

                // ((16.0 / 128.0) * text_out.len() as f32) * text_scale;
            text_blitter.draw(&text_out[..], text_scale, (1.0 - strlen, 1.0), &mut target);

            // draw cursor
            let cursor_uni = uniform! {
                ofs:   [wx as f32, wy as f32, 0.0f32],
                scale: 0.15f32,
                timer: time_ms as f32 * 0.001,
            };

            target.draw(&vbuf_cursor, &indices, &program, &cursor_uni, &tri_params)
                .ok().expect("could not blit cursor example");

            // draw control points
            {
                // vbuf.invalidate();
                let mut writer = vbuf_points.map_write();
                writer.set(0, Vert2 { pos: [-1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(1, Vert2 { pos: [-1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(2, Vert2 { pos: [ 1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });

                writer.set(3, Vert2 { pos: [ 1.0,  1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(4, Vert2 { pos: [ 1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
                writer.set(5, Vert2 { pos: [-1.0, -1.0,  0.0], color: [1.0, 0.0, 1.0] });
            }

            // for each path draw control point there
            for path in input_buffers.iter() {
                // inflate each control point to six verts
                for point in path.iter() {
                    let (wx, wy) = Engine::world_to_unit(point.screen_xy.0 as f64,
                                                         point.screen_xy.1 as f64);

                    let path_uni = uniform! {
                        ofs:   [wx as f32, wy as f32, 0.0f32],
                        scale: 0.05f32,
                        timer: time_ms as f32 * 0.001,
                    };

                    target.draw(&vbuf_points, &indices, &program, &path_uni, &tri_params)
                        .ok().expect("could not blit cursor example");
                }
            }

            target.finish()
                .ok().expect("could not render frame");

            // sleep for a bit if we made our deadline
            elapsed_time = frame_start_at.elapsed();
            let sleep_time = if elapsed_time > target_fps_ms {
                Duration::from_millis(0)
            } else { target_fps_ms - elapsed_time };

            thread::sleep(sleep_time);
        }
    }

    fn world_to_unit(x: f64, y: f64) -> (f64, f64) {
        let adj_x = x / 640.0;
        let adj_y = y / 360.0;
        ( (adj_x - 1.0), -(adj_y - 1.0) )
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::thread;
use std::net::{TcpListener, ToSocketAddrs};
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver
};

use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT);

pub fn begin<T, K>(address: T, handler: Box<K>) where
    T: ToSocketAddrs + Send + 'static,
    K: EventHandler + Send + Sync + 'static {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sockets1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(*handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sockets1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let sockets2 = sockets.clone();
    let prox = thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            listen(address, epfd3, sockets2);
        }).unwrap();

    // Stay alive forever
    let _ = prox.join();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                trace!("New connection received");
                // Create new socket
                match NbetStream::new(stream) {
                    Ok(nb_stream) => {
                        let socket = Socket::new(nb_stream);
                        let socket_ptr;
                        // Add to master list
                        { // Begin Mutex lock
                            let mut guard = match sockets.lock() {
                                Ok(guard) => guard,
                                Err(poisoned) => {
                                    warn!("SocketList Mutex failed, using anyway...");
                                    poisoned.into_inner()
                                }
                            };
                            let socket_list = guard.deref_mut();
                            socket_list.push_back(socket.clone());
                            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
                        } // End Mutex lock

                        // Add to epoll
                        let sfd = socket.raw_fd();
                        let mut event = EpollEvent {
                            data: socket_ptr as u64,
                            events: EVENTS
                        };
                        match epoll::ctl(epfd, ctl_op::ADD, sfd, &mut event) {
                            Ok(()) => {
                                trace!("New socket added to epoll list");
                                trace!("socket.id: {}", socket.id());
                                trace!("epfd: {}", epfd);
                                trace!("fd: {}", sfd);
                            },
                            Err(e) => warn!("Epoll CtrlError during add: {}", e)
                        };
                    }
                    Err(e) => warn!("Error creating nbstream: {}", e)
                }
            }
            Err(e) => warn!("Error encountered during TCP connection: {}", e)
        }
    }
    drop(listener);
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // Maximum number of events we want to be notified of at one time
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe { events.set_len(100); }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    let _ = tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Get a pointer to the socket in the list
        let socket;
        { // Begin Mutex lock
            let _ = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            socket = event.data as *mut Socket;
        } // End Mutex lock

        if (event.events & DROP_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socketfd = unsafe { (*socket).raw_fd() };
            let socketid = unsafe { (*socket).id() };

            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socketid, socket_list.clone());
                { // EventHandler Mutex locked
                    let mut guard = match t_handler.lock() {
                        Ok(guard) => guard,
                        Err(poisoned) => {
                            warn!("EventHandler Mutex failed, using anyway...");
                            poisoned.into_inner()
                        }
                    };
                    let e_handler = guard.deref_mut();
                    e_handler.on_socket_closed(socketid);
                } // EventHandler Mutex unlocked
            });
        } else if (event.events & READ_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let mut s_clone = unsafe { (*socket).clone() };
            let socketfd = s_clone.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socket_ptr = socket as u64;

            trace!("fd test...");
            trace!("c1.fd: {}", s_clone.raw_fd());

            let c2 = s_clone.clone();
            trace!("c2.fd: {}", c2.raw_fd());

            pool.run(move || {
                match s_clone.read() {
                    Ok(_) => {
                        for msg in s_clone.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // EventHandler Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("EventHandler Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(s_clone.clone(),
                                    socket_list.clone(), msg.clone());
                            } // EventHandler Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());

                            // Add socket's fd back to epoll watch list
                            let mut event = EpollEvent {
                                data: socket_ptr,
                                events: EVENTS
                            };
                            let s_id = s_clone.id();
                            match epoll::ctl(t_epfd.clone(), ctl_op::MOD, socketfd, &mut event) {
                                Ok(_) => trace!("Socket back in epoll list"),
                                Err(e) => {
                                    warn!("Epoll CtrlError during mod: {}", e);
                                    warn!("s.id: {}", s_id);
                                    warn!("epfd: {}", t_epfd.clone());
                                    warn!("fd: {}", socketfd);
                                }
                            };
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        let s_id = s_clone.id();
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(s_id, socket_list.clone());
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(s_id);
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("remove_socket_from_epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
    // before 2.6.9 should specify a non-null pointer in event.
    let mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds are duplicated with .clone(), this may fail.
    //
    // If the failure case is CtlError::ENOENT, we do not care, because
    // epoll will clean the up the descriptor after they are all dropped from
    // program memory
    match epoll::ctl(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket_id: u32, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

    let mut s_found = false;
    let mut index = 1usize;
    for s in s_list.iter() {
        if s.id() == socket_id {
            s_found = true;
            break;
        }
        index += 1;
    }

    if !s_found { return; }

    if index == 1 {
        s_list.pop_front();
    } else {
        let mut split = s_list.split_off(index - 1);
        split.pop_front();
        s_list.append(&mut split);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<commit_msg>Stupid F_DUPFD flag<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was not
// distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.

use std::thread;
use std::net::{TcpListener, ToSocketAddrs};
use std::ops::DerefMut;
use std::os::unix::io::RawFd;
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{
    channel,
    Sender,
    Receiver
};

use epoll;
use epoll::util::*;
use epoll::EpollEvent;
use simple_stream::nbetstream::NbetStream;
use stats;
use types::*;
use socket::Socket;
use resources::ResourcePool;

// When added to epoll, these will be the conditions of kernel notification:
//
// EPOLLIN      - Available for read
// EPOLLRDHUP   - Connection has been closed
// EPOLLONESHOT - After an event has been received, and reported, do not track
//                further changes until explicitly told to do so.
const EVENTS: u32 = (
    event_type::EPOLLET | // Set fd to EdgeTrigger mode
    event_type::EPOLLIN |
    event_type::EPOLLRDHUP |
    event_type::EPOLLONESHOT);

pub fn begin<T, K>(address: T, handler: Box<K>) where
    T: ToSocketAddrs + Send + 'static,
    K: EventHandler + Send + Sync + 'static {
    // Master socket list
    let sockets = Arc::new(Mutex::new(LinkedList::<Socket>::new()));

    // Epoll instance
    let result = epoll::create1(0);
    if result.is_err() {
        let err = result.unwrap_err();
        error!("Unable to create epoll instance: {}", err);
        panic!()
    }
    let epfd = result.unwrap();

    // EpollEvent handler thread
    let epfd1 = epfd.clone();
    let sockets1 = sockets.clone();
    let (tx_ep_event, rx_ep_event): (Sender<EpollEvent>, Receiver<EpollEvent>) = channel();
    let safe_handler = Arc::new(Mutex::new(*handler));
    thread::Builder::new()
        .name("EpollEvent Handler".to_string())
        .spawn(move || {
            epoll_event_handler(epfd1, rx_ep_event, sockets1, safe_handler);
        }).unwrap();

    // Epoll wait thread
    let epfd2 = epfd.clone();
    thread::Builder::new()
        .name("Epoll Wait".to_string())
        .spawn(move || {
            epoll_wait_loop(epfd2, tx_ep_event);
        }).unwrap();

    // New connection thread
    let epfd3 = epfd.clone();
    let sockets2 = sockets.clone();
    let prox = thread::Builder::new()
        .name("TCP Incoming Listener".to_string())
        .spawn(move || {
            listen(address, epfd3, sockets2);
        }).unwrap();

    // Stay alive forever
    let _ = prox.join();
}

fn listen<T: ToSocketAddrs>(address: T, epfd: RawFd, sockets: SocketList) {
    let listener = TcpListener::bind(address).unwrap();
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                trace!("New connection received");
                // Create new socket
                match NbetStream::new(stream) {
                    Ok(nb_stream) => {
                        let socket = Socket::new(nb_stream);
                        let socket_ptr;
                        // Add to master list
                        { // Begin Mutex lock
                            let mut guard = match sockets.lock() {
                                Ok(guard) => guard,
                                Err(poisoned) => {
                                    warn!("SocketList Mutex failed, using anyway...");
                                    poisoned.into_inner()
                                }
                            };
                            let socket_list = guard.deref_mut();
                            socket_list.push_back(socket.clone());
                            socket_ptr = socket_list.back_mut().unwrap() as *mut Socket;
                        } // End Mutex lock

                        // Add to epoll
                        let sfd = socket.raw_fd();
                        let mut event = EpollEvent {
                            data: socket_ptr as u64,
                            events: EVENTS
                        };
                        match epoll::ctl(epfd, ctl_op::ADD, sfd, &mut event) {
                            Ok(()) => {
                                trace!("New socket added to epoll list");
                                trace!("socket.id: {}", socket.id());
                                trace!("epfd: {}", epfd);
                                trace!("fd: {}", sfd);
                            },
                            Err(e) => warn!("Epoll CtrlError during add: {}", e)
                        };
                    }
                    Err(e) => warn!("Error creating nbstream: {}", e)
                }
            }
            Err(e) => warn!("Error encountered during TCP connection: {}", e)
        }
    }
    drop(listener);
}

fn epoll_wait_loop(epfd: RawFd, tx_handler: Sender<EpollEvent>) {
    // Maximum number of events we want to be notified of at one time
    let mut events = Vec::<EpollEvent>::with_capacity(100);
    unsafe { events.set_len(100); }

    loop {
        match epoll::wait(epfd, &mut events[..], -1) {
            Ok(num_events) => {
                for x in 0..num_events as usize {
                    let _ = tx_handler.send(events[x]);
                }
            }
            Err(e) => {
                error!("Error on epoll::wait(): {}", e);
                panic!()
            }
        }
    }
}

fn epoll_event_handler(epfd: RawFd,
                       rx: Receiver<EpollEvent>,
                       sockets: SocketList,
                       handler: SafeHandler) {
    // Types of events we care about
    const READ_EVENT: u32 = event_type::EPOLLIN;
    const DROP_EVENT: u32 = event_type::EPOLLRDHUP | event_type::EPOLLHUP;

    // Thread pool
    let mut pool = ResourcePool::new();

    for event in rx.iter() {
        // Get a pointer to the socket in the list
        let socket;
        { // Begin Mutex lock
            let _ = match sockets.lock() {
                Ok(guard) => guard,
                Err(poisoned) => {
                    warn!("SocketList Mutex failed, using anyway...");
                    poisoned.into_inner()
                }
            };
            socket = event.data as *mut Socket;
        } // End Mutex lock

        if (event.events & DROP_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socketfd = unsafe { (*socket).raw_fd() };
            let socketid = unsafe { (*socket).id() };

            pool.run(move || {
                epoll_remove_fd(t_epfd, socketfd);
                remove_socket_from_list(socketid, socket_list.clone());
                { // EventHandler Mutex locked
                    let mut guard = match t_handler.lock() {
                        Ok(guard) => guard,
                        Err(poisoned) => {
                            warn!("EventHandler Mutex failed, using anyway...");
                            poisoned.into_inner()
                        }
                    };
                    let e_handler = guard.deref_mut();
                    e_handler.on_socket_closed(socketid);
                } // EventHandler Mutex unlocked
            });
        } else if (event.events & READ_EVENT) > 0 {
            let t_epfd = epfd.clone();
            let mut s_clone = unsafe { (*socket).clone() };
            let socketfd = s_clone.raw_fd();
            let socket_list = sockets.clone();
            let t_handler = handler.clone();
            let socket_ptr = socket as u64;

            trace!("fd test...");
            trace!("c1.fd: {}", s_clone.raw_fd());

            let c2 = s_clone.clone();
            trace!("c2.fd: {}", c2.raw_fd());

            // Rust's TcpStream clone method makes use of the F_DUPFD flag for duplicating
            // file descriptors. This means the fd we currently have associated for this
            // stream is now worthless within epoll, and why we're grabbing it off of a raw
            // pointer dereference. Instead of setting it back to listening with ctl::MOD,
            // we'll remove it and add the new file descriptor given from the system.
            let orig_fd = unsafe { (*socket).raw_fd() };

            // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
            // a non-null pointer in event, even though this argument is ignored.
            // Since Linux 2.6.9, event can be specified as NULL when using
            // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
            // before 2.6.9 should specify a non-null pointer in event.
            let mut event = EpollEvent {
                data: 0u64,
                events: 0u32
            };
            match epoll::ctl(t_epfd.clone(), ctl_op::DEL, orig_fd, &mut event) {
                Ok(_) => trace!("Socket removed from epoll list"),
                Err(e) => {
                    warn!("Epoll CtrlError during mod: {}", e);
                    warn!("s.id: {}", unsafe { (*socket).id() });
                    warn!("epfd: {}", t_epfd.clone());
                    warn!("fd: {}", socketfd);
                }
            };

            pool.run(move || {
                match s_clone.read() {
                    Ok(_) => {
                        for msg in s_clone.buffer().iter() {
                            let debug_msg = msg.clone();
                            match String::from_utf8(debug_msg) {
                                Ok(msg_str) => trace!("msg: {}", msg_str),
                                Err(_) => trace!("msg not UTF-8")
                            };

                            { // EventHandler Mutex locked
                                let mut guard = match t_handler.lock() {
                                    Ok(guard) => guard,
                                    Err(poisoned) => {
                                        warn!("EventHandler Mutex failed, using anyway...");
                                        poisoned.into_inner()
                                    }
                                };
                                let e_handler = guard.deref_mut();
                                e_handler.on_data_received(s_clone.clone(),
                                    socket_list.clone(), msg.clone());
                            } // EventHandler Mutex unlocked

                            // Track message received event and num bytes received
                            stats::msg_recv();
                            stats::bytes_recv(msg.len());

                            // Add socket's fd back to epoll watch list
                            let mut event = EpollEvent {
                                data: socket_ptr,
                                events: EVENTS
                            };
                            let s_id = s_clone.id();
                            match epoll::ctl(t_epfd.clone(), ctl_op::ADD, socketfd, &mut event) {
                                Ok(_) => trace!("Socket back in epoll list"),
                                Err(e) => {
                                    warn!("Epoll CtrlError during mod: {}", e);
                                    warn!("s.id: {}", s_id);
                                    warn!("epfd: {}", t_epfd.clone());
                                    warn!("fd: {}", socketfd);
                                }
                            };
                        }
                    }
                    Err(e) => {
                        debug!("Error reading socket: {}", e);
                        // We really don't care what happened, it all results in the same
                        // outcome - remove the socket from system...
                        let s_id = s_clone.id();
                        epoll_remove_fd(t_epfd, socketfd);
                        remove_socket_from_list(s_id, socket_list.clone());
                        let mut guard = match t_handler.lock() {
                            Ok(guard) => guard,
                            Err(poisoned) => {
                                warn!("SocketList Mutex failed, using anyway...");
                                poisoned.into_inner()
                            }
                        };
                        let e_handler = guard.deref_mut();
                        e_handler.on_socket_closed(s_id);
                    }
                };
            });
        } else { warn!("Unknown epoll event received: {}", event.data); continue; }
    }
}

fn epoll_remove_fd(epfd: RawFd, fd: RawFd) {
    debug!("remove_socket_from_epoll");

    // In kernel versions before 2.6.9, the EPOLL_CTL_DEL operation required
    // a non-null pointer in event, even though this argument is ignored.
    // Since Linux 2.6.9, event can be specified as NULL when using
    // EPOLL_CTL_DEL.  Applications that need to be portable to kernels
    // before 2.6.9 should specify a non-null pointer in event.
    let mut rm_event = EpollEvent {
        data: 0 as u64,
        events: 0 as u32
    };

    // Depending on how fds are duplicated with .clone(), this may fail.
    //
    // If the failure case is CtlError::ENOENT, we do not care, because
    // epoll will clean the up the descriptor after they are all dropped from
    // program memory
    match epoll::ctl(epfd, ctl_op::DEL, fd, &mut rm_event) {
        Ok(()) => trace!("Socket removed from epoll watch list"),
        Err(e) => {
            match e {
                CtlError::ENOENT => {
                    trace!("Fd not found in epoll, will remove when fd is syscall closed");
                }
                _ => warn!("Epoll CtrlError during del: {}", e)
            }
        }
    };
}

/// Removes socket_ids from master list
fn remove_socket_from_list(socket_id: u32, sockets: SocketList) {
    debug!("remove_socket_from_list");

    let mut s_guard = match sockets.lock() {
        Ok(guard) => guard,
        Err(poisoned) => {
            warn!("SocketList Mutex was poisoned, using anyway");
            poisoned.into_inner()
        }
    };
    let s_list = s_guard.deref_mut();

    let mut s_found = false;
    let mut index = 1usize;
    for s in s_list.iter() {
        if s.id() == socket_id {
            s_found = true;
            break;
        }
        index += 1;
    }

    if !s_found { return; }

    if index == 1 {
        s_list.pop_front();
    } else {
        let mut split = s_list.split_off(index - 1);
        split.pop_front();
        s_list.append(&mut split);
    }

    stats::conn_lost();

    trace!("socket removed from list");
}
<|endoftext|>


<commit_before>
use piston_window::*;

use ::game::window::GameWindow;
use ::game::block::Block;

const GRID_OFFSET: f64 = 20.0;
const TILE_SIZE: f64 = 29.0;

pub struct Grid {
    boxes: [[Block; 10]; 22],
}

impl Grid {
    pub fn new() -> Grid {
        Grid { boxes: [[Block::new([0.0, 0.0, 0.0, 1.0]); 10]; 22] }
    }

    pub fn render<G>(&self, context: Context, gfx: &mut G, e: &Event)
        where G: Graphics
    {
        for mut y in 2..22 {
            for mut x in 0..10 {
                let adjusted_y = y - 2;
                rectangle(self.boxes[y][x].color,
                          [x as f64 * TILE_SIZE + 10.0,
                           adjusted_y as f64 * TILE_SIZE + 10.0,
                           TILE_SIZE as f64,
                           TILE_SIZE as f64],
                          context.transform,
                          gfx);
            }
        }
    }
}<commit_msg>Made blocks optional<commit_after>
use piston_window::*;

use ::game::window::GameWindow;
use ::game::block::Block;

const GRID_OFFSET: f64 = 20.0;
const TILE_SIZE: f64 = 29.0;

pub struct Grid {
    boxes: [[Option<Block>; 10]; 22],
}

impl Grid {
    pub fn new() -> Grid {
        Grid { boxes: [[None; 10]; 22] }
    }

    pub fn render<G>(&self, context: Context, gfx: &mut G, e: &Event)
        where G: Graphics
    {
        for mut y in 2..22 {
            for mut x in 0..10 {
                let adjusted_y = y - 2;
                let color = match self.boxes[y][x] {
                    Some(ref block) => block.color,
                    None => [0.0, 0.0, 0.0, 1.0],
                };
                rectangle(color,
                          [x as f64 * TILE_SIZE + 10.0,
                           adjusted_y as f64 * TILE_SIZE + 10.0,
                           TILE_SIZE as f64,
                           TILE_SIZE as f64],
                          context.transform,
                          gfx);
            }
        }
    }
}<|endoftext|>


<commit_before>use super::*;

// crc: u32 4
// kind: u8 1
// seg num: u64 9 (varint)
// pid: u64 9 (varint)
// len: u64 9 (varint)
/// Log messages have a header that might eb up to this length.
pub const MAX_MSG_HEADER_LEN: usize = 32;

/// Log segments have a header of this length.
pub const SEG_HEADER_LEN: usize = 20;

/// During testing, this should never be exceeded.
#[allow(unused)]
pub const MAX_SPACE_AMPLIFICATION: f64 = 6.;

pub(crate) const META_PID: PageId = 0;
pub(crate) const COUNTER_PID: PageId = 1;
pub(crate) const BATCH_MANIFEST_PID: PageId = PageId::max_value() - 666;

pub(crate) const PAGE_CONSOLIDATION_THRESHOLD: usize = 10;
pub(crate) const SEGMENT_CLEANUP_THRESHOLD: usize = 50;

// Allows for around 1 trillion items to be stored
// 2^37 * (assuming 50% node fill, 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
#[cfg(target_pointer_width = "64")]
pub(crate) const MAX_PID_BITS: usize = 37;

// Allows for around 32 billion items to be stored
// 2^32 * (assuming 50% node fill of 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
// Assumed to be enough for a 32-bit system.
#[cfg(target_pointer_width = "32")]
pub(crate) const MAX_PID_BITS: usize = 32;
<commit_msg>Adjust space amp temporarily<commit_after>use super::*;

// crc: u32 4
// kind: u8 1
// seg num: u64 9 (varint)
// pid: u64 9 (varint)
// len: u64 9 (varint)
/// Log messages have a header that might eb up to this length.
pub const MAX_MSG_HEADER_LEN: usize = 32;

/// Log segments have a header of this length.
pub const SEG_HEADER_LEN: usize = 20;

/// During testing, this should never be exceeded.
// TODO drop this to 3 over time
#[allow(unused)]
pub const MAX_SPACE_AMPLIFICATION: f64 = 10.;

pub(crate) const META_PID: PageId = 0;
pub(crate) const COUNTER_PID: PageId = 1;
pub(crate) const BATCH_MANIFEST_PID: PageId = PageId::max_value() - 666;

pub(crate) const PAGE_CONSOLIDATION_THRESHOLD: usize = 10;
pub(crate) const SEGMENT_CLEANUP_THRESHOLD: usize = 50;

// Allows for around 1 trillion items to be stored
// 2^37 * (assuming 50% node fill, 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
#[cfg(target_pointer_width = "64")]
pub(crate) const MAX_PID_BITS: usize = 37;

// Allows for around 32 billion items to be stored
// 2^32 * (assuming 50% node fill of 8 items per leaf)
// and well below 1% of nodes being non-leaf nodes.
// Assumed to be enough for a 32-bit system.
#[cfg(target_pointer_width = "32")]
pub(crate) const MAX_PID_BITS: usize = 32;
<|endoftext|>