<commit_before>//! VM Runtime
use utils::bigint::{U256, 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
    }
}

/// 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,
            },
        }
    }

    /// 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.create(self.state.context.address, U256::zero(), &[]);
            }
        } else {
            self.state.used_gas = self.state.used_gas + deposit_cost;
            self.state.account_state.create(self.state.context.address, U256::zero(),
                                            self.state.out.as_slice());
        }
        Ok(())
    }

    pub fn finalize(&mut self, real_used_gas: Gas) -> Result<(), RequireError> {
        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!(),
        }

        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);

        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 => {
                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.state.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(self.state.context.address,
                                                              sub.state.context.value);
                    self.state.account_state.create(sub.state.context.address,
                                                    sub.state.context.value,
                                                    sub.state.out.as_slice());
                }

            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                // 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 => {
                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.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                self.state.account_state.decrease_balance(self.state.context.address,
                                                          sub.state.context.value);
                self.state.account_state.increase_balance(sub.state.context.address,
                                                          sub.state.context.value);
                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.used_gas;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::from(1u64)).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 >= 2 {
            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 after_gas = self.state.context.gas_limit - memory_gas - self.state.used_gas - gas_cost + gas_stipend;

        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);
            },
        }

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

        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()
    }

    /// If the machine is exited with EmptyGas, return gas_limit,
    /// otherwise return the sum of memory gas and used gas.
    pub fn real_used_gas(&self) -> Gas {
        match self.status() {
            MachineStatus::ExitedErr(_) =>
                self.state.context.gas_limit,
            _ => self.state.memory_gas() + self.state.used_gas,
        }
    }
}
<commit_msg>Problem: gas_limit and after_gas check potentially underflow<commit_after>//! VM Runtime
use utils::bigint::{U256, 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
    }
}

/// 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,
            },
        }
    }

    /// 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.create(self.state.context.address, U256::zero(), &[]);
            }
        } else {
            self.state.used_gas = self.state.used_gas + deposit_cost;
            self.state.account_state.create(self.state.context.address, U256::zero(),
                                            self.state.out.as_slice());
        }
        Ok(())
    }

    pub fn finalize(&mut self, real_used_gas: Gas) -> Result<(), RequireError> {
        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!(),
        }

        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);

        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 => {
                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.state.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(self.state.context.address,
                                                              sub.state.context.value);
                    self.state.account_state.create(sub.state.context.address,
                                                    sub.state.context.value,
                                                    sub.state.out.as_slice());
                }

            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                // 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 => {
                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.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                self.state.account_state.decrease_balance(self.state.context.address,
                                                          sub.state.context.value);
                self.state.account_state.increase_balance(sub.state.context.address,
                                                          sub.state.context.value);
                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.used_gas;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::from(1u64)).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 >= 2 {
            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()
    }

    /// If the machine is exited with EmptyGas, return gas_limit,
    /// otherwise return the sum of memory gas and used gas.
    pub fn real_used_gas(&self) -> Gas {
        match self.status() {
            MachineStatus::ExitedErr(_) =>
                self.state.context.gas_limit,
            _ => self.state.memory_gas() + self.state.used_gas,
        }
    }
}
<|endoftext|>


<commit_before>//! `ra_hir_expand` deals with macro expansion.
//!
//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
//! tree originates not from the text of some `FileId`, but from some macro
//! expansion.

pub mod db;
pub mod ast_id_map;
pub mod either;
pub mod name;
pub mod hygiene;
pub mod diagnostics;

use std::hash::{Hash, Hasher};

use ra_db::{salsa, CrateId, FileId};
use ra_syntax::{
    ast::{self, AstNode},
    SyntaxNode, TextRange,
};

use crate::ast_id_map::FileAstId;

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    FileId(FileId),
    MacroFile(MacroFile),
}

impl From<FileId> for HirFileId {
    fn from(id: FileId) -> Self {
        HirFileId(HirFileIdRepr::FileId(id))
    }
}

impl From<MacroFile> for HirFileId {
    fn from(id: MacroFile) -> Self {
        HirFileId(HirFileIdRepr::MacroFile(id))
    }
}

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::FileId(file_id) => file_id,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc = db.lookup_intern_macro(macro_file.macro_call_id);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroFile {
    macro_call_id: MacroCallId,
    macro_file_kind: MacroFileKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroFileKind {
    Items,
    Expr,
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl salsa::InternKey for MacroCallId {
    fn from_intern_id(v: salsa::InternId) -> Self {
        MacroCallId(v)
    }
    fn as_intern_id(&self) -> salsa::InternId {
        self.0
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
    pub krate: CrateId,
    pub ast_id: AstId<ast::MacroCall>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub def: MacroDefId,
    pub ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub fn as_file(self, kind: MacroFileKind) -> HirFileId {
        let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
        macro_file.into()
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// ExpansionInfo mainly describle how to map text range between src and expaned macro
pub struct ExpansionInfo {
    pub arg_map: Vec<(TextRange, TextRange)>,
    pub def_map: Vec<(TextRange, TextRange)>,
}

impl ExpansionInfo {
    pub fn find_range(
        &self,
        from: TextRange,
        (arg_file_id, def_file_id): (HirFileId, HirFileId),
    ) -> Option<(HirFileId, TextRange)> {
        for (src, dest) in &self.arg_map {
            dbg!((src, *dest, "arg_map"));
            if src.is_subrange(&from) {
                dbg!((arg_file_id, *dest));
                return Some((arg_file_id, *dest));
            }
        }

        for (src, dest) in &self.def_map {
            dbg!((src, *dest, "def_map"));
            if src.is_subrange(&from) {
                dbg!((arg_file_id, *dest));
                return Some((def_file_id, *dest));
            }
        }

        None
    }
}

/// `AstId` points to an AST node in any file.
///
/// It is stable across reparses, and can be used as salsa key/value.
// FIXME: isn't this just a `Source<FileAstId<N>>` ?
#[derive(Debug)]
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> Clone for AstId<N> {
    fn clone(&self) -> AstId<N> {
        *self
    }
}
impl<N: AstNode> Copy for AstId<N> {}

impl<N: AstNode> PartialEq for AstId<N> {
    fn eq(&self, other: &Self) -> bool {
        (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
    }
}
impl<N: AstNode> Eq for AstId<N> {}
impl<N: AstNode> Hash for AstId<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        (self.file_id, self.file_ast_id).hash(hasher);
    }
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }

    pub fn file_id(&self) -> HirFileId {
        self.file_id
    }

    pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
        let root = db.parse_or_expand(self.file_id).unwrap();
        db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root)
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Source<T> {
    pub file_id: HirFileId,
    pub ast: T,
}

impl<T> Source<T> {
    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source { file_id: self.file_id, ast: f(self.ast) }
    }
    pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
        db.parse_or_expand(self.file_id).expect("source created from invalid file")
    }
}
<commit_msg>Add parent_expansion to HirFileId<commit_after>//! `ra_hir_expand` deals with macro expansion.
//!
//! Specifically, it implements a concept of `MacroFile` -- a file whose syntax
//! tree originates not from the text of some `FileId`, but from some macro
//! expansion.

pub mod db;
pub mod ast_id_map;
pub mod either;
pub mod name;
pub mod hygiene;
pub mod diagnostics;

use std::hash::{Hash, Hasher};

use ra_db::{salsa, CrateId, FileId};
use ra_syntax::{
    ast::{self, AstNode},
    SyntaxNode, TextRange,
};

use crate::ast_id_map::FileAstId;
use std::sync::Arc;

/// Input to the analyzer is a set of files, where each file is identified by
/// `FileId` and contains source code. However, another source of source code in
/// Rust are macros: each macro can be thought of as producing a "temporary
/// file". To assign an id to such a file, we use the id of the macro call that
/// produced the file. So, a `HirFileId` is either a `FileId` (source code
/// written by user), or a `MacroCallId` (source code produced by macro).
///
/// What is a `MacroCallId`? Simplifying, it's a `HirFileId` of a file
/// containing the call plus the offset of the macro call in the file. Note that
/// this is a recursive definition! However, the size_of of `HirFileId` is
/// finite (because everything bottoms out at the real `FileId`) and small
/// (`MacroCallId` uses the location interner).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HirFileId(HirFileIdRepr);

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum HirFileIdRepr {
    FileId(FileId),
    MacroFile(MacroFile),
}

impl From<FileId> for HirFileId {
    fn from(id: FileId) -> Self {
        HirFileId(HirFileIdRepr::FileId(id))
    }
}

impl From<MacroFile> for HirFileId {
    fn from(id: MacroFile) -> Self {
        HirFileId(HirFileIdRepr::MacroFile(id))
    }
}

impl HirFileId {
    /// For macro-expansion files, returns the file original source file the
    /// expansion originated from.
    pub fn original_file(self, db: &dyn db::AstDatabase) -> FileId {
        match self.0 {
            HirFileIdRepr::FileId(file_id) => file_id,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc = db.lookup_intern_macro(macro_file.macro_call_id);
                loc.ast_id.file_id().original_file(db)
            }
        }
    }

    /// Return expansion information if it is a macro-expansion file
    pub fn parent_expansion(
        self,
        db: &dyn db::AstDatabase,
    ) -> Option<((HirFileId, HirFileId), Arc<ExpansionInfo>)> {
        match self.0 {
            HirFileIdRepr::FileId(_) => None,
            HirFileIdRepr::MacroFile(macro_file) => {
                let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);

                let def_file = loc.def.ast_id.file_id;
                let arg_file = loc.ast_id.file_id;

                db.macro_expansion_info(macro_file).map(|ex| ((arg_file, def_file), ex))
            }
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroFile {
    macro_call_id: MacroCallId,
    macro_file_kind: MacroFileKind,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MacroFileKind {
    Items,
    Expr,
}

/// `MacroCallId` identifies a particular macro invocation, like
/// `println!("Hello, {}", world)`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroCallId(salsa::InternId);
impl salsa::InternKey for MacroCallId {
    fn from_intern_id(v: salsa::InternId) -> Self {
        MacroCallId(v)
    }
    fn as_intern_id(&self) -> salsa::InternId {
        self.0
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacroDefId {
    pub krate: CrateId,
    pub ast_id: AstId<ast::MacroCall>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MacroCallLoc {
    pub def: MacroDefId,
    pub ast_id: AstId<ast::MacroCall>,
}

impl MacroCallId {
    pub fn as_file(self, kind: MacroFileKind) -> HirFileId {
        let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind };
        macro_file.into()
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
/// ExpansionInfo mainly describle how to map text range between src and expaned macro
pub struct ExpansionInfo {
    pub arg_map: Vec<(TextRange, TextRange)>,
    pub def_map: Vec<(TextRange, TextRange)>,
}

impl ExpansionInfo {
    pub fn find_range(
        &self,
        from: TextRange,
        (arg_file_id, def_file_id): (HirFileId, HirFileId),
    ) -> Option<(HirFileId, TextRange)> {
        for (src, dest) in &self.arg_map {
            dbg!((src, *dest, "arg_map"));
            if src.is_subrange(&from) {
                dbg!((arg_file_id, *dest));
                return Some((arg_file_id, *dest));
            }
        }

        for (src, dest) in &self.def_map {
            dbg!((src, *dest, "def_map"));
            if src.is_subrange(&from) {
                dbg!((arg_file_id, *dest));
                return Some((def_file_id, *dest));
            }
        }

        None
    }
}

/// `AstId` points to an AST node in any file.
///
/// It is stable across reparses, and can be used as salsa key/value.
// FIXME: isn't this just a `Source<FileAstId<N>>` ?
#[derive(Debug)]
pub struct AstId<N: AstNode> {
    file_id: HirFileId,
    file_ast_id: FileAstId<N>,
}

impl<N: AstNode> Clone for AstId<N> {
    fn clone(&self) -> AstId<N> {
        *self
    }
}
impl<N: AstNode> Copy for AstId<N> {}

impl<N: AstNode> PartialEq for AstId<N> {
    fn eq(&self, other: &Self) -> bool {
        (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
    }
}
impl<N: AstNode> Eq for AstId<N> {}
impl<N: AstNode> Hash for AstId<N> {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        (self.file_id, self.file_ast_id).hash(hasher);
    }
}

impl<N: AstNode> AstId<N> {
    pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
        AstId { file_id, file_ast_id }
    }

    pub fn file_id(&self) -> HirFileId {
        self.file_id
    }

    pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
        let root = db.parse_or_expand(self.file_id).unwrap();
        db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root)
    }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Source<T> {
    pub file_id: HirFileId,
    pub ast: T,
}

impl<T> Source<T> {
    pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
        Source { file_id: self.file_id, ast: f(self.ast) }
    }
    pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
        db.parse_or_expand(self.file_id).expect("source created from invalid file")
    }
}
<|endoftext|>


<commit_before>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

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

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

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/
use game::{Position, Side};
use std::cmp;
use std::iter;

// A fragment extracted from a larger position.
pub struct PositionFragment {
    pub pos: Position,
    pub x_offset: usize,
    pub y_offset: usize,
}

// Depth-first search to find all coordinates which are part of the fragment including (x, y)
fn search(pos: &Position, x: usize, y: usize,
          visited: &mut Vec<Vec<bool>>, frag_coords: &mut Vec<(usize, usize)>) {
    visited[x][y] = true;
    frag_coords.push((x, y));
    for side in Side::all() {
        if pos.is_legal_move(x, y, side) {
            if let Some((next_x, next_y)) = pos.offset(x, y, side) {
                if !visited[next_x][next_y] {
                    search(pos, next_x, next_y, visited, frag_coords);
                }
            }
        }
    }
}

// Build a PositionFragment from a list of coordinates
fn make_fragment(pos: &Position, coords: &Vec<(usize, usize)>) -> PositionFragment {
    let (xl, xr, yt, yb) = coords.iter().fold(
        (coords[0].0, coords[0].0, coords[0].1, coords[0].1),
        |(xli, xri, yti, ybi), &(x, y)| (cmp::min(xli, x), cmp::max(xri, x), cmp::min(yti, y), cmp::max(ybi, y))
    );
    let mut frag_pos = Position::new_end_game(xr-xl+1, yb-yt+1);
    for &(x, y) in coords {
        let (frag_x, frag_y) = (x - xl, y - yt);
        for side in Side::all() {
            if pos.is_legal_move(x, y, side) && !frag_pos.is_legal_move(frag_x, frag_y, side) {
                frag_pos.undo_move(frag_x, frag_y, side);
            }
        }
    }
    PositionFragment{pos: frag_pos, x_offset: xl, y_offset: yt}
}

// Split a position into its independent fragments.
// If the position is fully connected, the result will consist of a single element
// representing the whole position.
pub fn split(pos: &Position) -> Vec<PositionFragment> {
    let mut visited: Vec<Vec<bool>> = Vec::with_capacity(pos.width());
    for _ in 0..pos.width() {
        visited.push(iter::repeat(false).take(pos.height()).collect());
    }
    let mut result = Vec::new();
    for x in 0..pos.width() {
        for y in 0..pos.height() {
            if !visited[x][y] && pos.valency(x, y) > 0 {
                let mut frag_coords = Vec::new();
                search(pos, x, y, &mut visited, &mut frag_coords);
                result.push(make_fragment(pos, &frag_coords));
            }
        }
    }
    result
}

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

    #[test]
    fn split_p50() {
        let pos = p50();
        let parts = split(&pos);
        assert_eq!(3, parts.len());

        let top_parts: Vec<&PositionFragment> = parts.iter().filter(|f| f.x_offset == 0 && f.y_offset == 0).collect();
        assert_eq!(1, top_parts.len());
        assert_eq!(true, top_parts[0].pos.eq(&p50_top()));

        let bl_parts: Vec<&PositionFragment> = parts.iter().filter(|f| f.x_offset == 0 && f.y_offset == 2).collect();
        assert_eq!(1, bl_parts.len());
        assert_eq!(true, bl_parts[0].pos.eq(&p50_bottomleft()));

        let br_parts: Vec<&PositionFragment> = parts.iter().filter(|f| f.x_offset == 3 && f.y_offset == 2).collect();
        assert_eq!(1, br_parts.len());
        assert_eq!(true, br_parts[0].pos.eq(&p50_bottomright()));
    }

    #[test]
    fn split_unsplittable() {
        let pos = Position::new_game(3, 3);
        let parts = split(&pos);
        assert_eq!(1, parts.len());
    }
}
<commit_msg>Add split_unsplittable assertions<commit_after>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

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

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

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/
use game::{Position, Side};
use std::cmp;
use std::iter;

// A fragment extracted from a larger position.
pub struct PositionFragment {
    pub pos: Position,
    pub x_offset: usize,
    pub y_offset: usize,
}

// Depth-first search to find all coordinates which are part of the fragment including (x, y)
fn search(pos: &Position, x: usize, y: usize,
          visited: &mut Vec<Vec<bool>>, frag_coords: &mut Vec<(usize, usize)>) {
    visited[x][y] = true;
    frag_coords.push((x, y));
    for side in Side::all() {
        if pos.is_legal_move(x, y, side) {
            if let Some((next_x, next_y)) = pos.offset(x, y, side) {
                if !visited[next_x][next_y] {
                    search(pos, next_x, next_y, visited, frag_coords);
                }
            }
        }
    }
}

// Build a PositionFragment from a list of coordinates
fn make_fragment(pos: &Position, coords: &Vec<(usize, usize)>) -> PositionFragment {
    let (xl, xr, yt, yb) = coords.iter().fold(
        (coords[0].0, coords[0].0, coords[0].1, coords[0].1),
        |(xli, xri, yti, ybi), &(x, y)| (cmp::min(xli, x), cmp::max(xri, x), cmp::min(yti, y), cmp::max(ybi, y))
    );
    let mut frag_pos = Position::new_end_game(xr-xl+1, yb-yt+1);
    for &(x, y) in coords {
        let (frag_x, frag_y) = (x - xl, y - yt);
        for side in Side::all() {
            if pos.is_legal_move(x, y, side) && !frag_pos.is_legal_move(frag_x, frag_y, side) {
                frag_pos.undo_move(frag_x, frag_y, side);
            }
        }
    }
    PositionFragment{pos: frag_pos, x_offset: xl, y_offset: yt}
}

// Split a position into its independent fragments.
// If the position is fully connected, the result will consist of a single element
// representing the whole position.
pub fn split(pos: &Position) -> Vec<PositionFragment> {
    let mut visited: Vec<Vec<bool>> = Vec::with_capacity(pos.width());
    for _ in 0..pos.width() {
        visited.push(iter::repeat(false).take(pos.height()).collect());
    }
    let mut result = Vec::new();
    for x in 0..pos.width() {
        for y in 0..pos.height() {
            if !visited[x][y] && pos.valency(x, y) > 0 {
                let mut frag_coords = Vec::new();
                search(pos, x, y, &mut visited, &mut frag_coords);
                result.push(make_fragment(pos, &frag_coords));
            }
        }
    }
    result
}

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

    #[test]
    fn split_p50() {
        let pos = p50();
        let parts = split(&pos);
        assert_eq!(3, parts.len());

        let top_parts: Vec<&PositionFragment> = parts.iter().filter(|f| f.x_offset == 0 && f.y_offset == 0).collect();
        assert_eq!(1, top_parts.len());
        assert_eq!(true, top_parts[0].pos.eq(&p50_top()));

        let bl_parts: Vec<&PositionFragment> = parts.iter().filter(|f| f.x_offset == 0 && f.y_offset == 2).collect();
        assert_eq!(1, bl_parts.len());
        assert_eq!(true, bl_parts[0].pos.eq(&p50_bottomleft()));

        let br_parts: Vec<&PositionFragment> = parts.iter().filter(|f| f.x_offset == 3 && f.y_offset == 2).collect();
        assert_eq!(1, br_parts.len());
        assert_eq!(true, br_parts[0].pos.eq(&p50_bottomright()));
    }

    #[test]
    fn split_unsplittable() {
        let pos = Position::new_game(3, 3);
        let parts = split(&pos);
        assert_eq!(1, parts.len());
        let frag = &parts[0];
        assert_eq!(0, frag.x_offset);
        assert_eq!(0, frag.y_offset);
        assert_eq!(true, frag.pos.eq(&pos));
    }
}
<|endoftext|>


<commit_before>use mio::net::UdpSocket;
use mio::{Events, Interests, Poll, Token};
use std::io;

const IN: Token = Token(0);

fn main() -> io::Result<()> {
    // Set up a new socket on port 9000 to listen on.
    let socket = UdpSocket::bind("0.0.0.0:9000".parse().unwrap())?;
    // Initialize poller.
    let mut poll = Poll::new()?;
    // Register our socket with the token IN (defined above) and an interest
    // in being `READABLE`.
    poll.registry()
        .register(&socket, IN, Interests::READABLE)?;

    // Prepare a buffer for the number of events we can handle at a time.
    // Someone might wat to echo really fast so lets give it some size.
    let mut events = Events::with_capacity(1024);
    // Initialize a buffer for the UDP datagram
    let mut buf = [0; 65535];
    // Main loop
    loop {
        // Poll if we have events waiting for us on the socket.
        poll.poll(&mut events, None)?;
        // If we do iterate throuigh them
        for event in events.iter() {
            // Validate the token we registered our socket with,
            // in this example it will only ever be one but we
            // make sure it's valid non the less.
            match event.token() {
                IN => loop {
                    // In this loop we receive from the socket as long as we
                    // can read data
                    match socket.recv_from(&mut buf) {
                        Ok((n, from_addr)) => {
                            // Send the data right back from where it came from.
                            socket.send_to(&buf[..n], from_addr)?;
                        }
                        Err(e) => {
                            // If we failed to receive data we have two cases
                            if e.kind() == io::ErrorKind::WouldBlock {
                                // If the reason was `WouldBlock` we know
                                // our socket has no more data to give so
                                // we can return to the poll to wait politely.
                                break;
                            } else {
                                // If it was any other kind of error, something
                                // went wrong and we terminate with an error.
                                return Err(e);
                            }
                        }
                    }
                },
                // We only have IN as a token, so this should never ever be hit
                _ => unreachable!(),
            }
        }
    }
}
<commit_msg>Fix typo and format code<commit_after>use mio::net::UdpSocket;
use mio::{Events, Interests, Poll, Token};
use std::io;

const IN: Token = Token(0);

fn main() -> io::Result<()> {
    // Set up a new socket on port 9000 to listen on.
    let socket = UdpSocket::bind("0.0.0.0:9000".parse().unwrap())?;
    // Initialize poller.
    let mut poll = Poll::new()?;
    // Register our socket with the token IN (defined above) and an interest
    // in being `READABLE`.
    poll.registry().register(&socket, IN, Interests::READABLE)?;

    // Prepare a buffer for the number of events we can handle at a time.
    // Someone might wat to echo really fast so lets give it some size.
    let mut events = Events::with_capacity(1024);
    // Initialize a buffer for the UDP datagram
    let mut buf = [0; 65535];
    // Main loop
    loop {
        // Poll if we have events waiting for us on the socket.
        poll.poll(&mut events, None)?;
        // If we do iterate throuigh them
        for event in events.iter() {
            // Validate the token we registered our socket with,
            // in this example it will only ever be one but we
            // make sure it's valid none the less.
            match event.token() {
                IN => loop {
                    // In this loop we receive from the socket as long as we
                    // can read data
                    match socket.recv_from(&mut buf) {
                        Ok((n, from_addr)) => {
                            // Send the data right back from where it came from.
                            socket.send_to(&buf[..n], from_addr)?;
                        }
                        Err(e) => {
                            // If we failed to receive data we have two cases
                            if e.kind() == io::ErrorKind::WouldBlock {
                                // If the reason was `WouldBlock` we know
                                // our socket has no more data to give so
                                // we can return to the poll to wait politely.
                                break;
                            } else {
                                // If it was any other kind of error, something
                                // went wrong and we terminate with an error.
                                return Err(e);
                            }
                        }
                    }
                },
                // We only have IN as a token, so this should never ever be hit
                _ => unreachable!(),
            }
        }
    }
}
<|endoftext|>


<commit_before>#[doc = "Breaks rustdocs into sections according to their headers"];

export mk_pass;

fn mk_pass() -> pass {
    {
        name: "sectionalize",
        f: run
    }
}

fn run(_srv: astsrv::srv, doc: doc::doc) -> doc::doc {
    let fold = fold::fold({
        fold_item: fold_item,
        fold_iface: fold_iface,
        fold_impl: fold_impl
        with *fold::default_any_fold(())
    });
    fold.fold_doc(fold, doc)
}

fn fold_item(fold: fold::fold<()>, doc: doc::itemdoc) -> doc::itemdoc {
    let doc = fold::default_seq_fold_item(fold, doc);
    let (desc, sections) = sectionalize(doc.desc);

    {
        desc: desc,
        sections: sections
        with doc
    }
}

fn fold_iface(fold: fold::fold<()>, doc: doc::ifacedoc) -> doc::ifacedoc {
    let doc = fold::default_seq_fold_iface(fold, doc);

    {
        methods: par::anymap(doc.methods) {|method|
            let (desc, sections) = sectionalize(method.desc);

            {
                desc: desc,
                sections: sections
                with method
            }
        }
        with doc
    }
}

fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc {
    let doc = fold::default_seq_fold_impl(fold, doc);

    {
        methods: par::anymap(doc.methods) {|method|
            let (desc, sections) = sectionalize(method.desc);

            {
                desc: desc,
                sections: sections
                with method
            }
        }
        with doc
    }
}

fn sectionalize(desc: option<str>) -> (option<str>, [doc::section]) {

    #[doc = "

    Take a description of the form

        General text

        # Section header

        Section text

        # Section header

        Section text

    and remove each header and accompanying text into section records.

    "];

    if option::is_none(desc) {
        ret (none, []);
    }

    let lines = str::lines(option::get(desc));

    let mut new_desc = none::<str>;
    let mut current_section = none;
    let mut sections = [];

    for lines.each {|line|
        alt parse_header(line) {
          some(header) {
            if option::is_some(current_section) {
                sections += [option::get(current_section)];
            }
            current_section = some({
                header: header,
                body: ""
            });
          }
          none {
            alt current_section {
              some(section) {
                current_section = some({
                    body: section.body + "\n" + line
                    with section
                });
              }
              none {
                alt new_desc {
                  some(desc) {
                    new_desc = some(desc + "\n" + line);
                  }
                  none {
                    new_desc = some(line);
                  }
                }
              }
            }
          }
        }
    }

    if option::is_some(current_section) {
        sections += [option::get(current_section)];
    }

    (new_desc, sections)
}

fn parse_header(line: str) -> option<str> {
    if str::starts_with(line, "# ") {
        some(str::slice(line, 2u, str::len(line)))
    } else {
        none
    }
}

#[test]
fn should_create_section_headers() {
    let doc = test::mk_doc(
        "#[doc = \"\
         # Header\n\
         Body\"]\
         mod a { }");
    assert str::contains(
        doc.cratemod().mods()[0].item.sections[0].header,
        "Header");
}

#[test]
fn should_create_section_bodies() {
    let doc = test::mk_doc(
        "#[doc = \"\
         # Header\n\
         Body\"]\
         mod a { }");
    assert str::contains(
        doc.cratemod().mods()[0].item.sections[0].body,
        "Body");
}

#[test]
fn should_not_create_sections_from_indented_headers() {
    let doc = test::mk_doc(
        "#[doc = \"\n\
         Text\n             # Header\n\
         Body\"]\
         mod a { }");
    assert vec::is_empty(doc.cratemod().mods()[0].item.sections);
}

#[test]
fn should_remove_section_text_from_main_desc() {
    let doc = test::mk_doc(
        "#[doc = \"\
         Description\n\n\
         # Header\n\
         Body\"]\
         mod a { }");
    assert !str::contains(
        option::get(doc.cratemod().mods()[0].desc()),
        "Header");
    assert !str::contains(
        option::get(doc.cratemod().mods()[0].desc()),
        "Body");
}

#[test]
fn should_eliminate_desc_if_it_is_just_whitespace() {
    let doc = test::mk_doc(
        "#[doc = \"\
         # Header\n\
         Body\"]\
         mod a { }");
    assert doc.cratemod().mods()[0].desc() == none;
}

#[test]
fn should_sectionalize_iface_methods() {
    let doc = test::mk_doc(
        "iface i {
         #[doc = \"\
         # Header\n\
         Body\"]\
         fn a(); }");
    assert doc.cratemod().ifaces()[0].methods[0].sections.len() == 1u;
}

#[test]
fn should_sectionalize_impl_methods() {
    let doc = test::mk_doc(
        "impl i for bool {
         #[doc = \"\
         # Header\n\
         Body\"]\
         fn a() { } }");
    assert doc.cratemod().impls()[0].methods[0].sections.len() == 1u;
}

#[cfg(test)]
mod test {
    fn mk_doc(source: str) -> doc::doc {
        astsrv::from_str(source) {|srv|
            let doc = extract::from_srv(srv, "");
            let doc = attr_pass::mk_pass().f(srv, doc);
            run(srv, doc)
        }
    }
}
<commit_msg>avoid modifying variable we are alting over<commit_after>#[doc = "Breaks rustdocs into sections according to their headers"];

export mk_pass;

fn mk_pass() -> pass {
    {
        name: "sectionalize",
        f: run
    }
}

fn run(_srv: astsrv::srv, doc: doc::doc) -> doc::doc {
    let fold = fold::fold({
        fold_item: fold_item,
        fold_iface: fold_iface,
        fold_impl: fold_impl
        with *fold::default_any_fold(())
    });
    fold.fold_doc(fold, doc)
}

fn fold_item(fold: fold::fold<()>, doc: doc::itemdoc) -> doc::itemdoc {
    let doc = fold::default_seq_fold_item(fold, doc);
    let (desc, sections) = sectionalize(doc.desc);

    {
        desc: desc,
        sections: sections
        with doc
    }
}

fn fold_iface(fold: fold::fold<()>, doc: doc::ifacedoc) -> doc::ifacedoc {
    let doc = fold::default_seq_fold_iface(fold, doc);

    {
        methods: par::anymap(doc.methods) {|method|
            let (desc, sections) = sectionalize(method.desc);

            {
                desc: desc,
                sections: sections
                with method
            }
        }
        with doc
    }
}

fn fold_impl(fold: fold::fold<()>, doc: doc::impldoc) -> doc::impldoc {
    let doc = fold::default_seq_fold_impl(fold, doc);

    {
        methods: par::anymap(doc.methods) {|method|
            let (desc, sections) = sectionalize(method.desc);

            {
                desc: desc,
                sections: sections
                with method
            }
        }
        with doc
    }
}

fn sectionalize(desc: option<str>) -> (option<str>, [doc::section]) {

    #[doc = "

    Take a description of the form

        General text

        # Section header

        Section text

        # Section header

        Section text

    and remove each header and accompanying text into section records.

    "];

    if option::is_none(desc) {
        ret (none, []);
    }

    let lines = str::lines(option::get(desc));

    let mut new_desc = none::<str>;
    let mut current_section = none;
    let mut sections = [];

    for lines.each {|line|
        alt parse_header(line) {
          some(header) {
            if option::is_some(current_section) {
                sections += [option::get(current_section)];
            }
            current_section = some({
                header: header,
                body: ""
            });
          }
          none {
            alt copy current_section {
              some(section) {
                current_section = some({
                    body: section.body + "\n" + line
                    with section
                });
              }
              none {
                new_desc = alt new_desc {
                  some(desc) {
                    some(desc + "\n" + line)
                  }
                  none {
                    some(line)
                  }
                };
              }
            }
          }
        }
    }

    if option::is_some(current_section) {
        sections += [option::get(current_section)];
    }

    (new_desc, sections)
}

fn parse_header(line: str) -> option<str> {
    if str::starts_with(line, "# ") {
        some(str::slice(line, 2u, str::len(line)))
    } else {
        none
    }
}

#[test]
fn should_create_section_headers() {
    let doc = test::mk_doc(
        "#[doc = \"\
         # Header\n\
         Body\"]\
         mod a { }");
    assert str::contains(
        doc.cratemod().mods()[0].item.sections[0].header,
        "Header");
}

#[test]
fn should_create_section_bodies() {
    let doc = test::mk_doc(
        "#[doc = \"\
         # Header\n\
         Body\"]\
         mod a { }");
    assert str::contains(
        doc.cratemod().mods()[0].item.sections[0].body,
        "Body");
}

#[test]
fn should_not_create_sections_from_indented_headers() {
    let doc = test::mk_doc(
        "#[doc = \"\n\
         Text\n             # Header\n\
         Body\"]\
         mod a { }");
    assert vec::is_empty(doc.cratemod().mods()[0].item.sections);
}

#[test]
fn should_remove_section_text_from_main_desc() {
    let doc = test::mk_doc(
        "#[doc = \"\
         Description\n\n\
         # Header\n\
         Body\"]\
         mod a { }");
    assert !str::contains(
        option::get(doc.cratemod().mods()[0].desc()),
        "Header");
    assert !str::contains(
        option::get(doc.cratemod().mods()[0].desc()),
        "Body");
}

#[test]
fn should_eliminate_desc_if_it_is_just_whitespace() {
    let doc = test::mk_doc(
        "#[doc = \"\
         # Header\n\
         Body\"]\
         mod a { }");
    assert doc.cratemod().mods()[0].desc() == none;
}

#[test]
fn should_sectionalize_iface_methods() {
    let doc = test::mk_doc(
        "iface i {
         #[doc = \"\
         # Header\n\
         Body\"]\
         fn a(); }");
    assert doc.cratemod().ifaces()[0].methods[0].sections.len() == 1u;
}

#[test]
fn should_sectionalize_impl_methods() {
    let doc = test::mk_doc(
        "impl i for bool {
         #[doc = \"\
         # Header\n\
         Body\"]\
         fn a() { } }");
    assert doc.cratemod().impls()[0].methods[0].sections.len() == 1u;
}

#[cfg(test)]
mod test {
    fn mk_doc(source: str) -> doc::doc {
        astsrv::from_str(source) {|srv|
            let doc = extract::from_srv(srv, "");
            let doc = attr_pass::mk_pass().f(srv, doc);
            run(srv, doc)
        }
    }
}
<|endoftext|>


<commit_before>/**
 *   Mles-utils to be used with Mles client or server.
 *   Copyright (C) 2017  Mles developers
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
extern crate mles_utils;

use std::{thread, process, env};
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc::channel;
use std::net::TcpStream;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::net::TcpListener;
use std::collections::HashMap;
use std::io::{Read, Error};
use std::io::Write;
use std::time::Duration;
use std::option::Option;
use std::str;
use mles_utils::*;

const HDRL: u64 = 4;
const KEYL: u64 = 8;
const DELAY: u64 = 50;

fn main() {
    let mut peer = "".to_string();
    let mut argcnt = 0;
    for arg in env::args() {
        argcnt += 1;
        if 2 == argcnt {
            peer = arg;
            peer += ":8077";
            match peer.parse::<SocketAddr>() {
                Ok(_) => {},
                    Err(err) => {
                        println!("Error: {}\nUsage: mles [peer-address]");
                        process::exit(1);
                    },
            }
        }
        if argcnt > 2 {
            println!("Usage: mles [peer-address]");
            process::exit(1);
        }
    }
    let peer = match peer.parse::<SocketAddr>() {
        Ok(addr) => addr,
        Err(_) => {
            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
        },
    };

    let address = "0.0.0.0:8077";
    let listener = match TcpListener::bind(&address) {
        Ok(listener) => listener,
        Err(err) => {
            println!("Error: {}", err);
            process::exit(1);
        },
    };

    let keyval =match env::var("MLES_KEY") {
        Ok(val) => val,
        Err(_) => "".to_string(),
    };

    let mut spawned = HashMap::new();
    let option: Option<Duration> = Some(Duration::from_millis(DELAY));
    let addr = listener.local_addr().unwrap();
    println!("Listening for connections on {}", addr);
    let (tx, rx) = channel();
    let (removedtx, removedrx) = channel();

    for socket in listener.incoming() {
        /* Check first has anybody removed channels */
        let mut remrx = true;
        while remrx {
            match removedrx.try_recv() {
                Ok(val) => {
                    let removed_channel: String = val;
                    println!("Removing unused channel {}", removed_channel.as_str());
                    spawned.remove(&removed_channel);
                    remrx = true;
                },
                Err(_) => { remrx = false; }
            }
        }
        /* 1. Read incoming msg channel
         * 2. If it does not exist, spawn new thread
         * 3. Send socket to thread
         */
        let socket = socket.unwrap();
        let stream = socket.try_clone().unwrap();
        let tuple = read_n(&stream, HDRL);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        let buf = tuple.1;
        if 0 == buf.len() {
            continue;
        }
        if read_hdr_type(buf.as_slice()) != 'M' as u32 {
            println!("Incorrect payload type");
            continue;
        }
        // read key
        let tuple = read_n(&stream, KEYL);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        // verify key
        let hkey;
        let key = read_key(tuple.1);
        if 0 == keyval.len() {
            let paddr = match stream.peer_addr() {
                Ok(paddr) => paddr,
                Err(_) => {
                    let addr = "0.0.0.0:0";
                    let addr = addr.parse::<SocketAddr>().unwrap();
                    addr
                }
            };
            hkey = do_hash(&paddr);
        }
        else {
            hkey = do_hash(&keyval);
        }
        if hkey != key {
            println!("Incorrect remote key");
            continue;
        }
        let tuple = read_n(&stream, read_hdr_len(buf.as_slice()) as u64);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        let buf = tuple.1;
        let decoded_msg = message_decode(buf.as_slice());
        if 0 == decoded_msg.channel.len() {
            continue;
        }
        let _val = socket.set_nodelay(true);
        let _val = socket.set_read_timeout(option);
        if !spawned.contains_key(decoded_msg.channel.as_str()) {
            let tx = tx.clone();
            let removedtx = removedtx.clone();
            let msg = decoded_msg.clone();
            thread::spawn(move|| process_channel(peer, key, tx, removedtx, msg));

            let thr_feed = rx.recv().unwrap();
            spawned.insert(decoded_msg.channel.clone(), thr_feed);
        }
        let thr_socket = spawned.get_mut(&decoded_msg.channel).unwrap();
        thr_socket.send(socket).unwrap();
    }
}

fn process_channel(peer: SocketAddr, key: u64, tx: Sender<Sender<TcpStream>>, removedtx: Sender<String>, msg: Msg ) {
    let mut cnt = 0;
    let (thr_tx, thr_rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
    println!("Spawned: New channel {} created!", msg.channel);
    let mut users = HashMap::new();
    let mut messages: Vec<Vec<u8>> = Vec::new();
    tx.send(thr_tx.clone()).unwrap();

    // just try once during channel creation
    if 0 != peer.port() {
        match TcpStream::connect(peer) {
            Ok(mut sock) => {
                let option: Option<Duration> = Some(Duration::from_millis(DELAY));
                let _val = sock.set_nodelay(true);
                let _val = sock.set_read_timeout(option);
                let encoded_msg = message_encode(&msg);
                let keyv = write_key(key);
                let mut msgv = write_hdr(encoded_msg.len());
                msgv.extend(keyv);
                msgv.extend(encoded_msg);
                sock.write(msgv.as_slice()).unwrap();

                cnt += 1;
                println!("Adding peer {}", cnt);
                users.insert(cnt, sock);
            },
            Err(_) => {
                println!("Could not connect to peer {}", peer);
            },
        }
    }

    loop {
        let mut removals = Vec::new();
        let mut newuser = true;
        while newuser {
            match thr_rx.try_recv() {
                Ok(val) => {
                    let mut thr: TcpStream = val;
                    cnt += 1;
                    println!("Adding user {}", cnt);
                    users.insert(cnt, thr.try_clone().unwrap());

                    /* If a new user, all push messages to her */
                    for buf in &messages {
                        thr.write(buf.as_slice()).unwrap();
                    }
                    newuser = true;
                },
                Err(_) => { newuser = false; }
            }
        }
        for (user, thr_socket) in &users {
            let stream = thr_socket.try_clone().unwrap();
            let tuple = read_n(&stream, HDRL);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    removals.push(user.clone());
                },
                    _ => {}
            }
            let mut buf = tuple.1;
            if 0 == buf.len() {
                continue;
            }
            if read_hdr_type(buf.as_slice()) != 'M' as u32 {
                continue;
            }
            let hdr_len = read_hdr_len(buf.as_slice()) as u64;
            if 0 == hdr_len {
                continue;
            }
            // read key
            let tuple = read_n(&stream, KEYL);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    continue;
                },
                    Ok(_) => {},
                    _ => {
                        continue;
                    },
            }
            let key = tuple.1;
            //ignore key
            buf.extend(key);
            let tuple = read_n(&stream, hdr_len);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    removals.push(user.clone());
                },
                    _ => {}
            }
            let payload = tuple.1;
            if payload.len() != (hdr_len as usize) {
                continue;
            }
            buf.extend(payload);
            for (another_user, mut thr_sock) in &users {
                if user != another_user {
                    thr_sock.write(buf.as_slice()).unwrap();
                }
            }
            /* Add to local db */
            messages.push(buf);
        }
        for removal in &removals {
            println!("Removing user {}", removal);
            users.remove(removal);
        }
        if cnt > 0 && users.is_empty() {
            removedtx.send(msg.channel).unwrap();
            break;
        }
    }
}

fn read_n<R>(reader: R, bytes_to_read: u64) -> (Result<usize, Error>, Vec<u8>)
where R: Read,
{
    let mut buf = vec![];
    let mut chunk = reader.take(bytes_to_read);
    let status = chunk.read_to_end(&mut buf);
    (status, buf)
}

<commit_msg>Fix build.<commit_after>/**
 *   Mles-utils to be used with Mles client or server.
 *   Copyright (C) 2017  Mles developers
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
extern crate mles_utils;

use std::{thread, process, env};
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc::channel;
use std::net::TcpStream;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::net::TcpListener;
use std::collections::HashMap;
use std::io::{Read, Error};
use std::io::Write;
use std::time::Duration;
use std::option::Option;
use std::str;
use mles_utils::*;

const HDRL: u64 = 4;
const KEYL: u64 = 8;
const DELAY: u64 = 50;

fn main() {
    let mut peer = "".to_string();
    let mut argcnt = 0;
    for arg in env::args() {
        argcnt += 1;
        if 2 == argcnt {
            peer = arg;
            peer += ":8077";
            match peer.parse::<SocketAddr>() {
                Ok(_) => {},
                    Err(err) => {
                        println!("Error: {}\nUsage: mles [peer-address]", err);
                        process::exit(1);
                    },
            }
        }
        if argcnt > 2 {
            println!("Usage: mles [peer-address]");
            process::exit(1);
        }
    }
    let peer = match peer.parse::<SocketAddr>() {
        Ok(addr) => addr,
        Err(_) => {
            SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 0)
        },
    };

    let address = "0.0.0.0:8077";
    let listener = match TcpListener::bind(&address) {
        Ok(listener) => listener,
        Err(err) => {
            println!("Error: {}", err);
            process::exit(1);
        },
    };

    let keyval =match env::var("MLES_KEY") {
        Ok(val) => val,
        Err(_) => "".to_string(),
    };

    let mut spawned = HashMap::new();
    let option: Option<Duration> = Some(Duration::from_millis(DELAY));
    let addr = listener.local_addr().unwrap();
    println!("Listening for connections on {}", addr);
    let (tx, rx) = channel();
    let (removedtx, removedrx) = channel();

    for socket in listener.incoming() {
        /* Check first has anybody removed channels */
        let mut remrx = true;
        while remrx {
            match removedrx.try_recv() {
                Ok(val) => {
                    let removed_channel: String = val;
                    println!("Removing unused channel {}", removed_channel.as_str());
                    spawned.remove(&removed_channel);
                    remrx = true;
                },
                Err(_) => { remrx = false; }
            }
        }
        /* 1. Read incoming msg channel
         * 2. If it does not exist, spawn new thread
         * 3. Send socket to thread
         */
        let socket = socket.unwrap();
        let stream = socket.try_clone().unwrap();
        let tuple = read_n(&stream, HDRL);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        let buf = tuple.1;
        if 0 == buf.len() {
            continue;
        }
        if read_hdr_type(buf.as_slice()) != 'M' as u32 {
            println!("Incorrect payload type");
            continue;
        }
        // read key
        let tuple = read_n(&stream, KEYL);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        // verify key
        let hkey;
        let key = read_key(tuple.1);
        if 0 == keyval.len() {
            let paddr = match stream.peer_addr() {
                Ok(paddr) => paddr,
                Err(_) => {
                    let addr = "0.0.0.0:0";
                    let addr = addr.parse::<SocketAddr>().unwrap();
                    addr
                }
            };
            hkey = do_hash(&paddr);
        }
        else {
            hkey = do_hash(&keyval);
        }
        if hkey != key {
            println!("Incorrect remote key");
            continue;
        }
        let tuple = read_n(&stream, read_hdr_len(buf.as_slice()) as u64);
        let status = tuple.0;
        match status {
            Ok(0) => {
               continue;
            },
            Ok(_) => {},
            _ => {
               continue;
            },
        }
        let buf = tuple.1;
        let decoded_msg = message_decode(buf.as_slice());
        if 0 == decoded_msg.channel.len() {
            continue;
        }
        let _val = socket.set_nodelay(true);
        let _val = socket.set_read_timeout(option);
        if !spawned.contains_key(decoded_msg.channel.as_str()) {
            let tx = tx.clone();
            let removedtx = removedtx.clone();
            let msg = decoded_msg.clone();
            thread::spawn(move|| process_channel(peer, key, tx, removedtx, msg));

            let thr_feed = rx.recv().unwrap();
            spawned.insert(decoded_msg.channel.clone(), thr_feed);
        }
        let thr_socket = spawned.get_mut(&decoded_msg.channel).unwrap();
        thr_socket.send(socket).unwrap();
    }
}

fn process_channel(peer: SocketAddr, key: u64, tx: Sender<Sender<TcpStream>>, removedtx: Sender<String>, msg: Msg ) {
    let mut cnt = 0;
    let (thr_tx, thr_rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel();
    println!("Spawned: New channel {} created!", msg.channel);
    let mut users = HashMap::new();
    let mut messages: Vec<Vec<u8>> = Vec::new();
    tx.send(thr_tx.clone()).unwrap();

    // just try once during channel creation
    if 0 != peer.port() {
        match TcpStream::connect(peer) {
            Ok(mut sock) => {
                let option: Option<Duration> = Some(Duration::from_millis(DELAY));
                let _val = sock.set_nodelay(true);
                let _val = sock.set_read_timeout(option);
                let encoded_msg = message_encode(&msg);
                let keyv = write_key(key);
                let mut msgv = write_hdr(encoded_msg.len());
                msgv.extend(keyv);
                msgv.extend(encoded_msg);
                sock.write(msgv.as_slice()).unwrap();

                cnt += 1;
                println!("Adding peer {}", cnt);
                users.insert(cnt, sock);
            },
            Err(_) => {
                println!("Could not connect to peer {}", peer);
            },
        }
    }

    loop {
        let mut removals = Vec::new();
        let mut newuser = true;
        while newuser {
            match thr_rx.try_recv() {
                Ok(val) => {
                    let mut thr: TcpStream = val;
                    cnt += 1;
                    println!("Adding user {}", cnt);
                    users.insert(cnt, thr.try_clone().unwrap());

                    /* If a new user, all push messages to her */
                    for buf in &messages {
                        thr.write(buf.as_slice()).unwrap();
                    }
                    newuser = true;
                },
                Err(_) => { newuser = false; }
            }
        }
        for (user, thr_socket) in &users {
            let stream = thr_socket.try_clone().unwrap();
            let tuple = read_n(&stream, HDRL);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    removals.push(user.clone());
                },
                    _ => {}
            }
            let mut buf = tuple.1;
            if 0 == buf.len() {
                continue;
            }
            if read_hdr_type(buf.as_slice()) != 'M' as u32 {
                continue;
            }
            let hdr_len = read_hdr_len(buf.as_slice()) as u64;
            if 0 == hdr_len {
                continue;
            }
            // read key
            let tuple = read_n(&stream, KEYL);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    continue;
                },
                    Ok(_) => {},
                    _ => {
                        continue;
                    },
            }
            let key = tuple.1;
            //ignore key
            buf.extend(key);
            let tuple = read_n(&stream, hdr_len);
            let status = tuple.0;
            match status {
                Ok(0) => {
                    removals.push(user.clone());
                },
                    _ => {}
            }
            let payload = tuple.1;
            if payload.len() != (hdr_len as usize) {
                continue;
            }
            buf.extend(payload);
            for (another_user, mut thr_sock) in &users {
                if user != another_user {
                    thr_sock.write(buf.as_slice()).unwrap();
                }
            }
            /* Add to local db */
            messages.push(buf);
        }
        for removal in &removals {
            println!("Removing user {}", removal);
            users.remove(removal);
        }
        if cnt > 0 && users.is_empty() {
            removedtx.send(msg.channel).unwrap();
            break;
        }
    }
}

fn read_n<R>(reader: R, bytes_to_read: u64) -> (Result<usize, Error>, Vec<u8>)
where R: Read,
{
    let mut buf = vec![];
    let mut chunk = reader.take(bytes_to_read);
    let status = chunk.read_to_end(&mut buf);
    (status, buf)
}

<|endoftext|>


<commit_before>extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate regex;
extern crate tera;
extern crate file;

extern crate fall_tree;
extern crate fall_parse;
extern crate lang_fall;

use std::error::Error;
use std::io::Write;
use std::path::{PathBuf, Path};
use std::fs;
use std::process::{Command, Stdio};
use fall_tree::{File, AstNode};

mod util;
mod generate;

pub fn generate(file: lang_fall::FallFile) -> generate::Result<String> {
    generate::generate(file)
}

pub struct TestRenderer;

impl TestRenderer {
    pub fn render_one(&mut self, file: &File, test: usize) -> String {
        let file = lang_fall::FallFile::new(file.root());
        let text = match file.tests().nth(test).and_then(|t| t.contents()) {
            None => return String::new(),
            Some(text) => text.to_string()
        };

        match self.render_all(file.node().text().to_string(), Some(text)) {
            Ok(result) => result,
            Err(e) => format!("{}", e),
        }
    }

    pub fn render_all(&mut self, grammar: String, test: Option<String>) -> Result<String, Box<Error>> {
        let file = lang_fall::lang_fall().parse(grammar);
        let ast = lang_fall::ast(&file);
        let parser = match generate(ast) {
            Ok(parser) => parser,
            Err(e) => return Ok(format!("error:\n{}", e))
        };
        let base_dir = base_directory()?;

        let syntax = base_dir.join("src").join("syntax.rs");
        put_text_if_changed(&syntax, &parser)?;

        let toml = base_dir.join("Cargo.toml");
        put_text_if_changed(&toml, &format!(r##"
        [package]
        name = "fall_tests_rendering"
        version = "0.1.0"
        authors = []

        [workspace]

        [dependencies]
        fall_tree = {{ path = "{fall_dir}/fall_tree" }}
        fall_parse = {{ path = "{fall_dir}/fall_parse" }}
    "##, fall_dir = fall_dir().display()))?;

        put_text_if_changed(&base_dir.join("src").join("main.rs"), r##"
        #![allow(warnings)]
        extern crate fall_tree;
        extern crate fall_parse;
        mod syntax;

        use std::io::Read;

        fn main() {
            let mut input = String::new();
            ::std::io::stdin().read_to_string(&mut input).unwrap();
            for test in input.split("\n***###***\n") {
                let file = syntax::LANG.parse(test.to_owned());
                println!("{}\n", fall_tree::dump_file(&file));
            }
        }
    "##)?;

        let build = Command::new("cargo")
            .arg("build")
            .arg("--manifest-path")
            .arg(&toml)
            .spawn()?
            .wait_with_output()?;

        if !build.status.success() {
            return Ok(String::from_utf8(build.stderr).unwrap());
        }

        let mut child = Command::new("cargo")
            .arg("run")
            .arg("--manifest-path")
            .arg(&toml)
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .spawn()?;

        let tests: String = match test {
            Some(test) => test,
            None => ast.tests()
                .filter_map(|t| t.contents())
                .map(|t| t.to_string())
                .collect::<Vec<_>>()
                .join("\n***###***\n")
        };

        {
            let mut stdin = child.stdin.as_mut().unwrap();
            stdin.write_all(tests.as_bytes()).unwrap();
            stdin.flush().unwrap();
        }

        let rendered = child.wait_with_output()?;
        assert!(rendered.status.success());
        let mut result = String::new();
        if !rendered.stderr.is_empty() {
            result += &::std::str::from_utf8(&rendered.stderr).unwrap();
            result += "\n\n";
        }
        result += &::std::str::from_utf8(&rendered.stdout).unwrap();
        Ok(result)
    }
}

fn base_directory() -> Result<PathBuf, Box<Error>> {
    let result = ::std::env::temp_dir().join("fall-tests");
    fs::create_dir_all(&result)?;
    fs::create_dir_all(&result.join("src"))?;
    Ok(result)
}

fn fall_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir).parent().unwrap().to_owned()
}

fn put_text_if_changed(path: &Path, text: &str) -> ::std::io::Result<()> {
    if path.exists() {
        let old_text = file::get_text(path)?;
        if old_text == text {
            return Ok(());
        }
    }
    file::put_text(path, text)
}
<commit_msg>Fix test rendering<commit_after>extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate regex;
extern crate tera;
extern crate file;

extern crate fall_tree;
extern crate fall_parse;
extern crate lang_fall;

use std::error::Error;
use std::io::Write;
use std::path::{PathBuf, Path};
use std::fs;
use std::process::{Command, Stdio};
use fall_tree::{File, AstNode};

mod util;
mod generate;

pub fn generate(file: lang_fall::FallFile) -> generate::Result<String> {
    generate::generate(file)
}

pub struct TestRenderer;

impl TestRenderer {
    pub fn render_one(&mut self, file: &File, test: usize) -> String {
        let file = lang_fall::FallFile::new(file.root());
        let text = match file.tests().nth(test).and_then(|t| t.contents()) {
            None => return String::new(),
            Some(text) => text.to_string()
        };

        match self.render_all(file.node().text().to_string(), Some(text)) {
            Ok(result) => result,
            Err(e) => format!("{}", e),
        }
    }

    pub fn render_all(&mut self, grammar: String, test: Option<String>) -> Result<String, Box<Error>> {
        let file = lang_fall::lang_fall().parse(grammar);
        let ast = lang_fall::ast(&file);
        let parser = match generate(ast) {
            Ok(parser) => parser,
            Err(e) => return Ok(format!("error:\n{}", e))
        };
        let base_dir = base_directory()?;

        let syntax = base_dir.join("src").join("syntax.rs");
        put_text_if_changed(&syntax, &parser)?;

        let toml = base_dir.join("Cargo.toml");
        put_text_if_changed(&toml, &format!(r##"
            [package]
            name = "fall_tests_rendering"
            version = "0.1.0"
            authors = []

            [workspace]

            [dependencies]
            fall_tree = {{ path = "{fall_dir}/fall_tree" }}
            fall_parse = {{ path = "{fall_dir}/fall_parse" }}
        "##, fall_dir = fall_dir().display()))?;

        put_text_if_changed(&base_dir.join("src").join("main.rs"), r##"
            #![allow(warnings)]
            extern crate fall_tree;
            extern crate fall_parse;
            mod syntax;

            use std::io::Read;

            fn main() {
                let mut input = String::new();
                ::std::io::stdin().read_to_string(&mut input).unwrap();
                for test in input.split("\n***###***\n") {
                    let file = syntax::language().parse(test.to_owned());
                    println!("{}\n", fall_tree::dump_file(&file));
                }
            }
        "##)?;

        let build = Command::new("cargo")
            .arg("build")
            .arg("--manifest-path")
            .arg(&toml)
            .spawn()?
            .wait_with_output()?;

        if !build.status.success() {
            let mut output = String::from_utf8(build.stderr).unwrap_or_default();
            output += "\n\n";
            output += &String::from_utf8(build.stdout).unwrap_or_default();
            return Ok(output);
        }

        let mut child = Command::new("cargo")
            .arg("run")
            .arg("--manifest-path")
            .arg(&toml)
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .spawn()?;

        let tests: String = match test {
            Some(test) => test,
            None => ast.tests()
                .filter_map(|t| t.contents())
                .map(|t| t.to_string())
                .collect::<Vec<_>>()
                .join("\n***###***\n")
        };

        {
            let mut stdin = child.stdin.as_mut().unwrap();
            stdin.write_all(tests.as_bytes()).unwrap();
            stdin.flush().unwrap();
        }

        let rendered = child.wait_with_output()?;
        assert!(rendered.status.success());
        let mut result = String::new();
        if !rendered.stderr.is_empty() {
            result += &::std::str::from_utf8(&rendered.stderr).unwrap();
            result += "\n\n";
        }
        result += &::std::str::from_utf8(&rendered.stdout).unwrap();
        Ok(result)
    }
}

fn base_directory() -> Result<PathBuf, Box<Error>> {
    let result = ::std::env::temp_dir().join("fall-tests");
    fs::create_dir_all(&result)?;
    fs::create_dir_all(&result.join("src"))?;
    Ok(result)
}

fn fall_dir() -> PathBuf {
    let dir = env!("CARGO_MANIFEST_DIR");
    PathBuf::from(dir).parent().unwrap().to_owned()
}

fn put_text_if_changed(path: &Path, text: &str) -> ::std::io::Result<()> {
    if path.exists() {
        let old_text = file::get_text(path)?;
        if old_text == text {
            return Ok(());
        }
    }
    file::put_text(path, text)
}
<|endoftext|>