<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<P::Account>
    ) -> 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<P: Patch>(
        self, upfront: Gas, origin: Option<Address>,
        account_state: &mut AccountState<P::Account>, 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<P::Account>,
    },
    Constructing {
        transaction: ValidTransaction,
        block: HeaderParams,

        account_state: AccountState<P::Account>,
        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, P>> {
        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<P::Account>;
        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::<P>(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>core: fix patch name changes<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<P::Account>
    ) -> 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<P: Patch>(
        self, upfront: Gas, origin: Option<Address>,
        account_state: &mut AccountState<P::Account>, 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<P::Account>,
    },
    Constructing {
        transaction: ValidTransaction,
        block: HeaderParams,

        account_state: AccountState<P::Account>,
        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, P>> {
        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<P::Account>;
        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::<P>(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::<MainnetEIP160Patch>::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><commit_msg>implement Buffered for Cursor<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2016 rs-transducers developers
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */
use std::mem;

use super::{Transducer, TransductionResult};

pub struct MapTransducer<F> {
    f: F
}

impl<I, O, F> Transducer<I, O> for MapTransducer<F>
    where F: Fn(I) -> O {

    #[inline]
    fn accept(&mut self, value: Option<I>) -> TransductionResult<O> {
        match value {
            None => TransductionResult::End,
            Some(value) => TransductionResult::Some((self.f)(value))
        }
    }
}

pub fn map<F, I, O>(f: F) -> MapTransducer<F>
    where F: Fn(I) -> O {

    MapTransducer {
        f: f
    }
}

pub struct FilterTransducer<F> {
    f: F
}

impl<T, F> Transducer<T, T> for FilterTransducer<F>
    where F: Fn(&T) -> bool {

    #[inline]
    fn accept(&mut self, value: Option<T>) -> TransductionResult<T> {
        match value {
            None => TransductionResult::End,
            Some(value) => {
                if (self.f)(&value) {
                    TransductionResult::Some(value)
                } else {
                    TransductionResult::None
                }
            }
        }
    }
}

pub fn filter<F, T>(f: F) -> FilterTransducer<F>
    where F: Fn(&T) -> bool {

    FilterTransducer {
        f: f
    }
}

pub struct PartitionTransducer<T> {
    size: usize,
    holder: Vec<T>,
    all: bool
}

impl<T> Transducer<T, Vec<T>> for PartitionTransducer<T> {
    #[inline]
    fn accept(&mut self, value: Option<T>) -> TransductionResult<Vec<T>> {
        match value {
            None => {
                if self.all {
                    if self.holder.is_empty() {
                        TransductionResult::End
                    } else {
                        let pending = mem::replace(&mut self.holder, Vec::with_capacity(0));
                        TransductionResult::Some(pending)
                    }
                } else {
                    TransductionResult::End
                }
            },
            Some(value) => {
                self.holder.push(value);
                if self.holder.len() == self.size {
                    let pending = mem::replace(&mut self.holder, Vec::with_capacity(self.size));
                    TransductionResult::Some(pending)
                } else {
                    TransductionResult::None
                }
            }
        }
    }
}

pub fn partition<T>(num: usize) -> PartitionTransducer<T> {
    PartitionTransducer {
        size: num,
        holder: Vec::with_capacity(num),
        all: false
    }
}

pub fn partition_all<T>(num: usize) -> PartitionTransducer<T> {
    PartitionTransducer {
        size: num,
        holder: Vec::with_capacity(num),
        all: true
    }
}

pub struct TakeTransducer {
    size: usize,
    taken: usize
}

impl<T> Transducer<T, T> for TakeTransducer {
    #[inline]
    fn accept(&mut self, value: Option<T>) -> TransductionResult<T> {
        if self.taken == self.size {
            TransductionResult::End
        } else {
            match value {
                None => TransductionResult::End,
                Some(value) => {
                    self.taken += 1;
                    TransductionResult::Some(value)
                }
            }
        }
    }
}

pub fn take(num: usize) -> TakeTransducer {
    TakeTransducer {
        size: num,
        taken: 0
    }
}

pub struct DropTransducer {
    size: usize,
    dropped: usize
}

impl<T> Transducer<T, T> for DropTransducer {
    #[inline]
    fn accept(&mut self, value: Option<T>) -> TransductionResult<T> {
        match value {
            None => TransductionResult::End,
            Some(value) => {
                if self.dropped == self.size {
                    TransductionResult::Some(value)
                } else {
                    TransductionResult::None
                }
            }
        }
    }
}

pub fn drop(num: usize) -> DropTransducer {
    DropTransducer {
        size: num,
        dropped: 0
    }
}
<commit_msg>Ensure drop count on Drop transducer is incremented<commit_after>/*
 * Copyright 2016 rs-transducers developers
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */
use std::mem;

use super::{Transducer, TransductionResult};

pub struct MapTransducer<F> {
    f: F
}

impl<I, O, F> Transducer<I, O> for MapTransducer<F>
    where F: Fn(I) -> O {

    #[inline]
    fn accept(&mut self, value: Option<I>) -> TransductionResult<O> {
        match value {
            None => TransductionResult::End,
            Some(value) => TransductionResult::Some((self.f)(value))
        }
    }
}

pub fn map<F, I, O>(f: F) -> MapTransducer<F>
    where F: Fn(I) -> O {

    MapTransducer {
        f: f
    }
}

pub struct FilterTransducer<F> {
    f: F
}

impl<T, F> Transducer<T, T> for FilterTransducer<F>
    where F: Fn(&T) -> bool {

    #[inline]
    fn accept(&mut self, value: Option<T>) -> TransductionResult<T> {
        match value {
            None => TransductionResult::End,
            Some(value) => {
                if (self.f)(&value) {
                    TransductionResult::Some(value)
                } else {
                    TransductionResult::None
                }
            }
        }
    }
}

pub fn filter<F, T>(f: F) -> FilterTransducer<F>
    where F: Fn(&T) -> bool {

    FilterTransducer {
        f: f
    }
}

pub struct PartitionTransducer<T> {
    size: usize,
    holder: Vec<T>,
    all: bool
}

impl<T> Transducer<T, Vec<T>> for PartitionTransducer<T> {
    #[inline]
    fn accept(&mut self, value: Option<T>) -> TransductionResult<Vec<T>> {
        match value {
            None => {
                if self.all {
                    if self.holder.is_empty() {
                        TransductionResult::End
                    } else {
                        let pending = mem::replace(&mut self.holder, Vec::with_capacity(0));
                        TransductionResult::Some(pending)
                    }
                } else {
                    TransductionResult::End
                }
            },
            Some(value) => {
                self.holder.push(value);
                if self.holder.len() == self.size {
                    let pending = mem::replace(&mut self.holder, Vec::with_capacity(self.size));
                    TransductionResult::Some(pending)
                } else {
                    TransductionResult::None
                }
            }
        }
    }
}

pub fn partition<T>(num: usize) -> PartitionTransducer<T> {
    PartitionTransducer {
        size: num,
        holder: Vec::with_capacity(num),
        all: false
    }
}

pub fn partition_all<T>(num: usize) -> PartitionTransducer<T> {
    PartitionTransducer {
        size: num,
        holder: Vec::with_capacity(num),
        all: true
    }
}

pub struct TakeTransducer {
    size: usize,
    taken: usize
}

impl<T> Transducer<T, T> for TakeTransducer {
    #[inline]
    fn accept(&mut self, value: Option<T>) -> TransductionResult<T> {
        if self.taken == self.size {
            TransductionResult::End
        } else {
            match value {
                None => TransductionResult::End,
                Some(value) => {
                    self.taken += 1;
                    TransductionResult::Some(value)
                }
            }
        }
    }
}

pub fn take(num: usize) -> TakeTransducer {
    TakeTransducer {
        size: num,
        taken: 0
    }
}

pub struct DropTransducer {
    size: usize,
    dropped: usize
}

impl<T> Transducer<T, T> for DropTransducer {
    #[inline]
    fn accept(&mut self, value: Option<T>) -> TransductionResult<T> {
        match value {
            None => TransductionResult::End,
            Some(value) => {
                if self.dropped == self.size {
                    TransductionResult::Some(value)
                } else {
                    self.dropped += 1;
                    TransductionResult::None
                }
            }
        }
    }
}

pub fn drop(num: usize) -> DropTransducer {
    DropTransducer {
        size: num,
        dropped: 0
    }
}
<|endoftext|>


<commit_before>

use serde::de::Error;
use serde::{Serialize, Serializer, Deserialize, Deserializer};

use std::marker::PhantomData;

use prelude::*;

use EdgeType;
use graph::Node;
use graph::{IndexType, Edge};
use stable_graph::StableGraph;
use util::rev;
use serde_utils::MappedSequenceVisitor;
use serde_utils::CollectSeqWithLength;
use serde_utils::{IntoSerializable, FromDeserialized};

use super::super::serialization::{EdgeProperty, invalid_length_err, invalid_node_err};

// Serialization representation for StableGraph
// Keep in sync with deserialization and Graph
#[derive(Serialize)]
#[serde(rename = "Graph")]
#[serde(bound(serialize = "N: Serialize, E: Serialize, Ix: IndexType + Serialize"))]
pub struct SerStableGraph<'a, N: 'a, E: 'a, Ix: 'a + IndexType> {
    #[serde(serialize_with="ser_stable_graph_nodes")]
    nodes: &'a [Node<Option<N>, Ix>],
    #[serde(serialize_with="ser_stable_graph_node_holes")]
    node_holes: &'a [Node<Option<N>, Ix>],
    edge_property: EdgeProperty,
    #[serde(serialize_with="ser_stable_graph_edges")]
    edges: &'a [Edge<Option<E>, Ix>],
}

// Deserialization representation for StableGraph
// Keep in sync with serialization and Graph
#[derive(Deserialize)]
#[serde(rename = "Graph")]
#[serde(bound(deserialize = "N: Deserialize<'de>, E: Deserialize<'de>, Ix: IndexType + Deserialize<'de>"))]
pub struct DeserStableGraph<N, E, Ix> {
    #[serde(deserialize_with="deser_stable_graph_nodes")]
    nodes: Vec<Node<Option<N>, Ix>>,
    #[serde(default="Vec::new")]
    node_holes: Vec<NodeIndex<Ix>>,
    edge_property: EdgeProperty,
    #[serde(deserialize_with="deser_stable_graph_edges")]
    edges: Vec<Edge<Option<E>, Ix>>,
}

fn ser_stable_graph_nodes<S, N, Ix>(nodes: &&[Node<Option<N>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          N: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_with_length(
        nodes.iter().map(|node| node.weight.is_some() as usize).sum(),
        nodes.iter()
             .filter_map(|node| node.weight.as_ref()))
}

fn ser_stable_graph_node_holes<S, N, Ix>(nodes: &&[Node<Option<N>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          N: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_with_length(
        nodes.iter().map(|node| node.weight.is_none() as usize).sum(),
        nodes.iter()
             .enumerate()
             .filter_map(|(i, node)| if node.weight.is_none() { Some(NodeIndex::<Ix>::new(i)) } else { None }))
}

fn ser_stable_graph_edges<S, E, Ix>(edges: &&[Edge<Option<E>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          E: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_exact(
        edges.iter()
            .map(|edge| edge.weight.as_ref().map(|w| (
               edge.source(),
               edge.target(),
               w
            ))))
}

fn deser_stable_graph_nodes<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Node<Option<N>, Ix>>, D::Error>
    where D: Deserializer<'de>,
          N: Deserialize<'de>,
          Ix: IndexType + Deserialize<'de>,
{
    deserializer.deserialize_seq(MappedSequenceVisitor::new(|n|
        Ok(Node {
            weight: Some(n),
            next: [EdgeIndex::end(); 2],
        })
    ))
}

fn deser_stable_graph_edges<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Edge<Option<N>, Ix>>, D::Error>
    where D: Deserializer<'de>,
          N: Deserialize<'de>,
          Ix: IndexType + Deserialize<'de>,
{
    deserializer.deserialize_seq(MappedSequenceVisitor::<Option<(NodeIndex<Ix>, NodeIndex<Ix>, N)>, _, _>::new(|x|
        if let Some((i, j, w)) = x {
            Ok(Edge {
                weight: Some(w),
                node: [i, j],
                next: [EdgeIndex::end(); 2],
            })
        } else {
            Ok(Edge {
                weight: None,
                node: [NodeIndex::end(); 2],
                next: [EdgeIndex::end(); 2],
            })
        }
    ))
}

impl<'a, N, E, Ty, Ix> IntoSerializable for &'a StableGraph<N, E, Ty, Ix>
    where Ix: IndexType,
          Ty: EdgeType,
{
    type Output = SerStableGraph<'a, N, E, Ix>;
    fn into_serializable(self) -> Self::Output {
        SerStableGraph {
            nodes: self.raw_nodes(),
            node_holes: self.raw_nodes(),
            edges: self.raw_edges(),
            edge_property: if self.is_directed() {
                EdgeProperty::Directed
            } else {
                EdgeProperty::Undirected
            },
        }
    }
}

impl<'a, N, E, Ty, Ix> FromDeserialized for StableGraph<N, E, Ty, Ix>
    where Ix: IndexType,
          Ty: EdgeType,
{
    type Input = DeserStableGraph<N, E, Ix>;
    fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
        where E2: Error
    {
        if input.edge_property.is_directed() != Ty::is_directed() {
            return Err(E2::custom(format_args!("graph edge property mismatch, \
                                               expected {:?}, found {:?}",
                                               EdgeProperty::from(PhantomData::<Ty>),
            input.edge_property)));
        }
        assemble_stable_graph(input.nodes, input.node_holes, input.edges)
    }
}

impl<N, E, Ty, Ix> Serialize for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType + Serialize,
          N: Serialize,
          E: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        self.into_serializable().serialize(serializer)
    }
}

fn assemble_stable_graph<N, E, Ty, Ix, E2>(mut nodes: Vec<Node<Option<N>, Ix>>,
                                           node_holes: Vec<NodeIndex<Ix>>,
                                           edges: Vec<Edge<Option<E>, Ix>>)
                                           -> Result<StableGraph<N, E, Ty, Ix>, E2>
    where E2: Error,
          Ty: EdgeType,
          Ix: IndexType,
{
    if nodes.len() >= <Ix as IndexType>::max().index() {
        Err(invalid_length_err::<Ix, _>("node", nodes.len()))?
    }

    if edges.len() >= <Ix as IndexType>::max().index() {
        Err(invalid_length_err::<Ix, _>("edge", edges.len()))?
    }

    // insert Nones for each hole
    let mut offset = node_holes.len();
    for hole_pos in rev(node_holes) {
        offset -= 1;
        nodes.insert(hole_pos.index() + offset, Node {
            weight: None,
            next: [EdgeIndex::end(); 2],
        });
    }

    let node_bound = nodes.len();
    let mut sgr = StableGraph {
        g: Graph {
            nodes: nodes,
            edges: edges,
            ty: PhantomData,
        },
        node_count: 0,
        edge_count: 0,
        free_edge: EdgeIndex::end(),
        free_node: NodeIndex::end(),
    };
    sgr.link_edges().map_err(|i| invalid_node_err(i.index(), node_bound))?;
    Ok(sgr)
}

impl<'de, N, E, Ty, Ix> Deserialize<'de> for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType + Deserialize<'de>,
          N: Deserialize<'de>,
          E: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        Self::from_deserialized(DeserStableGraph::deserialize(deserializer)?)
    }
}
<commit_msg>MAINT: Fix iterator counter<commit_after>

use serde::de::Error;
use serde::{Serialize, Serializer, Deserialize, Deserializer};

use std::marker::PhantomData;

use prelude::*;

use EdgeType;
use graph::Node;
use graph::{IndexType, Edge};
use stable_graph::StableGraph;
use util::rev;
use serde_utils::MappedSequenceVisitor;
use serde_utils::CollectSeqWithLength;
use serde_utils::{IntoSerializable, FromDeserialized};

use super::super::serialization::{EdgeProperty, invalid_length_err, invalid_node_err};

// Serialization representation for StableGraph
// Keep in sync with deserialization and Graph
#[derive(Serialize)]
#[serde(rename = "Graph")]
#[serde(bound(serialize = "N: Serialize, E: Serialize, Ix: IndexType + Serialize"))]
pub struct SerStableGraph<'a, N: 'a, E: 'a, Ix: 'a + IndexType> {
    #[serde(serialize_with="ser_stable_graph_nodes")]
    nodes: &'a [Node<Option<N>, Ix>],
    #[serde(serialize_with="ser_stable_graph_node_holes")]
    node_holes: &'a [Node<Option<N>, Ix>],
    edge_property: EdgeProperty,
    #[serde(serialize_with="ser_stable_graph_edges")]
    edges: &'a [Edge<Option<E>, Ix>],
}

// Deserialization representation for StableGraph
// Keep in sync with serialization and Graph
#[derive(Deserialize)]
#[serde(rename = "Graph")]
#[serde(bound(deserialize = "N: Deserialize<'de>, E: Deserialize<'de>, Ix: IndexType + Deserialize<'de>"))]
pub struct DeserStableGraph<N, E, Ix> {
    #[serde(deserialize_with="deser_stable_graph_nodes")]
    nodes: Vec<Node<Option<N>, Ix>>,
    #[serde(default="Vec::new")]
    node_holes: Vec<NodeIndex<Ix>>,
    edge_property: EdgeProperty,
    #[serde(deserialize_with="deser_stable_graph_edges")]
    edges: Vec<Edge<Option<E>, Ix>>,
}

fn ser_stable_graph_nodes<S, N, Ix>(nodes: &&[Node<Option<N>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          N: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_with_length(
        nodes.iter()
             .filter(|node| node.weight.is_some())
             .count(),
        nodes.iter()
             .filter_map(|node| node.weight.as_ref()))
}

fn ser_stable_graph_node_holes<S, N, Ix>(nodes: &&[Node<Option<N>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          N: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_with_length(
        nodes.iter()
             .filter(|node| node.weight.is_none())
             .count(),
        nodes.iter()
             .enumerate()
             .filter_map(|(i, node)| if node.weight.is_none() { Some(NodeIndex::<Ix>::new(i)) } else { None }))
}

fn ser_stable_graph_edges<S, E, Ix>(edges: &&[Edge<Option<E>, Ix>], serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer,
          E: Serialize,
          Ix: Serialize + IndexType,
{
    serializer.collect_seq_exact(
        edges.iter()
            .map(|edge| edge.weight.as_ref().map(|w| (
               edge.source(),
               edge.target(),
               w
            ))))
}

fn deser_stable_graph_nodes<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Node<Option<N>, Ix>>, D::Error>
    where D: Deserializer<'de>,
          N: Deserialize<'de>,
          Ix: IndexType + Deserialize<'de>,
{
    deserializer.deserialize_seq(MappedSequenceVisitor::new(|n|
        Ok(Node {
            weight: Some(n),
            next: [EdgeIndex::end(); 2],
        })
    ))
}

fn deser_stable_graph_edges<'de, D, N, Ix>(deserializer: D) -> Result<Vec<Edge<Option<N>, Ix>>, D::Error>
    where D: Deserializer<'de>,
          N: Deserialize<'de>,
          Ix: IndexType + Deserialize<'de>,
{
    deserializer.deserialize_seq(MappedSequenceVisitor::<Option<(NodeIndex<Ix>, NodeIndex<Ix>, N)>, _, _>::new(|x|
        if let Some((i, j, w)) = x {
            Ok(Edge {
                weight: Some(w),
                node: [i, j],
                next: [EdgeIndex::end(); 2],
            })
        } else {
            Ok(Edge {
                weight: None,
                node: [NodeIndex::end(); 2],
                next: [EdgeIndex::end(); 2],
            })
        }
    ))
}

impl<'a, N, E, Ty, Ix> IntoSerializable for &'a StableGraph<N, E, Ty, Ix>
    where Ix: IndexType,
          Ty: EdgeType,
{
    type Output = SerStableGraph<'a, N, E, Ix>;
    fn into_serializable(self) -> Self::Output {
        SerStableGraph {
            nodes: self.raw_nodes(),
            node_holes: self.raw_nodes(),
            edges: self.raw_edges(),
            edge_property: if self.is_directed() {
                EdgeProperty::Directed
            } else {
                EdgeProperty::Undirected
            },
        }
    }
}

impl<'a, N, E, Ty, Ix> FromDeserialized for StableGraph<N, E, Ty, Ix>
    where Ix: IndexType,
          Ty: EdgeType,
{
    type Input = DeserStableGraph<N, E, Ix>;
    fn from_deserialized<E2>(input: Self::Input) -> Result<Self, E2>
        where E2: Error
    {
        if input.edge_property.is_directed() != Ty::is_directed() {
            return Err(E2::custom(format_args!("graph edge property mismatch, \
                                               expected {:?}, found {:?}",
                                               EdgeProperty::from(PhantomData::<Ty>),
            input.edge_property)));
        }
        assemble_stable_graph(input.nodes, input.node_holes, input.edges)
    }
}

impl<N, E, Ty, Ix> Serialize for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType + Serialize,
          N: Serialize,
          E: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        self.into_serializable().serialize(serializer)
    }
}

fn assemble_stable_graph<N, E, Ty, Ix, E2>(mut nodes: Vec<Node<Option<N>, Ix>>,
                                           node_holes: Vec<NodeIndex<Ix>>,
                                           edges: Vec<Edge<Option<E>, Ix>>)
                                           -> Result<StableGraph<N, E, Ty, Ix>, E2>
    where E2: Error,
          Ty: EdgeType,
          Ix: IndexType,
{
    if nodes.len() >= <Ix as IndexType>::max().index() {
        Err(invalid_length_err::<Ix, _>("node", nodes.len()))?
    }

    if edges.len() >= <Ix as IndexType>::max().index() {
        Err(invalid_length_err::<Ix, _>("edge", edges.len()))?
    }

    // insert Nones for each hole
    let mut offset = node_holes.len();
    for hole_pos in rev(node_holes) {
        offset -= 1;
        nodes.insert(hole_pos.index() + offset, Node {
            weight: None,
            next: [EdgeIndex::end(); 2],
        });
    }

    let node_bound = nodes.len();
    let mut sgr = StableGraph {
        g: Graph {
            nodes: nodes,
            edges: edges,
            ty: PhantomData,
        },
        node_count: 0,
        edge_count: 0,
        free_edge: EdgeIndex::end(),
        free_node: NodeIndex::end(),
    };
    sgr.link_edges().map_err(|i| invalid_node_err(i.index(), node_bound))?;
    Ok(sgr)
}

impl<'de, N, E, Ty, Ix> Deserialize<'de> for StableGraph<N, E, Ty, Ix>
    where Ty: EdgeType,
          Ix: IndexType + Deserialize<'de>,
          N: Deserialize<'de>,
          E: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        Self::from_deserialized(DeserStableGraph::deserialize(deserializer)?)
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

// Integer binary logarithm of a 64-bit value.
// v: A 64-bit value.
// Returns floor(log2(v)) + 1, or 0 if v == 0.
// This is the number of bits that would be required to represent v in two's
//  complement notation with all of the leading zeros stripped.
// TODO: Mark const once leading_zeros() as a constant function stabilizes.
#[allow(unused)]
fn ilog64(v: i64) -> i32 {
  64 - (v.leading_zeros() as i32)
}

// Convert an integer into a Q57 fixed-point fraction.
// The integer must be in the range -64 to 63, inclusive.
#[allow(unused)]
const fn q57(v: i32) -> i64 {
  // TODO: Add assert if it ever becomes possible to do in a const function.
  (v as i64) << 57
}

#[rustfmt::skip]
#[allow(unused)]
const ATANH_LOG2: &[i64; 32] = &[
  0x32B803473F7AD0F4, 0x2F2A71BD4E25E916, 0x2E68B244BB93BA06,
  0x2E39FB9198CE62E4, 0x2E2E683F68565C8F, 0x2E2B850BE2077FC1,
  0x2E2ACC58FE7B78DB, 0x2E2A9E2DE52FD5F2, 0x2E2A92A338D53EEC,
  0x2E2A8FC08F5E19B6, 0x2E2A8F07E51A485E, 0x2E2A8ED9BA8AF388,
  0x2E2A8ECE2FE7384A, 0x2E2A8ECB4D3E4B1A, 0x2E2A8ECA94940FE8,
  0x2E2A8ECA6669811D, 0x2E2A8ECA5ADEDD6A, 0x2E2A8ECA57FC347E,
  0x2E2A8ECA57438A43, 0x2E2A8ECA57155FB4, 0x2E2A8ECA5709D510,
  0x2E2A8ECA5706F267, 0x2E2A8ECA570639BD, 0x2E2A8ECA57060B92,
  0x2E2A8ECA57060008, 0x2E2A8ECA5705FD25, 0x2E2A8ECA5705FC6C,
  0x2E2A8ECA5705FC3E, 0x2E2A8ECA5705FC33, 0x2E2A8ECA5705FC30,
  0x2E2A8ECA5705FC2F, 0x2E2A8ECA5705FC2F
];

// Computes the binary exponential of logq57.
// input: a log base 2 in Q57 format.
// output: a 64 bit integer in Q0 (no fraction).
// TODO: Mark const once we can use local variables in a const function.
#[allow(unused)]
fn bexp64(logq57: i64) -> i64 {
  let ipart = (logq57 >> 57) as i32;
  if ipart < 0 {
    return 0;
  }
  if ipart >= 63 {
    return 0x7FFFFFFFFFFFFFFF;
  }
  // z is the fractional part of the log in Q62 format.
  // We need 1 bit of headroom since the magnitude can get larger than 1
  //  during the iteration, and a sign bit.
  let mut z = logq57 - q57(ipart);
  let mut w: i64;
  if z != 0 {
    // Rust has 128 bit multiplies, so it should be possible to do this
    //  faster without losing accuracy.
    z <<= 5;
    // w is the exponential in Q61 format (since it also needs headroom and can
    //  get as large as 2.0); we could get another bit if we dropped the sign,
    //  but we'll recover that bit later anyway.
    // Ideally this should start out as
    //   \lim_{n->\infty} 2^{61}/\product_{i=1}^n \sqrt{1-2^{-2i}}
    //  but in order to guarantee convergence we have to repeat iterations 4,
    //  13 (=3*4+1), and 40 (=3*13+1, etc.), so it winds up somewhat larger.
    w = 0x26A3D0E401DD846D;
    let mut i: i64 = 0;
    loop {
      let mask = -((z < 0) as i64);
      w += ((w >> (i + 1)) + mask) ^ mask;
      z -= (ATANH_LOG2[i as usize] + mask) ^ mask;
      // Repeat iteration 4.
      if i >= 3 {
        break;
      }
      z *= 2;
      i += 1;
    }
    loop {
      let mask = -((z < 0) as i64);
      w += ((w >> (i + 1)) + mask) ^ mask;
      z -= (ATANH_LOG2[i as usize] + mask) ^ mask;
      // Repeat iteration 13.
      if i >= 12 {
        break;
      }
      z *= 2;
      i += 1;
    }
    while i < 32 {
      let mask = -((z < 0) as i64);
      w += ((w >> (i + 1)) + mask) ^ mask;
      z = (z - ((ATANH_LOG2[i as usize] + mask) ^ mask)) * 2;
      i += 1;
    }
    // Skip the remaining iterations unless we really require that much
    //  precision.
    // We could have bailed out earlier for smaller iparts, but that would
    //  require initializing w from a table, as the limit doesn't converge to
    //  61-bit precision until n=30.
    let mut wlo: i32 = 0;
    if ipart > 30 {
      // For these iterations, we just update the low bits, as the high bits
      //  can't possibly be affected.
      // OD_ATANH_LOG2 has also converged (it actually did so one iteration
      //  earlier, but that's no reason for an extra special case).
      loop {
        let mask = -((z < 0) as i64);
        wlo += (((w >> i) + mask) ^ mask) as i32;
        z -= (ATANH_LOG2[31] + mask) ^ mask;
        // Repeat iteration 40.
        if i >= 39 {
          break;
        }
        z *= 2;
        i += 1;
      }
      while i < 61 {
        let mask = -((z < 0) as i64);
        wlo += (((w >> i) + mask) ^ mask) as i32;
        z = (z - ((ATANH_LOG2[31] + mask) ^ mask)) * 2;
        i += 1;
      }
    }
    w = (w << 1) + (wlo as i64);
  } else {
    w = 1i64 << 62;
  }
  if ipart < 62 {
    w = ((w >> (61 - ipart)) + 1) >> 1;
  }
  w
}

// Computes the binary log of w.
// input: a 64-bit integer in Q0 (no fraction).
// output: a 64-bit log in Q57.
// TODO: Mark const once we can use local variables in a const function.
#[allow(unused)]
fn blog64(w: i64) -> i64 {
  let mut w = w;
  if w <= 0 {
    return -1;
  }
  let ipart = ilog64(w) - 1;
  if ipart > 61 {
    w >>= ipart - 61;
  } else {
    w <<= 61 - ipart;
  }
  // z is the fractional part of the log in Q61 format.
  let mut z: i64 = 0;
  if (w & (w - 1)) != 0 {
    // Rust has 128 bit multiplies, so it should be possible to do this
    //  faster without losing accuracy.
    // x and y are the cosh() and sinh(), respectively, in Q61 format.
    // We are computing z = 2*atanh(y/x) = 2*atanh((w - 1)/(w + 1)).
    let mut x = w + (1i64 << 61);
    let mut y = w - (1i64 << 61);
    for i in 0..4 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[i as usize] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    // Repeat iteration 4.
    for i in 3..13 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[i as usize] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    // Repeat iteration 13.
    for i in 12..32 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[i as usize] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    // OD_ATANH_LOG2 has converged.
    for i in 32..40 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[31] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    // Repeat iteration 40.
    for i in 39..62 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[31] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    z = (z + 8) >> 4;
  }
  q57(ipart) + z
}
<commit_msg>logexp: Add tests for bexp64 and blog64<commit_after>// Copyright (c) 2019, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

// Integer binary logarithm of a 64-bit value.
// v: A 64-bit value.
// Returns floor(log2(v)) + 1, or 0 if v == 0.
// This is the number of bits that would be required to represent v in two's
//  complement notation with all of the leading zeros stripped.
// TODO: Mark const once leading_zeros() as a constant function stabilizes.
#[allow(unused)]
fn ilog64(v: i64) -> i32 {
  64 - (v.leading_zeros() as i32)
}

// Convert an integer into a Q57 fixed-point fraction.
// The integer must be in the range -64 to 63, inclusive.
#[allow(unused)]
const fn q57(v: i32) -> i64 {
  // TODO: Add assert if it ever becomes possible to do in a const function.
  (v as i64) << 57
}

#[rustfmt::skip]
#[allow(unused)]
const ATANH_LOG2: &[i64; 32] = &[
  0x32B803473F7AD0F4, 0x2F2A71BD4E25E916, 0x2E68B244BB93BA06,
  0x2E39FB9198CE62E4, 0x2E2E683F68565C8F, 0x2E2B850BE2077FC1,
  0x2E2ACC58FE7B78DB, 0x2E2A9E2DE52FD5F2, 0x2E2A92A338D53EEC,
  0x2E2A8FC08F5E19B6, 0x2E2A8F07E51A485E, 0x2E2A8ED9BA8AF388,
  0x2E2A8ECE2FE7384A, 0x2E2A8ECB4D3E4B1A, 0x2E2A8ECA94940FE8,
  0x2E2A8ECA6669811D, 0x2E2A8ECA5ADEDD6A, 0x2E2A8ECA57FC347E,
  0x2E2A8ECA57438A43, 0x2E2A8ECA57155FB4, 0x2E2A8ECA5709D510,
  0x2E2A8ECA5706F267, 0x2E2A8ECA570639BD, 0x2E2A8ECA57060B92,
  0x2E2A8ECA57060008, 0x2E2A8ECA5705FD25, 0x2E2A8ECA5705FC6C,
  0x2E2A8ECA5705FC3E, 0x2E2A8ECA5705FC33, 0x2E2A8ECA5705FC30,
  0x2E2A8ECA5705FC2F, 0x2E2A8ECA5705FC2F
];

// Computes the binary exponential of logq57.
// input: a log base 2 in Q57 format.
// output: a 64 bit integer in Q0 (no fraction).
// TODO: Mark const once we can use local variables in a const function.
#[allow(unused)]
fn bexp64(logq57: i64) -> i64 {
  let ipart = (logq57 >> 57) as i32;
  if ipart < 0 {
    return 0;
  }
  if ipart >= 63 {
    return 0x7FFFFFFFFFFFFFFF;
  }
  // z is the fractional part of the log in Q62 format.
  // We need 1 bit of headroom since the magnitude can get larger than 1
  //  during the iteration, and a sign bit.
  let mut z = logq57 - q57(ipart);
  let mut w: i64;
  if z != 0 {
    // Rust has 128 bit multiplies, so it should be possible to do this
    //  faster without losing accuracy.
    z <<= 5;
    // w is the exponential in Q61 format (since it also needs headroom and can
    //  get as large as 2.0); we could get another bit if we dropped the sign,
    //  but we'll recover that bit later anyway.
    // Ideally this should start out as
    //   \lim_{n->\infty} 2^{61}/\product_{i=1}^n \sqrt{1-2^{-2i}}
    //  but in order to guarantee convergence we have to repeat iterations 4,
    //  13 (=3*4+1), and 40 (=3*13+1, etc.), so it winds up somewhat larger.
    w = 0x26A3D0E401DD846D;
    let mut i: i64 = 0;
    loop {
      let mask = -((z < 0) as i64);
      w += ((w >> (i + 1)) + mask) ^ mask;
      z -= (ATANH_LOG2[i as usize] + mask) ^ mask;
      // Repeat iteration 4.
      if i >= 3 {
        break;
      }
      z *= 2;
      i += 1;
    }
    loop {
      let mask = -((z < 0) as i64);
      w += ((w >> (i + 1)) + mask) ^ mask;
      z -= (ATANH_LOG2[i as usize] + mask) ^ mask;
      // Repeat iteration 13.
      if i >= 12 {
        break;
      }
      z *= 2;
      i += 1;
    }
    while i < 32 {
      let mask = -((z < 0) as i64);
      w += ((w >> (i + 1)) + mask) ^ mask;
      z = (z - ((ATANH_LOG2[i as usize] + mask) ^ mask)) * 2;
      i += 1;
    }
    // Skip the remaining iterations unless we really require that much
    //  precision.
    // We could have bailed out earlier for smaller iparts, but that would
    //  require initializing w from a table, as the limit doesn't converge to
    //  61-bit precision until n=30.
    let mut wlo: i32 = 0;
    if ipart > 30 {
      // For these iterations, we just update the low bits, as the high bits
      //  can't possibly be affected.
      // OD_ATANH_LOG2 has also converged (it actually did so one iteration
      //  earlier, but that's no reason for an extra special case).
      loop {
        let mask = -((z < 0) as i64);
        wlo += (((w >> i) + mask) ^ mask) as i32;
        z -= (ATANH_LOG2[31] + mask) ^ mask;
        // Repeat iteration 40.
        if i >= 39 {
          break;
        }
        z *= 2;
        i += 1;
      }
      while i < 61 {
        let mask = -((z < 0) as i64);
        wlo += (((w >> i) + mask) ^ mask) as i32;
        z = (z - ((ATANH_LOG2[31] + mask) ^ mask)) * 2;
        i += 1;
      }
    }
    w = (w << 1) + (wlo as i64);
  } else {
    w = 1i64 << 62;
  }
  if ipart < 62 {
    w = ((w >> (61 - ipart)) + 1) >> 1;
  }
  w
}

// Computes the binary log of w.
// input: a 64-bit integer in Q0 (no fraction).
// output: a 64-bit log in Q57.
// TODO: Mark const once we can use local variables in a const function.
#[allow(unused)]
fn blog64(w: i64) -> i64 {
  let mut w = w;
  if w <= 0 {
    return -1;
  }
  let ipart = ilog64(w) - 1;
  if ipart > 61 {
    w >>= ipart - 61;
  } else {
    w <<= 61 - ipart;
  }
  // z is the fractional part of the log in Q61 format.
  let mut z: i64 = 0;
  if (w & (w - 1)) != 0 {
    // Rust has 128 bit multiplies, so it should be possible to do this
    //  faster without losing accuracy.
    // x and y are the cosh() and sinh(), respectively, in Q61 format.
    // We are computing z = 2*atanh(y/x) = 2*atanh((w - 1)/(w + 1)).
    let mut x = w + (1i64 << 61);
    let mut y = w - (1i64 << 61);
    for i in 0..4 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[i as usize] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    // Repeat iteration 4.
    for i in 3..13 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[i as usize] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    // Repeat iteration 13.
    for i in 12..32 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[i as usize] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    // OD_ATANH_LOG2 has converged.
    for i in 32..40 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[31] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    // Repeat iteration 40.
    for i in 39..62 {
      let mask = -((y < 0) as i64);
      z += ((ATANH_LOG2[31] >> i) + mask) ^ mask;
      let u = x >> (i + 1);
      x -= ((y >> (i + 1)) + mask) ^ mask;
      y -= (u + mask) ^ mask;
    }
    z = (z + 8) >> 4;
  }
  q57(ipart) + z
}

#[cfg(test)]
mod test {
  use super::{bexp64, blog64};

  #[test]
  fn blog64_vectors() {
    assert!(blog64(1793) == 0x159dc71e24d32daf);
    assert!(blog64(0x678dde6e5fd29f05) == 0x7d6373ad151ca685);
  }

  #[test]
  fn bexp64_vectors() {
    assert!(bexp64(0x159dc71e24d32daf) == 1793);
    assert!((bexp64(0x7d6373ad151ca685) - 0x678dde6e5fd29f05).abs() < 29);
  }

  #[test]
  fn blog64_bexp64_round_trip() {
    for a in 1..=std::u16::MAX as i64 {
      let b = std::i64::MAX / a;
      let (log_a, log_b, log_ab) = (blog64(a), blog64(b), blog64(a * b));
      assert!((log_a + log_b - log_ab).abs() < 4);
      assert!(bexp64(log_a) == a);
      assert!((bexp64(log_b) - b).abs() < 128);
      assert!((bexp64(log_ab) - a * b).abs() < 128);
    }
  }
}
<|endoftext|>


<commit_before>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

/*===============================================================================================*/
//! The logging module.
//!
//! It provides basic logging functionality.
/*===============================================================================================*/

extern crate log;

use std::boxed::Box;
use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::Write;

/*===============================================================================================*/
/*------LOGGER STRUCT----------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The logger struct
///
/// It provides basic logging capabilities, and is designed for use within ion.
pub struct Logger {

    // Private
    log_file: BufWriter <File>,
    log_to_console: bool
}

/*===============================================================================================*/
/*------LOGGER PUBLIC STATIC METHODS-------------------------------------------------------------*/
/*===============================================================================================*/

impl Logger {

    /// Initializes the logger
    ///
    /// This is required before any logging functions are performed.
    /// Any logging done beforehand will be ignored.
    ///
    /// # Arguments
    /// * `log_file_path` - The path to where the log will be saved
    /// * `log_to_console` - Whether the log output should also be printed to the console
    ///
    /// # Return value
    /// A result, returning an error on failure.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::util::Logger;
    /// #
    /// Logger::init ("LogFile.log", false);
    pub fn init (log_file_path: &str, log_to_console: bool) -> Result<(), log::SetLoggerError> {

        log::set_logger (|max_log_level| {

            if cfg! (debug_assertions) {
                max_log_level.set (log::LogLevelFilter::Debug);
            }

            else {
                max_log_level.set (log::LogLevelFilter::Info);
            }

            Box::new (Logger {log_file: BufWriter::new (File::create (&log_file_path).unwrap ()),
                              log_to_console: log_to_console})
        })
    }
}

/*===============================================================================================*/
/*------LOGGER PRIVATE METHODS-------------------------------------------------------------------*/
/*===============================================================================================*/

impl log::Log for Logger {

    fn enabled (&self, metadata: &log::LogMetadata) -> bool {

        if cfg! (debug_assertions) {
            return metadata.level () <= log::LogLevel::Debug;
        }

        metadata.level () <= log::LogLevel::Info
    }

/*-----------------------------------------------------------------------------------------------*/

    fn log (&self, record: &log::LogRecord) {

        let string_output = format! ("{} ({} : {}) - {}\n", record.level (),
                                                            record.location ().file (),
                                                            record.location ().line (),
                                                            record.args ());
        if self.log_to_console {
            print! ("{}", string_output);
        }

        self.log_file.get_ref ().write (string_output.as_bytes ()).unwrap ();
    }
}
<commit_msg>Some random change<commit_after>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

/*===============================================================================================*/
//! The logging module.
//!
//! It provides basic logging functionality.
/*===============================================================================================*/

extern crate log;

use std::boxed::Box;
use std::fs::File;
use std::io::BufWriter;
use std::io::prelude::Write;

/*===============================================================================================*/
/*------LOGGER STRUCT----------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The logger struct
///
/// It provides basic logging capabilities, and is designed for use within ion.
pub struct Logger {

    // Private
    log_file: BufWriter <File>,
    log_to_console: bool
}

/*===============================================================================================*/
/*------LOGGER PUBLIC STATIC METHODS-------------------------------------------------------------*/
/*===============================================================================================*/

impl Logger {

    /// Initializes the logger
    ///
    /// This is required before any logging functions are performed.
    /// Any logging done beforehand will be ignored.
    ///
    /// # Arguments
    /// * `log_file_path` - The path to where the log will be saved
    /// * `log_to_console` - Whether the log output should also be printed to the console
    ///
    /// # Return value
    /// A result, returning an error on failure.
    ///
    /// # Examples
    /// ```
    /// # use ion_core::util::Logger;
    /// #
    /// Logger::init ("LogFile.log", false);
    pub fn init (log_file_path: &str, log_to_console: bool) -> Result<(), log::SetLoggerError> {

        log::set_logger (|max_log_level| {

            if cfg! (debug_assertions) {
                max_log_level.set (log::LogLevelFilter::Debug);
            }

            else {
                max_log_level.set (log::LogLevelFilter::Info);
            }

            Box::new (Logger {log_file: BufWriter::new (File::create (&log_file_path).unwrap ()),
                              log_to_console: log_to_console})
        })
    }
}

/*===============================================================================================*/
/*------LOGGER PRIVATE METHODS-------------------------------------------------------------------*/
/*===============================================================================================*/

impl log::Log for Logger {

    fn enabled (&self, metadata: &log::LogMetadata) -> bool {

        if cfg! (debug_assertions) {
            return metadata.level () <= log::LogLevel::Debug;
        }

        metadata.level () <= log::LogLevel::Info
    }

/*-----------------------------------------------------------------------------------------------*/

    fn log (&self, record: &log::LogRecord) {

        let string_output = format! ("{} ({} : {}) - {}\n", record.level (),
                                                            record.location ().file (),
                                                            record.location ().line (),
                                                            record.args ());
        if self.log_to_console {
            print! ("{}", string_output);
        }

        self.log_file.get_ref ().write (string_output.as_bytes ()).unwrap ();
    }
}
<|endoftext|>


<commit_before>// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com

// Seeking "vehicle" follows the mouse position

// Implements Craig Reynold's autonomous steering behaviors
// One vehicle "seeks"
// See: http://www.red3d.com/cwr/
extern crate nannou;

use nannou::prelude::*;

fn main() {
    nannou::app(model, event, view).run();
}

struct Model {
    vehicle: Vehicle,
}

struct Vehicle {
    position: Vector2,
    velocity: Vector2,
    acceleration: Vector2,
    r: f32,
    // Maximum steering force
    max_force: f32,
    // Maximum speed
    max_speed: f32,
}

impl Vehicle {
    fn new(x: f32, y: f32) -> Self {
        let position = Vector2::new(x, y);
        let velocity = Vector2::new(0.0, -2.0);
        let acceleration = Vector2::new(0.0, 0.0);
        let r = 6.0;
        let max_force = 0.1;
        let max_speed = 4.0;

        Vehicle {
            position,
            velocity,
            acceleration,
            r,
            max_force,
            max_speed,
        }
    }

    fn apply_force(&mut self, force: Vector2) {
        // We could add mass here if we want A = F / M
        self.acceleration += force;
    }
}

fn model(app: &App) -> Model {
    let _window = app.new_window().with_dimensions(640, 360).build().unwrap();
    let middle = app.window_rect().xy();
    let vehicle = Vehicle::new(middle.x, middle.y);
    Model { vehicle }
}

fn event(app: &App, mut m: Model, event: Event) -> Model {
    {
        let Model {
            ref mut vehicle, ..
        } = m;
        let mouse = Vector2::new(app.mouse.x, app.mouse.y);
        // update gets called just before view every frame
        if let Event::Update(_update) = event {
            seek(vehicle, mouse);
        }
    }
    m
}

fn view(app: &App, m: &Model, frame: Frame) -> Frame {
    // Begin drawing
    let draw = app.draw();
    draw.background().color(WHITE);

    let mouse = Vector2::new(app.mouse.x, app.mouse.y);

    draw.ellipse()
        // Missing Stroke
        .x_y(mouse.x, mouse.y)
        .radius(48.0)
        .color(Rgb::new(0.78, 0.78, 0.78));

    // Write the result of our drawing to the window's OpenGL frame.
    draw.to_frame(app, &frame).unwrap();

    // Return the drawn frame.
    frame
}

// A method that calculates a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
fn seek(vehicle: &mut Vehicle, target: Vector2) {
    let steer = {
        let Vehicle {
            ref position,
            ref velocity,
            ref max_speed,
            ref max_force,
            ..
        } = vehicle;
        // A vector pointing from the position to the target
        // Scale to maximum speed
        let desired = (target - *position).with_magnitude(*max_speed);

        // Steering = Desired minus velocity
        // Limit to maximum steering force
        (desired - *velocity).limit_magnitude(*max_force)
    };

    vehicle.apply_force(steer);
}
<commit_msg>added vehicle<commit_after>// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com

// Seeking "vehicle" follows the mouse position

// Implements Craig Reynold's autonomous steering behaviors
// One vehicle "seeks"
// See: http://www.red3d.com/cwr/
extern crate nannou;

use nannou::prelude::*;
use nannou::Draw;

fn main() {
    nannou::app(model, event, view).run();
}

struct Model {
    vehicle: Vehicle,
}

struct Vehicle {
    position: Vector2,
    velocity: Vector2,
    acceleration: Vector2,
    r: f32,
    // Maximum steering force
    max_force: f32,
    // Maximum speed
    max_speed: f32,
}

impl Vehicle {
    fn new(x: f32, y: f32) -> Self {
        let position = Vector2::new(x, y);
        let velocity = Vector2::new(0.0, -2.0);
        let acceleration = Vector2::new(0.0, 0.0);
        let r = 6.0;
        let max_force = 0.1;
        let max_speed = 4.0;

        Vehicle {
            position,
            velocity,
            acceleration,
            r,
            max_force,
            max_speed,
        }
    }

    // Method to update position
    fn update(&mut self) {
        // Update velocity
        self.velocity += self.acceleration;
        // Limit speed
        self.velocity.limit_magnitude(self.max_speed);
        self.position += self.velocity;
        // Reset accelerationelertion to 0 each cycle
        self.acceleration *= 0.0;
    }

    fn apply_force(&mut self, force: Vector2) {
        // We could add mass here if we want A = F / M
        self.acceleration += force;
    }
}

fn model(app: &App) -> Model {
    let _window = app.new_window().with_dimensions(640, 360).build().unwrap();
    let middle = app.window_rect().xy();
    let vehicle = Vehicle::new(middle.x, middle.y);
    Model { vehicle }
}

fn event(app: &App, mut m: Model, event: Event) -> Model {
    {
        let Model {
            ref mut vehicle, ..
        } = m;
        let mouse = Vector2::new(app.mouse.x, app.mouse.y);
        // update gets called just before view every frame
        if let Event::Update(_update) = event {
            seek(vehicle, mouse);
            vehicle.update();
        }
    }
    m
}

fn view(app: &App, m: &Model, frame: Frame) -> Frame {
    // Begin drawing
    let draw = app.draw();
    draw.background().color(WHITE);

    let mouse = Vector2::new(app.mouse.x, app.mouse.y);

    draw.ellipse()
        // Missing Stroke
        .x_y(mouse.x, mouse.y)
        .radius(48.0)
        .color(Rgb::new(0.78, 0.78, 0.78));
    display(&m.vehicle, &draw);

    // Write the result of our drawing to the window's OpenGL frame.
    draw.to_frame(app, &frame).unwrap();

    // Return the drawn frame.
    frame
}

// A method that calculates a steering force towards a target
// STEER = DESIRED MINUS VELOCITY
fn seek(vehicle: &mut Vehicle, target: Vector2) {
    let steer = {
        let Vehicle {
            ref position,
            ref velocity,
            ref max_speed,
            ref max_force,
            ..
        } = vehicle;
        // A vector pointing from the position to the target
        // Scale to maximum speed
        let desired = (target - *position).with_magnitude(*max_speed);

        // Steering = Desired minus velocity
        // Limit to maximum steering force
        (desired - *velocity).limit_magnitude(*max_force)
    };

    vehicle.apply_force(steer);
}

fn display(vehicle: &Vehicle, draw: &Draw) {
    let Vehicle {
        position,
        velocity,
        r,
        ..
    } = vehicle;
    // Draw a triangle rotated in the direction of velocity
    // This calculation is wrong
    let theta = velocity.angle() + 3.0 * (PI / 2.0);
    let points = vec![
        pt3(0.0, -r * 2.0, 0.0),
        pt3(-r, r * 2.0, 0.0),
        pt3(*r, r * 2.0, 0.0),
    ];
    draw.polygon()
        .points(points)
        .xy(*position)
        .color(DARK_GREY)
        //stroke(0);
        //strokeWeight(1);
        .rotate(theta);
}
<|endoftext|>


<commit_before>mod move_fn;
mod spatial_arg;
mod spatial_ops;

use std::convert::TryFrom;

use smallvec::SmallVec;

use super::ParseErrF;
pub(super) use errors::SpatialFnErr;
pub(super) use move_fn::MoveFn;
pub(super) use spatial_arg::SpatialArg;
pub(in crate::agent) use spatial_ops::SpatialOps;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(in crate::agent) struct Point(u64, u64, u64);

impl TryFrom<&str> for Point {
    type Error = ParseErrF;

    fn try_from(input: &str) -> Result<Self, Self::Error> {
        let p: Result<SmallVec<[u64; 3]>, _> = input
            .split('.')
            .map(|p| p.parse())
            .collect::<Result<_, _>>();
        match p {
            Ok(val) if val.len() == 3 => Ok(Point(val[0], val[1], val[2])),
            _ => Err(ParseErrF::WrongDef),
        }
    }
}

impl TryFrom<&[u8]> for Point {
    type Error = ParseErrF;

    fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
        let input_str = std::str::from_utf8(input).unwrap();
        Self::try_from(input_str)
    }
}

mod errors {
    use crate::agent::ParseErrF;

    #[derive(Debug, PartialEq, Eq)]
    pub enum SpatialFnErr {
        MoreThanOneSpatialArg,
        WrongDef,
    }

    impl Into<ParseErrF> for SpatialFnErr {
        fn into(self) -> ParseErrF {
            ParseErrF::SpatialFnErr(self)
        }
    }
}
<commit_msg>chang epoint type to i64<commit_after>mod move_fn;
mod spatial_arg;
mod spatial_ops;

use std::convert::TryFrom;

use smallvec::SmallVec;

use super::ParseErrF;
pub(super) use errors::SpatialFnErr;
pub(super) use move_fn::MoveFn;
pub(super) use spatial_arg::SpatialArg;
pub(in crate::agent) use spatial_ops::SpatialOps;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub(in crate::agent) struct Point(i64, i64, i64);

impl TryFrom<&str> for Point {
    type Error = ParseErrF;

    fn try_from(input: &str) -> Result<Self, Self::Error> {
        let p: Result<SmallVec<[i64; 3]>, _> = input
            .split('.')
            .map(|p| p.parse())
            .collect::<Result<_, _>>();
        match p {
            Ok(val) if val.len() == 3 => Ok(Point(val[0], val[1], val[2])),
            _ => Err(ParseErrF::WrongDef),
        }
    }
}

impl TryFrom<&[u8]> for Point {
    type Error = ParseErrF;

    fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
        let input_str = std::str::from_utf8(input).unwrap();
        Self::try_from(input_str)
    }
}

mod errors {
    use crate::agent::ParseErrF;

    #[derive(Debug, PartialEq, Eq)]
    pub enum SpatialFnErr {
        MoreThanOneSpatialArg,
        WrongDef,
    }

    impl Into<ParseErrF> for SpatialFnErr {
        fn into(self) -> ParseErrF {
            ParseErrF::SpatialFnErr(self)
        }
    }
}
<|endoftext|>