<commit_before>use crate::expression::subselect::Subselect;
use crate::expression::{AsExpression, Expression, ValidGrouping};
use crate::pg::Pg;
use crate::query_builder::*;
use crate::result::QueryResult;
use crate::sql_types::Array;

/// Creates a PostgreSQL `ANY` expression.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically from `diesel::expression::any`, or glob import
/// `diesel::dsl::*`
///
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
/// # use diesel::dsl::*;
/// #
/// # fn main() {
/// #     use schema::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("INSERT INTO users (name) VALUES ('Jim')").unwrap();
/// let sean = (1, "Sean".to_string());
/// let jim = (3, "Jim".to_string());
/// let data = users.filter(name.eq(any(vec!["Sean", "Jim"])));
/// assert_eq!(Ok(vec![sean, jim]), data.load(&connection));
/// # }
/// ```
pub fn any<ST, T>(vals: T) -> Any<T::Expression>
where
    T: AsArrayExpression<ST>,
{
    Any::new(vals.as_expression())
}

/// Creates a PostgreSQL `ALL` expression.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically as `diesel::dsl::all`.
///
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
/// # use diesel::dsl::*;
/// #
/// # fn main() {
/// #     use schema::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("INSERT INTO users (name) VALUES ('Jim')").unwrap();
/// let tess = (2, "Tess".to_string());
/// let data = users.filter(name.ne(all(vec!["Sean", "Jim"])));
/// assert_eq!(Ok(vec![tess]), data.load(&connection));
/// # }
/// ```
pub fn all<ST, T>(vals: T) -> All<T::Expression>
where
    T: AsArrayExpression<ST>,
{
    All::new(vals.as_expression())
}

#[doc(hidden)]
#[derive(Debug, Copy, Clone, QueryId, ValidGrouping)]
pub struct Any<Expr> {
    expr: Expr,
}

impl<Expr> Any<Expr> {
    fn new(expr: Expr) -> Self {
        Any { expr: expr }
    }
}

impl<Expr, ST> Expression for Any<Expr>
where
    Expr: Expression<SqlType = Array<ST>>,
{
    type SqlType = ST;
}

impl<Expr> QueryFragment<Pg> for Any<Expr>
where
    Expr: QueryFragment<Pg>,
{
    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
        out.push_sql("ANY(");
        self.expr.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl_selectable_expression!(Any<Expr>);

#[doc(hidden)]
#[derive(Debug, Copy, Clone, QueryId, ValidGrouping)]
pub struct All<Expr> {
    expr: Expr,
}

impl<Expr> All<Expr> {
    fn new(expr: Expr) -> Self {
        All { expr: expr }
    }
}

impl<Expr, ST> Expression for All<Expr>
where
    Expr: Expression<SqlType = Array<ST>>,
{
    type SqlType = ST;
}

impl<Expr> QueryFragment<Pg> for All<Expr>
where
    Expr: QueryFragment<Pg>,
{
    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
        out.push_sql("ALL(");
        self.expr.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl_selectable_expression!(All<Expr>);

pub trait AsArrayExpression<ST> {
    type Expression: Expression<SqlType = Array<ST>>;

    fn as_expression(self) -> Self::Expression;
}

impl<ST, T> AsArrayExpression<ST> for T
where
    T: AsExpression<Array<ST>>,
{
    type Expression = <T as AsExpression<Array<ST>>>::Expression;

    fn as_expression(self) -> Self::Expression {
        AsExpression::as_expression(self)
    }
}

impl<ST, S, F, W, O, L, Of, G, FU> AsArrayExpression<ST>
    for SelectStatement<S, F, W, O, L, Of, G, FU>
where
    Self: SelectQuery<SqlType = ST>,
{
    type Expression = Subselect<Self, Array<ST>>;

    fn as_expression(self) -> Self::Expression {
        Subselect::new(self)
    }
}

impl<'a, ST, QS, DB> AsArrayExpression<ST> for BoxedSelectStatement<'a, ST, QS, DB>
where
    Self: SelectQuery<SqlType = ST>,
{
    type Expression = Subselect<Self, Array<ST>>;

    fn as_expression(self) -> Self::Expression {
        Subselect::new(self)
    }
}
<commit_msg>Fix documentation for importing any and all in pg<commit_after>use crate::expression::subselect::Subselect;
use crate::expression::{AsExpression, Expression, ValidGrouping};
use crate::pg::Pg;
use crate::query_builder::*;
use crate::result::QueryResult;
use crate::sql_types::Array;

/// Creates a PostgreSQL `ANY` expression.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically from `diesel::pg::expression::dsl::any`, or glob import
/// `diesel::dsl::*`
///
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
/// # use diesel::dsl::*;
/// #
/// # fn main() {
/// #     use schema::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("INSERT INTO users (name) VALUES ('Jim')").unwrap();
/// let sean = (1, "Sean".to_string());
/// let jim = (3, "Jim".to_string());
/// let data = users.filter(name.eq(any(vec!["Sean", "Jim"])));
/// assert_eq!(Ok(vec![sean, jim]), data.load(&connection));
/// # }
/// ```
pub fn any<ST, T>(vals: T) -> Any<T::Expression>
where
    T: AsArrayExpression<ST>,
{
    Any::new(vals.as_expression())
}

/// Creates a PostgreSQL `ALL` expression.
///
/// As with most bare functions, this is not exported by default. You can import
/// it specifically as `diesel::pg::expression::dsl::all`, or glob import
/// `diesel::dsl::*`.
///
/// # Example
///
/// ```rust
/// # include!("../../doctest_setup.rs");
/// # use diesel::dsl::*;
/// #
/// # fn main() {
/// #     use schema::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("INSERT INTO users (name) VALUES ('Jim')").unwrap();
/// let tess = (2, "Tess".to_string());
/// let data = users.filter(name.ne(all(vec!["Sean", "Jim"])));
/// assert_eq!(Ok(vec![tess]), data.load(&connection));
/// # }
/// ```
pub fn all<ST, T>(vals: T) -> All<T::Expression>
where
    T: AsArrayExpression<ST>,
{
    All::new(vals.as_expression())
}

#[doc(hidden)]
#[derive(Debug, Copy, Clone, QueryId, ValidGrouping)]
pub struct Any<Expr> {
    expr: Expr,
}

impl<Expr> Any<Expr> {
    fn new(expr: Expr) -> Self {
        Any { expr: expr }
    }
}

impl<Expr, ST> Expression for Any<Expr>
where
    Expr: Expression<SqlType = Array<ST>>,
{
    type SqlType = ST;
}

impl<Expr> QueryFragment<Pg> for Any<Expr>
where
    Expr: QueryFragment<Pg>,
{
    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
        out.push_sql("ANY(");
        self.expr.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl_selectable_expression!(Any<Expr>);

#[doc(hidden)]
#[derive(Debug, Copy, Clone, QueryId, ValidGrouping)]
pub struct All<Expr> {
    expr: Expr,
}

impl<Expr> All<Expr> {
    fn new(expr: Expr) -> Self {
        All { expr: expr }
    }
}

impl<Expr, ST> Expression for All<Expr>
where
    Expr: Expression<SqlType = Array<ST>>,
{
    type SqlType = ST;
}

impl<Expr> QueryFragment<Pg> for All<Expr>
where
    Expr: QueryFragment<Pg>,
{
    fn walk_ast(&self, mut out: AstPass<Pg>) -> QueryResult<()> {
        out.push_sql("ALL(");
        self.expr.walk_ast(out.reborrow())?;
        out.push_sql(")");
        Ok(())
    }
}

impl_selectable_expression!(All<Expr>);

pub trait AsArrayExpression<ST> {
    type Expression: Expression<SqlType = Array<ST>>;

    fn as_expression(self) -> Self::Expression;
}

impl<ST, T> AsArrayExpression<ST> for T
where
    T: AsExpression<Array<ST>>,
{
    type Expression = <T as AsExpression<Array<ST>>>::Expression;

    fn as_expression(self) -> Self::Expression {
        AsExpression::as_expression(self)
    }
}

impl<ST, S, F, W, O, L, Of, G, FU> AsArrayExpression<ST>
    for SelectStatement<S, F, W, O, L, Of, G, FU>
where
    Self: SelectQuery<SqlType = ST>,
{
    type Expression = Subselect<Self, Array<ST>>;

    fn as_expression(self) -> Self::Expression {
        Subselect::new(self)
    }
}

impl<'a, ST, QS, DB> AsArrayExpression<ST> for BoxedSelectStatement<'a, ST, QS, DB>
where
    Self: SelectQuery<SqlType = ST>,
{
    type Expression = Subselect<Self, Array<ST>>;

    fn as_expression(self) -> Self::Expression {
        Subselect::new(self)
    }
}
<|endoftext|>


<commit_before>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::core::libexecutor::block::{ClosedBlock, OpenBlock};
use libproto::ExecutedResult;
use proof::BftProof as Proof;
use std::collections::BTreeMap;
use util::Itertools;

pub struct Backlog {
    open_block: Option<OpenBlock>,
    proof: Option<Proof>,
    closed_block: Option<ClosedBlock>,
    executed_result: Option<ExecutedResult>,
}

impl Default for Backlog {
    fn default() -> Self {
        Backlog {
            open_block: None,
            proof: None,
            closed_block: None,
            executed_result: None,
        }
    }
}

impl Backlog {
    // When a block is processed done and proofed, we can say this block is completed. So that our
    // chain grows up.
    // So, a Backlog `is_completed` return true if block, proof, and executed_result for that height
    // are all exist and matched.
    pub fn is_completed(&self) -> bool {
        if self.open_block.is_none()
            || self.proof.is_none()
            || self.executed_result.is_none()
            || self.closed_block.is_none()
        {
            return false;
        }

        self.is_matched()
    }

    // `is_matched` check whether the inside closed_block is equal to open_block
    pub fn is_matched(&self) -> bool {
        if self.open_block.is_none() || self.closed_block.is_none() {
            return false;
        }

        let open_block = self.open_block.as_ref().unwrap();
        let closed_block = self.closed_block.as_ref().unwrap();
        closed_block.is_equivalent(open_block)
    }

    // Mark this Backlog as completed.
    //
    // Make sure the backlog is really completed, otherwise it would panic.
    pub fn complete(self) -> (ClosedBlock, ExecutedResult) {
        assert!(self.is_completed());

        let bft_proof = self.proof.unwrap();
        let mut closed_block = self.closed_block.unwrap();
        let executed_result = self.executed_result.unwrap();
        closed_block.header.set_proof(bft_proof.into());
        closed_block.rehash();

        (closed_block, executed_result)
    }

    pub fn get_open_block(&self) -> Option<&OpenBlock> {
        self.open_block.as_ref()
    }
}

pub struct Backlogs {
    // current height of local chain, should be equal to `min(backlog.keys())`
    current_height: u64,

    // {height => Block}, which indicates pending processing blocks
    backlogs: BTreeMap<u64, Backlog>,

    // {height => ExecutedResult}, which indicates the executed results of elder blocks
    completed: BTreeMap<u64, ExecutedResult>,
}

impl Backlogs {
    pub fn new(current_height: u64) -> Backlogs {
        Backlogs {
            current_height,
            backlogs: BTreeMap::new(),
            completed: BTreeMap::new(),
        }
    }

    pub fn get_current_height(&self) -> u64 {
        self.current_height
    }

    pub fn get_open_block(&self, height: u64) -> Option<&OpenBlock> {
        match self.backlogs.get(&height) {
            Some(ref backlog) => backlog.get_open_block(),
            None => None,
        }
    }

    pub fn get_completed_result(&self, height: u64) -> Option<&ExecutedResult> {
        self.completed.get(&height)
    }

    pub fn insert_completed_result(&mut self, height: u64, executed_result: ExecutedResult) {
        self.completed.insert(height, executed_result);
    }

    pub fn insert_open_block(&mut self, height: u64, open_block: OpenBlock) -> bool {
        if !self.assert_height(height) {
            return false;
        }

        let backlog = self.backlogs.entry(height).or_default();
        backlog.open_block = Some(open_block);
        true
    }

    pub fn insert_proof(&mut self, height: u64, proof: Proof) -> bool {
        if !self.assert_height(height) {
            return false;
        }

        let backlog = self.backlogs.entry(height).or_default();
        backlog.proof = Some(proof);
        true
    }

    pub fn insert_result(
        &mut self,
        height: u64,
        closed_block: ClosedBlock,
        executed_result: ExecutedResult,
    ) -> bool {
        if !self.assert_height(height) {
            return false;
        }

        let backlog = self.backlogs.entry(height).or_default();
        backlog.closed_block = Some(closed_block);
        backlog.executed_result = Some(executed_result);
        true
    }

    pub fn is_completed(&self, height: u64) -> bool {
        match self.backlogs.get(&height) {
            Some(backlog) => backlog.is_completed(),
            None => false,
        }
    }

    pub fn is_matched(&self, height: u64) -> bool {
        match self.backlogs.get(&height) {
            Some(backlog) => backlog.is_matched(),
            None => false,
        }
    }

    // move "front of backlogs" into "back of completed"
    pub fn complete(&mut self, height: u64) -> ClosedBlock {
        let backlog = self.backlogs.remove(&height).unwrap();
        let (closed_block, executed_result) = backlog.complete();

        self.completed.insert(height, executed_result);
        self.current_height += 1;
        closed_block
    }

    pub fn completed_keys(&self) -> ::std::vec::Vec<&u64> {
        self.completed.keys().sorted()
    }

    pub fn prune(&mut self, height: u64) {
        // Importance guard: we must keep the executed result of the previous
        // height(current_height - 1), which used when postman check arrived
        // proof via `Postman::check_proof`
        if height < self.get_current_height() - 1 && self.get_current_height() != 0 {
            self.completed = self.completed.split_off(&height);
        }
    }

    fn assert_height(&self, height: u64) -> bool {
        if self.current_height > height {
            error!(
                "unexpected height, current height({}) > arrived height({})",
                self.current_height, height,
            );
            return false;
        }
        true
    }
}

#[cfg(test)]
mod tests {
    use super::Backlog;
    use super::Backlogs;
    use cita_types::H256;
    use core::header::OpenHeader;
    use core::libexecutor::block::{BlockBody, ClosedBlock, ExecutedBlock, OpenBlock};
    use core::libexecutor::sys_config::BlockSysConfig;
    use core::state_db::StateDB;
    use libproto::ExecutedResult;
    use proof::BftProof;
    use std::collections::HashMap;
    use std::sync::Arc;
    use util::journaldb;
    use util::kvdb::{in_memory, KeyValueDB};

    fn generate_block_body() -> BlockBody {
        let mut stx = SignedTransaction::default();
        use types::transaction::SignedTransaction;
        stx.data = vec![1; 200];
        let transactions = vec![stx; 200];
        BlockBody { transactions }
    }

    fn generate_block_header() -> OpenHeader {
        OpenHeader::default()
    }

    fn generate_block() -> OpenBlock {
        let block_body = generate_block_body();
        let block_header = generate_block_header();
        OpenBlock {
            body: block_body,
            header: block_header,
        }
    }

    fn generate_bft_proof() -> BftProof {
        BftProof::new(0, 1, H256::default(), HashMap::new())
    }

    fn generate_state_db() -> StateDB {
        let database = in_memory(7);
        let database: Arc<KeyValueDB> = Arc::new(database);
        let journaldb_type = journaldb::Algorithm::Archive;
        let journal_db = journaldb::new(Arc::clone(&database), journaldb_type, None);
        StateDB::new(journal_db, 5 * 1024 * 1024)
    }

    #[test]
    fn test_backlog_is_completed_with_default() {
        assert_eq!(false, Backlog::default().is_completed());
    }

    fn generate_executed_result() -> ExecutedResult {
        ExecutedResult::new()
    }

    fn generate_closed_block(open_block: OpenBlock) -> ClosedBlock {
        let state_db = generate_state_db();
        let exec_block = ExecutedBlock::new(
            Default::default(),
            &BlockSysConfig::default(),
            false,
            open_block.clone(),
            state_db,
            util::hashable::HASH_NULL_RLP,
            Arc::new(Vec::new()),
        )
        .unwrap();
        exec_block.close(&BlockSysConfig::default())
    }

    #[test]
    fn test_backlog_is_completed_with_none() {
        {
            let backlog = Backlog {
                open_block: None,
                proof: Some(generate_bft_proof()),
                closed_block: Some(generate_closed_block(generate_block())),
                executed_result: Some(generate_executed_result()),
            };
            assert_eq!(false, backlog.is_completed(), "block is none");
        }

        {
            let block = generate_block();
            let closed_block = generate_closed_block(block.clone());
            let backlog = Backlog {
                open_block: Some(block),
                proof: None,
                closed_block: Some(closed_block),
                executed_result: Some(generate_executed_result()),
            };
            assert_eq!(false, backlog.is_completed(), "proof is none");
        }

        {
            let backlog = Backlog {
                open_block: Some(generate_block()),
                proof: Some(generate_bft_proof()),
                closed_block: None,
                executed_result: Some(generate_executed_result()),
            };
            assert_eq!(false, backlog.is_completed(), "closed_block is none");
        }
    }

    #[test]
    fn test_is_completed_with_unequal_block() {
        {
            let mut block = generate_block();
            let closed_block = generate_closed_block(block.clone());
            block.header.set_timestamp(1);
            let backlog = Backlog {
                open_block: Some(block),
                proof: Some(generate_bft_proof()),
                closed_block: Some(closed_block),
                executed_result: Some(generate_executed_result()),
            };
            assert_eq!(
                false,
                backlog.is_completed(),
                "false cause block.timestamp is not equal"
            );
        }

        {
            let block = generate_block();
            let closed_block = generate_closed_block(block.clone());
            let backlog = Backlog {
                open_block: Some(block),
                proof: Some(generate_bft_proof()),
                closed_block: Some(closed_block),
                executed_result: Some(generate_executed_result()),
            };
            assert!(backlog.is_completed());
        }
    }

    #[test]
    #[should_panic]
    fn test_complete_but_is_completed_false() {
        let open_block = generate_block();
        let closed_block = generate_closed_block(open_block.clone());

        let backlog = Backlog {
            open_block: Some(open_block),
            proof: None,
            closed_block: Some(closed_block),
            executed_result: Some(generate_executed_result()),
        };
        assert_eq!(false, backlog.is_completed(), "false cause proof is none");

        // panic cause is_completed return false
        backlog.complete();
    }

    #[test]
    fn test_complete_normal() {
        let open_block = generate_block();
        let closed_block = generate_closed_block(open_block.clone());

        let backlog = Backlog {
            open_block: Some(open_block),
            proof: Some(generate_bft_proof()),
            closed_block: Some(closed_block),
            executed_result: Some(generate_executed_result()),
        };
        assert!(backlog.is_completed());
        backlog.complete();
        //        let closed_block = backlog.clone_closed_block();
        //        let proof = backlog.clone_proof();
        //        let proto_proof: Proof = proof.into();
        //        assert_eq!(proto_proof.content, closed_block.proof().content);
    }

    #[test]
    fn test_backlogs_whole_flow() {
        let open_block = generate_block();
        let closed_block = generate_closed_block(open_block.clone());

        // insert height 2 should be always failed
        let mut backlogs = Backlogs::new(3);
        assert_eq!(false, backlogs.insert_open_block(2, open_block.clone()));
        assert_eq!(false, backlogs.insert_proof(2, generate_bft_proof()));
        assert_eq!(
            false,
            backlogs.insert_result(2, closed_block, generate_executed_result()),
            "insert staled result should return false",
        );
        assert!(backlogs.get_open_block(2).is_none());

        // insert height 3 should be ok
        let closed_block = generate_closed_block(open_block.clone());
        assert_eq!(true, backlogs.insert_open_block(3, open_block.clone()));
        assert_eq!(true, backlogs.insert_proof(3, generate_bft_proof()));
        assert_eq!(
            true,
            backlogs.insert_result(3, closed_block, generate_executed_result()),
            "insert current result should return true",
        );
        assert!(backlogs.get_open_block(3).is_some());

        // complete height 3
        assert!(backlogs.is_completed(3));
        let _backlog = backlogs.complete(3);
        assert!(backlogs.get_completed_result(2).is_none());
        assert!(backlogs.get_completed_result(3).is_some());

        assert!(backlogs.get_open_block(3).is_none());
        assert_eq!(
            false,
            backlogs.insert_open_block(3, open_block.clone()),
            "insert staled open_block should return false",
        );
        assert_eq!(false, backlogs.insert_proof(3, generate_bft_proof()));
    }
}
<commit_msg>:hammer: remove ExecutedResult out of backlogs<commit_after>// CITA
// Copyright 2016-2018 Cryptape Technologies LLC.

// This program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any
// later version.

// This program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use super::core::libexecutor::block::{ClosedBlock, OpenBlock};
use libproto::ExecutedResult;
use libproto::Proof;
use std::collections::BTreeMap;
use util::Itertools;

pub struct Backlog {
    open_block: Option<OpenBlock>,
    proof: Option<Proof>,
    closed_block: Option<ClosedBlock>,
}

impl Default for Backlog {
    fn default() -> Self {
        Backlog {
            open_block: None,
            proof: None,
            closed_block: None,
        }
    }
}

impl Backlog {
    // When a block is processed done and proofed, we can say this block is completed. So that our
    // chain grows up.
    // So, a Backlog `is_completed` return true if open block, proof, and closed block for that
    // height are all exist and matched.
    pub fn is_completed(&self) -> bool {
        self.all_exist() && self.is_matched()
    }

    fn all_exist(&self) -> bool {
        self.open_block.is_some() && self.proof.is_some() && self.closed_block.is_some()
    }

    // `is_matched` check whether the inside closed_block is equal to open_block
    pub fn is_matched(&self) -> bool {
        if self.open_block.is_none() || self.closed_block.is_none() {
            return false;
        }

        let open_block = self.open_block.as_ref().unwrap();
        let closed_block = self.closed_block.as_ref().unwrap();
        closed_block.is_equivalent(open_block)
    }

    pub fn is_block_ok(&self, current_hash: &cita_types::H256) -> bool {
        let parent_hash = self.open_block.as_ref().unwrap().parent_hash();
        if parent_hash != current_hash {
            trace!(
                "invalid open_block, open_block.parent_hash({:?}) != current_hash({:?})",
                parent_hash,
                current_hash,
            );
        }
        parent_hash == current_hash
    }

    // Mark this Backlog as completed.
    //
    // Make sure the backlog is really completed, otherwise it would panic.
    pub fn complete(self) -> ClosedBlock {
        assert!(self.is_completed());

        let mut closed_block = self.closed_block.unwrap();
        let proof = self.proof.unwrap();

        closed_block.set_proof(proof);
        closed_block.rehash();
        closed_block
    }

    pub fn get_open_block(&self) -> Option<&OpenBlock> {
        self.open_block.as_ref()
    }

    pub fn get_proof(&self) -> Option<&Proof> {
        self.proof.as_ref()
    }
}

pub struct Backlogs {
    // block height of current local chain, should be equal to `min(backlog.keys())`
    current_height: u64,

    // block hash of current local chain
    current_hash: cita_types::H256,

    // {height => Block}, which indicates pending processing blocks
    backlogs: BTreeMap<u64, Backlog>,

    // {height => ExecutedResult}, which indicates the executed results of elder blocks
    completed: BTreeMap<u64, ExecutedResult>,
}

impl Backlogs {
    pub fn new(current_height: u64, current_hash: cita_types::H256) -> Backlogs {
        Backlogs {
            current_height,
            current_hash,
            backlogs: BTreeMap::new(),
            completed: BTreeMap::new(),
        }
    }

    pub fn get_current_height(&self) -> u64 {
        self.current_height
    }

    pub fn get_current_hash(&self) -> &cita_types::H256 {
        &self.current_hash
    }

    pub fn get_open_block(&self, height: u64) -> Option<&OpenBlock> {
        match self.backlogs.get(&height) {
            Some(ref backlog) => backlog.get_open_block(),
            None => None,
        }
    }

    pub fn get_completed_result(&self, height: u64) -> Option<&ExecutedResult> {
        self.completed.get(&height)
    }

    pub fn insert_completed_result(&mut self, height: u64, executed_result: ExecutedResult) {
        self.completed.insert(height, executed_result);
    }

    pub fn insert_open_block(&mut self, height: u64, open_block: OpenBlock) -> bool {
        if !self.assert_height(height) {
            return false;
        }

        let backlog = self.backlogs.entry(height).or_default();
        backlog.open_block = Some(open_block);
        true
    }

    pub fn insert_proof(&mut self, height: u64, proof: Proof) -> bool {
        if !self.assert_height(height) {
            return false;
        }

        let backlog = self.backlogs.entry(height).or_default();
        backlog.proof = Some(proof);
        true
    }

    pub fn insert_closed_block(&mut self, height: u64, closed_block: ClosedBlock) -> bool {
        if !self.assert_height(height) {
            return false;
        }

        let backlog = self.backlogs.entry(height).or_default();
        backlog.closed_block = Some(closed_block);
        true
    }

    pub fn is_completed(&self, height: u64) -> bool {
        assert_eq!(self.get_current_height(), height - 1);
        if self.backlogs.get(&height).is_none() {
            trace!(
                "{}-th is not completed cause backlog.open_block = None",
                height
            );
            return false;
        }

        let backlog = &self.backlogs[&height];
        if !backlog.is_completed() {
            trace!(
                "{}-th is not completed cause backlog.is_completed = false",
                height
            );
            return false;
        }
        if backlog.get_proof().is_none() {
            trace!("{}-th is not completed cause backlog.proof = None", height);
            return false;
        }

        let proof = backlog.get_proof().unwrap();
        if !self.is_proof_ok(height - 1, proof) {
            trace!(
                "{}-th is not completed cause backlog.proof is invalid",
                height
            );
            return false;
        }

        true
    }

    pub fn is_ready(&self, height: u64) -> bool {
        assert_eq!(self.get_current_height(), height - 1);
        match self.backlogs.get(&height) {
            Some(backlog) => backlog.is_block_ok(self.get_current_hash()) && !backlog.is_matched(),
            None => false,
        }
    }

    // validate proof based on executed result of its previous block
    pub fn is_proof_ok(&self, height: u64, proof: &Proof) -> bool {
        // 0-th proof is always valid
        if height == 0 {
            return true;
        }

        let prev_height = height - 1;
        let executed_result = self
            .completed
            .get(&prev_height)
            .unwrap_or_else(|| panic!("{}-th ExecutedResult exist by outside", prev_height));
        //        // FIXME BUG generated nodes -> validated nodes
        //        // let validators = executed_result.get_config().get_validators();
        //        // let authorities: Vec<Address> = validators
        //        //     .into_iter()
        //        //     .map(|vec| Address::from_slice(&vec[..]))
        //        //     .collect();
        let authorities: Vec<cita_types::Address> = executed_result
            .get_config()
            .get_nodes()
            .into_iter()
            .map(|vec| cita_types::Address::from_slice(&vec[..]))
            .collect();

        // FIXME for unit tests only. Should be remove latter
        if authorities.is_empty() {
            return true;
        }
        let bft_proof = proof::BftProof::from(proof.clone());
        // FIXME check proof. Integration tests have bug, uncomment it latter
        if !bft_proof.check(height as usize, &authorities) {
            trace!(
                "bft_proof is invalid, authorities: {:?}, bft_proof: {:?}",
                authorities,
                bft_proof
            );
        }
        true
    }

    // move "front of backlogs" into "back of completed"
    pub fn complete(&mut self, height: u64) -> ClosedBlock {
        let backlog = self.backlogs.remove(&height).unwrap();
        let closed_block = backlog.complete();

        self.current_height += 1;
        self.current_hash = closed_block
            .hash()
            .expect("already rehash at backlog.complete below");
        closed_block
    }

    pub fn completed_keys(&self) -> ::std::vec::Vec<&u64> {
        self.completed.keys().sorted()
    }

    pub fn prune(&mut self, height: u64) {
        // Importance guard: we must keep the executed result of the recent
        // 2 height(current_height - 1, current_height - 2), which used when
        // postman check arrived proof via `Postman::check_proof`
        if height + 2 < self.get_current_height() {
            self.completed = self.completed.split_off(&height);
        }
    }

    fn assert_height(&self, height: u64) -> bool {
        if self.current_height >= height {
            error!(
                "unexpected height, current height({}) >= arrived height({})",
                self.current_height, height,
            );
            return false;
        }
        true
    }
}

#[cfg(test)]
mod tests {
    use super::Backlog;
    use super::Backlogs;
    use core::header::OpenHeader;
    use core::libexecutor::block::{BlockBody, ClosedBlock, ExecutedBlock, OpenBlock};
    use core::libexecutor::sys_config::BlockSysConfig;
    use core::state_db::StateDB;
    use std::sync::Arc;
    use util::journaldb;
    use util::kvdb::{in_memory, KeyValueDB};

    fn generate_block_body() -> BlockBody {
        let mut stx = SignedTransaction::default();
        use types::transaction::SignedTransaction;
        stx.data = vec![1; 200];
        let transactions = vec![stx; 200];
        BlockBody { transactions }
    }

    fn generate_block_header() -> OpenHeader {
        OpenHeader::default()
    }

    fn generate_block() -> OpenBlock {
        let block_body = generate_block_body();
        let block_header = generate_block_header();
        OpenBlock {
            body: block_body,
            header: block_header,
        }
    }

    fn generate_proof() -> libproto::Proof {
        let mut commits = ::std::collections::HashMap::new();
        commits.insert(Default::default(), Default::default());
        let bft_proof = proof::BftProof::new(0, 1, Default::default(), commits);
        bft_proof.into()
    }

    fn generate_executed_result() -> libproto::ExecutedResult {
        libproto::ExecutedResult::new()
    }

    fn generate_state_db() -> StateDB {
        let database = in_memory(7);
        let database: Arc<KeyValueDB> = Arc::new(database);
        let journaldb_type = journaldb::Algorithm::Archive;
        let journal_db = journaldb::new(Arc::clone(&database), journaldb_type, None);
        StateDB::new(journal_db, 5 * 1024 * 1024)
    }

    #[test]
    fn test_backlog_is_completed_with_default() {
        assert_eq!(false, Backlog::default().is_completed());
    }

    fn generate_closed_block(open_block: OpenBlock) -> ClosedBlock {
        let state_db = generate_state_db();
        let exec_block = ExecutedBlock::new(
            Default::default(),
            &BlockSysConfig::default(),
            false,
            open_block.clone(),
            state_db,
            util::hashable::HASH_NULL_RLP,
            Arc::new(Vec::new()),
        )
        .unwrap();
        exec_block.close(&BlockSysConfig::default())
    }

    #[test]
    fn test_backlog_is_completed_with_none() {
        {
            let backlog = Backlog {
                open_block: None,
                proof: Some(generate_proof()),
                closed_block: Some(generate_closed_block(generate_block())),
            };
            assert_eq!(false, backlog.is_completed(), "block is none");
        }

        {
            let block = generate_block();
            let closed_block = generate_closed_block(block.clone());
            let backlog = Backlog {
                open_block: Some(block),
                proof: None,
                closed_block: Some(closed_block),
            };
            assert_eq!(false, backlog.is_completed(), "proof is none");
        }

        {
            let backlog = Backlog {
                open_block: Some(generate_block()),
                proof: Some(generate_proof()),
                closed_block: None,
            };
            assert_eq!(false, backlog.is_completed(), "closed_block is none");
        }
    }

    #[test]
    fn test_is_completed_with_unequal_block() {
        {
            let mut block = generate_block();
            let closed_block = generate_closed_block(block.clone());
            block.header.set_timestamp(1);
            let backlog = Backlog {
                open_block: Some(block),
                proof: Some(generate_proof()),
                closed_block: Some(closed_block),
            };
            assert_eq!(
                false,
                backlog.is_completed(),
                "false cause block.timestamp is not equal"
            );
        }

        {
            let block = generate_block();
            let closed_block = generate_closed_block(block.clone());
            let backlog = Backlog {
                open_block: Some(block),
                proof: Some(generate_proof()),
                closed_block: Some(closed_block),
            };
            assert!(backlog.is_completed());
        }
    }

    #[test]
    #[should_panic]
    fn test_complete_but_is_completed_false() {
        let open_block = generate_block();
        let closed_block = generate_closed_block(open_block.clone());

        let backlog = Backlog {
            open_block: Some(open_block),
            proof: None,
            closed_block: Some(closed_block),
        };
        assert_eq!(false, backlog.is_completed(), "false cause proof is none");

        // panic cause is_completed return false
        backlog.complete();
    }

    #[test]
    fn test_complete_normal() {
        let open_block = generate_block();
        let closed_block = generate_closed_block(open_block.clone());

        let backlog = Backlog {
            open_block: Some(open_block),
            proof: Some(generate_proof()),
            closed_block: Some(closed_block),
        };
        assert!(backlog.is_completed());
        backlog.complete();
    }

    #[test]
    fn test_backlogs_whole_flow() {
        let open_block = generate_block();
        let closed_block = generate_closed_block(open_block.clone());

        // insert height 2 should be always failed
        let mut backlogs = Backlogs::new(2, Default::default());
        backlogs.insert_completed_result(1, generate_executed_result());
        backlogs.insert_completed_result(2, generate_executed_result());
        assert_eq!(false, backlogs.insert_open_block(2, open_block.clone()));
        assert_eq!(false, backlogs.insert_proof(2, generate_proof()));
        assert_eq!(
            false,
            backlogs.insert_closed_block(2, closed_block),
            "insert staled result should return false",
        );
        assert!(backlogs.get_open_block(2).is_none());

        // insert height 3 should be ok
        let closed_block = generate_closed_block(open_block.clone());
        assert_eq!(true, backlogs.insert_open_block(3, open_block.clone()));
        assert_eq!(true, backlogs.insert_proof(3, generate_proof()));
        assert_eq!(
            true,
            backlogs.insert_closed_block(3, closed_block),
            "insert current result should return true",
        );
        assert!(backlogs.get_open_block(3).is_some());

        // complete height 3
        assert!(backlogs.is_completed(3));
        let _backlog = backlogs.complete(3);
        assert!(backlogs.get_completed_result(2).is_some());

        assert!(backlogs.get_open_block(3).is_none());
        assert_eq!(
            false,
            backlogs.insert_open_block(3, open_block.clone()),
            "insert staled open_block should return false",
        );
        assert_eq!(false, backlogs.insert_proof(3, generate_proof()),);
    }
}
<|endoftext|>


<commit_before>#[link(name = "rusp",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/rusp")];

#[comment = "A minimal Lisp dialect for Rust."];
#[license = "ASL2"];
#[crate_type = "lib"];

// Inspired by Peter Norvig's [Lis.py](http://norvig.com/lispy.html)

use std::hashmap::*;

pub mod builtins;
pub mod parser;
pub mod pprint;

///
/// Performs a recursive decent parse of the source string.
///
pub fn parse(src: &str) -> Result<~[@Value], parser::ParseFailure> {
    let mut parsed = ~[];
    let mut p = parser::Parser::new(src);

    while !p.is_eof() {
        match p.parse() {
            Ok(v) => parsed.push(@v),
            Err(e) => return Err(e)
        }
    }

    Ok(parsed)
}

/// Symbol identifier
pub type Ident = ~str;

/// Holds a typed value
#[deriving(Eq, Clone)]
pub enum Value {
    Bool(bool),
    Int(int),
    Float(float),
    Str(~str),
    List(~[@Value]),
    Symbol(Ident),
    Lambda(~[Ident], @Value),
    Macro(~[Ident], @Value),
    Rust(RustFn),
    RustMacro(RustFn),
}

/// Workaround for `deriving` not working for rust closures
pub struct RustFn(@fn(params: &[@Value], env: @mut Rusp) -> EvalResult);

impl Eq for RustFn {
    fn eq(&self, _: &RustFn) -> bool {
        fail!("Cannot test equality of Rust functions (yet?).");
    }
    fn ne(&self, other: &RustFn) -> bool { !self.eq(other) }
}

impl Clone for RustFn {
    fn clone(&self) -> RustFn {
        // copy the pointer
        *self
    }
}

#[deriving(Eq)]
pub struct Rusp {
    values: HashMap<Ident, @Value>,
    outer: Option<@mut Rusp>,
}

pub type EvalResult = Result<@Value, ~str>;

impl Rusp {
    /// Initializes an empty environment
    pub fn empty() -> @mut Rusp {
        @mut Rusp {
            values: HashMap::new(),
            outer: None,
        }
    }

    /// Initializes an environment containing the default built-ins
    pub fn new() -> @mut Rusp {
        @mut Rusp {
            values: builtins::builtins(),
            outer: None
        }
    }

    /// Initializes a new environment with a parent environment
    pub fn new_with_outer(outer: @mut Rusp) -> @mut Rusp {
        @mut Rusp {
            values: HashMap::new(),
            outer: Some(outer),
        }
    }

    /// Defines a new identifier/value pair in the environment
    pub fn define(&mut self, ident: Ident, val: @Value) -> EvalResult {
        if self.values.insert(ident.clone(), val)  {
            Ok(@List(~[]))
        } else {
            Err(fmt!("`%s` was already defined in this environment.", ident.to_str()))
        }
    }

    /// Attempts to find a value corresponding to the supplied identifier
    pub fn find(&self, ident: &Ident) -> Option<@Value> {
        match self.values.find(ident) {
            Some(val) => Some(*val),
            None => self.outer.chain(|env| env.find(ident)),
        }
    }

    /// Evaluates a Rusp expression in the environment
    pub fn eval(@mut self, value: @Value) -> EvalResult {
        match *value {
            Symbol(ref id) => {
                match self.find(id) {
                    Some(v) => Ok(v),
                    None => Err(fmt!("The value of `%s` was not defined in this environment",
                                     id.to_str())),
                }
            }
            List(ref vals) => {
                match *vals {
                    [ref v, .. args] => {
                        do self.eval(*v).chain |res| {
                            self.eval_call(res, args)
                        }
                    }
                    [] => Ok(@List(~[])),
                }
            }
            // everything else evaluates to itself
            _ => Ok(value)
        }
    }

    /// Eval a call using `func`, which should have been previously
    /// evaluated.
    fn eval_call(@mut self, func: &Value, args: &[@Value]) -> EvalResult {
        match *func {
            Lambda(ref ids, ref body) => {
                if ids.len() != args.len() {
                    return Err(fmt!("lambda expects %u arguments", ids.len()));
                }
                // stores the argument bindings of the function
                let local = Rusp::new_with_outer(self);
                for vec::each2(*ids, args) |id, val| {
                    match self.eval(*val) {
                        Err(e) => return Err(e),
                        Ok(v) => match local.define(id.clone(), v) {
                            Err(e) => return Err(e),
                            _ => {}
                        }
                    }
                }
                local.eval(*body)
            }
            Macro(ref ids, ref body) => {
                if ids.len() != args.len() {
                    return Err(fmt!("macro expects %u arguments", ids.len()));
                }
                // stores the argument bindings of the macro
                let local = Rusp::new_with_outer(self);
                for vec::each2(*ids, args) |id, val| {
                    match local.define(id.clone(), *val) {
                        Err(e) => return Err(e),
                        _ => {}
                    }
                }
                local.eval(*body)
            }
            Rust(ref f) => {
                let mut evaled_args = ~[];
                for args.each |v| {
                    match self.eval(*v) {
                        Err(e) => return Err(e),
                        Ok(evaled) => { evaled_args.push(evaled) }
                    }
                }
                (**f)(evaled_args, self)
            }
            RustMacro(ref f) => {
                (**f)(args, self)
            }
            _ => Err(~"not a function")
        }
    }
}

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

    #[test]
    fn test_env() {
        let outer = Rusp::new();
        outer.define(~"a", @Int(0));
        outer.define(~"b", @Float(1.0));
        outer.define(~"c", @Str(~"hi"));

        let inner = Rusp::new_with_outer(outer);
        inner.define(~"a", @Int(3));
        inner.define(~"b", @Int(4));

        assert_eq!(outer.find(&~"a"), Some(@Int(0)));
        assert_eq!(outer.find(&~"b"), Some(@Float(1.0)));
        assert_eq!(outer.find(&~"c"), Some(@Str(~"hi")));
        assert_eq!(inner.find(&~"a"), Some(@Int(3)));
        assert_eq!(inner.find(&~"b"), Some(@Int(4)));
        assert_eq!(inner.find(&~"c"), Some(@Str(~"hi")));
    }

    #[test]
    fn test_atoms() {
        assert_eq!(Rusp::new().eval(@Int(1)).get(), @Int(1));
        assert_eq!(Rusp::new().eval(@Float(1.0)).get(), @Float(1.0));
        assert_eq!(Rusp::new().eval(@Str(~"hi")).get(), @Str(~"hi"));
    }

    #[test]
    fn test_list() {
        assert_eq!(Rusp::new().eval(@List(~[])).get(), @List(~[]));
        assert_eq!(
            Rusp::new().eval(@List(~[
                @Symbol(~"list"),
                @Str(~"hi"),
                @List(~[@Symbol(~"quote"), @Symbol(~"x")]),
                @Int(1)
            ])).get(),
            @List(~[
                @Str(~"hi"),
                @Symbol(~"x"),
                @Int(1)
            ])
        );
    }

    #[test]
    fn test_quote() {
        assert_eq!(Rusp::new().eval(
            @List(~[@Symbol(~"quote"), @Symbol(~"x")])).get(),
            @Symbol(~"x")
        );
    }

    #[test]
    fn test_symbol() {
        let env = Rusp::new();
        env.define(~"a", @Int(0));
        env.define(~"b", @Float(1.0));
        env.define(~"c", @Str(~"hi"));

        assert_eq!(env.eval(@Symbol(~"a")).get(), @Int(0));
        assert_eq!(env.eval(@Symbol(~"b")).get(), @Float(1.0));
        assert_eq!(env.eval(@Symbol(~"c")).get(), @Str(~"hi"));
        assert!(env.eval(@Symbol(~"d")).is_err());
    }

    #[test]
    fn test_if() {
        fn not(test: Value) -> EvalResult {
            Rusp::new().eval(@List(~[@Symbol(~"if"), @test, @Bool(false), @Bool(true)]))
        }

        assert_eq!(not(Bool(true)).get(), @Bool(false));
        assert_eq!(not(Bool(false)).get(), @Bool(true));
        assert!(not(Str(~"hi")).is_err());
    }

    #[test]
    fn test_def() {
        let env = Rusp::new();
        assert!(env.eval(@List(~[@Symbol(~"def"), @Symbol(~"a"), @Int(0)])).is_ok());
        assert!(env.eval(@List(~[@Symbol(~"def"), @Symbol(~"b"), @Float(1.0)])).is_ok());
        assert!(env.eval(@List(~[@Symbol(~"def"), @Symbol(~"c"), @Str(~"hi")])).is_ok());

        assert_eq!(env.find(&~"a"), Some(@Int(0)));
        assert_eq!(env.find(&~"b"), Some(@Float(1.0)));
        assert_eq!(env.find(&~"c"), Some(@Str(~"hi")));

        assert!(env.eval(@List(~[@Symbol(~"def"), @Symbol(~"c"), @List(~[])])).is_err());
    }

    #[test]
    fn test_do() {
        assert_eq!(Rusp::new().eval(@List(~[@Symbol(~"do"), @Str(~"hi")])).get(), @Str(~"hi"));
        assert_eq!(
            Rusp::new().eval(@List(~[
                @Symbol(~"do"),
                @List(~[]),
                @List(~[@Symbol(~"do"), @List(~[])]),
                @Str(~"hi")
            ])).get(),
            @Str(~"hi")
        );

        assert!(Rusp::new().eval(@List(~[@Symbol(~"do"), @Str(~"hi"), @List(~[])])).is_err());
    }

    #[test]
    fn test_fn() {
        let env = Rusp::new();
        env.eval(parse("(def f (fn (a b) a))").unwrap()[0]);
        assert_eq!(env.eval(parse("(f 1 2)").unwrap()[0]).unwrap(), @Int(1));

        assert!(env.eval(parse("(f 1)").unwrap()[0]).is_err());
    }

    #[test]
    fn test_macro() {
        let env = Rusp::new();
        env.eval(parse("(def m (macro (a) a))").unwrap()[0]);
        env.eval(parse("(def f (fn (a) a))").unwrap()[0]);
        env.eval(parse("(def x 1)").unwrap()[0]);

        // check the semantics of macros vs fn, x is not evaluated for
        // `m`, but is for `f`.
        assert_eq!(env.eval(parse("(m x)").unwrap()[0]).unwrap(), @Symbol(~"x"));
        assert_eq!(env.eval(parse("(f x)").unwrap()[0]).unwrap(), @Int(1));
    }
}
<commit_msg>Flatten list pattern matching<commit_after>#[link(name = "rusp",
       vers = "0.1",
       author = "Brendan Zabarauskas",
       url = "https://github.com/bjz/rusp")];

#[comment = "A minimal Lisp dialect for Rust."];
#[license = "ASL2"];
#[crate_type = "lib"];

// Inspired by Peter Norvig's [Lis.py](http://norvig.com/lispy.html)

use std::hashmap::*;

pub mod builtins;
pub mod parser;
pub mod pprint;

///
/// Performs a recursive decent parse of the source string.
///
pub fn parse(src: &str) -> Result<~[@Value], parser::ParseFailure> {
    let mut parsed = ~[];
    let mut p = parser::Parser::new(src);

    while !p.is_eof() {
        match p.parse() {
            Ok(v) => parsed.push(@v),
            Err(e) => return Err(e)
        }
    }

    Ok(parsed)
}

/// Symbol identifier
pub type Ident = ~str;

/// Holds a typed value
#[deriving(Eq, Clone)]
pub enum Value {
    Bool(bool),
    Int(int),
    Float(float),
    Str(~str),
    List(~[@Value]),
    Symbol(Ident),
    Lambda(~[Ident], @Value),
    Macro(~[Ident], @Value),
    Rust(RustFn),
    RustMacro(RustFn),
}

/// Workaround for `deriving` not working for rust closures
pub struct RustFn(@fn(params: &[@Value], env: @mut Rusp) -> EvalResult);

impl Eq for RustFn {
    fn eq(&self, _: &RustFn) -> bool {
        fail!("Cannot test equality of Rust functions (yet?).");
    }
    fn ne(&self, other: &RustFn) -> bool { !self.eq(other) }
}

impl Clone for RustFn {
    fn clone(&self) -> RustFn {
        // copy the pointer
        *self
    }
}

#[deriving(Eq)]
pub struct Rusp {
    values: HashMap<Ident, @Value>,
    outer: Option<@mut Rusp>,
}

pub type EvalResult = Result<@Value, ~str>;

impl Rusp {
    /// Initializes an empty environment
    pub fn empty() -> @mut Rusp {
        @mut Rusp {
            values: HashMap::new(),
            outer: None,
        }
    }

    /// Initializes an environment containing the default built-ins
    pub fn new() -> @mut Rusp {
        @mut Rusp {
            values: builtins::builtins(),
            outer: None
        }
    }

    /// Initializes a new environment with a parent environment
    pub fn new_with_outer(outer: @mut Rusp) -> @mut Rusp {
        @mut Rusp {
            values: HashMap::new(),
            outer: Some(outer),
        }
    }

    /// Defines a new identifier/value pair in the environment
    pub fn define(&mut self, ident: Ident, val: @Value) -> EvalResult {
        if self.values.insert(ident.clone(), val)  {
            Ok(@List(~[]))
        } else {
            Err(fmt!("`%s` was already defined in this environment.", ident.to_str()))
        }
    }

    /// Attempts to find a value corresponding to the supplied identifier
    pub fn find(&self, ident: &Ident) -> Option<@Value> {
        match self.values.find(ident) {
            Some(val) => Some(*val),
            None => self.outer.chain(|env| env.find(ident)),
        }
    }

    /// Evaluates a Rusp expression in the environment
    pub fn eval(@mut self, value: @Value) -> EvalResult {
        match *value {
            Symbol(ref id) => {
                match self.find(id) {
                    Some(val) => Ok(val),
                    None => Err(fmt!("The value of `%s` was not defined in this environment",
                                     id.to_str())),
                }
            }
            List([ref vals, .. args]) => {
                do self.eval(*vals).chain |res| {
                    self.eval_call(res, args)
                }
            }
            List([]) => Ok(@List(~[])),
            // everything else evaluates to itself
            _ => Ok(value)
        }
    }

    /// Eval a call using `func`, which should have been previously
    /// evaluated.
    fn eval_call(@mut self, func: &Value, args: &[@Value]) -> EvalResult {
        match *func {
            Lambda(ref ids, ref body) => {
                if ids.len() != args.len() {
                    return Err(fmt!("lambda expects %u arguments", ids.len()));
                }
                // stores the argument bindings of the function
                let local = Rusp::new_with_outer(self);
                for vec::each2(*ids, args) |id, val| {
                    match self.eval(*val) {
                        Err(e) => return Err(e),
                        Ok(v) => match local.define(id.clone(), v) {
                            Err(e) => return Err(e),
                            _ => {}
                        }
                    }
                }
                local.eval(*body)
            }
            Macro(ref ids, ref body) => {
                if ids.len() != args.len() {
                    return Err(fmt!("macro expects %u arguments", ids.len()));
                }
                // stores the argument bindings of the macro
                let local = Rusp::new_with_outer(self);
                for vec::each2(*ids, args) |id, val| {
                    match local.define(id.clone(), *val) {
                        Err(e) => return Err(e),
                        _ => {}
                    }
                }
                local.eval(*body)
            }
            Rust(ref f) => {
                let mut evaled_args = ~[];
                for args.each |v| {
                    match self.eval(*v) {
                        Err(e) => return Err(e),
                        Ok(evaled) => { evaled_args.push(evaled) }
                    }
                }
                (**f)(evaled_args, self)
            }
            RustMacro(ref f) => {
                (**f)(args, self)
            }
            _ => Err(~"not a function")
        }
    }
}

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

    #[test]
    fn test_env() {
        let outer = Rusp::new();
        outer.define(~"a", @Int(0));
        outer.define(~"b", @Float(1.0));
        outer.define(~"c", @Str(~"hi"));

        let inner = Rusp::new_with_outer(outer);
        inner.define(~"a", @Int(3));
        inner.define(~"b", @Int(4));

        assert_eq!(outer.find(&~"a"), Some(@Int(0)));
        assert_eq!(outer.find(&~"b"), Some(@Float(1.0)));
        assert_eq!(outer.find(&~"c"), Some(@Str(~"hi")));
        assert_eq!(inner.find(&~"a"), Some(@Int(3)));
        assert_eq!(inner.find(&~"b"), Some(@Int(4)));
        assert_eq!(inner.find(&~"c"), Some(@Str(~"hi")));
    }

    #[test]
    fn test_atoms() {
        assert_eq!(Rusp::new().eval(@Int(1)).get(), @Int(1));
        assert_eq!(Rusp::new().eval(@Float(1.0)).get(), @Float(1.0));
        assert_eq!(Rusp::new().eval(@Str(~"hi")).get(), @Str(~"hi"));
    }

    #[test]
    fn test_list() {
        assert_eq!(Rusp::new().eval(@List(~[])).get(), @List(~[]));
        assert_eq!(
            Rusp::new().eval(@List(~[
                @Symbol(~"list"),
                @Str(~"hi"),
                @List(~[@Symbol(~"quote"), @Symbol(~"x")]),
                @Int(1)
            ])).get(),
            @List(~[
                @Str(~"hi"),
                @Symbol(~"x"),
                @Int(1)
            ])
        );
    }

    #[test]
    fn test_quote() {
        assert_eq!(Rusp::new().eval(
            @List(~[@Symbol(~"quote"), @Symbol(~"x")])).get(),
            @Symbol(~"x")
        );
    }

    #[test]
    fn test_symbol() {
        let env = Rusp::new();
        env.define(~"a", @Int(0));
        env.define(~"b", @Float(1.0));
        env.define(~"c", @Str(~"hi"));

        assert_eq!(env.eval(@Symbol(~"a")).get(), @Int(0));
        assert_eq!(env.eval(@Symbol(~"b")).get(), @Float(1.0));
        assert_eq!(env.eval(@Symbol(~"c")).get(), @Str(~"hi"));
        assert!(env.eval(@Symbol(~"d")).is_err());
    }

    #[test]
    fn test_if() {
        fn not(test: Value) -> EvalResult {
            Rusp::new().eval(@List(~[@Symbol(~"if"), @test, @Bool(false), @Bool(true)]))
        }

        assert_eq!(not(Bool(true)).get(), @Bool(false));
        assert_eq!(not(Bool(false)).get(), @Bool(true));
        assert!(not(Str(~"hi")).is_err());
    }

    #[test]
    fn test_def() {
        let env = Rusp::new();
        assert!(env.eval(@List(~[@Symbol(~"def"), @Symbol(~"a"), @Int(0)])).is_ok());
        assert!(env.eval(@List(~[@Symbol(~"def"), @Symbol(~"b"), @Float(1.0)])).is_ok());
        assert!(env.eval(@List(~[@Symbol(~"def"), @Symbol(~"c"), @Str(~"hi")])).is_ok());

        assert_eq!(env.find(&~"a"), Some(@Int(0)));
        assert_eq!(env.find(&~"b"), Some(@Float(1.0)));
        assert_eq!(env.find(&~"c"), Some(@Str(~"hi")));

        assert!(env.eval(@List(~[@Symbol(~"def"), @Symbol(~"c"), @List(~[])])).is_err());
    }

    #[test]
    fn test_do() {
        assert_eq!(Rusp::new().eval(@List(~[@Symbol(~"do"), @Str(~"hi")])).get(), @Str(~"hi"));
        assert_eq!(
            Rusp::new().eval(@List(~[
                @Symbol(~"do"),
                @List(~[]),
                @List(~[@Symbol(~"do"), @List(~[])]),
                @Str(~"hi")
            ])).get(),
            @Str(~"hi")
        );

        assert!(Rusp::new().eval(@List(~[@Symbol(~"do"), @Str(~"hi"), @List(~[])])).is_err());
    }

    #[test]
    fn test_fn() {
        let env = Rusp::new();
        env.eval(parse("(def f (fn (a b) a))").unwrap()[0]);
        assert_eq!(env.eval(parse("(f 1 2)").unwrap()[0]).unwrap(), @Int(1));

        assert!(env.eval(parse("(f 1)").unwrap()[0]).is_err());
    }

    #[test]
    fn test_macro() {
        let env = Rusp::new();
        env.eval(parse("(def m (macro (a) a))").unwrap()[0]);
        env.eval(parse("(def f (fn (a) a))").unwrap()[0]);
        env.eval(parse("(def x 1)").unwrap()[0]);

        // check the semantics of macros vs fn, x is not evaluated for
        // `m`, but is for `f`.
        assert_eq!(env.eval(parse("(m x)").unwrap()[0]).unwrap(), @Symbol(~"x"));
        assert_eq!(env.eval(parse("(f x)").unwrap()[0]).unwrap(), @Int(1));
    }
}
<|endoftext|>


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

#![doc = "Rust wrappers around the raw JS apis"]

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::c_char;
use std::cmp;
use std::rc;
use std::rt::Runtime;
use jsapi::*;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use ERR;
use std::str::raw::from_c_str;
use green::task::GreenTask;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

extern fn gc_callback(rt: *JSRuntime, _status: JSGCStatus) {
    use std::rt::local::Local;
    use std::rt::task::Task;
    unsafe {
        let mut task = Local::borrow(None::<Task>);
        let green_task: ~GreenTask = task.get().maybe_take_runtime().unwrap();
        let (start, end) = green_task.stack_bounds();
        JS_SetNativeStackBounds(rt, cmp::min(start, end), cmp::max(start, end));
        task.get().put_runtime(green_task);
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        JS_SetGCCallback(runtime, gc_callback);
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: i32) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportError);
        }
    }

    pub fn set_error_reporter(&self, reportfn: extern "C" fn(*JSContext, *c_char, *JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportfn);
        }
    }

    pub fn evaluate_script(&self, glob: *JSObject, script: ~str, filename: ~str, line_num: uint)
                    -> Result<(),()> {
        let script_utf16 = script.to_utf16();
        filename.to_c_str().with_ref(|filename_cstr| {
            let rval: JSVal = NullValue();
            debug!("Evaluating script from {:s} with content {}", filename, script);
            unsafe {
                if ERR == JS_EvaluateUCScript(self.ptr, glob,
                                              script_utf16.as_ptr(), script_utf16.len() as c_uint,
                                              filename_cstr, line_num as c_uint,
                                              &rval) {
                    debug!("...err!");
                    Err(())
                } else {
                    // we could return the script result but then we'd have
                    // to root it and so forth and, really, who cares?
                    debug!("...ok!");
                    Ok(())
                }
            }
        })
    }
}

pub extern fn reportError(_cx: *JSContext, msg: *c_char, report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {"none".to_owned()};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at {:s}:{}: {:s}\n", fname, lineno, msg);
    }
}

pub fn with_compartment<R>(cx: *JSContext, object: *JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

}
<commit_msg>Upgrade to current Rust.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#![doc = "Rust wrappers around the raw JS apis"]

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::c_char;
use std::cmp;
use std::rc;
use std::rt::Runtime;
use jsapi::*;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use ERR;
use std::str::raw::from_c_str;
use green::task::GreenTask;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

extern fn gc_callback(rt: *JSRuntime, _status: JSGCStatus) {
    use std::rt::local::Local;
    use std::rt::task::Task;
    unsafe {
        let mut task = Local::borrow(None::<Task>);
        let green_task: Box<GreenTask> = task.maybe_take_runtime().unwrap();
        let (start, end) = green_task.stack_bounds();
        JS_SetNativeStackBounds(rt, cmp::min(start, end), cmp::max(start, end));
        task.put_runtime(green_task);
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        JS_SetGCCallback(runtime, gc_callback);
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: i32) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportError);
        }
    }

    pub fn set_error_reporter(&self, reportfn: extern "C" fn(*JSContext, *c_char, *JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, reportfn);
        }
    }

    pub fn evaluate_script(&self, glob: *JSObject, script: ~str, filename: ~str, line_num: uint)
                    -> Result<(),()> {
        let script_utf16 = script.to_utf16();
        filename.to_c_str().with_ref(|filename_cstr| {
            let rval: JSVal = NullValue();
            debug!("Evaluating script from {:s} with content {}", filename, script);
            unsafe {
                if ERR == JS_EvaluateUCScript(self.ptr, glob,
                                              script_utf16.as_ptr(), script_utf16.len() as c_uint,
                                              filename_cstr, line_num as c_uint,
                                              &rval) {
                    debug!("...err!");
                    Err(())
                } else {
                    // we could return the script result but then we'd have
                    // to root it and so forth and, really, who cares?
                    debug!("...ok!");
                    Ok(())
                }
            }
        })
    }
}

pub extern fn reportError(_cx: *JSContext, msg: *c_char, report: *JSErrorReport) {
    unsafe {
        let fnptr = (*report).filename;
        let fname = if fnptr.is_not_null() {from_c_str(fnptr)} else {"none".to_owned()};
        let lineno = (*report).lineno;
        let msg = from_c_str(msg);
        error!("Error at {:s}:{}: {:s}\n", fname, lineno, msg);
    }
}

pub fn with_compartment<R>(cx: *JSContext, object: *JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

}
<|endoftext|>


<commit_before>fn on_osmain(f: fn~()) {
    let builder = task::builder();
    task::set_opts(builder, {
        sched: some({
            mode: task::osmain,
            foreign_stack_size: none
        })
        with task::get_opts(builder)
    });
    let po = comm::port();
    let ch = comm::chan(po);
    task::run(builder, || {
        f();
        comm::send(ch, ());
    });
    comm::recv(po);
}

// FIXME: Needs additional cocoa setup on OS X. rust-cocoa should probably just
// be a dependency
#[test]
#[ignore(cfg(target_os = "macos"))]
fn test_everything() {

    on_osmain(|| {
        init(~[init_video, init_timer]);
        run_tests(~[
            general::test_was_init,
            general::test_set_error,
            general::test_error,
            general::test_clear_error,
            video::test_set_video_mode,
            // FIXME: Doesn't work when called from a directory that
            // doesn't contain the test image file
            //video::test_blit,
            test_event::test_poll_event_none
            // FIXME: This test is interactive
            //test_event::test_keyboard
        ]);
        quit();
    })
}

fn run_tests(tests: ~[fn()]) {
    vec::iter(tests, |test| test());
}

mod general {
    fn test_was_init() {
        assert vec::contains(was_init(~[init_timer]), init_timer);
    }

    fn test_set_error() {
        set_error(~"test");
        assert get_error() == ~"test";
    }

    fn test_error() {
        clear_error();
        assert str::is_empty(get_error());
        error(enomem);
        assert str::is_not_empty(get_error());
    }

    fn test_clear_error() {
        set_error(~"test");
        clear_error();
        assert str::is_empty(get_error());
    }
}

mod test_event {
    fn test_poll_event_none() {
        ::event::poll_event(|event| assert event == ::event::no_event);
    }

    fn test_keyboard() {
        io::println(~"press a key in the window");
        let surface = ::video::set_video_mode(320, 200, 32,
            ~[::video::swsurface], ~[::video::doublebuf, ::video::resizable]);
        let mut keydown = false;
        let mut keyup = false;
        while !keydown || !keyup {
            ::event::poll_event(|event| {
                alt event {
                  event::keyup_event(_) { keyup = true; }
                  event::keydown_event(_) { keydown = true; }
                  _ { }
                }
            })
        }
        ::video::free_surface(surface);
    }
}

mod video {

    fn test_set_video_mode() {
        let surface = ::video::set_video_mode(320, 200, 32,
            ~[::video::hwsurface], ~[::video::doublebuf]);
        assert surface != ptr::null();
        ::video::free_surface(surface);
    }

    fn test_blit() {
        let screen = ::video::set_video_mode(320, 200, 32,
            ~[::video::swsurface], ~[::video::doublebuf]);
        assert screen != ptr::null();

        let image = {
            // FIXME: We need to load this from the crate instead of
            // off the filesystem
            let tmp = ::video::load_bmp(~"rust-logo-128x128-blk.bmp");
            assert tmp != ptr::null();
            let image = ::video::display_format(tmp);
            assert image != ptr::null();
            ::video::free_surface(tmp);
            image
        };

        for iter::repeat(1u) || {
            ::video::blit_surface(image, ptr::null(),
                                  screen, ptr::null());
            ::video::flip(screen);
            ::event::poll_event(|_event| {})
        };

        ::video::free_surface(image);
        ::video::free_surface(screen);
    }
}
<commit_msg>Change rust-sdl test.rs to new task::task_builder interface<commit_after>fn on_osmain(f: fn~()) {
    let po = comm::port();
    let ch = comm::chan(po);
    do task::spawn_sched(task::osmain) {
        f();
        comm::send(ch, ());
    }
    comm::recv(po);
}

// FIXME: Needs additional cocoa setup on OS X. rust-cocoa should probably just
// be a dependency
#[test]
#[ignore(cfg(target_os = "macos"))]
fn test_everything() {

    on_osmain(|| {
        init(~[init_video, init_timer]);
        run_tests(~[
            general::test_was_init,
            general::test_set_error,
            general::test_error,
            general::test_clear_error,
            video::test_set_video_mode,
            // FIXME: Doesn't work when called from a directory that
            // doesn't contain the test image file
            //video::test_blit,
            test_event::test_poll_event_none
            // FIXME: This test is interactive
            //test_event::test_keyboard
        ]);
        quit();
    })
}

fn run_tests(tests: ~[fn()]) {
    vec::iter(tests, |test| test());
}

mod general {
    fn test_was_init() {
        assert vec::contains(was_init(~[init_timer]), init_timer);
    }

    fn test_set_error() {
        set_error(~"test");
        assert get_error() == ~"test";
    }

    fn test_error() {
        clear_error();
        assert str::is_empty(get_error());
        error(enomem);
        assert str::is_not_empty(get_error());
    }

    fn test_clear_error() {
        set_error(~"test");
        clear_error();
        assert str::is_empty(get_error());
    }
}

mod test_event {
    fn test_poll_event_none() {
        ::event::poll_event(|event| assert event == ::event::no_event);
    }

    fn test_keyboard() {
        io::println(~"press a key in the window");
        let surface = ::video::set_video_mode(320, 200, 32,
            ~[::video::swsurface], ~[::video::doublebuf, ::video::resizable]);
        let mut keydown = false;
        let mut keyup = false;
        while !keydown || !keyup {
            ::event::poll_event(|event| {
                alt event {
                  event::keyup_event(_) { keyup = true; }
                  event::keydown_event(_) { keydown = true; }
                  _ { }
                }
            })
        }
        ::video::free_surface(surface);
    }
}

mod video {

    fn test_set_video_mode() {
        let surface = ::video::set_video_mode(320, 200, 32,
            ~[::video::hwsurface], ~[::video::doublebuf]);
        assert surface != ptr::null();
        ::video::free_surface(surface);
    }

    fn test_blit() {
        let screen = ::video::set_video_mode(320, 200, 32,
            ~[::video::swsurface], ~[::video::doublebuf]);
        assert screen != ptr::null();

        let image = {
            // FIXME: We need to load this from the crate instead of
            // off the filesystem
            let tmp = ::video::load_bmp(~"rust-logo-128x128-blk.bmp");
            assert tmp != ptr::null();
            let image = ::video::display_format(tmp);
            assert image != ptr::null();
            ::video::free_surface(tmp);
            image
        };

        for iter::repeat(1u) || {
            ::video::blit_surface(image, ptr::null(),
                                  screen, ptr::null());
            ::video::flip(screen);
            ::event::poll_event(|_event| {})
        };

        ::video::free_surface(image);
        ::video::free_surface(screen);
    }
}
<|endoftext|>


<commit_before><commit_msg>SNI tests<commit_after><|endoftext|>


<commit_before>// "Tifflin" Kernel - ATA Driver
// - By John Hodge (thePowersGang)
//
// Modules/input_ps2/keyboard.rs
//! PS2 Keyboard driver
use kernel::_common::*;

#[derive(Debug)]
pub enum Type
{
	AT,
	MF2,
	MF2Emul,
}

#[derive(Debug)]
enum State
{
	Init(Init),
	Idle(Layer,bool),
}
#[derive(Copy,Clone,Debug)]
enum Layer
{
	Base,
	E0,
	E1,
}
#[derive(Copy,Clone,Debug)]
enum Init
{
	Disabled,
	ReqScancodeSetAck,
	ReqScancodeSetRsp,
	SetLeds(u8),
}

#[derive(Debug)]
pub struct Dev
{
	ty: Type,
	state: State,
}

impl Dev
{
	pub fn new(ty: Type) -> (Option<u8>,Dev) {

		match ty
		{
		Type::MF2Emul => {
			log_warning!("Unexpected emulation enabled MF2");
			return (None, Dev { ty: ty, state: State::Init(Init::Disabled) });
			},
		_ => {},
		}

		// 1. Request scancode set
		(Some(0xF0), Dev {
			ty: ty,
			state: State::Init(Init::ReqScancodeSetAck),
			})
	}

	pub fn recv_byte(&mut self, byte: u8) -> Option<u8> {
		match self.state
		{
		State::Init(s) =>
			match s
			{
			Init::Disabled => None,
			Init::ReqScancodeSetAck => {
				self.state = State::Init(Init::ReqScancodeSetRsp);
				Some(0x00)
				},
			Init::ReqScancodeSetRsp =>
				match byte
				{
				// Scancode set 1
				1 /*0x43*/ => {
					log_warning!("TODO: Support scancode set 1");
					self.state = State::Init(Init::Disabled);
					None
					},
				// Scancode set 2 (most common)
				2 /*0x41*/ => {
					self.state = State::Idle(Layer::Base,false);
					None
					},
				// Scancode set 3 (newest)
				3 /*0x3F*/ => {
					log_warning!("TODO: Support scancode set 3");
					self.state = State::Init(Init::Disabled);
					None
					},
				_ => {
					log_warning!("Unkown scancode set reponse {:#02x}", byte);
					self.state = State::Init(Init::Disabled);
					None
					},
				},
			Init::SetLeds(v) => {
				self.state = State::Idle(Layer::Base,false);
				Some(v)
				},
			},
		State::Idle(layer,mut release) =>
			match byte
			{
			// Error/Buffer Overrun
			0x00 => None,
			0xFF => None,
			// Self-test passed
			0xAA => None,
			// Self-test failed
			0xFC => None,
			0xFD => None,
			// Echo reply
			0xEE => None,
			// ACK
			0xFA => { log_notice!("Unexpected ACK from keyboard"); None },
			// Resend
			0xFE => { log_notice!("Resend request from keyboard"); None },
			// Extended scancodes
			0xE0 => {
				self.state = State::Idle(Layer::E0, false);
				None
				},
			0xE1 => {
				self.state = State::Idle(Layer::E1, false);
				None
				},
			// Released key flag
			0xF0 => {
				self.state = State::Idle(layer, true);
				None
				},

			v @ _ => {
				log_debug!("Scancode {:?} {:#02x} (release={})", layer, v, release);
				// TODO: Translate to a HID scancode, then pass to a higher layer (GUI or metadev keyboard)
				self.state = State::Idle(Layer::Base,false);
				None
				},
			},
		}
	}
}

<commit_msg>PS2 - (minor) Add error when AT keyboard is requested<commit_after>// "Tifflin" Kernel - ATA Driver
// - By John Hodge (thePowersGang)
//
// Modules/input_ps2/keyboard.rs
//! PS2 Keyboard driver
use kernel::_common::*;

#[derive(Debug)]
pub enum Type
{
	AT,
	MF2,
	MF2Emul,
}

#[derive(Debug)]
enum State
{
	Init(Init),
	Idle(Layer,bool),
}
#[derive(Copy,Clone,Debug)]
enum Layer
{
	Base,
	E0,
	E1,
}
#[derive(Copy,Clone,Debug)]
enum Init
{
	Disabled,
	ReqScancodeSetAck,
	ReqScancodeSetRsp,
	SetLeds(u8),
}

#[derive(Debug)]
pub struct Dev
{
	ty: Type,
	state: State,
}

impl Dev
{
	pub fn new(ty: Type) -> (Option<u8>,Dev) {

		match ty
		{
		Type::AT => {
			log_warning!("Unexpected AT keyboard");
			return (None, Dev { ty: ty, state: State::Init(Init::Disabled) });
			},
		Type::MF2Emul => {
			log_warning!("Unexpected emulation enabled MF2");
			return (None, Dev { ty: ty, state: State::Init(Init::Disabled) });
			},
		Type::MF2 => {},
		}

		// 1. Request scancode set
		(Some(0xF0), Dev {
			ty: ty,
			state: State::Init(Init::ReqScancodeSetAck),
			})
	}

	pub fn recv_byte(&mut self, byte: u8) -> Option<u8> {
		match self.state
		{
		State::Init(s) =>
			match s
			{
			Init::Disabled => None,
			Init::ReqScancodeSetAck => {
				self.state = State::Init(Init::ReqScancodeSetRsp);
				Some(0x00)
				},
			Init::ReqScancodeSetRsp =>
				match byte
				{
				// Scancode set 1
				1 /*0x43*/ => {
					log_warning!("TODO: Support scancode set 1");
					self.state = State::Init(Init::Disabled);
					None
					},
				// Scancode set 2 (most common)
				2 /*0x41*/ => {
					self.state = State::Idle(Layer::Base,false);
					None
					},
				// Scancode set 3 (newest)
				3 /*0x3F*/ => {
					log_warning!("TODO: Support scancode set 3");
					self.state = State::Init(Init::Disabled);
					None
					},
				_ => {
					log_warning!("Unkown scancode set reponse {:#02x}", byte);
					self.state = State::Init(Init::Disabled);
					None
					},
				},
			Init::SetLeds(v) => {
				self.state = State::Idle(Layer::Base,false);
				Some(v)
				},
			},
		State::Idle(layer,mut release) =>
			match byte
			{
			// Error/Buffer Overrun
			0x00 => None,
			0xFF => None,
			// Self-test passed
			0xAA => None,
			// Self-test failed
			0xFC => None,
			0xFD => None,
			// Echo reply
			0xEE => None,
			// ACK
			0xFA => { log_notice!("Unexpected ACK from keyboard"); None },
			// Resend
			0xFE => { log_notice!("Resend request from keyboard"); None },
			// Extended scancodes
			0xE0 => {
				self.state = State::Idle(Layer::E0, false);
				None
				},
			0xE1 => {
				self.state = State::Idle(Layer::E1, false);
				None
				},
			// Released key flag
			0xF0 => {
				self.state = State::Idle(layer, true);
				None
				},

			v @ _ => {
				log_debug!("Scancode {:?} {:#02x} (release={})", layer, v, release);
				// TODO: Translate to a HID scancode, then pass to a higher layer (GUI or metadev keyboard)
				self.state = State::Idle(Layer::Base,false);
				None
				},
			},
		}
	}
}

<|endoftext|>