<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#[derive(Debug)]
pub struct Stack<T: Clone> {
    snapshots: Vec<usize>,
    ops: Vec<StackOp<T>>,
    cache: Vec<T>
}

impl<T: Clone> Stack<T> {
    pub fn new() -> Self {
        Stack {
            ops: vec![],
            cache: vec![],
            snapshots: vec![]
        }
    }

    pub fn is_empty(&self) -> bool {
        self.cache.is_empty()
    }

    pub fn peek(&self) -> Option<&T> {
        self.cache.last()
    }

    pub fn push(&mut self, elem: T) {
        self.ops.push(StackOp::Push(elem.clone()));
        self.cache.push(elem);
    }

    pub fn pop(&mut self) -> Option<T> {
        self.ops.push(StackOp::Pop());
        self.cache.pop()
    }

    pub fn snapshot(&mut self) {
        self.snapshots.push(self.ops.len());
    }

    pub fn backtrack(&mut self) {
        match self.snapshots.pop() {
            Some(index) => {
                self.ops.truncate(index);
                self.recache();
            }
            None => {}
        }
    }

    fn recache(&mut self) {
        self.cache.clear();
        for op in self.ops.iter() {
            match op {
                &StackOp::Push(ref elem) => {
                    self.cache.push(elem.clone());
                },
                &StackOp::Pop() => {
                    self.cache.pop();
                }
            }
        }
    }
}

#[derive(Debug)]
enum StackOp<T> {
    Push(T),
    Pop()
}

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

    #[test]
    fn stack_ops() {
        let mut stack = Stack::new();

        // []
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // [0]
        stack.push(0);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 1]
        stack.push(1);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&1));

        // [0]
        assert_eq!(stack.pop(), Some(1));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 2]
        stack.push(2);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // [0, 2, 3]
        stack.push(3);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&3));

        // [0, 2]
        assert_eq!(stack.pop(), Some(3));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // Take a snapshot of the current stack
        stack.snapshot();

        // [0]
        assert_eq!(stack.pop(), Some(2));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // []
        assert_eq!(stack.pop(), Some(0));
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2]
        stack.backtrack();
        assert_eq!(stack.peek(), Some(&2));
    }
}
<commit_msg>add some more checks to the test<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

#[derive(Debug)]
pub struct Stack<T: Clone> {
    ops: Vec<StackOp<T>>,
    cache: Vec<T>,
    snapshots: Vec<usize>
}

impl<T: Clone> Stack<T> {
    pub fn new() -> Self {
        Stack {
            ops: vec![],
            cache: vec![],
            snapshots: vec![]
        }
    }

    pub fn is_empty(&self) -> bool {
        self.cache.is_empty()
    }

    pub fn peek(&self) -> Option<&T> {
        self.cache.last()
    }

    pub fn push(&mut self, elem: T) {
        self.ops.push(StackOp::Push(elem.clone()));
        self.cache.push(elem);
    }

    pub fn pop(&mut self) -> Option<T> {
        self.ops.push(StackOp::Pop());
        self.cache.pop()
    }

    pub fn snapshot(&mut self) {
        self.snapshots.push(self.ops.len());
    }

    pub fn backtrack(&mut self) {
        match self.snapshots.pop() {
            Some(index) => {
                self.ops.truncate(index);
                self.recache();
            }
            None => {}
        }
    }

    fn recache(&mut self) {
        self.cache.clear();
        for op in self.ops.iter() {
            match op {
                &StackOp::Push(ref elem) => {
                    self.cache.push(elem.clone());
                },
                &StackOp::Pop() => {
                    self.cache.pop();
                }
            }
        }
    }
}

#[derive(Debug)]
enum StackOp<T> {
    Push(T),
    Pop()
}

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

    #[test]
    fn stack_ops() {
        let mut stack = Stack::new();

        // []
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // [0]
        stack.push(0);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 1]
        stack.push(1);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&1));

        // [0]
        assert_eq!(stack.pop(), Some(1));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 2]
        stack.push(2);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // [0, 2, 3]
        stack.push(3);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&3));

        // [0, 2]
        assert_eq!(stack.pop(), Some(3));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // Take a snapshot of the current stack
        // [0, 2]
        stack.snapshot();

        // [0]
        assert_eq!(stack.pop(), Some(2));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // []
        assert_eq!(stack.pop(), Some(0));
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2]
        stack.backtrack();
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);
    }
}
<|endoftext|>


<commit_before>//! VM Runtime
use utils::bigint::M256;
use utils::gas::Gas;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Memory, AccountCommitment, Log};

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas, code_deposit_gas};
use self::utils::copy_into_memory;

mod cost;
mod run;
mod check;
mod utils;
mod precompiled;

/// A VM state without PC.
pub struct State<M> {
    pub memory: M,
    pub stack: Stack,

    pub context: Context,
    pub block: BlockHeader,
    pub patch: &'static Patch,

    pub out: Vec<u8>,

    pub memory_cost: Gas,
    pub used_gas: Gas,
    pub refunded_gas: Gas,

    pub account_state: AccountState,
    pub blockhash_state: BlockhashState,
    pub logs: Vec<Log>,

    pub depth: usize,
}

impl<M> State<M> {
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }

    pub fn total_used_gas(&self) -> Gas {
        self.memory_gas() + self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M> {
    state: State<M>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
/// Represents the current runtime status.
pub enum MachineStatus {
    /// This runtime is actively running or has just been started.
    Running,
    /// This runtime has exited successfully. Calling `step` on this
    /// runtime again would panic.
    ExitedOk,
    /// This runtime has exited with errors. Calling `step` on this
    /// runtime again would panic.
    ExitedErr(MachineError),
    /// This runtime requires execution of a sub runtime, which is a
    /// ContractCreation instruction.
    InvokeCreate(Context),
    /// This runtime requires execution of a sub runtime, which is a
    /// MessageCall instruction.
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
/// Used for `check` for additional checks related to the runtime.
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
/// Used for `step` for additional operations related to the runtime.
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default> Machine<M> {
    /// Create a new runtime.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch, depth: usize) -> Self {
        Self::with_states(context, block, patch, depth,
                          AccountState::default(), BlockhashState::default())
    }

    pub fn with_states(context: Context, block: BlockHeader, patch: &'static Patch,
                       depth: usize, account_state: AccountState,
                       blockhash_state: BlockhashState) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context,
                block,
                patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state,
                blockhash_state,
                logs: Vec::new(),

                depth,
            },
        }
    }

    /// Derive this runtime to create a sub runtime. This will not
    /// modify the current runtime, and it will have a chance to
    /// review whether it wants to accept the result of this sub
    /// runtime afterwards.
    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    pub fn initialize_call(&mut self) {
        self.state.account_state.decrease_balance(self.state.context.caller, self.state.context.value);
        self.state.account_state.increase_balance(self.state.context.address, self.state.context.value);
    }

    pub fn initialize_create(&mut self) {
        self.state.account_state.decrease_balance(self.state.context.caller, self.state.context.value);
        self.state.account_state.create(self.state.context.address, self.state.context.value);
    }

    /// Commit a new account into this runtime.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    /// Commit a new blockhash into this runtime.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    pub fn code_deposit(&mut self) -> Result<(), RequireError> {
        match self.status() {
            MachineStatus::ExitedOk | MachineStatus::ExitedErr(_) => (),
            _ => panic!(),
        }

        let deposit_cost = code_deposit_gas(self.state.out.len());
        if deposit_cost > self.state.available_gas() {
            if !self.state.patch.force_code_deposit {
                self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            } else {
                self.state.account_state.code_deposit(self.state.context.address, &[]);
            }
        } else {
            self.state.used_gas = self.state.used_gas + deposit_cost;
            self.state.account_state.code_deposit(self.state.context.address,
                                                  self.state.out.as_slice());
        }
        Ok(())
    }

    pub fn finalize(&mut self, real_used_gas: Gas, fresh_account_state: &AccountState) -> Result<(), RequireError> {
        match self.status() {
            MachineStatus::ExitedOk => (),
            MachineStatus::ExitedErr(_) => {
                // If exited with error, reset all changes.
                self.state.account_state = fresh_account_state.clone();
                self.state.logs = Vec::new();
            },
            _ => panic!(),
        }

        let gas_dec = real_used_gas * self.state.context.gas_price;
        self.state.account_state.decrease_balance(self.state.context.caller, gas_dec.into());

        match self.status() {
            MachineStatus::ExitedOk => (),
            MachineStatus::ExitedErr(_) => return Ok(()),
            _ => panic!(),
        }

        Ok(())
    }

    #[allow(unused_variables)]
    /// Apply a sub runtime into the current runtime. This sub runtime
    /// should have been created by the current runtime's `derive`
    /// function. Depending whether the current runtime is invoking a
    /// ContractCreation or MessageCall instruction, it will apply
    /// various states back.
    pub fn apply_sub(&mut self, sub: Machine<M>) {
        use std::mem::swap;
        let mut status = MachineStatus::Running;
        swap(&mut status, &mut self.status);
        match status {
            MachineStatus::InvokeCreate(_) => {
                self.apply_create(sub);
            },
            MachineStatus::InvokeCall(_, (out_start, out_len)) => {
                self.apply_call(sub, out_start, out_len);
            },
            _ => panic!(),
        }
    }

    fn apply_create(&mut self, sub: Machine<M>) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                let sub_total_used_gas = sub.state.total_used_gas();

                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub_total_used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                if self.state.available_gas() >= code_deposit_gas(sub.state.out.len()) {
                    self.state.account_state.decrease_balance(sub.state.context.caller,
                                                              code_deposit_gas(sub.state.out.len()).into());
                    self.state.account_state.code_deposit(sub.state.context.address,
                                                          sub.state.out.as_slice());
                } else {
                    self.state.account_state.code_deposit(sub.state.context.address, &[]);
                }

            },
            MachineStatus::ExitedErr(_) => {
                self.state.used_gas = self.state.used_gas + sub.state.context.gas_limit;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    fn apply_call(&mut self, sub: Machine<M>, out_start: M256, out_len: M256) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                let sub_total_used_gas = sub.state.total_used_gas();

                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub_total_used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                copy_into_memory(&mut self.state.memory, sub.state.out.as_slice(),
                                 out_start, M256::zero(), out_len);
            },
            MachineStatus::ExitedErr(_) => {
                self.state.used_gas = self.state.used_gas + sub.state.context.gas_limit;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    /// Check the next instruction about whether it will return
    /// errors.
    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.into()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    /// Step an instruction in the PC. The eval result is refected by
    /// the runtime status, and it will only return an error if
    /// there're accounts or blockhashes to be committed to this
    /// runtime for it to run. In that case, the state of the current
    /// runtime will not be affected.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.step_precompiled() {
            return Ok(());
        }

        if self.state.depth >= self.state.patch.callstack_limit {
            self.status = MachineStatus::ExitedErr(MachineError::CallstackOverflow);
            return Ok(());
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);

        let all_gas_cost = memory_gas + self.state.used_gas + gas_cost - gas_stipend;
        if self.state.context.gas_limit < all_gas_cost {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let after_gas = self.state.context.gas_limit - all_gas_cost;

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.into()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    /// Get the runtime state.
    pub fn state(&self) -> &State<M> {
        &self.state
    }

    /// Get the current runtime status.
    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<commit_msg>Problem: code deposit gas should be deducted from... gas<commit_after>//! VM Runtime
use utils::bigint::M256;
use utils::gas::Gas;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Memory, AccountCommitment, Log};

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas, code_deposit_gas};
use self::utils::copy_into_memory;

mod cost;
mod run;
mod check;
mod utils;
mod precompiled;

/// A VM state without PC.
pub struct State<M> {
    pub memory: M,
    pub stack: Stack,

    pub context: Context,
    pub block: BlockHeader,
    pub patch: &'static Patch,

    pub out: Vec<u8>,

    pub memory_cost: Gas,
    pub used_gas: Gas,
    pub refunded_gas: Gas,

    pub account_state: AccountState,
    pub blockhash_state: BlockhashState,
    pub logs: Vec<Log>,

    pub depth: usize,
}

impl<M> State<M> {
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }

    pub fn total_used_gas(&self) -> Gas {
        self.memory_gas() + self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M> {
    state: State<M>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
/// Represents the current runtime status.
pub enum MachineStatus {
    /// This runtime is actively running or has just been started.
    Running,
    /// This runtime has exited successfully. Calling `step` on this
    /// runtime again would panic.
    ExitedOk,
    /// This runtime has exited with errors. Calling `step` on this
    /// runtime again would panic.
    ExitedErr(MachineError),
    /// This runtime requires execution of a sub runtime, which is a
    /// ContractCreation instruction.
    InvokeCreate(Context),
    /// This runtime requires execution of a sub runtime, which is a
    /// MessageCall instruction.
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
/// Used for `check` for additional checks related to the runtime.
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
/// Used for `step` for additional operations related to the runtime.
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default> Machine<M> {
    /// Create a new runtime.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch, depth: usize) -> Self {
        Self::with_states(context, block, patch, depth,
                          AccountState::default(), BlockhashState::default())
    }

    pub fn with_states(context: Context, block: BlockHeader, patch: &'static Patch,
                       depth: usize, account_state: AccountState,
                       blockhash_state: BlockhashState) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context,
                block,
                patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state,
                blockhash_state,
                logs: Vec::new(),

                depth,
            },
        }
    }

    /// Derive this runtime to create a sub runtime. This will not
    /// modify the current runtime, and it will have a chance to
    /// review whether it wants to accept the result of this sub
    /// runtime afterwards.
    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    pub fn initialize_call(&mut self) {
        self.state.account_state.decrease_balance(self.state.context.caller, self.state.context.value);
        self.state.account_state.increase_balance(self.state.context.address, self.state.context.value);
    }

    pub fn initialize_create(&mut self) {
        self.state.account_state.decrease_balance(self.state.context.caller, self.state.context.value);
        self.state.account_state.create(self.state.context.address, self.state.context.value);
    }

    /// Commit a new account into this runtime.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    /// Commit a new blockhash into this runtime.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    pub fn code_deposit(&mut self) -> Result<(), RequireError> {
        match self.status() {
            MachineStatus::ExitedOk | MachineStatus::ExitedErr(_) => (),
            _ => panic!(),
        }

        let deposit_cost = code_deposit_gas(self.state.out.len());
        if deposit_cost > self.state.available_gas() {
            if !self.state.patch.force_code_deposit {
                self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            } else {
                self.state.account_state.code_deposit(self.state.context.address, &[]);
            }
        } else {
            self.state.used_gas = self.state.used_gas + deposit_cost;
            self.state.account_state.code_deposit(self.state.context.address,
                                                  self.state.out.as_slice());
        }
        Ok(())
    }

    pub fn finalize(&mut self, real_used_gas: Gas, fresh_account_state: &AccountState) -> Result<(), RequireError> {
        match self.status() {
            MachineStatus::ExitedOk => (),
            MachineStatus::ExitedErr(_) => {
                // If exited with error, reset all changes.
                self.state.account_state = fresh_account_state.clone();
                self.state.logs = Vec::new();
            },
            _ => panic!(),
        }

        let gas_dec = real_used_gas * self.state.context.gas_price;
        self.state.account_state.decrease_balance(self.state.context.caller, gas_dec.into());

        match self.status() {
            MachineStatus::ExitedOk => (),
            MachineStatus::ExitedErr(_) => return Ok(()),
            _ => panic!(),
        }

        Ok(())
    }

    #[allow(unused_variables)]
    /// Apply a sub runtime into the current runtime. This sub runtime
    /// should have been created by the current runtime's `derive`
    /// function. Depending whether the current runtime is invoking a
    /// ContractCreation or MessageCall instruction, it will apply
    /// various states back.
    pub fn apply_sub(&mut self, sub: Machine<M>) {
        use std::mem::swap;
        let mut status = MachineStatus::Running;
        swap(&mut status, &mut self.status);
        match status {
            MachineStatus::InvokeCreate(_) => {
                self.apply_create(sub);
            },
            MachineStatus::InvokeCall(_, (out_start, out_len)) => {
                self.apply_call(sub, out_start, out_len);
            },
            _ => panic!(),
        }
    }

    fn apply_create(&mut self, sub: Machine<M>) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                let sub_total_used_gas = sub.state.total_used_gas();

                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub_total_used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                if self.state.available_gas() >= code_deposit_gas(sub.state.out.len()) {
                    self.state.used_gas = self.state.used_gas + code_deposit_gas(sub.state.out.len());
                    self.state.account_state.code_deposit(sub.state.context.address,
                                                          sub.state.out.as_slice());
                } else {
                    self.state.account_state.code_deposit(sub.state.context.address, &[]);
                }

            },
            MachineStatus::ExitedErr(_) => {
                self.state.used_gas = self.state.used_gas + sub.state.context.gas_limit;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    fn apply_call(&mut self, sub: Machine<M>, out_start: M256, out_len: M256) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                let sub_total_used_gas = sub.state.total_used_gas();

                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub_total_used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                copy_into_memory(&mut self.state.memory, sub.state.out.as_slice(),
                                 out_start, M256::zero(), out_len);
            },
            MachineStatus::ExitedErr(_) => {
                self.state.used_gas = self.state.used_gas + sub.state.context.gas_limit;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    /// Check the next instruction about whether it will return
    /// errors.
    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.into()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    /// Step an instruction in the PC. The eval result is refected by
    /// the runtime status, and it will only return an error if
    /// there're accounts or blockhashes to be committed to this
    /// runtime for it to run. In that case, the state of the current
    /// runtime will not be affected.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.step_precompiled() {
            return Ok(());
        }

        if self.state.depth >= self.state.patch.callstack_limit {
            self.status = MachineStatus::ExitedErr(MachineError::CallstackOverflow);
            return Ok(());
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);

        let all_gas_cost = memory_gas + self.state.used_gas + gas_cost - gas_stipend;
        if self.state.context.gas_limit < all_gas_cost {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let after_gas = self.state.context.gas_limit - all_gas_cost;

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.into()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    /// Get the runtime state.
    pub fn state(&self) -> &State<M> {
        &self.state
    }

    /// Get the current runtime status.
    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<|endoftext|>


<commit_before>use core::iter::{InPlaceIterable, SourceIter};
use core::mem::{self, ManuallyDrop};
use core::ptr::{self};

use super::{AsIntoIter, InPlaceDrop, SpecFromIter, SpecFromIterNested, Vec};

/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
/// source allocation, i.e. executing the pipeline in place.
///
/// The SourceIter parent trait is necessary for the specializing function to access the allocation
/// which is to be reused. But it is not sufficient for the specialization to be valid. See
/// additional bounds on the impl.
#[rustc_unsafe_specialization_marker]
pub(super) trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}

// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
// several other specializations already depend on.
impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}

impl<T, I> SpecFromIter<T, I> for Vec<T>
where
    I: Iterator<Item = T> + SourceIterMarker,
{
    default fn from_iter(mut iterator: I) -> Self {
        // Additional requirements which cannot expressed via trait bounds. We rely on const eval
        // instead:
        // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
        // b) size match as required by Alloc contract
        // c) alignments match as required by Alloc contract
        if mem::size_of::<T>() == 0
            || mem::size_of::<T>()
                != mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
            || mem::align_of::<T>()
                != mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
        {
            // fallback to more generic implementations
            return SpecFromIterNested::from_iter(iterator);
        }

        let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
            let inner = iterator.as_inner().as_into_iter();
            (
                inner.buf.as_ptr(),
                inner.ptr,
                inner.buf.as_ptr() as *mut T,
                inner.end as *const T,
                inner.cap,
            )
        };

        // use try-fold since
        // - it vectorizes better for some iterator adapters
        // - unlike most internal iteration methods, it only takes a &mut self
        // - it lets us thread the write pointer through its innards and get it back in the end
        let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
        let sink = iterator
            .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
            .unwrap();
        // iteration succeeded, don't drop head
        let dst = ManuallyDrop::new(sink).dst;

        let src = unsafe { iterator.as_inner().as_into_iter() };
        // check if SourceIter contract was upheld
        // caveat: if they weren't we may not even make it to this point
        debug_assert_eq!(src_buf, src.buf.as_ptr());
        // check InPlaceIterable contract. This is only possible if the iterator advanced the
        // source pointer at all. If it uses unchecked access via TrustedRandomAccess
        // then the source pointer will stay in its initial position and we can't use it as reference
        if src.ptr != src_ptr {
            debug_assert!(
                dst as *const _ <= src.ptr,
                "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
            );
        }

        // drop any remaining values at the tail of the source
        src.drop_remaining();
        // but prevent drop of the allocation itself once IntoIter goes out of scope
        src.forget_allocation();

        let vec = unsafe {
            let len = dst.offset_from(dst_buf) as usize;
            Vec::from_raw_parts(dst_buf, len, cap)
        };

        vec
    }
}

fn write_in_place_with_drop<T>(
    src_end: *const T,
) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
    move |mut sink, item| {
        unsafe {
            // the InPlaceIterable contract cannot be verified precisely here since
            // try_fold has an exclusive reference to the source pointer
            // all we can do is check if it's still in range
            debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
            ptr::write(sink.dst, item);
            sink.dst = sink.dst.add(1);
        }
        Ok(sink)
    }
}
<commit_msg>specialize in-place collection further via TrustedRandomAccess<commit_after>use core::iter::{InPlaceIterable, SourceIter, TrustedRandomAccess};
use core::mem::{self, ManuallyDrop};
use core::ptr::{self};

use super::{AsIntoIter, InPlaceDrop, SpecFromIter, SpecFromIterNested, Vec};

/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the
/// source allocation, i.e. executing the pipeline in place.
///
/// The SourceIter parent trait is necessary for the specializing function to access the allocation
/// which is to be reused. But it is not sufficient for the specialization to be valid. See
/// additional bounds on the impl.
#[rustc_unsafe_specialization_marker]
pub(super) trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}

// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
// several other specializations already depend on.
impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}

impl<T, I> SpecFromIter<T, I> for Vec<T>
where
    I: Iterator<Item = T> + SourceIterMarker,
{
    default fn from_iter(mut iterator: I) -> Self {
        // Additional requirements which cannot expressed via trait bounds. We rely on const eval
        // instead:
        // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
        // b) size match as required by Alloc contract
        // c) alignments match as required by Alloc contract
        if mem::size_of::<T>() == 0
            || mem::size_of::<T>()
                != mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
            || mem::align_of::<T>()
                != mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
        {
            // fallback to more generic implementations
            return SpecFromIterNested::from_iter(iterator);
        }

        let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
            let inner = iterator.as_inner().as_into_iter();
            (
                inner.buf.as_ptr(),
                inner.ptr,
                inner.buf.as_ptr() as *mut T,
                inner.end as *const T,
                inner.cap,
            )
        };

        let len = SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end);

        let src = unsafe { iterator.as_inner().as_into_iter() };
        // check if SourceIter contract was upheld
        // caveat: if they weren't we may not even make it to this point
        debug_assert_eq!(src_buf, src.buf.as_ptr());
        // check InPlaceIterable contract. This is only possible if the iterator advanced the
        // source pointer at all. If it uses unchecked access via TrustedRandomAccess
        // then the source pointer will stay in its initial position and we can't use it as reference
        if src.ptr != src_ptr {
            debug_assert!(
                unsafe { dst_buf.add(len) as *const _ } <= src.ptr,
                "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
            );
        }

        // drop any remaining values at the tail of the source
        src.drop_remaining();
        // but prevent drop of the allocation itself once IntoIter goes out of scope
        src.forget_allocation();

        let vec = unsafe { Vec::from_raw_parts(dst_buf, len, cap) };

        vec
    }
}

fn write_in_place_with_drop<T>(
    src_end: *const T,
) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
    move |mut sink, item| {
        unsafe {
            // the InPlaceIterable contract cannot be verified precisely here since
            // try_fold has an exclusive reference to the source pointer
            // all we can do is check if it's still in range
            debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
            ptr::write(sink.dst, item);
            sink.dst = sink.dst.add(1);
        }
        Ok(sink)
    }
}

/// Helper trait to hold specialized implementations of the in-place iterate-collect loop
trait SpecInPlaceCollect<T, I>: Iterator<Item = T> {
    /// Collects an iterator (`self`) into the destination buffer (`dst`) and returns the number of items
    /// collected. `end` is the last writable element of the allocation and used for bounds checks.
    fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize;
}

impl<T, I> SpecInPlaceCollect<T, I> for I
where
    I: Iterator<Item = T>,
{
    #[inline]
    default fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
        // use try-fold since
        // - it vectorizes better for some iterator adapters
        // - unlike most internal iteration methods, it only takes a &mut self
        // - it lets us thread the write pointer through its innards and get it back in the end
        let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
        let sink =
            self.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(end)).unwrap();
        // iteration succeeded, don't drop head
        unsafe { ManuallyDrop::new(sink).dst.offset_from(dst_buf) as usize }
    }
}

impl<T, I> SpecInPlaceCollect<T, I> for I
where
    I: Iterator<Item = T> + TrustedRandomAccess,
{
    #[inline]
    fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
        let len = self.size();
        let mut drop_guard = InPlaceDrop { inner: dst_buf, dst: dst_buf };
        for i in 0..len {
            // Safety: InplaceIterable contract guarantees that for every element we read
            // one slot in the underlying storage will have been freed up and we can immediately
            // write back the result.
            unsafe {
                let dst = dst_buf.offset(i as isize);
                debug_assert!(dst as *const _ <= end, "InPlaceIterable contract violation");
                ptr::write(dst, self.__iterator_get_unchecked(i));
                drop_guard.dst = dst.add(1);
            }
        }
        mem::forget(drop_guard);
        len
    }
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, rustc_private)]
#![feature(const_fn)]

extern crate syntax;
extern crate rustc_plugin;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;
extern crate owning_ref;

use rustc_plugin::registry::Registry;
use syntax::ext::base::{SyntaxExtension, ExtCtxt, MacResult, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::codemap::Span;
use syntax::ast;
use syntax::util::small_vector::SmallVector;
use syntax::parse::token::intern;
use syntax::tokenstream::TokenTree;
use syntax::ptr::P;

use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::collections::HashMap;

use owning_ref::{OwningRef, RwLockReadGuardRef};

pub mod parser;
pub mod compiler;
pub mod x64data;
pub mod serialize;
pub mod debug;

/// Welcome to the documentation of the dynasm plugin. This mostly exists to ease
/// development and to show a glimpse of what is under the hood of dynasm. Please
/// be aware that nothing in here should be counted on to be stable, the only
/// guarantees are in the syntax the `dynasm!` macro parses and in the code it
/// generates.

#[plugin_registrar]
pub fn registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        intern("dynasm"),
        SyntaxExtension::NormalTT(
            Box::new(main),
            None,
            false
        )
    );
}

fn main<'cx>(ecx: &'cx mut ExtCtxt, span: Span, token_tree: &[TokenTree])
-> Box<MacResult + 'cx> {
    // expand all macros in our token tree first. This enables the use of rust macros
    // within dynasm
    let token_tree = ecx.expander().fold_tts(token_tree);

    let mut parser = ecx.new_parser_from_tts(&token_tree);

    // construct an ast of assembly nodes
    let (name, ast) = match parser::parse(ecx, &mut parser) {
        Ok(ast) => ast,
        Err(mut e) => {e.emit(); return DummyResult::any(span)}
    };

    // println!("{:?}", ast);

    let stmts = if let Ok(stmts) = compiler::compile(ecx, ast) {
        stmts
    } else {
        return DummyResult::any(span)
    };

    let stmts = serialize::serialize(ecx, name, stmts);

    Box::new(DynAsm {
        ecx: ecx,
        stmts: stmts
    })
}

struct DynAsm<'cx, 'a: 'cx> {
    ecx: &'cx ExtCtxt<'a>,
    stmts: Vec<ast::Stmt>
}

impl<'cx, 'a> MacResult for DynAsm<'cx, 'a> {
    fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
        Some(self.ecx.expr_block(self.ecx.block(self.ecx.call_site(), self.stmts)))
    }
    fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
        Some(SmallVector::many(self.stmts))
    }

    fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
        if self.stmts.is_empty() {
            Some(SmallVector::zero())
        } else {
            None
        }
    }
}

// Crate local data implementation.

pub struct DynasmData {
    aliases: HashMap<ast::Name, (parser::RegId, parser::Size)>
}

pub struct CrateLocalData {
    inner: OwningRef<
        RwLockReadGuard<'static, DynasmStorage>,
        RwLock<DynasmData>
    >
}

impl CrateLocalData {
    fn read(&self) ->RwLockReadGuard<DynasmData> {
        self.inner.read().unwrap()
    }

    fn write(&self) -> RwLockWriteGuard<DynasmData> {
        self.inner.write().unwrap()
    }
}

pub fn crate_local_data(ecx: &ExtCtxt) -> CrateLocalData {
    let id = ecx.mod_path()[0];

    {
        let data = RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap());

        if data.get(&id).is_some() {
            return CrateLocalData {
                inner: data.map(|x| x.get(&id).unwrap())
            }
        }
    }

    {
        let mut lock = DYNASM_STORAGE.write().unwrap();
        lock.insert(id, RwLock::new(DynasmData {
            aliases: HashMap::new()
        }));
    }
    CrateLocalData {
        inner: RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap()).map(|x| x.get(&id).unwrap())
    }
}

// the root of all crate-local data
type DynasmStorage = HashMap<ast::Ident, RwLock<DynasmData>>;

lazy_static! {
    pub static ref DYNASM_STORAGE: RwLock<DynasmStorage> = RwLock::new(HashMap::new());
}
<commit_msg>ExtCtxt::mod_path has been removed<commit_after>#![feature(plugin_registrar, rustc_private)]
#![feature(const_fn)]

extern crate syntax;
extern crate rustc_plugin;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate bitflags;
extern crate owning_ref;

use rustc_plugin::registry::Registry;
use syntax::ext::base::{SyntaxExtension, ExtCtxt, MacResult, DummyResult};
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::codemap::Span;
use syntax::ast;
use syntax::util::small_vector::SmallVector;
use syntax::parse::token::{intern, str_to_ident};
use syntax::tokenstream::TokenTree;
use syntax::ptr::P;

use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::collections::HashMap;

use owning_ref::{OwningRef, RwLockReadGuardRef};

pub mod parser;
pub mod compiler;
pub mod x64data;
pub mod serialize;
pub mod debug;

/// Welcome to the documentation of the dynasm plugin. This mostly exists to ease
/// development and to show a glimpse of what is under the hood of dynasm. Please
/// be aware that nothing in here should be counted on to be stable, the only
/// guarantees are in the syntax the `dynasm!` macro parses and in the code it
/// generates.

#[plugin_registrar]
pub fn registrar(reg: &mut Registry) {
    reg.register_syntax_extension(
        intern("dynasm"),
        SyntaxExtension::NormalTT(
            Box::new(main),
            None,
            false
        )
    );
}

fn main<'cx>(ecx: &'cx mut ExtCtxt, span: Span, token_tree: &[TokenTree])
-> Box<MacResult + 'cx> {
    // expand all macros in our token tree first. This enables the use of rust macros
    // within dynasm
    let token_tree = ecx.expander().fold_tts(token_tree);

    let mut parser = ecx.new_parser_from_tts(&token_tree);

    // construct an ast of assembly nodes
    let (name, ast) = match parser::parse(ecx, &mut parser) {
        Ok(ast) => ast,
        Err(mut e) => {e.emit(); return DummyResult::any(span)}
    };

    // println!("{:?}", ast);

    let stmts = if let Ok(stmts) = compiler::compile(ecx, ast) {
        stmts
    } else {
        return DummyResult::any(span)
    };

    let stmts = serialize::serialize(ecx, name, stmts);

    Box::new(DynAsm {
        ecx: ecx,
        stmts: stmts
    })
}

struct DynAsm<'cx, 'a: 'cx> {
    ecx: &'cx ExtCtxt<'a>,
    stmts: Vec<ast::Stmt>
}

impl<'cx, 'a> MacResult for DynAsm<'cx, 'a> {
    fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
        Some(self.ecx.expr_block(self.ecx.block(self.ecx.call_site(), self.stmts)))
    }
    fn make_stmts(self: Box<Self>) -> Option<SmallVector<ast::Stmt>> {
        Some(SmallVector::many(self.stmts))
    }

    fn make_items(self: Box<Self>) -> Option<SmallVector<P<ast::Item>>> {
        if self.stmts.is_empty() {
            Some(SmallVector::zero())
        } else {
            None
        }
    }
}

// Crate local data implementation.

pub struct DynasmData {
    aliases: HashMap<ast::Name, (parser::RegId, parser::Size)>
}

pub struct CrateLocalData {
    inner: OwningRef<
        RwLockReadGuard<'static, DynasmStorage>,
        RwLock<DynasmData>
    >
}

impl CrateLocalData {
    fn read(&self) ->RwLockReadGuard<DynasmData> {
        self.inner.read().unwrap()
    }

    fn write(&self) -> RwLockWriteGuard<DynasmData> {
        self.inner.write().unwrap()
    }
}

pub fn crate_local_data(ecx: &ExtCtxt) -> CrateLocalData {
    let id = str_to_ident(&ecx.ecfg.crate_name);

    {
        let data = RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap());

        if data.get(&id).is_some() {
            return CrateLocalData {
                inner: data.map(|x| x.get(&id).unwrap())
            }
        }
    }

    {
        let mut lock = DYNASM_STORAGE.write().unwrap();
        lock.insert(id, RwLock::new(DynasmData {
            aliases: HashMap::new()
        }));
    }
    CrateLocalData {
        inner: RwLockReadGuardRef::new(DYNASM_STORAGE.read().unwrap()).map(|x| x.get(&id).unwrap())
    }
}

// the root of all crate-local data
type DynasmStorage = HashMap<ast::Ident, RwLock<DynasmData>>;

lazy_static! {
    pub static ref DYNASM_STORAGE: RwLock<DynasmStorage> = RwLock::new(HashMap::new());
}
<|endoftext|>


<commit_before>#![feature(proc_macro_hygiene)]
#![allow(unused_imports)]

fn main() {
    println!("Please execute: cargo test --no-fail-fast")
}
<commit_msg>Remove last remaining feature directive from testing<commit_after>#![allow(unused_imports)]

fn main() {
    println!("Please execute: cargo test --no-fail-fast")
}
<|endoftext|>


<commit_before>use anyhow::Result;
use pueue_lib::network::message::*;

use crate::helper::*;

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
/// Add and directly remove a group.
async fn test_add_and_remove() -> Result<()> {
    let (settings, tempdir) = base_setup()?;
    let shared = &settings.shared;
    let _pid = boot_daemon(tempdir.path())?;

    // Add a new group
    let add_message = Message::Group(GroupMessage::Add("testgroup".to_string()));
    assert_success(send_message(shared, add_message.clone()).await?);

    // Make sure it got added
    let state = get_state(shared).await?;
    assert!(state.groups.contains_key("testgroup"));

    // Try to add the same group again. This should fail
    assert_failure(send_message(shared, add_message).await?);

    // Remove the newly added group
    let remove_message = Message::Group(GroupMessage::Remove("testgroup".to_string()));
    assert_success(send_message(shared, remove_message.clone()).await?);

    // Make sure it got removed
    let state = get_state(shared).await?;
    assert!(!state.groups.contains_key("testgroup"));

    Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
/// Users cannot delete the default group.
async fn test_cannot_delete_default() -> Result<()> {
    let (settings, tempdir) = base_setup()?;
    let shared = &settings.shared;
    let _pid = boot_daemon(tempdir.path())?;

    let pause_message = Message::Group(GroupMessage::Remove("default".to_string()));
    assert_failure(send_message(shared, pause_message).await?);

    Ok(())
}
<commit_msg>tests: Test non-existing group deletion<commit_after>use anyhow::Result;
use pueue_lib::network::message::*;

use crate::helper::*;

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
/// Add and directly remove a group.
async fn test_add_and_remove() -> Result<()> {
    let (settings, tempdir) = base_setup()?;
    let shared = &settings.shared;
    let _pid = boot_daemon(tempdir.path())?;

    // Add a new group
    let add_message = Message::Group(GroupMessage::Add("testgroup".to_string()));
    assert_success(send_message(shared, add_message.clone()).await?);

    // Make sure it got added
    let state = get_state(shared).await?;
    assert!(state.groups.contains_key("testgroup"));

    // Try to add the same group again. This should fail
    assert_failure(send_message(shared, add_message).await?);

    // Remove the newly added group
    let remove_message = Message::Group(GroupMessage::Remove("testgroup".to_string()));
    assert_success(send_message(shared, remove_message.clone()).await?);

    // Make sure it got removed
    let state = get_state(shared).await?;
    assert!(!state.groups.contains_key("testgroup"));

    Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
/// Users cannot delete the default group.
async fn test_cannot_delete_default() -> Result<()> {
    let (settings, tempdir) = base_setup()?;
    let shared = &settings.shared;
    let _pid = boot_daemon(tempdir.path())?;

    let pause_message = Message::Group(GroupMessage::Remove("default".to_string()));
    assert_failure(send_message(shared, pause_message).await?);

    Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
/// Users cannot delete the default group.
async fn test_cannot_delete_non_existing() -> Result<()> {
    let (settings, tempdir) = base_setup()?;
    let shared = &settings.shared;
    let _pid = boot_daemon(tempdir.path())?;

    let pause_message = Message::Group(GroupMessage::Remove("doesnt_exist".to_string()));
    assert_failure(send_message(shared, pause_message).await?);

    Ok(())
}
<|endoftext|>


<commit_before>use super::event_manager::*;
use glium::glutin::{ElementState, Event, VirtualKeyCode};
use std::f32::consts;

#[derive(Debug)]
pub struct DayTime {
    time_year: u32,
    time_day: u32,
    time_on_day: f32,
    speed: f32,
}

// `DEFAULT_TIME_SPEED` is 1.0 so the time goes at normal speed
// `PLUS_TIME_SPEED` is the factor with which the time is sped up, when the
// speed-up key is pressed
const DEFAULT_TIME_SPEED: f32 = 1.0;
const PLUS_TIME_SPEED: f32 = 1000.0;

impl Default for DayTime {
    fn default() -> DayTime {
        DayTime {
            time_year: 0,
            time_day: 0,
            time_on_day: 0.0,
            speed: 1.0,
        }
    }
}

const DAY_LENGTH: f32 = 720.0;
const YEAR_LENGTH: u32 = 12;

const MONTH_DIFFERENCE: f32 = 3.1415 / 18.0;

impl DayTime {
    pub fn set_time(&mut self, time_year: u32, time_day: u32, time_on_day: f32) {
        self.time_year = time_year;
        self.time_day = time_day;
        self.time_on_day = time_on_day;
        self.speed = DEFAULT_TIME_SPEED;
    }

    pub fn get_time_year(&self) -> u32 {
        self.time_year
    }

    pub fn get_time_day(&self) -> u32 {
        self.time_day
    }

    pub fn get_time_on_day(&self) -> f32 {
        self.time_on_day
    }

    // Updates time with the use of `delta` as additionally passed time
    // `DAY_LENGTH` defines the length of a day in real-life seconds
    // `YEAR_LENGTH` defines the length of a year in `DAY_LENGTH`s
    pub fn update(&mut self, delta: f32) {
        // Output of Time
        info!("Year: {} Day: {} Time: {}",
              self.time_year,
              self.time_day,
              self.time_on_day);

        // Checks if one day has passed
        self.time_on_day += delta * self.speed;
        if (self.time_on_day) >= DAY_LENGTH {
            self.time_on_day -= DAY_LENGTH; // Removes one day from time_on_day
            self.time_day += 1;
            if (self.time_day) >= YEAR_LENGTH {
                self.time_day = 0;
                self.time_year += 1;
            }
        }

    }

    pub fn get_sun_light_vector(&self) {
        // 0 degrees for mid summer
        // 60 degrees for hard winter
        let mut half_year = YEAR_LENGTH as f32 / 2.0;
        let mut half_day = DAY_LENGTH as f32 / 2.0;

        let mut theta = self.time_day as f32 - half_year;
        if theta < 0.0 {
            theta *= -1.0;
        }
        // theta now is the day difference from the highest day, sunposition-wise
        theta *= MONTH_DIFFERENCE;

        if self.time_on_day < half_day {
            // pre noon
            // sun rising
            theta += consts::PI - consts::PI * (self.time_on_day / half_day)
        } else {
            // after noon
            // sun going down
            theta += consts::PI * ((self.time_on_day - half_day) / half_day)
        }

        let mut phi = self.time_on_day / DAY_LENGTH as f32 * 2.0 * consts::PI;

        info!("THETA: {} PHI: {}", theta, phi);
    }
}

// Handler to speed up time with use of key
impl EventHandler for DayTime {
    fn handle_event(&mut self, e: &Event) -> EventResponse {
        match *e {
            Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Add)) => {
                self.speed = PLUS_TIME_SPEED;
                EventResponse::Continue
            }
            Event::KeyboardInput(ElementState::Released, _, Some(VirtualKeyCode::Add)) => {
                self.speed = DEFAULT_TIME_SPEED;
                EventResponse::Continue
            }
            _ => EventResponse::NotHandled,
        }

    }
}

// position in theta phi

// lichtvektor
<commit_msg>add methods for sunposition and vector for directional sunlight<commit_after>use super::event_manager::*;
use glium::glutin::{ElementState, Event, VirtualKeyCode};
use std::f32::consts;
use base::math::*;

#[derive(Debug)]
pub struct DayTime {
    time_year: u32,
    time_day: u32,
    time_on_day: f32,
    speed: f32,
}

// `DEFAULT_TIME_SPEED` is 1.0 so the time goes at normal speed
// `PLUS_TIME_SPEED` is the factor with which the time is sped up, when the
// speed-up key is pressed
const DEFAULT_TIME_SPEED: f32 = 1.0;
const PLUS_TIME_SPEED: f32 = 1000.0;

impl Default for DayTime {
    fn default() -> DayTime {
        DayTime {
            time_year: 0,
            time_day: 0,
            time_on_day: 0.0,
            speed: 1.0,
        }
    }
}

const DAY_LENGTH: f32 = 720.0;
const YEAR_LENGTH: u32 = 12;

const MONTH_DIFFERENCE: f32 = 3.1415 / 18.0;

impl DayTime {
    pub fn set_time(&mut self, time_year: u32, time_day: u32, time_on_day: f32) {
        self.time_year = time_year;
        self.time_day = time_day;
        self.time_on_day = time_on_day;
        self.speed = DEFAULT_TIME_SPEED;
    }

    pub fn get_time_year(&self) -> u32 {
        self.time_year
    }

    pub fn get_time_day(&self) -> u32 {
        self.time_day
    }

    pub fn get_time_on_day(&self) -> f32 {
        self.time_on_day
    }

    // Updates time with the use of `delta` as additionally passed time
    // `DAY_LENGTH` defines the length of a day in real-life seconds
    // `YEAR_LENGTH` defines the length of a year in `DAY_LENGTH`s
    pub fn update(&mut self, delta: f32) {
        // Output of Time
        info!("Year: {} Day: {} Time: {}",
              self.time_year,
              self.time_day,
              self.time_on_day);

        // Checks if one day has passed
        self.time_on_day += delta * self.speed;
        if (self.time_on_day) >= DAY_LENGTH {
            self.time_on_day -= DAY_LENGTH; // Removes one day from time_on_day
            self.time_day += 1;
            if (self.time_day) >= YEAR_LENGTH {
                self.time_day = 0;
                self.time_year += 1;
            }
        }

    }

    pub fn get_sun_position(&self) -> Vector3f {
        // 0 degrees for mid summer
        // 60 degrees for hard winter
        let half_year = YEAR_LENGTH as f32 / 2.0;
        let half_day = DAY_LENGTH as f32 / 2.0;

        let mut theta = self.time_day as f32 - half_year;
        if theta < 0.0 {
            theta *= -1.0;
        }
        // theta now is the day difference from the highest day, sunposition-wise
        theta *= MONTH_DIFFERENCE;

        if self.time_on_day < half_day {
            // pre noon
            // sun rising
            theta += consts::PI - consts::PI * (self.time_on_day / half_day)
        } else {
            // after noon
            // sun going down
            theta += consts::PI * ((self.time_on_day - half_day) / half_day)
        }

        let phi = self.time_on_day / DAY_LENGTH as f32 * 2.0 * consts::PI;

        // for debugging
        // info!("THETA: {} PHI: {}", theta, phi);

        // returns sun position in cartesian coordinates
        Vector3f::new(theta.sin() * phi.cos(),
                      theta.sin() * phi.sin(),
                      theta.cos())

    }

    pub fn get_sun_light_vector(&self) -> Vector3f {
        // returns the Vector3f from the sun to the origin
        // for later calculation of directional sunlight
        Vector3f::new(0.0, 0.0, 0.0) - self.get_sun_position()
    }
}

// Handler to speed up time with use of key
impl EventHandler for DayTime {
    fn handle_event(&mut self, e: &Event) -> EventResponse {
        match *e {
            Event::KeyboardInput(ElementState::Pressed, _, Some(VirtualKeyCode::Add)) => {
                self.speed = PLUS_TIME_SPEED;
                EventResponse::Continue
            }
            Event::KeyboardInput(ElementState::Released, _, Some(VirtualKeyCode::Add)) => {
                self.speed = DEFAULT_TIME_SPEED;
                EventResponse::Continue
            }
            _ => EventResponse::NotHandled,
        }

    }
}
<|endoftext|>


<commit_before>//! Representation of Bézier paths.

use smallvec::SmallVec;

use std::f64;
use std::f64::consts::*;
use std::slice;

use crate::float_eq_cairo::ApproxEqCairo;
use crate::util::clamp;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct LargeArc(pub bool);

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Sweep {
    Negative,
    Positive,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CubicBezierCurve {
    /// The (x, y) coordinates of the first control point.
    pub pt1: (f64, f64),
    /// The (x, y) coordinates of the second control point.
    pub pt2: (f64, f64),
    /// The (x, y) coordinates of the end point of this path segment.
    pub to: (f64, f64),
}

impl CubicBezierCurve {
    fn to_cairo(self, cr: &cairo::Context) {
        let Self { pt1, pt2, to } = self;
        cr.curve_to(pt1.0, pt1.1, pt2.0, pt2.1, to.0, to.1);
    }
}

/// When attempting to compute the center parameterization of the arc,
/// out of range parameters may see an arc omited or treated as a line.
pub enum ArcParameterization {
    /// Center parameterization of the arc.
    CenterParameters {
        /// Center of the ellipse.
        center: (f64, f64),
        /// Radii of the ellipse (corrected).
        radii: (f64, f64),
        /// Angle of the start point.
        theta1: f64,
        /// Delta angle to the end point.
        delta_theta: f64,
    },
    /// Treat the arc as a line to the end point.
    LineTo,
    /// Omit the arc.
    Omit,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct EllipticalArc {
    /// The (x-axis, y-axis) radii for the ellipse.
    pub r: (f64, f64),
    /// The rotation angle in degrees for the ellipse's x-axis
    /// relative to the x-axis of the user coordinate system.
    pub x_axis_rotation: f64,
    /// Flag indicating whether the arc sweep should be
    /// greater than or equal to 180 degrees, or smaller than 180 degrees.
    pub large_arc: LargeArc,
    /// Flag indicating the angular direction in which the arc is drawn.
    pub sweep: Sweep,
    /// The (x, y) coordinates for the start point of this path segment.
    pub from: (f64, f64),
    /// The (x, y) coordinates for the end point of this path segment.
    pub to: (f64, f64),
}

impl EllipticalArc {
    /// Calculates a center parameterization from the endpoint parameterization.
    ///
    /// Radii may be adjusted if there is no solution.
    ///
    /// See Appendix F.6 Elliptical arc implementation notes.
    /// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
    pub(crate) fn center_parameterization(self) -> ArcParameterization {
        let Self {
            r: (mut rx, mut ry),
            x_axis_rotation,
            large_arc,
            sweep,
            from: (x1, y1),
            to: (x2, y2),
        } = self;

        // If the end points are identical, omit the arc segment entirely.
        if x1.approx_eq_cairo(x2) && y1.approx_eq_cairo(y2) {
            return ArcParameterization::Omit;
        }

        // Ensure radii are non-zero.
        // Otherwise this arc is treated as a line segment joining the end points.
        //
        // A bit further down we divide by the square of the radii.
        // Check that we won't divide by zero.
        // See http://bugs.debian.org/508443
        if rx * rx < f64::EPSILON || ry * ry < f64::EPSILON {
            return ArcParameterization::LineTo;
        }

        let is_large_arc = large_arc.0;
        let is_positive_sweep = sweep == Sweep::Positive;

        let phi = x_axis_rotation * PI / 180.0;
        let (sin_phi, cos_phi) = phi.sin_cos();

        // Ensure radii are positive.
        rx = rx.abs();
        ry = ry.abs();

        // The equations simplify after a translation which places
        // the origin at the midpoint of the line joining (x1, y1) to (x2, y2),
        // followed by a rotation to line up the coordinate axes
        // with the axes of the ellipse.
        // All transformed coordinates will be written with primes.
        //
        // Compute (x1', y1').
        let mid_x = (x1 - x2) / 2.0;
        let mid_y = (y1 - y2) / 2.0;
        let x1_ = cos_phi * mid_x + sin_phi * mid_y;
        let y1_ = -sin_phi * mid_x + cos_phi * mid_y;

        // Ensure radii are large enough.
        let lambda = (x1_ / rx).powi(2) + (y1_ / ry).powi(2);
        if lambda > 1.0 {
            // If not, scale up the ellipse uniformly
            // until there is exactly one solution.
            rx *= lambda.sqrt();
            ry *= lambda.sqrt();
        }

        // Compute the transformed center (cx', cy').
        let d = (rx * y1_).powi(2) + (ry * x1_).powi(2);
        if d == 0.0 {
            return ArcParameterization::Omit;
        }
        let k = {
            let mut k = ((rx * ry).powi(2) / d - 1.0).abs().sqrt();
            if is_positive_sweep == is_large_arc {
                k = -k;
            }
            k
        };
        let cx_ = k * rx * y1_ / ry;
        let cy_ = -k * ry * x1_ / rx;

        // Compute the center (cx, cy).
        let cx = cos_phi * cx_ - sin_phi * cy_ + (x1 + x2) / 2.0;
        let cy = sin_phi * cx_ + cos_phi * cy_ + (y1 + y2) / 2.0;

        // Compute the start angle θ1.
        let ux = (x1_ - cx_) / rx;
        let uy = (y1_ - cy_) / ry;
        let u_len = (ux * ux + uy * uy).abs().sqrt();
        if u_len == 0.0 {
            return ArcParameterization::Omit;
        }
        let cos_theta1 = clamp(ux / u_len, -1.0, 1.0);
        let theta1 = {
            let mut theta1 = cos_theta1.acos();
            if uy < 0.0 {
                theta1 = -theta1;
            }
            theta1
        };

        // Compute the total delta angle Δθ.
        let vx = (-x1_ - cx_) / rx;
        let vy = (-y1_ - cy_) / ry;
        let v_len = (vx * vx + vy * vy).abs().sqrt();
        if v_len == 0.0 {
            return ArcParameterization::Omit;
        }
        let dp_uv = ux * vx + uy * vy;
        let cos_delta_theta = clamp(dp_uv / (u_len * v_len), -1.0, 1.0);
        let delta_theta = {
            let mut delta_theta = cos_delta_theta.acos();
            if ux * vy - uy * vx < 0.0 {
                delta_theta = -delta_theta;
            }
            if is_positive_sweep && delta_theta < 0.0 {
                delta_theta += PI * 2.0;
            } else if !is_positive_sweep && delta_theta > 0.0 {
                delta_theta -= PI * 2.0;
            }
            delta_theta
        };

        ArcParameterization::CenterParameters {
            center: (cx, cy),
            radii: (rx, ry),
            theta1,
            delta_theta,
        }
    }

    fn to_cairo(self, cr: &cairo::Context) {
        match self.center_parameterization() {
            ArcParameterization::CenterParameters {
                center,
                radii,
                theta1,
                delta_theta,
            } => {
                let n_segs = (delta_theta / (PI * 0.5 + 0.001)).abs().ceil() as u32;
                let d_theta = delta_theta / f64::from(n_segs);

                let mut theta = theta1;
                for _ in 0..n_segs {
                    arc_segment(center, radii, self.x_axis_rotation, theta, theta + d_theta)
                        .to_cairo(cr);
                    theta += d_theta;
                }
            }
            ArcParameterization::LineTo => {
                let (x2, y2) = self.to;
                cr.line_to(x2, y2);
            }
            ArcParameterization::Omit => {}
        }
    }
}

/// Turns an arc segment into a cubic bezier curve.
///
/// Takes the center, the radii and the x-axis rotation of the ellipse,
/// the angles of the start and end points,
/// and returns cubic bezier curve parameters.
pub(crate) fn arc_segment(
    c: (f64, f64),
    r: (f64, f64),
    x_axis_rotation: f64,
    th0: f64,
    th1: f64,
) -> CubicBezierCurve {
    let (cx, cy) = c;
    let (rx, ry) = r;
    let phi = x_axis_rotation * PI / 180.0;
    let (sin_phi, cos_phi) = phi.sin_cos();
    let (sin_th0, cos_th0) = th0.sin_cos();
    let (sin_th1, cos_th1) = th1.sin_cos();

    let th_half = 0.5 * (th1 - th0);
    let t = (8.0 / 3.0) * (th_half * 0.5).sin().powi(2) / th_half.sin();
    let x1 = rx * (cos_th0 - t * sin_th0);
    let y1 = ry * (sin_th0 + t * cos_th0);
    let x3 = rx * cos_th1;
    let y3 = ry * sin_th1;
    let x2 = x3 + rx * (t * sin_th1);
    let y2 = y3 + ry * (-t * cos_th1);

    CubicBezierCurve {
        pt1: (
            cx + cos_phi * x1 - sin_phi * y1,
            cy + sin_phi * x1 + cos_phi * y1,
        ),
        pt2: (
            cx + cos_phi * x2 - sin_phi * y2,
            cy + sin_phi * x2 + cos_phi * y2,
        ),
        to: (
            cx + cos_phi * x3 - sin_phi * y3,
            cy + sin_phi * x3 + cos_phi * y3,
        ),
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum PathCommand {
    MoveTo(f64, f64),
    LineTo(f64, f64),
    CurveTo(CubicBezierCurve),
    Arc(EllipticalArc),
    ClosePath,
}

impl PathCommand {
    fn to_cairo(&self, cr: &cairo::Context) {
        match *self {
            PathCommand::MoveTo(x, y) => cr.move_to(x, y),
            PathCommand::LineTo(x, y) => cr.line_to(x, y),
            PathCommand::CurveTo(curve) => curve.to_cairo(cr),
            PathCommand::Arc(arc) => arc.to_cairo(cr),
            PathCommand::ClosePath => cr.close_path(),
        }
    }
}

/// Constructs a path out of commands
///
/// When you are finished constructing a path builder, turn it into
/// a `Path` with `into_path`.
#[derive(Clone)]
pub struct PathBuilder {
    path_commands: SmallVec<[PathCommand; 32]>,
}

/// An immutable path
///
/// This is constructed from a `PathBuilder` once it is finished.
pub struct Path {
    path_commands: Box<[PathCommand]>,
}

/// Iterator over a path's commands
pub struct PathIter<'a> {
    commands: slice::Iter<'a, PathCommand>,
}

impl PathBuilder {
    pub fn new() -> PathBuilder {
        PathBuilder {
            path_commands: SmallVec::new(),
        }
    }

    pub fn into_path(self) -> Path {
        Path {
            path_commands: self.path_commands.into_boxed_slice(),
        }
    }

    pub fn move_to(&mut self, x: f64, y: f64) {
        self.path_commands.push(PathCommand::MoveTo(x, y));
    }

    pub fn line_to(&mut self, x: f64, y: f64) {
        self.path_commands.push(PathCommand::LineTo(x, y));
    }

    pub fn curve_to(&mut self, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) {
        let curve = CubicBezierCurve {
            pt1: (x2, y2),
            pt2: (x3, y3),
            to: (x4, y4),
        };
        self.path_commands.push(PathCommand::CurveTo(curve));
    }

    pub fn arc(
        &mut self,
        x1: f64,
        y1: f64,
        rx: f64,
        ry: f64,
        x_axis_rotation: f64,
        large_arc: LargeArc,
        sweep: Sweep,
        x2: f64,
        y2: f64,
    ) {
        let arc = EllipticalArc {
            r: (rx, ry),
            x_axis_rotation,
            large_arc,
            sweep,
            from: (x1, y1),
            to: (x2, y2),
        };
        self.path_commands.push(PathCommand::Arc(arc));
    }

    pub fn close_path(&mut self) {
        self.path_commands.push(PathCommand::ClosePath);
    }
}

impl Path {
    pub fn iter(&self) -> PathIter {
        PathIter {
            commands: self.path_commands.iter(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.iter().nth(0).is_none()
    }

    pub fn to_cairo(&self, cr: &cairo::Context) -> Result<(), cairo::Status> {
        assert!(!self.is_empty());

        for s in self.iter() {
            s.to_cairo(cr);
        }

        // We check the cr's status right after feeding it a new path for a few reasons:
        //
        // * Any of the individual path commands may cause the cr to enter an error state, for
        //   example, if they come with coordinates outside of Cairo's supported range.
        //
        // * The *next* call to the cr will probably be something that actually checks the status
        //   (i.e. in cairo-rs), and we don't want to panic there.

        let status = cr.status();

        if status == cairo::Status::Success {
            Ok(())
        } else {
            Err(status)
        }
    }
}

impl<'a> Iterator for PathIter<'a> {
    type Item = PathCommand;

    fn next(&mut self) -> Option<Self::Item> {
        self.commands.next().map(Clone::clone)
    }
}

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

    #[test]
    fn survives_degenerate_arcs() {
        let mut builder = PathBuilder::new();
        builder.move_to(0.0, 0.0);
        // Deliberately close to 0 to try to trigger division by 0.
        builder.arc(
            0.0,
            0.0,
            f64::EPSILON,
            f64::EPSILON,
            0.0,
            LargeArc(true),
            Sweep::Positive,
            1.0,
            1.0,
        );
    }
}
<commit_msg>Remove obsolete test<commit_after>//! Representation of Bézier paths.

use smallvec::SmallVec;

use std::f64;
use std::f64::consts::*;
use std::slice;

use crate::float_eq_cairo::ApproxEqCairo;
use crate::util::clamp;

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct LargeArc(pub bool);

#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Sweep {
    Negative,
    Positive,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct CubicBezierCurve {
    /// The (x, y) coordinates of the first control point.
    pub pt1: (f64, f64),
    /// The (x, y) coordinates of the second control point.
    pub pt2: (f64, f64),
    /// The (x, y) coordinates of the end point of this path segment.
    pub to: (f64, f64),
}

impl CubicBezierCurve {
    fn to_cairo(self, cr: &cairo::Context) {
        let Self { pt1, pt2, to } = self;
        cr.curve_to(pt1.0, pt1.1, pt2.0, pt2.1, to.0, to.1);
    }
}

/// When attempting to compute the center parameterization of the arc,
/// out of range parameters may see an arc omited or treated as a line.
pub enum ArcParameterization {
    /// Center parameterization of the arc.
    CenterParameters {
        /// Center of the ellipse.
        center: (f64, f64),
        /// Radii of the ellipse (corrected).
        radii: (f64, f64),
        /// Angle of the start point.
        theta1: f64,
        /// Delta angle to the end point.
        delta_theta: f64,
    },
    /// Treat the arc as a line to the end point.
    LineTo,
    /// Omit the arc.
    Omit,
}

#[derive(Debug, Copy, Clone, PartialEq)]
pub struct EllipticalArc {
    /// The (x-axis, y-axis) radii for the ellipse.
    pub r: (f64, f64),
    /// The rotation angle in degrees for the ellipse's x-axis
    /// relative to the x-axis of the user coordinate system.
    pub x_axis_rotation: f64,
    /// Flag indicating whether the arc sweep should be
    /// greater than or equal to 180 degrees, or smaller than 180 degrees.
    pub large_arc: LargeArc,
    /// Flag indicating the angular direction in which the arc is drawn.
    pub sweep: Sweep,
    /// The (x, y) coordinates for the start point of this path segment.
    pub from: (f64, f64),
    /// The (x, y) coordinates for the end point of this path segment.
    pub to: (f64, f64),
}

impl EllipticalArc {
    /// Calculates a center parameterization from the endpoint parameterization.
    ///
    /// Radii may be adjusted if there is no solution.
    ///
    /// See Appendix F.6 Elliptical arc implementation notes.
    /// http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
    pub(crate) fn center_parameterization(self) -> ArcParameterization {
        let Self {
            r: (mut rx, mut ry),
            x_axis_rotation,
            large_arc,
            sweep,
            from: (x1, y1),
            to: (x2, y2),
        } = self;

        // If the end points are identical, omit the arc segment entirely.
        if x1.approx_eq_cairo(x2) && y1.approx_eq_cairo(y2) {
            return ArcParameterization::Omit;
        }

        // Ensure radii are non-zero.
        // Otherwise this arc is treated as a line segment joining the end points.
        //
        // A bit further down we divide by the square of the radii.
        // Check that we won't divide by zero.
        // See http://bugs.debian.org/508443
        if rx * rx < f64::EPSILON || ry * ry < f64::EPSILON {
            return ArcParameterization::LineTo;
        }

        let is_large_arc = large_arc.0;
        let is_positive_sweep = sweep == Sweep::Positive;

        let phi = x_axis_rotation * PI / 180.0;
        let (sin_phi, cos_phi) = phi.sin_cos();

        // Ensure radii are positive.
        rx = rx.abs();
        ry = ry.abs();

        // The equations simplify after a translation which places
        // the origin at the midpoint of the line joining (x1, y1) to (x2, y2),
        // followed by a rotation to line up the coordinate axes
        // with the axes of the ellipse.
        // All transformed coordinates will be written with primes.
        //
        // Compute (x1', y1').
        let mid_x = (x1 - x2) / 2.0;
        let mid_y = (y1 - y2) / 2.0;
        let x1_ = cos_phi * mid_x + sin_phi * mid_y;
        let y1_ = -sin_phi * mid_x + cos_phi * mid_y;

        // Ensure radii are large enough.
        let lambda = (x1_ / rx).powi(2) + (y1_ / ry).powi(2);
        if lambda > 1.0 {
            // If not, scale up the ellipse uniformly
            // until there is exactly one solution.
            rx *= lambda.sqrt();
            ry *= lambda.sqrt();
        }

        // Compute the transformed center (cx', cy').
        let d = (rx * y1_).powi(2) + (ry * x1_).powi(2);
        if d == 0.0 {
            return ArcParameterization::Omit;
        }
        let k = {
            let mut k = ((rx * ry).powi(2) / d - 1.0).abs().sqrt();
            if is_positive_sweep == is_large_arc {
                k = -k;
            }
            k
        };
        let cx_ = k * rx * y1_ / ry;
        let cy_ = -k * ry * x1_ / rx;

        // Compute the center (cx, cy).
        let cx = cos_phi * cx_ - sin_phi * cy_ + (x1 + x2) / 2.0;
        let cy = sin_phi * cx_ + cos_phi * cy_ + (y1 + y2) / 2.0;

        // Compute the start angle θ1.
        let ux = (x1_ - cx_) / rx;
        let uy = (y1_ - cy_) / ry;
        let u_len = (ux * ux + uy * uy).abs().sqrt();
        if u_len == 0.0 {
            return ArcParameterization::Omit;
        }
        let cos_theta1 = clamp(ux / u_len, -1.0, 1.0);
        let theta1 = {
            let mut theta1 = cos_theta1.acos();
            if uy < 0.0 {
                theta1 = -theta1;
            }
            theta1
        };

        // Compute the total delta angle Δθ.
        let vx = (-x1_ - cx_) / rx;
        let vy = (-y1_ - cy_) / ry;
        let v_len = (vx * vx + vy * vy).abs().sqrt();
        if v_len == 0.0 {
            return ArcParameterization::Omit;
        }
        let dp_uv = ux * vx + uy * vy;
        let cos_delta_theta = clamp(dp_uv / (u_len * v_len), -1.0, 1.0);
        let delta_theta = {
            let mut delta_theta = cos_delta_theta.acos();
            if ux * vy - uy * vx < 0.0 {
                delta_theta = -delta_theta;
            }
            if is_positive_sweep && delta_theta < 0.0 {
                delta_theta += PI * 2.0;
            } else if !is_positive_sweep && delta_theta > 0.0 {
                delta_theta -= PI * 2.0;
            }
            delta_theta
        };

        ArcParameterization::CenterParameters {
            center: (cx, cy),
            radii: (rx, ry),
            theta1,
            delta_theta,
        }
    }

    fn to_cairo(self, cr: &cairo::Context) {
        match self.center_parameterization() {
            ArcParameterization::CenterParameters {
                center,
                radii,
                theta1,
                delta_theta,
            } => {
                let n_segs = (delta_theta / (PI * 0.5 + 0.001)).abs().ceil() as u32;
                let d_theta = delta_theta / f64::from(n_segs);

                let mut theta = theta1;
                for _ in 0..n_segs {
                    arc_segment(center, radii, self.x_axis_rotation, theta, theta + d_theta)
                        .to_cairo(cr);
                    theta += d_theta;
                }
            }
            ArcParameterization::LineTo => {
                let (x2, y2) = self.to;
                cr.line_to(x2, y2);
            }
            ArcParameterization::Omit => {}
        }
    }
}

/// Turns an arc segment into a cubic bezier curve.
///
/// Takes the center, the radii and the x-axis rotation of the ellipse,
/// the angles of the start and end points,
/// and returns cubic bezier curve parameters.
pub(crate) fn arc_segment(
    c: (f64, f64),
    r: (f64, f64),
    x_axis_rotation: f64,
    th0: f64,
    th1: f64,
) -> CubicBezierCurve {
    let (cx, cy) = c;
    let (rx, ry) = r;
    let phi = x_axis_rotation * PI / 180.0;
    let (sin_phi, cos_phi) = phi.sin_cos();
    let (sin_th0, cos_th0) = th0.sin_cos();
    let (sin_th1, cos_th1) = th1.sin_cos();

    let th_half = 0.5 * (th1 - th0);
    let t = (8.0 / 3.0) * (th_half * 0.5).sin().powi(2) / th_half.sin();
    let x1 = rx * (cos_th0 - t * sin_th0);
    let y1 = ry * (sin_th0 + t * cos_th0);
    let x3 = rx * cos_th1;
    let y3 = ry * sin_th1;
    let x2 = x3 + rx * (t * sin_th1);
    let y2 = y3 + ry * (-t * cos_th1);

    CubicBezierCurve {
        pt1: (
            cx + cos_phi * x1 - sin_phi * y1,
            cy + sin_phi * x1 + cos_phi * y1,
        ),
        pt2: (
            cx + cos_phi * x2 - sin_phi * y2,
            cy + sin_phi * x2 + cos_phi * y2,
        ),
        to: (
            cx + cos_phi * x3 - sin_phi * y3,
            cy + sin_phi * x3 + cos_phi * y3,
        ),
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum PathCommand {
    MoveTo(f64, f64),
    LineTo(f64, f64),
    CurveTo(CubicBezierCurve),
    Arc(EllipticalArc),
    ClosePath,
}

impl PathCommand {
    fn to_cairo(&self, cr: &cairo::Context) {
        match *self {
            PathCommand::MoveTo(x, y) => cr.move_to(x, y),
            PathCommand::LineTo(x, y) => cr.line_to(x, y),
            PathCommand::CurveTo(curve) => curve.to_cairo(cr),
            PathCommand::Arc(arc) => arc.to_cairo(cr),
            PathCommand::ClosePath => cr.close_path(),
        }
    }
}

/// Constructs a path out of commands
///
/// When you are finished constructing a path builder, turn it into
/// a `Path` with `into_path`.
#[derive(Clone)]
pub struct PathBuilder {
    path_commands: SmallVec<[PathCommand; 32]>,
}

/// An immutable path
///
/// This is constructed from a `PathBuilder` once it is finished.
pub struct Path {
    path_commands: Box<[PathCommand]>,
}

/// Iterator over a path's commands
pub struct PathIter<'a> {
    commands: slice::Iter<'a, PathCommand>,
}

impl PathBuilder {
    pub fn new() -> PathBuilder {
        PathBuilder {
            path_commands: SmallVec::new(),
        }
    }

    pub fn into_path(self) -> Path {
        Path {
            path_commands: self.path_commands.into_boxed_slice(),
        }
    }

    pub fn move_to(&mut self, x: f64, y: f64) {
        self.path_commands.push(PathCommand::MoveTo(x, y));
    }

    pub fn line_to(&mut self, x: f64, y: f64) {
        self.path_commands.push(PathCommand::LineTo(x, y));
    }

    pub fn curve_to(&mut self, x2: f64, y2: f64, x3: f64, y3: f64, x4: f64, y4: f64) {
        let curve = CubicBezierCurve {
            pt1: (x2, y2),
            pt2: (x3, y3),
            to: (x4, y4),
        };
        self.path_commands.push(PathCommand::CurveTo(curve));
    }

    pub fn arc(
        &mut self,
        x1: f64,
        y1: f64,
        rx: f64,
        ry: f64,
        x_axis_rotation: f64,
        large_arc: LargeArc,
        sweep: Sweep,
        x2: f64,
        y2: f64,
    ) {
        let arc = EllipticalArc {
            r: (rx, ry),
            x_axis_rotation,
            large_arc,
            sweep,
            from: (x1, y1),
            to: (x2, y2),
        };
        self.path_commands.push(PathCommand::Arc(arc));
    }

    pub fn close_path(&mut self) {
        self.path_commands.push(PathCommand::ClosePath);
    }
}

impl Path {
    pub fn iter(&self) -> PathIter {
        PathIter {
            commands: self.path_commands.iter(),
        }
    }

    pub fn is_empty(&self) -> bool {
        self.iter().nth(0).is_none()
    }

    pub fn to_cairo(&self, cr: &cairo::Context) -> Result<(), cairo::Status> {
        assert!(!self.is_empty());

        for s in self.iter() {
            s.to_cairo(cr);
        }

        // We check the cr's status right after feeding it a new path for a few reasons:
        //
        // * Any of the individual path commands may cause the cr to enter an error state, for
        //   example, if they come with coordinates outside of Cairo's supported range.
        //
        // * The *next* call to the cr will probably be something that actually checks the status
        //   (i.e. in cairo-rs), and we don't want to panic there.

        let status = cr.status();

        if status == cairo::Status::Success {
            Ok(())
        } else {
            Err(status)
        }
    }
}

impl<'a> Iterator for PathIter<'a> {
    type Item = PathCommand;

    fn next(&mut self) -> Option<Self::Item> {
        self.commands.next().map(Clone::clone)
    }
}

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

}
<|endoftext|>