<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};

/// Prepared statements LRU cache.
#[derive(Debug)]
pub struct StatementCache<'conn> {
    conn: &'conn Connection,
    cache: RefCell<VecDeque<Statement<'conn>>>, // 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<'c: 's, 's> {
    stmt: Option<Statement<'c>>,
    cache: &'s StatementCache<'c>,
}

impl<'c, 's> Deref for CachedStatement<'c, 's> {
    type Target = Statement<'c>;

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

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

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

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

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

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
        StatementCache {
            conn: conn,
            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<'s>(&'s self, sql: &str) -> Result<CachedStatement<'conn, 's>> {
        let mut cache = self.cache.borrow_mut();
        let stmt = match cache.iter().rposition(|entry| entry.eq(sql)) {
            Some(index) => Ok(cache.swap_remove_front(index).unwrap()), // FIXME Not LRU compliant
            _ => self.conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, self))
    }

    /// If `discard` is true, then the statement is deleted immediately.
    /// Otherwise it is added to the LRU list and may be returned
    /// by a subsequent call to `get()`.
    ///
    /// # Failure
    ///
    /// Will return `Err` if `stmt` (or the already cached statement implementing the same SQL) statement is `discard`ed
    /// and the underlying SQLite finalize call fails.
    fn release(&self, mut stmt: Statement<'conn>) {
        let mut cache = self.cache.borrow_mut();
        if cache.capacity() == cache.len() {
            // is full
            cache.pop_back(); // LRU dropped
        }
        stmt.reset_if_needed();
        stmt.clear_bindings();
        cache.push_front(stmt)
    }

    /// Flush the prepared statement cache
    pub fn clear(&self) {
        self.cache.borrow_mut().clear();
    }

    /// Return current cache size.
    pub fn len(&self) -> usize {
        self.cache.borrow().len()
    }

    /// Return maximum cache size.
    pub fn capacity(&self) -> usize {
        self.cache.borrow().capacity()
    }
}

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

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

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = cache.get(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 = cache.get(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!(15, cache.capacity());
    }

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

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = cache.get(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>Rename StatementCache::release -> cache_stmt<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};

/// Prepared statements LRU cache.
#[derive(Debug)]
pub struct StatementCache<'conn> {
    conn: &'conn Connection,
    cache: RefCell<VecDeque<Statement<'conn>>>, // 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<'c: 's, 's> {
    stmt: Option<Statement<'c>>,
    cache: &'s StatementCache<'c>,
}

impl<'c, 's> Deref for CachedStatement<'c, 's> {
    type Target = Statement<'c>;

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

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

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

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

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

impl<'conn> StatementCache<'conn> {
    /// Create a statement cache.
    pub fn new(conn: &'conn Connection, capacity: usize) -> StatementCache<'conn> {
        StatementCache {
            conn: conn,
            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<'s>(&'s self, sql: &str) -> Result<CachedStatement<'conn, 's>> {
        let mut cache = self.cache.borrow_mut();
        let stmt = match cache.iter().rposition(|entry| entry.eq(sql)) {
            Some(index) => Ok(cache.swap_remove_front(index).unwrap()), // FIXME Not LRU compliant
            _ => self.conn.prepare(sql),
        };
        stmt.map(|stmt| CachedStatement::new(stmt, self))
    }

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

    /// Flush the prepared statement cache
    pub fn clear(&self) {
        self.cache.borrow_mut().clear();
    }

    /// Return current cache size.
    pub fn len(&self) -> usize {
        self.cache.borrow().len()
    }

    /// Return maximum cache size.
    pub fn capacity(&self) -> usize {
        self.cache.borrow().capacity()
    }
}

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

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

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = cache.get(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 = cache.get(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!(15, cache.capacity());
    }

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

        let sql = "PRAGMA schema_version";
        {
            let mut stmt = cache.get(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>extern crate postgres;
extern crate chrono;
extern crate hyper;
extern crate regex;

use std::env;
use std::io::Read;

use postgres::{Connection, TlsMode};
use chrono::{DateTime, UTC};
use regex::Regex;

struct DonationEntry {
    id: i32,
    timestamp: DateTime<UTC>,
    donation_count: i32,
    donation_total: i32,
}

fn main() {
	let database_uri: String = env::var("GDQ_DATABASE_URI").unwrap();

    let conn = Connection::connect(database_uri.as_str(), TlsMode::None).unwrap();
    /*conn.execute("DROP TABLE DonationEntry", &[]).unwrap();
    conn.execute("CREATE TABLE DonationEntry (
                    id              SERIAL PRIMARY KEY,
                    timestamp       TIMESTAMP WITH TIME ZONE NOT NULL,
                    donation_count           INT,
                    donation_total           INT
                  )", &[]).unwrap();
    */

    let (count, total) = get_current_donation_stats();

    let new_entry = DonationEntry {
    	id: 0,
        timestamp: UTC::now(),
        donation_count: count,
        donation_total: total
    };
    conn.execute("INSERT INTO DonationEntry (timestamp, donation_count, donation_total) VALUES ($1, $2, $3)",
                 &[&new_entry.timestamp, &new_entry.donation_count, &new_entry.donation_total]).unwrap();

    for row in &conn.query("SELECT id, timestamp, donation_count, donation_total FROM DonationEntry", &[]).unwrap() {
        let entry = DonationEntry {
            id: row.get(0),
            timestamp: row.get(1),
            donation_count: row.get(2),
            donation_total: row.get(3),
        };
        println!("id: {}, timestamp: {}, count: {}, total: {}", entry.id, entry.timestamp, entry.donation_count, entry.donation_total);
    }
}

fn get_current_donation_stats() -> (i32, i32) {

    //send the request and read the response
    let client = hyper::Client::new();

    let scrape_url: String = env::var("GDQ_SCRAPE_URL").unwrap();
    //let scrape_url = "https://gamesdonequick.com/tracker/19";

    let mut response = client.get(scrape_url.as_str()).send().unwrap();
    assert_eq!(response.status, hyper::Ok);

    let mut response_string = String::new();
    response.read_to_string(&mut response_string).unwrap();

    //pull out the donation total and donation count text
    let parse_regex = Regex::new(r"Donation Total:\s*\$(?P<total>[\d,]+)(?:[.\d]+)?\s*\((?P<count>\d+)\)\s*\—").unwrap();
    let captures = parse_regex.captures(&response_string).unwrap();

    let matched_total = captures.name("total").unwrap().as_str();
    let matched_count = captures.name("count").unwrap().as_str();

    //remove any comma separators before parsing
    let parsed_total = matched_total.replace(",", "").parse::<i32>().unwrap();
    let parsed_count = matched_count.replace(",", "").parse::<i32>().unwrap();

	(parsed_count, parsed_total)
}<commit_msg>Only print the row we jsut added<commit_after>extern crate postgres;
extern crate chrono;
extern crate hyper;
extern crate regex;

use std::env;
use std::io::Read;

use postgres::{Connection, TlsMode};
use chrono::{DateTime, UTC};
use regex::Regex;

struct DonationEntry {
    id: i32,
    timestamp: DateTime<UTC>,
    donation_count: i32,
    donation_total: i32,
}

fn main() {
	let database_uri: String = env::var("GDQ_DATABASE_URI").unwrap();

    let conn = Connection::connect(database_uri.as_str(), TlsMode::None).unwrap();
    /*conn.execute("DROP TABLE DonationEntry", &[]).unwrap();
    conn.execute("CREATE TABLE DonationEntry (
                    id              SERIAL PRIMARY KEY,
                    timestamp       TIMESTAMP WITH TIME ZONE NOT NULL,
                    donation_count           INT,
                    donation_total           INT
                  )", &[]).unwrap();
    */

    let (count, total) = get_current_donation_stats();

    let new_entry = DonationEntry {
    	id: 0,
        timestamp: UTC::now(),
        donation_count: count,
        donation_total: total
    };
    conn.execute("INSERT INTO DonationEntry (timestamp, donation_count, donation_total) VALUES ($1, $2, $3)",
                 &[&new_entry.timestamp, &new_entry.donation_count, &new_entry.donation_total]).unwrap();

    let result = conn.query("SELECT id, timestamp, donation_count, donation_total FROM DonationEntry ORDER BY timestamp DESC LIMIT 1", &[]).unwrap();
    assert_eq!(result.len(), 1);
    for row in &result {
        let entry = DonationEntry {
            id: row.get(0),
            timestamp: row.get(1),
            donation_count: row.get(2),
            donation_total: row.get(3),
        };
        println!("Successfuly added row: id: {}, timestamp: {}, count: {}, total: {}", entry.id, entry.timestamp, entry.donation_count, entry.donation_total);
    }
}

fn get_current_donation_stats() -> (i32, i32) {

    //send the request and read the response
    let client = hyper::Client::new();

    let scrape_url: String = env::var("GDQ_SCRAPE_URL").unwrap();
    //let scrape_url = "https://gamesdonequick.com/tracker/19";

    let mut response = client.get(scrape_url.as_str()).send().unwrap();
    assert_eq!(response.status, hyper::Ok);

    let mut response_string = String::new();
    response.read_to_string(&mut response_string).unwrap();

    //pull out the donation total and donation count text
    let parse_regex = Regex::new(r"Donation Total:\s*\$(?P<total>[\d,]+)(?:[.\d]+)?\s*\((?P<count>\d+)\)\s*\—").unwrap();
    let captures = parse_regex.captures(&response_string).unwrap();

    let matched_total = captures.name("total").unwrap().as_str();
    let matched_count = captures.name("count").unwrap().as_str();

    //remove any comma separators before parsing
    let parsed_total = matched_total.replace(",", "").parse::<i32>().unwrap();
    let parsed_count = matched_count.replace(",", "").parse::<i32>().unwrap();

	(parsed_count, parsed_total)
}<|endoftext|>


<commit_before>use super::{ArrayLength, GenericArray};
use core::cmp::Ordering;
use core::fmt;
use core::fmt::Debug;
use core::mem;
use core::ptr;
use nodrop::NoDrop;

impl<T: Default, N> Default for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn default() -> Self {
        unsafe {
            let mut res: NoDrop<GenericArray<T, N>> = NoDrop::new(mem::uninitialized());
            for r in res.iter_mut() {
                ptr::write(r, T::default())
            }
            res.into_inner()
        }
    }
}

impl<T: Clone, N> Clone for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn clone(&self) -> GenericArray<T, N> {
        unsafe {
            let mut res: NoDrop<GenericArray<T, N>> = NoDrop::new(mem::uninitialized());
            for i in 0..N::to_usize() {
                ptr::write(&mut res[i], self[i].clone())
            }
            res.into_inner()
        }
    }
}
impl<T: Copy, N> Copy for GenericArray<T, N>
    where N: ArrayLength<T>,
          N::ArrayType: Copy
{
}

impl<T: PartialEq, N> PartialEq for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn eq(&self, other: &Self) -> bool {
        **self == **other
    }
}
impl<T: Eq, N> Eq for GenericArray<T, N> where N: ArrayLength<T> {}

impl<T: PartialOrd, N> PartialOrd for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn partial_cmp(&self, other: &GenericArray<T, N>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&self, &other)
    }
}

impl<T: Ord, N> Ord for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn cmp(&self, other: &GenericArray<T, N>) -> Ordering {
        Ord::cmp(&self, &other)
    }
}

impl<T: Debug, N> Debug for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self[..].fmt(fmt)
    }
}
<commit_msg>implement AsRef, AsMut, Borrow, BorrowMut, Hash for GenericArray<commit_after>use super::{ArrayLength, GenericArray};
use core::{mem, ptr};
use core::borrow::{Borrow, BorrowMut};
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::hash::{Hash, Hasher};
use nodrop::NoDrop;

impl<T: Default, N> Default for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn default() -> Self {
        unsafe {
            let mut res: NoDrop<GenericArray<T, N>> = NoDrop::new(mem::uninitialized());
            for r in res.iter_mut() {
                ptr::write(r, T::default())
            }
            res.into_inner()
        }
    }
}

impl<T: Clone, N> Clone for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn clone(&self) -> GenericArray<T, N> {
        unsafe {
            let mut res: NoDrop<GenericArray<T, N>> = NoDrop::new(mem::uninitialized());
            for i in 0..N::to_usize() {
                ptr::write(&mut res[i], self[i].clone())
            }
            res.into_inner()
        }
    }
}
impl<T: Copy, N> Copy for GenericArray<T, N>
    where N: ArrayLength<T>,
          N::ArrayType: Copy
{
}

impl<T: PartialEq, N> PartialEq for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn eq(&self, other: &Self) -> bool {
        **self == **other
    }
}
impl<T: Eq, N> Eq for GenericArray<T, N> where N: ArrayLength<T> {}

impl<T: PartialOrd, N> PartialOrd for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn partial_cmp(&self, other: &GenericArray<T, N>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&self, &other)
    }
}

impl<T: Ord, N> Ord for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn cmp(&self, other: &GenericArray<T, N>) -> Ordering {
        Ord::cmp(&self, &other)
    }
}

impl<T: Debug, N> Debug for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        self[..].fmt(fmt)
    }
}

impl<T, N> Borrow<[T]> for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn borrow(&self) -> &[T] {
        &self[..]
    }
}

impl<T, N> BorrowMut<[T]> for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn borrow_mut(&mut self) -> &mut [T] {
        &mut self[..]
    }
}

impl<T, N> AsRef<[T]> for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn as_ref(&self) -> &[T] {
        &self[..]
    }
}

impl<T, N> AsMut<[T]> for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn as_mut(&mut self) -> &mut [T] {
        &mut self[..]
    }
}

impl<T: Hash, N> Hash for GenericArray<T, N>
    where N: ArrayLength<T>
{
    fn hash<H>(&self, state: &mut H)
        where H: Hasher
    {
        Hash::hash(&self[..], state)
    }
}
<|endoftext|>


<commit_before>use fnv::FnvHashMap;
use treewalk::ast::*;

pub type Depth = usize;

pub struct LexicalScopes {
    depths: FnvHashMap<VariableUseHandle, Depth>,
}

impl LexicalScopes {
    fn new() -> LexicalScopes {
        LexicalScopes {
            depths: FnvHashMap::default(),
        }
    }

    pub fn get_depth(&self, handle: &VariableUseHandle) -> Option<&Depth> {
        self.depths.get(handle)
    }
}

#[derive(Debug)]
pub enum LexicalScopesResolutionError {
    ReadLocalInItsOwnInitializer,
    VariableAlreadyExistsInScope,
    ReturnFromTopLevelCode,
    ReturnFromInitializer,
    UseOfThisOutsideAClass,
    UseOfSuperOutsideAClass,
    UseOfSuperOutsideASubClass,
}

trait LexicalScopesResolver {
    fn resolve(
        &self,
        &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError>;
}

#[derive(PartialEq)]
enum VariableDefinition {
    Undefined,
    Declared,
    Defined,
}

#[derive(PartialEq, Clone, Copy)]
enum ClassType {
    None,
    Class,
    Subclass,
}

pub struct ProgramLexicalScopesResolver {
    // Note that this doesn't track globals at all
    scopes: Vec<FnvHashMap<Identifier, VariableDefinition>>,
    current_function: Option<FunctionKind>,
    current_class: ClassType,
    lexical_scopes: LexicalScopes,
}

impl ProgramLexicalScopesResolver {
    pub fn new() -> ProgramLexicalScopesResolver {
        ProgramLexicalScopesResolver {
            scopes: vec![],
            current_function: None,
            current_class: ClassType::None,
            lexical_scopes: LexicalScopes::new(),
        }
    }

    fn begin_scope(&mut self) -> () {
        self.scopes.push(FnvHashMap::default());
    }

    fn end_scope(&mut self) -> () {
        self.scopes.pop();
    }

    fn declare(&mut self, identifier: &Identifier) -> Result<(), LexicalScopesResolutionError> {
        let scopes = self.scopes.len();
        if scopes == 0 {
            return Ok(());
        };
        if self.scopes[scopes - 1].contains_key(&identifier) {
            Err(LexicalScopesResolutionError::VariableAlreadyExistsInScope)
        } else {
            self.scopes[scopes - 1].insert(*identifier, VariableDefinition::Declared);
            Ok(())
        }
    }

    fn define(&mut self, identifier: &Identifier) -> () {
        let scopes = self.scopes.len();
        if scopes == 0 {
            return;
        };
        self.scopes[scopes - 1].insert(*identifier, VariableDefinition::Defined);
    }

    fn resolve_local(&mut self, handle: VariableUseHandle, identifier: &Identifier) -> () {
        let max_depth = self.scopes.len();
        for depth in 0..max_depth {
            if self.scopes[max_depth - depth - 1].contains_key(identifier) {
                self.lexical_scopes.depths.insert(handle, depth);
                return;
            }
        }
        // If we failed to find it in the locals, it must be a global.
        // It might not be there right now, but it might appear later on.
        // We will know it only at runtime.
        self.lexical_scopes.depths.insert(handle, max_depth);
    }

    pub fn resolve(&mut self, statement: &Statement) -> Result<(), LexicalScopesResolutionError> {
        statement.resolve(self)
    }

    pub fn get_depth(&self, handle: &VariableUseHandle) -> Option<&Depth> {
        self.lexical_scopes.get_depth(handle)
    }
}

impl LexicalScopesResolver for Statement {
    fn resolve(
        &self,
        resolver: &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError> {
        match *self {
            Statement::Block(ref b) => {
                resolver.begin_scope();
                for statement in &b.statements {
                    try!(statement.resolve(resolver));
                }
                resolver.end_scope();
                Ok(())
            }
            Statement::VariableDefinition(ref identifier) => {
                let _ = try!(resolver.declare(identifier));
                resolver.define(identifier);
                Ok(())
            }
            Statement::VariableDefinitionWithInitalizer(ref identifier, ref initializer) => {
                let _ = try!(resolver.declare(identifier));
                try!(initializer.resolve(resolver));
                resolver.define(identifier);
                Ok(())
            }
            Statement::FunctionDefinition(ref f) => f.resolve(resolver),
            Statement::Class(ref c) => {
                let _ = try!(resolver.declare(&c.name));
                let enclosing_class = resolver.current_class;
                resolver.current_class = ClassType::Class;
                resolver.define(&c.name);
                if let Some(ref superclass) = c.superclass {
                    resolver.current_class = ClassType::Subclass;
                    let _ = try!(superclass.resolve(resolver));
                    resolver.begin_scope();
                    resolver.define(&Identifier::super_identifier());
                }
                resolver.begin_scope();
                resolver.define(&Identifier::this());
                for method in c.methods.iter() {
                    let _ = try!(method.resolve(resolver));
                }
                resolver.end_scope();
                if let Some(_) = c.superclass {
                    resolver.end_scope();
                }
                resolver.current_class = enclosing_class;
                Ok(())
            }
            Statement::Expression(ref e) => e.resolve(resolver),
            Statement::IfThen(ref s) => s
                .condition
                .resolve(resolver)
                .and_then(|_| s.then_branch.resolve(resolver)),
            Statement::IfThenElse(ref s) => s
                .condition
                .resolve(resolver)
                .and_then(|_| s.then_branch.resolve(resolver))
                .and_then(|_| s.else_branch.resolve(resolver)),
            Statement::While(ref s) => s
                .condition
                .resolve(resolver)
                .and_then(|_| s.body.resolve(resolver)),
            Statement::Print(ref e) => e.resolve(resolver),
            Statement::Return(ref r) => match resolver.current_function {
                Some(FunctionKind::Initializer) => {
                    Err(LexicalScopesResolutionError::ReturnFromInitializer)
                }
                Some(_) => match *r {
                    None => Ok(()),
                    Some(ref e) => e.resolve(resolver),
                },
                None => Err(LexicalScopesResolutionError::ReturnFromTopLevelCode),
            },
        }
    }
}

impl LexicalScopesResolver for Expr {
    fn resolve(
        &self,
        resolver: &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError> {
        match *self {
            Expr::This(ref handle, ref identifier) => {
                if let ClassType::None = resolver.current_class {
                    return Err(LexicalScopesResolutionError::UseOfThisOutsideAClass);
                }
                resolver.resolve_local(handle.clone(), identifier);
                Ok(())
            }
            Expr::Super(ref handle, ref super_identifier, _member_identifier) => match resolver
                .current_class
            {
                ClassType::None => Err(LexicalScopesResolutionError::UseOfSuperOutsideAClass),
                ClassType::Class => Err(LexicalScopesResolutionError::UseOfSuperOutsideASubClass),
                _ => {
                    resolver.resolve_local(handle.clone(), super_identifier);
                    Ok(())
                }
            },
            Expr::Identifier(ref handle, ref identifier) => {
                let scopes = resolver.scopes.len();
                if scopes != 0
                    && resolver.scopes[scopes - 1]
                        .get(&identifier)
                        .unwrap_or(&VariableDefinition::Undefined)
                        == &VariableDefinition::Declared
                {
                    Err(LexicalScopesResolutionError::ReadLocalInItsOwnInitializer)
                } else {
                    resolver.resolve_local(*handle, &identifier);
                    Ok(())
                }
            }
            Expr::Assignment(ref assigment) => assigment.resolve(resolver),
            Expr::Literal(_) => Ok(()),
            Expr::Unary(ref e) => e.right.resolve(resolver),
            Expr::Binary(ref e) => e
                .left
                .resolve(resolver)
                .and_then(|_| e.right.resolve(resolver)),
            Expr::Logic(ref e) => e
                .left
                .resolve(resolver)
                .and_then(|_| e.right.resolve(resolver)),
            Expr::Grouping(ref e) => e.expr.resolve(resolver),
            Expr::Call(ref e) => {
                try!(e.callee.resolve(resolver));
                for argument in e.arguments.iter() {
                    try!(argument.resolve(resolver));
                }
                Ok(())
            }
            Expr::Get(ref g) => {
                try!(g.instance.resolve(resolver));
                Ok(())
            }
            Expr::Set(ref s) => {
                try!(s.value.resolve(resolver));
                try!(s.instance.resolve(resolver));
                Ok(())
            }
        }
    }
}

impl LexicalScopesResolver for Assignment {
    fn resolve(
        &self,
        resolver: &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError> {
        try!{self.rvalue.resolve(resolver)};
        let Target::Identifier(ref identifier) = self.lvalue;
        resolver.resolve_local(self.handle, identifier);
        Ok(())
    }
}

impl LexicalScopesResolver for FunctionDefinition {
    fn resolve(
        &self,
        resolver: &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError> {
        let _ = try!(resolver.declare(&self.name));
        let enclosing_function = resolver.current_function;
        resolver.current_function = Some(self.kind);
        resolver.define(&self.name);
        resolver.begin_scope();
        for argument in self.arguments.iter() {
            let _ = try!(resolver.declare(argument));
            resolver.define(argument);
        }
        let _ = try!(self.body.resolve(resolver));
        resolver.end_scope();
        resolver.current_function = enclosing_function;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use frontend::scanner::*;
    use treewalk::lexical_scope_resolver::*;
    use treewalk::parser::*;

    #[test]
    fn global_variable() {
        let (tokens, _) = scan(&"var a = 0;{fun f() {print a;}}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        for statement in statements.iter() {
            assert!(lexical_scope_resolver.resolve(&statement).is_ok());
        }
        let lexical_scopes = lexical_scope_resolver.lexical_scopes;
        let mut handle_factory = VariableUseHandleFactory::new();
        let handle = handle_factory.next(); // Use of a in the function
        assert_eq!(Some(&3), lexical_scopes.get_depth(&handle));
    }

    #[test]
    fn captured_variable() {
        let (tokens, _) = scan(&"{var a = 0;fun f() {print a;}}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        for statement in statements.iter() {
            assert!(lexical_scope_resolver.resolve(&statement).is_ok());
        }
        let lexical_scopes = lexical_scope_resolver.lexical_scopes;
        let mut handle_factory = VariableUseHandleFactory::new();
        let handle = handle_factory.next(); // Use of a in the function
        assert_eq!(Some(&2), lexical_scopes.get_depth(&handle));
    }

    #[test]
    fn lexical_capture() {
        let (tokens, _) = scan(&"var a = 0;{fun f() {print a;} var a = 1;}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        for statement in statements.iter() {
            assert!(lexical_scope_resolver.resolve(&statement).is_ok());
        }
        let lexical_scopes = lexical_scope_resolver.lexical_scopes;
        let mut handle_factory = VariableUseHandleFactory::new();
        let handle = handle_factory.next(); // Use of a in the function
        assert_eq!(Some(&3), lexical_scopes.get_depth(&handle));
    }

    #[test]
    fn error_on_shadowing() {
        let (tokens, _) = scan(&"var a = 0;{var a = a;}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        assert!(lexical_scope_resolver.resolve(&statements[0]).is_ok());
        assert!(lexical_scope_resolver.resolve(&statements[1]).is_err());
    }

    #[test]
    fn error_on_local_redeclaration() {
        let (tokens, _) = scan(&"fun bad() {var a = 1;var a = 2;}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        assert!(lexical_scope_resolver.resolve(&statements[0]).is_err());
    }

    #[test]
    fn global_redeclaration_is_allowed() {
        let (tokens, _) = scan(&"var a = 1;var a = 2;");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        assert!(lexical_scope_resolver.resolve(&statements[0]).is_ok());
        assert!(lexical_scope_resolver.resolve(&statements[1]).is_ok());
    }

    #[test]
    fn error_on_return_outside_a_function() {
        let (tokens, _) = scan(&"return;");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        assert!(lexical_scope_resolver.resolve(&statements[0]).is_err());
    }
}
<commit_msg>cargo fmt<commit_after>use fnv::FnvHashMap;
use treewalk::ast::*;

pub type Depth = usize;

pub struct LexicalScopes {
    depths: FnvHashMap<VariableUseHandle, Depth>,
}

impl LexicalScopes {
    fn new() -> LexicalScopes {
        LexicalScopes {
            depths: FnvHashMap::default(),
        }
    }

    pub fn get_depth(&self, handle: &VariableUseHandle) -> Option<&Depth> {
        self.depths.get(handle)
    }
}

#[derive(Debug)]
pub enum LexicalScopesResolutionError {
    ReadLocalInItsOwnInitializer,
    VariableAlreadyExistsInScope,
    ReturnFromTopLevelCode,
    ReturnFromInitializer,
    UseOfThisOutsideAClass,
    UseOfSuperOutsideAClass,
    UseOfSuperOutsideASubClass,
}

trait LexicalScopesResolver {
    fn resolve(
        &self,
        &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError>;
}

#[derive(PartialEq)]
enum VariableDefinition {
    Undefined,
    Declared,
    Defined,
}

#[derive(PartialEq, Clone, Copy)]
enum ClassType {
    None,
    Class,
    Subclass,
}

pub struct ProgramLexicalScopesResolver {
    // Note that this doesn't track globals at all
    scopes: Vec<FnvHashMap<Identifier, VariableDefinition>>,
    current_function: Option<FunctionKind>,
    current_class: ClassType,
    lexical_scopes: LexicalScopes,
}

impl ProgramLexicalScopesResolver {
    pub fn new() -> ProgramLexicalScopesResolver {
        ProgramLexicalScopesResolver {
            scopes: vec![],
            current_function: None,
            current_class: ClassType::None,
            lexical_scopes: LexicalScopes::new(),
        }
    }

    fn begin_scope(&mut self) -> () {
        self.scopes.push(FnvHashMap::default());
    }

    fn end_scope(&mut self) -> () {
        self.scopes.pop();
    }

    fn declare(&mut self, identifier: &Identifier) -> Result<(), LexicalScopesResolutionError> {
        let scopes = self.scopes.len();
        if scopes == 0 {
            return Ok(());
        };
        if self.scopes[scopes - 1].contains_key(&identifier) {
            Err(LexicalScopesResolutionError::VariableAlreadyExistsInScope)
        } else {
            self.scopes[scopes - 1].insert(*identifier, VariableDefinition::Declared);
            Ok(())
        }
    }

    fn define(&mut self, identifier: &Identifier) -> () {
        let scopes = self.scopes.len();
        if scopes == 0 {
            return;
        };
        self.scopes[scopes - 1].insert(*identifier, VariableDefinition::Defined);
    }

    fn resolve_local(&mut self, handle: VariableUseHandle, identifier: &Identifier) -> () {
        let max_depth = self.scopes.len();
        for depth in 0..max_depth {
            if self.scopes[max_depth - depth - 1].contains_key(identifier) {
                self.lexical_scopes.depths.insert(handle, depth);
                return;
            }
        }
        // If we failed to find it in the locals, it must be a global.
        // It might not be there right now, but it might appear later on.
        // We will know it only at runtime.
        self.lexical_scopes.depths.insert(handle, max_depth);
    }

    pub fn resolve(&mut self, statement: &Statement) -> Result<(), LexicalScopesResolutionError> {
        statement.resolve(self)
    }

    pub fn get_depth(&self, handle: &VariableUseHandle) -> Option<&Depth> {
        self.lexical_scopes.get_depth(handle)
    }
}

impl LexicalScopesResolver for Statement {
    fn resolve(
        &self,
        resolver: &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError> {
        match *self {
            Statement::Block(ref b) => {
                resolver.begin_scope();
                for statement in &b.statements {
                    try!(statement.resolve(resolver));
                }
                resolver.end_scope();
                Ok(())
            }
            Statement::VariableDefinition(ref identifier) => {
                let _ = try!(resolver.declare(identifier));
                resolver.define(identifier);
                Ok(())
            }
            Statement::VariableDefinitionWithInitalizer(ref identifier, ref initializer) => {
                let _ = try!(resolver.declare(identifier));
                try!(initializer.resolve(resolver));
                resolver.define(identifier);
                Ok(())
            }
            Statement::FunctionDefinition(ref f) => f.resolve(resolver),
            Statement::Class(ref c) => {
                let _ = try!(resolver.declare(&c.name));
                let enclosing_class = resolver.current_class;
                resolver.current_class = ClassType::Class;
                resolver.define(&c.name);
                if let Some(ref superclass) = c.superclass {
                    resolver.current_class = ClassType::Subclass;
                    let _ = try!(superclass.resolve(resolver));
                    resolver.begin_scope();
                    resolver.define(&Identifier::super_identifier());
                }
                resolver.begin_scope();
                resolver.define(&Identifier::this());
                for method in c.methods.iter() {
                    let _ = try!(method.resolve(resolver));
                }
                resolver.end_scope();
                if let Some(_) = c.superclass {
                    resolver.end_scope();
                }
                resolver.current_class = enclosing_class;
                Ok(())
            }
            Statement::Expression(ref e) => e.resolve(resolver),
            Statement::IfThen(ref s) => s
                .condition
                .resolve(resolver)
                .and_then(|_| s.then_branch.resolve(resolver)),
            Statement::IfThenElse(ref s) => s
                .condition
                .resolve(resolver)
                .and_then(|_| s.then_branch.resolve(resolver))
                .and_then(|_| s.else_branch.resolve(resolver)),
            Statement::While(ref s) => s
                .condition
                .resolve(resolver)
                .and_then(|_| s.body.resolve(resolver)),
            Statement::Print(ref e) => e.resolve(resolver),
            Statement::Return(ref r) => match resolver.current_function {
                Some(FunctionKind::Initializer) => {
                    Err(LexicalScopesResolutionError::ReturnFromInitializer)
                }
                Some(_) => match *r {
                    None => Ok(()),
                    Some(ref e) => e.resolve(resolver),
                },
                None => Err(LexicalScopesResolutionError::ReturnFromTopLevelCode),
            },
        }
    }
}

impl LexicalScopesResolver for Expr {
    fn resolve(
        &self,
        resolver: &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError> {
        match *self {
            Expr::This(ref handle, ref identifier) => {
                if let ClassType::None = resolver.current_class {
                    return Err(LexicalScopesResolutionError::UseOfThisOutsideAClass);
                }
                resolver.resolve_local(handle.clone(), identifier);
                Ok(())
            }
            Expr::Super(ref handle, ref super_identifier, _member_identifier) => {
                match resolver.current_class {
                    ClassType::None => Err(LexicalScopesResolutionError::UseOfSuperOutsideAClass),
                    ClassType::Class => {
                        Err(LexicalScopesResolutionError::UseOfSuperOutsideASubClass)
                    }
                    _ => {
                        resolver.resolve_local(handle.clone(), super_identifier);
                        Ok(())
                    }
                }
            }
            Expr::Identifier(ref handle, ref identifier) => {
                let scopes = resolver.scopes.len();
                if scopes != 0
                    && resolver.scopes[scopes - 1]
                        .get(&identifier)
                        .unwrap_or(&VariableDefinition::Undefined)
                        == &VariableDefinition::Declared
                {
                    Err(LexicalScopesResolutionError::ReadLocalInItsOwnInitializer)
                } else {
                    resolver.resolve_local(*handle, &identifier);
                    Ok(())
                }
            }
            Expr::Assignment(ref assigment) => assigment.resolve(resolver),
            Expr::Literal(_) => Ok(()),
            Expr::Unary(ref e) => e.right.resolve(resolver),
            Expr::Binary(ref e) => e
                .left
                .resolve(resolver)
                .and_then(|_| e.right.resolve(resolver)),
            Expr::Logic(ref e) => e
                .left
                .resolve(resolver)
                .and_then(|_| e.right.resolve(resolver)),
            Expr::Grouping(ref e) => e.expr.resolve(resolver),
            Expr::Call(ref e) => {
                try!(e.callee.resolve(resolver));
                for argument in e.arguments.iter() {
                    try!(argument.resolve(resolver));
                }
                Ok(())
            }
            Expr::Get(ref g) => {
                try!(g.instance.resolve(resolver));
                Ok(())
            }
            Expr::Set(ref s) => {
                try!(s.value.resolve(resolver));
                try!(s.instance.resolve(resolver));
                Ok(())
            }
        }
    }
}

impl LexicalScopesResolver for Assignment {
    fn resolve(
        &self,
        resolver: &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError> {
        try!{self.rvalue.resolve(resolver)};
        let Target::Identifier(ref identifier) = self.lvalue;
        resolver.resolve_local(self.handle, identifier);
        Ok(())
    }
}

impl LexicalScopesResolver for FunctionDefinition {
    fn resolve(
        &self,
        resolver: &mut ProgramLexicalScopesResolver,
    ) -> Result<(), LexicalScopesResolutionError> {
        let _ = try!(resolver.declare(&self.name));
        let enclosing_function = resolver.current_function;
        resolver.current_function = Some(self.kind);
        resolver.define(&self.name);
        resolver.begin_scope();
        for argument in self.arguments.iter() {
            let _ = try!(resolver.declare(argument));
            resolver.define(argument);
        }
        let _ = try!(self.body.resolve(resolver));
        resolver.end_scope();
        resolver.current_function = enclosing_function;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use frontend::scanner::*;
    use treewalk::lexical_scope_resolver::*;
    use treewalk::parser::*;

    #[test]
    fn global_variable() {
        let (tokens, _) = scan(&"var a = 0;{fun f() {print a;}}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        for statement in statements.iter() {
            assert!(lexical_scope_resolver.resolve(&statement).is_ok());
        }
        let lexical_scopes = lexical_scope_resolver.lexical_scopes;
        let mut handle_factory = VariableUseHandleFactory::new();
        let handle = handle_factory.next(); // Use of a in the function
        assert_eq!(Some(&3), lexical_scopes.get_depth(&handle));
    }

    #[test]
    fn captured_variable() {
        let (tokens, _) = scan(&"{var a = 0;fun f() {print a;}}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        for statement in statements.iter() {
            assert!(lexical_scope_resolver.resolve(&statement).is_ok());
        }
        let lexical_scopes = lexical_scope_resolver.lexical_scopes;
        let mut handle_factory = VariableUseHandleFactory::new();
        let handle = handle_factory.next(); // Use of a in the function
        assert_eq!(Some(&2), lexical_scopes.get_depth(&handle));
    }

    #[test]
    fn lexical_capture() {
        let (tokens, _) = scan(&"var a = 0;{fun f() {print a;} var a = 1;}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        for statement in statements.iter() {
            assert!(lexical_scope_resolver.resolve(&statement).is_ok());
        }
        let lexical_scopes = lexical_scope_resolver.lexical_scopes;
        let mut handle_factory = VariableUseHandleFactory::new();
        let handle = handle_factory.next(); // Use of a in the function
        assert_eq!(Some(&3), lexical_scopes.get_depth(&handle));
    }

    #[test]
    fn error_on_shadowing() {
        let (tokens, _) = scan(&"var a = 0;{var a = a;}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        assert!(lexical_scope_resolver.resolve(&statements[0]).is_ok());
        assert!(lexical_scope_resolver.resolve(&statements[1]).is_err());
    }

    #[test]
    fn error_on_local_redeclaration() {
        let (tokens, _) = scan(&"fun bad() {var a = 1;var a = 2;}");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        assert!(lexical_scope_resolver.resolve(&statements[0]).is_err());
    }

    #[test]
    fn global_redeclaration_is_allowed() {
        let (tokens, _) = scan(&"var a = 1;var a = 2;");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        assert!(lexical_scope_resolver.resolve(&statements[0]).is_ok());
        assert!(lexical_scope_resolver.resolve(&statements[1]).is_ok());
    }

    #[test]
    fn error_on_return_outside_a_function() {
        let (tokens, _) = scan(&"return;");
        let statements = Parser::new().parse(&tokens).unwrap();
        let mut lexical_scope_resolver = ProgramLexicalScopesResolver::new();
        assert!(lexical_scope_resolver.resolve(&statements[0]).is_err());
    }
}
<|endoftext|>


<commit_before>#![feature(core, io, path)]

extern crate image;
extern crate nalgebra;

use std::f64::consts::{PI_2, FRAC_PI_2};
use std::old_io::File;
use std::num::Float;
use image::{GenericImage, Pixel, Rgba};
use nalgebra::{DVec, Mat2, Pnt2, Rot2, Vec1, Vec2, Vec3};

fn draw(v: &DVec<f64>, path: &Path) {
    let width = v.len() as u32;
    let height = 128u32;
    let white: Rgba<u8> = Pixel::from_channels(255, 255, 255, 255);
    let buffer = image::ImageBuffer::from_fn(width, height, Box::new(|&: _, _| white));
    let mut img = image::DynamicImage::ImageRgba8(buffer);
    let red = Pixel::from_channels(255, 0, 0, 255);
    for i in 0u32..(width) {
        let half = (height / 2) as f64;
        let y = half * (1.0 + v[i as usize]);
        let y = nalgebra::clamp(y as u32, 1u32, height);
        img.put_pixel(i, height - y, red);
    }
    let mut out = File::create(path).unwrap();
    let _ = img.save(&mut out, image::PNG);
}

fn main() {
    println!("24 days of Rust - nalgebra (day 14)");
    let v = Vec2::new(0.0f64, 1.0);
    // 90 degrees clockwise
    //  0, 1
    // -1, 0
    let rot = Mat2::new(0.0f64, -1.0, 1.0, 0.0);
    println!("{:?}", rot * v);
    let angle = FRAC_PI_2;
    let rot = Rot2::new(Vec1::new(angle));
    println!("{:?}", rot * v);
    let point = Pnt2::new(4.0f64, 4.0);
    println!("Translate from {:?} to {:?}", point, nalgebra::translate(&v, &point));

    let v1 = Vec3::new(2.0f64, 2.0, 0.0);
    let v2 = Vec3::new(2.0f64, -2.0, 0.0);
    if nalgebra::approx_eq(&0.0f64, &nalgebra::dot(&v1, &v2)) {
        println!("v1 is orthogonal to v2");
    }

    println!("{:?}", nalgebra::cross(&v1, &v2));
    println!("{:?}", nalgebra::cross(&v2, &v1));

    const SIZE: usize = 512;
    let sine = DVec::from_fn(SIZE, |i: usize| {
        let t = i as f64 / 16.0f64;
        t.sin()
    });
    draw(&sine, &Path::new("out_sine.png"));

    let window = DVec::from_fn(SIZE, |i: usize| {
        0.54f64 - 0.46 * (PI_2 * (i as f64) / (SIZE - 1) as f64).cos()
    });
    draw(&window, &Path::new("out_window.png"));

    draw(&(sine * window), &Path::new("out_windowed.png"));
}
<commit_msg>Simplify image creation with from_pixel()<commit_after>#![feature(core, io, path)]

extern crate image;
extern crate nalgebra;

use std::f64::consts::{PI_2, FRAC_PI_2};
use std::old_io::File;
use std::num::Float;
use image::{GenericImage, Pixel, Rgba};
use nalgebra::{DVec, Mat2, Pnt2, Rot2, Vec1, Vec2, Vec3};

fn draw(v: &DVec<f64>, path: &Path) {
    let width = v.len() as u32;
    let height = 128u32;
    let white: Rgba<u8> = Pixel::from_channels(255, 255, 255, 255);
    let buffer = image::ImageBuffer::from_pixel(width, height, white);
    let mut img = image::DynamicImage::ImageRgba8(buffer);
    let red = Pixel::from_channels(255, 0, 0, 255);
    for i in 0u32..(width) {
        let half = (height / 2) as f64;
        let y = half * (1.0 + v[i as usize]);
        let y = nalgebra::clamp(y as u32, 1u32, height);
        img.put_pixel(i, height - y, red);
    }
    let mut out = File::create(path).unwrap();
    let _ = img.save(&mut out, image::PNG);
}

fn main() {
    println!("24 days of Rust - nalgebra (day 14)");
    let v = Vec2::new(0.0f64, 1.0);
    // 90 degrees clockwise
    //  0, 1
    // -1, 0
    let rot = Mat2::new(0.0f64, -1.0, 1.0, 0.0);
    println!("{:?}", rot * v);
    let angle = FRAC_PI_2;
    let rot = Rot2::new(Vec1::new(angle));
    println!("{:?}", rot * v);
    let point = Pnt2::new(4.0f64, 4.0);
    println!("Translate from {:?} to {:?}", point, nalgebra::translate(&v, &point));

    let v1 = Vec3::new(2.0f64, 2.0, 0.0);
    let v2 = Vec3::new(2.0f64, -2.0, 0.0);
    if nalgebra::approx_eq(&0.0f64, &nalgebra::dot(&v1, &v2)) {
        println!("v1 is orthogonal to v2");
    }

    println!("{:?}", nalgebra::cross(&v1, &v2));
    println!("{:?}", nalgebra::cross(&v2, &v1));

    const SIZE: usize = 512;
    let sine = DVec::from_fn(SIZE, |i: usize| {
        let t = i as f64 / 16.0f64;
        t.sin()
    });
    draw(&sine, &Path::new("out_sine.png"));

    let window = DVec::from_fn(SIZE, |i: usize| {
        0.54f64 - 0.46 * (PI_2 * (i as f64) / (SIZE - 1) as f64).cos()
    });
    draw(&window, &Path::new("out_window.png"));

    draw(&(sine * window), &Path::new("out_windowed.png"));
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

pub struct Model {
    pub board: Board,
    pub turn: Color,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
    // If a piece moves off of a hex, and that hex gets removed, the last move will not have a
    // "from" field, only a "to" field
    pub last_move: Option<(Option<FieldCoord>, FieldCoord)>,
    pub available_moves: Option<Vec<FieldCoord>>,
}

impl Model {
    pub fn new() -> Model {
        Model {
            board: Board::new(),
            turn: Color::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
            last_move: None,
            available_moves: None,
        }
    }
    pub fn switch_turns(&mut self) {
        self.turn = match self.turn {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(PartialEq)]
pub enum Color {
    White,
    Black,
}

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(neighbor) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(neighbor.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for neighbor in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&neighbor));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to) &&
            self.get_field_vertex_neighbors(from).contains(to)
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        if HexCoord::is_valid_coord(x, y) {
            let coord = HexCoord::new(x, y);
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for f in 0..6 {
            if let Some(neighbor) = self.get_hex_neighbor(coord, f) {
                neighbors.push(neighbor.to_field((f + 3) % 6));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex.iter().any(|&f| f == Field::Piece) {
                return false;
            },
            None => panic!("The hex at {:?} has already been removed", coord),
        }

        let neighbor_indexes: Vec<u32> = vec![0, 1, 2, 3, 4, 5]
            .into_iter()
            .filter(|&f| self.get_hex_neighbor(coord, f).is_some())
            .collect();
        let neighbor_indexes = neighbor_indexes.as_slice();

        match neighbor_indexes.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            [0, 1, 2, 3, 4, 5]
                .into_iter()
                .filter(|&&f| self.get_hex_neighbor(coord, f).is_some())
                .collect::<Vec<_>>()
                .len(),
        );
        self.set_hex(coord, None);
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if HexCoord::is_valid_coord(x, y) {
                    let coord = HexCoord::new(x, y);
                    if self.is_hex_extant(&coord) {
                        coords.push(coord);
                    }
                }
            }
        }
        coords
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
    pub fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    pub fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<commit_msg>Name variables more consistently<commit_after>/*
 * Copyright (C) 2017 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

pub struct Model {
    pub board: Board,
    pub turn: Color,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
    // If a piece moves off of a hex, and that hex gets removed, the last move will not have a
    // "from" field, only a "to" field
    pub last_move: Option<(Option<FieldCoord>, FieldCoord)>,
    pub available_moves: Option<Vec<FieldCoord>>,
}

impl Model {
    pub fn new() -> Model {
        Model {
            board: Board::new(),
            turn: Color::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
            last_move: None,
            available_moves: None,
        }
    }
    pub fn switch_turns(&mut self) {
        self.turn = match self.turn {
            Color::White => Color::Black,
            Color::Black => Color::White,
        }
    }
}

#[derive(PartialEq)]
pub enum Color {
    White,
    Black,
}

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5]
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(hex) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(hex.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for field in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&field));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to) &&
            self.get_field_vertex_neighbors(from).contains(to)
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert_eq!(
            self.get_field(coord),
            &Field::Piece,
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
    }
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        if HexCoord::is_valid_coord(x, y) {
            let coord = HexCoord::new(x, y);
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for f in 0..6 {
            if let Some(hex) = self.get_hex_neighbor(coord, f) {
                neighbors.push(hex.to_field((f + 3) % 6));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex.iter().any(|&f| f == Field::Piece) {
                return false;
            },
            None => panic!("The hex at {:?} has already been removed", coord),
        }

        let neighbor_indexes: Vec<u32> = vec![0, 1, 2, 3, 4, 5]
            .into_iter()
            .filter(|&f| self.get_hex_neighbor(coord, f).is_some())
            .collect();
        let neighbor_indexes = neighbor_indexes.as_slice();

        match neighbor_indexes.len() {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 => true,
            2 => {
                let valid_idx_combos = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [0, 5]];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            3 => {
                let valid_idx_combos = [
                    [0, 1, 2],
                    [1, 2, 3],
                    [2, 3, 4],
                    [3, 4, 5],
                    [0, 4, 5],
                    [0, 1, 5],
                ];
                valid_idx_combos.iter().any(|c| c == neighbor_indexes)
            }
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            [0, 1, 2, 3, 4, 5]
                .into_iter()
                .filter(|&&f| self.get_hex_neighbor(coord, f).is_some())
                .collect::<Vec<_>>()
                .len(),
        );
        self.set_hex(coord, None);
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if HexCoord::is_valid_coord(x, y) {
                    let coord = HexCoord::new(x, y);
                    if self.is_hex_extant(&coord) {
                        coords.push(coord);
                    }
                }
            }
        }
        coords
    }
}

#[derive(Debug, PartialEq)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy, Debug)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!(Self::is_valid_coord(x, y, f));
        FieldCoord { x, y, f }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn f(&self) -> u32 {
        self.f
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
    pub fn is_valid_coord(x: i32, y: i32, f: u32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6
    }
    pub fn color(&self) -> Color {
        if self.f % 2 == 0 {
            Color::Black
        } else {
            Color::White
        }
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!(Self::is_valid_coord(x, y));
        HexCoord { x, y }
    }
    pub fn x(&self) -> i32 {
        self.x
    }
    pub fn y(&self) -> i32 {
        self.y
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    pub fn is_valid_coord(x: i32, y: i32) -> bool {
        (x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2
    }
}
<|endoftext|>


<commit_before>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
        }
    }
}

pub enum Turn {
    White,
    Black,
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = [[None; 5]; 5];

        // (0, 0) is the only empty hex
        board[2][2] = Some([Field::Empty; 6]);

        // Conveniently, each hex (except for (0, 0)) has exactly two pieces on it in the starting
        // position. The format here is (hex_x, hex_y, field1, field2).
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board[(x + 2) as usize][(y + 2) as usize] = Some(hex);
        }

        Board { board }
    }

    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Tried to get field on removed hex: {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        unimplemented!();
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        unimplemented!();
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        unimplemented!();
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        unimplemented!();
    }
}

#[derive(Debug)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable only if it is "attached to the board by 3 or less
    //                       adjacent sides"
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<commit_msg>Implement get_field_edge_neighbors<commit_after>pub struct Model {
    pub board: Board,
    pub turn: Turn,
    pub white_pieces: u32,
    pub white_hexes: u32,
    pub black_pieces: u32,
    pub black_hexes: u32,
    pub selected_piece: Option<FieldCoord>,
}

impl Model {
    pub fn init() -> Model {
        Model {
            board: Board::new(),
            turn: Turn::White,
            white_pieces: 18,
            white_hexes: 0,
            black_pieces: 18,
            black_hexes: 0,
            selected_piece: None,
        }
    }
}

pub enum Turn {
    White,
    Black,
}

pub struct Board {
    // The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
    // up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
    // as a ragged array won't work (since each row would have to be a different type).
    board: [[Option<Hex>; 5]; 5],
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = [[None; 5]; 5];

        // (0, 0) is the only empty hex
        board[2][2] = Some([Field::Empty; 6]);

        // Conveniently, each hex (except for (0, 0)) has exactly two pieces on it in the starting
        // position. The format here is (hex_x, hex_y, field1, field2).
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board[(x + 2) as usize][(y + 2) as usize] = Some(hex);
        }

        Board { board }
    }

    pub fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!("Tried to get field on removed hex: {:?}", coord),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord {
                f: (coord.f + 1) % 6,
                ..*coord
            },
            FieldCoord {
                f: (coord.f + 5) % 6,
                ..*coord
            },
        ];

        for (i, neighbor) in coord.to_hex().get_neighbors() {
            if coord.f == i && self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
                break;
            }
        }
        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        unimplemented!();
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        unimplemented!();
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        unimplemented!();
    }

    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    pub fn get_hex_neighbors(&self, coord: &HexCoord) -> Vec<HexCoord> {
        coord
            .get_neighbors()
            .iter()
            .filter_map(|&(_, c)| match *self.get_hex(&c) {
                Some(_) => Some(c),
                None => None,
            })
            .collect()
    }
    /// Return fields that share an edge with the given hex and are outside of the given hex. If a
    /// hex is removed from the board, pieces occupying that hex's field neighbors might be
    /// capturable.
    pub fn get_hex_field_neighbors(&self, coord: &HexCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![];

        for (i, neighbor) in coord.get_neighbors() {
            if self.get_hex(&neighbor).is_some() {
                let f = (i + 3) % 6;
                neighbors.push(neighbor.to_field(f));
            }
        }
        neighbors
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        unimplemented!();
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        unimplemented!();
    }
}

#[derive(Debug)]
pub struct FieldCoord {
    x: i32,
    y: i32,
    f: u32,
}

#[derive(Clone, Copy)]
pub struct HexCoord {
    x: i32,
    y: i32,
}

impl FieldCoord {
    pub fn new(x: i32, y: i32, f: u32) -> FieldCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2 && f < 6);
        FieldCoord { x, y, f }
    }
    pub fn to_hex(&self) -> HexCoord {
        HexCoord::new(self.x, self.y)
    }
}

impl HexCoord {
    pub fn new(x: i32, y: i32) -> HexCoord {
        assert!((x + y).abs() <= 2 && x.abs() <= 2 && y.abs() <= 2);
        HexCoord { x, y }
    }
    pub fn to_field(&self, f: u32) -> FieldCoord {
        FieldCoord::new(self.x, self.y, f)
    }
    // We return a Vec of tuples so that get_hex_field_neighbors and is_hex_removable know which
    // neighbors are on which side of the hex. They need to know this for different reasons:
    //   * get_hex_field_neighbors: the index of each neighboring field depends on which hex
    //                              neighbor that field neighbor is on
    //   * is_hex_removable: a hex is removable only if it is "attached to the board by 3 or less
    //                       adjacent sides"
    fn get_neighbors(&self) -> Vec<(u32, HexCoord)> {
        let mut neighbors = vec![];

        if self.y < 2 && (self.x + self.y) != 2 {
            neighbors.push((0, HexCoord::new(self.x, self.y + 1)));
        }
        if (self.x + self.y) != 2 && self.x < 2 {
            neighbors.push((1, HexCoord::new(self.x + 1, self.y)));
        }
        if self.x < 2 && self.y > -2 {
            neighbors.push((2, HexCoord::new(self.x + 1, self.y - 1)));
        }
        if self.y > -2 && (self.x + self.y) > -2 {
            neighbors.push((3, HexCoord::new(self.x, self.y - 1)));
        }
        if (self.x + self.y) > -2 && self.x > -2 {
            neighbors.push((4, HexCoord::new(self.x - 1, self.y)));
        }
        if self.x > -2 && self.y < 2 {
            neighbors.push((5, HexCoord::new(self.x - 1, self.y + 1)));
        }

        neighbors
    }
}
<|endoftext|>