<commit_before>use std::str::FromStr;
use std::collections::HashMap;

type Stack<T> = Vec<T>;

#[derive(Default)]
pub struct Interpreter<'a, 'b, T: 'b> {
    data_stack: Stack<T>,
    vocabulary: HashMap<&'a str, &'b Word<T>>,
}

impl<'a, 'b, T: 'b> Interpreter<'a, 'b, T> where T: FromStr {

    fn push(&mut self, value: T) {
        self.data_stack.push(value)
    }

    fn pop(&mut self) -> Option<T> {
        self.data_stack.pop()
    }

    fn eval_token(&mut self, token: &str) {
        if let Ok(literal) = token.parse::<T>() {
            self.push(literal);
        } else {
            if let Some(&word) = self.lookup(token) {
                word.eval_within(self);
            }
        }
    }

    fn define_word(&mut self, name: &'a str, word: &'b Word<T>) {
        self.vocabulary.insert(name, word);
    }

    fn lookup(&self, token: &str) -> Option<&&'b Word<T>> {
        self.vocabulary.get(token)
    }
}

struct Word<T> {
    entry: Box<Fn(&mut Interpreter<T>) -> ()>,
}

impl<T> Word<T> {
    fn eval_within(&self, i: &mut Interpreter<T>) {
      (self.entry)(i)
    }
}

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

    fn fixture_plus() -> Word<i32> {
        Word {
            entry: Box::new(|ref mut i| {
                if let (Some(b), Some(a)) = (i.pop(), i.pop()) {
                    i.push(a + b)
                } else { panic!("Stack underflow") }
            })
        }
    }

    #[test]
    fn register_word() {
        let plus = fixture_plus(); // FIXME needs to have longer lifetime than the interpreter…
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.define_word("+", &plus);
        interpreter.push(51);
        interpreter.push(42);
        interpreter.eval_token("+");
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn plus_word() {
        let mut interpreter = Interpreter::<i32>::default();
        let plus = fixture_plus();
        interpreter.push(42);
        interpreter.push(51);
        plus.eval_within(&mut interpreter);
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn push_literal() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.eval_token("42");
        assert_eq!(Some(42), interpreter.pop());
    }

    #[test]
    fn pops_nothing() {
        let mut interpreter = Interpreter::<i32>::default();
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_as_pushed() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_in_reverse_order() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        interpreter.push(51);
        assert_eq!(Some(51), interpreter.pop());
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }
}
<commit_msg>Define & eval several words separately<commit_after>use std::str::FromStr;
use std::collections::HashMap;

type Stack<T> = Vec<T>;

#[derive(Default)]
pub struct Interpreter<'a, 'b, T: 'b> {
    data_stack: Stack<T>,
    vocabulary: HashMap<&'a str, &'b Word<T>>,
}

impl<'a, 'b, T: 'b> Interpreter<'a, 'b, T> where T: FromStr {

    fn push(&mut self, value: T) {
        self.data_stack.push(value)
    }

    fn pop(&mut self) -> Option<T> {
        self.data_stack.pop()
    }

    fn eval_token(&mut self, token: &str) {
        if let Ok(literal) = token.parse::<T>() {
            self.push(literal);
        } else {
            if let Some(&word) = self.lookup(token) {
                word.eval_within(self);
            }
        }
    }

    fn define_word(&mut self, name: &'a str, word: &'b Word<T>) {
        self.vocabulary.insert(name, word);
    }

    fn lookup(&self, token: &str) -> Option<&&'b Word<T>> {
        self.vocabulary.get(token)
    }
}

struct Word<T> {
    entry: Box<Fn(&mut Interpreter<T>) -> ()>,
}

impl<T> Word<T> {
    fn eval_within(&self, i: &mut Interpreter<T>) {
      (self.entry)(i)
    }
}

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

    fn fixture_plus() -> Word<i32> {
        Word {
            entry: Box::new(|ref mut i| {
                if let (Some(b), Some(a)) = (i.pop(), i.pop()) {
                    i.push(a + b)
                } else { panic!("Stack underflow") }
            })
        }
    }

    fn fixture_dup() -> Word<i32> {
        Word {
            entry: Box::new(|ref mut i| {
                if let Some(x) = i.pop() {
                    i.push(x);
                    i.push(x);
                } else { panic!("Stack underflow") }
            })
        }
    }

    #[test]
    fn eval_several_words() {
        let plus = fixture_plus();
        let dup = fixture_dup();
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.define_word("+", &plus);
        interpreter.define_word("dup", &dup);
        interpreter.eval_token("2");
        interpreter.eval_token("dup");
        interpreter.eval_token("+");
        assert_eq!(Some(4), interpreter.pop())
    }

    #[test]
    fn register_word() {
        let plus = fixture_plus(); // FIXME needs to have longer lifetime than the interpreter…
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.define_word("+", &plus);
        interpreter.push(51);
        interpreter.push(42);
        interpreter.eval_token("+");
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn plus_word() {
        let mut interpreter = Interpreter::<i32>::default();
        let plus = fixture_plus();
        interpreter.push(42);
        interpreter.push(51);
        plus.eval_within(&mut interpreter);
        assert_eq!(Some(93), interpreter.pop())
    }

    #[test]
    fn push_literal() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.eval_token("42");
        assert_eq!(Some(42), interpreter.pop());
    }

    #[test]
    fn pops_nothing() {
        let mut interpreter = Interpreter::<i32>::default();
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_as_pushed() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }

    #[test]
    fn pops_in_reverse_order() {
        let mut interpreter = Interpreter::<i32>::default();
        interpreter.push(42);
        interpreter.push(51);
        assert_eq!(Some(51), interpreter.pop());
        assert_eq!(Some(42), interpreter.pop());
        assert_eq!(None, interpreter.pop())
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{Sender , Receiver};
use std::marker::PhantomData;
use std::process::exit;

use http_client::HttpClient;
use ota_plus::{get_package_updates, download_package_update, post_packages, send_install_report};
use datatype::{Event, Command, Config, AccessToken, UpdateState, Package, Error, UpdateRequestId, UpdateReport, UpdateResultCode};

pub struct Interpreter<'a, C: HttpClient> {
    client_type: PhantomData<C>,
    config: &'a Config,
    token: AccessToken,
    // Commands mpsc, events spmc
    commands_rx: Receiver<Command>,
    events_tx: Sender<Event>
}

impl<'a, C: HttpClient> Interpreter<'a, C> {
    pub fn new(config: &'a Config, token: AccessToken, commands_rx: Receiver<Command>, events_tx: Sender<Event>) -> Interpreter<'a, C> {
        Interpreter { client_type: PhantomData, config: config, token: token, commands_rx: commands_rx, events_tx: events_tx }
    }

    pub fn start(&self) {
        loop {
            match self.commands_rx.recv() {
                Ok(cmd) => self.interpret(cmd),
                Err(e) => error!("Error receiving command: {:?}", e)
            }
        }
    }

    pub fn interpret(&self, command: Command) {
        match command {
            Command::GetPendingUpdates => self.get_pending_updates(),
            Command::PostInstalledPackages => self.post_installed_packages(),
            Command::AcceptUpdate(ref id) => self.accept_update(id),
            Command::ListInstalledPackages => self.list_installed_packages(),
            Command::Shutdown => {
                info!("Shutting down...");
                exit(0)
            }
        }
    }

    fn publish(&self, event: Event) {
        let _ = self.events_tx.send(event);
    }

    fn get_installed_packages(&self) -> Result<Vec<Package>, Error> {
        self.config.ota.package_manager.installed_packages()
    }

    fn get_pending_updates(&self) {
        debug!("Fetching package updates...");
        let response: Event = match get_package_updates::<C>(&self.token, &self.config) {
            Ok(updates) => {
                let update_events: Vec<Event> = updates.iter().map(move |id| Event::NewUpdateAvailable(id.clone())).collect();
                info!("New package updates available: {:?}", update_events);
                Event::Batch(update_events)
            },
            Err(e) => {
                Event::Error(format!("{}", e))
            }
        };
        self.publish(response);
    }

    fn post_installed_packages(&self) {
        let _ = self.get_installed_packages().and_then(|pkgs| {
            debug!("Found installed packages in the system: {:?}", pkgs);
            post_packages::<C>(&self.token, &self.config, &pkgs)
        }).map(|_| {
            info!("Posted installed packages to the server.");
        }).map_err(|e| {
            error!("Error fetching/posting installed packages: {:?}.", e);
        });
    }

    fn accept_update(&self, id: &UpdateRequestId) {
        info!("Accepting update {}...", id);
        self.publish(Event::UpdateStateChanged(id.clone(), UpdateState::Downloading));
        let report = download_package_update::<C>(&self.token, &self.config, id)
            .and_then(|path| {
                info!("Downloaded at {:?}. Installing...", path);
                self.publish(Event::UpdateStateChanged(id.clone(), UpdateState::Installing));

                let p = try!(path.to_str().ok_or(Error::ParseError(format!("Path is not valid UTF-8: {:?}", path))));
                self.config.ota.package_manager.install_package(p)
                    .map(|(code, output)| {
                        self.publish(Event::UpdateStateChanged(id.clone(), UpdateState::Installed));
                        UpdateReport::new(id.clone(), code, output)
                    })
                    .or_else(|(code, output)| {
                        self.publish(Event::UpdateErrored(id.clone(), format!("{:?}: {:?}", code, output)));
                        Ok(UpdateReport::new(id.clone(), code, output))
                    })
            }).unwrap_or_else(|e| {
                self.publish(Event::UpdateErrored(id.clone(), format!("{:?}", e)));
                UpdateReport::new(id.clone(),
                                   UpdateResultCode::GENERAL_ERROR,
                                   format!("Download failed: {:?}", e))
            });

        match send_install_report::<C>(&self.token, &self.config, &report) {
            Ok(_) => info!("Update finished. Report sent: {:?}", report),
            Err(e) => error!("Error reporting back to the server: {:?}", e)
        }
    }

    fn list_installed_packages(&self) {
        let _ = self.get_installed_packages().and_then(|pkgs| {
            self.publish(Event::FoundInstalledPackages(pkgs.clone()));
            Ok(())
        });
    }
}
<commit_msg>Post installed packages after successful install<commit_after>use std::sync::mpsc::{Sender , Receiver};
use std::marker::PhantomData;
use std::process::exit;

use http_client::HttpClient;
use ota_plus::{get_package_updates, download_package_update, post_packages, send_install_report};
use datatype::{Event, Command, Config, AccessToken, UpdateState, Package, Error, UpdateRequestId, UpdateReport, UpdateResultCode};

pub struct Interpreter<'a, C: HttpClient> {
    client_type: PhantomData<C>,
    config: &'a Config,
    token: AccessToken,
    // Commands mpsc, events spmc
    commands_rx: Receiver<Command>,
    events_tx: Sender<Event>
}

impl<'a, C: HttpClient> Interpreter<'a, C> {
    pub fn new(config: &'a Config, token: AccessToken, commands_rx: Receiver<Command>, events_tx: Sender<Event>) -> Interpreter<'a, C> {
        Interpreter { client_type: PhantomData, config: config, token: token, commands_rx: commands_rx, events_tx: events_tx }
    }

    pub fn start(&self) {
        loop {
            match self.commands_rx.recv() {
                Ok(cmd) => self.interpret(cmd),
                Err(e) => error!("Error receiving command: {:?}", e)
            }
        }
    }

    pub fn interpret(&self, command: Command) {
        match command {
            Command::GetPendingUpdates => self.get_pending_updates(),
            Command::PostInstalledPackages => self.post_installed_packages(),
            Command::AcceptUpdate(ref id) => self.accept_update(id),
            Command::ListInstalledPackages => self.list_installed_packages(),
            Command::Shutdown => {
                info!("Shutting down...");
                exit(0)
            }
        }
    }

    fn publish(&self, event: Event) {
        let _ = self.events_tx.send(event);
    }

    fn get_installed_packages(&self) -> Result<Vec<Package>, Error> {
        self.config.ota.package_manager.installed_packages()
    }

    fn get_pending_updates(&self) {
        debug!("Fetching package updates...");
        let response: Event = match get_package_updates::<C>(&self.token, &self.config) {
            Ok(updates) => {
                let update_events: Vec<Event> = updates.iter().map(move |id| Event::NewUpdateAvailable(id.clone())).collect();
                info!("New package updates available: {:?}", update_events);
                Event::Batch(update_events)
            },
            Err(e) => {
                Event::Error(format!("{}", e))
            }
        };
        self.publish(response);
    }

    fn post_installed_packages(&self) {
        let _ = self.get_installed_packages().and_then(|pkgs| {
            debug!("Found installed packages in the system: {:?}", pkgs);
            post_packages::<C>(&self.token, &self.config, &pkgs)
        }).map(|_| {
            info!("Posted installed packages to the server.");
        }).map_err(|e| {
            error!("Error fetching/posting installed packages: {:?}.", e);
        });
    }

    fn accept_update(&self, id: &UpdateRequestId) {
        info!("Accepting update {}...", id);
        self.publish(Event::UpdateStateChanged(id.clone(), UpdateState::Downloading));
        let report = download_package_update::<C>(&self.token, &self.config, id)
            .and_then(|path| {
                info!("Downloaded at {:?}. Installing...", path);
                self.publish(Event::UpdateStateChanged(id.clone(), UpdateState::Installing));

                let p = try!(path.to_str().ok_or(Error::ParseError(format!("Path is not valid UTF-8: {:?}", path))));
                self.config.ota.package_manager.install_package(p)
                    .map(|(code, output)| {
                        self.publish(Event::UpdateStateChanged(id.clone(), UpdateState::Installed));
                        self.post_installed_packages();
                        UpdateReport::new(id.clone(), code, output)
                    })
                    .or_else(|(code, output)| {
                        self.publish(Event::UpdateErrored(id.clone(), format!("{:?}: {:?}", code, output)));
                        Ok(UpdateReport::new(id.clone(), code, output))
                    })
            }).unwrap_or_else(|e| {
                self.publish(Event::UpdateErrored(id.clone(), format!("{:?}", e)));
                UpdateReport::new(id.clone(),
                                   UpdateResultCode::GENERAL_ERROR,
                                   format!("Download failed: {:?}", e))
            });

        match send_install_report::<C>(&self.token, &self.config, &report) {
            Ok(_) => info!("Update finished. Report sent: {:?}", report),
            Err(e) => error!("Error reporting back to the server: {:?}", e)
        }
    }

    fn list_installed_packages(&self) {
        let _ = self.get_installed_packages().and_then(|pkgs| {
            self.publish(Event::FoundInstalledPackages(pkgs.clone()));
            Ok(())
        });
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Gas metering logic for the Move VM.
use crate::{
    code_cache::module_cache::ModuleCache, execution_stack::ExecutionStack,
    loaded_data::function::FunctionReference,
};
use types::{account_address::ADDRESS_LENGTH, transaction::MAX_TRANSACTION_SIZE_IN_BYTES};
use vm::{access::ModuleAccess, errors::*, file_format::Bytecode, gas_schedule::*};
use vm_runtime_types::value::Local;

/// Holds the state of the gas meter.
pub struct GasMeter {
    // The current amount of gas that is left ("unburnt gas") in the gas meter.
    current_gas_left: GasUnits<GasCarrier>,

    // We need to disable and enable gas metering for both the prologue and epilogue of the Account
    // contract. The VM will then internally unset/set this flag before executing either of them.
    meter_on: bool,
}

// NB: A number of the functions/methods in this struct will return a VMResult<T>
// since we will need to access stack and memory states, and we need to be able
// to report errors properly from these accesses.
impl GasMeter {
    /// Create a new gas meter with starting gas amount `gas_amount`
    pub fn new(gas_amount: GasUnits<GasCarrier>) -> Self {
        GasMeter {
            current_gas_left: gas_amount,
            meter_on: true,
        }
    }

    /// Charges additional gas for the transaction based upon the total size (in bytes) of the
    /// submitted transaction. It is important that we charge for the transaction size since a
    /// transaction can contain arbitrary amounts of bytes in the `note` field. We also want to
    /// disinsentivize large transactions with large notes, so we charge the same amount up to a
    /// cutoff, after which we start charging at a greater rate.
    pub fn charge_transaction_gas<'alloc, 'txn, P>(
        &mut self,
        transaction_size: AbstractMemorySize<GasCarrier>,
        stk: &ExecutionStack<'alloc, 'txn, P>,
    ) -> VMResult<()>
    where
        'alloc: 'txn,
        P: ModuleCache<'alloc>,
    {
        precondition!(transaction_size.get() <= (MAX_TRANSACTION_SIZE_IN_BYTES as u64));
        let cost = calculate_intrinsic_gas(transaction_size);
        self.consume_gas(cost, stk)
    }

    /// Queries the internal state of the gas meter to determine if it has at
    /// least `needed_gas` amount of gas.
    pub fn has_gas(&self, needed_gas: GasUnits<GasCarrier>) -> bool {
        self.current_gas_left
            .app(&needed_gas, |curr_gas, needed_gas| curr_gas >= needed_gas)
    }

    /// Disables metering of gas.
    ///
    /// We need to disable and enable gas metering for both the prologue and epilogue of the
    /// Account contract. The VM will then internally turn off gas metering before executing either
    /// of them using this method.
    pub fn disable_metering(&mut self) {
        self.meter_on = false;
    }

    /// Re-enables metering of gas.
    ///
    /// After executing the prologue and epilogue in the Account contract gas metering is re-enabled
    /// using this method. The VM is responsible for internally calling this method after disabling
    /// gas metering.
    pub fn enable_metering(&mut self) {
        self.meter_on = true;
    }

    /// A wrapper that calculates and then consumes the gas unless metering is disabled.
    pub fn calculate_and_consume<'alloc, 'txn, P>(
        &mut self,
        instr: &Bytecode,
        stk: &ExecutionStack<'alloc, 'txn, P>,
        memory_size: AbstractMemorySize<GasCarrier>,
    ) -> VMResult<()>
    where
        'alloc: 'txn,
        P: ModuleCache<'alloc>,
    {
        if self.meter_on {
            let instruction_gas = try_runtime!(self.gas_for_instruction(instr, stk, memory_size));
            self.consume_gas(instruction_gas, stk)
        } else {
            Ok(Ok(()))
        }
    }

    /// Calculate the gas usage for an instruction taking into account the current stack state, and
    /// the size of memory that is being accessed.
    pub fn gas_for_instruction<'alloc, 'txn, P>(
        &mut self,
        instr: &Bytecode,
        stk: &ExecutionStack<'alloc, 'txn, P>,
        memory_size: AbstractMemorySize<GasCarrier>,
    ) -> VMResult<GasUnits<GasCarrier>>
    where
        'alloc: 'txn,
        P: ModuleCache<'alloc>,
    {
        // Get the base cost for the instruction.
        let instruction_reqs = match instr {
            Bytecode::Add
            | Bytecode::Sub
            | Bytecode::Mul
            | Bytecode::Mod
            | Bytecode::Div
            | Bytecode::BitOr
            | Bytecode::BitAnd
            | Bytecode::Xor
            | Bytecode::Or
            | Bytecode::And
            | Bytecode::Not
            | Bytecode::Eq
            | Bytecode::Neq
            | Bytecode::Lt
            | Bytecode::Gt
            | Bytecode::Le
            | Bytecode::LdTrue
            | Bytecode::LdFalse
            | Bytecode::LdConst(_)
            | Bytecode::Branch(_)
            | Bytecode::Abort
            | Bytecode::Pop
            | Bytecode::BrTrue(_)
            | Bytecode::BrFalse(_)
            | Bytecode::GetTxnGasUnitPrice
            | Bytecode::GetTxnMaxGasUnits
            | Bytecode::GetGasRemaining
            | Bytecode::GetTxnPublicKey
            | Bytecode::GetTxnSenderAddress
            | Bytecode::GetTxnSequenceNumber
            | Bytecode::Ge
            | Bytecode::FreezeRef => {
                let default_gas = static_cost_instr(instr, AbstractMemorySize::new(1));
                Self::gas_of(default_gas)
            }
            Bytecode::LdAddr(_) => {
                let size = AbstractMemorySize::new(ADDRESS_LENGTH as GasCarrier);
                let default_gas = static_cost_instr(instr, size);
                Self::gas_of(default_gas)
            }
            Bytecode::LdByteArray(idx) => {
                let byte_array_ref = stk.top_frame()?.module().byte_array_at(*idx);
                let byte_array_len = AbstractMemorySize::new(byte_array_ref.len() as GasCarrier);
                let byte_array_len = words_in(byte_array_len);
                let default_gas = static_cost_instr(instr, byte_array_len);
                Self::gas_of(default_gas)
            }
            // We charge by the length of the string being stored on the stack.
            Bytecode::LdStr(idx) => {
                let string_ref = stk.top_frame()?.module().string_at(*idx);
                let str_len = AbstractMemorySize::new(string_ref.len() as GasCarrier);
                let str_len = words_in(str_len);
                let default_gas = static_cost_instr(instr, str_len);
                Self::gas_of(default_gas)
            }
            Bytecode::StLoc(_) => {
                // Get the local to store
                let local = stk.peek()?;
                // Get the size of the local
                let size = local.size();
                let default_gas = static_cost_instr(instr, size);
                Self::gas_of(default_gas)
            }
            // Note that a moveLoc incurs a copy overhead
            Bytecode::CopyLoc(local_idx) | Bytecode::MoveLoc(local_idx) => {
                let local = stk.top_frame()?.get_local(*local_idx)?;
                let size = local.size();
                let default_gas = static_cost_instr(instr, size);
                Self::gas_of(default_gas)
            }
            // A return does not affect the value stack at all, and simply pops the call stack
            // -- the callee's frame then knows that the return value(s) will be at the top of the
            // value stack.  Because of this, the cost of the instruction is not dependent upon the
            // size of the value being returned.
            Bytecode::Ret => {
                let default_gas = static_cost_instr(instr, AbstractMemorySize::new(1));
                Self::gas_of(default_gas)
            }
            Bytecode::Call(call_idx, _) => {
                let self_module = &stk.top_frame()?.module();
                let function_ref = try_runtime!(stk
                    .module_cache
                    .resolve_function_ref(self_module, *call_idx))
                .ok_or(VMInvariantViolation::LinkerError)?;
                if function_ref.is_native() {
                    GasUnits::new(0) // This will be costed at the call site/by the native function
                } else {
                    let call_size = AbstractMemorySize::new(function_ref.arg_count() as GasCarrier);
                    let call_gas = static_cost_instr(instr, call_size);
                    Self::gas_of(call_gas)
                }
            }
            Bytecode::Unpack(_, _) => {
                let size = stk.peek()?.size();
                Self::gas_of(static_cost_instr(instr, size))
            }
            Bytecode::Pack(struct_idx, _) => {
                let struct_def = &stk.top_frame()?.module().struct_def_at(*struct_idx);
                // Similar logic applies here as in Call, so we probably don't need to take
                // into account the size of the values on the value stack that we are placing into
                // the struct.
                let member_count = struct_def.declared_field_count()?;
                let arg_count = AbstractMemorySize::new(u64::from(member_count));

                let total_size = arg_count.add(*STRUCT_SIZE);
                let new_gas = static_cost_instr(instr, total_size);
                Self::gas_of(new_gas)
            }
            Bytecode::WriteRef => {
                // Get a reference to the value that we are going to write
                let write_val = stk.peek_at(1)?;
                // Grab the reference that's going to be written to
                let ref_val = stk.peek()?;
                // Get the size of this value and charge accordingly.
                let size = write_val.size();
                let mut default_gas = static_cost_instr(instr, size);
                // Determine if the reference is global. If so charge for any expansion of global
                // memory along with the write operation that will be incurred.
                if let Local::GlobalRef(_) = ref_val {
                    // Charge for any memory expansion
                    let new_val_size = ref_val.size();
                    let size_difference = if new_val_size.app(&size, |new_vl_size, size| new_vl_size > size) {
                        new_val_size.sub(size)
                    } else {
                        // The difference is always >= 0
                        AbstractMemorySize::new(0)
                    };
                    default_gas.memory_gas = default_gas.memory_gas
                        // Charge for the iops on global memory
                        .add(size.mul(*GLOBAL_MEMORY_PER_BYTE_WRITE_COST))
                        // Charge for any memory expansion
                        .add(size_difference.mul(*GLOBAL_MEMORY_PER_BYTE_COST));
                };
                Self::gas_of(default_gas)
            }
            | Bytecode::ReadRef => {
                // NB: We don't charge for reads from global memory: we charge once for the read
                // from global memory that is performed by a BorrowGlobal operation. After this,
                // all ReadRefs will be reading from local cache and we don't need to distinguish.
                let size = stk.peek()?.size();
                let default_gas = static_cost_instr(instr, size);
                Self::gas_of(default_gas)
            }
            | Bytecode::MutBorrowLoc(_)
            | Bytecode::ImmBorrowLoc(_)
            | Bytecode::MutBorrowField(_)
            | Bytecode::ImmBorrowField(_) => {
                let default_gas = static_cost_instr(instr, AbstractMemorySize::new(1));
                Self::gas_of(default_gas)
            }
            Bytecode::CreateAccount => Self::gas_of(static_cost_instr(instr, *DEFAULT_ACCOUNT_SIZE)),
            // Note that we charge twice for these operations; once at the start of
            // `execute_single_instruction` we charge once with size 1. This then covers the cost
            // of accessing the value and guards (somewhat) against abusive memory accesses. Once
            // we have the value/resource in hand we then charge a cost that is dependent on the
            // size of the value being moved.
            //
            // Borrowing a global causes a read of the underlying data. Therefore the cost is
            // dependent on the size of the data being borrowed.
            Bytecode::BorrowGlobal(_, _)
            // In the process of determining if a resource exists, we need to load/read that
            // memory. We therefore need to charge for this query based on the size of the data
            // being accessed.
            | Bytecode::Exists(_, _)
            // A MoveFrom does not trigger a write to memory. But it does push the value of that
            // size onto the stack. So we charge based upon the size of the instruction.
            | Bytecode::MoveFrom(_, _)
            // A MoveToSender causes a write of the resource to storage. We therefore charge based
            // on the size of the resource being moved.
            | Bytecode::MoveToSender(_, _) => {
                let mem_size = if memory_size.get() > 1 {
                    memory_size.sub(AbstractMemorySize::new(1))
                } else {
                    AbstractMemorySize::new(0) // We already charged for size 1
                };
                Self::gas_of(static_cost_instr(instr, mem_size))
            }
        };
        Ok(Ok(instruction_reqs))
    }

    /// Get the amount of gas that remains (that has _not_ been consumed) in the gas meter.
    ///
    /// This method is used by the `GetGasRemaining` bytecode instruction to get the current
    /// amount of gas remaining at the point of call.
    pub fn remaining_gas(&self) -> GasUnits<GasCarrier> {
        self.current_gas_left
    }

    /// Consume the amount of gas given by `gas_amount`. If there is not enough gas
    /// left in the internal state, an `OutOfGasError` is returned.
    pub fn consume_gas<'alloc, 'txn, P>(
        &mut self,
        gas_amount: GasUnits<GasCarrier>,
        stk: &ExecutionStack<'alloc, 'txn, P>,
    ) -> VMResult<()>
    where
        'alloc: 'txn,
        P: ModuleCache<'alloc>,
    {
        if !self.meter_on {
            return Ok(Ok(()));
        }
        if self
            .current_gas_left
            .app(&gas_amount, |curr_gas, gas_amt| curr_gas >= gas_amt)
        {
            self.current_gas_left = self.current_gas_left.sub(gas_amount);
            Ok(Ok(()))
        } else {
            // Zero out the internal gas state
            self.current_gas_left = GasUnits::new(0);
            let location = stk.location().unwrap_or_default();
            Ok(Err(VMRuntimeError {
                loc: location,
                err: VMErrorKind::OutOfGasError,
            }))
        }
    }

    /// Take a GasCost from our gas schedule and convert it to a total gas charge in `GasUnits`.
    ///
    /// This is used internally for converting from a `GasCost` which is a triple of numbers
    /// represeing instruction, stack, and memory consumption into a number of `GasUnits`.
    fn gas_of(gas_cost: GasCost) -> GasUnits<GasCarrier> {
        gas_cost.instruction_gas.add(gas_cost.memory_gas)
    }
}
<commit_msg>[language] Update gas meter to take into account that equality is now deep<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Gas metering logic for the Move VM.
use crate::{
    code_cache::module_cache::ModuleCache, execution_stack::ExecutionStack,
    loaded_data::function::FunctionReference,
};
use types::{account_address::ADDRESS_LENGTH, transaction::MAX_TRANSACTION_SIZE_IN_BYTES};
use vm::{access::ModuleAccess, errors::*, file_format::Bytecode, gas_schedule::*};
use vm_runtime_types::value::Local;

/// Holds the state of the gas meter.
pub struct GasMeter {
    // The current amount of gas that is left ("unburnt gas") in the gas meter.
    current_gas_left: GasUnits<GasCarrier>,

    // We need to disable and enable gas metering for both the prologue and epilogue of the Account
    // contract. The VM will then internally unset/set this flag before executing either of them.
    meter_on: bool,
}

// NB: A number of the functions/methods in this struct will return a VMResult<T>
// since we will need to access stack and memory states, and we need to be able
// to report errors properly from these accesses.
impl GasMeter {
    /// Create a new gas meter with starting gas amount `gas_amount`
    pub fn new(gas_amount: GasUnits<GasCarrier>) -> Self {
        GasMeter {
            current_gas_left: gas_amount,
            meter_on: true,
        }
    }

    /// Charges additional gas for the transaction based upon the total size (in bytes) of the
    /// submitted transaction. It is important that we charge for the transaction size since a
    /// transaction can contain arbitrary amounts of bytes in the `note` field. We also want to
    /// disinsentivize large transactions with large notes, so we charge the same amount up to a
    /// cutoff, after which we start charging at a greater rate.
    pub fn charge_transaction_gas<'alloc, 'txn, P>(
        &mut self,
        transaction_size: AbstractMemorySize<GasCarrier>,
        stk: &ExecutionStack<'alloc, 'txn, P>,
    ) -> VMResult<()>
    where
        'alloc: 'txn,
        P: ModuleCache<'alloc>,
    {
        precondition!(transaction_size.get() <= (MAX_TRANSACTION_SIZE_IN_BYTES as u64));
        let cost = calculate_intrinsic_gas(transaction_size);
        self.consume_gas(cost, stk)
    }

    /// Queries the internal state of the gas meter to determine if it has at
    /// least `needed_gas` amount of gas.
    pub fn has_gas(&self, needed_gas: GasUnits<GasCarrier>) -> bool {
        self.current_gas_left
            .app(&needed_gas, |curr_gas, needed_gas| curr_gas >= needed_gas)
    }

    /// Disables metering of gas.
    ///
    /// We need to disable and enable gas metering for both the prologue and epilogue of the
    /// Account contract. The VM will then internally turn off gas metering before executing either
    /// of them using this method.
    pub fn disable_metering(&mut self) {
        self.meter_on = false;
    }

    /// Re-enables metering of gas.
    ///
    /// After executing the prologue and epilogue in the Account contract gas metering is re-enabled
    /// using this method. The VM is responsible for internally calling this method after disabling
    /// gas metering.
    pub fn enable_metering(&mut self) {
        self.meter_on = true;
    }

    /// A wrapper that calculates and then consumes the gas unless metering is disabled.
    pub fn calculate_and_consume<'alloc, 'txn, P>(
        &mut self,
        instr: &Bytecode,
        stk: &ExecutionStack<'alloc, 'txn, P>,
        memory_size: AbstractMemorySize<GasCarrier>,
    ) -> VMResult<()>
    where
        'alloc: 'txn,
        P: ModuleCache<'alloc>,
    {
        if self.meter_on {
            let instruction_gas = try_runtime!(self.gas_for_instruction(instr, stk, memory_size));
            self.consume_gas(instruction_gas, stk)
        } else {
            Ok(Ok(()))
        }
    }

    /// Calculate the gas usage for an instruction taking into account the current stack state, and
    /// the size of memory that is being accessed.
    pub fn gas_for_instruction<'alloc, 'txn, P>(
        &mut self,
        instr: &Bytecode,
        stk: &ExecutionStack<'alloc, 'txn, P>,
        memory_size: AbstractMemorySize<GasCarrier>,
    ) -> VMResult<GasUnits<GasCarrier>>
    where
        'alloc: 'txn,
        P: ModuleCache<'alloc>,
    {
        // Get the base cost for the instruction.
        let instruction_reqs = match instr {
            Bytecode::Add
            | Bytecode::Sub
            | Bytecode::Mul
            | Bytecode::Mod
            | Bytecode::Div
            | Bytecode::BitOr
            | Bytecode::BitAnd
            | Bytecode::Xor
            | Bytecode::Or
            | Bytecode::And
            | Bytecode::Not
            | Bytecode::Lt
            | Bytecode::Gt
            | Bytecode::Le
            | Bytecode::LdTrue
            | Bytecode::LdFalse
            | Bytecode::LdConst(_)
            | Bytecode::Branch(_)
            | Bytecode::Abort
            | Bytecode::Pop
            | Bytecode::BrTrue(_)
            | Bytecode::BrFalse(_)
            | Bytecode::GetTxnGasUnitPrice
            | Bytecode::GetTxnMaxGasUnits
            | Bytecode::GetGasRemaining
            | Bytecode::GetTxnPublicKey
            | Bytecode::GetTxnSenderAddress
            | Bytecode::GetTxnSequenceNumber
            | Bytecode::Ge
            // Releasing and freezing a reference is not dependent on the size of the underlying data
            | Bytecode::FreezeRef
            // Neither is borrowing local data dependent upon the size of the data
            | Bytecode::MutBorrowLoc(_)
            | Bytecode::ImmBorrowLoc(_)
            | Bytecode::MutBorrowField(_)
            | Bytecode::ImmBorrowField(_)
            // A return does not affect the value stack at all, and simply pops the call stack
            // -- the callee's frame then knows that the return value(s) will be at the top of the
            // value stack.  Because of this, the cost of the instruction is not dependent upon the
            // size of the value being returned.
            | Bytecode::Ret => {
                let default_gas = static_cost_instr(instr, AbstractMemorySize::new(1));
                Self::gas_of(default_gas)
            }
            Bytecode::Eq
            | Bytecode::Neq => {
                let lhs_size = stk.peek()?.size();
                let rhs_size = stk.peek_at(1)?.size();
                let max_size = lhs_size.map2(rhs_size, std::cmp::max);
                Self::gas_of(static_cost_instr(instr, max_size))
            }
            Bytecode::LdAddr(_) => {
                let size = AbstractMemorySize::new(ADDRESS_LENGTH as GasCarrier);
                let default_gas = static_cost_instr(instr, size);
                Self::gas_of(default_gas)
            }
            Bytecode::LdByteArray(idx) => {
                let byte_array_ref = stk.top_frame()?.module().byte_array_at(*idx);
                let byte_array_len = AbstractMemorySize::new(byte_array_ref.len() as GasCarrier);
                let byte_array_len = words_in(byte_array_len);
                let default_gas = static_cost_instr(instr, byte_array_len);
                Self::gas_of(default_gas)
            }
            // We charge by the length of the string being stored on the stack.
            Bytecode::LdStr(idx) => {
                let string_ref = stk.top_frame()?.module().string_at(*idx);
                let str_len = AbstractMemorySize::new(string_ref.len() as GasCarrier);
                let str_len = words_in(str_len);
                let default_gas = static_cost_instr(instr, str_len);
                Self::gas_of(default_gas)
            }
            Bytecode::StLoc(_) => {
                // Get the local to store
                let local = stk.peek()?;
                // Get the size of the local
                let size = local.size();
                let default_gas = static_cost_instr(instr, size);
                Self::gas_of(default_gas)
            }
            // Note that a moveLoc incurs a copy overhead
            Bytecode::CopyLoc(local_idx) | Bytecode::MoveLoc(local_idx) => {
                let local = stk.top_frame()?.get_local(*local_idx)?;
                let size = local.size();
                let default_gas = static_cost_instr(instr, size);
                Self::gas_of(default_gas)
            }
            Bytecode::Call(call_idx, _) => {
                let self_module = &stk.top_frame()?.module();
                let function_ref = try_runtime!(stk
                    .module_cache
                    .resolve_function_ref(self_module, *call_idx))
                .ok_or(VMInvariantViolation::LinkerError)?;
                if function_ref.is_native() {
                    GasUnits::new(0) // This will be costed at the call site/by the native function
                } else {
                    let call_size = AbstractMemorySize::new(function_ref.arg_count() as GasCarrier);
                    let call_gas = static_cost_instr(instr, call_size);
                    Self::gas_of(call_gas)
                }
            }
            Bytecode::Unpack(_, _) => {
                let size = stk.peek()?.size();
                Self::gas_of(static_cost_instr(instr, size))
            }
            Bytecode::Pack(struct_idx, _) => {
                let struct_def = &stk.top_frame()?.module().struct_def_at(*struct_idx);
                // Similar logic applies here as in Call, so we probably don't need to take
                // into account the size of the values on the value stack that we are placing into
                // the struct.
                let member_count = struct_def.declared_field_count()?;
                let arg_count = AbstractMemorySize::new(u64::from(member_count));

                let total_size = arg_count.add(*STRUCT_SIZE);
                let new_gas = static_cost_instr(instr, total_size);
                Self::gas_of(new_gas)
            }
            Bytecode::WriteRef => {
                // Get a reference to the value that we are going to write
                let write_val = stk.peek_at(1)?;
                // Grab the reference that's going to be written to
                let ref_val = stk.peek()?;
                // Get the size of this value and charge accordingly.
                let size = write_val.size();
                let mut default_gas = static_cost_instr(instr, size);
                // Determine if the reference is global. If so charge for any expansion of global
                // memory along with the write operation that will be incurred.
                if let Local::GlobalRef(_) = ref_val {
                    // Charge for any memory expansion
                    let new_val_size = ref_val.size();
                    let size_difference = if new_val_size.app(&size, |new_vl_size, size| new_vl_size > size) {
                        new_val_size.sub(size)
                    } else {
                        // The difference is always >= 0
                        AbstractMemorySize::new(0)
                    };
                    default_gas.memory_gas = default_gas.memory_gas
                        // Charge for the iops on global memory
                        .add(size.mul(*GLOBAL_MEMORY_PER_BYTE_WRITE_COST))
                        // Charge for any memory expansion
                        .add(size_difference.mul(*GLOBAL_MEMORY_PER_BYTE_COST));
                };
                Self::gas_of(default_gas)
            }
            Bytecode::ReadRef => {
                // NB: We don't charge for reads from global memory: we charge once for the read
                // from global memory that is performed by a BorrowGlobal operation. After this,
                // all ReadRefs will be reading from local cache and we don't need to distinguish.
                let size = stk.peek()?.size();
                let default_gas = static_cost_instr(instr, size);
                Self::gas_of(default_gas)
            }
            Bytecode::CreateAccount => Self::gas_of(static_cost_instr(instr, *DEFAULT_ACCOUNT_SIZE)),
            // Note that we charge twice for these operations; once at the start of
            // `execute_single_instruction` we charge once with size 1. This then covers the cost
            // of accessing the value and guards (somewhat) against abusive memory accesses. Once
            // we have the value/resource in hand we then charge a cost that is dependent on the
            // size of the value being moved.
            //
            // Borrowing a global causes a read of the underlying data. Therefore the cost is
            // dependent on the size of the data being borrowed.
            Bytecode::BorrowGlobal(_, _)
            // In the process of determining if a resource exists, we need to load/read that
            // memory. We therefore need to charge for this query based on the size of the data
            // being accessed.
            | Bytecode::Exists(_, _)
            // A MoveFrom does not trigger a write to memory. But it does push the value of that
            // size onto the stack. So we charge based upon the size of the instruction.
            | Bytecode::MoveFrom(_, _)
            // A MoveToSender causes a write of the resource to storage. We therefore charge based
            // on the size of the resource being moved.
            | Bytecode::MoveToSender(_, _) => {
                let mem_size = if memory_size.get() > 1 {
                    memory_size.sub(AbstractMemorySize::new(1))
                } else {
                    AbstractMemorySize::new(0) // We already charged for size 1
                };
                Self::gas_of(static_cost_instr(instr, mem_size))
            }
        };
        Ok(Ok(instruction_reqs))
    }

    /// Get the amount of gas that remains (that has _not_ been consumed) in the gas meter.
    ///
    /// This method is used by the `GetGasRemaining` bytecode instruction to get the current
    /// amount of gas remaining at the point of call.
    pub fn remaining_gas(&self) -> GasUnits<GasCarrier> {
        self.current_gas_left
    }

    /// Consume the amount of gas given by `gas_amount`. If there is not enough gas
    /// left in the internal state, an `OutOfGasError` is returned.
    pub fn consume_gas<'alloc, 'txn, P>(
        &mut self,
        gas_amount: GasUnits<GasCarrier>,
        stk: &ExecutionStack<'alloc, 'txn, P>,
    ) -> VMResult<()>
    where
        'alloc: 'txn,
        P: ModuleCache<'alloc>,
    {
        if !self.meter_on {
            return Ok(Ok(()));
        }
        if self
            .current_gas_left
            .app(&gas_amount, |curr_gas, gas_amt| curr_gas >= gas_amt)
        {
            self.current_gas_left = self.current_gas_left.sub(gas_amount);
            Ok(Ok(()))
        } else {
            // Zero out the internal gas state
            self.current_gas_left = GasUnits::new(0);
            let location = stk.location().unwrap_or_default();
            Ok(Err(VMRuntimeError {
                loc: location,
                err: VMErrorKind::OutOfGasError,
            }))
        }
    }

    /// Take a GasCost from our gas schedule and convert it to a total gas charge in `GasUnits`.
    ///
    /// This is used internally for converting from a `GasCost` which is a triple of numbers
    /// represeing instruction, stack, and memory consumption into a number of `GasUnits`.
    fn gas_of(gas_cost: GasCost) -> GasUnits<GasCarrier> {
        gas_cost.instruction_gas.add(gas_cost.memory_gas)
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use seccomp::{
    allow_syscall, allow_syscall_if, Error, SeccompAction, SeccompCmpOp::Eq,
    SeccompCondition as Cond, SeccompFilter, SeccompRule,
};

/// The default filter containing the white listed syscall rules required by `Firecracker` to
/// function.
///
pub fn default_filter() -> Result<SeccompFilter, Error> {
    Ok(SeccompFilter::new(
        vec![
            #[cfg(target_env = "musl")]
            allow_syscall(libc::SYS_accept),
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_accept4),
            allow_syscall(libc::SYS_brk),
            allow_syscall(libc::SYS_clock_gettime),
            allow_syscall(libc::SYS_close),
            allow_syscall(libc::SYS_dup),
            allow_syscall_if(
                libc::SYS_epoll_ctl,
                or![
                    and![Cond::new(1, Eq, super::EPOLL_CTL_ADD)?],
                    and![Cond::new(1, Eq, super::EPOLL_CTL_DEL)?],
                ],
            ),
            #[cfg(target_env = "musl")]
            allow_syscall(libc::SYS_epoll_pwait),
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_epoll_wait),
            allow_syscall(libc::SYS_exit),
            allow_syscall(libc::SYS_exit_group),
            allow_syscall_if(
                libc::SYS_fcntl,
                or![and![
                    Cond::new(1, Eq, super::FCNTL_F_SETFD)?,
                    Cond::new(2, Eq, super::FCNTL_FD_CLOEXEC)?,
                ]],
            ),
            allow_syscall(libc::SYS_fstat),
            allow_syscall_if(
                libc::SYS_futex,
                or![
                    and![Cond::new(1, Eq, super::FUTEX_WAIT_PRIVATE)?],
                    and![Cond::new(1, Eq, super::FUTEX_WAKE_PRIVATE)?],
                    and![Cond::new(1, Eq, super::FUTEX_REQUEUE_PRIVATE)?],
                    #[cfg(target_env = "gnu")]
                    and![Cond::new(1, Eq, super::FUTEX_CMP_REQUEUE_PRIVATE)?],
                ],
            ),
            allow_syscall(libc::SYS_getrandom),
            allow_syscall_if(libc::SYS_ioctl, super::create_ioctl_seccomp_rule()?),
            allow_syscall(libc::SYS_lseek),
            #[cfg(target_env = "musl")]
            allow_syscall_if(
                libc::SYS_madvise,
                or![and![Cond::new(2, Eq, libc::MADV_DONTNEED as u64)?],],
            ),
            allow_syscall(libc::SYS_mmap),
            allow_syscall(libc::SYS_munmap),
            allow_syscall(libc::SYS_open),
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_openat),
            allow_syscall(libc::SYS_pipe),
            allow_syscall(libc::SYS_read),
            allow_syscall(libc::SYS_readv),
            // SYS_rt_sigreturn is needed in case a fault does occur, so that the signal handler
            // can return. Otherwise we get stuck in a fault loop.
            allow_syscall(libc::SYS_rt_sigreturn),
            allow_syscall(libc::SYS_stat),
            allow_syscall(libc::SYS_timerfd_create),
            allow_syscall(libc::SYS_timerfd_settime),
            allow_syscall(libc::SYS_write),
            allow_syscall(libc::SYS_writev),
        ]
        .into_iter()
        .collect(),
        SeccompAction::Trap,
    )?)
}
<commit_msg>vmm: seccomp whitelist accept4 for all targets<commit_after>// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use seccomp::{
    allow_syscall, allow_syscall_if, Error, SeccompAction, SeccompCmpOp::Eq,
    SeccompCondition as Cond, SeccompFilter, SeccompRule,
};

/// The default filter containing the white listed syscall rules required by `Firecracker` to
/// function.
///
pub fn default_filter() -> Result<SeccompFilter, Error> {
    Ok(SeccompFilter::new(
        vec![
            allow_syscall(libc::SYS_accept4),
            allow_syscall(libc::SYS_brk),
            allow_syscall(libc::SYS_clock_gettime),
            allow_syscall(libc::SYS_close),
            allow_syscall(libc::SYS_dup),
            allow_syscall_if(
                libc::SYS_epoll_ctl,
                or![
                    and![Cond::new(1, Eq, super::EPOLL_CTL_ADD)?],
                    and![Cond::new(1, Eq, super::EPOLL_CTL_DEL)?],
                ],
            ),
            #[cfg(target_env = "musl")]
            allow_syscall(libc::SYS_epoll_pwait),
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_epoll_wait),
            allow_syscall(libc::SYS_exit),
            allow_syscall(libc::SYS_exit_group),
            allow_syscall_if(
                libc::SYS_fcntl,
                or![and![
                    Cond::new(1, Eq, super::FCNTL_F_SETFD)?,
                    Cond::new(2, Eq, super::FCNTL_FD_CLOEXEC)?,
                ]],
            ),
            allow_syscall(libc::SYS_fstat),
            allow_syscall_if(
                libc::SYS_futex,
                or![
                    and![Cond::new(1, Eq, super::FUTEX_WAIT_PRIVATE)?],
                    and![Cond::new(1, Eq, super::FUTEX_WAKE_PRIVATE)?],
                    and![Cond::new(1, Eq, super::FUTEX_REQUEUE_PRIVATE)?],
                    #[cfg(target_env = "gnu")]
                    and![Cond::new(1, Eq, super::FUTEX_CMP_REQUEUE_PRIVATE)?],
                ],
            ),
            allow_syscall(libc::SYS_getrandom),
            allow_syscall_if(libc::SYS_ioctl, super::create_ioctl_seccomp_rule()?),
            allow_syscall(libc::SYS_lseek),
            #[cfg(target_env = "musl")]
            allow_syscall_if(
                libc::SYS_madvise,
                or![and![Cond::new(2, Eq, libc::MADV_DONTNEED as u64)?],],
            ),
            allow_syscall(libc::SYS_mmap),
            allow_syscall(libc::SYS_munmap),
            allow_syscall(libc::SYS_open),
            #[cfg(target_env = "gnu")]
            allow_syscall(libc::SYS_openat),
            allow_syscall(libc::SYS_pipe),
            allow_syscall(libc::SYS_read),
            allow_syscall(libc::SYS_readv),
            // SYS_rt_sigreturn is needed in case a fault does occur, so that the signal handler
            // can return. Otherwise we get stuck in a fault loop.
            allow_syscall(libc::SYS_rt_sigreturn),
            allow_syscall(libc::SYS_stat),
            allow_syscall(libc::SYS_timerfd_create),
            allow_syscall(libc::SYS_timerfd_settime),
            allow_syscall(libc::SYS_write),
            allow_syscall(libc::SYS_writev),
        ]
        .into_iter()
        .collect(),
        SeccompAction::Trap,
    )?)
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_osc;

use std::fmt;
use std::io::Cursor;
use serde::Deserializer;
use serde::de::{SeqVisitor, Visitor};
use serde_osc::de::PktDeserializer;

#[test]
fn basic() {
    /// Struct we'll deserialize into
    #[derive(Debug, PartialEq, Eq)]
    struct Deserialized {
        address: String,
        arg_0: i32,
        arg_1: i32,
    }
    struct MyVisitor;
    impl Visitor for MyVisitor {
        type Value = Deserialized;
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            write!(formatter, "An OSC path followed by two integer arguments")
        }
        fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
            where V: SeqVisitor
        {
            let address = visitor.visit()?.unwrap();
            let arg_0 = visitor.visit()?.unwrap();
            let arg_1 = visitor.visit()?.unwrap();
            Ok(Deserialized{
                address: address,
                arg_0: arg_0,
                arg_1: arg_1})
        }
    }
    let test_input = b"\x00\x00\x00\x1c/example/path\0\0\0,ii\0\x01\x02\x03\x04\x05\x06\x07\x08";
    let expected = Deserialized {
        address: "/example/path".to_owned(),
        arg_0: 0x01020304,
        arg_1: 0x05060708,
    };
    let rd = Cursor::new(test_input);
    let visitor = MyVisitor;
    let mut test_de = PktDeserializer::new(rd);
    let deserialized = test_de.deserialize(visitor).unwrap();
    assert_eq!(deserialized, expected);
}

<commit_msg>Add float & bytes to the deserialization test.<commit_after>extern crate serde;
extern crate serde_osc;

use std::fmt;
use std::io::Cursor;
use serde::Deserializer;
use serde::bytes::ByteBuf;
use serde::de::{SeqVisitor, Visitor};
use serde_osc::de::PktDeserializer;

#[test]
fn basic() {
    /// Struct we'll deserialize into
    #[derive(Debug, PartialEq)]
    struct Deserialized {
        address: String,
        arg_0: i32,
        arg_1: f32,
        arg_2: ByteBuf,
    }
    struct MyVisitor;
    impl Visitor for MyVisitor {
        type Value = Deserialized;
        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            write!(formatter, "An OSC path followed by two integer arguments")
        }
        fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
            where V: SeqVisitor
        {
            let address = visitor.visit()?.unwrap();
            let arg_0 = visitor.visit()?.unwrap();
            let arg_1 = visitor.visit()?.unwrap();
            let arg_2 = visitor.visit()?.unwrap();
            Ok(Deserialized{ address, arg_0, arg_1, arg_2 })
        }
    }
    // Note: 0x43dc0000 is 440.0 in f32.
    let test_input = b"\x00\x00\x00\x2C/example/path\0\0\0,ifb\0\0\0\0\x01\x02\x03\x04\x43\xdc\0\0\0\0\0\x05\xde\xad\xbe\xef\xff\x00\x00\x00";
    let expected = Deserialized {
        address: "/example/path".to_owned(),
        arg_0: 0x01020304,
        arg_1: 440.0,
        arg_2: ByteBuf::from(vec![0xde, 0xad, 0xbe, 0xef, 0xff]),
    };
    let rd = Cursor::new(&test_input[..]);
    let visitor = MyVisitor;
    let mut test_de = PktDeserializer::new(rd);
    let deserialized = test_de.deserialize(visitor).unwrap();
    assert_eq!(deserialized, expected);
}

<|endoftext|>


<commit_before>extern crate libcapstone_sys;

use libcapstone_sys::*;

fn main() {
    assert!(support(CS_ARCH_X86));

    let engine = Builder::new(CS_ARCH_X86, CS_MODE_64)
        .syntax(CS_OPT_SYNTAX_INTEL)
        .detail(CS_OPT_ON)
        .build()
        .expect("Could not create capstone engine");

    let instructions = engine.disasm_all(&[0x31, 0xed, 0x49, 0x89, 0xd1], 0x4a7aa0)
        .expect("Could not disassemble instructions");

    for instruction in instructions.iter() {
        println!("Instruction: id={}, address={}, size={}, bytes={:?}, mnemonic={}, op_str={}, \
                  detail={:?}",
                 instruction.id,
                 instruction.address,
                 instruction.size,
                 instruction.bytes,
                 instruction.get_mnemonic().unwrap(),
                 instruction.get_op_str().unwrap(),
                 instruction.detail);
    }
}
<commit_msg>Fix compilation of examples/disassemble.rs<commit_after>extern crate libcapstone_sys;

use libcapstone_sys::*;

fn main() {
    assert!(support(CS_ARCH_X86));

    let engine = Builder::new(CS_ARCH_X86, CS_MODE_64)
        .syntax(CS_OPT_SYNTAX_INTEL)
        .detail(CS_OPT_ON)
        .build()
        .expect("Could not create capstone engine");

    let instructions = engine.disasm_all(&[0x31, 0xed, 0x49, 0x89, 0xd1], 0x4a7aa0);

    for instruction in instructions.iter() {
        println!("Instruction: id={}, address={}, size={}, bytes={:?}, mnemonic={}, op_str={}, \
                  detail={:?}",
                 instruction.id,
                 instruction.address,
                 instruction.size,
                 instruction.bytes,
                 instruction.get_mnemonic().unwrap(),
                 instruction.get_op_str().unwrap(),
                 instruction.detail);
    }
}
<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate sdl2_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

use std::path::Path;
use std::rc::Rc;
use std::cell::RefCell;
use piston::quack::Get;
use gfx_graphics::gfx::traits::*;
use gfx_graphics::{
    Gfx2d,
    Texture,
    gfx
};
use sdl2_window::{ Sdl2Window, OpenGL };

fn main() {
    let window = Sdl2Window::new(
        OpenGL::_3_2,
        piston::window::WindowSettings {
            title: "gfx_graphics: draw_state_test".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut device = gfx_device_gl::GlDevice::new(Sdl2Window::get_proc_address);
    let piston::window::Size(size) = window.get();
    let frame = gfx::Frame::new(size[0] as u16, size[1] as u16);
    let mut renderer = device.create_renderer();

    let rust_logo = Texture::from_path(&mut device,
        &Path::new("./assets/rust.png")).unwrap();
    let mut g2d = Gfx2d::new(&mut device);
    let window = Rc::new(RefCell::new(window));
    for e in piston::events(window) {
        use piston::event::*;

        if let Some(_) = e.render_args() {
            use graphics::*;

            g2d.draw(&mut renderer, &frame, |c, g| {
                let transform = c.transform.trans(100.0, 100.0);

                clear([1.0; 4], g);
                Rectangle::new([1.0, 0.0, 0.0, 1.0])
                    .draw([0.0, 0.0, 100.0, 100.0],
                          &c.draw_state,
                          c.transform,
                          g);
                Rectangle::new([0.0, 1.0, 0.0, 0.3])
                    .draw([50.0, 50.0, 100.0, 100.0],
                          &c.draw_state,
                          c.transform,
                          g);
                image(&rust_logo, transform, g);
            });

            device.submit(renderer.as_buffer());
            renderer.reset();
        }

        if let Some(_) = e.after_render_args() {
            device.after_frame();
        }
    }
}
<commit_msg>Added blending<commit_after>extern crate piston;
extern crate graphics;
extern crate sdl2_window;
extern crate gfx_device_gl;
extern crate gfx_graphics;

use std::path::Path;
use std::rc::Rc;
use std::cell::RefCell;
use piston::quack::Get;
use gfx_graphics::gfx::traits::*;
use gfx_graphics::{
    Gfx2d,
    Texture,
    gfx
};
use sdl2_window::{ Sdl2Window, OpenGL };

fn main() {
    use graphics::draw_state::BlendPreset;

    println!("Press A to change blending");

    let window = Sdl2Window::new(
        OpenGL::_3_2,
        piston::window::WindowSettings {
            title: "gfx_graphics: draw_state_test".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let mut device = gfx_device_gl::GlDevice::new(Sdl2Window::get_proc_address);
    let piston::window::Size(size) = window.get();
    let frame = gfx::Frame::new(size[0] as u16, size[1] as u16);
    let mut renderer = device.create_renderer();

    let rust_logo = Texture::from_path(&mut device,
        &Path::new("./assets/rust.png")).unwrap();
    let mut g2d = Gfx2d::new(&mut device);
    let mut blend = BlendPreset::Alpha;
    let window = Rc::new(RefCell::new(window));
    for e in piston::events(window) {
        use piston::event::*;
        use piston::input::*;

        if let Some(_) = e.render_args() {
            use graphics::*;

            g2d.draw(&mut renderer, &frame, |c, g| {
                let transform = c.transform.trans(100.0, 100.0);

                clear([0.8, 0.8, 0.8, 1.0], g);
                Rectangle::new([1.0, 0.0, 0.0, 1.0])
                    .draw([0.0, 0.0, 100.0, 100.0],
                          &c.draw_state,
                          c.transform,
                          g);

                let draw_state = c.draw_state.blend(blend);
                Rectangle::new([0.5, 1.0, 0.0, 0.3])
                    .draw([50.0, 50.0, 100.0, 100.0],
                          &draw_state,
                          c.transform,
                          g);
                Image::new().draw(&rust_logo, &c.draw_state, transform, g);
            });

            device.submit(renderer.as_buffer());
            renderer.reset();
        }

        if let Some(Button::Keyboard(Key::A)) = e.press_args() {
            blend = match blend {
                BlendPreset::Alpha => BlendPreset::Additive,
                BlendPreset::Additive => BlendPreset::Multiplicative,
                BlendPreset::Multiplicative => BlendPreset::Alpha,
            };
            println!("Changed blending to {:?}", blend);
        }

        if let Some(_) = e.after_render_args() {
            device.after_frame();
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>iterators wip<commit_after>use std::marker::PhantomData;
use std::fmt;

use cells::Cell;
use grid_traits::{GridDimensions, GridIterators};

pub struct RectGridIterators;
impl<'a, CellT: Cell> GridIterators<CellT> for RectGridIterators {
    type CellIter = RectGridCellIter<'a, CellT>;
    type BatchIter = RectBatchIter;

    fn iter(&self, dimensions: &GridDimensions) -> Self::CellIter {
        RectGridCellIter {
            dimensions: dimensions,
            current_cell_number: 0,
            cells_count: dimensions.size().0,
            cell_type: PhantomData
        }
    }

    fn iter_row(&self, dimensions: &GridDimensions) -> Self::BatchIter {
        RectBatchIter {}
    }

    fn iter_column(&self, dimensions: &GridDimensions) -> Self::BatchIter {
        RectBatchIter {}
    }
}

#[derive(Copy, Clone)]
pub struct RectGridCellIter<'a, CellT: Cell> {
    dimensions: &'a GridDimensions,
    current_cell_number: usize,
    cells_count: usize,
    cell_type: PhantomData<CellT>
}
impl<'a, CellT: Cell> fmt::Debug for RectGridCellIter<'a, CellT> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "CellIter :: current_cell_number: {:?}, cells_count: {:?}",
               self.current_cell_number, self.cells_count)
    }
}
impl<'a, CellT: Cell> ExactSizeIterator for RectGridCellIter<'a, CellT> { } // default impl using size_hint()
impl<'a, CellT: Cell> Iterator for RectGridCellIter<'a, CellT> {
    type Item = CellT::Coord;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current_cell_number < self.cells_count {
            let coord = Self::Item::from_row_major_index(self.current_cell_number,
                                                         self.dimensions);
            self.current_cell_number += 1;
            Some(coord)
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let lower_bound = self.cells_count - self.current_cell_number;
        let upper_bound = lower_bound;
        (lower_bound, Some(upper_bound))
    }
}

struct RectBatchIter {

}
<|endoftext|>


<commit_before>//! Main module to handle the layout.
//! This is where the i3-specific code is.

use std::sync::{Mutex, MutexGuard, TryLockError};
use std::ptr;

use super::container::{Container, Handle, ContainerType};
use super::node::{Node};
use super::super::rustwlc::handle::{WlcView, WlcOutput};

pub type TreeResult = Result<(), TryLockError<MutexGuard<'static, Tree>>>;

const ERR_BAD_TREE: &'static str = "Layout tree was in an invalid configuration";

pub struct Tree {
    root: Node,
    active_container: *const Node,
}

impl Tree {
    fn get_active_container(&self) -> Option<&Node> {
        if self.active_container.is_null() {
            None
        } else {
            unsafe {
                Some(&*self.active_container)
            }
        }
    }

    fn get_active_output(&self) -> Option<&Node> {
        if let Some(node) = self.get_active_container() {
            node.get_ancestor_of_type(ContainerType::Output)
        } else {
            None
        }
    }

    fn get_current_workspace(&self) -> Option<&mut Node> {
        if let Some(container) = self.get_active_container() {
            //if let Some(child) = container.get_ancestor_of_type(ContainerType::Workspace) {
            //return child.get_children()[0].get_parent()

            //}
            // NOTE hack here, remove commented code above to make this work properly
            let parent = container.get_parent().expect(ERR_BAD_TREE);
            for child in parent.get_children_mut() {
                if child == container {
                    return Some(child);
                }
            }
        }
        return None
    }

    fn get_workspace_by_name(&self, name: &str) -> Option<&Node> {
        for child in self.root.get_children()[0].get_children() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn get_workspace_by_name_mut(&mut self, name: &str) -> Option<&mut Node> {
        for child in self.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn add_output(&mut self, wlc_output: WlcOutput) {
        self.root.new_child(Container::new_output(wlc_output));
    }

    fn add_workspace(&mut self, name: String) {
        let workspace = Container::new_workspace(name.to_string());
        let mut index = 0;
        if let Some(output) = self.get_active_output() {
            for (cur_index, child) in self.root.get_children().iter().enumerate() {
                if child == output {
                    index = cur_index;
                    break;
                }
            }
        }
        self.root.get_children_mut()[index].new_child(workspace);
    }

    fn add_view(&self, wlc_view: WlcView) {
        if let Some(current_workspace) = self.get_current_workspace() {
            trace!("Adding view {:?} to {:?}", wlc_view, current_workspace);
            current_workspace.new_child(Container::new_view(wlc_view));
        }
    }

    fn remove_view(&self, wlc_view: &WlcView) {
        if let Some(view) = self.root.find_view_by_handle(&wlc_view) {
            let parent = view.get_parent().expect(ERR_BAD_TREE);
            parent.remove_child(view);
        }
    }
}

unsafe impl Send for Tree {}

lazy_static! {
    static ref TREE: Mutex<Tree> = {
        Mutex::new(Tree{
            root: Node::new(Container::new_root()),
            active_container: ptr::null(),
        })
    };
}

pub fn add_output(wlc_output: WlcOutput) -> TreeResult {
    {
        let mut tree = try!(TREE.try_lock());
        tree.add_output(wlc_output);
    }
    try!(add_workspace("1".to_string()));
    try!(switch_workspace(&"1"));
    Ok(())
}

pub fn add_workspace(name: String) -> TreeResult {
    trace!("Adding new workspace to root");
    let mut tree = try!(TREE.lock());
    tree.add_workspace(name);
    Ok(())
}

pub fn add_view(wlc_view: WlcView) -> TreeResult {
    let tree = try!(TREE.lock());
    tree.add_view(wlc_view);
    Ok(())
}

pub fn remove_view(wlc_view: &WlcView) -> TreeResult {
    let tree = try!(TREE.lock());
    tree.remove_view(wlc_view);
    Ok(())
}

pub fn switch_workspace(name: &str) -> TreeResult {
    trace!("Switching to workspace {}", name);
    let mut tree = try!(TREE.lock());
    if let Some(old_workspace) = tree.get_current_workspace() {
        old_workspace.set_visibility(false);
    }
    let current_workspace: *const Node;
    {
        if let Some(_) = tree.get_workspace_by_name(name) {
            trace!("Found workspace {}", name);
        } else {
            trace!("Adding workspace {}", name);
            tree.add_workspace(name.to_string());
        }
        let new_current_workspace = tree.get_workspace_by_name_mut(name).expect(ERR_BAD_TREE);
        new_current_workspace.set_visibility(true);
        // Set the first view to be focused, so that the view is updated to this new workspace
        if new_current_workspace.get_children().len() > 0 {
            trace!("Focusing view");
            match new_current_workspace.get_children_mut()[0]
                .get_val().get_handle().expect(ERR_BAD_TREE) {
                Handle::View(view) => view.focus(),
                _ => {},
            }
        } else {
            WlcView::root().focus();
        }
        current_workspace = new_current_workspace as *const Node;
    }
    tree.active_container = current_workspace;
    Ok(())
}
<commit_msg>Moved lazy static to top of file<commit_after>//! Main module to handle the layout.
//! This is where the i3-specific code is.

use std::sync::{Mutex, MutexGuard, TryLockError};
use std::ptr;

use super::container::{Container, Handle, ContainerType};
use super::node::{Node};
use super::super::rustwlc::handle::{WlcView, WlcOutput};

pub type TreeResult = Result<(), TryLockError<MutexGuard<'static, Tree>>>;

const ERR_BAD_TREE: &'static str = "Layout tree was in an invalid configuration";

lazy_static! {
    static ref TREE: Mutex<Tree> = {
        Mutex::new(Tree{
            root: Node::new(Container::new_root()),
            active_container: ptr::null(),
        })
    };
}

pub struct Tree {
    root: Node,
    active_container: *const Node,
}

impl Tree {
    fn get_active_container(&self) -> Option<&Node> {
        if self.active_container.is_null() {
            None
        } else {
            unsafe {
                Some(&*self.active_container)
            }
        }
    }

    fn get_active_output(&self) -> Option<&Node> {
        if let Some(node) = self.get_active_container() {
            node.get_ancestor_of_type(ContainerType::Output)
        } else {
            None
        }
    }

    fn get_current_workspace(&self) -> Option<&mut Node> {
        if let Some(container) = self.get_active_container() {
            //if let Some(child) = container.get_ancestor_of_type(ContainerType::Workspace) {
            //return child.get_children()[0].get_parent()

            //}
            // NOTE hack here, remove commented code above to make this work properly
            let parent = container.get_parent().expect(ERR_BAD_TREE);
            for child in parent.get_children_mut() {
                if child == container {
                    return Some(child);
                }
            }
        }
        return None
    }

    fn get_workspace_by_name(&self, name: &str) -> Option<&Node> {
        for child in self.root.get_children()[0].get_children() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn get_workspace_by_name_mut(&mut self, name: &str) -> Option<&mut Node> {
        for child in self.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn add_output(&mut self, wlc_output: WlcOutput) {
        self.root.new_child(Container::new_output(wlc_output));
    }

    fn add_workspace(&mut self, name: String) {
        let workspace = Container::new_workspace(name.to_string());
        let mut index = 0;
        if let Some(output) = self.get_active_output() {
            for (cur_index, child) in self.root.get_children().iter().enumerate() {
                if child == output {
                    index = cur_index;
                    break;
                }
            }
        }
        self.root.get_children_mut()[index].new_child(workspace);
    }

    fn add_view(&self, wlc_view: WlcView) {
        if let Some(current_workspace) = self.get_current_workspace() {
            trace!("Adding view {:?} to {:?}", wlc_view, current_workspace);
            current_workspace.new_child(Container::new_view(wlc_view));
        }
    }

    fn remove_view(&self, wlc_view: &WlcView) {
        if let Some(view) = self.root.find_view_by_handle(&wlc_view) {
            let parent = view.get_parent().expect(ERR_BAD_TREE);
            parent.remove_child(view);
        }
    }
}

unsafe impl Send for Tree {}

pub fn add_output(wlc_output: WlcOutput) -> TreeResult {
    {
        let mut tree = try!(TREE.try_lock());
        tree.add_output(wlc_output);
    }
    try!(add_workspace("1".to_string()));
    try!(switch_workspace(&"1"));
    Ok(())
}

pub fn add_workspace(name: String) -> TreeResult {
    trace!("Adding new workspace to root");
    let mut tree = try!(TREE.lock());
    tree.add_workspace(name);
    Ok(())
}

pub fn add_view(wlc_view: WlcView) -> TreeResult {
    let tree = try!(TREE.lock());
    tree.add_view(wlc_view);
    Ok(())
}

pub fn remove_view(wlc_view: &WlcView) -> TreeResult {
    let tree = try!(TREE.lock());
    tree.remove_view(wlc_view);
    Ok(())
}

pub fn switch_workspace(name: &str) -> TreeResult {
    trace!("Switching to workspace {}", name);
    let mut tree = try!(TREE.lock());
    if let Some(old_workspace) = tree.get_current_workspace() {
        old_workspace.set_visibility(false);
    }
    let current_workspace: *const Node;
    {
        if let Some(_) = tree.get_workspace_by_name(name) {
            trace!("Found workspace {}", name);
        } else {
            trace!("Adding workspace {}", name);
            tree.add_workspace(name.to_string());
        }
        let new_current_workspace = tree.get_workspace_by_name_mut(name).expect(ERR_BAD_TREE);
        new_current_workspace.set_visibility(true);
        // Set the first view to be focused, so that the view is updated to this new workspace
        if new_current_workspace.get_children().len() > 0 {
            trace!("Focusing view");
            match new_current_workspace.get_children_mut()[0]
                .get_val().get_handle().expect(ERR_BAD_TREE) {
                Handle::View(view) => view.focus(),
                _ => {},
            }
        } else {
            WlcView::root().focus();
        }
        current_workspace = new_current_workspace as *const Node;
    }
    tree.active_container = current_workspace;
    Ok(())
}
<|endoftext|>


<commit_before>
//! Helper functions for hue and saturation selection

use image::{
    GenericImage,
    Rgba,
    RgbaImage,
};

/// Selects color at coordinate in a rectangle show hue and saturation
pub fn select(rect: [u32, ..4], x: u32, y: u32) -> Rgba<u8> {
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;

    let fx = (x - rect[0]) as f64 * inv_rect_width;
    let hue = fx * 360.0_f64;
    // Saturation is 0.5 * fy, so by halving the height we save operations.
    let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
    let hi = (hue * inv60) as int;
    let f = hue * inv60 - hi as f64;
    let hi = hi % 6;
    let v = 255; // use white as color without saturation.
    let p = (255.0 * (1.0 - saturation)) as u8;
    let q = (255.0 * (1.0 - f * saturation)) as u8;
    let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
    Rgba([
        match hi {
            0 | 1 => p,
            2 => t,
            3 | 4 => v,
            _ => q
        },
        match hi {
            0 => t,
            1 | 2 => v,
            3 => q,
            _ => p
        },
        match hi {
            1 => q,
            2 | 3 => p,
            4 => t,
            _ => v
        },
        255
    ])
}

/// Sets colors to hue/saturation image.
/// White is used as color without saturation.
/// This is at the top of the image,
/// while saturated colors are at the bottom.
pub fn fill_image(
    image: &mut RgbaImage,
    rect: [u32, ..4]
) {
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;
    for x in range(rect[0], rect[0] + rect[2]) {
        for y in range(rect[1], rect[1] + rect[3]) {
            let fx = (x - rect[0]) as f64 * inv_rect_width;
            let hue = fx * 360.0_f64;
            // Saturation is 0.5 * fy, so by halving the height we save operations.
            let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
            let hi = (hue * inv60) as int;
            let f = hue * inv60 - hi as f64;
            let hi = hi % 6;
            let v = 255; // use white as color without saturation.
            let p = (255.0 * (1.0 - saturation)) as u8;
            let q = (255.0 * (1.0 - f * saturation)) as u8;
            let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
            *image.get_pixel_mut(x, y) = Rgba([
                match hi {
                    0 | 1 => p,
                    2 => t,
                    3 | 4 => v,
                    _ => q
                },
                match hi {
                    0 => t,
                    1 | 2 => v,
                    3 => q,
                    _ => p
                },
                match hi {
                    1 => q,
                    2 | 3 => p,
                    4 => t,
                    _ => v
                },
                255
            ]);
        }
    }
}
<commit_msg>Upgraded to latest Rust<commit_after>
//! Helper functions for hue and saturation selection

use image::{
    GenericImage,
    Rgba,
    RgbaImage,
};

/// Selects color at coordinate in a rectangle show hue and saturation
pub fn select(rect: [u32; 4], x: u32, y: u32) -> Rgba<u8> {
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;

    let fx = (x - rect[0]) as f64 * inv_rect_width;
    let hue = fx * 360.0_f64;
    // Saturation is 0.5 * fy, so by halving the height we save operations.
    let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
    let hi = (hue * inv60) as int;
    let f = hue * inv60 - hi as f64;
    let hi = hi % 6;
    let v = 255; // use white as color without saturation.
    let p = (255.0 * (1.0 - saturation)) as u8;
    let q = (255.0 * (1.0 - f * saturation)) as u8;
    let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
    Rgba([
        match hi {
            0 | 1 => p,
            2 => t,
            3 | 4 => v,
            _ => q
        },
        match hi {
            0 => t,
            1 | 2 => v,
            3 => q,
            _ => p
        },
        match hi {
            1 => q,
            2 | 3 => p,
            4 => t,
            _ => v
        },
        255
    ])
}

/// Sets colors to hue/saturation image.
/// White is used as color without saturation.
/// This is at the top of the image,
/// while saturated colors are at the bottom.
pub fn fill_image(
    image: &mut RgbaImage,
    rect: [u32; 4]
) {
    let inv_rect_width = 1.0_f64 / rect[2] as f64;
    let half_inv_rect_height = 0.5_f64 / rect[3] as f64;
    let inv60 = 1.0_f64 / 60.0_f64;
    for x in range(rect[0], rect[0] + rect[2]) {
        for y in range(rect[1], rect[1] + rect[3]) {
            let fx = (x - rect[0]) as f64 * inv_rect_width;
            let hue = fx * 360.0_f64;
            // Saturation is 0.5 * fy, so by halving the height we save operations.
            let saturation = (y - rect[1]) as f64 * half_inv_rect_height;
            let hi = (hue * inv60) as int;
            let f = hue * inv60 - hi as f64;
            let hi = hi % 6;
            let v = 255; // use white as color without saturation.
            let p = (255.0 * (1.0 - saturation)) as u8;
            let q = (255.0 * (1.0 - f * saturation)) as u8;
            let t = (255.0 * (1.0 - (1.0 - f) * saturation)) as u8;
            *image.get_pixel_mut(x, y) = Rgba([
                match hi {
                    0 | 1 => p,
                    2 => t,
                    3 | 4 => v,
                    _ => q
                },
                match hi {
                    0 => t,
                    1 | 2 => v,
                    3 => q,
                    _ => p
                },
                match hi {
                    1 => q,
                    2 | 3 => p,
                    4 => t,
                    _ => v
                },
                255
            ]);
        }
    }
}
<|endoftext|>