<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-emscripten no threads support

#![feature(const_fn)]
#![feature(rand)]
#![feature(sort_unstable)]

use std::__rand::{thread_rng, Rng};
use std::cell::Cell;
use std::cmp::Ordering;
use std::panic;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize};
use std::sync::atomic::Ordering::Relaxed;
use std::thread;

const MAX_LEN: usize = 80;

static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
    // FIXME #5244: AtomicUsize is not Copy.
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
];

static VERSIONS: AtomicUsize = ATOMIC_USIZE_INIT;

#[derive(Clone, Eq)]
struct DropCounter {
    x: u32,
    id: usize,
    version: Cell<usize>,
}

impl PartialEq for DropCounter {
    fn eq(&self, other: &Self) -> bool {
        self.partial_cmp(other) == Some(Ordering::Equal)
    }
}

impl PartialOrd for DropCounter {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.version.set(self.version.get() + 1);
        other.version.set(other.version.get() + 1);
        VERSIONS.fetch_add(2, Relaxed);
        self.x.partial_cmp(&other.x)
    }
}

impl Ord for DropCounter {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl Drop for DropCounter {
    fn drop(&mut self) {
        DROP_COUNTS[self.id].fetch_add(1, Relaxed);
        VERSIONS.fetch_sub(self.version.get(), Relaxed);
    }
}

macro_rules! test {
    ($input:ident, $func:ident) => {
        let len = $input.len();

        // Work out the total number of comparisons required to sort
        // this array...
        let mut count = 0usize;
        $input.to_owned().$func(|a, b| { count += 1; a.cmp(b) });

        // ... and then panic on each and every single one.
        for panic_countdown in 0..count {
            // Refresh the counters.
            VERSIONS.store(0, Relaxed);
            for i in 0..len {
                DROP_COUNTS[i].store(0, Relaxed);
            }

            let v = $input.to_owned();
            let _ = thread::spawn(move || {
                let mut v = v;
                let mut panic_countdown = panic_countdown;
                v.$func(|a, b| {
                    if panic_countdown == 0 {
                        SILENCE_PANIC.with(|s| s.set(true));
                        panic!();
                    }
                    panic_countdown -= 1;
                    a.cmp(b)
                })
            }).join();

            // Check that the number of things dropped is exactly
            // what we expect (i.e. the contents of `v`).
            for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
                let count = c.load(Relaxed);
                assert!(count == 1,
                        "found drop count == {} for i == {}, len == {}",
                        count, i, len);
            }

            // Check that the most recent versions of values were dropped.
            assert_eq!(VERSIONS.load(Relaxed), 0);
        }
    }
}

thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));

fn main() {
    let prev = panic::take_hook();
    panic::set_hook(Box::new(move |info| {
        if !SILENCE_PANIC.with(|s| s.get()) {
            prev(info);
        }
    }));

    for len in (1..20).chain(70..MAX_LEN) {
        for &modulus in &[5, 20, 50] {
            for &has_runs in &[false, true] {
                let mut rng = thread_rng();
                let mut input = (0..len)
                    .map(|id| {
                        DropCounter {
                            x: rng.next_u32() % modulus,
                            id: id,
                            version: Cell::new(0),
                        }
                    })
                    .collect::<Vec<_>>();

                if has_runs {
                    for c in &mut input {
                        c.x = c.id as u32;
                    }

                    for _ in 0..5 {
                        let a = rng.gen::<usize>() % len;
                        let b = rng.gen::<usize>() % len;
                        if a < b {
                            input[a..b].reverse();
                        } else {
                            input.swap(a, b);
                        }
                    }
                }

                test!(input, sort_by);
                test!(input, sort_unstable_by);
            }
        }
    }
}
<commit_msg>Move thread_rng() outside the loop<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-emscripten no threads support

#![feature(const_fn)]
#![feature(rand)]
#![feature(sort_unstable)]

use std::__rand::{thread_rng, Rng};
use std::cell::Cell;
use std::cmp::Ordering;
use std::panic;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize};
use std::sync::atomic::Ordering::Relaxed;
use std::thread;

const MAX_LEN: usize = 80;

static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [
    // FIXME #5244: AtomicUsize is not Copy.
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
    AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0),
];

static VERSIONS: AtomicUsize = ATOMIC_USIZE_INIT;

#[derive(Clone, Eq)]
struct DropCounter {
    x: u32,
    id: usize,
    version: Cell<usize>,
}

impl PartialEq for DropCounter {
    fn eq(&self, other: &Self) -> bool {
        self.partial_cmp(other) == Some(Ordering::Equal)
    }
}

impl PartialOrd for DropCounter {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.version.set(self.version.get() + 1);
        other.version.set(other.version.get() + 1);
        VERSIONS.fetch_add(2, Relaxed);
        self.x.partial_cmp(&other.x)
    }
}

impl Ord for DropCounter {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

impl Drop for DropCounter {
    fn drop(&mut self) {
        DROP_COUNTS[self.id].fetch_add(1, Relaxed);
        VERSIONS.fetch_sub(self.version.get(), Relaxed);
    }
}

macro_rules! test {
    ($input:ident, $func:ident) => {
        let len = $input.len();

        // Work out the total number of comparisons required to sort
        // this array...
        let mut count = 0usize;
        $input.to_owned().$func(|a, b| { count += 1; a.cmp(b) });

        // ... and then panic on each and every single one.
        for panic_countdown in 0..count {
            // Refresh the counters.
            VERSIONS.store(0, Relaxed);
            for i in 0..len {
                DROP_COUNTS[i].store(0, Relaxed);
            }

            let v = $input.to_owned();
            let _ = thread::spawn(move || {
                let mut v = v;
                let mut panic_countdown = panic_countdown;
                v.$func(|a, b| {
                    if panic_countdown == 0 {
                        SILENCE_PANIC.with(|s| s.set(true));
                        panic!();
                    }
                    panic_countdown -= 1;
                    a.cmp(b)
                })
            }).join();

            // Check that the number of things dropped is exactly
            // what we expect (i.e. the contents of `v`).
            for (i, c) in DROP_COUNTS.iter().enumerate().take(len) {
                let count = c.load(Relaxed);
                assert!(count == 1,
                        "found drop count == {} for i == {}, len == {}",
                        count, i, len);
            }

            // Check that the most recent versions of values were dropped.
            assert_eq!(VERSIONS.load(Relaxed), 0);
        }
    }
}

thread_local!(static SILENCE_PANIC: Cell<bool> = Cell::new(false));

fn main() {
    let prev = panic::take_hook();
    panic::set_hook(Box::new(move |info| {
        if !SILENCE_PANIC.with(|s| s.get()) {
            prev(info);
        }
    }));

    let mut rng = thread_rng();

    for len in (1..20).chain(70..MAX_LEN) {
        for &modulus in &[5, 20, 50] {
            for &has_runs in &[false, true] {
                let mut input = (0..len)
                    .map(|id| {
                        DropCounter {
                            x: rng.next_u32() % modulus,
                            id: id,
                            version: Cell::new(0),
                        }
                    })
                    .collect::<Vec<_>>();

                if has_runs {
                    for c in &mut input {
                        c.x = c.id as u32;
                    }

                    for _ in 0..5 {
                        let a = rng.gen::<usize>() % len;
                        let b = rng.gen::<usize>() % len;
                        if a < b {
                            input[a..b].reverse();
                        } else {
                            input.swap(a, b);
                        }
                    }
                }

                test!(input, sort_by);
                test!(input, sort_unstable_by);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Prepared statements cache for faster execution.

use std::cell::RefCell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use {Result, Connection, Statement};
use raw_statement::RawStatement;

impl Connection {
    /// Prepare a SQL statement for execution, returning a previously prepared (but
    /// not currently in-use) statement if one is available. The returned statement
    /// will be cached for reuse by future calls to `prepare_cached` once it is
    /// dropped.
    ///
    /// ```rust,no_run
    /// # use rusqlite::{Connection, Result};
    /// fn insert_new_people(conn: &Connection) -> Result<()> {
    ///     {
    ///         let mut stmt = try!(conn.prepare_cached("INSERT INTO People (name) VALUES (?)"));
    ///         try!(stmt.execute(&[&"Joe Smith"]));
    ///     }
    ///     {
    ///         // This will return the same underlying SQLite statement handle without
    ///         // having to prepare it again.
    ///         let mut stmt = try!(conn.prepare_cached("INSERT INTO People (name) VALUES (?)"));
    ///         try!(stmt.execute(&[&"Bob Jones"]));
    ///     }
    ///     Ok(())
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
    /// underlying SQLite call fails.
    pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result<CachedStatement<'a>> {
        self.cache.get(&self, sql)
    }
}

/// Prepared statements LRU cache.
#[derive(Debug)]
pub struct StatementCache {
    cache: RefCell<VecDeque<RawStatement>>, // back = LRU
}

/// Cacheable statement.
///
/// Statement will return automatically to the cache by default.
/// If you want the statement to be discarded, call `discard()` on it.
pub struct CachedStatement<'conn> {
    stmt: Option<Statement<'conn>>,
    cache: &'conn StatementCache,
}

impl<'conn> Deref for CachedStatement<'conn> {
    type Target = Statement<'conn>;

    fn deref(&self) -> &Statement<'conn> {
        self.stmt.as_ref().unwrap()
    }
}

impl<'conn> DerefMut for CachedStatement<'conn> {
    fn deref_mut(&mut self) -> &mut Statement<'conn> {
        self.stmt.as_mut().unwrap()
    }
}

impl<'conn> Drop for CachedStatement<'conn> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if let Some(stmt) = self.stmt.take() {
            self.cache.cache_stmt(stmt.into());
        }
    }
}

impl<'conn> CachedStatement<'conn> {
    fn new(stmt: Statement<'conn>, cache: &'conn StatementCache) -> CachedStatement<'conn> {
        CachedStatement {
            stmt: Some(stmt),
            cache: cache,
        }
    }

    pub fn discard(mut self) {
        self.stmt = None;
    }
}

impl StatementCache {
    /// Create a statement cache.
    pub fn with_capacity(capacity: usize) -> StatementCache {
        StatementCache {
            cache: RefCell::new(VecDeque::with_capacity(capacity)),
        }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    /// If no such prepared-statement can be found, allocate and prepare a new one.
    ///
    /// # Failure
    ///
    /// Will return `Err` if no cached statement can be found and the underlying SQLite prepare call fails.
    pub fn get<'conn>(&'conn self, conn: &'conn Connection, sql: &str) -> Result<CachedStatement<'conn>> {
        let mut cache = self.cache.borrow_mut();
        let stmt = match cache.iter().rposition(|entry| entry.sql().to_bytes().eq(sql.as_bytes())) {
            Some(index) => {
                let raw_stmt = cache.swap_remove_front(index).unwrap(); // FIXME Not LRU compliant
                Ok(Statement::new(conn, raw_stmt))
            }
            _ => conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, self))
    }

    // Return a statement to the cache.
    fn cache_stmt(&self, stmt: RawStatement) {
        let mut cache = self.cache.borrow_mut();
        if cache.capacity() == cache.len() {
            // is full
            cache.pop_back(); // LRU dropped
        }
        stmt.clear_bindings();
        cache.push_front(stmt)
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::StatementCache;

    impl StatementCache {
        fn clear(&self) {
            self.cache.borrow_mut().clear();
        }

        fn len(&self) -> usize {
            self.cache.borrow().len()
        }

        fn capacity(&self) -> usize {
            self.cache.borrow().capacity()
        }
    }

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;
        let initial_capacity = cache.capacity();
        assert_eq!(0, cache.len());
        assert!(initial_capacity > 0);

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32,i64>(0));
        }
        assert_eq!(1, cache.len());

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32,i64>(0));
        }
        assert_eq!(1, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(initial_capacity, cache.capacity());
    }

    #[test]
    fn test_discard() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32,i64>(0));
            stmt.discard();
        }
        assert_eq!(0, cache.len());
    }
}
<commit_msg>rustfmt<commit_after>//! Prepared statements cache for faster execution.

use std::cell::RefCell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
use {Result, Connection, Statement};
use raw_statement::RawStatement;

impl Connection {
    /// Prepare a SQL statement for execution, returning a previously prepared (but
    /// not currently in-use) statement if one is available. The returned statement
    /// will be cached for reuse by future calls to `prepare_cached` once it is
    /// dropped.
    ///
    /// ```rust,no_run
    /// # use rusqlite::{Connection, Result};
    /// fn insert_new_people(conn: &Connection) -> Result<()> {
    ///     {
    ///         let mut stmt = try!(conn.prepare_cached("INSERT INTO People (name) VALUES (?)"));
    ///         try!(stmt.execute(&[&"Joe Smith"]));
    ///     }
    ///     {
    ///         // This will return the same underlying SQLite statement handle without
    ///         // having to prepare it again.
    ///         let mut stmt = try!(conn.prepare_cached("INSERT INTO People (name) VALUES (?)"));
    ///         try!(stmt.execute(&[&"Bob Jones"]));
    ///     }
    ///     Ok(())
    /// }
    /// ```
    ///
    /// # Failure
    ///
    /// Will return `Err` if `sql` cannot be converted to a C-compatible string or if the
    /// underlying SQLite call fails.
    pub fn prepare_cached<'a>(&'a self, sql: &str) -> Result<CachedStatement<'a>> {
        self.cache.get(&self, sql)
    }
}

/// Prepared statements LRU cache.
#[derive(Debug)]
pub struct StatementCache {
    cache: RefCell<VecDeque<RawStatement>>, // back = LRU
}

/// Cacheable statement.
///
/// Statement will return automatically to the cache by default.
/// If you want the statement to be discarded, call `discard()` on it.
pub struct CachedStatement<'conn> {
    stmt: Option<Statement<'conn>>,
    cache: &'conn StatementCache,
}

impl<'conn> Deref for CachedStatement<'conn> {
    type Target = Statement<'conn>;

    fn deref(&self) -> &Statement<'conn> {
        self.stmt.as_ref().unwrap()
    }
}

impl<'conn> DerefMut for CachedStatement<'conn> {
    fn deref_mut(&mut self) -> &mut Statement<'conn> {
        self.stmt.as_mut().unwrap()
    }
}

impl<'conn> Drop for CachedStatement<'conn> {
    #[allow(unused_must_use)]
    fn drop(&mut self) {
        if let Some(stmt) = self.stmt.take() {
            self.cache.cache_stmt(stmt.into());
        }
    }
}

impl<'conn> CachedStatement<'conn> {
    fn new(stmt: Statement<'conn>, cache: &'conn StatementCache) -> CachedStatement<'conn> {
        CachedStatement {
            stmt: Some(stmt),
            cache: cache,
        }
    }

    pub fn discard(mut self) {
        self.stmt = None;
    }
}

impl StatementCache {
    /// Create a statement cache.
    pub fn with_capacity(capacity: usize) -> StatementCache {
        StatementCache { cache: RefCell::new(VecDeque::with_capacity(capacity)) }
    }

    /// Search the cache for a prepared-statement object that implements `sql`.
    /// If no such prepared-statement can be found, allocate and prepare a new one.
    ///
    /// # Failure
    ///
    /// Will return `Err` if no cached statement can be found and the underlying SQLite prepare
    /// call fails.
    pub fn get<'conn>(&'conn self,
                      conn: &'conn Connection,
                      sql: &str)
                      -> Result<CachedStatement<'conn>> {
        let mut cache = self.cache.borrow_mut();
        let stmt = match cache.iter()
            .rposition(|entry| entry.sql().to_bytes().eq(sql.as_bytes())) {
            Some(index) => {
                let raw_stmt = cache.swap_remove_front(index).unwrap(); // FIXME Not LRU compliant
                Ok(Statement::new(conn, raw_stmt))
            }
            _ => conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, self))
    }

    // Return a statement to the cache.
    fn cache_stmt(&self, stmt: RawStatement) {
        let mut cache = self.cache.borrow_mut();
        if cache.capacity() == cache.len() {
            // is full
            cache.pop_back(); // LRU dropped
        }
        stmt.clear_bindings();
        cache.push_front(stmt)
    }
}

#[cfg(test)]
mod test {
    use Connection;
    use super::StatementCache;

    impl StatementCache {
        fn clear(&self) {
            self.cache.borrow_mut().clear();
        }

        fn len(&self) -> usize {
            self.cache.borrow().len()
        }

        fn capacity(&self) -> usize {
            self.cache.borrow().capacity()
        }
    }

    #[test]
    fn test_cache() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;
        let initial_capacity = cache.capacity();
        assert_eq!(0, cache.len());
        assert!(initial_capacity > 0);

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());

        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
        }
        assert_eq!(1, cache.len());

        cache.clear();
        assert_eq!(0, cache.len());
        assert_eq!(initial_capacity, cache.capacity());
    }

    #[test]
    fn test_discard() {
        let db = Connection::open_in_memory().unwrap();
        let cache = &db.cache;

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = db.prepare_cached(sql).unwrap();
            assert_eq!(0, cache.len());
            assert_eq!(0,
                       stmt.query(&[]).unwrap().get_expected_row().unwrap().get::<i32, i64>(0));
            stmt.discard();
        }
        assert_eq!(0, cache.len());
    }
}
<|endoftext|>


<commit_before>use piston_window::*;
use piston_window::grid::Grid;

use colors::GREY;
use tetromino::*;
use settings::*;

enum GameState {
    Playing,
    Paused
}

#[derive(Clone, Copy)]
enum CellState {
    Empty,
    Block(types::Color)
}
impl CellState {
    fn draw(&self, x: u32, y: u32, context: Context, graphics: &mut G2d) {
        match *self {
            CellState::Block(color) => {
                let square = rectangle::square(
                    0.0, 0.0, BLOCK_SIZE - (2.0 * GRID_LINE_WIDTH)
                );
                let transform = context.transform
                    // Move the origin of the transform based on where the grid starts
                    .trans(GRID_X_OFFSET, GRID_Y_OFFSET)
                    // Move the square into the first grid cell (off of the bounding box)
                    .trans(GRID_LINE_WIDTH, GRID_LINE_WIDTH)
                    // Move the square into the proper grid cell based on x and y
                    .trans((x as f64)*BLOCK_SIZE, (y as f64)*BLOCK_SIZE);
                rectangle(color, square, transform, graphics);
            },
            CellState::Empty => {}
        }
    }
}

pub trait Game {
    fn on_input(&mut self, input: Input);
    fn on_update(&mut self, update_args: UpdateArgs);
    fn on_render(&mut self, render_args: RenderArgs, e: PistonWindow);
}

pub trait Renderer {
    fn render(&self, context: Context, graphics: &mut G2d);
}

// TODO: Move this to its own module
pub struct Board {
    grid: [[CellState; HEIGHT_IN_BLOCKS as usize]; WIDTH_IN_BLOCKS as usize]
}
impl Board {
    pub fn new() -> Board {
        // TODO: Get rid of this the hacky CellState stuff I put in
        // for testing
        use colors::*;
        let mut board = Board {
            grid: [[CellState::Empty; HEIGHT_IN_BLOCKS as usize]; WIDTH_IN_BLOCKS as usize]
        };
        board.grid[8][1] = CellState::Block(RED);
        board.grid[3][4] = CellState::Block(CYAN);
        board
    }
    fn get_cell_state(&self, x: u32, y: u32) -> CellState {
        self.grid[x as usize][y as usize]
    }
}
impl Renderer for Board {
    fn render(&self, context: Context, graphics: &mut G2d) {
        let grid = Grid {
            cols: WIDTH_IN_BLOCKS,
            rows: HEIGHT_IN_BLOCKS,
            units: BLOCK_SIZE
        };
        let line = Line::new(GREY, GRID_LINE_WIDTH);
        let transform = context.transform.trans(GRID_X_OFFSET, GRID_Y_OFFSET);
        grid.draw(&line, &Default::default(), transform, graphics);
        for (x, y) in grid.cells() {
            // TODO: Figure out why this only goes up to 9, 9...
            self.get_cell_state(x, y).draw(x, y, context, graphics);
        }
    }
}

pub struct Rustris {
    board: Board,
    current_piece: Piece,
    // next_piece: Piece,
    // score: u32,
    // level: u32,
    // state: GameState
}
impl Rustris {
    pub fn new() -> Rustris {
        Rustris {
            board: Board::new(),
            current_piece: Piece::create(J)
        }
    }
    pub fn reset(&mut self) {

    }
}
impl Game for Rustris {
    fn on_input(&mut self, input: Input) {

    }
    fn on_update(&mut self, update_args: UpdateArgs) {

    }
    fn on_render(&mut self, render_args: RenderArgs, e: PistonWindow) {
        e.draw_2d(|c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);
            self.board.render(c, g);
        });
    }
}

pub struct TheGame {
    rotation: f64,
    x: f64,
    y: f64,
    up_d: bool, down_d: bool, left_d: bool, right_d: bool
}
impl TheGame {
    pub fn new() -> TheGame {
        TheGame { rotation : 0.0, x : 0.0, y : 0.0, up_d: false, down_d: false, left_d: false, right_d: false }
    }
}
impl Game for TheGame {
    fn on_update(&mut self, update_args: UpdateArgs) {
        self.rotation += 3.0 * update_args.dt;
        if self.up_d {
            self.y += (-50.0) * update_args.dt;
        }
        if self.down_d {
            self.y += (50.0) * update_args.dt;
        }
        if self.left_d {
            self.x += (-50.0) * update_args.dt;
        }
        if self.right_d {
            self.x += (50.0) * update_args.dt;
        }
    }
    fn on_render(&mut self, render_args: RenderArgs, e: PistonWindow) {
        e.draw_2d(|c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);
            let center = c.transform.trans((render_args.width / 2) as f64, (render_args.height / 2) as f64);
            let square = rectangle::square(0.0, 0.0, 100.0);
            let red = [1.0, 0.0, 0.0, 1.0];
            rectangle(red, square, center.trans(self.x, self.y).rot_rad(self.rotation).trans(-50.0, -50.0), g);
        });
    }
    fn on_input(&mut self, inp: Input) {
        match inp {
            Input::Press(but) => {
                match but {
                    Button::Keyboard(Key::Up) => {
                        self.up_d = true;
                    }
                    Button::Keyboard(Key::Down) => {
                        self.down_d = true;
                    }
                    Button::Keyboard(Key::Left) => {
                        self.left_d = true;
                    }
                    Button::Keyboard(Key::Right) => {
                        self.right_d = true;
                    }
                    _ => {}
                }
            }
            Input::Release(but) => {
                match but {
                    Button::Keyboard(Key::Up) => {
                        self.up_d = false;
                    }
                    Button::Keyboard(Key::Down) => {
                        self.down_d = false;
                    }
                    Button::Keyboard(Key::Left) => {
                        self.left_d = false;
                    }
                    Button::Keyboard(Key::Right) => {
                        self.right_d = false;
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}
<commit_msg>update the comments around the cell state transformations<commit_after>use piston_window::*;
use piston_window::grid::Grid;

use colors::GREY;
use tetromino::*;
use settings::*;

enum GameState {
    Playing,
    Paused
}

#[derive(Clone, Copy)]
enum CellState {
    Empty,
    Block(types::Color)
}
impl CellState {
    fn draw(&self, x: u32, y: u32, context: Context, graphics: &mut G2d) {
        match *self {
            CellState::Block(color) => {
                let square = rectangle::square(
                    0.0, 0.0, BLOCK_SIZE - (2.0 * GRID_LINE_WIDTH)
                );
                let transform = context.transform
                    // Translate the origin of the transform based on where the grid starts
                    .trans(GRID_X_OFFSET, GRID_Y_OFFSET)
                    // Translate the square into the first grid cell (off of the bounding box)
                    .trans(GRID_LINE_WIDTH, GRID_LINE_WIDTH)
                    // Translate the square into the proper grid cell based on the grid x and y position
                    .trans((x as f64)*BLOCK_SIZE, (y as f64)*BLOCK_SIZE);
                rectangle(color, square, transform, graphics);
            },
            CellState::Empty => {}
        }
    }
}

pub trait Game {
    fn on_input(&mut self, input: Input);
    fn on_update(&mut self, update_args: UpdateArgs);
    fn on_render(&mut self, render_args: RenderArgs, e: PistonWindow);
}

pub trait Renderer {
    fn render(&self, context: Context, graphics: &mut G2d);
}

// TODO: Move this to its own module
pub struct Board {
    grid: [[CellState; HEIGHT_IN_BLOCKS as usize]; WIDTH_IN_BLOCKS as usize]
}
impl Board {
    pub fn new() -> Board {
        // TODO: Get rid of this the hacky CellState stuff I put in
        // for testing
        use colors::*;
        let mut board = Board {
            grid: [[CellState::Empty; HEIGHT_IN_BLOCKS as usize]; WIDTH_IN_BLOCKS as usize]
        };
        board.grid[8][1] = CellState::Block(RED);
        board.grid[3][4] = CellState::Block(CYAN);
        board
    }
    fn get_cell_state(&self, x: u32, y: u32) -> CellState {
        self.grid[x as usize][y as usize]
    }
}
impl Renderer for Board {
    fn render(&self, context: Context, graphics: &mut G2d) {
        let grid = Grid {
            cols: WIDTH_IN_BLOCKS,
            rows: HEIGHT_IN_BLOCKS,
            units: BLOCK_SIZE
        };
        let line = Line::new(GREY, GRID_LINE_WIDTH);
        let transform = context.transform.trans(GRID_X_OFFSET, GRID_Y_OFFSET);
        grid.draw(&line, &Default::default(), transform, graphics);
        for (x, y) in grid.cells() {
            // TODO: Figure out why this only goes up to 9, 9...
            self.get_cell_state(x, y).draw(x, y, context, graphics);
        }
    }
}

pub struct Rustris {
    board: Board,
    current_piece: Piece,
    // next_piece: Piece,
    // score: u32,
    // level: u32,
    // state: GameState
}
impl Rustris {
    pub fn new() -> Rustris {
        Rustris {
            board: Board::new(),
            current_piece: Piece::create(J)
        }
    }
    pub fn reset(&mut self) {

    }
}
impl Game for Rustris {
    fn on_input(&mut self, input: Input) {

    }
    fn on_update(&mut self, update_args: UpdateArgs) {

    }
    fn on_render(&mut self, render_args: RenderArgs, e: PistonWindow) {
        e.draw_2d(|c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);
            self.board.render(c, g);
        });
    }
}

pub struct TheGame {
    rotation: f64,
    x: f64,
    y: f64,
    up_d: bool, down_d: bool, left_d: bool, right_d: bool
}
impl TheGame {
    pub fn new() -> TheGame {
        TheGame { rotation : 0.0, x : 0.0, y : 0.0, up_d: false, down_d: false, left_d: false, right_d: false }
    }
}
impl Game for TheGame {
    fn on_update(&mut self, update_args: UpdateArgs) {
        self.rotation += 3.0 * update_args.dt;
        if self.up_d {
            self.y += (-50.0) * update_args.dt;
        }
        if self.down_d {
            self.y += (50.0) * update_args.dt;
        }
        if self.left_d {
            self.x += (-50.0) * update_args.dt;
        }
        if self.right_d {
            self.x += (50.0) * update_args.dt;
        }
    }
    fn on_render(&mut self, render_args: RenderArgs, e: PistonWindow) {
        e.draw_2d(|c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);
            let center = c.transform.trans((render_args.width / 2) as f64, (render_args.height / 2) as f64);
            let square = rectangle::square(0.0, 0.0, 100.0);
            let red = [1.0, 0.0, 0.0, 1.0];
            rectangle(red, square, center.trans(self.x, self.y).rot_rad(self.rotation).trans(-50.0, -50.0), g);
        });
    }
    fn on_input(&mut self, inp: Input) {
        match inp {
            Input::Press(but) => {
                match but {
                    Button::Keyboard(Key::Up) => {
                        self.up_d = true;
                    }
                    Button::Keyboard(Key::Down) => {
                        self.down_d = true;
                    }
                    Button::Keyboard(Key::Left) => {
                        self.left_d = true;
                    }
                    Button::Keyboard(Key::Right) => {
                        self.right_d = true;
                    }
                    _ => {}
                }
            }
            Input::Release(but) => {
                match but {
                    Button::Keyboard(Key::Up) => {
                        self.up_d = false;
                    }
                    Button::Keyboard(Key::Down) => {
                        self.down_d = false;
                    }
                    Button::Keyboard(Key::Left) => {
                        self.left_d = false;
                    }
                    Button::Keyboard(Key::Right) => {
                        self.right_d = false;
                    }
                    _ => {}
                }
            }
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>//! Helper to crudely rewrite types from the spec's format to our own.
//!
//! This reads a file containing table and record descriptions (from the spec)
//! and converts them to the form that we use, writing the result to stdout.
//!
//! Input should be in the format:
//!
//!
//! ```
//! Gpos1_0
//! uint16      majorVersion       Major version of the GPOS table, = 1
//! uint16      minorVersion       Minor version of the GPOS table, = 0
//! Offset16    scriptListOffset   Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset  Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset   Offset to LookupList table, from beginning of GPOS table
//!
//! Gpos1_1
//! uint16      majorVersion            Major version of the GPOS table, = 1
//! uint16      minorVersion            Minor version of the GPOS table, = 1
//! Offset16    scriptListOffset        Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset       Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset        Offset to LookupList table, from beginning of GPOS table
//! Offset32    featureVariationsOffset Offset to FeatureVariations table, from beginning of GPOS table (may be NULL)
//! ```
//!
//! - different records/tables are separated by newlines.
//! - the first line should be a single word, used as the name of the type
//! - other lines are just copy pasted
//!
//! *limitations:* this doesn't handle lifetimes, and doesn't generate annotations.
//! You will need to clean up the output.

macro_rules! exit_with_msg {
    ($disp:expr) => {{
        eprintln!("{}", $disp);
        std::process::exit(1);
    }};
}
fn main() {
    let in_path = std::env::args().nth(1).expect("expected path argument");
    let input = std::fs::read_to_string(in_path).expect("failed to read path");
    let mut lines = input.lines().map(str::trim);
    while let Some(item) = generate_one_item(&mut lines) {
        println!("{}", item);
    }
}

/// parse a single table or record.
///
/// Returns `Some` on success, `None` if there are no more items, and terminates
/// if something goes wrong.
fn generate_one_item<'a>(lines: impl Iterator<Item = &'a str>) -> Option<String> {
    let mut lines = lines.skip_while(|line| line.is_empty());

    let name = match lines.next() {
        Some(line) if line.split_whitespace().nth(1).is_none() => line,
        Some(line) => exit_with_msg!(format!("expected table or record name, found '{}'", line)),
        _ => return None,
    };

    let field_text = lines.map_while(parse_field);
    let mut result = format!("{} {{\n", name);
    for line in field_text {
        result.push_str(&line);
        result.push('\n');
    }
    result.push_str("}\n");
    Some(result)
}

fn parse_field(line: &str) -> Option<String> {
    if line.is_empty() {
        return None;
    }
    let mut iter = line.splitn(3, |c: char| c.is_ascii_whitespace());
    let (typ, ident, comment) = match (iter.next(), iter.next(), iter.next()) {
        (Some(a), Some(b), Some(c)) => (a, b, c),
        _ => exit_with_msg!(format!(
            "line could not be parsed as type/name/comment: '{}'",
            line
        )),
    };
    let typ = normalize_type(typ);
    let ident = decamalize(ident);
    let comment = format_comment("    ", comment);
    Some(format!("{}\n    {}: {},", comment, ident, typ))
}

fn normalize_type(input: &str) -> &str {
    match input {
        "uint8" => "Uint8",
        "uint16" => "Uint16",
        "uint24" => "Uint24",
        "uint32" => "Uint32",
        "int8" => "Int8",
        "int16" => "Int16",
        "int32" => "Int32",
        "FWORD" => "FWord",
        "UFWORD" => "UfWord",
        "F2DOT14" => "F2Dot14",
        "LONGDATETIME" => "LongDateTime",
        "Tag" | "Fixed" | "Offset16" | "Offset32" | "Offset24" | "Version16Dot16" => input,
        other => exit_with_msg!(format!("unknown type '{}'", other)),
    }
}

fn decamalize(input: &str) -> String {
    //taken from serde: https://github.com/serde-rs/serde/blob/7e19ae8c9486a3bbbe51f1befb05edee94c454f9/serde_derive/src/internals/case.rs#L69-L76
    let mut snake = String::new();
    for (i, ch) in input.char_indices() {
        if i > 0 && ch.is_uppercase() {
            snake.push('_');
        }
        snake.push(ch.to_ascii_lowercase());
    }
    snake
}

fn format_comment(whitespace: &str, input: &str) -> String {
    const LINE_LEN: usize = 72;

    let mut docs = String::new();
    //docs.push_str()

    let mut cur_len = docs.len();
    for token in input.split_inclusive(' ') {
        if docs.is_empty() || cur_len + token.len() > LINE_LEN {
            if !docs.is_empty() {
                docs.push('\n');
            }
            docs.push_str(whitespace);
            docs.push_str("/// ");
            cur_len = whitespace.len() + 4;
        }
        docs.push_str(token);
        cur_len += token.len();
    }
    docs
}
<commit_msg>Array, reserved & lifetime support in codegen tool<commit_after>//! Helper to crudely rewrite types from the spec's format to our own.
//!
//! This reads a file containing table and record descriptions (from the spec)
//! and converts them to the form that we use, writing the result to stdout.
//!
//! Input should be in the format:
//!
//!
//! ```
//! Gpos1_0
//! uint16      majorVersion       Major version of the GPOS table, = 1
//! uint16      minorVersion       Minor version of the GPOS table, = 0
//! Offset16    scriptListOffset   Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset  Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset   Offset to LookupList table, from beginning of GPOS table
//!
//! Gpos1_1
//! uint16      majorVersion            Major version of the GPOS table, = 1
//! uint16      minorVersion            Minor version of the GPOS table, = 1
//! Offset16    scriptListOffset        Offset to ScriptList table, from beginning of GPOS table
//! Offset16    featureListOffset       Offset to FeatureList table, from beginning of GPOS table
//! Offset16    lookupListOffset        Offset to LookupList table, from beginning of GPOS table
//! Offset32    featureVariationsOffset Offset to FeatureVariations table, from beginning of GPOS table (may be NULL)
//! ```
//!
//! - different records/tables are separated by newlines.
//! - the first line should be a single word, used as the name of the type
//! - other lines are just copy pasted
//!
//! *limitations:* this doesn't handle lifetimes, and doesn't generate annotations.
//! You will need to clean up the output.

use std::fmt::Write;

macro_rules! exit_with_msg {
    ($disp:expr) => {{
        eprintln!("ERROR: {}", $disp);
        std::process::exit(1);
    }};
}
fn main() {
    let in_path = std::env::args().nth(1).expect("expected path argument");
    let input = std::fs::read_to_string(in_path).expect("failed to read path");
    let mut lines = input.lines().map(str::trim).filter(|l| !l.starts_with('#'));
    while let Some(item) = generate_one_item(&mut lines) {
        println!("{}", item);
    }
}

/// parse a single table or record.
///
/// Returns `Some` on success, `None` if there are no more items, and terminates
/// if something goes wrong.
fn generate_one_item<'a>(lines: impl Iterator<Item = &'a str>) -> Option<String> {
    let mut lines = lines.skip_while(|line| line.is_empty());

    let name = match lines.next() {
        Some(line) if line.split_whitespace().nth(1).is_none() => line,
        Some(line) => exit_with_msg!(format!("expected table or record name, found '{}'", line)),
        _ => return None,
    };

    let fields = lines.map_while(parse_field).collect::<Vec<_>>();
    let lifetime_str = if fields.iter().any(|x| x.maybe_count.is_some()) {
        "<'a>"
    } else {
        ""
    };
    let mut result = format!("{}{} {{\n", name, lifetime_str);
    for line in &fields {
        writeln!(&mut result, "{}", line).unwrap();
    }
    result.push_str("}\n");
    Some(result)
}

struct Field<'a> {
    name: String,
    maybe_count: Option<String>,
    typ: &'a str,
    comment: &'a str,
}

impl<'a> std::fmt::Display for Field<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        format_comment(f, "    ", self.comment)?;
        if self.name.contains("reserved") {
            writeln!(f, "    #[hidden]")?;
        }
        if let Some(count) = &self.maybe_count {
            writeln!(f, "    #[count({})]", count)?;
            write!(f, "    {}: [{}],", self.name, self.typ)?;
        } else {
            write!(f, "    {}: {},", self.name, self.typ)?;
        }
        Ok(())
    }
}

fn parse_field(line: &str) -> Option<Field> {
    if line.is_empty() {
        return None;
    }
    let mut iter = line.splitn(3, |c: char| c.is_ascii_whitespace());
    let (typ, ident, comment) = match (iter.next(), iter.next(), iter.next()) {
        (Some(a), Some(b), Some(c)) => (a, b, c),
        _ => exit_with_msg!(format!(
            "line could not be parsed as type/name/comment: '{}'",
            line
        )),
    };
    let typ = normalize_type(typ);
    let (name, maybe_count) = split_ident(ident);
    let name = decamalize(name);
    let maybe_count = maybe_count.map(decamalize);
    Some(Field {
        name,
        maybe_count,
        typ,
        comment,
    })
}

/// takes an ident and splits it into the name and an optional count (if the item
/// is an array)
fn split_ident(input: &str) -> (&str, Option<&str>) {
    match input.split_once('[') {
        Some((front, back)) => (front, Some(back.trim_end_matches(']'))),
        None => (input, None),
    }
}

fn normalize_type(input: &str) -> &str {
    match input {
        "uint8" => "Uint8",
        "uint16" => "Uint16",
        "uint24" => "Uint24",
        "uint32" => "Uint32",
        "int8" => "Int8",
        "int16" => "Int16",
        "int32" => "Int32",
        "FWORD" => "FWord",
        "UFWORD" => "UfWord",
        "F2DOT14" => "F2Dot14",
        "LONGDATETIME" => "LongDateTime",
        other => other,
    }
}

fn decamalize(input: &str) -> String {
    //taken from serde: https://github.com/serde-rs/serde/blob/7e19ae8c9486a3bbbe51f1befb05edee94c454f9/serde_derive/src/internals/case.rs#L69-L76
    let mut snake = String::new();
    for (i, ch) in input.char_indices() {
        if i > 0 && ch.is_uppercase() {
            snake.push('_');
        }
        snake.push(ch.to_ascii_lowercase());
    }
    snake
}

fn format_comment(
    f: &mut std::fmt::Formatter<'_>,
    whitespace: &str,
    input: &str,
) -> std::fmt::Result {
    const LINE_LEN: usize = 72;

    let mut cur_len = 0;

    for token in input.split_inclusive(' ') {
        if cur_len == 0 || cur_len + token.len() > LINE_LEN {
            if cur_len > 0 {
                writeln!(f)?;
            }
            write!(f, "{}/// ", whitespace)?;
            cur_len = whitespace.len() + 4;
        }
        write!(f, "{}", token)?;
        cur_len += token.len();
    }
    if cur_len > 0 {
        writeln!(f)?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};
use noise::{Brownian2, perlin2};

const SPAWN_RATE: f64 = 0.1;
const CONSUMPTION: f64 = 0.04;
const SURVIVAL_THRESHOLD: f64 = 0.0;
const DEATH_RELEASE_COEFFICIENT: f64 = 0.5;
const INHALE_CAP: usize = 1000000;
const MOVEMENT_COST: usize = 20;

const FLUID_CYCLES: usize = 6;

const KILL_FLUID_COLOR_NORMAL: f64 = 0.01;
const SIGNAL_FLUID_COLOR_NORMAL: f64 = 0.2;
const FOOD_FLUID_COLOR_NORMAL: f64 = 180.0;

const EXPLODE_AMOUNT: f64 = 0.1;

#[derive(Debug, Clone)]
struct Mate {
    mate: (usize, usize),
    source: (usize, usize),
}

#[derive(Debug)]
struct Delta {
    movement_attempts: Vec<(usize, usize)>,
    mate_attempts: Vec<Mate>,
}

pub struct Hex {
    pub solution: Solution,
    pub cell: Option<Cell>,
    pub decision: Option<Decision>,
    delta: Delta,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        let killf = ((self.solution.fluids[2] - KILL_FLUID_NORMAL) /
                     KILL_FLUID_COLOR_NORMAL) as f32;
        let mut ocolors = [killf.abs(),
                           (self.solution.fluids[0] / FOOD_FLUID_COLOR_NORMAL) as f32,
                           0.25 * self.solution.fluids[3] as f32,
                           1.0];
        let signal_colors = [[0.0, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]];
        for i in 0..4 {
            let signalf = (((self.solution.fluids[4 + i] - SIGNAL_FLUID_NORMAL) /
                            SIGNAL_FLUID_COLOR_NORMAL) as f32)
                .abs();
            for j in 0..3 {
                ocolors[j] += signal_colors[i][j] * signalf;
            }
        }
        ocolors
    }
}

pub struct Grid {
    pub spawning: bool,
    pub width: usize,
    pub height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            spawning: true,
            width: width,
            height: height,
            tiles: randomizing_vec(width, height, rng),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        self.tiles = randomizing_vec(self.width, self.height, rng);
    }

    pub fn hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn hex_mut(&mut self, x: usize, y: usize) -> &mut Hex {
        &mut self.tiles[x + y * self.width]
    }

    fn hex_and_neighbors(&mut self, x: usize, y: usize) -> (&mut Hex, [&Hex; 6]) {
        (unsafe { mem::transmute(self.hex_mut(x, y)) },
         if y % 2 == 0 {
            [// UpRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height - 1) % self.height),
             // UpLeft
             self.hex(x, (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex(x, (y + self.height + 1) % self.height),
             // DownRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        } else {
            [// UpRight
             self.hex(x, (y + self.height - 1) % self.height),
             // UpLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height + 1) % self.height),
             // DownRight
             self.hex(x, (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        })
    }

    pub fn cycle(&mut self, rng: &mut Isaac64Rng) {
        if self.spawning {
            self.cycle_spawn(rng);
        }
        self.cycle_cells();
        self.cycle_decisions(rng);
        for _ in 0..FLUID_CYCLES {
            self.cycle_fluids();
        }
        self.cycle_death();
    }

    fn cycle_spawn(&mut self, rng: &mut Isaac64Rng) {
        if rng.next_f64() < SPAWN_RATE {
            let tile = rng.gen_range(0, self.width * self.height);
            if self.tiles[tile].cell.is_none() {
                self.tiles[tile].cell = Some(Cell::new(rng));
            }
        }
    }

    fn cycle_cells(&mut self) {
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                this.decision = if let Some(ref mut this_cell) = this.cell {
                    let neighbor_presents = [neighbors[0].cell.is_some(),
                                             neighbors[1].cell.is_some(),
                                             neighbors[2].cell.is_some(),
                                             neighbors[3].cell.is_some(),
                                             neighbors[4].cell.is_some(),
                                             neighbors[5].cell.is_some()];

                    Some(this_cell.decide([&this.solution.fluids,
                                           &neighbors[0].solution.fluids,
                                           &neighbors[1].solution.fluids,
                                           &neighbors[2].solution.fluids,
                                           &neighbors[3].solution.fluids,
                                           &neighbors[4].solution.fluids,
                                           &neighbors[5].solution.fluids],
                                          &neighbor_presents))
                } else {
                    None
                }
            }
        }
    }

    fn cycle_decisions(&mut self, rng: &mut Isaac64Rng) {
        // Compute the deltas resulting from the decision.
        for x in 0..self.width {
            for y in 0..self.height {
                let (width, height) = (self.width, self.height);
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                // Clear the movements from the previous cycle.
                this.delta.movement_attempts.clear();
                this.delta.mate_attempts.clear();
                this.solution.coefficients = if let Some(ref decision) = this.decision {
                    decision.coefficients
                } else {
                    // Set the diffusion coefficients to the normal values.
                    NORMAL_DIFFUSION
                };

                // Only add movements here if no cell is present.
                if this.cell.is_none() {
                    // Add any neighbor movements to the movement_attempts vector.
                    for (n, &facing) in neighbors.iter().zip(&[Direction::DownLeft,
                                                               Direction::DownRight,
                                                               Direction::Right,
                                                               Direction::UpRight,
                                                               Direction::UpLeft,
                                                               Direction::Left]) {
                        match n.decision {
                            Some(Decision { choice: Choice::Move(direction), .. }) => {
                                // It attempted to move into this hex cell.
                                if facing == direction {
                                    this.delta
                                        .movement_attempts
                                        .push(in_direction(x, y, width, height, facing.flip()));

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.movement_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Divide { mate, spawn }, .. }) => {
                                // It attempted to spawn into this hex cell.
                                if facing == spawn {
                                    let source = in_direction(x, y, width, height, facing.flip());;
                                    this.delta
                                        .mate_attempts
                                        .push(Mate {
                                            mate: in_direction(source.0,
                                                               source.1,
                                                               width,
                                                               height,
                                                               mate),
                                            source: source,
                                        });

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.mate_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Explode(way), .. }) => {
                                this.solution.diffuse[2] += if way {
                                    EXPLODE_AMOUNT
                                } else {
                                    -EXPLODE_AMOUNT
                                };
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        // Perform the deltas.
        for x in 0..self.width {
            for y in 0..self.height {
                // Handle movement.
                if self.hex(x, y).delta.movement_attempts.len() == 1 {
                    let from_coord = self.hex(x, y).delta.movement_attempts[0];
                    self.hex_mut(x, y).cell = self.hex_mut(from_coord.0, from_coord.1).cell.take();
                    // Apply movement cost.
                    let inhale = self.hex(x, y).cell.as_ref().unwrap().inhale;
                    if inhale >= MOVEMENT_COST {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale -= MOVEMENT_COST;
                    } else {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale = 0;
                    }
                    // Handle mating.
                } else if self.hex(x, y).delta.mate_attempts.len() == 1 {
                    let mate = self.hex(x, y).delta.mate_attempts[0].clone();
                    self.hex_mut(x, y).cell = if mate.mate == (x, y) {
                        // Apply movement cost to source.
                        let inhale =
                            self.hex(mate.source.0, mate.source.1).cell.as_ref().unwrap().inhale;
                        if inhale >= MOVEMENT_COST {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale -= MOVEMENT_COST;
                        } else {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale = 0;
                        }
                        Some(self.hex_mut(mate.source.0, mate.source.1)
                            .cell
                            .as_mut()
                            .unwrap()
                            .divide(rng))
                    } else {
                        if self.hex(mate.mate.0, mate.mate.1).cell.is_some() {
                            // Apply movement cost to source.
                            let inhale = self.hex(mate.source.0, mate.source.1)
                                .cell
                                .as_ref()
                                .unwrap()
                                .inhale;
                            if inhale >= MOVEMENT_COST {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale -= MOVEMENT_COST;
                            } else {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale = 0;
                            }
                            // This is safe so long as the cells arent the same.
                            Some(unsafe {
                                    mem::transmute::<_,
                                                     &mut Hex>(self.hex_mut(mate.source.0, mate.source.1))
                                }
                                .cell
                                .as_mut()
                                .unwrap()
                                .mate(&self.hex(mate.mate.0, mate.mate.1)
                                          .cell
                                          .as_ref()
                                          .unwrap(),
                                      rng))
                        } else {
                            None
                        }
                    };
                }

                // Clear the decisions.
                self.hex_mut(x, y).decision = None;
            }
        }
    }

    fn cycle_fluids(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);

                for n in &neighbors {
                    this.solution.diffuse_from(&n.solution);
                }
            }
        }

        // Finish the cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }

    fn cycle_death(&mut self) {
        // Finish the cycle.
        for hex in &mut self.tiles {
            if hex.cell.is_some() {
                if hex.solution.fluids[2] > KILL_FLUID_UPPER_THRESHOLD ||
                   hex.solution.fluids[2] < KILL_FLUID_LOWER_THRESHOLD ||
                   hex.cell.as_ref().unwrap().inhale == 0 {
                    hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                              hex.cell.as_ref().unwrap().inhale as f64;
                    hex.cell = None;
                } else if hex.solution.fluids[0] <= CONSUMPTION {
                    if hex.cell.as_ref().unwrap().inhale != 0 {
                        hex.cell.as_mut().unwrap().inhale -= 1;
                    } else {
                        hex.cell = None;
                    }
                } else {
                    hex.solution.fluids[0] -= CONSUMPTION;
                    if hex.solution.fluids[0] < SURVIVAL_THRESHOLD {
                        if hex.cell.as_ref().unwrap().inhale != 0 {
                            hex.cell.as_mut().unwrap().inhale -= 1;
                        } else {
                            hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                                      hex.cell.as_ref().unwrap().inhale as f64;
                            hex.cell = None;
                        }
                    } else {
                        if hex.cell.as_ref().unwrap().inhale < INHALE_CAP {
                            hex.cell.as_mut().unwrap().inhale += 1;
                        }
                    }
                }
            }
        }
    }
}

fn randomizing_vec(width: usize, height: usize, rng: &mut Isaac64Rng) -> Vec<Hex> {
    let seeds = [rng.gen(), rng.gen()];
    let noise = Brownian2::new(perlin2, 4).wavelength(64.0);
    (0..height)
        .cartesian_product((0..width))
        .map(|(x, y)| {
            Hex {
                solution: Solution::new([0.0,
                                         1.0,
                                         KILL_FLUID_NORMAL,
                                         noise.apply(&seeds[0], &[x as f64, y as f64]),
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL],
                                        NORMAL_DIFFUSION),
                cell: None,
                decision: None,
                delta: Delta {
                    movement_attempts: Vec::with_capacity(6),
                    mate_attempts: Vec::with_capacity(6),
                },
            }
        })
        .collect_vec()
}

fn in_direction(x: usize,
                y: usize,
                width: usize,
                height: usize,
                direction: Direction)
                -> (usize, usize) {
    let diff = direction.delta(y % 2 == 0);
    (((width + x) as isize + diff.0) as usize % width,
     ((height + y) as isize + diff.1) as usize % height)
}
<commit_msg>massively decrease spawn rate to decrease volatility<commit_after>use super::cell::*;
use super::fluid::*;
use itertools::Itertools;
use std::mem;
use rand::{Isaac64Rng, Rng};
use noise::{Brownian2, perlin2};

const SPAWN_RATE: f64 = 0.005;
const CONSUMPTION: f64 = 0.04;
const SURVIVAL_THRESHOLD: f64 = 0.0;
const DEATH_RELEASE_COEFFICIENT: f64 = 0.5;
const INHALE_CAP: usize = 1000000;
const MOVEMENT_COST: usize = 20;

const FLUID_CYCLES: usize = 6;

const KILL_FLUID_COLOR_NORMAL: f64 = 0.01;
const SIGNAL_FLUID_COLOR_NORMAL: f64 = 0.2;
const FOOD_FLUID_COLOR_NORMAL: f64 = 180.0;

const EXPLODE_AMOUNT: f64 = 0.1;

#[derive(Debug, Clone)]
struct Mate {
    mate: (usize, usize),
    source: (usize, usize),
}

#[derive(Debug)]
struct Delta {
    movement_attempts: Vec<(usize, usize)>,
    mate_attempts: Vec<Mate>,
}

pub struct Hex {
    pub solution: Solution,
    pub cell: Option<Cell>,
    pub decision: Option<Decision>,
    delta: Delta,
}

impl Hex {
    pub fn color(&self) -> [f32; 4] {
        let killf = ((self.solution.fluids[2] - KILL_FLUID_NORMAL) /
                     KILL_FLUID_COLOR_NORMAL) as f32;
        let mut ocolors = [killf.abs(),
                           (self.solution.fluids[0] / FOOD_FLUID_COLOR_NORMAL) as f32,
                           0.25 * self.solution.fluids[3] as f32,
                           1.0];
        let signal_colors = [[0.0, 0.5, 0.5], [0.5, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]];
        for i in 0..4 {
            let signalf = (((self.solution.fluids[4 + i] - SIGNAL_FLUID_NORMAL) /
                            SIGNAL_FLUID_COLOR_NORMAL) as f32)
                .abs();
            for j in 0..3 {
                ocolors[j] += signal_colors[i][j] * signalf;
            }
        }
        ocolors
    }
}

pub struct Grid {
    pub spawning: bool,
    pub width: usize,
    pub height: usize,
    tiles: Vec<Hex>,
}

impl Grid {
    pub fn new(width: usize, height: usize, rng: &mut Isaac64Rng) -> Self {
        Grid {
            spawning: true,
            width: width,
            height: height,
            tiles: randomizing_vec(width, height, rng),
        }
    }

    pub fn randomize(&mut self, rng: &mut Isaac64Rng) {
        self.tiles = randomizing_vec(self.width, self.height, rng);
    }

    pub fn hex(&self, x: usize, y: usize) -> &Hex {
        &self.tiles[x + y * self.width]
    }

    pub fn hex_mut(&mut self, x: usize, y: usize) -> &mut Hex {
        &mut self.tiles[x + y * self.width]
    }

    fn hex_and_neighbors(&mut self, x: usize, y: usize) -> (&mut Hex, [&Hex; 6]) {
        (unsafe { mem::transmute(self.hex_mut(x, y)) },
         if y % 2 == 0 {
            [// UpRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height - 1) % self.height),
             // UpLeft
             self.hex(x, (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex(x, (y + self.height + 1) % self.height),
             // DownRight
             self.hex((x + self.width + 1) % self.width,
                      (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        } else {
            [// UpRight
             self.hex(x, (y + self.height - 1) % self.height),
             // UpLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height - 1) % self.height),
             // Left
             self.hex((x + self.width - 1) % self.width, y),
             // DownLeft
             self.hex((x + self.width - 1) % self.width,
                      (y + self.height + 1) % self.height),
             // DownRight
             self.hex(x, (y + self.height + 1) % self.height),
             // Right
             self.hex((x + self.width + 1) % self.width, y)]
        })
    }

    pub fn cycle(&mut self, rng: &mut Isaac64Rng) {
        if self.spawning {
            self.cycle_spawn(rng);
        }
        self.cycle_cells();
        self.cycle_decisions(rng);
        for _ in 0..FLUID_CYCLES {
            self.cycle_fluids();
        }
        self.cycle_death();
    }

    fn cycle_spawn(&mut self, rng: &mut Isaac64Rng) {
        if rng.next_f64() < SPAWN_RATE {
            let tile = rng.gen_range(0, self.width * self.height);
            if self.tiles[tile].cell.is_none() {
                self.tiles[tile].cell = Some(Cell::new(rng));
            }
        }
    }

    fn cycle_cells(&mut self) {
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                this.decision = if let Some(ref mut this_cell) = this.cell {
                    let neighbor_presents = [neighbors[0].cell.is_some(),
                                             neighbors[1].cell.is_some(),
                                             neighbors[2].cell.is_some(),
                                             neighbors[3].cell.is_some(),
                                             neighbors[4].cell.is_some(),
                                             neighbors[5].cell.is_some()];

                    Some(this_cell.decide([&this.solution.fluids,
                                           &neighbors[0].solution.fluids,
                                           &neighbors[1].solution.fluids,
                                           &neighbors[2].solution.fluids,
                                           &neighbors[3].solution.fluids,
                                           &neighbors[4].solution.fluids,
                                           &neighbors[5].solution.fluids],
                                          &neighbor_presents))
                } else {
                    None
                }
            }
        }
    }

    fn cycle_decisions(&mut self, rng: &mut Isaac64Rng) {
        // Compute the deltas resulting from the decision.
        for x in 0..self.width {
            for y in 0..self.height {
                let (width, height) = (self.width, self.height);
                let (this, neighbors) = self.hex_and_neighbors(x, y);
                // Clear the movements from the previous cycle.
                this.delta.movement_attempts.clear();
                this.delta.mate_attempts.clear();
                this.solution.coefficients = if let Some(ref decision) = this.decision {
                    decision.coefficients
                } else {
                    // Set the diffusion coefficients to the normal values.
                    NORMAL_DIFFUSION
                };

                // Only add movements here if no cell is present.
                if this.cell.is_none() {
                    // Add any neighbor movements to the movement_attempts vector.
                    for (n, &facing) in neighbors.iter().zip(&[Direction::DownLeft,
                                                               Direction::DownRight,
                                                               Direction::Right,
                                                               Direction::UpRight,
                                                               Direction::UpLeft,
                                                               Direction::Left]) {
                        match n.decision {
                            Some(Decision { choice: Choice::Move(direction), .. }) => {
                                // It attempted to move into this hex cell.
                                if facing == direction {
                                    this.delta
                                        .movement_attempts
                                        .push(in_direction(x, y, width, height, facing.flip()));

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.movement_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Divide { mate, spawn }, .. }) => {
                                // It attempted to spawn into this hex cell.
                                if facing == spawn {
                                    let source = in_direction(x, y, width, height, facing.flip());;
                                    this.delta
                                        .mate_attempts
                                        .push(Mate {
                                            mate: in_direction(source.0,
                                                               source.1,
                                                               width,
                                                               height,
                                                               mate),
                                            source: source,
                                        });

                                    // No need to continue if we reach 2 attempts.
                                    if this.delta.mate_attempts.len() == 2 {
                                        break;
                                    }
                                }
                            }
                            Some(Decision { choice: Choice::Explode(way), .. }) => {
                                this.solution.diffuse[2] += if way {
                                    EXPLODE_AMOUNT
                                } else {
                                    -EXPLODE_AMOUNT
                                };
                            }
                            _ => {}
                        }
                    }
                }
            }
        }

        // Perform the deltas.
        for x in 0..self.width {
            for y in 0..self.height {
                // Handle movement.
                if self.hex(x, y).delta.movement_attempts.len() == 1 {
                    let from_coord = self.hex(x, y).delta.movement_attempts[0];
                    self.hex_mut(x, y).cell = self.hex_mut(from_coord.0, from_coord.1).cell.take();
                    // Apply movement cost.
                    let inhale = self.hex(x, y).cell.as_ref().unwrap().inhale;
                    if inhale >= MOVEMENT_COST {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale -= MOVEMENT_COST;
                    } else {
                        self.hex_mut(x, y).cell.as_mut().unwrap().inhale = 0;
                    }
                    // Handle mating.
                } else if self.hex(x, y).delta.mate_attempts.len() == 1 {
                    let mate = self.hex(x, y).delta.mate_attempts[0].clone();
                    self.hex_mut(x, y).cell = if mate.mate == (x, y) {
                        // Apply movement cost to source.
                        let inhale =
                            self.hex(mate.source.0, mate.source.1).cell.as_ref().unwrap().inhale;
                        if inhale >= MOVEMENT_COST {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale -= MOVEMENT_COST;
                        } else {
                            self.hex_mut(mate.source.0, mate.source.1)
                                .cell
                                .as_mut()
                                .unwrap()
                                .inhale = 0;
                        }
                        Some(self.hex_mut(mate.source.0, mate.source.1)
                            .cell
                            .as_mut()
                            .unwrap()
                            .divide(rng))
                    } else {
                        if self.hex(mate.mate.0, mate.mate.1).cell.is_some() {
                            // Apply movement cost to source.
                            let inhale = self.hex(mate.source.0, mate.source.1)
                                .cell
                                .as_ref()
                                .unwrap()
                                .inhale;
                            if inhale >= MOVEMENT_COST {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale -= MOVEMENT_COST;
                            } else {
                                self.hex_mut(mate.source.0, mate.source.1)
                                    .cell
                                    .as_mut()
                                    .unwrap()
                                    .inhale = 0;
                            }
                            // This is safe so long as the cells arent the same.
                            Some(unsafe {
                                    mem::transmute::<_,
                                                     &mut Hex>(self.hex_mut(mate.source.0, mate.source.1))
                                }
                                .cell
                                .as_mut()
                                .unwrap()
                                .mate(&self.hex(mate.mate.0, mate.mate.1)
                                          .cell
                                          .as_ref()
                                          .unwrap(),
                                      rng))
                        } else {
                            None
                        }
                    };
                }

                // Clear the decisions.
                self.hex_mut(x, y).decision = None;
            }
        }
    }

    fn cycle_fluids(&mut self) {
        // Then update diffusion.
        for x in 0..self.width {
            for y in 0..self.height {
                let (this, neighbors) = self.hex_and_neighbors(x, y);

                for n in &neighbors {
                    this.solution.diffuse_from(&n.solution);
                }
            }
        }

        // Finish the cycle.
        for hex in &mut self.tiles {
            hex.solution.end_cycle();
        }
    }

    fn cycle_death(&mut self) {
        // Finish the cycle.
        for hex in &mut self.tiles {
            if hex.cell.is_some() {
                if hex.solution.fluids[2] > KILL_FLUID_UPPER_THRESHOLD ||
                   hex.solution.fluids[2] < KILL_FLUID_LOWER_THRESHOLD ||
                   hex.cell.as_ref().unwrap().inhale == 0 {
                    hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                              hex.cell.as_ref().unwrap().inhale as f64;
                    hex.cell = None;
                } else if hex.solution.fluids[0] <= CONSUMPTION {
                    if hex.cell.as_ref().unwrap().inhale != 0 {
                        hex.cell.as_mut().unwrap().inhale -= 1;
                    } else {
                        hex.cell = None;
                    }
                } else {
                    hex.solution.fluids[0] -= CONSUMPTION;
                    if hex.solution.fluids[0] < SURVIVAL_THRESHOLD {
                        if hex.cell.as_ref().unwrap().inhale != 0 {
                            hex.cell.as_mut().unwrap().inhale -= 1;
                        } else {
                            hex.solution.fluids[0] += DEATH_RELEASE_COEFFICIENT * CONSUMPTION *
                                                      hex.cell.as_ref().unwrap().inhale as f64;
                            hex.cell = None;
                        }
                    } else {
                        if hex.cell.as_ref().unwrap().inhale < INHALE_CAP {
                            hex.cell.as_mut().unwrap().inhale += 1;
                        }
                    }
                }
            }
        }
    }
}

fn randomizing_vec(width: usize, height: usize, rng: &mut Isaac64Rng) -> Vec<Hex> {
    let seeds = [rng.gen(), rng.gen()];
    let noise = Brownian2::new(perlin2, 4).wavelength(64.0);
    (0..height)
        .cartesian_product((0..width))
        .map(|(x, y)| {
            Hex {
                solution: Solution::new([0.0,
                                         1.0,
                                         KILL_FLUID_NORMAL,
                                         noise.apply(&seeds[0], &[x as f64, y as f64]),
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL,
                                         SIGNAL_FLUID_NORMAL],
                                        NORMAL_DIFFUSION),
                cell: None,
                decision: None,
                delta: Delta {
                    movement_attempts: Vec::with_capacity(6),
                    mate_attempts: Vec::with_capacity(6),
                },
            }
        })
        .collect_vec()
}

fn in_direction(x: usize,
                y: usize,
                width: usize,
                height: usize,
                direction: Direction)
                -> (usize, usize) {
    let diff = direction.delta(y % 2 == 0);
    (((width + x) as isize + diff.0) as usize % width,
     ((height + y) as isize + diff.1) as usize % height)
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use glib as ffi;
use types::{gchar,gpointer};
use util::escape_bytestring;

use libc;
use std::error::Error;
use std::fmt;
use std::marker;
use std::mem;
use std::ops::Deref;
use std::slice;
use std::str;

const NUL: u8 = 0;

pub struct OwnedGStr {
    ptr: *const gchar,
}

pub unsafe fn parse_as_bytes<'a, T: ?Sized>(raw: *const gchar,
                                            life_anchor: &'a T)
                                           -> &'a [u8]
{
    assert!(!raw.is_null());
    let r = mem::copy_lifetime(life_anchor, &(raw as *const u8));
    slice::from_raw_buf(r, libc::strlen(raw) as usize)
}

#[inline]
pub unsafe fn parse_as_utf8<'a, T: ?Sized>(raw: *const gchar,
                                           life_anchor: &'a T)
                                          -> Result<&'a str, str::Utf8Error>
{
    str::from_utf8(parse_as_bytes(raw, life_anchor))
}

impl OwnedGStr {

    pub unsafe fn from_raw(ptr: *mut gchar) -> OwnedGStr {
        assert!(!ptr.is_null());
        OwnedGStr { ptr: ptr as *const gchar }
    }
}

impl Deref for OwnedGStr {

    type Target = GStr;

    fn deref(&self) -> &GStr {
        unsafe { g_str_from_ptr_internal(self.ptr as *const u8, self) }
    }
}

impl Drop for OwnedGStr {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.ptr as gpointer) }
    }
}

impl Clone for OwnedGStr {
    fn clone(&self) -> OwnedGStr {
        unsafe {
            OwnedGStr::from_raw(ffi::g_strdup(self.ptr))
        }
    }
}

impl PartialEq for OwnedGStr {
    fn eq(&self, other: &OwnedGStr) -> bool {
        unsafe { libc::strcmp(self.ptr, other.ptr) == 0 }
    }
}

impl Eq for OwnedGStr { }

#[derive(Copy)]
pub struct NulError {
    pub position: usize
}

impl Error for NulError {

    fn description(&self) -> &str {
        "invalid data for C string: contains a NUL byte"
    }
}

impl fmt::Display for NulError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "invalid data for C string: NUL at position {}",
               self.position)
    }
}

impl fmt::Debug for NulError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

pub struct IntoGStrError {
    cause: NulError,
    bytes: Vec<u8>
}

impl IntoGStrError {

    pub fn nul_error(&self) -> &NulError {
        &self.cause
    }

    pub fn into_bytes(self) -> Vec<u8> {
        self.bytes
    }
}

impl Error for IntoGStrError {

    fn description(&self) -> &str {
        self.cause.description()
    }
}

impl fmt::Display for IntoGStrError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.cause)
    }
}

impl fmt::Debug for IntoGStrError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.cause)
    }
}

#[repr(C)]
pub struct GStr {
    head: gchar,
    marker: marker::NoCopy
}

#[repr(C)]
pub struct Utf8 {
    gstr: GStr
}

impl GStr {
    #[inline]
    pub fn as_ptr(&self) -> *const gchar {
        &self.head as *const gchar
    }

    pub fn parse_as_bytes(&self) -> &[u8] {
        unsafe {
            let r = mem::copy_lifetime(self, &(self.as_ptr() as *const u8));
            slice::from_raw_buf(r, libc::strlen(self.as_ptr()) as usize)
        }
    }

    #[inline]
    pub fn parse_as_utf8(&self) -> Result<&str, str::Utf8Error> {
        str::from_utf8(self.parse_as_bytes())
    }

    #[inline]
    pub unsafe fn parse_as_utf8_unchecked(&self) -> &str {
        str::from_utf8_unchecked(self.parse_as_bytes())
    }

    pub fn from_static_bytes(bytes: &'static [u8]) -> &'static GStr {
        assert!(bytes.last() == Some(&NUL),
                "static byte string is not null-terminated: \"{}\"",
                escape_bytestring(bytes));
        unsafe { g_str_from_ptr_internal(bytes.as_ptr(), bytes) }
    }

    pub unsafe fn from_raw<'a, T: ?Sized>(ptr: *const gchar,
                                          life_anchor: &'a T)
                                         -> &'a GStr
    {
        assert!(!ptr.is_null());
        g_str_from_ptr_internal(ptr as *const u8, life_anchor)
    }
}

impl Utf8 {

    #[inline]
    pub fn as_ptr(&self) -> *const gchar {
        self.gstr.as_ptr()
    }

    #[inline]
    pub fn as_g_str(&self) -> &GStr {
        &self.gstr
    }

    #[inline]
    pub fn parse_as_str(&self) -> &str {
        unsafe { str::from_utf8_unchecked(self.gstr.parse_as_bytes()) }
    }

    pub fn from_static_str(s: &'static str) -> &'static Utf8 {
        assert!(s.ends_with("\0"),
                "static string is not null-terminated: \"{}\"", s);
        unsafe { utf8_from_ptr_internal(s.as_ptr(), s) }
    }

    pub unsafe fn from_raw<'a, T: ?Sized>(ptr: *const gchar,
                                          life_anchor: &'a T)
                                         -> &'a Utf8
    {
        assert!(!ptr.is_null());
        utf8_from_ptr_internal(ptr as *const u8, life_anchor)
    }
}

unsafe fn g_str_from_ptr_internal<'a, T: ?Sized>(ptr: *const u8,
                                                 life_anchor: &'a T)
                                                -> &'a GStr
{
    mem::copy_lifetime(life_anchor, &*(ptr as *const GStr))
}

unsafe fn utf8_from_ptr_internal<'a, T: ?Sized>(ptr: *const u8,
                                                life_anchor: &'a T)
                                               -> &'a Utf8
{
    mem::copy_lifetime(life_anchor, &*(ptr as *const Utf8))
}

fn vec_into_g_str_buf(mut v: Vec<u8>) -> GStrBuf {
    v.push(NUL);
    GStrBuf { data: v }
}

pub struct GStrBuf {
    data: Vec<u8>
}

impl Deref for GStrBuf {

    type Target = GStr;

    fn deref(&self) -> &GStr {
        unsafe { g_str_from_ptr_internal(self.data.as_ptr(), self) }
    }
}

impl GStrBuf {

    #[inline]
    pub fn from_str(s: &str) -> Result<GStrBuf, NulError> {
        GStrBuf::from_bytes(s.as_bytes())
    }

    pub fn from_bytes(bytes: &[u8]) -> Result<GStrBuf, NulError> {
        if let Some(pos) = bytes.position_elem(&NUL) {
            return Err(NulError { position: pos });
        }
        Ok(vec_into_g_str_buf(bytes.to_vec()))
    }

    pub fn from_vec(vec: Vec<u8>) -> Result<GStrBuf, IntoGStrError> {
        if let Some(pos) = vec.position_elem(&NUL) {
            return Err(IntoGStrError {
                cause: NulError { position: pos },
                bytes: vec
            });
        }
        Ok(vec_into_g_str_buf(vec))
    }
}

pub struct Utf8Buf {
    inner: GStrBuf
}

impl Deref for Utf8Buf {

    type Target = Utf8;

    fn deref(&self) -> &Utf8 {
        unsafe { utf8_from_ptr_internal(self.inner.data.as_ptr(), self) }
    }
}

fn utf8_wrap_g_str_result<E>(res: Result<GStrBuf, E>) -> Result<Utf8Buf, E> {
    res.map(|buf| {
        Utf8Buf { inner: buf }
    })
}

impl Utf8Buf {

    pub fn from_str(s: &str) -> Result<Utf8Buf, NulError> {
        utf8_wrap_g_str_result(GStrBuf::from_bytes(s.as_bytes()))
    }

    pub fn from_string(s: String) -> Result<Utf8Buf, IntoGStrError> {
        utf8_wrap_g_str_result(GStrBuf::from_vec(s.into_bytes()))
    }
}
<commit_msg>gstr: Use unsafe for an internal function<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use glib as ffi;
use types::{gchar,gpointer};
use util::escape_bytestring;

use libc;
use std::error::Error;
use std::fmt;
use std::marker;
use std::mem;
use std::ops::Deref;
use std::slice;
use std::str;

const NUL: u8 = 0;

pub struct OwnedGStr {
    ptr: *const gchar,
}

pub unsafe fn parse_as_bytes<'a, T: ?Sized>(raw: *const gchar,
                                            life_anchor: &'a T)
                                           -> &'a [u8]
{
    assert!(!raw.is_null());
    let r = mem::copy_lifetime(life_anchor, &(raw as *const u8));
    slice::from_raw_buf(r, libc::strlen(raw) as usize)
}

#[inline]
pub unsafe fn parse_as_utf8<'a, T: ?Sized>(raw: *const gchar,
                                           life_anchor: &'a T)
                                          -> Result<&'a str, str::Utf8Error>
{
    str::from_utf8(parse_as_bytes(raw, life_anchor))
}

impl OwnedGStr {

    pub unsafe fn from_raw(ptr: *mut gchar) -> OwnedGStr {
        assert!(!ptr.is_null());
        OwnedGStr { ptr: ptr as *const gchar }
    }
}

impl Deref for OwnedGStr {

    type Target = GStr;

    fn deref(&self) -> &GStr {
        unsafe { g_str_from_ptr_internal(self.ptr as *const u8, self) }
    }
}

impl Drop for OwnedGStr {
    fn drop(&mut self) {
        unsafe { ffi::g_free(self.ptr as gpointer) }
    }
}

impl Clone for OwnedGStr {
    fn clone(&self) -> OwnedGStr {
        unsafe {
            OwnedGStr::from_raw(ffi::g_strdup(self.ptr))
        }
    }
}

impl PartialEq for OwnedGStr {
    fn eq(&self, other: &OwnedGStr) -> bool {
        unsafe { libc::strcmp(self.ptr, other.ptr) == 0 }
    }
}

impl Eq for OwnedGStr { }

#[derive(Copy)]
pub struct NulError {
    pub position: usize
}

impl Error for NulError {

    fn description(&self) -> &str {
        "invalid data for C string: contains a NUL byte"
    }
}

impl fmt::Display for NulError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "invalid data for C string: NUL at position {}",
               self.position)
    }
}

impl fmt::Debug for NulError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

pub struct IntoGStrError {
    cause: NulError,
    bytes: Vec<u8>
}

impl IntoGStrError {

    pub fn nul_error(&self) -> &NulError {
        &self.cause
    }

    pub fn into_bytes(self) -> Vec<u8> {
        self.bytes
    }
}

impl Error for IntoGStrError {

    fn description(&self) -> &str {
        self.cause.description()
    }
}

impl fmt::Display for IntoGStrError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.cause)
    }
}

impl fmt::Debug for IntoGStrError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.cause)
    }
}

#[repr(C)]
pub struct GStr {
    head: gchar,
    marker: marker::NoCopy
}

#[repr(C)]
pub struct Utf8 {
    gstr: GStr
}

impl GStr {
    #[inline]
    pub fn as_ptr(&self) -> *const gchar {
        &self.head as *const gchar
    }

    pub fn parse_as_bytes(&self) -> &[u8] {
        unsafe {
            let r = mem::copy_lifetime(self, &(self.as_ptr() as *const u8));
            slice::from_raw_buf(r, libc::strlen(self.as_ptr()) as usize)
        }
    }

    #[inline]
    pub fn parse_as_utf8(&self) -> Result<&str, str::Utf8Error> {
        str::from_utf8(self.parse_as_bytes())
    }

    #[inline]
    pub unsafe fn parse_as_utf8_unchecked(&self) -> &str {
        str::from_utf8_unchecked(self.parse_as_bytes())
    }

    pub fn from_static_bytes(bytes: &'static [u8]) -> &'static GStr {
        assert!(bytes.last() == Some(&NUL),
                "static byte string is not null-terminated: \"{}\"",
                escape_bytestring(bytes));
        unsafe { g_str_from_ptr_internal(bytes.as_ptr(), bytes) }
    }

    pub unsafe fn from_raw<'a, T: ?Sized>(ptr: *const gchar,
                                          life_anchor: &'a T)
                                         -> &'a GStr
    {
        assert!(!ptr.is_null());
        g_str_from_ptr_internal(ptr as *const u8, life_anchor)
    }
}

impl Utf8 {

    #[inline]
    pub fn as_ptr(&self) -> *const gchar {
        self.gstr.as_ptr()
    }

    #[inline]
    pub fn as_g_str(&self) -> &GStr {
        &self.gstr
    }

    #[inline]
    pub fn parse_as_str(&self) -> &str {
        unsafe { str::from_utf8_unchecked(self.gstr.parse_as_bytes()) }
    }

    pub fn from_static_str(s: &'static str) -> &'static Utf8 {
        assert!(s.ends_with("\0"),
                "static string is not null-terminated: \"{}\"", s);
        unsafe { utf8_from_ptr_internal(s.as_ptr(), s) }
    }

    pub unsafe fn from_raw<'a, T: ?Sized>(ptr: *const gchar,
                                          life_anchor: &'a T)
                                         -> &'a Utf8
    {
        assert!(!ptr.is_null());
        utf8_from_ptr_internal(ptr as *const u8, life_anchor)
    }
}

unsafe fn g_str_from_ptr_internal<'a, T: ?Sized>(ptr: *const u8,
                                                 life_anchor: &'a T)
                                                -> &'a GStr
{
    mem::copy_lifetime(life_anchor, &*(ptr as *const GStr))
}

unsafe fn utf8_from_ptr_internal<'a, T: ?Sized>(ptr: *const u8,
                                                life_anchor: &'a T)
                                               -> &'a Utf8
{
    mem::copy_lifetime(life_anchor, &*(ptr as *const Utf8))
}

fn vec_into_g_str_buf(mut v: Vec<u8>) -> GStrBuf {
    v.push(NUL);
    GStrBuf { data: v }
}

pub struct GStrBuf {
    data: Vec<u8>
}

impl Deref for GStrBuf {

    type Target = GStr;

    fn deref(&self) -> &GStr {
        unsafe { g_str_from_ptr_internal(self.data.as_ptr(), self) }
    }
}

impl GStrBuf {

    #[inline]
    pub fn from_str(s: &str) -> Result<GStrBuf, NulError> {
        GStrBuf::from_bytes(s.as_bytes())
    }

    pub fn from_bytes(bytes: &[u8]) -> Result<GStrBuf, NulError> {
        if let Some(pos) = bytes.position_elem(&NUL) {
            return Err(NulError { position: pos });
        }
        Ok(vec_into_g_str_buf(bytes.to_vec()))
    }

    pub fn from_vec(vec: Vec<u8>) -> Result<GStrBuf, IntoGStrError> {
        if let Some(pos) = vec.position_elem(&NUL) {
            return Err(IntoGStrError {
                cause: NulError { position: pos },
                bytes: vec
            });
        }
        Ok(vec_into_g_str_buf(vec))
    }
}

pub struct Utf8Buf {
    inner: GStrBuf
}

impl Deref for Utf8Buf {

    type Target = Utf8;

    fn deref(&self) -> &Utf8 {
        unsafe { Utf8::from_ptr(self.inner.data.as_ptr() as *const gchar) }
    }
}

unsafe fn utf8_wrap_g_str_result<E>(res: Result<GStrBuf, E>)
                                   -> Result<Utf8Buf, E>
{
    res.map(|buf| {
        Utf8Buf { inner: buf }
    })
}

impl Utf8Buf {

    pub fn from_str(s: &str) -> Result<Utf8Buf, NulError> {
        let g_str_res = GStrBuf::from_bytes(s.as_bytes());
        unsafe { utf8_wrap_g_str_result(g_str_res) }
    }

    pub fn from_string(s: String) -> Result<Utf8Buf, IntoGStrError> {
        let g_str_res = GStrBuf::from_vec(s.into_bytes());
        unsafe { utf8_wrap_g_str_result(g_str_res) }
    }
}
<|endoftext|>