<commit_before>//! Pragma helpers

use std::ops::Deref;

use crate::error::Error;
use crate::ffi;
use crate::types::{ToSql, ToSqlOutput, ValueRef};
use crate::{Connection, DatabaseName, Result, Row, NO_PARAMS};

pub struct Sql {
    buf: String,
}

impl Sql {
    pub fn new() -> Sql {
        Sql { buf: String::new() }
    }

    pub fn push_pragma(
        &mut self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
    ) -> Result<()> {
        self.push_keyword("PRAGMA")?;
        self.push_space();
        if let Some(schema_name) = schema_name {
            self.push_schema_name(schema_name);
            self.push_dot();
        }
        self.push_keyword(pragma_name)
    }

    pub fn push_keyword(&mut self, keyword: &str) -> Result<()> {
        if !keyword.is_empty() && is_identifier(keyword) {
            self.buf.push_str(keyword);
            Ok(())
        } else {
            Err(Error::SqliteFailure(
                ffi::Error::new(ffi::SQLITE_MISUSE),
                Some(format!("Invalid keyword \"{}\"", keyword)),
            ))
        }
    }

    pub fn push_schema_name(&mut self, schema_name: DatabaseName<'_>) {
        match schema_name {
            DatabaseName::Main => self.buf.push_str("main"),
            DatabaseName::Temp => self.buf.push_str("temp"),
            DatabaseName::Attached(s) => self.push_identifier(s),
        };
    }

    pub fn push_identifier(&mut self, s: &str) {
        if is_identifier(s) {
            self.buf.push_str(s);
        } else {
            self.wrap_and_escape(s, '"');
        }
    }

    pub fn push_value(&mut self, value: &dyn ToSql) -> Result<()> {
        let value = value.to_sql()?;
        let value = match value {
            ToSqlOutput::Borrowed(v) => v,
            ToSqlOutput::Owned(ref v) => ValueRef::from(v),
            #[cfg(feature = "blob")]
            ToSqlOutput::ZeroBlob(_) => {
                return Err(Error::SqliteFailure(
                    ffi::Error::new(ffi::SQLITE_MISUSE),
                    Some(format!("Unsupported value \"{:?}\"", value)),
                ));
            }
            #[cfg(feature = "array")]
            ToSqlOutput::Array(_) => {
                return Err(Error::SqliteFailure(
                    ffi::Error::new(ffi::SQLITE_MISUSE),
                    Some(format!("Unsupported value \"{:?}\"", value)),
                ));
            }
        };
        match value {
            ValueRef::Integer(i) => {
                self.push_int(i);
            }
            ValueRef::Real(r) => {
                self.push_real(r);
            }
            ValueRef::Text(s) => {
                self.push_string_literal(s);
            }
            _ => {
                return Err(Error::SqliteFailure(
                    ffi::Error::new(ffi::SQLITE_MISUSE),
                    Some(format!("Unsupported value \"{:?}\"", value)),
                ));
            }
        };
        Ok(())
    }

    pub fn push_string_literal(&mut self, s: &str) {
        self.wrap_and_escape(s, '\'');
    }

    pub fn push_int(&mut self, i: i64) {
        self.buf.push_str(&i.to_string());
    }

    pub fn push_real(&mut self, f: f64) {
        self.buf.push_str(&f.to_string());
    }

    pub fn push_space(&mut self) {
        self.buf.push(' ');
    }

    pub fn push_dot(&mut self) {
        self.buf.push('.');
    }

    pub fn push_equal_sign(&mut self) {
        self.buf.push('=');
    }

    pub fn open_brace(&mut self) {
        self.buf.push('(');
    }

    pub fn close_brace(&mut self) {
        self.buf.push(')');
    }

    pub fn as_str(&self) -> &str {
        &self.buf
    }

    fn wrap_and_escape(&mut self, s: &str, quote: char) {
        self.buf.push(quote);
        let chars = s.chars();
        for ch in chars {
            // escape `quote` by doubling it
            if ch == quote {
                self.buf.push(ch);
            }
            self.buf.push(ch)
        }
        self.buf.push(quote);
    }
}

impl Deref for Sql {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl Connection {
    /// Query the current value of `pragma_name`.
    ///
    /// Some pragmas will return multiple rows/values which cannot be retrieved
    /// with this method.
    pub fn pragma_query_value<T, F>(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        f: F,
    ) -> Result<T>
    where
        F: FnOnce(Row<'_, '_>) -> Result<T>,
    {
        let mut query = Sql::new();
        query.push_pragma(schema_name, pragma_name)?;
        let mut stmt = self.prepare(&query)?;
        let mut rows = stmt.query(NO_PARAMS)?;
        if let Some(result_row) = rows.next() {
            let row = result_row?;
            f(row)
        } else {
            Err(Error::QueryReturnedNoRows)
        }
    }

    /// Query the current rows/values of `pragma_name`.
    pub fn pragma_query<F>(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        mut f: F,
    ) -> Result<()>
    where
        F: FnMut(&Row<'_, '_>) -> Result<()>,
    {
        let mut query = Sql::new();
        query.push_pragma(schema_name, pragma_name)?;
        let mut stmt = self.prepare(&query)?;
        let mut rows = stmt.query(NO_PARAMS)?;
        while let Some(result_row) = rows.next() {
            let row = result_row?;
            f(&row)?;
        }
        Ok(())
    }

    /// Query the current value(s) of `pragma_name` associated to
    /// `pragma_value`.
    ///
    /// This method can be used with query-only pragmas which need an argument
    /// (e.g. `table_info('one_tbl')`) or pragmas which return the updated value
    /// (e.g. `journal_mode`).
    pub fn pragma<F>(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        pragma_value: &dyn ToSql,
        mut f: F,
    ) -> Result<()>
    where
        F: FnMut(&Row<'_, '_>) -> Result<()>,
    {
        let mut sql = Sql::new();
        sql.push_pragma(schema_name, pragma_name)?;
        // The argument is may be either in parentheses
        // or it may be separated from the pragma name by an equal sign.
        // The two syntaxes yield identical results.
        sql.open_brace();
        sql.push_value(pragma_value)?;
        sql.close_brace();
        let mut stmt = self.prepare(&sql)?;
        let mut rows = stmt.query(NO_PARAMS)?;
        while let Some(result_row) = rows.next() {
            let row = result_row?;
            f(&row)?;
        }
        Ok(())
    }

    /// Set a new value to `pragma_name`.
    ///
    /// Some pragmas will return the updated value which cannot be retrieved
    /// with this method.
    pub fn pragma_update(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        pragma_value: &dyn ToSql,
    ) -> Result<()> {
        let mut sql = Sql::new();
        sql.push_pragma(schema_name, pragma_name)?;
        // The argument is may be either in parentheses
        // or it may be separated from the pragma name by an equal sign.
        // The two syntaxes yield identical results.
        sql.push_equal_sign();
        sql.push_value(pragma_value)?;
        self.execute_batch(&sql)
    }

    /// Set a new value to `pragma_name` and return the updated value.
    ///
    /// Only few pragmas automatically return the updated value.
    pub fn pragma_update_and_check<F, T>(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        pragma_value: &dyn ToSql,
        f: F,
    ) -> Result<T>
    where
        F: FnOnce(Row<'_, '_>) -> Result<T>,
    {
        let mut sql = Sql::new();
        sql.push_pragma(schema_name, pragma_name)?;
        // The argument is may be either in parentheses
        // or it may be separated from the pragma name by an equal sign.
        // The two syntaxes yield identical results.
        sql.push_equal_sign();
        sql.push_value(pragma_value)?;
        let mut stmt = self.prepare(&sql)?;
        let mut rows = stmt.query(NO_PARAMS)?;
        if let Some(result_row) = rows.next() {
            let row = result_row?;
            f(row)
        } else {
            Err(Error::QueryReturnedNoRows)
        }
    }
}

fn is_identifier(s: &str) -> bool {
    let chars = s.char_indices();
    for (i, ch) in chars {
        if i == 0 {
            if !is_identifier_start(ch) {
                return false;
            }
        } else if !is_identifier_continue(ch) {
            return false;
        }
    }
    true
}

fn is_identifier_start(c: char) -> bool {
    (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z') || c > '\x7F'
}

fn is_identifier_continue(c: char) -> bool {
    c == '$'
        || (c >= '0' && c <= '9')
        || (c >= 'A' && c <= 'Z')
        || c == '_'
        || (c >= 'a' && c <= 'z')
        || c > '\x7F'
}

#[cfg(test)]
mod test {
    use super::Sql;
    use crate::pragma;
    use crate::{Connection, DatabaseName};

    #[test]
    fn pragma_query_value() {
        let db = Connection::open_in_memory().unwrap();
        let user_version: i32 = db
            .pragma_query_value(None, "user_version", |row| row.get_checked(0))
            .unwrap();
        assert_eq!(0, user_version);
    }

    #[test]
    fn pragma_query_no_schema() {
        let db = Connection::open_in_memory().unwrap();
        let mut user_version = -1;
        db.pragma_query(None, "user_version", |row| {
            user_version = row.get_checked(0)?;
            Ok(())
        })
        .unwrap();
        assert_eq!(0, user_version);
    }

    #[test]
    fn pragma_query_with_schema() {
        let db = Connection::open_in_memory().unwrap();
        let mut user_version = -1;
        db.pragma_query(Some(DatabaseName::Main), "user_version", |row| {
            user_version = row.get_checked(0)?;
            Ok(())
        })
        .unwrap();
        assert_eq!(0, user_version);
    }

    #[test]
    fn pragma() {
        let db = Connection::open_in_memory().unwrap();
        let mut columns = Vec::new();
        db.pragma(None, "table_info", &"sqlite_master", |row| {
            let column: String = row.get_checked(1)?;
            columns.push(column);
            Ok(())
        })
        .unwrap();
        assert_eq!(5, columns.len());
    }

    #[test]
    fn pragma_update() {
        let db = Connection::open_in_memory().unwrap();
        db.pragma_update(None, "user_version", &1).unwrap();
    }

    #[test]
    fn pragma_update_and_check() {
        let db = Connection::open_in_memory().unwrap();
        let journal_mode: String = db
            .pragma_update_and_check(None, "journal_mode", &"OFF", |row| row.get_checked(0))
            .unwrap();
        assert_eq!("off", &journal_mode);
    }

    #[test]
    fn is_identifier() {
        assert!(pragma::is_identifier("full"));
        assert!(pragma::is_identifier("r2d2"));
        assert!(!pragma::is_identifier("sp ce"));
        assert!(!pragma::is_identifier("semi;colon"));
    }

    #[test]
    fn double_quote() {
        let mut sql = Sql::new();
        sql.push_schema_name(DatabaseName::Attached(r#"schema";--"#));
        assert_eq!(r#""schema"";--""#, sql.as_str());
    }

    #[test]
    fn wrap_and_escape() {
        let mut sql = Sql::new();
        sql.push_string_literal("value'; --");
        assert_eq!("'value''; --'", sql.as_str());
    }
}
<commit_msg>Suggest users to use PRAGMA function instead<commit_after>//! Pragma helpers

use std::ops::Deref;

use crate::error::Error;
use crate::ffi;
use crate::types::{ToSql, ToSqlOutput, ValueRef};
use crate::{Connection, DatabaseName, Result, Row, NO_PARAMS};

pub struct Sql {
    buf: String,
}

impl Sql {
    pub fn new() -> Sql {
        Sql { buf: String::new() }
    }

    pub fn push_pragma(
        &mut self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
    ) -> Result<()> {
        self.push_keyword("PRAGMA")?;
        self.push_space();
        if let Some(schema_name) = schema_name {
            self.push_schema_name(schema_name);
            self.push_dot();
        }
        self.push_keyword(pragma_name)
    }

    pub fn push_keyword(&mut self, keyword: &str) -> Result<()> {
        if !keyword.is_empty() && is_identifier(keyword) {
            self.buf.push_str(keyword);
            Ok(())
        } else {
            Err(Error::SqliteFailure(
                ffi::Error::new(ffi::SQLITE_MISUSE),
                Some(format!("Invalid keyword \"{}\"", keyword)),
            ))
        }
    }

    pub fn push_schema_name(&mut self, schema_name: DatabaseName<'_>) {
        match schema_name {
            DatabaseName::Main => self.buf.push_str("main"),
            DatabaseName::Temp => self.buf.push_str("temp"),
            DatabaseName::Attached(s) => self.push_identifier(s),
        };
    }

    pub fn push_identifier(&mut self, s: &str) {
        if is_identifier(s) {
            self.buf.push_str(s);
        } else {
            self.wrap_and_escape(s, '"');
        }
    }

    pub fn push_value(&mut self, value: &dyn ToSql) -> Result<()> {
        let value = value.to_sql()?;
        let value = match value {
            ToSqlOutput::Borrowed(v) => v,
            ToSqlOutput::Owned(ref v) => ValueRef::from(v),
            #[cfg(feature = "blob")]
            ToSqlOutput::ZeroBlob(_) => {
                return Err(Error::SqliteFailure(
                    ffi::Error::new(ffi::SQLITE_MISUSE),
                    Some(format!("Unsupported value \"{:?}\"", value)),
                ));
            }
            #[cfg(feature = "array")]
            ToSqlOutput::Array(_) => {
                return Err(Error::SqliteFailure(
                    ffi::Error::new(ffi::SQLITE_MISUSE),
                    Some(format!("Unsupported value \"{:?}\"", value)),
                ));
            }
        };
        match value {
            ValueRef::Integer(i) => {
                self.push_int(i);
            }
            ValueRef::Real(r) => {
                self.push_real(r);
            }
            ValueRef::Text(s) => {
                self.push_string_literal(s);
            }
            _ => {
                return Err(Error::SqliteFailure(
                    ffi::Error::new(ffi::SQLITE_MISUSE),
                    Some(format!("Unsupported value \"{:?}\"", value)),
                ));
            }
        };
        Ok(())
    }

    pub fn push_string_literal(&mut self, s: &str) {
        self.wrap_and_escape(s, '\'');
    }

    pub fn push_int(&mut self, i: i64) {
        self.buf.push_str(&i.to_string());
    }

    pub fn push_real(&mut self, f: f64) {
        self.buf.push_str(&f.to_string());
    }

    pub fn push_space(&mut self) {
        self.buf.push(' ');
    }

    pub fn push_dot(&mut self) {
        self.buf.push('.');
    }

    pub fn push_equal_sign(&mut self) {
        self.buf.push('=');
    }

    pub fn open_brace(&mut self) {
        self.buf.push('(');
    }

    pub fn close_brace(&mut self) {
        self.buf.push(')');
    }

    pub fn as_str(&self) -> &str {
        &self.buf
    }

    fn wrap_and_escape(&mut self, s: &str, quote: char) {
        self.buf.push(quote);
        let chars = s.chars();
        for ch in chars {
            // escape `quote` by doubling it
            if ch == quote {
                self.buf.push(ch);
            }
            self.buf.push(ch)
        }
        self.buf.push(quote);
    }
}

impl Deref for Sql {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl Connection {
    /// Query the current value of `pragma_name`.
    ///
    /// Some pragmas will return multiple rows/values which cannot be retrieved
    /// with this method.
    ///
    /// Prefer [PRAGMA function](https://sqlite.org/pragma.html#pragfunc) introduced in SQLite 3.20:
    /// `SELECT user_version FROM pragma_user_version;`
    pub fn pragma_query_value<T, F>(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        f: F,
    ) -> Result<T>
    where
        F: FnOnce(Row<'_, '_>) -> Result<T>,
    {
        let mut query = Sql::new();
        query.push_pragma(schema_name, pragma_name)?;
        let mut stmt = self.prepare(&query)?;
        let mut rows = stmt.query(NO_PARAMS)?;
        if let Some(result_row) = rows.next() {
            let row = result_row?;
            f(row)
        } else {
            Err(Error::QueryReturnedNoRows)
        }
    }

    /// Query the current rows/values of `pragma_name`.
    ///
    /// Prefer [PRAGMA function](https://sqlite.org/pragma.html#pragfunc) introduced in SQLite 3.20:
    /// `SELECT * FROM pragma_collation_list;`
    pub fn pragma_query<F>(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        mut f: F,
    ) -> Result<()>
    where
        F: FnMut(&Row<'_, '_>) -> Result<()>,
    {
        let mut query = Sql::new();
        query.push_pragma(schema_name, pragma_name)?;
        let mut stmt = self.prepare(&query)?;
        let mut rows = stmt.query(NO_PARAMS)?;
        while let Some(result_row) = rows.next() {
            let row = result_row?;
            f(&row)?;
        }
        Ok(())
    }

    /// Query the current value(s) of `pragma_name` associated to
    /// `pragma_value`.
    ///
    /// This method can be used with query-only pragmas which need an argument
    /// (e.g. `table_info('one_tbl')`) or pragmas which returns value(s)
    /// (e.g. `integrity_check`).
    ///
    /// Prefer [PRAGMA function](https://sqlite.org/pragma.html#pragfunc) introduced in SQLite 3.20:
    /// `SELECT * FROM pragma_table_info(?);`
    pub fn pragma<F>(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        pragma_value: &dyn ToSql,
        mut f: F,
    ) -> Result<()>
    where
        F: FnMut(&Row<'_, '_>) -> Result<()>,
    {
        let mut sql = Sql::new();
        sql.push_pragma(schema_name, pragma_name)?;
        // The argument is may be either in parentheses
        // or it may be separated from the pragma name by an equal sign.
        // The two syntaxes yield identical results.
        sql.open_brace();
        sql.push_value(pragma_value)?;
        sql.close_brace();
        let mut stmt = self.prepare(&sql)?;
        let mut rows = stmt.query(NO_PARAMS)?;
        while let Some(result_row) = rows.next() {
            let row = result_row?;
            f(&row)?;
        }
        Ok(())
    }

    /// Set a new value to `pragma_name`.
    ///
    /// Some pragmas will return the updated value which cannot be retrieved
    /// with this method.
    pub fn pragma_update(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        pragma_value: &dyn ToSql,
    ) -> Result<()> {
        let mut sql = Sql::new();
        sql.push_pragma(schema_name, pragma_name)?;
        // The argument is may be either in parentheses
        // or it may be separated from the pragma name by an equal sign.
        // The two syntaxes yield identical results.
        sql.push_equal_sign();
        sql.push_value(pragma_value)?;
        self.execute_batch(&sql)
    }

    /// Set a new value to `pragma_name` and return the updated value.
    ///
    /// Only few pragmas automatically return the updated value.
    pub fn pragma_update_and_check<F, T>(
        &self,
        schema_name: Option<DatabaseName<'_>>,
        pragma_name: &str,
        pragma_value: &dyn ToSql,
        f: F,
    ) -> Result<T>
    where
        F: FnOnce(Row<'_, '_>) -> Result<T>,
    {
        let mut sql = Sql::new();
        sql.push_pragma(schema_name, pragma_name)?;
        // The argument is may be either in parentheses
        // or it may be separated from the pragma name by an equal sign.
        // The two syntaxes yield identical results.
        sql.push_equal_sign();
        sql.push_value(pragma_value)?;
        let mut stmt = self.prepare(&sql)?;
        let mut rows = stmt.query(NO_PARAMS)?;
        if let Some(result_row) = rows.next() {
            let row = result_row?;
            f(row)
        } else {
            Err(Error::QueryReturnedNoRows)
        }
    }
}

fn is_identifier(s: &str) -> bool {
    let chars = s.char_indices();
    for (i, ch) in chars {
        if i == 0 {
            if !is_identifier_start(ch) {
                return false;
            }
        } else if !is_identifier_continue(ch) {
            return false;
        }
    }
    true
}

fn is_identifier_start(c: char) -> bool {
    (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z') || c > '\x7F'
}

fn is_identifier_continue(c: char) -> bool {
    c == '$'
        || (c >= '0' && c <= '9')
        || (c >= 'A' && c <= 'Z')
        || c == '_'
        || (c >= 'a' && c <= 'z')
        || c > '\x7F'
}

#[cfg(test)]
mod test {
    use super::Sql;
    use crate::pragma;
    use crate::{Connection, DatabaseName, NO_PARAMS};

    #[test]
    fn pragma_query_value() {
        let db = Connection::open_in_memory().unwrap();
        let user_version: i32 = db
            .pragma_query_value(None, "user_version", |row| row.get_checked(0))
            .unwrap();
        assert_eq!(0, user_version);
    }

    #[test]
    #[cfg(feature = "bundled")]
    fn pragma_func_query_value() {
        let db = Connection::open_in_memory().unwrap();
        let user_version: i32 = db
            .query_row(
                "SELECT user_version FROM pragma_user_version",
                NO_PARAMS,
                |row| row.get(0),
            )
            .unwrap();
        assert_eq!(0, user_version);
    }

    #[test]
    fn pragma_query_no_schema() {
        let db = Connection::open_in_memory().unwrap();
        let mut user_version = -1;
        db.pragma_query(None, "user_version", |row| {
            user_version = row.get_checked(0)?;
            Ok(())
        })
        .unwrap();
        assert_eq!(0, user_version);
    }

    #[test]
    fn pragma_query_with_schema() {
        let db = Connection::open_in_memory().unwrap();
        let mut user_version = -1;
        db.pragma_query(Some(DatabaseName::Main), "user_version", |row| {
            user_version = row.get_checked(0)?;
            Ok(())
        })
        .unwrap();
        assert_eq!(0, user_version);
    }

    #[test]
    fn pragma() {
        let db = Connection::open_in_memory().unwrap();
        let mut columns = Vec::new();
        db.pragma(None, "table_info", &"sqlite_master", |row| {
            let column: String = row.get_checked(1)?;
            columns.push(column);
            Ok(())
        })
        .unwrap();
        assert_eq!(5, columns.len());
    }

    #[test]
    #[cfg(feature = "bundled")]
    fn pragma_func() {
        let db = Connection::open_in_memory().unwrap();
        let mut table_info = db.prepare("SELECT * FROM pragma_table_info(?)").unwrap();
        let mut columns = Vec::new();
        let mut rows = table_info.query(&["sqlite_master"]).unwrap();

        while let Some(row) = rows.next() {
            let row = row.unwrap();
            let column: String = row.get(1);
            columns.push(column);
        }
        assert_eq!(5, columns.len());
    }

    #[test]
    fn pragma_update() {
        let db = Connection::open_in_memory().unwrap();
        db.pragma_update(None, "user_version", &1).unwrap();
    }

    #[test]
    fn pragma_update_and_check() {
        let db = Connection::open_in_memory().unwrap();
        let journal_mode: String = db
            .pragma_update_and_check(None, "journal_mode", &"OFF", |row| row.get_checked(0))
            .unwrap();
        assert_eq!("off", &journal_mode);
    }

    #[test]
    fn is_identifier() {
        assert!(pragma::is_identifier("full"));
        assert!(pragma::is_identifier("r2d2"));
        assert!(!pragma::is_identifier("sp ce"));
        assert!(!pragma::is_identifier("semi;colon"));
    }

    #[test]
    fn double_quote() {
        let mut sql = Sql::new();
        sql.push_schema_name(DatabaseName::Attached(r#"schema";--"#));
        assert_eq!(r#""schema"";--""#, sql.as_str());
    }

    #[test]
    fn wrap_and_escape() {
        let mut sql = Sql::new();
        sql.push_string_literal("value'; --");
        assert_eq!("'value''; --'", sql.as_str());
    }
}
<|endoftext|>


<commit_before>extern crate termion;

use termion::raw::*;
use termion::clear;
use termion::color;
use termion::input::MouseTerminal;

use actor::*;
use floor::*;
use world::*;
use primitive::*;

use std::io::{Write, stdout};
use std::sync::*;
use std::thread;
use std::time::Duration;

fn render_floor<W : Write>(screen : &mut W, floor: &Floor) {
    for row in &floor.tiles {
        let mut line = String::new();
        for tile in row {
            if let Some(ref wall) = tile.wall {
                line.push_str(wall);
            } else {
                line.push_str(" "); // U-2027
                //line.push_str("‧"); // U-2027
            }
        }
        write!(screen, "{}\n\r", line).unwrap(); // U-2502
    }
}

fn goto_cursor_coord(coord : &Coord) -> termion::cursor::Goto {
    // Coordinate translation naively assumes floor is being rendered at 1,1
    termion::cursor::Goto(coord.col+1, coord.row+1)
}

pub fn render_loop(world_mutex : Arc<Mutex<World>>, stop : Arc<Mutex<bool>>, dirty_coord_rx : mpsc::Receiver<Coord>) {
    let mut screen = MouseTerminal::from(stdout().into_raw_mode().unwrap());
    // Hide the cursor, clear the screen
    write!(screen, "{}{}", termion::cursor::Hide, termion::clear::All).unwrap();

    {
        write!(screen, "{}", termion::cursor::Goto(1, 1)).unwrap();
        let world = world_mutex.lock().unwrap();
        render_floor(&mut screen, &world.floor);
    }

    // Render Loop
    loop {
        // Time to stop?
        {
            let stop = stop.lock().unwrap();
            if *stop {
                break;
            }
        }

        let world = world_mutex.lock().unwrap();

        // Redraw any dirty world coordinates
        while let Ok(coord) = dirty_coord_rx.try_recv() {
            write!(screen, "{}{}", goto_cursor_coord(&coord), world.floor.get_symbol(&coord)).unwrap();
        }

        // Render Player
        write!(screen, "{}", goto_cursor_coord(&world.player.coord())).unwrap();
        write!(screen, "{}", &world.player.symbol()).unwrap();

        // Render Monsters
        for monster in &world.monsters {
            write!(screen, "{}", goto_cursor_coord(monster.coord())).unwrap();
            write!(screen, "{}", monster.symbol()).unwrap();
        }

        // Bottom text
        write!(screen, "{}", termion::cursor::Goto(1, (world.floor.rows+1) as u16)).unwrap();
        write!(screen, "{}\n\r\n\r", world.floor.name).unwrap(); // Dungeon Name
        for msg in &world.messages {
            write!(screen, "{}{}", color::Fg(color::LightWhite), msg).unwrap();
            write!(screen, "{}{}\n\r", color::Fg(color::Reset), clear::UntilNewline).unwrap();
        }

        screen.flush().unwrap();

        // Don't render too hot.
        thread::sleep(Duration::from_millis(50));
    }

    // Nice cleanup: Move cursor below the world, so we can see how we finished
    {
        let world = world_mutex.lock().unwrap();
        write!(screen, "{}", goto_cursor_coord(&Coord { col: 0, row: (world.floor.rows+7) as u16})).unwrap();
    }
    print!("{}", termion::cursor::Show);
    screen.flush().unwrap();
}

<commit_msg>simplify<commit_after>extern crate termion;

use termion::raw::*;
use termion::clear;
use termion::color;
use termion::input::MouseTerminal;

use actor::*;
use floor::*;
use world::*;
use primitive::*;

use std::io::{Write, stdout};
use std::sync::*;
use std::thread;
use std::time::Duration;

fn render_floor<W : Write>(screen : &mut W, floor: &Floor) {
    for row in &floor.tiles {
        let mut line = String::new();
        for tile in row {
            if let Some(ref wall) = tile.wall {
                line.push_str(wall);
            } else {
                line.push_str(" "); // U-2027
                //line.push_str("‧"); // U-2027
            }
        }
        write!(screen, "{}\n\r", line).unwrap(); // U-2502
    }
}

fn goto_cursor_coord(coord : Coord) -> termion::cursor::Goto {
    // Coordinate translation naively assumes floor is being rendered at 1,1
    termion::cursor::Goto(coord.col+1, coord.row+1)
}

pub fn render_loop(world_mutex : Arc<Mutex<World>>, stop : Arc<Mutex<bool>>, dirty_coord_rx : mpsc::Receiver<Coord>) {
    let mut screen = MouseTerminal::from(stdout().into_raw_mode().unwrap());
    // Hide the cursor, clear the screen
    write!(screen, "{}{}", termion::cursor::Hide, termion::clear::All).unwrap();

    {
        write!(screen, "{}", termion::cursor::Goto(1, 1)).unwrap();
        let world = world_mutex.lock().unwrap();
        render_floor(&mut screen, &world.floor);
    }

    // Render Loop
    loop {
        // Time to stop?
        {
            let stop = stop.lock().unwrap();
            if *stop {
                break;
            }
        }

        let world = world_mutex.lock().unwrap();

        // Redraw any dirty world coordinates
        while let Ok(coord) = dirty_coord_rx.try_recv() {
            write!(screen, "{}{}", goto_cursor_coord(coord), world.floor.get_symbol(&coord)).unwrap();
        }

        // Render Player
        write!(screen, "{}", goto_cursor_coord(world.player.coord())).unwrap();
        write!(screen, "{}", &world.player.symbol()).unwrap();

        // Render Monsters
        for monster in &world.monsters {
            write!(screen, "{}", goto_cursor_coord(monster.coord())).unwrap();
            write!(screen, "{}", monster.symbol()).unwrap();
        }

        // Bottom text
        write!(screen, "{}", termion::cursor::Goto(1, (world.floor.rows+1) as u16)).unwrap();
        write!(screen, "{}\n\r\n\r", world.floor.name).unwrap(); // Dungeon Name
        for msg in &world.messages {
            write!(screen, "{}{}", color::Fg(color::LightWhite), msg).unwrap();
            write!(screen, "{}{}\n\r", color::Fg(color::Reset), clear::UntilNewline).unwrap();
        }

        screen.flush().unwrap();

        // Don't render too hot.
        thread::sleep(Duration::from_millis(50));
    }

    // Nice cleanup: Move cursor below the world, so we can see how we finished
    {
        let world = world_mutex.lock().unwrap();
        write!(screen, "{}", goto_cursor_coord(Coord { col: 0, row: (world.floor.rows+7) as u16})).unwrap();
    }
    print!("{}", termion::cursor::Show);
    screen.flush().unwrap();
}

<|endoftext|>


<commit_before>use std::fmt;
use std::io;
use std::borrow::Cow;
use std::str::Utf8Error;
use std::result::Result as StdResult;
use std::error::Error as StdError;
use std::convert::{From, Into};

use httparse;
use mio;
#[cfg(feature="ssl")]
use openssl::ssl::{Error as SslError, HandshakeError as SslHandshakeError};
#[cfg(feature="ssl")]
type HandshakeError = SslHandshakeError<mio::tcp::TcpStream>;

use communication::Command;

pub type Result<T> = StdResult<T, Error>;

/// The type of an error, which may indicate other kinds of errors as the underlying cause.
#[derive(Debug)]
pub enum Kind {
    /// Indicates an internal application error.
    /// The WebSocket will automatically attempt to send an Error (1011) close code.
    Internal,
    /// Indicates a state where some size limit has been exceeded, such as an inability to accept
    /// any more new connections.
    /// If a Connection is active, the WebSocket will automatically attempt to send
    /// a Size (1009) close code.
    Capacity,
    /// Indicates a violation of the WebSocket protocol.
    /// The WebSocket will automatically attempt to send a Protocol (1002) close code, or if
    /// this error occurs during a handshake, an HTTP 400 response will be generated.
    Protocol,
    /// Indicates that the WebSocket received data that should be utf8 encoded but was not.
    /// The WebSocket will automatically attempt to send a Invalid Frame Payload Data (1007) close
    /// code.
    Encoding(Utf8Error),
    /// Indicates an underlying IO Error.
    /// This kind of error will result in a WebSocket Connection disconnecting.
    Io(io::Error),
    /// Indicates a failure to parse an HTTP message.
    /// This kind of error should only occur during a WebSocket Handshake, and a HTTP 500 response
    /// will be generated.
    Http(httparse::Error),
    /// Indicates a failure to send a signal on the internal EventLoop channel. This means that
    /// the WebSocket is overloaded. In order to avoid this error, it is important to set
    /// `Settings::max_connections` and `Settings:queue_size` high enough to handle the load.
    /// If encountered, retuning from a handler method and waiting for the EventLoop to consume
    /// the queue may relieve the situation.
    Queue(mio::channel::SendError<Command>),
    /// Indicates a failure to schedule a timeout on the EventLoop.
    Timer(mio::timer::TimerError),
    /// Indicates a failure to perform SSL encryption.
    #[cfg(feature="ssl")]
    Ssl(SslError),
    /// Indicates a failure to perform SSL encryption.
    #[cfg(feature="ssl")]
    SslHandshake(HandshakeError),
    /// A custom error kind for use by applications. This error kind involves extra overhead
    /// because it will allocate the memory on the heap. The WebSocket ignores such errors by
    /// default, simply passing them to the Connection Handler.
    Custom(Box<StdError + Send + Sync>),
}

/// A struct indicating the kind of error that has occurred and any precise details of that error.
pub struct Error {
    pub kind: Kind,
    pub details: Cow<'static, str>,
}

impl Error {

    pub fn new<I>(kind: Kind, details: I) -> Error
        where I: Into<Cow<'static, str>>
    {
        Error {
            kind: kind,
            details: details.into(),
        }
    }

    pub fn into_box(self) -> Box<StdError> {
        match self.kind {
            Kind::Custom(err) => err,
            _ => Box::new(self),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.details.len() > 0 {
            write!(f, "WS Error <{:?}>: {}", self.kind, self.details)
        } else {
            write!(f, "WS Error <{:?}>", self.kind)
        }
    }
}

impl fmt::Display for Error {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.details.len() > 0 {
            write!(f, "{}: {}", self.description(), self.details)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl StdError for Error {

    fn description(&self) -> &str {
        match self.kind {
            Kind::Internal              => "Internal Application Error",
            Kind::Capacity              => "WebSocket at Capacity",
            Kind::Protocol              => "WebSocket Protocol Error",
            Kind::Encoding(ref err)     => err.description(),
            Kind::Io(ref err)           => err.description(),
            Kind::Http(_)               => "Unable to parse HTTP",
            #[cfg(feature="ssl")]
            Kind::Ssl(ref err)          => err.description(),
            #[cfg(feature="ssl")]
            Kind::SslHandshake(ref err) => err.description(),
            Kind::Queue(_)              => "Unable to send signal on event loop",
            Kind::Timer(_)              => "Unable to schedule timeout on event loop",
            Kind::Custom(ref err)       => err.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.kind {
            Kind::Encoding(ref err) => Some(err),
            Kind::Io(ref err)       => Some(err),
            #[cfg(feature="ssl")]
            Kind::Ssl(ref err)      => Some(err),
            #[cfg(feature="ssl")]
            Kind::SslHandshake(ref err)      => err.cause(),
            Kind::Custom(ref err)   => Some(err.as_ref()),
            _ => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::new(Kind::Io(err), "")
    }
}

impl From<httparse::Error> for Error {

    fn from(err: httparse::Error) -> Error {
        let details = match err {
            httparse::Error::HeaderName => "Invalid byte in header name.",
            httparse::Error::HeaderValue => "Invalid byte in header value.",
            httparse::Error::NewLine => "Invalid byte in new line.",
            httparse::Error::Status => "Invalid byte in Response status.",
            httparse::Error::Token => "Invalid byte where token is required.",
            httparse::Error::TooManyHeaders => "Parsed more headers than provided buffer can contain.",
            httparse::Error::Version => "Invalid byte in HTTP version.",
        };

        Error::new(Kind::Http(err), details)
    }

}

impl From<mio::channel::SendError<Command>> for Error {

    fn from(err: mio::channel::SendError<Command>) -> Error {
        match err {
            mio::channel::SendError::Io(err) => Error::from(err),
            _ => Error::new(Kind::Queue(err), "")
        }
    }

}

impl From<mio::timer::TimerError> for Error {

    fn from(err: mio::timer::TimerError) -> Error {
        match err {
            _ => Error::new(Kind::Timer(err), "")
        }
    }

}

impl From<Utf8Error> for Error {
    fn from(err: Utf8Error) -> Error {
        Error::new(Kind::Encoding(err), "")
    }
}

#[cfg(feature="ssl")]
impl From<SslError> for Error {
    fn from(err: SslError) -> Error {
        Error::new(Kind::Ssl(err), "")
    }
}

#[cfg(feature="ssl")]
impl From<HandshakeError> for Error {
    fn from(err: HandshakeError) -> Error {
        Error::new(Kind::SslHandshake(err), "")
    }
}

impl<B> From<Box<B>> for Error
    where B: StdError + Send + Sync + 'static
{
    fn from(err: Box<B>) -> Error {
        Error::new(Kind::Custom(err), "")
    }
}
<commit_msg>Updating docs for ErrorKind::Internal<commit_after>use std::fmt;
use std::io;
use std::borrow::Cow;
use std::str::Utf8Error;
use std::result::Result as StdResult;
use std::error::Error as StdError;
use std::convert::{From, Into};

use httparse;
use mio;
#[cfg(feature="ssl")]
use openssl::ssl::{Error as SslError, HandshakeError as SslHandshakeError};
#[cfg(feature="ssl")]
type HandshakeError = SslHandshakeError<mio::tcp::TcpStream>;

use communication::Command;

pub type Result<T> = StdResult<T, Error>;

/// The type of an error, which may indicate other kinds of errors as the underlying cause.
#[derive(Debug)]
pub enum Kind {
    /// Indicates an internal application error.
    /// If panic_on_internal is true, which is the default, then the application will panic.
    /// Otherwise the WebSocket will automatically attempt to send an Error (1011) close code.
    Internal,
    /// Indicates a state where some size limit has been exceeded, such as an inability to accept
    /// any more new connections.
    /// If a Connection is active, the WebSocket will automatically attempt to send
    /// a Size (1009) close code.
    Capacity,
    /// Indicates a violation of the WebSocket protocol.
    /// The WebSocket will automatically attempt to send a Protocol (1002) close code, or if
    /// this error occurs during a handshake, an HTTP 400 response will be generated.
    Protocol,
    /// Indicates that the WebSocket received data that should be utf8 encoded but was not.
    /// The WebSocket will automatically attempt to send a Invalid Frame Payload Data (1007) close
    /// code.
    Encoding(Utf8Error),
    /// Indicates an underlying IO Error.
    /// This kind of error will result in a WebSocket Connection disconnecting.
    Io(io::Error),
    /// Indicates a failure to parse an HTTP message.
    /// This kind of error should only occur during a WebSocket Handshake, and a HTTP 500 response
    /// will be generated.
    Http(httparse::Error),
    /// Indicates a failure to send a signal on the internal EventLoop channel. This means that
    /// the WebSocket is overloaded. In order to avoid this error, it is important to set
    /// `Settings::max_connections` and `Settings:queue_size` high enough to handle the load.
    /// If encountered, retuning from a handler method and waiting for the EventLoop to consume
    /// the queue may relieve the situation.
    Queue(mio::channel::SendError<Command>),
    /// Indicates a failure to schedule a timeout on the EventLoop.
    Timer(mio::timer::TimerError),
    /// Indicates a failure to perform SSL encryption.
    #[cfg(feature="ssl")]
    Ssl(SslError),
    /// Indicates a failure to perform SSL encryption.
    #[cfg(feature="ssl")]
    SslHandshake(HandshakeError),
    /// A custom error kind for use by applications. This error kind involves extra overhead
    /// because it will allocate the memory on the heap. The WebSocket ignores such errors by
    /// default, simply passing them to the Connection Handler.
    Custom(Box<StdError + Send + Sync>),
}

/// A struct indicating the kind of error that has occurred and any precise details of that error.
pub struct Error {
    pub kind: Kind,
    pub details: Cow<'static, str>,
}

impl Error {

    pub fn new<I>(kind: Kind, details: I) -> Error
        where I: Into<Cow<'static, str>>
    {
        Error {
            kind: kind,
            details: details.into(),
        }
    }

    pub fn into_box(self) -> Box<StdError> {
        match self.kind {
            Kind::Custom(err) => err,
            _ => Box::new(self),
        }
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.details.len() > 0 {
            write!(f, "WS Error <{:?}>: {}", self.kind, self.details)
        } else {
            write!(f, "WS Error <{:?}>", self.kind)
        }
    }
}

impl fmt::Display for Error {

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.details.len() > 0 {
            write!(f, "{}: {}", self.description(), self.details)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl StdError for Error {

    fn description(&self) -> &str {
        match self.kind {
            Kind::Internal              => "Internal Application Error",
            Kind::Capacity              => "WebSocket at Capacity",
            Kind::Protocol              => "WebSocket Protocol Error",
            Kind::Encoding(ref err)     => err.description(),
            Kind::Io(ref err)           => err.description(),
            Kind::Http(_)               => "Unable to parse HTTP",
            #[cfg(feature="ssl")]
            Kind::Ssl(ref err)          => err.description(),
            #[cfg(feature="ssl")]
            Kind::SslHandshake(ref err) => err.description(),
            Kind::Queue(_)              => "Unable to send signal on event loop",
            Kind::Timer(_)              => "Unable to schedule timeout on event loop",
            Kind::Custom(ref err)       => err.description(),
        }
    }

    fn cause(&self) -> Option<&StdError> {
        match self.kind {
            Kind::Encoding(ref err) => Some(err),
            Kind::Io(ref err)       => Some(err),
            #[cfg(feature="ssl")]
            Kind::Ssl(ref err)      => Some(err),
            #[cfg(feature="ssl")]
            Kind::SslHandshake(ref err)      => err.cause(),
            Kind::Custom(ref err)   => Some(err.as_ref()),
            _ => None,
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::new(Kind::Io(err), "")
    }
}

impl From<httparse::Error> for Error {

    fn from(err: httparse::Error) -> Error {
        let details = match err {
            httparse::Error::HeaderName => "Invalid byte in header name.",
            httparse::Error::HeaderValue => "Invalid byte in header value.",
            httparse::Error::NewLine => "Invalid byte in new line.",
            httparse::Error::Status => "Invalid byte in Response status.",
            httparse::Error::Token => "Invalid byte where token is required.",
            httparse::Error::TooManyHeaders => "Parsed more headers than provided buffer can contain.",
            httparse::Error::Version => "Invalid byte in HTTP version.",
        };

        Error::new(Kind::Http(err), details)
    }

}

impl From<mio::channel::SendError<Command>> for Error {

    fn from(err: mio::channel::SendError<Command>) -> Error {
        match err {
            mio::channel::SendError::Io(err) => Error::from(err),
            _ => Error::new(Kind::Queue(err), "")
        }
    }

}

impl From<mio::timer::TimerError> for Error {

    fn from(err: mio::timer::TimerError) -> Error {
        match err {
            _ => Error::new(Kind::Timer(err), "")
        }
    }

}

impl From<Utf8Error> for Error {
    fn from(err: Utf8Error) -> Error {
        Error::new(Kind::Encoding(err), "")
    }
}

#[cfg(feature="ssl")]
impl From<SslError> for Error {
    fn from(err: SslError) -> Error {
        Error::new(Kind::Ssl(err), "")
    }
}

#[cfg(feature="ssl")]
impl From<HandshakeError> for Error {
    fn from(err: HandshakeError) -> Error {
        Error::new(Kind::SslHandshake(err), "")
    }
}

impl<B> From<Box<B>> for Error
    where B: StdError + Send + Sync + 'static
{
    fn from(err: Box<B>) -> Error {
        Error::new(Kind::Custom(err), "")
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use iron::{Request, Response, Handler, IronResult, Error, IronError, Set};
use iron::{status, method};
use iron::response::modifiers::Status;
use iron::typemap::Assoc;
use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    // The routers, specialized by method.
    routers: HashMap<method::Method, Recognizer<Box<Handler + Send + Sync>>>,
    error: Option<Box<Handler + Send + Sync>>
}

#[deriving(Show)]
/// The error thrown by router if there is no matching route.
pub struct NoRoute;

impl Error for NoRoute {
    fn name(&self) -> &'static str { "No Route" }
}

impl Router {
    /// `new` constructs a new, blank `Router`.
    pub fn new() -> Router { Router { routers: HashMap::new(), error: None } }
    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// router.route(iron::method::Method::Get, "/users/:userid/:friendid", controller);
    /// ```
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<H: Handler, S: Str>(&mut self, method: method::Method, glob: S, handler: H) -> &mut Router {
        match self.routers.entry(method) {
            Vacant(entry)   => entry.set(Recognizer::new()),
            Occupied(entry) => entry.into_mut()
        }.add(glob.as_slice(), box handler as Box<Handler + Send + Sync>);
        self
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Get, glob, handler)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Post, glob, handler)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Put, glob, handler)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Delete, glob, handler)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Head, glob, handler)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Patch, glob, handler)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Options, glob, handler)
    }

    /// Add a Handler to be used for this Router's `catch` method.
    pub fn error<H: Handler>(&mut self, handler: H) -> &mut Router {
        self.error = Some(box handler as Box<Handler + Send + Sync>);
        self
    }

    fn recognize<'a>(&'a self, method: &method::Method, path: &str)
                     -> Option<Match<&'a Box<Handler + Send + Sync>>> {
        self.routers.get(method).and_then(|router| router.recognize(path).ok())
    }
}

impl Assoc<Params> for Router {}

impl Handler for Router {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let matched = match self.recognize(&req.method, req.url.path.connect("/").as_slice()) {
            Some(matched) => matched,
            // No match.
            None => return Err(box NoRoute as IronError)
        };

        req.extensions.insert::<Router, Params>(matched.params);
        matched.handler.call(req)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> (Response, IronResult<()>) {
        match self.error {
            Some(ref error_handler) => error_handler.catch(req, err),
            // Error that is not caught by anything!
            None => (Response::new().set(Status(status::InternalServerError)), Err(err))
        }
    }
}
<commit_msg>(fix) Use std::error interop with iron::Error.<commit_after>use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::error::Error;
use iron::{Request, Response, Handler, IronResult, IronError, Set};
use iron::{status, method};
use iron::response::modifiers::Status;
use iron::typemap::Assoc;
use recognizer::Router as Recognizer;
use recognizer::{Match, Params};

/// `Router` provides an interface for creating complex routes as middleware
/// for the Iron framework.
pub struct Router {
    // The routers, specialized by method.
    routers: HashMap<method::Method, Recognizer<Box<Handler + Send + Sync>>>,
    error: Option<Box<Handler + Send + Sync>>
}

#[deriving(Show)]
/// The error thrown by router if there is no matching route.
pub struct NoRoute;

impl Error for NoRoute {
    fn description(&self) -> &str { "No Route" }
}

impl Router {
    /// `new` constructs a new, blank `Router`.
    pub fn new() -> Router { Router { routers: HashMap::new(), error: None } }
    /// Add a new route to a `Router`, matching both a method and glob pattern.
    ///
    /// `route` supports glob patterns: `*` for a single wildcard segment and
    /// `:param` for matching storing that segment of the request url in the `Params`
    /// object, which is stored in the request `extensions`.
    ///
    /// For instance, to route `Get` requests on any route matching
    /// `/users/:userid/:friend` and store `userid` and `friend` in
    /// the exposed Params object:
    ///
    /// ```ignore
    /// router.route(iron::method::Method::Get, "/users/:userid/:friendid", controller);
    /// ```
    ///
    /// The controller provided to route can be any `Handler`, which allows
    /// extreme flexibility when handling routes. For instance, you could provide
    /// a `Chain`, a `Handler`, which contains an authorization middleware and
    /// a controller function, so that you can confirm that the request is
    /// authorized for this route before handling it.
    pub fn route<H: Handler, S: Str>(&mut self, method: method::Method, glob: S, handler: H) -> &mut Router {
        match self.routers.entry(method) {
            Vacant(entry)   => entry.set(Recognizer::new()),
            Occupied(entry) => entry.into_mut()
        }.add(glob.as_slice(), box handler as Box<Handler + Send + Sync>);
        self
    }

    /// Like route, but specialized to the `Get` method.
    pub fn get<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Get, glob, handler)
    }

    /// Like route, but specialized to the `Post` method.
    pub fn post<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Post, glob, handler)
    }

    /// Like route, but specialized to the `Put` method.
    pub fn put<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Put, glob, handler)
    }

    /// Like route, but specialized to the `Delete` method.
    pub fn delete<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Delete, glob, handler)
    }

    /// Like route, but specialized to the `Head` method.
    pub fn head<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Head, glob, handler)
    }

    /// Like route, but specialized to the `Patch` method.
    pub fn patch<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Patch, glob, handler)
    }

    /// Like route, but specialized to the `Options` method.
    pub fn options<H: Handler, S: Str>(&mut self, glob: S, handler: H) -> &mut Router {
        self.route(method::Options, glob, handler)
    }

    /// Add a Handler to be used for this Router's `catch` method.
    pub fn error<H: Handler>(&mut self, handler: H) -> &mut Router {
        self.error = Some(box handler as Box<Handler + Send + Sync>);
        self
    }

    fn recognize<'a>(&'a self, method: &method::Method, path: &str)
                     -> Option<Match<&'a Box<Handler + Send + Sync>>> {
        self.routers.get(method).and_then(|router| router.recognize(path).ok())
    }
}

impl Assoc<Params> for Router {}

impl Handler for Router {
    fn call(&self, req: &mut Request) -> IronResult<Response> {
        let matched = match self.recognize(&req.method, req.url.path.connect("/").as_slice()) {
            Some(matched) => matched,
            // No match.
            None => return Err(box NoRoute as IronError)
        };

        req.extensions.insert::<Router, Params>(matched.params);
        matched.handler.call(req)
    }

    fn catch(&self, req: &mut Request, err: IronError) -> (Response, IronResult<()>) {
        match self.error {
            Some(ref error_handler) => error_handler.catch(req, err),
            // Error that is not caught by anything!
            None => (Response::new().set(Status(status::InternalServerError)), Err(err))
        }
    }
}
<|endoftext|>


<commit_before>//! Serial interface
//!
//! You can use the `Serial` interface with these USART instances
//!
//! # USART1
//!
//! - TX = PA9
//! - RX = PA10
//! - Interrupt = USART1
//!
//! # USART2
//!
//! - TX = PA2
//! - RX = PA3
//! - Interrupt = USART2
//!
//! # USART3
//!
//! - TX = PB10
//! - RX = PB11
//! - Interrupt = USART3

use core::any::{Any, TypeId};
use core::marker::Unsize;
use core::ops::Deref;
use core::ptr;

use cast::u16;
use hal;
use nb;
use static_ref::Ref;
use stm32f103xx::{AFIO, DMA1, GPIOA, GPIOB, RCC, USART1, USART2, USART3, gpioa, usart1};

use dma::{self, Buffer, Dma1Channel4, Dma1Channel5};

/// Specialized `Result` type
pub type Result<T> = ::core::result::Result<T, nb::Error<Error>>;

/// IMPLEMENTATION DETAIL
pub unsafe trait Usart: Deref<Target = usart1::RegisterBlock> {
    /// IMPLEMENTATION DETAIL
    type GPIO: Deref<Target = gpioa::RegisterBlock>;
    /// IMPLEMENTATION DETAIL
    type Ticks: Into<u32>;
}

unsafe impl Usart for USART1 {
    type GPIO = GPIOA;
    type Ticks = ::apb2::Ticks;
}

unsafe impl Usart for USART2 {
    type GPIO = GPIOA;
    type Ticks = ::apb1::Ticks;
}

unsafe impl Usart for USART3 {
    type GPIO = GPIOB;
    type Ticks = ::apb1::Ticks;
}

/// An error
#[derive(Debug)]
pub enum Error {
    /// De-synchronization, excessive noise or a break character detected
    Framing,
    /// Noise detected in the received frame
    Noise,
    /// RX buffer overrun
    Overrun,
    #[doc(hidden)]
    _Extensible,
}

/// Interrupt event
pub enum Event {
    /// RX buffer Not Empty (new data available)
    Rxne,
    /// Transmission Complete
    Tc,
    /// TX buffer Empty (more data can be send)
    Txe,
}

/// Serial interface
///
/// # Interrupts
///
/// - RXNE
pub struct Serial<'a, U>(pub &'a U) where U: Any + Usart;

impl<'a, U> Clone for Serial<'a, U>
    where U: Any + Usart
{
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a, U> Copy for Serial<'a, U> where U: Any + Usart {}

impl<'a, U> Serial<'a, U>
    where U: Any + Usart
{
    /// Initializes the serial interface with a baud rate of `baut_rate` bits
    /// per second
    ///
    /// The serial interface will be configured to use 8 bits of data, 1 stop
    /// bit, no hardware control and to omit parity checking
    pub fn init<B>(&self,
                   baud_rate: B,
                   afio: &AFIO,
                   dma1: Option<&DMA1>,
                   gpio: &U::GPIO,
                   rcc: &RCC)
        where B: Into<U::Ticks>
    {
        self._init(baud_rate.into(), afio, dma1, gpio, rcc)
    }

    fn _init(&self,
             baud_rate: U::Ticks,
             afio: &AFIO,
             dma1: Option<&DMA1>,
             gpio: &U::GPIO,
             rcc: &RCC) {
        let usart = self.0;

        // power up peripherals
        if dma1.is_some() {
            rcc.ahbenr.modify(|_, w| w.dma1en().enabled());
        }
        if usart.get_type_id() == TypeId::of::<USART1>() {
            rcc.apb2enr
                .modify(|_, w| {
                            w.afioen()
                                .enabled()
                                .iopaen()
                                .enabled()
                                .usart1en()
                                .enabled()
                        });
        } else if usart.get_type_id() == TypeId::of::<USART2>() {
            rcc.apb1enr.modify(|_, w| w.usart2en().enabled());
            rcc.apb2enr
                .modify(|_, w| w.afioen().enabled().iopaen().enabled());
        } else if usart.get_type_id() == TypeId::of::<USART3>() {
            rcc.apb1enr.modify(|_, w| w.usart3en().enabled());
            rcc.apb2enr
                .modify(|_, w| w.afioen().enabled().iopben().enabled());
        }

        if usart.get_type_id() == TypeId::of::<USART1>() {
            // PA9 = TX, PA10 = RX
            afio.mapr.modify(|_, w| w.usart1_remap().clear());
            gpio.crh
                .modify(|_, w| {
                    w.mode9()
                        .output()
                        .cnf9()
                        .alt_push()
                        .mode10()
                        .input()
                        .cnf10()
                        .bits(0b01)
                });
        } else if usart.get_type_id() == TypeId::of::<USART2>() {
            // PA2 = TX, PA3 = RX
            afio.mapr.modify(|_, w| w.usart2_remap().clear());
            gpio.crl
                .modify(|_, w| {
                    w.mode2()
                        .output()
                        .cnf2()
                        .alt_push()
                        .mode3()
                        .input()
                        .cnf3()
                        .bits(0b01)
                });
        } else if usart.get_type_id() == TypeId::of::<USART3>() {
            // PB10 = TX, PB11 = RX
            afio.mapr
                .modify(|_, w| unsafe { w.usart3_remap().bits(0b00) });
            gpio.crh
                .modify(|_, w| {
                    w.mode10()
                        .output()
                        .cnf10()
                        .alt_push()
                        .mode11()
                        .input()
                        .cnf11()
                        .bits(0b01)
                });
        }

        if let Some(dma1) = dma1 {
            if usart.get_type_id() == TypeId::of::<USART1>() {
                // TX DMA transfer
                // mem2mem: Memory to memory mode disabled
                // pl: Medium priority
                // msize: Memory size = 8 bits
                // psize: Peripheral size = 8 bits
                // minc: Memory increment mode enabled
                // pinc: Peripheral increment mode disabled
                // circ: Circular mode disabled
                // dir: Transfer from memory to peripheral
                // tceie: Transfer complete interrupt enabled
                // en: Disabled
                dma1.ccr4
                    .write(|w| unsafe {
                        w.mem2mem()
                            .clear()
                            .pl()
                            .bits(0b01)
                            .msize()
                            .bits(0b00)
                            .psize()
                            .bits(0b00)
                            .minc()
                            .set()
                            .circ()
                            .clear()
                            .pinc()
                            .clear()
                            .dir()
                            .set()
                            .tcie()
                            .set()
                            .en()
                            .clear()
                    });

                // RX DMA transfer
                // mem2mem: Memory to memory mode disabled
                // pl: Medium priority
                // msize: Memory size = 8 bits
                // psize: Peripheral size = 8 bits
                // minc: Memory increment mode enabled
                // pinc: Peripheral increment mode disabled
                // circ: Circular mode disabled
                // dir: Transfer from peripheral to memory
                // tceie: Transfer complete interrupt enabled
                // en: Disabled
                dma1.ccr5
                    .write(|w| unsafe {
                        w.mem2mem()
                            .clear()
                            .pl()
                            .bits(0b01)
                            .msize()
                            .bits(0b00)
                            .psize()
                            .bits(0b00)
                            .minc()
                            .set()
                            .circ()
                            .clear()
                            .pinc()
                            .clear()
                            .dir()
                            .clear()
                            .tcie()
                            .set()
                            .en()
                            .clear()
                    });
            } else {
                // TODO enable DMA for USART{2,3}
                unimplemented!()
            }
        }

        // 8N1
        usart.cr2.write(|w| unsafe { w.stop().bits(0b00) });

        // baud rate
        let brr = baud_rate.into();

        assert!(brr >= 16, "impossible baud rate");

        usart.brr.write(|w| unsafe { w.bits(brr) });

        // disable hardware flow control
        // enable DMA TX and RX transfers
        usart
            .cr3
            .write(|w| {
                w.rtse()
                    .clear()
                    .ctse()
                    .clear()
                    .dmat()
                    .set()
                    .dmar()
                    .set()
            });

        // enable TX, RX; disable parity checking
        usart
            .cr1
            .write(|w| {
                w.ue()
                    .set()
                    .re()
                    .set()
                    .te()
                    .set()
                    .m()
                    .clear()
                    .pce()
                    .clear()
                    .rxneie()
                    .clear()
            });
    }

    /// Starts listening for an interrupt `event`
    pub fn listen(&self, event: Event) {
        let usart = self.0;

        match event {
            Event::Rxne => usart.cr1.modify(|_, w| w.rxneie().set()),
            Event::Tc => usart.cr1.modify(|_, w| w.tcie().set()),
            Event::Txe => usart.cr1.modify(|_, w| w.txeie().set()),
        }
    }

    /// Stops listening for an interrupt `event`
    pub fn unlisten(&self, event: Event) {
        let usart = self.0;

        match event {
            Event::Rxne => usart.cr1.modify(|_, w| w.rxneie().clear()),
            Event::Tc => usart.cr1.modify(|_, w| w.tcie().clear()),
            Event::Txe => usart.cr1.modify(|_, w| w.txeie().clear()),
        }
    }
}

impl<'a, U> hal::Serial for Serial<'a, U>
    where U: Any + Usart
{
    type Error = Error;

    fn read(&self) -> Result<u8> {
        let usart1 = self.0;
        let sr = usart1.sr.read();

        if sr.ore().is_set() {
            Err(nb::Error::Other(Error::Overrun))
        } else if sr.ne().is_set() {
            Err(nb::Error::Other(Error::Noise))
        } else if sr.fe().is_set() {
            Err(nb::Error::Other(Error::Framing))
        } else if sr.rxne().is_set() {
            // NOTE(read_volatile) the register is 9 bits big but we'll only
            // work with the first 8 bits
            Ok(unsafe { ptr::read_volatile(&usart1.dr as *const _ as *const u8) })
        } else {
            Err(nb::Error::WouldBlock)
        }
    }

    fn write(&self, byte: u8) -> Result<()> {
        let usart1 = self.0;
        let sr = usart1.sr.read();

        if sr.ore().is_set() {
            Err(nb::Error::Other(Error::Overrun))
        } else if sr.ne().is_set() {
            Err(nb::Error::Other(Error::Noise))
        } else if sr.fe().is_set() {
            Err(nb::Error::Other(Error::Framing))
        } else if sr.txe().is_set() {
            // NOTE(write_volatile) see NOTE in the `read` method
            unsafe { ptr::write_volatile(&usart1.dr as *const _ as *mut u8, byte) }
            Ok(())
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}

impl<'a> Serial<'a, USART1> {
    /// Starts a DMA transfer to receive serial data into a `buffer`
    ///
    /// This will mutably lock the `buffer` preventing borrowing its contents
    /// The `buffer` can be `release`d after the DMA transfer finishes
    // TODO support circular mode + half transfer interrupt as a double
    // buffering mode
    pub fn read_exact<B>(&self,
                         dma1: &DMA1,
                         buffer: Ref<Buffer<B, Dma1Channel5>>)
                         -> ::core::result::Result<(), dma::Error>
        where B: Unsize<[u8]>
    {
        let usart1 = self.0;

        if dma1.ccr5.read().en().is_set() {
            return Err(dma::Error::InUse);
        }

        let buffer: &mut [u8] = buffer.lock_mut();

        dma1.cndtr5
            .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) });
        dma1.cpar5
            .write(|w| unsafe { w.bits(&usart1.dr as *const _ as u32) });
        dma1.cmar5
            .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) });
        dma1.ccr5.modify(|_, w| w.en().set());

        Ok(())
    }

    /// Starts a DMA transfer to send `buffer` through this serial port
    ///
    /// This will immutably lock the `buffer` preventing mutably borrowing its
    /// contents. The `buffer` can be `release`d after the DMA transfer finishes
    pub fn write_all<B>(&self,
                        dma1: &DMA1,
                        buffer: Ref<Buffer<B, Dma1Channel4>>)
                        -> ::core::result::Result<(), dma::Error>
        where B: Unsize<[u8]>
    {
        let usart1 = self.0;

        if dma1.ccr4.read().en().is_set() {
            return Err(dma::Error::InUse);
        }

        let buffer: &[u8] = buffer.lock();

        dma1.cndtr4
            .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) });
        dma1.cpar4
            .write(|w| unsafe { w.bits(&usart1.dr as *const _ as u32) });
        dma1.cmar4
            .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) });
        dma1.ccr4.modify(|_, w| w.en().set());

        Ok(())
    }
}
<commit_msg>Add serial<commit_after>use core::any::{Any, TypeId};
use core::marker::Unsize;
use core::ops::Deref;
use core::ptr;

use cast::u16;
use hal;
use hal::serial::Write;
use nb;
use time::U32Ext;

// use static_ref::Ref;
use stm32f411::{usart1, USART1, USART2, USART6};

/// Specialized `Result` type
pub type Result<T> = ::core::result::Result<T, nb::Error<Error>>;

/// IMPLEMENTATION DETAIL
pub unsafe trait Usart: Deref<Target = usart1::RegisterBlock> {
    /// IMPLEMENTATION DETAIL
    type Ticks: Into<u32>;
}

unsafe impl Usart for USART1 {
    type Ticks = ::apb2::Ticks;
}

unsafe impl Usart for USART2 {
    type Ticks = ::apb1::Ticks;
}

unsafe impl Usart for USART6 {
    type Ticks = ::apb1::Ticks;
}

/// An error
#[derive(Debug)]
pub enum Error {
    /// De-synchronization, excessive noise or a break character detected
    Framing,
    /// Noise detected in the received frame
    Noise,
    /// RX buffer overrun
    Overrun,
    #[doc(hidden)]
    _Extensible,
}

/// Interrupt event
pub enum Event {
    /// RX buffer Not Empty (new data available)
    Rxne,
    /// Transmission Complete
    Tc,
    /// TX buffer Empty (more data can be send)
    Txe,
}

/// Serial interface
///
/// # Interrupts
///
/// - RXNE
pub struct Serial<'a, U>(pub &'a U) where U: Any + Usart;

impl<'a, U> Clone for Serial<'a, U>
    where U: Any + Usart
{
    fn clone(&self) -> Self {
        *self
    }
}

impl<'a, U> Copy for Serial<'a, U> where U: Any + Usart {}

impl<'a, U> Serial<'a, U>
    where U: Any + Usart
{
    /// Initializes the serial interface with a baud rate of `baut_rate` bits
    /// per second
    ///
    /// The serial interface will be configured to use 8 bits of data, 1 stop
    /// bit, no hardware control and to omit parity checking
    pub fn init<B>(&self, baud_rate: B)
        where B: Into<U::Ticks>
    {
        self.set_baud_rate(baud_rate);
        self.enable();
    }

    pub fn set_baud_rate<B>(&self, baud_rate: B)
        where B: Into<U::Ticks>
    {
        let ticks = baud_rate.into();
        let baud = ticks.into();
        self.0.brr.write(|w| unsafe { w.bits(baud) });
    }

    pub fn enable(&self) {
        self.0.cr1.modify(|_, w|
            w.ue().set_bit()
             .te().set_bit()
             .re().set_bit());
    }

    pub fn disable(&self) {
        self.0.cr1.modify(|_, w| w.ue().clear_bit());
    }
}

impl<'a, U> hal::serial::Read<u8> for Serial<'a, U>
where
    U: Any + Usart,
{
    type Error = Error;

    fn read(&self) -> Result<u8> {
        let usart = self.0;
        let sr = usart.sr.read();

        if sr.ore().bit_is_set() {
            Err(nb::Error::Other(Error::Overrun))
        } else if sr.nf().bit_is_set() {
            Err(nb::Error::Other(Error::Noise))
        } else if sr.fe().bit_is_set() {
            Err(nb::Error::Other(Error::Framing))
        } else if sr.rxne().bit_is_set() {
            // NOTE(read_volatile) the register is 9 bits big but we'll only
            // work with the first 8 bits
            Ok(unsafe {
                ptr::read_volatile(&usart.dr as *const _ as *const u8)
            })
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}

impl<'a, U> Write<u8> for Serial<'a, U>
where
    U: Any + Usart,
{
    type Error = Error;

    fn write(&self, byte: u8) -> Result<()> {
        let usart = self.0;
        let sr = usart.sr.read();

        if sr.ore().bit_is_set() {
            Err(nb::Error::Other(Error::Overrun))
        } else if sr.nf().bit_is_set() {
            Err(nb::Error::Other(Error::Noise))
        } else if sr.fe().bit_is_set() {
            Err(nb::Error::Other(Error::Framing))
        } else if sr.txe().bit_is_set() {
            // NOTE(write_volatile) see NOTE in the `read` method
            unsafe {
                ptr::write_volatile(&usart.dr as *const _ as *mut u8, byte)
            }
            Ok(())
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}

impl<'a, U> hal::serial::Write<&'a [u8]> for Serial<'a, U>
where
    U: Any + Usart,
{
    type Error = Error;

    fn write<'b>(&self, buffer: &'b [u8]) -> Result<()> {
        for byte in buffer {
            let status = block!(self.write(*byte));
            match status {
                Err(e) => return Err(nb::Error::Other(e)),
                _ => {}
            }
        }
        Ok(())
    }
}

impl<'a, U> hal::serial::Write<&'a str> for Serial<'a, U>
where
    U: Any + Usart,
{
    type Error = Error;

    fn write<'b>(&self, string: &'a str) -> Result<()> {
        self.write(string.as_bytes())
    }
}
/*
impl<'a> Serial<'a, USART1> {
    /// Starts a DMA transfer to receive serial data into a `buffer`
    ///
    /// This will mutably lock the `buffer` preventing borrowing its contents
    /// The `buffer` can be `release`d after the DMA transfer finishes
    // TODO support circular mode + half transfer interrupt as a double
    // buffering mode
    pub fn read_exact<B>(&self,
                         dma1: &DMA1,
                         buffer: Ref<Buffer<B, Dma1Channel5>>)
                         -> ::core::result::Result<(), dma::Error>
        where B: Unsize<[u8]>
    {
        let usart1 = self.0;

        if dma1.ccr5.read().en().is_set() {
            return Err(dma::Error::InUse);
        }

        let buffer: &mut [u8] = buffer.lock_mut();

        dma1.cndtr5
            .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) });
        dma1.cpar5
            .write(|w| unsafe { w.bits(&usart1.dr as *const _ as u32) });
        dma1.cmar5
            .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) });
        dma1.ccr5.modify(|_, w| w.en().set());

        Ok(())
    }

    /// Starts a DMA transfer to send `buffer` through this serial port
    ///
    /// This will immutably lock the `buffer` preventing mutably borrowing its
    /// contents. The `buffer` can be `release`d after the DMA transfer finishes
    pub fn write_all<B>(&self,
                        dma1: &DMA1,
                        buffer: Ref<Buffer<B, Dma1Channel4>>)
                        -> ::core::result::Result<(), dma::Error>
        where B: Unsize<[u8]>
    {
        let usart1 = self.0;

        if dma1.ccr4.read().en().is_set() {
            return Err(dma::Error::InUse);
        }

        let buffer: &[u8] = buffer.lock();

        dma1.cndtr4
            .write(|w| unsafe { w.ndt().bits(u16(buffer.len()).unwrap()) });
        dma1.cpar4
            .write(|w| unsafe { w.bits(&usart1.dr as *const _ as u32) });
        dma1.cmar4
            .write(|w| unsafe { w.bits(buffer.as_ptr() as u32) });
        dma1.ccr4.modify(|_, w| w.en().set());

        Ok(())
    }
}
*/<|endoftext|>


<commit_before>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::fs::OpenOptions;
use std::io::BufWriter;
use std::io::Result;
use time::now;

// Internal modules:
use configuration::Configuration;

fn handle_client(stream: &mut TcpStream, remote_addr: &SocketAddr, all_data_file: &Arc<Mutex<String>>) -> Result<()> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
    	SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

	let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);
    info!("Bytes: {:?}", buffer);

    match all_data_file.lock() {
        Ok(all_data_file) => {
            let mut file_handle = BufWriter::new(try!(OpenOptions::new().write(true).create(true).append(true).open(&*all_data_file)));

            let tm = now();
            let tm = tm.strftime("%Y.%m.%d - %H:%M:%S").unwrap();

            try!(write!(file_handle, "<measure>\n"));
            try!(write!(file_handle, "<port>{}</port>\n", local_port));
            try!(write!(file_handle, "<date_time>{}</date_time>\n", &tm));
            try!(write!(file_handle, "<data>\n"));
            try!(write!(file_handle, "{:?}\n", buffer));
            try!(write!(file_handle, "</data>\n"));
            try!(write!(file_handle, "</measure>\n"));
        },
        Err(e) => info!("Mutex (poison) error: {}", e)
    }

    Ok(())
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        let listener = TcpListener::bind(("0.0.0.0", port));
        if let Ok(listener) = listener {
            listeners.push(listener);
        }
    }

    let all_data_file = Arc::new(Mutex::new(config.all_data_file.clone()));

    for listener in listeners {
        let all_data_file = all_data_file.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
					let (mut stream, addr) = result;
                    if let Err(io_error) = handle_client(&mut stream, &addr, &all_data_file) {
                        info!("IOError: {}", io_error);
                    }
                }
            }
        });
    }
}
<commit_msg>add support for a second (monthly) file, some comments about refactoring<commit_after>//! Provides the server and handles the incomming requests
//! All ports are handled by the same function

// System modules:
use std::net::{TcpListener, TcpStream, SocketAddr};
use std::thread::spawn;
use std::io::prelude::*;
use std::sync::{Arc, Mutex};
use std::fs::OpenOptions;
use std::io::BufWriter;
use std::io::Result;
use time::now;

// Internal modules:
use configuration::Configuration;

fn handle_client(stream: &mut TcpStream, remote_addr: &SocketAddr,
    all_data_file: &Arc<Mutex<String>>, monthly_data_folder: &Arc<Mutex<String>>) -> Result<()> {
    info!("Client socket address: {}", remote_addr);

    let local_addr = try!(stream.local_addr());

    let local_port = match local_addr {
        SocketAddr::V4(local_addr) => local_addr.port(),
        SocketAddr::V6(local_addr) => local_addr.port()
    };

    info!("Port: {}", local_port);

    let mut buffer = Vec::new();

    let len = try!(stream.read_to_end(&mut buffer));
    info!("Number of bytes received: {}", len);
    info!("Bytes: {:?}", buffer);

    // TODO: refactor to utility function

    // TODO: use str::from_utf8(buf) if data is sent in clear text
    // Otherwise parse binary data to floats

    match all_data_file.lock() {
        Ok(all_data_file) => {
            let mut file_handle = BufWriter::new(try!(OpenOptions::new()
                .write(true).create(true).append(true).open(&*all_data_file)));

            let tm = now();
            let current_date_time = tm.strftime("%Y.%m.%d - %H:%M:%S").unwrap();

            try!(write!(file_handle, "<measure>\n"));
            try!(write!(file_handle, "<port>{}</port>\n", local_port));
            try!(write!(file_handle, "<date_time>{}</date_time>\n", &current_date_time));
            try!(write!(file_handle, "<data>\n"));
            try!(write!(file_handle, "{:?}\n", buffer));
            try!(write!(file_handle, "</data>\n"));
            try!(write!(file_handle, "</measure>\n\n"));
        },
        Err(e) => info!("Mutex (poison) error (all_data_file): {}", e)
    }

    match monthly_data_folder.lock() {
        Ok(monthly_data_folder) => {
            let tm = now();
            let current_year = tm.strftime("%Y").unwrap();
            let current_month = tm.strftime("%m").unwrap();
            // TODO: create separate folder for year and month
            let file_name = format!("{}/{}_{}.txt", *monthly_data_folder, current_year, current_month);
            let mut file_handle = BufWriter::new(try!(OpenOptions::new()
                .write(true).create(true).append(true).open(file_name)));

            let current_date_time = tm.strftime("%Y.%m.%d - %H:%M:%S").unwrap();

            try!(write!(file_handle, "<measure>\n"));
            try!(write!(file_handle, "<port>{}</port>\n", local_port));
            try!(write!(file_handle, "<date_time>{}</date_time>\n", &current_date_time));
            try!(write!(file_handle, "<data>\n"));
            try!(write!(file_handle, "{:?}\n", buffer));
            try!(write!(file_handle, "</data>\n"));
            try!(write!(file_handle, "</measure>\n\n"));
        },
        Err(e) => info!("Mutex (poison) error (monthly_data_folder): {}", e)
    }

    Ok(())
}

pub fn start_service(config: Configuration) {
    let mut listeners = Vec::new();

    for port in config.ports {
        let listener = TcpListener::bind(("0.0.0.0", port));
        if let Ok(listener) = listener {
            listeners.push(listener);
        }
    }

    let all_data_file = Arc::new(Mutex::new(config.all_data_file.clone()));
    let monthly_data_folder = Arc::new(Mutex::new(config.monthly_data_folder.clone()));

    for listener in listeners {
        let all_data_file = all_data_file.clone();
        let monthly_data_folder = monthly_data_folder.clone();
        spawn(move|| {
            loop {
                let result = listener.accept();
                if let Ok(result) = result {
                    let (mut stream, addr) = result;
                    if let Err(io_error) = handle_client(&mut stream, &addr,
                            &all_data_file, &monthly_data_folder) {
                        info!("IOError: {}", io_error);
                    }
                }
            }
        });
    }
}

<|endoftext|>


<commit_before>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl::new());
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> WebSessionImpl {
        WebSessionImpl {
            db : sqlite3::open("/var/data.db").unwrap(),
        }
    }
}

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : HashMap<~str, ~str>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : HashMap::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.insert(a[0].into_owned(),
                                a[1].into_owned());
        }
    }
    return result;
}

impl WebSessionImpl {
    fn is_word(&mut self, word : &str) -> sqlite3::SqliteResult<bool> {
        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));
        println!("got the cursor");
        return Ok(try!(cursor.step_row()).is_some());
    }
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);
        println!("{}, {}", path.path, path.query);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            let word : ~str = path.query.get(&~"word").clone();

            // TODO check that `word` is actually a word.
            match self.is_word(word) {
                Err(e) => fail!("is_word error: {}", e),
                Ok(false) => {
                    content.get_body().set_bytes(
                        html_body(
                            "
 that's not a word

                           <form action=\"define\" method=\"get\">
                           <input name=\"word\"/><button>go</button></form>").as_bytes());
                    return context.done();
                }
                Ok(true) => {}
            }

            content.get_body().set_bytes(
                html_body(
                    format!(
                        "
{word}

                     <form action=\"define\" method=\"get\">
                     <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
                     <input name=\"definition\"/><button>define</button></form>",
                        word=word)).as_bytes());

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<commit_msg>print the error message too<commit_after>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use collections::hashmap::HashMap;
use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

use sqlite3;

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl::new());
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl {
    db : sqlite3::Database,
}

impl WebSessionImpl {
    pub fn new() -> WebSessionImpl {
        WebSessionImpl {
            db : sqlite3::open("/var/data.db").unwrap(),
        }
    }
}

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
             text-align: center;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : HashMap<~str, ~str>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : HashMap::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.insert(a[0].into_owned(),
                                a[1].into_owned());
        }
    }
    return result;
}

impl WebSessionImpl {
    fn is_word(&mut self, word : &str) -> sqlite3::SqliteResult<bool> {
        let cursor = try!(self.db.prepare(
            format!("SELECT * FROM Words WHERE Word = \"{}\";", word),
            &None));
        println!("got the cursor");
        return Ok(try!(cursor.step_row()).is_some());
    }
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);
        println!("{}, {}", path.path, path.query);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            let word : ~str = path.query.get(&~"word").clone();

            // TODO check that `word` is actually a word.
            match self.is_word(word) {
                Err(e) => fail!("is_word error: {}, {:?}", e, self.db.get_errmsg()),
                Ok(false) => {
                    content.get_body().set_bytes(
                        html_body(
                            "
 that's not a word

                           <form action=\"define\" method=\"get\">
                           <input name=\"word\"/><button>go</button></form>").as_bytes());
                    return context.done();
                }
                Ok(true) => {}
            }

            content.get_body().set_bytes(
                html_body(
                    format!(
                        "
{word}

                     <form action=\"define\" method=\"get\">
                     <input name=\"word\" value=\"{word}\" type=\"hidden\"/>
                     <input name=\"definition\"/><button>define</button></form>",
                        word=word)).as_bytes());

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<|endoftext|>