<commit_before>//! Storage Engine trait and several implementations
//!
//!
pub mod flatfile;

use self::flatfile::FlatFile;

use std::mem;

use std::io;
use std::io::prelude::*;

use std::fs;
use std::fs::{OpenOptions, create_dir};

use std::convert::From;

use byteorder::Error;
use byteorder::{WriteBytesExt, ReadBytesExt, BigEndian};

use bincode::SizeLimit;
use bincode::rustc_serialize::{EncodingError, DecodingError, encode_into, decode_from};

/// constants
 const MAGIC_NUMBER: u64 = 0x6561742073686974; // secret
 const VERSION_NO: u8 = 1;

/// A database table
///
/// Through this type, you can retreive certain meta information about the
/// table (like column names, column types, storage engine, ...). It's `access`
/// method locks the table globally and returns a storage engine to access
/// the table data.
#[derive(Debug)]
pub enum DatabaseError {
    Io(io::Error),
    BinEn(EncodingError),
    BinDe(DecodingError),
    Byteorder(::byteorder::Error),
    WrongMagicNmbr,
    Engine, //cur not used
    LoadDataBase,
    RemoveColumn,
    AddColumn,
}

impl From<io::Error> for DatabaseError {
    fn from(err: io::Error) -> DatabaseError {
        DatabaseError::Io(err)
    }
}

impl  From<EncodingError> for DatabaseError {
    fn from(err: EncodingError) -> DatabaseError {
        DatabaseError::BinEn(err)
    }
}

impl From<DecodingError> for DatabaseError {
    fn from(err: DecodingError) -> DatabaseError {
        DatabaseError::BinDe(err)
    }
}

impl From< ::byteorder::Error> for DatabaseError {
    fn from(err: ::byteorder::Error) -> DatabaseError {
        DatabaseError::Byteorder(err)
    }
}

//---------------------------------------------------------------
// DataType
//---------------------------------------------------------------
/// A Enum for Datatypes (will be removed later)
#[repr(u8)]
#[derive(Clone,Copy,Debug,RustcDecodable, RustcEncodable)]
pub enum DataType { Integer = 1, Float = 2, }

impl DataType {
    pub fn value(&self) -> u8 {
       *self as u8
    }
}

//---------------------------------------------------------------
// Database
//---------------------------------------------------------------
#[derive(Debug)]
pub struct Database {
    name: String,
}

impl Database {
    /// Starts the process of creating a new Database
    /// Returns database or on fail DatabaseError
    pub fn create(name: &str) -> Result<Database, DatabaseError> {
        let d = Database{ name: name.to_string() };
        try!(d.save());
        Ok(d)
    }

    /// Loads already existing Database
    /// returns DataBase Error when database does not exist else the loaded DB
    pub fn load(name: &str) -> Result<Database, DatabaseError> {
        if try!(fs::metadata(name)).is_dir() {
            Ok(Database{ name: name.to_string() })
        } else {
            return Err(DatabaseError::LoadDataBase)
        }
    }

    /// Creates a folder for the database
    fn save(&self) -> Result<(), DatabaseError> {
        println!("trying to create dir!");
        try!(create_dir(&self.name));
        println!("created dir");
        Ok(())
    }

    /// Creates a new table in the DB folder
    /// Returns with DatabaseError on fail else Table
    pub fn create_table(&self, name: &str, columns: Vec<Column>, engine_id: u8)
        -> Result<Table, DatabaseError>
    {

        let t = Table::new(&self, name, columns, engine_id);
        try!(t.save());
        Ok(t)
    }

    /// calls load for table with the database path
    /// Returns with DatabaseError on fail else Table
    pub fn load_table(&self, name: &str) -> Result<Table, DatabaseError> {
        Table::load(&self, name)
    }
}

//---------------------------------------------------------------
// TableMetaData
//---------------------------------------------------------------

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct  TableMetaData {
    version_nmbr: u8,
    engine_id: u8,
    columns: Vec<Column>,
}

//---------------------------------------------------------------
// Table
//---------------------------------------------------------------

/// Table struct that contains the table information
pub struct Table<'a> {
    database: &'a Database,
    name: String,
    meta_data: TableMetaData,
}

impl<'a> Table<'a> {
    /// Creates new table object
    /// Returns Table
    pub fn new<'b>(database: &'b Database, name: &str,
                   columns: Vec<Column>, engine_id: u8)
        -> Table<'b>
    {

        let meta_data = TableMetaData {
            version_nmbr: VERSION_NO,
            engine_id: engine_id,
            columns: columns,
        };

        Table {
            name: name.to_string(),
            database: database,
            meta_data: meta_data,
        }
    }

    /// Loads the table from the DB
    /// Returns with DatabaseError on fail else Table
    fn load<'b>(database: &'b Database, name: &str)
        -> Result<Table<'b>, DatabaseError>
    {
        // TODO: Read the .tbl file from disk and parse it
        let path_to_table = Table::get_path(&database.name, name, "tbl");
        let mut file = try!(OpenOptions::new()
            .read(true)
            .open(path_to_table));

        let ma_nmbr = try!(file.read_uint::<BigEndian>(mem::size_of_val(&MAGIC_NUMBER)));

        if ma_nmbr != MAGIC_NUMBER {
            println!("Magic Number not correct");
            return Err(DatabaseError::WrongMagicNmbr)
        }
        let meta_data: TableMetaData = try!(decode_from(&mut file, SizeLimit::Infinite));
        println!("{:?}", meta_data);

        let table = Table::new(database, name, meta_data.columns, meta_data.engine_id);

        Ok(table)
    }

    /// Saves the table with a identification number in table file
    /// Returns DatabaseError on fail else Nothing
    pub fn save(&self) -> Result<(), DatabaseError> {
        // call for open file
        let mut file = try!(OpenOptions::new()
            .write(true)
            .create(true)
            .open(self.get_table_metadata_path()));

        try!(file.write_u64::<BigEndian>(MAGIC_NUMBER));//MAGIC_NUMBER
        try!(encode_into(&self.meta_data, &mut file,SizeLimit::Infinite));

        // debug message all okay
        println!("I Wrote my File");
        Ok(())
    }

    /// Returns columns of table as array
    pub fn columns(&self) -> &[Column] {
        &self.meta_data.columns
    }

    /// Adds a column to the tabel
    /// Returns name of Column or on fail DatabaseError
    pub fn add_column(&mut self, name: &str, dtype: DataType) -> Result<(), DatabaseError> {
        match self.meta_data.columns.iter().find(|x| x.name == name) {
            Some(_) => {
                warn!("Column {:?} already exists", name);
                return Err(DatabaseError::AddColumn)
            },
            None => {
                info!("Column {:?} was added", name);
            },
        }
        self.meta_data.columns.push(Column::create_new(name, dtype));
        Ok(())
    }

    /// Removes a column from the table
    /// Returns name of Column or on fail DatabaseError
    pub fn remove_column(&mut self, name: &str) -> Result<(), DatabaseError> {
        let index = match self.meta_data.columns.iter().position(|x| x.name == name) {
            Some(x) => {
                info!("Column {:?} was removed" , self.name);
                x
            },
            None => {
                warn!("Column {:?} could not be found", self.name);
                return Err(DatabaseError::RemoveColumn)
            },
        };
        self.meta_data.columns.swap_remove(index);
        Ok(())
    }

    /// Creates an engine for Table
    /// Returns Box<Engine>
    pub fn create_engine(self) -> Box<Engine + 'a> {
        Box::new(FlatFile::new(self))
    }

    /// Returns the path for the metadata files
    fn get_table_metadata_path(&self) -> String {
        Self::get_path(&self.database.name, &self.name, "tbl")
    }

    /// Returns the path for the data files
    fn get_table_data_path(&self) -> String {
        Self::get_path(&self.database.name, &self.name, "dat")
    }

    /// Returns the path of the table
    fn get_path(database: &str, name: &str, ext: &str) -> String {
         format!("{}/{}.{}", database, name, ext)
    }
}

//---------------------------------------------------------------
// Column
//---------------------------------------------------------------

/// A table column. Has a name, a type, ...
#[derive(Debug,RustcDecodable, RustcEncodable,Clone)]
pub struct Column {
    pub name: String, //name of column
    pub data_type: DataType, //name of the data type that is contained in this column
}

impl Default for Column {
    /// Returns a default Column construct
    fn default() -> Column {
        Column {
            name: "default".to_string(),
            data_type: DataType::Integer
        }
    }
}

impl Column {
    /// Creates a new column object
    /// Returns with Column
    pub fn create_new(name: &str, dtype: DataType) -> Column {
        Column {
            name: name.to_string(),
            data_type: dtype.clone()
        }
    }
}

//---------------------------------------------------------------
// Engine
//---------------------------------------------------------------

/// Storage Engine Interface.
///
/// A storage engine, like MyISAM and InnoDB, is responsible for reading and
/// writing data to disk, maintain and use indices, check for data corruption
/// and repair corrupt files.
///
/// Each table in a database may use a different storage engine.
pub trait Engine {
    fn create_table(&mut self) -> Result<(), DatabaseError>;
}

// # Some information for the `storage` working group:
//
// You work at the very bottom of the database: The thing that actually
// writes the data disk. Everything in this module is used only by the
// query execution module.
//
// The file layout may look like this:
// We have some `db_dir` where everything lives. In that directory, there are
// subdirectories for every database. In each of those subdirs is optionally
// a file `db.meta` that contains information about the database (such as
// permissions). The tables of each database are saved in *.tbl files that
// live inside the database directory.
//
// Your task is to provide types and method to:
// - read a specific table from a specific
//   database from file
// - create a new table in a database
// - query meta information about a table (columns for example)
// - lock a table for reading/writing it's data through a storage engine
//
// The other main task is to:
// - specify the storage engine interface
// - implement a simple storage engine (heap/flatfiles)
//
<commit_msg>Change all println! to info! or warn!, also added more logs<commit_after>//! Storage Engine trait and several implementations
//!
//!
pub mod flatfile;

use self::flatfile::FlatFile;

use std::mem;

use std::io;
use std::io::prelude::*;

use std::fs;
use std::fs::{OpenOptions, create_dir};

use std::convert::From;

use byteorder::Error;
use byteorder::{WriteBytesExt, ReadBytesExt, BigEndian};

use bincode::SizeLimit;
use bincode::rustc_serialize::{EncodingError, DecodingError, encode_into, decode_from};

/// constants
 const MAGIC_NUMBER: u64 = 0x6561742073686974; // secret
 const VERSION_NO: u8 = 1;

/// A database table
///
/// Through this type, you can retreive certain meta information about the
/// table (like column names, column types, storage engine, ...). It's `access`
/// method locks the table globally and returns a storage engine to access
/// the table data.
#[derive(Debug)]
pub enum DatabaseError {
    Io(io::Error),
    BinEn(EncodingError),
    BinDe(DecodingError),
    Byteorder(::byteorder::Error),
    WrongMagicNmbr,
    Engine, //cur not used
    LoadDataBase,
    RemoveColumn,
    AddColumn,
}

impl From<io::Error> for DatabaseError {
    fn from(err: io::Error) -> DatabaseError {
        DatabaseError::Io(err)
    }
}

impl  From<EncodingError> for DatabaseError {
    fn from(err: EncodingError) -> DatabaseError {
        DatabaseError::BinEn(err)
    }
}

impl From<DecodingError> for DatabaseError {
    fn from(err: DecodingError) -> DatabaseError {
        DatabaseError::BinDe(err)
    }
}

impl From< ::byteorder::Error> for DatabaseError {
    fn from(err: ::byteorder::Error) -> DatabaseError {
        DatabaseError::Byteorder(err)
    }
}

//---------------------------------------------------------------
// DataType
//---------------------------------------------------------------
/// A Enum for Datatypes (will be removed later)
#[repr(u8)]
#[derive(Clone,Copy,Debug,RustcDecodable, RustcEncodable)]
pub enum DataType { Integer = 1, Float = 2, }

impl DataType {
    pub fn value(&self) -> u8 {
       *self as u8
    }
}

//---------------------------------------------------------------
// Database
//---------------------------------------------------------------
#[derive(Debug)]
pub struct Database {
    name: String,
}

impl Database {
    /// Starts the process of creating a new Database
    /// Returns database or on fail DatabaseError
    pub fn create(name: &str) -> Result<Database, DatabaseError> {
        let d = Database{ name: name.to_string() };
        try!(d.save());
        info!("created new database {:?}",d);
        Ok(d)
    }

    /// Loads already existing Database
    /// returns DataBase Error when database does not exist else the loaded DB
    pub fn load(name: &str) -> Result<Database, DatabaseError> {
        if try!(fs::metadata(name)).is_dir() {
            info!("loaded Database {:?}", name.to_string());
            Ok(Database{ name: name.to_string() })
        } else {
            warn!("could not load database {:?}", name.to_string());
            return Err(DatabaseError::LoadDataBase)
        }
    }

    /// Creates a folder for the database
    fn save(&self) -> Result<(), DatabaseError> {
        info!("trying to create dir!");
        try!(create_dir(&self.name));
        info!("created dir");
        Ok(())
    }

    /// Creates a new table in the DB folder
    /// Returns with DatabaseError on fail else Table
    pub fn create_table(&self, name: &str, columns: Vec<Column>, engine_id: u8)
        -> Result<Table, DatabaseError>
    {

        let t = Table::new(&self, name, columns, engine_id);
        try!(t.save());
        info!("created new table {:?}", t);
        Ok(t)
    }

    /// calls load for table with the database path
    /// Returns with DatabaseError on fail else Table
    pub fn load_table(&self, name: &str) -> Result<Table, DatabaseError> {
        Table::load(&self, name)
    }
}

//---------------------------------------------------------------
// TableMetaData
//---------------------------------------------------------------

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct  TableMetaData {
    version_nmbr: u8,
    engine_id: u8,
    columns: Vec<Column>,
}

//---------------------------------------------------------------
// Table
//---------------------------------------------------------------

/// Table struct that contains the table information
#[derive(Debug)]
pub struct Table<'a> {
    database: &'a Database,
    name: String,
    meta_data: TableMetaData,
}

impl<'a> Table<'a> {
    /// Creates new table object
    /// Returns Table
    pub fn new<'b>(database: &'b Database, name: &str,
                   columns: Vec<Column>, engine_id: u8)
        -> Table<'b>
    {

        let meta_data = TableMetaData {
            version_nmbr: VERSION_NO,
            engine_id: engine_id,
            columns: columns,
        };
        info!("created meta data: {:?}", meta_data);

        Table {
            name: name.to_string(),
            database: database,
            meta_data: meta_data,
        }
    }

    /// Loads the table from the DB
    /// Returns with DatabaseError on fail else Table
    fn load<'b>(database: &'b Database, name: &str)
        -> Result<Table<'b>, DatabaseError>
    {
        // TODO: Read the .tbl file from disk and parse it

        let path_to_table = Table::get_path(&database.name, name, "tbl");
        info!("getting path and opening file: {:?}", path_to_table);
        let mut file = try!(OpenOptions::new()
            .read(true)
            .open(path_to_table));
        info!("reading file: {:?}", file);
        let ma_nmbr = try!(file.read_uint::<BigEndian>(mem::size_of_val(&MAGIC_NUMBER)));

        info!("checking magic number: {:?}",ma_nmbr);
        if ma_nmbr != MAGIC_NUMBER {
            println!("Magic Number not correct");
            return Err(DatabaseError::WrongMagicNmbr)
        }
        let meta_data: TableMetaData = try!(decode_from(&mut file, SizeLimit::Infinite));
        info!("getting meta data{:?}", meta_data);

        let table = Table::new(database, name, meta_data.columns, meta_data.engine_id);
        info!("returning table: {:?}", table);
        Ok(table)
    }

    /// Saves the table with a identification number in table file
    /// Returns DatabaseError on fail else Nothing
    pub fn save(&self) -> Result<(), DatabaseError> {
        // call for open file
        info!("opening file to write",);
        let mut file = try!(OpenOptions::new()
            .write(true)
            .create(true)
            .open(self.get_table_metadata_path()));
        info!("writing magic number in file: {:?}", file);
        try!(file.write_u64::<BigEndian>(MAGIC_NUMBER));//MAGIC_NUMBER
        info!("writing meta data in file: {:?}",file);
        try!(encode_into(&self.meta_data, &mut file,SizeLimit::Infinite));

        // debug message all okay
        info!("I Wrote my File");
        Ok(())
    }

    /// Returns columns of table as array
    pub fn columns(&self) -> &[Column] {
        &self.meta_data.columns
    }

    /// Adds a column to the tabel
    /// Returns name of Column or on fail DatabaseError
    pub fn add_column(&mut self, name: &str, dtype: DataType) -> Result<(), DatabaseError> {
        match self.meta_data.columns.iter().find(|x| x.name == name) {
            Some(_) => {
                warn!("Column {:?} already exists", name);
                return Err(DatabaseError::AddColumn)
            },
            None => {
                info!("Column {:?} was added", name);
            },
        }
        self.meta_data.columns.push(Column::create_new(name, dtype));
        Ok(())
    }

    /// Removes a column from the table
    /// Returns name of Column or on fail DatabaseError
    pub fn remove_column(&mut self, name: &str) -> Result<(), DatabaseError> {
        let index = match self.meta_data.columns.iter().position(|x| x.name == name) {
            Some(x) => {
                info!("Column {:?} was removed" , self.name);
                x
            },
            None => {
                warn!("Column {:?} could not be found", self.name);
                return Err(DatabaseError::RemoveColumn)
            },
        };
        self.meta_data.columns.swap_remove(index);
        Ok(())
    }

    /// Creates an engine for Table
    /// Returns Box<Engine>
    pub fn create_engine(self) -> Box<Engine + 'a> {
        Box::new(FlatFile::new(self))
    }

    /// Returns the path for the metadata files
    fn get_table_metadata_path(&self) -> String {
        Self::get_path(&self.database.name, &self.name, "tbl")
    }

    /// Returns the path for the data files
    fn get_table_data_path(&self) -> String {
        Self::get_path(&self.database.name, &self.name, "dat")
    }

    /// Returns the path of the table
    fn get_path(database: &str, name: &str, ext: &str) -> String {
         format!("{}/{}.{}", database, name, ext)
    }
}

//---------------------------------------------------------------
// Column
//---------------------------------------------------------------

/// A table column. Has a name, a type, ...
#[derive(Debug,RustcDecodable, RustcEncodable,Clone)]
pub struct Column {
    pub name: String, //name of column
    pub data_type: DataType, //name of the data type that is contained in this column
}

impl Default for Column {
    /// Returns a default Column construct
    fn default() -> Column {
        Column {
            name: "default".to_string(),
            data_type: DataType::Integer
        }
    }
}

impl Column {
    /// Creates a new column object
    /// Returns with Column
    pub fn create_new(name: &str, dtype: DataType) -> Column {
        Column {
            name: name.to_string(),
            data_type: dtype.clone()
        }
    }
}

//---------------------------------------------------------------
// Engine
//---------------------------------------------------------------

/// Storage Engine Interface.
///
/// A storage engine, like MyISAM and InnoDB, is responsible for reading and
/// writing data to disk, maintain and use indices, check for data corruption
/// and repair corrupt files.
///
/// Each table in a database may use a different storage engine.
pub trait Engine {
    fn create_table(&mut self) -> Result<(), DatabaseError>;
}

// # Some information for the `storage` working group:
//
// You work at the very bottom of the database: The thing that actually
// writes the data disk. Everything in this module is used only by the
// query execution module.
//
// The file layout may look like this:
// We have some `db_dir` where everything lives. In that directory, there are
// subdirectories for every database. In each of those subdirs is optionally
// a file `db.meta` that contains information about the database (such as
// permissions). The tables of each database are saved in *.tbl files that
// live inside the database directory.
//
// Your task is to provide types and method to:
// - read a specific table from a specific
//   database from file
// - create a new table in a database
// - query meta information about a table (columns for example)
// - lock a table for reading/writing it's data through a storage engine
//
// The other main task is to:
// - specify the storage engine interface
// - implement a simple storage engine (heap/flatfiles)
//
<|endoftext|>


<commit_before>//! Transaction related functionality.

use std::collections::{HashSet, hash_map};
use std::cmp::min;
use std::str::FromStr;
use bigint::{U256, H256, Address, Gas};

use super::errors::{RequireError, CommitError, PreExecutionError};
use super::{State, Machine, Context, ContextVM, VM, AccountState,
            BlockhashState, Patch, HeaderParams, Memory, VMStatus,
            AccountCommitment, Log, AccountChange, MachineStatus};
use block::{Transaction, TransactionAction};

const G_TXDATAZERO: usize = 4;
const G_TXDATANONZERO: usize = 68;
const G_TRANSACTION: usize = 21000;

macro_rules! system_address {
    () => {
        Address::from_str("0xffffffffffffffffffffffffffffffffffffffff").unwrap()
    }
}

/// ## About SYSTEM transaction
///
/// SYSTEM transaction in Ethereum is something that cannot be
/// executed by the user, and is enforced by the blockchain rules. The
/// SYSTEM transaction does not have a caller. When executed in EVM,
/// however, the CALLER opcode would return
/// 0xffffffffffffffffffffffffffffffffffffffff. As a result, when
/// executing a message call or a contract creation, nonce are not
/// changed. A SYSTEM transaction must have gas_price set to zero.

#[derive(Debug, Clone)]
/// Represents an Ethereum transaction.
pub struct ValidTransaction {
    /// Caller of this transaction. If caller is None, then this is a
    /// SYSTEM transaction.
    pub caller: Option<Address>,
    /// Gas price of this transaction.
    pub gas_price: Gas,
    /// Gas limit of this transaction.
    pub gas_limit: Gas,
    /// Transaction action.
    pub action: TransactionAction,
    /// Value of this transaction.
    pub value: U256,
    /// Data or init associated with this transaction.
    pub input: Vec<u8>,
    /// Nonce of the transaction.
    pub nonce: U256,
}

impl ValidTransaction {
    /// Create a valid transaction from a block transaction. Caller is
    /// always Some.
    pub fn from_transaction<P: Patch>(
        transaction: &Transaction, account_state: &AccountState
    ) -> Result<Result<ValidTransaction, PreExecutionError>, RequireError> {
        let caller = match transaction.caller() {
            Ok(val) => val,
            Err(_) => return Ok(Err(PreExecutionError::InvalidCaller)),
        };

        let nonce = account_state.nonce(caller)?;
        if nonce != transaction.nonce {
            return Ok(Err(PreExecutionError::InvalidNonce));
        }

        let valid = ValidTransaction {
            caller: Some(caller),
            gas_price: transaction.gas_price,
            gas_limit: transaction.gas_limit,
            action: transaction.action.clone(),
            value: transaction.value,
            input: transaction.input.clone(),
            nonce: nonce,
        };

        if valid.gas_limit < valid.intrinsic_gas::<P>() {
            return Ok(Err(PreExecutionError::InsufficientGasLimit));
        }

        let balance = account_state.balance(caller)?;
        if balance < valid.preclaimed_value() {
            return Ok(Err(PreExecutionError::InsufficientBalance));
        }

        Ok(Ok(valid))
    }
}

impl ValidTransaction {
    /// To address of the transaction.
    pub fn address(&self) -> Address {
        self.action.address(self.caller.unwrap_or(system_address!()), self.nonce)
    }

    /// Intrinsic gas to be paid in prior to this transaction
    /// execution.
    pub fn intrinsic_gas<P: Patch>(&self) -> Gas {
        let mut gas = Gas::from(G_TRANSACTION);
        if self.action == TransactionAction::Create {
            gas = gas + Gas::from(P::gas_transaction_create());
        }
        for d in &self.input {
            if *d == 0 {
                gas = gas + Gas::from(G_TXDATAZERO);
            } else {
                gas = gas + Gas::from(G_TXDATANONZERO);
            }
        }
        return gas;
    }

    /// Convert this transaction into a context. Note that this will
    /// change the account state.
    pub fn into_context(self, upfront: Gas, origin: Option<Address>,
                        account_state: &mut AccountState, is_code: bool) -> Result<Context, RequireError> {
        let address = self.address();

        match self.action {
            TransactionAction::Call(_) => {
                if self.caller.is_some() {
                    account_state.require(self.caller.unwrap())?;
                }
                account_state.require_code(address)?;

                if self.caller.is_some() && !is_code {
                    let nonce = self.nonce;
                    account_state.set_nonce(self.caller.unwrap(), nonce + U256::from(1u64)).unwrap();
                }

                Ok(Context {
                    address,
                    caller: self.caller.unwrap_or(system_address!()),
                    data: self.input,
                    gas_price: self.gas_price,
                    value: self.value,
                    gas_limit: self.gas_limit - upfront,
                    code: account_state.code(address).unwrap().into(),
                    origin: origin.unwrap_or(self.caller.unwrap_or(system_address!())),
                    apprent_value: self.value,
                    is_system: self.caller.is_none(),
                })
            },
            TransactionAction::Create => {
                if self.caller.is_some() {
                    account_state.require(self.caller.unwrap())?;
                    let nonce = self.nonce;
                    account_state.set_nonce(self.caller.unwrap(), nonce + U256::from(1u64)).unwrap();
                }

                Ok(Context {
                    address,
                    caller: self.caller.unwrap_or(system_address!()),
                    gas_price: self.gas_price,
                    value: self.value,
                    gas_limit: self.gas_limit - upfront,
                    data: Vec::new(),
                    code: self.input,
                    origin: origin.unwrap_or(self.caller.unwrap_or(system_address!())),
                    apprent_value: self.value,
                    is_system: self.caller.is_none(),
                })
            },
        }
    }

    /// When the execution of a transaction begins, this preclaimed
    /// value is deducted from the account.
    pub fn preclaimed_value(&self) -> U256 {
        (self.gas_limit * self.gas_price).into()
    }
}

enum TransactionVMState<M, P: Patch> {
    Running {
        vm: ContextVM<M, P>,
        intrinsic_gas: Gas,
        preclaimed_value: U256,
        finalized: bool,
        code_deposit: bool,
        fresh_account_state: AccountState,
    },
    Constructing {
        transaction: ValidTransaction,
        block: HeaderParams,

        account_state: AccountState,
        blockhash_state: BlockhashState,
    },
}

/// A VM that executes using a transaction and block information.
pub struct TransactionVM<M, P: Patch>(TransactionVMState<M, P>);

impl<M: Memory + Default, P: Patch> TransactionVM<M, P> {
    /// Create a new VM using the given transaction, block header and
    /// patch. This VM runs at the transaction level.
    pub fn new(transaction: ValidTransaction, block: HeaderParams) -> Self {
        TransactionVM(TransactionVMState::Constructing {
            transaction: transaction,
            block: block,

            account_state: AccountState::default(),
            blockhash_state: BlockhashState::default(),
        })
    }

    /// Create a new VM with the result of the previous VM. This is
    /// usually used by transaction for chaining them.
    pub fn with_previous(
        transaction: ValidTransaction, block: HeaderParams, vm: &TransactionVM<M, P>
    ) -> Self {
        TransactionVM(TransactionVMState::Constructing {
            transaction: transaction,
            block: block,

            account_state: match vm.0 {
                TransactionVMState::Constructing { ref account_state, .. } =>
                    account_state.clone(),
                TransactionVMState::Running { ref vm, .. } =>
                    vm.machines[0].state().account_state.clone(),
            },
            blockhash_state: match vm.0 {
                TransactionVMState::Constructing { ref blockhash_state, .. } =>
                    blockhash_state.clone(),
                TransactionVMState::Running { ref vm, .. } =>
                    vm.machines[0].state().blockhash_state.clone(),
            },
        })
    }

    /// Returns the real used gas by the transaction. This is what is
    /// recorded in the transaction receipt.
    pub fn real_used_gas(&self) -> Gas {
        match self.0 {
            TransactionVMState::Running { ref vm, intrinsic_gas, .. } => {
                match vm.machines[0].status() {
                    MachineStatus::ExitedErr(_) =>
                        vm.machines[0].state().context.gas_limit + intrinsic_gas,
                    MachineStatus::ExitedOk => {
                        let total_used = vm.machines[0].state().memory_gas() + vm.machines[0].state().used_gas + intrinsic_gas;
                        let refund_cap = total_used / Gas::from(2u64);
                        let refunded = min(refund_cap, vm.machines[0].state().refunded_gas);
                        total_used - refunded
                    }
                    _ => Gas::zero(),
                }
            }
            TransactionVMState::Constructing { .. } => Gas::zero(),
        }
    }

    /// Returns the current state of the VM.
    pub fn current_state(&self) -> Option<&State<M>> {
        self.current_machine().map(|m| m.state())
    }

    /// Returns the current runtime machine.
    pub fn current_machine(&self) -> Option<&Machine<M, P>> {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => {
                Some(vm.current_machine())
            }
            TransactionVMState::Constructing { .. } => None,
        }
    }
}

impl<M: Memory + Default, P: Patch> VM for TransactionVM<M, P> {
    fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        match self.0 {
            TransactionVMState::Running { ref mut vm, .. } => vm.commit_account(commitment),
            TransactionVMState::Constructing { ref mut account_state, .. } => account_state.commit(commitment),
        }
    }

    fn commit_blockhash(&mut self, number: U256, hash: H256) -> Result<(), CommitError> {
        match self.0 {
            TransactionVMState::Running { ref mut vm, .. } => vm.commit_blockhash(number, hash),
            TransactionVMState::Constructing { ref mut blockhash_state, .. } => blockhash_state.commit(number, hash),
        }
    }

    fn status(&self) -> VMStatus {
        match self.0 {
            TransactionVMState::Running { ref vm, finalized, .. } => {
                if !finalized {
                    VMStatus::Running
                } else {
                    vm.status()
                }
            },
            TransactionVMState::Constructing { .. } => VMStatus::Running,
        }
    }

    fn step(&mut self) -> Result<(), RequireError> {
        let cgas: Gas;
        let ccontext: Context;
        let cblock: HeaderParams;
        let caccount_state: AccountState;
        let cblockhash_state: BlockhashState;
        let ccode_deposit: bool;
        let cpreclaimed_value: U256;

        let real_used_gas = self.real_used_gas();

        match self.0 {
            TransactionVMState::Running {
                ref mut vm,
                ref mut finalized,
                ref mut code_deposit,
                ref fresh_account_state,
                preclaimed_value,
                ..
            } => {
                match vm.status() {
                    VMStatus::Running => {
                        return vm.step();
                    },
                    VMStatus::ExitedNotSupported(_) => {
                        return Ok(());
                    },
                    _ => {
                        if *code_deposit {
                            vm.machines[0].code_deposit();
                            *code_deposit = false;
                            return Ok(());
                        }

                        if !*finalized {
                            vm.machines[0].finalize(real_used_gas, preclaimed_value,
                                                    fresh_account_state)?;
                            *finalized = true;
                            return Ok(());
                        }

                        return vm.step();
                    },
                }
            }
            TransactionVMState::Constructing {
                ref transaction, ref block,
                ref mut account_state, ref blockhash_state } => {

                let address = transaction.address();
                account_state.require(address)?;

                ccode_deposit = match transaction.action {
                    TransactionAction::Call(_) => false,
                    TransactionAction::Create => true,
                };
                cgas = transaction.intrinsic_gas::<P>();
                cpreclaimed_value = transaction.preclaimed_value();
                ccontext = transaction.clone().into_context(cgas, None, account_state, false)?;
                cblock = block.clone();
                caccount_state = account_state.clone();
                cblockhash_state = blockhash_state.clone();
            }
        }

        let account_state = caccount_state;
        let mut vm = ContextVM::with_states(ccontext, cblock,
                                            account_state.clone(),
                                            cblockhash_state);

        if ccode_deposit {
            vm.machines[0].initialize_create(cpreclaimed_value).unwrap();
        } else {
            vm.machines[0].initialize_call(cpreclaimed_value);
        }

        self.0 = TransactionVMState::Running {
            fresh_account_state: account_state,
            vm,
            intrinsic_gas: cgas,
            finalized: false,
            code_deposit: ccode_deposit,
            preclaimed_value: cpreclaimed_value,
        };

        Ok(())
    }

    fn accounts(&self) -> hash_map::Values<Address, AccountChange> {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.accounts(),
            TransactionVMState::Constructing { ref account_state, .. } => account_state.accounts(),
        }
    }

    fn used_addresses(&self) -> HashSet<Address> {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.used_addresses(),
            TransactionVMState::Constructing { ref account_state, .. } => account_state.used_addresses(),
        }
    }

    fn out(&self) -> &[u8] {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.out(),
            TransactionVMState::Constructing { .. } => &[],
        }
    }

    fn available_gas(&self) -> Gas {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.available_gas(),
            TransactionVMState::Constructing { ref transaction, .. } => transaction.gas_limit,
        }
    }

    fn refunded_gas(&self) -> Gas {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.refunded_gas(),
            TransactionVMState::Constructing { .. } => Gas::zero(),
        }
    }

    fn logs(&self) -> &[Log] {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.logs(),
            TransactionVMState::Constructing { .. } => &[],
        }
    }

    fn removed(&self) -> &[Address] {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.removed(),
            TransactionVMState::Constructing { .. } => &[],
        }
    }
}

#[cfg(test)]
mod tests {
    use ::*;
    use bigint::*;
    use block::TransactionAction;
    use std::str::FromStr;

    #[test]
    fn system_transaction() {
        let transaction = ValidTransaction {
            caller: None,
            gas_price: Gas::zero(),
            gas_limit: Gas::from_str("0xffffffffffffffff").unwrap(),
            action: TransactionAction::Call(Address::default()),
            value: U256::from_str("0xffffffffffffffff").unwrap(),
            input: Vec::new(),
            nonce: U256::zero(),
        };
        let mut vm = SeqTransactionVM::<EIP160Patch>::new(transaction, HeaderParams {
            beneficiary: Address::default(),
            timestamp: 0,
            number: U256::zero(),
            difficulty: U256::zero(),
            gas_limit: Gas::zero(),
        });
        vm.commit_account(AccountCommitment::Nonexist(Address::default())).unwrap();
        vm.fire().unwrap();

        let mut accounts: Vec<AccountChange> = Vec::new();
        for account in vm.accounts() {
            accounts.push(account.clone());
        }
        assert_eq!(accounts.len(), 1);
        match accounts[0] {
            AccountChange::Create {
                address, exists, balance, ..
            } => {
                assert_eq!(address, Address::default());
                assert_eq!(exists, true);
                assert_eq!(balance, U256::from_str("0xffffffffffffffff").unwrap());
            },
            _ => panic!()
        }
    }
}
<commit_msg>Fix a bug that valid transaction can still cause VM to panic<commit_after>//! Transaction related functionality.

use std::collections::{HashSet, hash_map};
use std::cmp::min;
use std::str::FromStr;
use bigint::{U256, H256, Address, Gas};

use super::errors::{RequireError, CommitError, PreExecutionError};
use super::{State, Machine, Context, ContextVM, VM, AccountState,
            BlockhashState, Patch, HeaderParams, Memory, VMStatus,
            AccountCommitment, Log, AccountChange, MachineStatus};
use block::{Transaction, TransactionAction};

const G_TXDATAZERO: usize = 4;
const G_TXDATANONZERO: usize = 68;
const G_TRANSACTION: usize = 21000;

macro_rules! system_address {
    () => {
        Address::from_str("0xffffffffffffffffffffffffffffffffffffffff").unwrap()
    }
}

/// ## About SYSTEM transaction
///
/// SYSTEM transaction in Ethereum is something that cannot be
/// executed by the user, and is enforced by the blockchain rules. The
/// SYSTEM transaction does not have a caller. When executed in EVM,
/// however, the CALLER opcode would return
/// 0xffffffffffffffffffffffffffffffffffffffff. As a result, when
/// executing a message call or a contract creation, nonce are not
/// changed. A SYSTEM transaction must have gas_price set to zero.

#[derive(Debug, Clone)]
/// Represents an Ethereum transaction.
pub struct ValidTransaction {
    /// Caller of this transaction. If caller is None, then this is a
    /// SYSTEM transaction.
    pub caller: Option<Address>,
    /// Gas price of this transaction.
    pub gas_price: Gas,
    /// Gas limit of this transaction.
    pub gas_limit: Gas,
    /// Transaction action.
    pub action: TransactionAction,
    /// Value of this transaction.
    pub value: U256,
    /// Data or init associated with this transaction.
    pub input: Vec<u8>,
    /// Nonce of the transaction.
    pub nonce: U256,
}

impl ValidTransaction {
    /// Create a valid transaction from a block transaction. Caller is
    /// always Some.
    pub fn from_transaction<P: Patch>(
        transaction: &Transaction, account_state: &AccountState
    ) -> Result<Result<ValidTransaction, PreExecutionError>, RequireError> {
        let caller = match transaction.caller() {
            Ok(val) => val,
            Err(_) => return Ok(Err(PreExecutionError::InvalidCaller)),
        };

        let nonce = account_state.nonce(caller)?;
        if nonce != transaction.nonce {
            return Ok(Err(PreExecutionError::InvalidNonce));
        }

        let valid = ValidTransaction {
            caller: Some(caller),
            gas_price: transaction.gas_price,
            gas_limit: transaction.gas_limit,
            action: transaction.action.clone(),
            value: transaction.value,
            input: transaction.input.clone(),
            nonce: nonce,
        };

        if valid.gas_limit < valid.intrinsic_gas::<P>() {
            return Ok(Err(PreExecutionError::InsufficientGasLimit));
        }

        let balance = account_state.balance(caller)?;
        if balance < valid.preclaimed_value() + valid.value {
            return Ok(Err(PreExecutionError::InsufficientBalance));
        }

        Ok(Ok(valid))
    }
}

impl ValidTransaction {
    /// To address of the transaction.
    pub fn address(&self) -> Address {
        self.action.address(self.caller.unwrap_or(system_address!()), self.nonce)
    }

    /// Intrinsic gas to be paid in prior to this transaction
    /// execution.
    pub fn intrinsic_gas<P: Patch>(&self) -> Gas {
        let mut gas = Gas::from(G_TRANSACTION);
        if self.action == TransactionAction::Create {
            gas = gas + Gas::from(P::gas_transaction_create());
        }
        for d in &self.input {
            if *d == 0 {
                gas = gas + Gas::from(G_TXDATAZERO);
            } else {
                gas = gas + Gas::from(G_TXDATANONZERO);
            }
        }
        return gas;
    }

    /// Convert this transaction into a context. Note that this will
    /// change the account state.
    pub fn into_context(self, upfront: Gas, origin: Option<Address>,
                        account_state: &mut AccountState, is_code: bool) -> Result<Context, RequireError> {
        let address = self.address();

        match self.action {
            TransactionAction::Call(_) => {
                if self.caller.is_some() {
                    account_state.require(self.caller.unwrap())?;
                }
                account_state.require_code(address)?;

                if self.caller.is_some() && !is_code {
                    let nonce = self.nonce;
                    account_state.set_nonce(self.caller.unwrap(), nonce + U256::from(1u64)).unwrap();
                }

                Ok(Context {
                    address,
                    caller: self.caller.unwrap_or(system_address!()),
                    data: self.input,
                    gas_price: self.gas_price,
                    value: self.value,
                    gas_limit: self.gas_limit - upfront,
                    code: account_state.code(address).unwrap().into(),
                    origin: origin.unwrap_or(self.caller.unwrap_or(system_address!())),
                    apprent_value: self.value,
                    is_system: self.caller.is_none(),
                })
            },
            TransactionAction::Create => {
                if self.caller.is_some() {
                    account_state.require(self.caller.unwrap())?;
                    let nonce = self.nonce;
                    account_state.set_nonce(self.caller.unwrap(), nonce + U256::from(1u64)).unwrap();
                }

                Ok(Context {
                    address,
                    caller: self.caller.unwrap_or(system_address!()),
                    gas_price: self.gas_price,
                    value: self.value,
                    gas_limit: self.gas_limit - upfront,
                    data: Vec::new(),
                    code: self.input,
                    origin: origin.unwrap_or(self.caller.unwrap_or(system_address!())),
                    apprent_value: self.value,
                    is_system: self.caller.is_none(),
                })
            },
        }
    }

    /// When the execution of a transaction begins, this preclaimed
    /// value is deducted from the account.
    pub fn preclaimed_value(&self) -> U256 {
        (self.gas_limit * self.gas_price).into()
    }
}

enum TransactionVMState<M, P: Patch> {
    Running {
        vm: ContextVM<M, P>,
        intrinsic_gas: Gas,
        preclaimed_value: U256,
        finalized: bool,
        code_deposit: bool,
        fresh_account_state: AccountState,
    },
    Constructing {
        transaction: ValidTransaction,
        block: HeaderParams,

        account_state: AccountState,
        blockhash_state: BlockhashState,
    },
}

/// A VM that executes using a transaction and block information.
pub struct TransactionVM<M, P: Patch>(TransactionVMState<M, P>);

impl<M: Memory + Default, P: Patch> TransactionVM<M, P> {
    /// Create a new VM using the given transaction, block header and
    /// patch. This VM runs at the transaction level.
    pub fn new(transaction: ValidTransaction, block: HeaderParams) -> Self {
        TransactionVM(TransactionVMState::Constructing {
            transaction: transaction,
            block: block,

            account_state: AccountState::default(),
            blockhash_state: BlockhashState::default(),
        })
    }

    /// Create a new VM with the result of the previous VM. This is
    /// usually used by transaction for chaining them.
    pub fn with_previous(
        transaction: ValidTransaction, block: HeaderParams, vm: &TransactionVM<M, P>
    ) -> Self {
        TransactionVM(TransactionVMState::Constructing {
            transaction: transaction,
            block: block,

            account_state: match vm.0 {
                TransactionVMState::Constructing { ref account_state, .. } =>
                    account_state.clone(),
                TransactionVMState::Running { ref vm, .. } =>
                    vm.machines[0].state().account_state.clone(),
            },
            blockhash_state: match vm.0 {
                TransactionVMState::Constructing { ref blockhash_state, .. } =>
                    blockhash_state.clone(),
                TransactionVMState::Running { ref vm, .. } =>
                    vm.machines[0].state().blockhash_state.clone(),
            },
        })
    }

    /// Returns the real used gas by the transaction. This is what is
    /// recorded in the transaction receipt.
    pub fn real_used_gas(&self) -> Gas {
        match self.0 {
            TransactionVMState::Running { ref vm, intrinsic_gas, .. } => {
                match vm.machines[0].status() {
                    MachineStatus::ExitedErr(_) =>
                        vm.machines[0].state().context.gas_limit + intrinsic_gas,
                    MachineStatus::ExitedOk => {
                        let total_used = vm.machines[0].state().memory_gas() + vm.machines[0].state().used_gas + intrinsic_gas;
                        let refund_cap = total_used / Gas::from(2u64);
                        let refunded = min(refund_cap, vm.machines[0].state().refunded_gas);
                        total_used - refunded
                    }
                    _ => Gas::zero(),
                }
            }
            TransactionVMState::Constructing { .. } => Gas::zero(),
        }
    }

    /// Returns the current state of the VM.
    pub fn current_state(&self) -> Option<&State<M>> {
        self.current_machine().map(|m| m.state())
    }

    /// Returns the current runtime machine.
    pub fn current_machine(&self) -> Option<&Machine<M, P>> {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => {
                Some(vm.current_machine())
            }
            TransactionVMState::Constructing { .. } => None,
        }
    }
}

impl<M: Memory + Default, P: Patch> VM for TransactionVM<M, P> {
    fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        match self.0 {
            TransactionVMState::Running { ref mut vm, .. } => vm.commit_account(commitment),
            TransactionVMState::Constructing { ref mut account_state, .. } => account_state.commit(commitment),
        }
    }

    fn commit_blockhash(&mut self, number: U256, hash: H256) -> Result<(), CommitError> {
        match self.0 {
            TransactionVMState::Running { ref mut vm, .. } => vm.commit_blockhash(number, hash),
            TransactionVMState::Constructing { ref mut blockhash_state, .. } => blockhash_state.commit(number, hash),
        }
    }

    fn status(&self) -> VMStatus {
        match self.0 {
            TransactionVMState::Running { ref vm, finalized, .. } => {
                if !finalized {
                    VMStatus::Running
                } else {
                    vm.status()
                }
            },
            TransactionVMState::Constructing { .. } => VMStatus::Running,
        }
    }

    fn step(&mut self) -> Result<(), RequireError> {
        let cgas: Gas;
        let ccontext: Context;
        let cblock: HeaderParams;
        let caccount_state: AccountState;
        let cblockhash_state: BlockhashState;
        let ccode_deposit: bool;
        let cpreclaimed_value: U256;

        let real_used_gas = self.real_used_gas();

        match self.0 {
            TransactionVMState::Running {
                ref mut vm,
                ref mut finalized,
                ref mut code_deposit,
                ref fresh_account_state,
                preclaimed_value,
                ..
            } => {
                match vm.status() {
                    VMStatus::Running => {
                        return vm.step();
                    },
                    VMStatus::ExitedNotSupported(_) => {
                        return Ok(());
                    },
                    _ => {
                        if *code_deposit {
                            vm.machines[0].code_deposit();
                            *code_deposit = false;
                            return Ok(());
                        }

                        if !*finalized {
                            vm.machines[0].finalize(real_used_gas, preclaimed_value,
                                                    fresh_account_state)?;
                            *finalized = true;
                            return Ok(());
                        }

                        return vm.step();
                    },
                }
            }
            TransactionVMState::Constructing {
                ref transaction, ref block,
                ref mut account_state, ref blockhash_state } => {

                let address = transaction.address();
                account_state.require(address)?;

                ccode_deposit = match transaction.action {
                    TransactionAction::Call(_) => false,
                    TransactionAction::Create => true,
                };
                cgas = transaction.intrinsic_gas::<P>();
                cpreclaimed_value = transaction.preclaimed_value();
                ccontext = transaction.clone().into_context(cgas, None, account_state, false)?;
                cblock = block.clone();
                caccount_state = account_state.clone();
                cblockhash_state = blockhash_state.clone();
            }
        }

        let account_state = caccount_state;
        let mut vm = ContextVM::with_states(ccontext, cblock,
                                            account_state.clone(),
                                            cblockhash_state);

        if ccode_deposit {
            vm.machines[0].initialize_create(cpreclaimed_value).unwrap();
        } else {
            vm.machines[0].initialize_call(cpreclaimed_value);
        }

        self.0 = TransactionVMState::Running {
            fresh_account_state: account_state,
            vm,
            intrinsic_gas: cgas,
            finalized: false,
            code_deposit: ccode_deposit,
            preclaimed_value: cpreclaimed_value,
        };

        Ok(())
    }

    fn accounts(&self) -> hash_map::Values<Address, AccountChange> {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.accounts(),
            TransactionVMState::Constructing { ref account_state, .. } => account_state.accounts(),
        }
    }

    fn used_addresses(&self) -> HashSet<Address> {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.used_addresses(),
            TransactionVMState::Constructing { ref account_state, .. } => account_state.used_addresses(),
        }
    }

    fn out(&self) -> &[u8] {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.out(),
            TransactionVMState::Constructing { .. } => &[],
        }
    }

    fn available_gas(&self) -> Gas {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.available_gas(),
            TransactionVMState::Constructing { ref transaction, .. } => transaction.gas_limit,
        }
    }

    fn refunded_gas(&self) -> Gas {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.refunded_gas(),
            TransactionVMState::Constructing { .. } => Gas::zero(),
        }
    }

    fn logs(&self) -> &[Log] {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.logs(),
            TransactionVMState::Constructing { .. } => &[],
        }
    }

    fn removed(&self) -> &[Address] {
        match self.0 {
            TransactionVMState::Running { ref vm, .. } => vm.removed(),
            TransactionVMState::Constructing { .. } => &[],
        }
    }
}

#[cfg(test)]
mod tests {
    use ::*;
    use bigint::*;
    use block::TransactionAction;
    use std::str::FromStr;

    #[test]
    fn system_transaction() {
        let transaction = ValidTransaction {
            caller: None,
            gas_price: Gas::zero(),
            gas_limit: Gas::from_str("0xffffffffffffffff").unwrap(),
            action: TransactionAction::Call(Address::default()),
            value: U256::from_str("0xffffffffffffffff").unwrap(),
            input: Vec::new(),
            nonce: U256::zero(),
        };
        let mut vm = SeqTransactionVM::<EIP160Patch>::new(transaction, HeaderParams {
            beneficiary: Address::default(),
            timestamp: 0,
            number: U256::zero(),
            difficulty: U256::zero(),
            gas_limit: Gas::zero(),
        });
        vm.commit_account(AccountCommitment::Nonexist(Address::default())).unwrap();
        vm.fire().unwrap();

        let mut accounts: Vec<AccountChange> = Vec::new();
        for account in vm.accounts() {
            accounts.push(account.clone());
        }
        assert_eq!(accounts.len(), 1);
        match accounts[0] {
            AccountChange::Create {
                address, exists, balance, ..
            } => {
                assert_eq!(address, Address::default());
                assert_eq!(exists, true);
                assert_eq!(balance, U256::from_str("0xffffffffffffffff").unwrap());
            },
            _ => panic!()
        }
    }
}
<|endoftext|>


<commit_before>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: gl/ttf/font.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      TrueType font atlas.
*/

use std::{ str, vec, cmp, ptr };
use std::hashmap::HashMap;
use std::libc::{ c_uint };
use std::iterator::IteratorUtil;
use math;
use self::glyph::Glyph;
use gl2 = opengles::gl2;

#[path = "../../gl/check.rs"]
mod check;

mod glyph;
mod ft;

struct Font
{
  file: ~str,
  library: ft::Library,
  face: ft::Face,
  texture_atlas: gl2::GLuint,
  atlas_dimensions: math::Vec2i,
  glyphs: HashMap<u8, Glyph>,
  height: i32,
}

impl Font
{
  pub fn new(filename: &str, size: i32) -> Font
  {
    let mut font = Font
    {
      file: filename.to_owned(),
      library: ptr::null(),
      face: ptr::null(),
      texture_atlas: 0,
      atlas_dimensions: math::Vec2i::zero(),
      glyphs: HashMap::new::<u8, Glyph>(),
      height: 0,
    };

    unsafe
    {
      ft::FT_Init_FreeType(&font.library);

      do str::as_c_str(filename) |c_str|
      {
        if ft::FT_New_Face(font.library, c_str, 0, &font.face) != 0
        { fail!(~"Failed to create TTF face."); }
      }

      ft::FT_Set_Pixel_Sizes(font.face, 0, size as c_uint);
      check!(gl2::active_texture(gl2::TEXTURE0));

      let ft_glyph = (*font.face).glyph;
      let max_width = 1024;
      let mut row_width = 0;
      let mut row_height = 0;

      let chars = &" !\"#$%&'`()*+,-_./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^abcdefghijklmnopqrstuvwxyz{|}~";

      for chars.iter().advance |curr|
      {
        if ft::FT_Load_Char(font.face, curr as u32, ft::LOAD_RENDER) != 0
        { loop; }

        /* If we've exhausted the width for this row, add another. */
        if row_width + (*ft_glyph).bitmap.width + 1 >= max_width
        {
          font.atlas_dimensions.x = cmp::max(font.atlas_dimensions.x, row_width);
          font.atlas_dimensions.y += row_height;
          row_width = 0; row_height = 0;
        }

        let mut glyph = Glyph::new();
        glyph.advance.x = ((*ft_glyph).advance.x >> 6) as f32;
        glyph.advance.y = ((*ft_glyph).advance.y >> 6) as f32;
        glyph.dimensions.x = (*ft_glyph).bitmap.width as f32;
        glyph.dimensions.y = (*ft_glyph).bitmap.rows as f32;
        glyph.offset.x = (*ft_glyph).bitmap_left as f32;
        glyph.offset.y = (*ft_glyph).bitmap_top as f32;
        glyph.buffer = vec::from_buf( (*ft_glyph).bitmap.buffer,
                                      (glyph.dimensions.x * glyph.dimensions.y) as uint);

        row_width += (glyph.dimensions.x + 1.0) as i32;
        row_height = cmp::max(row_height, (*ft_glyph).bitmap.rows);
        font.height = cmp::max(font.height, row_height);

        font.glyphs.insert(curr as u8, glyph);
      }

      font.atlas_dimensions.x = math::next_power_of_2(cmp::max(font.atlas_dimensions.x, row_width));
      font.atlas_dimensions.y = math::next_power_of_2(font.atlas_dimensions.y + row_height);

      /* We're using 1 byte alignment buffering. */
      check!(gl2::pixel_store_i(gl2::UNPACK_ALIGNMENT, 1));

      let name = check!(gl2::gen_textures(1));
      assert!(name.len() == 1);
      font.texture_atlas = name[0];
      check!(gl2::bind_texture(gl2::TEXTURE_2D, font.texture_atlas));
      check!(gl2::tex_image_2d(gl2::TEXTURE_2D, 0, gl2::RGB as gl2::GLint,
                              font.atlas_dimensions.x, font.atlas_dimensions.y,
                              0, gl2::RED, gl2::UNSIGNED_BYTE, None));

      /* Clamp to the edge to avoid artifacts when scaling. */
      check!(gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_WRAP_S, gl2::CLAMP_TO_EDGE as i32));
      check!(gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_WRAP_T, gl2::CLAMP_TO_EDGE as i32));

      /* Linear filtering usually looks best for text. */
      check!(gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_MIN_FILTER, gl2::LINEAR as i32));
      check!(gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_MAG_FILTER, gl2::LINEAR as i32));

      /* Copy all glyphs into the texture atlas. */
      let mut offset = math::Vec2i::zero();
      row_height = 0;
      for chars.iter().advance |curr|
      {
        let glyph = match font.glyphs.find_mut(&(curr as u8))
        {
          Some(g) => g,
          None => fail!(fmt!("Invalid char (%?) in font %?", curr, filename))
        };

        if offset.x + (glyph.dimensions.x as i32) + 1 >= max_width
        {
          offset.y += row_height;
          row_height = 0; offset.x = 0;
        }

        { /* temp has a short scope. */
          let temp: &[u8] = glyph.buffer;
          check!(gl2::tex_sub_image_2d(
                      gl2::TEXTURE_2D, 0, offset.x, offset.y,
                      glyph.dimensions.x as i32, glyph.dimensions.y as i32,
                      gl2::RED, gl2::UNSIGNED_BYTE, Some(temp)));
        }

        /* Calculate the position in the texture. */
        glyph.tex.x = (offset.x as f32 / (font.atlas_dimensions.x as f32));
        glyph.tex.y = (offset.y as f32 / (font.atlas_dimensions.y as f32));

        offset.x += glyph.dimensions.x as i32;
        row_height = cmp::max(row_height, glyph.dimensions.y as i32);
      }
    }

    /* Reset the state. */
    check!(gl2::pixel_store_i(gl2::UNPACK_ALIGNMENT, 4));

    assert!(font.height > 0);

    font
  }
}

impl Drop for Font
{
  fn drop(&self)
  {
    unsafe
    { ft::FT_Done_FreeType(self.library); }
  }
}

<commit_msg>(lang) as_c_str becomes a method (lang update)<commit_after>/*
    Copyright 2013 Jesse 'Jeaye' Wilkerson
    See licensing in LICENSE file, or at:
        http://www.opensource.org/licenses/BSD-3-Clause

    File: gl/ttf/font.rs
    Author: Jesse 'Jeaye' Wilkerson
    Description:
      TrueType font atlas.
*/

use std::{ vec, cmp, ptr };
use std::hashmap::HashMap;
use std::libc::{ c_uint };
use std::iterator::IteratorUtil;
use math;
use self::glyph::Glyph;
use gl2 = opengles::gl2;

#[path = "../../gl/check.rs"]
mod check;

mod glyph;
mod ft;

struct Font
{
  file: ~str,
  library: ft::Library,
  face: ft::Face,
  texture_atlas: gl2::GLuint,
  atlas_dimensions: math::Vec2i,
  glyphs: HashMap<u8, Glyph>,
  height: i32,
}

impl Font
{
  pub fn new(filename: &str, size: i32) -> Font
  {
    let mut font = Font
    {
      file: filename.to_owned(),
      library: ptr::null(),
      face: ptr::null(),
      texture_atlas: 0,
      atlas_dimensions: math::Vec2i::zero(),
      glyphs: HashMap::new::<u8, Glyph>(),
      height: 0,
    };

    unsafe
    {
      ft::FT_Init_FreeType(&font.library);

      do filename.as_c_str() |c_str|
      {
        if ft::FT_New_Face(font.library, c_str, 0, &font.face) != 0
        { fail!(~"Failed to create TTF face."); }
      }

      ft::FT_Set_Pixel_Sizes(font.face, 0, size as c_uint);
      check!(gl2::active_texture(gl2::TEXTURE0));

      let ft_glyph = (*font.face).glyph;
      let max_width = 1024;
      let mut row_width = 0;
      let mut row_height = 0;

      let chars = &" !\"#$%&'`()*+,-_./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^abcdefghijklmnopqrstuvwxyz{|}~";

      for chars.iter().advance |curr|
      {
        if ft::FT_Load_Char(font.face, curr as u32, ft::LOAD_RENDER) != 0
        { loop; }

        /* If we've exhausted the width for this row, add another. */
        if row_width + (*ft_glyph).bitmap.width + 1 >= max_width
        {
          font.atlas_dimensions.x = cmp::max(font.atlas_dimensions.x, row_width);
          font.atlas_dimensions.y += row_height;
          row_width = 0; row_height = 0;
        }

        let mut glyph = Glyph::new();
        glyph.advance.x = ((*ft_glyph).advance.x >> 6) as f32;
        glyph.advance.y = ((*ft_glyph).advance.y >> 6) as f32;
        glyph.dimensions.x = (*ft_glyph).bitmap.width as f32;
        glyph.dimensions.y = (*ft_glyph).bitmap.rows as f32;
        glyph.offset.x = (*ft_glyph).bitmap_left as f32;
        glyph.offset.y = (*ft_glyph).bitmap_top as f32;
        glyph.buffer = vec::from_buf( (*ft_glyph).bitmap.buffer,
                                      (glyph.dimensions.x * glyph.dimensions.y) as uint);

        row_width += (glyph.dimensions.x + 1.0) as i32;
        row_height = cmp::max(row_height, (*ft_glyph).bitmap.rows);
        font.height = cmp::max(font.height, row_height);

        font.glyphs.insert(curr as u8, glyph);
      }

      font.atlas_dimensions.x = math::next_power_of_2(cmp::max(font.atlas_dimensions.x, row_width));
      font.atlas_dimensions.y = math::next_power_of_2(font.atlas_dimensions.y + row_height);

      /* We're using 1 byte alignment buffering. */
      check!(gl2::pixel_store_i(gl2::UNPACK_ALIGNMENT, 1));

      let name = check!(gl2::gen_textures(1));
      assert!(name.len() == 1);
      font.texture_atlas = name[0];
      check!(gl2::bind_texture(gl2::TEXTURE_2D, font.texture_atlas));
      check!(gl2::tex_image_2d(gl2::TEXTURE_2D, 0, gl2::RGB as gl2::GLint,
                              font.atlas_dimensions.x, font.atlas_dimensions.y,
                              0, gl2::RED, gl2::UNSIGNED_BYTE, None));

      /* Clamp to the edge to avoid artifacts when scaling. */
      check!(gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_WRAP_S, gl2::CLAMP_TO_EDGE as i32));
      check!(gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_WRAP_T, gl2::CLAMP_TO_EDGE as i32));

      /* Linear filtering usually looks best for text. */
      check!(gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_MIN_FILTER, gl2::LINEAR as i32));
      check!(gl2::tex_parameter_i(gl2::TEXTURE_2D, gl2::TEXTURE_MAG_FILTER, gl2::LINEAR as i32));

      /* Copy all glyphs into the texture atlas. */
      let mut offset = math::Vec2i::zero();
      row_height = 0;
      for chars.iter().advance |curr|
      {
        let glyph = match font.glyphs.find_mut(&(curr as u8))
        {
          Some(g) => g,
          None => fail!(fmt!("Invalid char (%?) in font %?", curr, filename))
        };

        if offset.x + (glyph.dimensions.x as i32) + 1 >= max_width
        {
          offset.y += row_height;
          row_height = 0; offset.x = 0;
        }

        { /* temp has a short scope. */
          let temp: &[u8] = glyph.buffer;
          check!(gl2::tex_sub_image_2d(
                      gl2::TEXTURE_2D, 0, offset.x, offset.y,
                      glyph.dimensions.x as i32, glyph.dimensions.y as i32,
                      gl2::RED, gl2::UNSIGNED_BYTE, Some(temp)));
        }

        /* Calculate the position in the texture. */
        glyph.tex.x = (offset.x as f32 / (font.atlas_dimensions.x as f32));
        glyph.tex.y = (offset.y as f32 / (font.atlas_dimensions.y as f32));

        offset.x += glyph.dimensions.x as i32;
        row_height = cmp::max(row_height, glyph.dimensions.y as i32);
      }
    }

    /* Reset the state. */
    check!(gl2::pixel_store_i(gl2::UNPACK_ALIGNMENT, 4));

    assert!(font.height > 0);

    font
  }
}

impl Drop for Font
{
  fn drop(&self)
  {
    unsafe
    { ft::FT_Done_FreeType(self.library); }
  }
}

<|endoftext|>


<commit_before>#![macro_use]

#[macro_export]
macro_rules! cond{
  (orelse => $default:block) => ($default);
  ($pred:expr => $body:block , $($tail:tt)*) => (if $pred $body else { cond!($($tail)*) })
}

#[macro_export]
macro_rules! withDefault{
  ($default, $expr)  => (match $expr { Ok(val) => val; Err(e) => $default})
}

#[macro_export]
macro_rules! bindMaybe{
    ($left:expr, $right:stmt) => ( match $left
                           { Ok(val) => $right(val)
                           ; Err(e)  => Err(e)
                           }
                       )
}

#[macro_export]
macro_rules! mdo{
  ($x:ident <- $y:expr ; $($tail:tt)*) => ( bindMaybe!($y, |$x|   mdo!($($tail)*)));
  ($y:block ; $($tail:tt)*)          => ( { $y; mdo!($($tail)*) });
  ($y:expr )                        => ( Ok($y));
}

<commit_msg>Fixed spacing<commit_after>#![macro_use]

#[macro_export]
macro_rules! cond{
  (orelse => $default:block) => ($default);
  ($pred:expr => $body:block , $($tail:tt)*) => (if $pred $body else { cond!($($tail)*) })
}

#[macro_export]
macro_rules! withDefault{
  ($default, $expr)  => (match $expr { Ok(val) => val; Err(e) => $default})
}

#[macro_export]
macro_rules! bindMaybe{
    ($left:expr, $right:stmt) => (match $left { Ok(val) => $right(val) ; Err(e)  => Err(e) })
}

#[macro_export]
macro_rules! mdo{
  ($x:ident <- $y:expr ; $($tail:tt)*) => ( bindMaybe!($y, |$x|   mdo!($($tail)*)));
  ($y:block ; $($tail:tt)*)            => ( { $y; mdo!($($tail)*) });
  ($y:expr )                           => ( Ok($y));
}

<|endoftext|>


<commit_before>use crate::config::Config;
use crate::cpp_checker::cpp_checker_step;
use crate::cpp_explicit_xstructors::add_explicit_xstructors_step;
use crate::cpp_ffi_generator::cpp_ffi_generator_step;
use crate::cpp_parser::cpp_parser_step;
use crate::cpp_template_instantiator::find_template_instantiations_step;
use crate::cpp_template_instantiator::instantiate_templates_step;
use crate::crate_writer::crate_writer_step;
use crate::database::{CppDatabaseItem, Database};
use crate::rust_generator::clear_rust_info_step;
use crate::rust_generator::rust_generator_step;
use crate::type_allocation_places::choose_allocation_places_step;
use crate::workspace::Workspace;
use itertools::Itertools;
use log::{error, info};
use ritual_common::errors::{bail, err_msg, Result, ResultExt};
use ritual_common::utils::MapIfOk;
use std::cmp::Ordering;
use std::fmt;
use std::iter::once;
use std::path::PathBuf;

/// Creates output and cache directories if they don't exist.
/// Returns `Err` if any path in `config` is invalid or relative.
fn check_all_paths(config: &Config) -> Result<()> {
    let check_dir = |path: &PathBuf| -> Result<()> {
        if !path.is_absolute() {
            bail!(
                "Only absolute paths allowed. Relative path: {}",
                path.display()
            );
        }
        if !path.exists() {
            bail!("Directory doesn't exist: {}", path.display());
        }
        if !path.is_dir() {
            bail!("Path is not a directory: {}", path.display());
        }
        Ok(())
    };

    if let Some(path) = config.crate_template_path() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().include_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().lib_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().framework_paths() {
        check_dir(path)?;
    }
    for path in config.target_include_paths() {
        check_dir(path)?;
    }
    Ok(())
}

pub struct ProcessorData<'a> {
    pub workspace: &'a mut Workspace,
    pub config: &'a Config,
    pub current_database: &'a mut Database,
    pub dep_databases: &'a [Database],
}

impl<'a> ProcessorData<'a> {
    pub fn all_databases(&self) -> Vec<&Database> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .collect()
    }
    pub fn all_items(&self) -> Vec<&CppDatabaseItem> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .flat_map(|d| d.cpp_items.iter())
            .collect()
    }
}

pub struct ProcessingStep {
    pub name: String,
    pub is_const: bool,
    pub function: Box<Fn(&mut ProcessorData) -> Result<()>>,
}

impl fmt::Debug for ProcessingStep {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ProcessingStep")
            .field("name", &self.name)
            .field("is_const", &self.is_const)
            .finish()
    }
}

#[derive(Debug)]
pub struct ProcessingSteps {
    all_steps: Vec<ProcessingStep>,
    main_procedure: Vec<String>,
}

impl Default for ProcessingSteps {
    fn default() -> Self {
        let main_steps = vec![
            cpp_parser_step(),
            add_explicit_xstructors_step(),
            choose_allocation_places_step(),
            find_template_instantiations_step(),
            instantiate_templates_step(),
            cpp_ffi_generator_step(),
            // TODO: generate_slot_wrappers
            cpp_checker_step(),
            rust_generator_step(),
            crate_writer_step(),
            steps::build_crate(),
        ];

        let main_procedure = main_steps.iter().map(|s| s.name.clone()).collect();

        let mut all_steps = main_steps;
        all_steps.extend(vec![
            steps::print_database(),
            steps::clear_ffi(),
            clear_rust_info_step(),
        ]);
        Self {
            all_steps,
            main_procedure,
        }
    }
}

impl ProcessingSteps {
    pub fn add_after(&mut self, after: &[&str], step: ProcessingStep) -> Result<()> {
        let indexes: Vec<usize> = after.iter().map_if_ok(|s| {
            self.main_procedure
                .iter()
                .position(|a| a == s)
                .ok_or_else(|| err_msg(format!("requested step not found: {}", s)))
        })?;

        let max_index = indexes
            .into_iter()
            .max()
            .ok_or_else(|| err_msg("no steps provided"))?;
        self.main_procedure.insert(max_index + 1, step.name.clone());
        self.all_steps.push(step);
        Ok(())
    }
}

impl ProcessingStep {
    pub fn new<S: Into<String>, F: 'static + Fn(&mut ProcessorData) -> Result<()>>(
        name: S,
        function: F,
    ) -> ProcessingStep {
        ProcessingStep {
            name: name.into(),
            is_const: false,
            function: Box::new(function),
        }
    }
    pub fn new_const<S: Into<String>, F: 'static + Fn(&mut ProcessorData) -> Result<()>>(
        name: S,
        function: F,
    ) -> ProcessingStep {
        let name = name.into();
        ProcessingStep {
            name,
            is_const: true,
            function: Box::new(function),
        }
    }
}

mod steps {
    use crate::processor::ProcessingStep;
    use log::trace;
    use ritual_common::utils::run_command;
    use std::process::Command;

    pub fn print_database() -> ProcessingStep {
        ProcessingStep::new_const("print_database", |data| {
            for item in &data.current_database.cpp_items {
                trace!(
                    "[database_item] cpp_data={}; source={:?}",
                    item.cpp_data.to_string(),
                    item.source
                );
                for ffi_item in &item.ffi_items {
                    trace!("[database_item]   ffi_item={:?}", ffi_item);
                }
            }
            Ok(())
        })
    }

    pub fn clear_ffi() -> ProcessingStep {
        ProcessingStep::new("clear_ffi", |data| {
            for item in &mut data.current_database.cpp_items {
                item.ffi_items.clear();
                item.is_cpp_ffi_processed = false;
            }
            Ok(())
        })
    }

    pub fn build_crate() -> ProcessingStep {
        ProcessingStep::new_const("build_crate", |data| {
            let path = data
                .workspace
                .crate_path(&data.current_database.crate_name)?;
            for cargo_cmd in &["update", "build", "test", "doc"] {
                let mut command = Command::new("cargo");
                command.arg(cargo_cmd);
                command.current_dir(&path);
                run_command(&mut command)?;
            }
            Ok(())
        })
    }
}

#[derive(Debug)]
struct MainItemRef<'a> {
    step: &'a ProcessingStep,
    run_after: &'a [String],
}

impl PartialEq for MainItemRef<'_> {
    fn eq(&self, other: &MainItemRef) -> bool {
        self.step.name == other.step.name
    }
}

impl PartialOrd for MainItemRef<'_> {
    fn partial_cmp(&self, other: &MainItemRef) -> Option<Ordering> {
        if self.run_after.contains(&other.step.name) {
            Some(Ordering::Greater)
        } else {
            Some(Ordering::Less)
        }
    }
}
impl Eq for MainItemRef<'_> {}
impl Ord for MainItemRef<'_> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn process(workspace: &mut Workspace, config: &Config, step_names: &[String]) -> Result<()> {
    info!("Processing crate: {}", config.crate_properties().name());
    check_all_paths(&config)?;

    // TODO: allow to remove any prefix through `Config` (#25)

    info!("Loading current crate data");
    let mut current_database = workspace
        .load_or_create_crate(config.crate_properties().name())
        .with_context(|_| "failed to load current crate data")?;

    if !config.dependent_cpp_crates().is_empty() {
        info!("Loading dependencies");
    }
    let dependent_cpp_crates = config.dependent_cpp_crates().iter().map_if_ok(|name| {
        workspace
            .load_crate(name)
            .with_context(|_| "failed to load dependency")
    })?;

    let mut current_database_saved = true;

    if current_database.crate_version != config.crate_properties().version() {
        current_database.crate_version = config.crate_properties().version().to_string();
        current_database_saved = false;
    }

    let mut steps_result = Ok(());

    for step_name in step_names {
        if steps_result.is_err() {
            break;
        }

        let step_names = if step_name == "main" {
            config.processing_steps().main_procedure.clone()
        } else if step_name.starts_with("from:") {
            let start_step = &step_name["from:".len()..];
            let start_index = config
                .processing_steps()
                .main_procedure
                .iter()
                .position(|s| s == start_step)
                .ok_or_else(|| err_msg(format!("requested step not found: {}", start_step)))?;
            config.processing_steps().main_procedure[start_index..].to_vec()
        } else {
            vec![step_name.to_string()]
        };

        for step_name in step_names {
            let step = if let Some(item) = config
                .processing_steps()
                .all_steps
                .iter()
                .find(|item| item.name == step_name)
            {
                item
            } else {
                bail!(
                    "Unknown operation: {}. Supported operations: main, {}.",
                    step_name,
                    config
                        .processing_steps()
                        .all_steps
                        .iter()
                        .map(|item| &item.name)
                        .join(", ")
                );
            };

            info!("Running processing step: {}", &step.name);

            let mut data = ProcessorData {
                workspace,
                current_database: &mut current_database,
                dep_databases: &dependent_cpp_crates,
                config,
            };

            if !step.is_const {
                current_database_saved = false;
            }

            if let Err(err) = (step.function)(&mut data) {
                steps_result = Err(err);
                error!("Step failed! Aborting...");
                break;
            }
        }
    }

    for database in dependent_cpp_crates {
        workspace.put_crate(database, true);
    }

    if !current_database_saved {
        info!("Saving data");
    }

    workspace.put_crate(current_database, current_database_saved);
    workspace.save_data()?;

    steps_result
}
<commit_msg>measure processing step durations<commit_after>use crate::config::Config;
use crate::cpp_checker::cpp_checker_step;
use crate::cpp_explicit_xstructors::add_explicit_xstructors_step;
use crate::cpp_ffi_generator::cpp_ffi_generator_step;
use crate::cpp_parser::cpp_parser_step;
use crate::cpp_template_instantiator::find_template_instantiations_step;
use crate::cpp_template_instantiator::instantiate_templates_step;
use crate::crate_writer::crate_writer_step;
use crate::database::{CppDatabaseItem, Database};
use crate::rust_generator::clear_rust_info_step;
use crate::rust_generator::rust_generator_step;
use crate::type_allocation_places::choose_allocation_places_step;
use crate::workspace::Workspace;
use itertools::Itertools;
use log::{debug, error, info};
use ritual_common::errors::{bail, err_msg, Result, ResultExt};
use ritual_common::utils::MapIfOk;
use std::cmp::Ordering;
use std::fmt;
use std::iter::once;
use std::path::PathBuf;
use std::time::Instant;

/// Creates output and cache directories if they don't exist.
/// Returns `Err` if any path in `config` is invalid or relative.
fn check_all_paths(config: &Config) -> Result<()> {
    let check_dir = |path: &PathBuf| -> Result<()> {
        if !path.is_absolute() {
            bail!(
                "Only absolute paths allowed. Relative path: {}",
                path.display()
            );
        }
        if !path.exists() {
            bail!("Directory doesn't exist: {}", path.display());
        }
        if !path.is_dir() {
            bail!("Path is not a directory: {}", path.display());
        }
        Ok(())
    };

    if let Some(path) = config.crate_template_path() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().include_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().lib_paths() {
        check_dir(path)?;
    }
    for path in config.cpp_build_paths().framework_paths() {
        check_dir(path)?;
    }
    for path in config.target_include_paths() {
        check_dir(path)?;
    }
    Ok(())
}

pub struct ProcessorData<'a> {
    pub workspace: &'a mut Workspace,
    pub config: &'a Config,
    pub current_database: &'a mut Database,
    pub dep_databases: &'a [Database],
}

impl<'a> ProcessorData<'a> {
    pub fn all_databases(&self) -> Vec<&Database> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .collect()
    }
    pub fn all_items(&self) -> Vec<&CppDatabaseItem> {
        once(&self.current_database as &_)
            .chain(self.dep_databases.iter())
            .flat_map(|d| d.cpp_items.iter())
            .collect()
    }
}

pub struct ProcessingStep {
    pub name: String,
    pub is_const: bool,
    pub function: Box<Fn(&mut ProcessorData) -> Result<()>>,
}

impl fmt::Debug for ProcessingStep {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ProcessingStep")
            .field("name", &self.name)
            .field("is_const", &self.is_const)
            .finish()
    }
}

#[derive(Debug)]
pub struct ProcessingSteps {
    all_steps: Vec<ProcessingStep>,
    main_procedure: Vec<String>,
}

impl Default for ProcessingSteps {
    fn default() -> Self {
        let main_steps = vec![
            cpp_parser_step(),
            add_explicit_xstructors_step(),
            choose_allocation_places_step(),
            find_template_instantiations_step(),
            instantiate_templates_step(),
            cpp_ffi_generator_step(),
            // TODO: generate_slot_wrappers
            cpp_checker_step(),
            rust_generator_step(),
            crate_writer_step(),
            steps::build_crate(),
        ];

        let main_procedure = main_steps.iter().map(|s| s.name.clone()).collect();

        let mut all_steps = main_steps;
        all_steps.extend(vec![
            steps::print_database(),
            steps::clear_ffi(),
            clear_rust_info_step(),
        ]);
        Self {
            all_steps,
            main_procedure,
        }
    }
}

impl ProcessingSteps {
    pub fn add_after(&mut self, after: &[&str], step: ProcessingStep) -> Result<()> {
        let indexes: Vec<usize> = after.iter().map_if_ok(|s| {
            self.main_procedure
                .iter()
                .position(|a| a == s)
                .ok_or_else(|| err_msg(format!("requested step not found: {}", s)))
        })?;

        let max_index = indexes
            .into_iter()
            .max()
            .ok_or_else(|| err_msg("no steps provided"))?;
        self.main_procedure.insert(max_index + 1, step.name.clone());
        self.all_steps.push(step);
        Ok(())
    }
}

impl ProcessingStep {
    pub fn new<S: Into<String>, F: 'static + Fn(&mut ProcessorData) -> Result<()>>(
        name: S,
        function: F,
    ) -> ProcessingStep {
        ProcessingStep {
            name: name.into(),
            is_const: false,
            function: Box::new(function),
        }
    }
    pub fn new_const<S: Into<String>, F: 'static + Fn(&mut ProcessorData) -> Result<()>>(
        name: S,
        function: F,
    ) -> ProcessingStep {
        let name = name.into();
        ProcessingStep {
            name,
            is_const: true,
            function: Box::new(function),
        }
    }
}

mod steps {
    use crate::processor::ProcessingStep;
    use log::trace;
    use ritual_common::utils::run_command;
    use std::process::Command;

    pub fn print_database() -> ProcessingStep {
        ProcessingStep::new_const("print_database", |data| {
            for item in &data.current_database.cpp_items {
                trace!(
                    "[database_item] cpp_data={}; source={:?}",
                    item.cpp_data.to_string(),
                    item.source
                );
                for ffi_item in &item.ffi_items {
                    trace!("[database_item]   ffi_item={:?}", ffi_item);
                }
            }
            Ok(())
        })
    }

    pub fn clear_ffi() -> ProcessingStep {
        ProcessingStep::new("clear_ffi", |data| {
            for item in &mut data.current_database.cpp_items {
                item.ffi_items.clear();
                item.is_cpp_ffi_processed = false;
            }
            Ok(())
        })
    }

    pub fn build_crate() -> ProcessingStep {
        ProcessingStep::new_const("build_crate", |data| {
            let path = data
                .workspace
                .crate_path(&data.current_database.crate_name)?;
            for cargo_cmd in &["update", "build", "test", "doc"] {
                let mut command = Command::new("cargo");
                command.arg(cargo_cmd);
                command.current_dir(&path);
                run_command(&mut command)?;
            }
            Ok(())
        })
    }
}

#[derive(Debug)]
struct MainItemRef<'a> {
    step: &'a ProcessingStep,
    run_after: &'a [String],
}

impl PartialEq for MainItemRef<'_> {
    fn eq(&self, other: &MainItemRef) -> bool {
        self.step.name == other.step.name
    }
}

impl PartialOrd for MainItemRef<'_> {
    fn partial_cmp(&self, other: &MainItemRef) -> Option<Ordering> {
        if self.run_after.contains(&other.step.name) {
            Some(Ordering::Greater)
        } else {
            Some(Ordering::Less)
        }
    }
}
impl Eq for MainItemRef<'_> {}
impl Ord for MainItemRef<'_> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[allow(clippy::useless_let_if_seq)]
pub fn process(workspace: &mut Workspace, config: &Config, step_names: &[String]) -> Result<()> {
    info!("Processing crate: {}", config.crate_properties().name());
    check_all_paths(&config)?;

    // TODO: allow to remove any prefix through `Config` (#25)

    info!("Loading current crate data");
    let mut current_database = workspace
        .load_or_create_crate(config.crate_properties().name())
        .with_context(|_| "failed to load current crate data")?;

    if !config.dependent_cpp_crates().is_empty() {
        info!("Loading dependencies");
    }
    let dependent_cpp_crates = config.dependent_cpp_crates().iter().map_if_ok(|name| {
        workspace
            .load_crate(name)
            .with_context(|_| "failed to load dependency")
    })?;

    let mut current_database_saved = true;

    if current_database.crate_version != config.crate_properties().version() {
        current_database.crate_version = config.crate_properties().version().to_string();
        current_database_saved = false;
    }

    let mut steps_result = Ok(());

    for step_name in step_names {
        if steps_result.is_err() {
            break;
        }

        let step_names = if step_name == "main" {
            config.processing_steps().main_procedure.clone()
        } else if step_name.starts_with("from:") {
            let start_step = &step_name["from:".len()..];
            let start_index = config
                .processing_steps()
                .main_procedure
                .iter()
                .position(|s| s == start_step)
                .ok_or_else(|| err_msg(format!("requested step not found: {}", start_step)))?;
            config.processing_steps().main_procedure[start_index..].to_vec()
        } else {
            vec![step_name.to_string()]
        };

        for step_name in step_names {
            let step = if let Some(item) = config
                .processing_steps()
                .all_steps
                .iter()
                .find(|item| item.name == step_name)
            {
                item
            } else {
                bail!(
                    "Unknown operation: {}. Supported operations: main, {}.",
                    step_name,
                    config
                        .processing_steps()
                        .all_steps
                        .iter()
                        .map(|item| &item.name)
                        .join(", ")
                );
            };

            info!("Running processing step: {}", &step.name);

            let mut data = ProcessorData {
                workspace,
                current_database: &mut current_database,
                dep_databases: &dependent_cpp_crates,
                config,
            };

            if !step.is_const {
                current_database_saved = false;
            }

            let started_time = Instant::now();

            if let Err(err) = (step.function)(&mut data) {
                steps_result = Err(err);
                error!("Step failed! Aborting...");
                break;
            }

            debug!(
                "Step '{}' completed in {:?}",
                step.name,
                started_time.elapsed()
            );
        }
    }

    for database in dependent_cpp_crates {
        workspace.put_crate(database, true);
    }

    if !current_database_saved {
        info!("Saving data");
    }

    workspace.put_crate(current_database, current_database_saved);
    workspace.save_data()?;

    steps_result
}
<|endoftext|>


<commit_before>extern crate neon;

use neon::js::JsNumber;

fn main() {
    JsNumber::new(scope, "9000")
    //~^ ERROR E0425
    //     (cannot find value `scope` in this scope)
    //~| ERROR E0308
    //     (mismatched types)
    //~| ERROR E0308
    //     (mismatched types)
}
<commit_msg>all tests pass \o/<commit_after>extern crate neon;

use neon::js::JsNumber;

fn main() {
    JsNumber::new(cx, "9000")
    //~^ ERROR E0425
    //     (cannot find value `cx` in this scope)
    //~| ERROR E0277
    //     (trait bound f64: From<&str> is not satisfied)
    //~| ERROR E0308
    //     (mismatched types)
}
<|endoftext|>