<commit_before>//! Cost calculation logic

use bigint::{M256, U256, Gas, Address};

#[cfg(feature = "std")] use std::cmp::max;
#[cfg(not(feature = "std"))] use core::cmp::max;

use ::{Memory, Instruction, Patch};
use super::State;

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_JUMPDEST: usize = 1;
const G_SNOOP: usize = 200;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SRESET: isize = 15000;
const R_SCLEAR: isize = 19800;
const R_SNOOP: isize = 4800;
const R_SUICIDE: isize = 24000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSIT: usize = 200;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_MEMORY: usize = 3;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;
const G_EXTCODEHASH: usize = 400;

fn sstore_cost<M: Memory + Default, P: Patch>(state: &State<M, P>) -> Gas {
    let index: U256 = state.stack.peek(0).unwrap().into();
    let value = state.stack.peek(1).unwrap();
    let address = state.context.address;

    if P::has_reduced_sstore_gas_metering() {
        let orig = state.account_state.storage_read_orig(address, index).unwrap();
        let current = state.account_state.storage_read(address, index).unwrap();
        if value == current {
            G_SNOOP.into()
        } else {
            if orig == current {
                if orig == M256::zero() {
                    G_SSET.into()
                } else {
                    G_SRESET.into()
                }
            } else {
                G_SNOOP.into()
            }
        }
    } else {
        if value != M256::zero() && state.account_state.storage_read(address, index).unwrap() == M256::zero() {
            G_SSET.into()
        } else {
            G_SRESET.into()
        }
    }
}

fn call_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    P::gas_call() + xfer_cost(machine, instruction) + new_cost(machine, instruction)
}

fn xfer_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    if instruction == &Instruction::CALL || instruction == &Instruction::CALLCODE {
        let val = machine.stack.peek(2).unwrap();
        if val != M256::zero() {
            G_CALLVALUE.into()
        } else {
            Gas::zero()
        }
    } else {
        Gas::zero()
    }
}

fn new_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    let address: Address = machine.stack.peek(1).unwrap().into();
    if (instruction == &Instruction::CALL || instruction == &Instruction::STATICCALL) && !machine.account_state.exists(address).unwrap() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    }
}

fn suicide_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>) -> Gas {
    let address: Address = machine.stack.peek(0).unwrap().into();
    let suicide_gas_topup = if !machine.account_state.exists(address).unwrap() {
        P::gas_suicide_new_account()
    } else {
        Gas::zero()
    };
    P::gas_suicide() + suicide_gas_topup
}

fn memory_expand(current: Gas, from: Gas, len: Gas) -> Gas {
    if len == Gas::zero() {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

/// Calculate code deposit cost for a ContractCreation transaction.
pub fn code_deposit_gas(len: usize) -> Gas {
    Gas::from(G_CODEDEPOSIT) * Gas::from(len)
}

/// Calculate the memory gas from the memory cost.
pub fn memory_gas(a: Gas) -> Gas {
    Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)
}

/// Calculate the memory cost. This is the same as the active memory
/// length in the Yellow Paper.
pub fn memory_cost<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    let stack = &state.stack;

    let current = state.memory_cost;
    match instruction {
        Instruction::SHA3 | Instruction::RETURN | Instruction::REVERT | Instruction::LOG(_) => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(1).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CODECOPY | Instruction::CALLDATACOPY | Instruction::RETURNDATACOPY => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::EXTCODECOPY => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(3).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::MLOAD | Instruction::MSTORE => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(32u64))
        },
        Instruction::MSTORE8 => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(1u64))
        },
        Instruction::CREATE | Instruction::CREATE2 => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CALL | Instruction::CALLCODE => {
            let in_from: U256 = stack.peek(3).unwrap().into();
            let in_len: U256 = stack.peek(4).unwrap().into();
            let out_from: U256 = stack.peek(5).unwrap().into();
            let out_len: U256 = stack.peek(6).unwrap().into();
            memory_expand(memory_expand(current, Gas::from(in_from), Gas::from(in_len)),
                          Gas::from(out_from), Gas::from(out_len))
        },
        _ => {
            current
        }
    }
}

/// Calculate the gas cost.
pub fn gas_cost<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::CALL => call_cost::<M, P>(state, &Instruction::CALL),
        Instruction::CALLCODE => call_cost::<M, P>(state, &Instruction::CALLCODE),
        Instruction::DELEGATECALL => call_cost::<M, P>(state, &Instruction::DELEGATECALL),
        Instruction::STATICCALL => call_cost::<M, P>(state, &Instruction::STATICCALL),
        Instruction::SUICIDE => suicide_cost::<M, P>(state),
        Instruction::SSTORE => sstore_cost(state),

        Instruction::SHA3 => {
            let len = state.stack.peek(1).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }
        },

        Instruction::LOG(v) => {
            let len = state.stack.peek(1).unwrap();
            Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)
        },

        Instruction::EXTCODECOPY => {
            let len = state.stack.peek(3).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            P::gas_extcode() + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }
        },

        Instruction::CALLDATACOPY | Instruction::CODECOPY | Instruction::RETURNDATACOPY => {
            let len = state.stack.peek(2).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }
        },

        Instruction::EXP => {
            if state.stack.peek(1).unwrap() == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + P::gas_expbyte() * (Gas::from(1u64) + Gas::from(state.stack.peek(1).unwrap().log2floor()) / Gas::from(8u64))
            }
        }

        Instruction::CREATE | Instruction::CREATE2 => G_CREATE.into(),
        Instruction::JUMPDEST => G_JUMPDEST.into(),
        Instruction::SLOAD => P::gas_sload(),

        // W_zero
        Instruction::STOP | Instruction::RETURN | Instruction::REVERT
            => G_ZERO.into(),

        // W_base
        Instruction::ADDRESS | Instruction::ORIGIN | Instruction::CALLER |
        Instruction::CALLVALUE | Instruction::CALLDATASIZE | Instruction::RETURNDATASIZE |
        Instruction::CODESIZE | Instruction::GASPRICE | Instruction::COINBASE |
        Instruction::TIMESTAMP | Instruction::NUMBER | Instruction::DIFFICULTY |
        Instruction::GASLIMIT | Instruction::POP | Instruction::PC |
        Instruction::MSIZE | Instruction::GAS
            => G_BASE.into(),

        // W_verylow
        Instruction::ADD | Instruction::SUB | Instruction::NOT | Instruction::LT |
        Instruction::GT | Instruction::SLT | Instruction::SGT | Instruction::EQ |
        Instruction::ISZERO | Instruction::AND | Instruction::OR | Instruction::XOR |
        Instruction::BYTE | Instruction::CALLDATALOAD | Instruction::MLOAD |
        Instruction::MSTORE | Instruction::MSTORE8 | Instruction::PUSH(_) |
        Instruction::DUP(_) | Instruction::SWAP(_) |
        Instruction::SHL | Instruction::SHR | Instruction::SAR
            => G_VERYLOW.into(),

        // W_low
        Instruction::MUL | Instruction::DIV | Instruction::SDIV | Instruction::MOD |
        Instruction::SMOD | Instruction::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Instruction::ADDMOD | Instruction::MULMOD | Instruction::JUMP
            => G_MID.into(),

        // W_high
        Instruction::JUMPI => G_HIGH.into(),

        // W_extcode
        Instruction::EXTCODESIZE => P::gas_extcode(),
        Instruction::BALANCE => P::gas_balance(),
        Instruction::BLOCKHASH => G_BLOCKHASH.into(),
        Instruction::EXTCODEHASH => G_EXTCODEHASH.into(),
    }
}

/// Raise gas stipend for CALL and CALLCODE instruction.
pub fn gas_stipend<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE => {
            let value = state.stack.peek(2).unwrap();

            if value != M256::zero() {
                G_CALLSTIPEND.into()
            } else {
                Gas::zero()
            }
        },
        _ => Gas::zero(),
    }
}

/// Calculate the refunded gas.
pub fn gas_refund<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> isize {
    match instruction {
        Instruction::SSTORE => {
            let index: U256 = state.stack.peek(0).unwrap().into();
            let value = state.stack.peek(1).unwrap();
            let address = state.context.address;

            if P::has_reduced_sstore_gas_metering() {
                let orig = state.account_state.storage_read_orig(address, index).unwrap();
                let current = state.account_state.storage_read(address, index).unwrap();
                let mut refund = 0;

                if value != current {
                    if orig == current {
                        if orig != M256::zero() {
                            refund += R_SRESET;
                        }
                    } else {
                        if orig != M256::zero() {
                            if current == M256::zero() {
                                refund -= R_SRESET;
                            }
                            if value == M256::zero() {
                                refund += R_SRESET;
                            }
                        }
                        if orig == value {
                            if orig == M256::zero() {
                                refund += R_SCLEAR;
                            } else {
                                refund += R_SNOOP;
                            }
                        }
                    }
                }

                refund
            } else {
                if value == M256::zero() && state.account_state.storage_read(address, index).unwrap() != M256::zero() {
                    R_SRESET
                } else {
                    0
                }
            }
        },
        Instruction::SUICIDE => {
            if state.removed.contains(&state.context.address) {
                0
            } else {
                R_SUICIDE
            }
        },
        _ => 0
    }
}

pub trait AddRefund {
    fn add_refund(self, refund: isize) -> Self;
}

impl AddRefund for Gas {
    fn add_refund(self, refund: isize) -> Self {
        let (refund, sign) = if refund < 0 {
            (0 - refund, true)
        } else {
            (refund, false)
        };

        if sign {
            self - Gas::from(refund as usize)
        } else {
            self + Gas::from(refund as usize)
        }
    }
}
<commit_msg>corrected gas price calculation<commit_after>//! Cost calculation logic

use bigint::{M256, U256, Gas, Address};

#[cfg(feature = "std")] use std::cmp::max;
#[cfg(not(feature = "std"))] use core::cmp::max;

use ::{Memory, Instruction, Patch};
use super::State;

const G_ZERO: usize = 0;
const G_BASE: usize = 2;
const G_VERYLOW: usize = 3;
const G_LOW: usize = 5;
const G_MID: usize = 8;
const G_HIGH: usize = 10;
const G_JUMPDEST: usize = 1;
const G_SNOOP: usize = 200;
const G_SSET: usize = 20000;
const G_SRESET: usize = 5000;
const R_SRESET: isize = 15000;
const R_SCLEAR: isize = 19800;
const R_SNOOP: isize = 4800;
const R_SUICIDE: isize = 24000;
const G_CREATE: usize = 32000;
const G_CODEDEPOSIT: usize = 200;
const G_CALLVALUE: usize = 9000;
const G_CALLSTIPEND: usize = 2300;
const G_NEWACCOUNT: usize = 25000;
const G_EXP: usize = 10;
const G_MEMORY: usize = 3;
const G_LOG: usize = 375;
const G_LOGDATA: usize = 8;
const G_LOGTOPIC: usize = 375;
const G_SHA3: usize = 30;
const G_SHA3WORD: usize = 6;
const G_COPY: usize = 3;
const G_BLOCKHASH: usize = 20;
const G_EXTCODEHASH: usize = 400;

fn sstore_cost<M: Memory + Default, P: Patch>(state: &State<M, P>) -> Gas {
    let index: U256 = state.stack.peek(0).unwrap().into();
    let value = state.stack.peek(1).unwrap();
    let address = state.context.address;

    if P::has_reduced_sstore_gas_metering() {
        let orig = state.account_state.storage_read_orig(address, index).unwrap();
        let current = state.account_state.storage_read(address, index).unwrap();
        if value == current {
            G_SNOOP.into()
        } else {
            if orig == current {
                if orig == M256::zero() {
                    G_SSET.into()
                } else {
                    G_SRESET.into()
                }
            } else {
                G_SNOOP.into()
            }
        }
    } else {
        if value != M256::zero() && state.account_state.storage_read(address, index).unwrap() == M256::zero() {
            G_SSET.into()
        } else {
            G_SRESET.into()
        }
    }
}

fn call_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    P::gas_call() + xfer_cost(machine, instruction) + new_cost(machine, instruction)
}

fn xfer_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    if instruction == &Instruction::CALL || instruction == &Instruction::CALLCODE {
        let val = machine.stack.peek(2).unwrap();
        if val != M256::zero() {
            G_CALLVALUE.into()
        } else {
            Gas::zero()
        }
    } else {
        Gas::zero()
    }
}

fn new_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>, instruction: &Instruction) -> Gas {
    let address: Address = machine.stack.peek(1).unwrap().into();
    if (instruction == &Instruction::CALL || instruction == &Instruction::STATICCALL) && !machine.account_state.exists(address).unwrap() {
        Gas::from(G_NEWACCOUNT)
    } else {
        Gas::zero()
    }
}

fn suicide_cost<M: Memory + Default, P: Patch>(machine: &State<M, P>) -> Gas {
    let address: Address = machine.stack.peek(0).unwrap().into();
    let suicide_gas_topup = if !machine.account_state.exists(address).unwrap() {
        P::gas_suicide_new_account()
    } else {
        Gas::zero()
    };
    P::gas_suicide() + suicide_gas_topup
}

fn memory_expand(current: Gas, from: Gas, len: Gas) -> Gas {
    if len == Gas::zero() {
        return current;
    }

    let rem = (from + len) % Gas::from(32u64);
    let new = if rem == Gas::zero() {
        (from + len) / Gas::from(32u64)
    } else {
        (from + len) / Gas::from(32u64) + Gas::from(1u64)
    };
    max(current, new)
}

/// Calculate code deposit cost for a ContractCreation transaction.
pub fn code_deposit_gas(len: usize) -> Gas {
    Gas::from(G_CODEDEPOSIT) * Gas::from(len)
}

/// Calculate the memory gas from the memory cost.
pub fn memory_gas(a: Gas) -> Gas {
    Gas::from(G_MEMORY) * a + a * a / Gas::from(512u64)
}

/// Calculate the memory cost. This is the same as the active memory
/// length in the Yellow Paper.
pub fn memory_cost<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    let stack = &state.stack;

    let current = state.memory_cost;
    match instruction {
        Instruction::SHA3 | Instruction::RETURN | Instruction::REVERT | Instruction::LOG(_) => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(1).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CODECOPY | Instruction::CALLDATACOPY | Instruction::RETURNDATACOPY => {
            let from: U256 = stack.peek(0).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::EXTCODECOPY => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(3).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::MLOAD | Instruction::MSTORE => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(32u64))
        },
        Instruction::MSTORE8 => {
            let from: U256 = stack.peek(0).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(1u64))
        },
        Instruction::CREATE | Instruction::CREATE2 => {
            let from: U256 = stack.peek(1).unwrap().into();
            let len: U256 = stack.peek(2).unwrap().into();
            memory_expand(current, Gas::from(from), Gas::from(len))
        },
        Instruction::CALL | Instruction::CALLCODE => {
            let in_from: U256 = stack.peek(3).unwrap().into();
            let in_len: U256 = stack.peek(4).unwrap().into();
            let out_from: U256 = stack.peek(5).unwrap().into();
            let out_len: U256 = stack.peek(6).unwrap().into();
            memory_expand(memory_expand(current, Gas::from(in_from), Gas::from(in_len)),
                          Gas::from(out_from), Gas::from(out_len))
        },
        _ => {
            current
        }
    }
}

/// Calculate the gas cost.
pub fn gas_cost<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::CALL => call_cost::<M, P>(state, &Instruction::CALL),
        Instruction::CALLCODE => call_cost::<M, P>(state, &Instruction::CALLCODE),
        Instruction::DELEGATECALL => call_cost::<M, P>(state, &Instruction::DELEGATECALL),
        Instruction::STATICCALL => call_cost::<M, P>(state, &Instruction::STATICCALL),
        Instruction::SUICIDE => suicide_cost::<M, P>(state),
        Instruction::SSTORE => sstore_cost(state),

        Instruction::SHA3 => {
            let len = state.stack.peek(1).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            Gas::from(G_SHA3) + Gas::from(G_SHA3WORD) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }
        },

        Instruction::LOG(v) => {
            let len = state.stack.peek(1).unwrap();
            Gas::from(G_LOG) + Gas::from(G_LOGDATA) * Gas::from(len) + Gas::from(G_LOGTOPIC) * Gas::from(v)
        },

        Instruction::EXTCODECOPY => {
            let len = state.stack.peek(3).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            P::gas_extcode() + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }
        },

        Instruction::CALLDATACOPY | Instruction::CODECOPY | Instruction::RETURNDATACOPY => {
            let len = state.stack.peek(2).unwrap();
            let wordd = Gas::from(len) / Gas::from(32u64);
            let wordr = Gas::from(len) % Gas::from(32u64);
            Gas::from(G_VERYLOW) + Gas::from(G_COPY) * if wordr == Gas::zero() { wordd } else { wordd + Gas::from(1u64) }
        },

        Instruction::EXP => {
            if state.stack.peek(1).unwrap() == M256::zero() {
                Gas::from(G_EXP)
            } else {
                Gas::from(G_EXP) + P::gas_expbyte() * (Gas::from(1u64) + Gas::from(state.stack.peek(1).unwrap().log2floor()) / Gas::from(8u64))
            }
        }

        Instruction::CREATE => G_CREATE.into(),
        Instruction::CREATE2 => {
            let base = G_CREATE;
            let init_code_len = state.stack.peek(2).unwrap().as_u64();
            let sha_addup = G_SHA3WORD * (init_code_len as f32 / 32.0).ceil() as usize;
            (base + sha_addup).into()
        },
        Instruction::JUMPDEST => G_JUMPDEST.into(),
        Instruction::SLOAD => P::gas_sload(),

        // W_zero
        Instruction::STOP | Instruction::RETURN | Instruction::REVERT
            => G_ZERO.into(),

        // W_base
        Instruction::ADDRESS | Instruction::ORIGIN | Instruction::CALLER |
        Instruction::CALLVALUE | Instruction::CALLDATASIZE | Instruction::RETURNDATASIZE |
        Instruction::CODESIZE | Instruction::GASPRICE | Instruction::COINBASE |
        Instruction::TIMESTAMP | Instruction::NUMBER | Instruction::DIFFICULTY |
        Instruction::GASLIMIT | Instruction::POP | Instruction::PC |
        Instruction::MSIZE | Instruction::GAS
            => G_BASE.into(),

        // W_verylow
        Instruction::ADD | Instruction::SUB | Instruction::NOT | Instruction::LT |
        Instruction::GT | Instruction::SLT | Instruction::SGT | Instruction::EQ |
        Instruction::ISZERO | Instruction::AND | Instruction::OR | Instruction::XOR |
        Instruction::BYTE | Instruction::CALLDATALOAD | Instruction::MLOAD |
        Instruction::MSTORE | Instruction::MSTORE8 | Instruction::PUSH(_) |
        Instruction::DUP(_) | Instruction::SWAP(_) |
        Instruction::SHL | Instruction::SHR | Instruction::SAR
            => G_VERYLOW.into(),

        // W_low
        Instruction::MUL | Instruction::DIV | Instruction::SDIV | Instruction::MOD |
        Instruction::SMOD | Instruction::SIGNEXTEND
            => G_LOW.into(),

        // W_mid
        Instruction::ADDMOD | Instruction::MULMOD | Instruction::JUMP
            => G_MID.into(),

        // W_high
        Instruction::JUMPI => G_HIGH.into(),

        // W_extcode
        Instruction::EXTCODESIZE => P::gas_extcode(),
        Instruction::BALANCE => P::gas_balance(),
        Instruction::BLOCKHASH => G_BLOCKHASH.into(),
        Instruction::EXTCODEHASH => G_EXTCODEHASH.into(),
    }
}

/// Raise gas stipend for CALL and CALLCODE instruction.
pub fn gas_stipend<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> Gas {
    match instruction {
        Instruction::CALL | Instruction::CALLCODE => {
            let value = state.stack.peek(2).unwrap();

            if value != M256::zero() {
                G_CALLSTIPEND.into()
            } else {
                Gas::zero()
            }
        },
        _ => Gas::zero(),
    }
}

/// Calculate the refunded gas.
pub fn gas_refund<M: Memory + Default, P: Patch>(instruction: Instruction, state: &State<M, P>) -> isize {
    match instruction {
        Instruction::SSTORE => {
            let index: U256 = state.stack.peek(0).unwrap().into();
            let value = state.stack.peek(1).unwrap();
            let address = state.context.address;

            if P::has_reduced_sstore_gas_metering() {
                let orig = state.account_state.storage_read_orig(address, index).unwrap();
                let current = state.account_state.storage_read(address, index).unwrap();
                let mut refund = 0;

                if value != current {
                    if orig == current {
                        if orig != M256::zero() {
                            refund += R_SRESET;
                        }
                    } else {
                        if orig != M256::zero() {
                            if current == M256::zero() {
                                refund -= R_SRESET;
                            }
                            if value == M256::zero() {
                                refund += R_SRESET;
                            }
                        }
                        if orig == value {
                            if orig == M256::zero() {
                                refund += R_SCLEAR;
                            } else {
                                refund += R_SNOOP;
                            }
                        }
                    }
                }

                refund
            } else {
                if value == M256::zero() && state.account_state.storage_read(address, index).unwrap() != M256::zero() {
                    R_SRESET
                } else {
                    0
                }
            }
        },
        Instruction::SUICIDE => {
            if state.removed.contains(&state.context.address) {
                0
            } else {
                R_SUICIDE
            }
        },
        _ => 0
    }
}

pub trait AddRefund {
    fn add_refund(self, refund: isize) -> Self;
}

impl AddRefund for Gas {
    fn add_refund(self, refund: isize) -> Self {
        let (refund, sign) = if refund < 0 {
            (0 - refund, true)
        } else {
            (refund, false)
        };

        if sign {
            self - Gas::from(refund as usize)
        } else {
            self + Gas::from(refund as usize)
        }
    }
}
<|endoftext|>


<commit_before>//! Exposes the JavaScript event loop for scheduling asynchronous events.
//!
//! The [_event loop_][event-loop] is how Node.js provides JavaScript programs
//! access to concurrent events such as the completion of [file][fs] or
//! [network][net] operations, scheduled [timers][timer], or receiving messages
//! from other [processes][process].
//!
//! When an asynchronous operation is started from JavaScript, it registers
//! a JavaScript callback function to wait for the operation to complete. When
//! the operation completes, the callback and the result data are added to an
//! internal _event queue_ in the Node.js runtime so that the event can be
//! processed in order.
//!
//! The event loop processes completed events one at a time in the JavaScript
//! execution thread by calling the registered callback function with its result
//! value as an argument.
//!
//! ## Creating Custom Events
//!
//! This module allows Neon programs to create new types of concurrent events
//! in Rust and expose them to JavaScript as asynchronous functions.
//!
//! A common use for custom events is to run expensive or long-lived
//! computations in a background thread without blocking the JavaScript
//! thread. For example, using the [`psd` crate][psd-crate], a Neon program could
//! asynchronously parse (potentially large) [PSD files][psd-file] in a
//! background thread:
//!
//! ```
//! # #[cfg(feature = "napi-1")] {
//! # use neon::prelude::*;
//! #
//! # fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) { }
//! #
//! fn parse_async(mut cx: FunctionContext) -> JsResult<JsUndefined> {
//!     // The types `String`, `Root<JsFunction>`, and `EventQueue` can all be
//!     // sent across threads.
//!     let filename = cx.argument::<JsString>(0)?.value(&mut cx);
//!     let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
//!     let queue = cx.queue();
//!
//!     // Spawn a thread to complete the execution. This will _not_ block the
//!     // JavaScript event loop.
//!     std::thread::spawn(move || {
//!         // Do the heavy lifting inside the background thread.
//!         parse(filename, callback, queue);
//!     });
//!
//!     Ok(cx.undefined())
//! }
//! # }
//! ```
//!
//! (Note that this usage of [`spawn`](std::thread::spawn) makes use of Rust's
//! [`move`][move] syntax to transfer ownership of data to the background
//! thread.)
//!
//! Upon completion of its task, the background thread can use the JavaScript
//! callback and the event queue to notify the main thread of the result:
//!
//! ```
//! # extern crate psd;
//! # extern crate failure;
//! #
//! # #[cfg(feature = "napi-1")] fn main() {
//! # use neon::prelude::*;
//! # use psd::Psd;
//! # use failure::Error;
//! #
//! fn psd_from_filename(filename: String) -> Result<Psd, Error> {
//!     Psd::from_bytes(&std::fs::read(&filename)?)
//! }
//!
//! fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) {
//!     let result = psd_from_filename(filename);
//!
//!     // Send a closure as a task to be executed by the JavaScript event
//!     // queue. This _will_ block the event queue while executing.
//!     queue.send(move |mut cx| {
//!         let callback = callback.into_inner(&mut cx);
//!         let this = cx.undefined();
//!         let null = cx.null();
//!         let args = match result {
//!             Ok(psd) => {
//!                 // Extract data from the parsed file.
//!                 let width = cx.number(psd.width());
//!                 let height = cx.number(psd.height());
//!
//!                 // Save the data in a result object.
//!                 let obj = cx.empty_object();
//!                 obj.set(&mut cx, "width", width)?;
//!                 obj.set(&mut cx, "height", height)?;
//!                 vec![
//!                     cx.null().upcast::<JsValue>(),
//!                     obj.upcast(),
//!                 ]
//!             }
//!             Err(_) => {
//!                 // A full implementation would provide
//!                 // more detailed error diagnostics.
//!                 let err = cx.string("PSD parse error");
//!                 vec![
//!                     err.upcast::<JsValue>(),
//!                 ]
//!             }
//!         };
//!
//!         callback.call(&mut cx, this, args)?;
//!
//!         Ok(())
//!     });
//! }
//! # }
//! ```
//!
//! ## See also
//!
//! 1. Panu Pitkamaki. [Event loop from 10,000ft][event-loop].
//!
//! [event-loop]: https://bytearcher.com/articles/event-loop-10-000ft/
//! [fs]: https://nodejs.org/dist/latest/docs/api/fs.html
//! [net]: https://nodejs.org/dist/latest/docs/api/net.html
//! [process]: https://nodejs.org/dist/latest/docs/api/process.html
//! [timer]: https://nodejs.org/dist/latest/docs/api/timers.html
//! [move]: https://doc.rust-lang.org/std/keyword.move.html
//! [psd-crate]: https://crates.io/crates/psd
//! [psd-file]: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/

#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
mod event_queue;

#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
pub use self::event_queue::{EventQueue, EventQueueError};

#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
mod event_handler;

#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
pub use self::event_handler::EventHandler;

#[cfg(all(feature = "napi-1", feature = "event-handler-api"))]
compile_error!(
    "The `EventHandler` API is not supported with the N-API \
    backend. Use `EventQueue` instead."
);
<commit_msg>Delete trailing spaces<commit_after>//! Exposes the JavaScript event loop for scheduling asynchronous events.
//!
//! The [_event loop_][event-loop] is how Node.js provides JavaScript programs
//! access to concurrent events such as the completion of [file][fs] or
//! [network][net] operations, scheduled [timers][timer], or receiving messages
//! from other [processes][process].
//!
//! When an asynchronous operation is started from JavaScript, it registers
//! a JavaScript callback function to wait for the operation to complete. When
//! the operation completes, the callback and the result data are added to an
//! internal _event queue_ in the Node.js runtime so that the event can be
//! processed in order.
//!
//! The event loop processes completed events one at a time in the JavaScript
//! execution thread by calling the registered callback function with its result
//! value as an argument.
//!
//! ## Creating Custom Events
//!
//! This module allows Neon programs to create new types of concurrent events
//! in Rust and expose them to JavaScript as asynchronous functions.
//!
//! A common use for custom events is to run expensive or long-lived
//! computations in a background thread without blocking the JavaScript
//! thread. For example, using the [`psd` crate][psd-crate], a Neon program could
//! asynchronously parse (potentially large) [PSD files][psd-file] in a
//! background thread:
//!
//! ```
//! # #[cfg(feature = "napi-1")] {
//! # use neon::prelude::*;
//! #
//! # fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) { }
//! #
//! fn parse_async(mut cx: FunctionContext) -> JsResult<JsUndefined> {
//!     // The types `String`, `Root<JsFunction>`, and `EventQueue` can all be
//!     // sent across threads.
//!     let filename = cx.argument::<JsString>(0)?.value(&mut cx);
//!     let callback = cx.argument::<JsFunction>(1)?.root(&mut cx);
//!     let queue = cx.queue();
//!
//!     // Spawn a thread to complete the execution. This will _not_ block the
//!     // JavaScript event loop.
//!     std::thread::spawn(move || {
//!         // Do the heavy lifting inside the background thread.
//!         parse(filename, callback, queue);
//!     });
//!
//!     Ok(cx.undefined())
//! }
//! # }
//! ```
//!
//! (Note that this usage of [`spawn`](std::thread::spawn) makes use of Rust's
//! [`move`][move] syntax to transfer ownership of data to the background
//! thread.)
//!
//! Upon completion of its task, the background thread can use the JavaScript
//! callback and the event queue to notify the main thread of the result:
//!
//! ```
//! # extern crate psd;
//! # extern crate failure;
//! #
//! # #[cfg(feature = "napi-1")] fn main() {
//! # use neon::prelude::*;
//! # use psd::Psd;
//! # use failure::Error;
//! #
//! fn psd_from_filename(filename: String) -> Result<Psd, Error> {
//!     Psd::from_bytes(&std::fs::read(&filename)?)
//! }
//!
//! fn parse(filename: String, callback: Root<JsFunction>, queue: EventQueue) {
//!     let result = psd_from_filename(filename);
//!
//!     // Send a closure as a task to be executed by the JavaScript event
//!     // queue. This _will_ block the event queue while executing.
//!     queue.send(move |mut cx| {
//!         let callback = callback.into_inner(&mut cx);
//!         let this = cx.undefined();
//!         let null = cx.null();
//!         let args = match result {
//!             Ok(psd) => {
//!                 // Extract data from the parsed file.
//!                 let width = cx.number(psd.width());
//!                 let height = cx.number(psd.height());
//!
//!                 // Save the data in a result object.
//!                 let obj = cx.empty_object();
//!                 obj.set(&mut cx, "width", width)?;
//!                 obj.set(&mut cx, "height", height)?;
//!                 vec![
//!                     cx.null().upcast::<JsValue>(),
//!                     obj.upcast(),
//!                 ]
//!             }
//!             Err(_) => {
//!                 // A full implementation would provide
//!                 // more detailed error diagnostics.
//!                 let err = cx.string("PSD parse error");
//!                 vec![
//!                     err.upcast::<JsValue>(),
//!                 ]
//!             }
//!         };
//!
//!         callback.call(&mut cx, this, args)?;
//!
//!         Ok(())
//!     });
//! }
//! # }
//! ```
//!
//! ## See also
//!
//! 1. Panu Pitkamaki. [Event loop from 10,000ft][event-loop].
//!
//! [event-loop]: https://bytearcher.com/articles/event-loop-10-000ft/
//! [fs]: https://nodejs.org/dist/latest/docs/api/fs.html
//! [net]: https://nodejs.org/dist/latest/docs/api/net.html
//! [process]: https://nodejs.org/dist/latest/docs/api/process.html
//! [timer]: https://nodejs.org/dist/latest/docs/api/timers.html
//! [move]: https://doc.rust-lang.org/std/keyword.move.html
//! [psd-crate]: https://crates.io/crates/psd
//! [psd-file]: https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/

#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
mod event_queue;

#[cfg(all(feature = "napi-4", feature = "event-queue-api"))]
pub use self::event_queue::{EventQueue, EventQueueError};

#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
mod event_handler;

#[cfg(all(not(feature = "napi-1"), feature = "event-handler-api"))]
pub use self::event_handler::EventHandler;

#[cfg(all(feature = "napi-1", feature = "event-handler-api"))]
compile_error!(
    "The `EventHandler` API is not supported with the N-API \
    backend. Use `EventQueue` instead."
);
<|endoftext|>


<commit_before>use std::iter::repeat;
use std::ops::{Index, RangeFull};
use std::fmt::Debug;

use super::point::Point;
use super::number::NumberOps;

#[derive(Debug)]
pub struct Ring<T> {
   v: Vec<T>,
   start: usize,
   end: usize,
}

impl<T> Ring<T> where T: Default + Clone + Debug {
   #[inline]
   pub fn new(capacity: usize) -> Self {
      let v = repeat(T::default()).take(capacity).collect();

      Ring { v: v, start: 0, end: 0 }
   }

   #[inline]
   pub fn len(&self) -> usize {
      self.end - self.start
   }

   #[inline]
   pub fn last(&self) -> Option<&T> {
      if self.start == self.end {
         None
      } else {
         Some(unsafe {
            self.v.get_unchecked(self.end - 1)
         })
      }
   }

   #[inline]
   pub fn start(&self) -> usize {
      self.start
   }

   #[inline]
   pub fn end(&self) -> usize {
      self.end
   }

   #[inline]
   pub fn consume_at(&mut self, marker: usize) {
      self.start = marker;
   }

   #[inline]
   pub fn consume(&mut self) {
      self.start = self.end;
   }

   #[inline]
   pub fn reserve(&mut self, additional: usize) {
      self.v.reserve(additional);
   }

   #[inline]
   pub fn rewind(&mut self, extra: usize) {
      if extra > (self.v.len() - self.end) {
         if self.start != self.end {
            for i in 0..(self.end - self.start) {
               self.v[i] = self.v[self.start + i].clone();
            }
         }

         self.end -= self.start;
         self.start = 0;
      }
   }

   #[inline]
   pub fn push(&mut self, value: T) {
      self.v[self.end] = value;
      self.end += 1;
   }

   #[inline]
   pub fn next_index(&self, index: usize) -> usize {
      let index = index + 1;
      if index == self.end {
         self.start
      } else {
         index
      }
   }

   #[inline]
   pub fn prev_index(&self, index: usize) -> usize {
      if index == self.start {
         self.end - 1
      } else {
         self.start - 1
      }
   }
}

impl<T> Index<usize> for Ring<T> {
   type Output = T;

   #[inline]
   fn index(&self, index: usize) -> &T {
      &self.v[index]
   }
}

impl<T> Index<RangeFull> for Ring<T> {
   type Output = [T];

   #[inline]
   fn index(&self, _index: RangeFull) -> &[T] {
      &self.v[self.start..self.end]
   }
}

#[inline]
pub fn h_down_intersect(y: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.y > y {
      if p1.y < y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
   } else {
      if p1.y > y && p2.y < y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
      points.push(p2);
   }
}

#[inline]
pub fn h_up_intersect(y: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.y < y {
      if p1.y > y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
   } else {
      if p1.y < y && p2.y > y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
      points.push(p2);
   }
}

#[inline]
pub fn v_left_intersect(x: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.x > x {
      if p1.x < x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
   } else {
      if p1.x > x && p2.x < x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
      points.push(p2);
   }
}

#[inline]
pub fn v_right_intersect(x: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.x < x {
      if p1.x > x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
   } else {
      if p1.x < x && p2.x > x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
      points.push(p2);
   }
}

#[inline]
pub fn h_intersect(y: i64, p1: Point, p2: Point) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

#[inline]
pub fn v_intersect(x: i64, p1: Point, p2: Point) -> i64 {
   p1.y + ((p2.y - p1.y) * (x - p1.x)).rounding_div(p2.x - p1.x)
}

pub fn hv_clip<F>(intersect: F, at: i64, points: &mut Ring<Point>) where
   F: Fn(i64, Point, Point, &mut Ring<Point>),
{
   let start = points.start();
   let end = points.end();

   points.rewind(2 * (end - start));

   let rewinded_end = points.end();

   let mut p1 = points[end-1];

   for i in start..end {
      let p2 = points[i];

      intersect(at, p1, p2, points);

      p1 = p2;
   }

   points.consume_at(rewinded_end);
}

pub fn hv_split<F>(split: F, at: i64, write: &mut Ring<Point>, read_write: &mut Ring<Point>) where
   F: Fn(i64, Point, Point, &mut Ring<Point>, &mut Ring<Point>),
{
   let start = read_write.start();
   let end = read_write.end();

   if end - start <= 2 {
      read_write.consume();
      return;
   }

   let double = 2 * (end - start);
   read_write.rewind(double);
   write.rewind(double);

   let rewinded_end = read_write.end();

   let mut p1 = read_write[end-1];

   for i in start..end {
      let p2 = read_write[i];

      split(at, p1, p2, write, read_write);

      p1 = p2;
   }

   read_write.consume_at(rewinded_end);
}

#[inline]
pub fn h_split_edge(y: i64, p1: Point, p2: Point, down: &mut Ring<Point>, up: &mut Ring<Point>) {
   if p2.y > y {
      if p1.y < y {
         let intersection = Point::new(h_intersect(y, p1, p2), y);
         down.push(intersection);
         up.push(intersection);
      }
      up.push(p2);
   } else if p2.y < y {
      if p1.y > y {
         let intersection = Point::new(h_intersect(y, p1, p2), y);
         down.push(intersection);
         up.push(intersection);
      }
      down.push(p2);
   } else {
      down.push(p2);
      up.push(p2);
   }
}

#[inline]
pub fn v_split_edge(x: i64, p1: Point, p2: Point, left: &mut Ring<Point>, right: &mut Ring<Point>) {
   if p2.x > x {
      if p1.x < x {
         let intersection = Point::new(x, v_intersect(x, p1, p2));
         left.push(intersection);
         right.push(intersection);
      }
      right.push(p2);
   } else if p2.x < x {
      if p1.x > x {
         let intersection = Point::new(x, v_intersect(x, p1, p2));
         left.push(intersection);
         right.push(intersection);
      }
      left.push(p2);
   } else {
      left.push(p2);
      right.push(p2);
   }
}

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

   use super::super::point::Point;

   use super::*;

   #[bench]
   fn bench_clip(b: &mut Bencher) {
      let mut points = Ring::new(1024 * 256);

      b.iter(|| {
         for _ in 0..1000 {
            points.consume();

            points.push(Point::new(50, 50));
            points.push(Point::new(100, 200));
            points.push(Point::new(150, 100));

            hv_clip(h_down_intersect, 150, &mut points);

            hv_clip(h_up_intersect, 80, &mut points);

            hv_clip(v_right_intersect, 70, &mut points);

            hv_clip(v_left_intersect, 140, &mut points);
         }
      });
   }

   #[test]
   fn test_clip() {
      let mut points = Ring::new(30);

      points.push(Point::new(50, 50));
      points.push(Point::new(100, 200));
      points.push(Point::new(150, 100));

      hv_clip(h_down_intersect, 150, &mut points);

      hv_clip(h_up_intersect, 80, &mut points);

      hv_clip(v_right_intersect, 70, &mut points);

      hv_clip(v_left_intersect, 140, &mut points);

      assert_eq!(points[..].len(), 7);

      assert_eq!(&points[..], [
         Point::new(140, 95),
         Point::new(110, 80),
         Point::new(70, 80),
         Point::new(70, 110),
         Point::new(83, 150),
         Point::new(125, 150),
         Point::new(140, 120),
      ]);
   }
}
<commit_msg>Ring::prev_index fix<commit_after>use std::iter::repeat;
use std::ops::{Index, RangeFull};
use std::fmt::Debug;

use super::point::Point;
use super::number::NumberOps;

#[derive(Debug)]
pub struct Ring<T> {
   v: Vec<T>,
   start: usize,
   end: usize,
}

impl<T> Ring<T> where T: Default + Clone + Debug {
   #[inline]
   pub fn new(capacity: usize) -> Self {
      let v = repeat(T::default()).take(capacity).collect();

      Ring { v: v, start: 0, end: 0 }
   }

   #[inline]
   pub fn len(&self) -> usize {
      self.end - self.start
   }

   #[inline]
   pub fn last(&self) -> Option<&T> {
      if self.start == self.end {
         None
      } else {
         Some(unsafe {
            self.v.get_unchecked(self.end - 1)
         })
      }
   }

   #[inline]
   pub fn start(&self) -> usize {
      self.start
   }

   #[inline]
   pub fn end(&self) -> usize {
      self.end
   }

   #[inline]
   pub fn consume_at(&mut self, marker: usize) {
      self.start = marker;
   }

   #[inline]
   pub fn consume(&mut self) {
      self.start = self.end;
   }

   #[inline]
   pub fn reserve(&mut self, additional: usize) {
      self.v.reserve(additional);
   }

   #[inline]
   pub fn rewind(&mut self, extra: usize) {
      if extra > (self.v.len() - self.end) {
         if self.start != self.end {
            for i in 0..(self.end - self.start) {
               self.v[i] = self.v[self.start + i].clone();
            }
         }

         self.end -= self.start;
         self.start = 0;
      }
   }

   #[inline]
   pub fn push(&mut self, value: T) {
      self.v[self.end] = value;
      self.end += 1;
   }

   #[inline]
   pub fn next_index(&self, index: usize) -> usize {
      let index = index + 1;
      if index == self.end {
         self.start
      } else {
         index
      }
   }

   #[inline]
   pub fn prev_index(&self, index: usize) -> usize {
      if index == self.start {
         self.end - 1
      } else {
         index - 1
      }
   }
}

impl<T> Index<usize> for Ring<T> {
   type Output = T;

   #[inline]
   fn index(&self, index: usize) -> &T {
      &self.v[index]
   }
}

impl<T> Index<RangeFull> for Ring<T> {
   type Output = [T];

   #[inline]
   fn index(&self, _index: RangeFull) -> &[T] {
      &self.v[self.start..self.end]
   }
}

#[inline]
pub fn h_down_intersect(y: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.y > y {
      if p1.y < y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
   } else {
      if p1.y > y && p2.y < y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
      points.push(p2);
   }
}

#[inline]
pub fn h_up_intersect(y: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.y < y {
      if p1.y > y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
   } else {
      if p1.y < y && p2.y > y {
         points.push(Point::new(h_intersect(y, p1, p2), y));
      }
      points.push(p2);
   }
}

#[inline]
pub fn v_left_intersect(x: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.x > x {
      if p1.x < x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
   } else {
      if p1.x > x && p2.x < x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
      points.push(p2);
   }
}

#[inline]
pub fn v_right_intersect(x: i64, p1: Point, p2: Point, points: &mut Ring<Point>) {
   if p2.x < x {
      if p1.x > x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
   } else {
      if p1.x < x && p2.x > x {
         points.push(Point::new(x, v_intersect(x, p1, p2)));
      }
      points.push(p2);
   }
}

#[inline]
pub fn h_intersect(y: i64, p1: Point, p2: Point) -> i64 {
   p1.x + ((p2.x - p1.x) * (y - p1.y)).rounding_div(p2.y - p1.y)
}

#[inline]
pub fn v_intersect(x: i64, p1: Point, p2: Point) -> i64 {
   p1.y + ((p2.y - p1.y) * (x - p1.x)).rounding_div(p2.x - p1.x)
}

pub fn hv_clip<F>(intersect: F, at: i64, points: &mut Ring<Point>) where
   F: Fn(i64, Point, Point, &mut Ring<Point>),
{
   let start = points.start();
   let end = points.end();

   points.rewind(2 * (end - start));

   let rewinded_end = points.end();

   let mut p1 = points[end-1];

   for i in start..end {
      let p2 = points[i];

      intersect(at, p1, p2, points);

      p1 = p2;
   }

   points.consume_at(rewinded_end);
}

pub fn hv_split<F>(split: F, at: i64, write: &mut Ring<Point>, read_write: &mut Ring<Point>) where
   F: Fn(i64, Point, Point, &mut Ring<Point>, &mut Ring<Point>),
{
   let start = read_write.start();
   let end = read_write.end();

   if end - start <= 2 {
      read_write.consume();
      return;
   }

   let double = 2 * (end - start);
   read_write.rewind(double);
   write.rewind(double);

   let rewinded_end = read_write.end();

   let mut p1 = read_write[end-1];

   for i in start..end {
      let p2 = read_write[i];

      split(at, p1, p2, write, read_write);

      p1 = p2;
   }

   read_write.consume_at(rewinded_end);
}

#[inline]
pub fn h_split_edge(y: i64, p1: Point, p2: Point, down: &mut Ring<Point>, up: &mut Ring<Point>) {
   if p2.y > y {
      if p1.y < y {
         let intersection = Point::new(h_intersect(y, p1, p2), y);
         down.push(intersection);
         up.push(intersection);
      }
      up.push(p2);
   } else if p2.y < y {
      if p1.y > y {
         let intersection = Point::new(h_intersect(y, p1, p2), y);
         down.push(intersection);
         up.push(intersection);
      }
      down.push(p2);
   } else {
      down.push(p2);
      up.push(p2);
   }
}

#[inline]
pub fn v_split_edge(x: i64, p1: Point, p2: Point, left: &mut Ring<Point>, right: &mut Ring<Point>) {
   if p2.x > x {
      if p1.x < x {
         let intersection = Point::new(x, v_intersect(x, p1, p2));
         left.push(intersection);
         right.push(intersection);
      }
      right.push(p2);
   } else if p2.x < x {
      if p1.x > x {
         let intersection = Point::new(x, v_intersect(x, p1, p2));
         left.push(intersection);
         right.push(intersection);
      }
      left.push(p2);
   } else {
      left.push(p2);
      right.push(p2);
   }
}

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

   use super::super::point::Point;

   use super::*;

   #[bench]
   fn bench_clip(b: &mut Bencher) {
      let mut points = Ring::new(1024 * 256);

      b.iter(|| {
         for _ in 0..1000 {
            points.consume();

            points.push(Point::new(50, 50));
            points.push(Point::new(100, 200));
            points.push(Point::new(150, 100));

            hv_clip(h_down_intersect, 150, &mut points);

            hv_clip(h_up_intersect, 80, &mut points);

            hv_clip(v_right_intersect, 70, &mut points);

            hv_clip(v_left_intersect, 140, &mut points);
         }
      });
   }

   #[test]
   fn test_clip() {
      let mut points = Ring::new(30);

      points.push(Point::new(50, 50));
      points.push(Point::new(100, 200));
      points.push(Point::new(150, 100));

      hv_clip(h_down_intersect, 150, &mut points);

      hv_clip(h_up_intersect, 80, &mut points);

      hv_clip(v_right_intersect, 70, &mut points);

      hv_clip(v_left_intersect, 140, &mut points);

      assert_eq!(points[..].len(), 7);

      assert_eq!(&points[..], [
         Point::new(140, 95),
         Point::new(110, 80),
         Point::new(70, 80),
         Point::new(70, 110),
         Point::new(83, 150),
         Point::new(125, 150),
         Point::new(140, 120),
      ]);
   }
}
<|endoftext|>


<commit_before>use std::io;

use classfile::ClassFile;
use classfile::attr;
use classfile::attr::AttributeInfo;
use classfile::attr::annotation;
use classfile::constant_pool as cp;
use classfile::method;

pub struct Formatter {
    indent: usize,
    out: Box<io::Write>,
}

impl Formatter {
    pub fn new() -> Formatter {
        Formatter {
            indent: 0,
            out: Box::new(io::stdout()),
        }
    }

    pub fn indent(&mut self) {
        self.indent = self.indent + 1
    }

    pub fn unindent(&mut self) {
        if self.indent <= 0 {
            panic!("Attempting to negatively indent");
        }
        self.indent = self.indent - 1
    }

    pub fn println(&mut self, line: &str) -> io::Result<()> {
        for _ in 0..self.indent {
            try!(write!(self.out, "  "));
        }
        try!(write!(self.out, "{}", line));
        Ok(())
    }
}

pub struct Options<'a> {
    pub verbose: bool,
    pub constant_pool: &'a cp::ConstantPool,
}

pub trait Disassemble {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()>;
}

impl Disassemble for ClassFile {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        for attribute in self.attributes.iter() {
            if let attr::AttributeInfo::SourceFile(ref sourcefile_info) = *attribute {
                let source_file = &self.constant_pool[sourcefile_info.sourcefile_index];
                write!(fmt.out,
                       "Compiled from \"{}\"\n", source_file.as_utf8().unwrap());
            }
        }
        let this_class = self.this_class();
        let class_name = self.constant_pool.get_string(this_class.name_index).unwrap();
        let class_name = class_name.replace("/", ".");
        let access_mode =  if self.access_flags.is_public() {
            "public "
        } else {
            ""
        };
        let class_type = if self.access_flags.is_interface() {
            "interface"
        } else if self.access_flags.is_annotation() {
            "@interface"
        } else {
            "class"
        };
        write!(fmt.out, "{}{} {}", access_mode, class_type, class_name);
        if let Some(super_class) = self.super_class() {
            let super_class_name = self.constant_pool.get_string(super_class.name_index).unwrap();
            let super_class_name = super_class_name.replace("/", ".");
            write!(fmt.out, " extends {} ", super_class_name);
        }
        if opts.verbose {
            write!(fmt.out, "\n");
            write!(fmt.out, "  minor version: {}\n", self.minor_version);
            write!(fmt.out, "  major version: {}\n", self.major_version);
            write!(fmt.out, "  flags: {}\n", self.access_flags);
            self.constant_pool.pretty_print(fmt, opts);
        }
        write!(fmt.out, "{{\n");
        self.methods.pretty_print(fmt, opts);
        write!(fmt.out, "}}");
        Ok(())
    }
}

impl Disassemble for cp::Tag {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        let mut tag_string = "";
        let mut arg_string = String::new();
        let mut comment_string: Option<String> = None;
        match *self {
            cp::Tag::Methodref(ref method_tag) => {
                tag_string = "Methodref";
                arg_string = format!("#{}.#{}", method_tag.class_index, method_tag.name_and_type_index);
                let class_info = opts.constant_pool[method_tag.class_index]
                    .as_class().unwrap();
                let method_info = opts.constant_pool[method_tag.name_and_type_index]
                    .as_name_and_type().unwrap();
                let class_name = opts.constant_pool[class_info.name_index]
                    .as_utf8().unwrap();
                let method_name = opts.constant_pool[method_info.name_index]
                    .as_utf8().unwrap();
                let method_type = opts.constant_pool[method_info.descriptor_index]
                    .as_utf8().unwrap();
                comment_string = Some(format!("{}.{}:{}", class_name, method_name, method_type));
            }
            cp::Tag::Fieldref(ref field_tag) => {
                tag_string = "Fieldref";
                arg_string = format!("#{}.#{}", field_tag.class_index, field_tag.name_and_type_index);
                let class_info = opts.constant_pool[field_tag.class_index]
                    .as_class().unwrap();
                let method_info = opts.constant_pool[field_tag.name_and_type_index]
                    .as_name_and_type().unwrap();
                let class_name = opts.constant_pool[class_info.name_index]
                    .as_utf8().unwrap();
                let method_name = opts.constant_pool[method_info.name_index]
                    .as_utf8().unwrap();
                let method_type = opts.constant_pool[method_info.descriptor_index]
                    .as_utf8().unwrap();
                comment_string = Some(format!("{}.{}:{}", class_name, method_name, method_type));
            }
            cp::Tag::String(ref string_tag) => {
                tag_string = "String";
                arg_string = format!("#{}", string_tag.string_index);
                let string = opts.constant_pool[string_tag.string_index].as_utf8().unwrap();
                comment_string = Some(format!("{}", string));
            }
            cp::Tag::Class(ref class_tag) => {
                tag_string = "Class";
                arg_string = format!("#{}", class_tag.name_index);
                let class_name = opts.constant_pool[class_tag.name_index]
                    .as_utf8().unwrap();
                comment_string = Some(format!("{}", class_name));
            }
            cp::Tag::Utf8(ref string) => {
                tag_string = "Utf8";
                arg_string = format!("{}", string);
            }
            cp::Tag::NameAndType(cp::NameAndTypeTag { name_index, descriptor_index }) => {
                tag_string = "NameAndType";
                arg_string = format!("#{}:#{}", name_index, descriptor_index);
                let method_name = opts.constant_pool[name_index]
                    .as_utf8().unwrap();
                let method_type = opts.constant_pool[descriptor_index]
                    .as_utf8().unwrap();
                comment_string = Some(format!("{}:{}", method_name, method_type));
            }
            _ => { }
        }
        let comment_string = comment_string.map_or(String::new(), |s| format!("// {}", s));
        write!(fmt.out, "{:<19}{:<15}{}", tag_string, arg_string, comment_string);
        Ok(())
    }
}

impl Disassemble for cp::ConstantPool {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        let mut magnitude = 1;
        let mut entries = self.len();
        loop {
            entries = entries / 10;
            if entries == 0 {
                break;
            }
            magnitude = magnitude + 1;
        }
        write!(fmt.out, "Constant pool:\n");
        for (i, tag) in self.iter().enumerate() {
            let index = format!("#{}", i + 1);
            write!(fmt.out, "  {:>1$} = ", index, magnitude + 1);
            tag.pretty_print(fmt, opts);
            write!(fmt.out, "\n");
        }
        Ok(())
    }
}

impl Disassemble for method::Methods {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        for method in self.iter() {
            method.pretty_print(fmt, opts);
            write!(fmt.out, "\n");
        }
        Ok(())
    }
}

impl Disassemble for attr::Attributes {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        for attr in self.iter() {
            attr.pretty_print(fmt, opts);
            write!(fmt.out, "\n");
        }
        Ok(())
    }
}

impl Disassemble for AttributeInfo {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        match *self {
            AttributeInfo::SourceFile(ref source_file) => {
                write!(fmt.out, "SourceFile");
            }
            AttributeInfo::AnnotationDefault(ref annotation_default) => {
                annotation_default.pretty_print(fmt, opts);
            }
            AttributeInfo::Code(ref code) => { code.pretty_print(fmt, opts); }
            _ => {
                write!(fmt.out, "Other");
            }
        }
        Ok(())
    }
}

impl Disassemble for method::MethodInfo {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        write!(fmt.out, "  ");
        if self.access_flags.is_public() {
            write!(fmt.out, "public ");
        } else if self.access_flags.is_private() {
            write!(fmt.out, "private ");
        } else if self.access_flags.is_protected() {
            write!(fmt.out, "protected ");
        } else {
            write!(fmt.out, "/* package */ ");
        }
        if self.access_flags.is_static() {
            write!(fmt.out, "static ");
        }
        let method_descriptor = opts.constant_pool.get_string(self.descriptor_index);
        let method_name = opts.constant_pool.get_string(self.name_index);
        write!(fmt.out, "{};\n", method_name.unwrap());
        if opts.verbose {
            write!(fmt.out, "    descriptor: {}\n", method_descriptor.unwrap());
            write!(fmt.out, "    flags: {:?}\n", self.access_flags);
            for attr in self.attributes.iter() {
                attr.pretty_print(fmt, opts);
            }
        }
        Ok(())
    }
}

impl Disassemble for annotation::ElementValue {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        match *self {
            annotation::ElementValue::ConstantValue(ref constant_value) => {
                write!(fmt.out, "{}#{}", constant_value.tag as char, constant_value.const_value_index);
            }
            _ => { write!(fmt.out, "Unsupported ElementValue!"); }
        }
        Ok(())
    }
}

impl Disassemble for attr::AnnotationDefaultAttribute {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        write!(fmt.out, "AnnotationDefault:\n");
        write!(fmt.out, "  default_value: ");
        self.default_value.pretty_print(fmt, opts);
        write!(fmt.out, "\n");
        Ok(())
    }
}

impl Disassemble for attr::CodeAttribute {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        write!(fmt.out, "      stack={}, locals={}, args_size={}\n",
                                 self.max_stack,
                                 self.max_locals,
                                 "TODO!");
        Ok(())
    }
}
<commit_msg>cargo fmt<commit_after>use std::io;

use classfile::ClassFile;
use classfile::attr;
use classfile::attr::AttributeInfo;
use classfile::attr::annotation;
use classfile::constant_pool as cp;
use classfile::method;

pub struct Formatter {
    indent: usize,
    out: Box<io::Write>,
}

impl Formatter {
    pub fn new() -> Formatter {
        Formatter {
            indent: 0,
            out: Box::new(io::stdout()),
        }
    }

    pub fn indent(&mut self) {
        self.indent = self.indent + 1
    }

    pub fn unindent(&mut self) {
        if self.indent <= 0 {
            panic!("Attempting to negatively indent");
        }
        self.indent = self.indent - 1
    }

    pub fn println(&mut self, line: &str) -> io::Result<()> {
        for _ in 0..self.indent {
            try!(write!(self.out, "  "));
        }
        try!(write!(self.out, "{}", line));
        Ok(())
    }
}

pub struct Options<'a> {
    pub verbose: bool,
    pub constant_pool: &'a cp::ConstantPool,
}

pub trait Disassemble {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()>;
}

impl Disassemble for ClassFile {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        for attribute in self.attributes.iter() {
            if let attr::AttributeInfo::SourceFile(ref sourcefile_info) = *attribute {
                let source_file = &self.constant_pool[sourcefile_info.sourcefile_index];
                write!(fmt.out,
                       "Compiled from \"{}\"\n",
                       source_file.as_utf8().unwrap());
            }
        }
        let this_class = self.this_class();
        let class_name = self.constant_pool.get_string(this_class.name_index).unwrap();
        let class_name = class_name.replace("/", ".");
        let access_mode = if self.access_flags.is_public() {
            "public "
        } else {
            ""
        };
        let class_type = if self.access_flags.is_interface() {
            "interface"
        } else if self.access_flags.is_annotation() {
            "@interface"
        } else {
            "class"
        };
        write!(fmt.out, "{}{} {}", access_mode, class_type, class_name);
        if let Some(super_class) = self.super_class() {
            let super_class_name = self.constant_pool.get_string(super_class.name_index).unwrap();
            let super_class_name = super_class_name.replace("/", ".");
            write!(fmt.out, " extends {} ", super_class_name);
        }
        if opts.verbose {
            write!(fmt.out, "\n");
            write!(fmt.out, "  minor version: {}\n", self.minor_version);
            write!(fmt.out, "  major version: {}\n", self.major_version);
            write!(fmt.out, "  flags: {}\n", self.access_flags);
            self.constant_pool.pretty_print(fmt, opts);
        }
        write!(fmt.out, "{{\n");
        self.methods.pretty_print(fmt, opts);
        write!(fmt.out, "}}");
        Ok(())
    }
}

impl Disassemble for cp::Tag {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        let mut tag_string = "";
        let mut arg_string = String::new();
        let mut comment_string: Option<String> = None;
        match *self {
            cp::Tag::Methodref(ref method_tag) => {
                tag_string = "Methodref";
                arg_string = format!("#{}.#{}",
                                     method_tag.class_index,
                                     method_tag.name_and_type_index);
                let class_info = opts.constant_pool[method_tag.class_index]
                    .as_class()
                    .unwrap();
                let method_info = opts.constant_pool[method_tag.name_and_type_index]
                    .as_name_and_type()
                    .unwrap();
                let class_name = opts.constant_pool[class_info.name_index]
                    .as_utf8()
                    .unwrap();
                let method_name = opts.constant_pool[method_info.name_index]
                    .as_utf8()
                    .unwrap();
                let method_type = opts.constant_pool[method_info.descriptor_index]
                    .as_utf8()
                    .unwrap();
                comment_string = Some(format!("{}.{}:{}", class_name, method_name, method_type));
            }
            cp::Tag::Fieldref(ref field_tag) => {
                tag_string = "Fieldref";
                arg_string = format!("#{}.#{}",
                                     field_tag.class_index,
                                     field_tag.name_and_type_index);
                let class_info = opts.constant_pool[field_tag.class_index]
                    .as_class()
                    .unwrap();
                let method_info = opts.constant_pool[field_tag.name_and_type_index]
                    .as_name_and_type()
                    .unwrap();
                let class_name = opts.constant_pool[class_info.name_index]
                    .as_utf8()
                    .unwrap();
                let method_name = opts.constant_pool[method_info.name_index]
                    .as_utf8()
                    .unwrap();
                let method_type = opts.constant_pool[method_info.descriptor_index]
                    .as_utf8()
                    .unwrap();
                comment_string = Some(format!("{}.{}:{}", class_name, method_name, method_type));
            }
            cp::Tag::String(ref string_tag) => {
                tag_string = "String";
                arg_string = format!("#{}", string_tag.string_index);
                let string = opts.constant_pool[string_tag.string_index].as_utf8().unwrap();
                comment_string = Some(format!("{}", string));
            }
            cp::Tag::Class(ref class_tag) => {
                tag_string = "Class";
                arg_string = format!("#{}", class_tag.name_index);
                let class_name = opts.constant_pool[class_tag.name_index]
                    .as_utf8()
                    .unwrap();
                comment_string = Some(format!("{}", class_name));
            }
            cp::Tag::Utf8(ref string) => {
                tag_string = "Utf8";
                arg_string = format!("{}", string);
            }
            cp::Tag::NameAndType(cp::NameAndTypeTag { name_index, descriptor_index }) => {
                tag_string = "NameAndType";
                arg_string = format!("#{}:#{}", name_index, descriptor_index);
                let method_name = opts.constant_pool[name_index]
                    .as_utf8()
                    .unwrap();
                let method_type = opts.constant_pool[descriptor_index]
                    .as_utf8()
                    .unwrap();
                comment_string = Some(format!("{}:{}", method_name, method_type));
            }
            _ => {}
        }
        let comment_string = comment_string.map_or(String::new(), |s| format!("// {}", s));
        write!(fmt.out,
               "{:<19}{:<15}{}",
               tag_string,
               arg_string,
               comment_string);
        Ok(())
    }
}

impl Disassemble for cp::ConstantPool {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        let mut magnitude = 1;
        let mut entries = self.len();
        loop {
            entries = entries / 10;
            if entries == 0 {
                break;
            }
            magnitude = magnitude + 1;
        }
        write!(fmt.out, "Constant pool:\n");
        for (i, tag) in self.iter().enumerate() {
            let index = format!("#{}", i + 1);
            write!(fmt.out, "  {:>1$} = ", index, magnitude + 1);
            tag.pretty_print(fmt, opts);
            write!(fmt.out, "\n");
        }
        Ok(())
    }
}

impl Disassemble for method::Methods {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        for method in self.iter() {
            method.pretty_print(fmt, opts);
            write!(fmt.out, "\n");
        }
        Ok(())
    }
}

impl Disassemble for attr::Attributes {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        for attr in self.iter() {
            attr.pretty_print(fmt, opts);
            write!(fmt.out, "\n");
        }
        Ok(())
    }
}

impl Disassemble for AttributeInfo {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        match *self {
            AttributeInfo::SourceFile(ref source_file) => {
                write!(fmt.out, "SourceFile");
            }
            AttributeInfo::AnnotationDefault(ref annotation_default) => {
                annotation_default.pretty_print(fmt, opts);
            }
            AttributeInfo::Code(ref code) => {
                code.pretty_print(fmt, opts);
            }
            _ => {
                write!(fmt.out, "Other");
            }
        }
        Ok(())
    }
}

impl Disassemble for method::MethodInfo {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        write!(fmt.out, "  ");
        if self.access_flags.is_public() {
            write!(fmt.out, "public ");
        } else if self.access_flags.is_private() {
            write!(fmt.out, "private ");
        } else if self.access_flags.is_protected() {
            write!(fmt.out, "protected ");
        } else {
            write!(fmt.out, "/* package */ ");
        }
        if self.access_flags.is_static() {
            write!(fmt.out, "static ");
        }
        let method_descriptor = opts.constant_pool.get_string(self.descriptor_index);
        let method_name = opts.constant_pool.get_string(self.name_index);
        write!(fmt.out, "{};\n", method_name.unwrap());
        if opts.verbose {
            write!(fmt.out, "    descriptor: {}\n", method_descriptor.unwrap());
            write!(fmt.out, "    flags: {:?}\n", self.access_flags);
            for attr in self.attributes.iter() {
                attr.pretty_print(fmt, opts);
            }
        }
        Ok(())
    }
}

impl Disassemble for annotation::ElementValue {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        match *self {
            annotation::ElementValue::ConstantValue(ref constant_value) => {
                write!(fmt.out,
                       "{}#{}",
                       constant_value.tag as char,
                       constant_value.const_value_index);
            }
            _ => {
                write!(fmt.out, "Unsupported ElementValue!");
            }
        }
        Ok(())
    }
}

impl Disassemble for attr::AnnotationDefaultAttribute {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        write!(fmt.out, "AnnotationDefault:\n");
        write!(fmt.out, "  default_value: ");
        self.default_value.pretty_print(fmt, opts);
        write!(fmt.out, "\n");
        Ok(())
    }
}

impl Disassemble for attr::CodeAttribute {
    fn pretty_print(&self, fmt: &mut Formatter, opts: &Options) -> io::Result<()> {
        write!(fmt.out,
               "      stack={}, locals={}, args_size={}\n",
               self.max_stack,
               self.max_locals,
               "TODO!");
        Ok(())
    }
}
<|endoftext|>


<commit_before>use js::value::{Value, ValueData, ValueConv, VUndefined, VString, ResultValue, to_value, from_value};
use collections::treemap::TreeMap;
use std::gc::Gc;

#[deriving(Clone)]
pub type ObjectData = TreeMap<~str, Property>;

#[deriving(Clone)]
/// A Javascript property
pub struct Property {
	/// If the type of this can be changed and this can be deleted
	pub configurable : bool,
	/// If the property shows up in enumeration of the object
	pub enumerable: bool,
	/// If this property can be changed with an assignment
	pub writable: bool,
	/// The value associated with the property
	pub value: Value,
	/// The function serving as getter
	pub get: Value,
	/// The function serving as setter
	pub set: Value
}
impl Property {
	/// Make a new property with the given value
	pub fn new(value : Value) -> Property {
		Property {
			configurable: false,
			enumerable: false,
			writable: false,
			value: value,
			get: Gc::new(VUndefined),
			set: Gc::new(VUndefined)
		}
	}
}

impl ValueConv for Property {
	fn to_value(&self) -> Value {
		let prop = ValueData::new_obj();
		let prop_ref = prop.borrow();
		prop_ref.set_field(~"configurable", to_value(self.configurable));
		prop_ref.set_field(~"enumerable", to_value(self.enumerable));
		prop_ref.set_field(~"writable", to_value(self.writable));
		prop_ref.set_field(~"value", self.value);
		prop_ref.set_field(~"get", self.get);
		prop_ref.set_field(~"set", self.set);
		prop
	}
	fn from_value(v:Value) -> Option<Property> {
		let vb = v.borrow();
		Some(Property {
			configurable: from_value(vb.get_field(~"configurable")).unwrap(),
			enumerable: from_value(vb.get_field(~"enumerable")).unwrap(),
			writable: from_value(vb.get_field(~"writable")).unwrap(),
			value: vb.get_field(~"value"),
			get: vb.get_field(~"get"),
			set: vb.get_field(~"set")
		})
	}
}
/// Create new object
pub fn make_object(_:Value, _:Value, _:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VUndefined))
}
/// Get the prototype
pub fn get_proto_of(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let obj = args.get(0);
	return Ok(obj.borrow().get_field(~"__proto__"));
}
/// Set the prototype
pub fn set_proto_of(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let proto = args.get(1).clone();
	let obj = args.get(0);
	obj.borrow().set_field(~"__proto__", proto);
	return Ok(*obj);
}
/// Define the property
pub fn define_prop(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let obj = args.get(0);
	let prop = from_value::<~str>(*args.get(1)).unwrap();
	let desc = from_value::<Property>(*args.get(2)).unwrap();
	obj.borrow().set_prop(prop, desc);
	return Ok(Gc::new(VUndefined));
}
/// To string
pub fn to_string(this:Value, _:Value, _:Vec<Value>) -> ResultValue {
	return Ok(Gc::new(VString(this.borrow().to_str())));
}
/// Create a new 'Object' object
pub fn _create() -> Value {
	let obj = to_value(make_object);
	let prototype = ValueData::new_obj();
	prototype.borrow().set_field(~"toString", to_value(to_string));
	obj.borrow().set_field(~"length", to_value(1i32));
	obj.borrow().set_field(~"prototype", prototype);
	obj.borrow().set_field(~"setPrototypeOf", to_value(set_proto_of));
	obj.borrow().set_field(~"getPrototypeOf", to_value(get_proto_of));
	obj.borrow().set_field(~"defineProperty", to_value(define_prop));
	obj
}<commit_msg>Add hasOwnProperty<commit_after>use js::value::{Value, ValueData, ValueConv, VUndefined, VObject, ResultValue, to_value, from_value};
use collections::treemap::TreeMap;
use std::gc::Gc;

#[deriving(Clone)]
pub type ObjectData = TreeMap<~str, Property>;

#[deriving(Clone)]
/// A Javascript property
pub struct Property {
	/// If the type of this can be changed and this can be deleted
	pub configurable : bool,
	/// If the property shows up in enumeration of the object
	pub enumerable: bool,
	/// If this property can be changed with an assignment
	pub writable: bool,
	/// The value associated with the property
	pub value: Value,
	/// The function serving as getter
	pub get: Value,
	/// The function serving as setter
	pub set: Value
}
impl Property {
	/// Make a new property with the given value
	pub fn new(value : Value) -> Property {
		Property {
			configurable: false,
			enumerable: false,
			writable: false,
			value: value,
			get: Gc::new(VUndefined),
			set: Gc::new(VUndefined)
		}
	}
}

impl ValueConv for Property {
	fn to_value(&self) -> Value {
		let prop = ValueData::new_obj();
		let prop_ref = prop.borrow();
		prop_ref.set_field(~"configurable", to_value(self.configurable));
		prop_ref.set_field(~"enumerable", to_value(self.enumerable));
		prop_ref.set_field(~"writable", to_value(self.writable));
		prop_ref.set_field(~"value", self.value);
		prop_ref.set_field(~"get", self.get);
		prop_ref.set_field(~"set", self.set);
		prop
	}
	fn from_value(v:Value) -> Option<Property> {
		let vb = v.borrow();
		Some(Property {
			configurable: from_value(vb.get_field(~"configurable")).unwrap(),
			enumerable: from_value(vb.get_field(~"enumerable")).unwrap(),
			writable: from_value(vb.get_field(~"writable")).unwrap(),
			value: vb.get_field(~"value"),
			get: vb.get_field(~"get"),
			set: vb.get_field(~"set")
		})
	}
}
/// Create new object
pub fn make_object(_:Value, _:Value, _:Vec<Value>) -> ResultValue {
	Ok(Gc::new(VUndefined))
}
/// Get the prototype
pub fn get_proto_of(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let obj = args.get(0);
	return Ok(obj.borrow().get_field(~"__proto__"));
}
/// Set the prototype
pub fn set_proto_of(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let proto = args.get(1).clone();
	let obj = args.get(0);
	obj.borrow().set_field(~"__proto__", proto);
	return Ok(*obj);
}
/// Define the property
pub fn define_prop(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let obj = args.get(0);
	let prop = from_value::<~str>(*args.get(1)).unwrap();
	let desc = from_value::<Property>(*args.get(2)).unwrap();
	obj.borrow().set_prop(prop, desc);
	return Ok(Gc::new(VUndefined));
}
/// To string
pub fn to_string(this:Value, _:Value, _:Vec<Value>) -> ResultValue {
	return Ok(to_value(this.borrow().to_str()));
}
/// Check if it has a property
pub fn has_own_prop(this:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let prop = from_value::<~str>(*args.get(0)).unwrap();
	Ok(to_value::<bool>(match *this.borrow() {
		VObject(ref obj) => obj.borrow().find(&prop).is_some(),
		_ => false
	}))
}
/// Create a new `Object` object
pub fn _create() -> Value {
	let obj = to_value(make_object);
	let prototype = ValueData::new_obj();
	prototype.borrow().set_field(~"hasOwnProperty", to_value(has_own_prop));
	prototype.borrow().set_field(~"toString", to_value(to_string));
	obj.borrow().set_field(~"length", to_value(1i32));
	obj.borrow().set_field(~"prototype", prototype);
	obj.borrow().set_field(~"setPrototypeOf", to_value(set_proto_of));
	obj.borrow().set_field(~"getPrototypeOf", to_value(get_proto_of));
	obj.borrow().set_field(~"defineProperty", to_value(define_prop));
	obj
}<|endoftext|>