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

use crate::PeerId;
use logger::prelude::*;
use network::validator_network::StateSynchronizerSender;
use rand::{
    distributions::{Distribution, WeightedIndex},
    thread_rng,
};
use std::{
    collections::{HashMap, HashSet},
    time::{Duration, SystemTime},
};

const MAX_SCORE: f64 = 100.0;
const MIN_SCORE: f64 = 1.0;

#[derive(Default, Debug)]
pub struct PeerInfo {
    is_alive: bool,
    is_upstream: bool,
    score: f64,
}

impl PeerInfo {
    pub fn new(is_alive: bool, is_upstream: bool, score: f64) -> Self {
        Self {
            is_alive,
            is_upstream,
            score,
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PeerScoreUpdateType {
    Success,
    InvalidChunk,
    TimeOut,
}

pub struct PeerManager {
    peers: HashMap<PeerId, PeerInfo>,
    network_senders: HashMap<PeerId, StateSynchronizerSender>,
    // Latest requested block versions from a peer
    requests: HashMap<u64, (PeerId, SystemTime)>,
}

impl PeerManager {
    pub fn new(peer_ids: Vec<PeerId>) -> Self {
        let peers = peer_ids
            .into_iter()
            .map(|peer_id| (peer_id, PeerInfo::new(false, true, MAX_SCORE)))
            .collect();
        Self {
            peers,
            network_senders: HashMap::new(),
            requests: HashMap::new(),
        }
    }

    pub fn set_peers(&mut self, peer_ids: Vec<PeerId>) {
        let new_peer_ids: HashSet<_> = peer_ids.iter().collect();
        for (peer_id, info) in self.peers.iter_mut() {
            info.is_upstream = new_peer_ids.contains(peer_id);
        }
        for peer_id in new_peer_ids {
            if !self.peers.contains_key(peer_id) {
                self.peers
                    .insert(*peer_id, PeerInfo::new(false, true, MAX_SCORE));
            }
        }
        debug!("[state sync] (set_peers) state: {:?}", self.peers);
    }

    pub fn enable_peer(&mut self, peer_id: PeerId, sender: StateSynchronizerSender) {
        debug!("[state sync] state before: {:?}", self.peers);
        self.network_senders.insert(peer_id, sender);
        if let Some(peer_info) = self.peers.get_mut(&peer_id) {
            peer_info.is_alive = true;
        } else {
            self.peers
                .insert(peer_id, PeerInfo::new(true, false, MAX_SCORE));
        }
        debug!("[state sync] state after: {:?}", self.peers);
    }

    pub fn disable_peer(&mut self, peer_id: &PeerId) {
        self.network_senders.remove(&peer_id);
        if let Some(peer_info) = self.peers.get_mut(peer_id) {
            peer_info.is_alive = false;
        };
    }

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

    pub fn update_score(&mut self, peer_id: &PeerId, update_type: PeerScoreUpdateType) {
        if let Some(peer_info) = self.peers.get_mut(peer_id) {
            match update_type {
                PeerScoreUpdateType::Success => {
                    let new_score = peer_info.score + 1.0;
                    peer_info.score = new_score.min(MAX_SCORE);
                }
                PeerScoreUpdateType::InvalidChunk => {
                    let new_score = peer_info.score * 0.8;
                    peer_info.score = new_score.max(MIN_SCORE);
                }
                PeerScoreUpdateType::TimeOut => {
                    let new_score = peer_info.score * 0.95;
                    peer_info.score = new_score.max(MIN_SCORE);
                }
            }
        }
    }

    pub fn pick_peer(&mut self) -> Option<(PeerId, StateSynchronizerSender)> {
        let active_peers = self.get_active_upstream_peers();
        debug!("[state sync] (pick_peer) state: {:?}", self.peers);

        if !active_peers.is_empty() {
            let weights: Vec<_> = active_peers
                .iter()
                .map(|(_, peer_info)| peer_info.score)
                .collect();

            if let Ok(weighted_index) = WeightedIndex::new(&weights) {
                let mut rng = thread_rng();
                let peer_id = *active_peers[weighted_index.sample(&mut rng)].0;

                match self.get_network_sender(&peer_id) {
                    Some(sender) => {
                        return Some((peer_id, sender));
                    }
                    None => {
                        debug!("[state sync] (pick_peer) no sender for {}", peer_id);
                    }
                }
            } else {
                error!("[state sync] (pick_peer) invalid weighted index distribution");
            }
        }
        None
    }

    fn get_active_upstream_peers(&self) -> Vec<(&PeerId, &PeerInfo)> {
        self.peers
            .iter()
            .filter(|&(_, peer_info)| peer_info.is_alive && peer_info.is_upstream)
            .collect()
    }

    pub fn get_network_sender(&self, peer_id: &PeerId) -> Option<StateSynchronizerSender> {
        self.network_senders.get(peer_id).cloned()
    }

    pub fn process_request(&mut self, version: u64, peer_id: PeerId) {
        self.requests.insert(version, (peer_id, SystemTime::now()));
    }

    pub fn process_response(&mut self, version: u64, peer_id: PeerId) {
        if let Some((id, _)) = self.requests.get(&version) {
            if *id == peer_id {
                self.requests.remove(&version);
            }
        }
    }

    pub fn process_timeout(&mut self, current_requested_version: u64, timeout: u64) {
        let request = self.requests.get(&current_requested_version).cloned();
        if let Some((peer_id, request_time)) = request {
            if let Some(timeout_threshold) =
                request_time.checked_add(Duration::from_millis(timeout))
            {
                if SystemTime::now().duration_since(timeout_threshold).is_ok() {
                    self.update_score(&peer_id, PeerScoreUpdateType::TimeOut);
                    self.requests.remove(&current_requested_version);
                }
            }
        }
    }
}
<commit_msg>[state-sync] Optimize weight distribution calculation for peer scoring<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::PeerId;
use logger::prelude::*;
use network::validator_network::StateSynchronizerSender;
use rand::{
    distributions::{Distribution, WeightedIndex},
    thread_rng,
};
use std::{
    collections::{HashMap, HashSet},
    time::{Duration, SystemTime},
};

const MAX_SCORE: f64 = 100.0;
const MIN_SCORE: f64 = 1.0;

#[derive(Default, Debug, Clone)]
pub struct PeerInfo {
    is_alive: bool,
    is_upstream: bool,
    score: f64,
}

impl PeerInfo {
    pub fn new(is_alive: bool, is_upstream: bool, score: f64) -> Self {
        Self {
            is_alive,
            is_upstream,
            score,
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PeerScoreUpdateType {
    Success,
    InvalidChunk,
    TimeOut,
}

pub struct PeerManager {
    peers: HashMap<PeerId, PeerInfo>,
    network_senders: HashMap<PeerId, StateSynchronizerSender>,
    // Latest requested block versions from a peer
    requests: HashMap<u64, (PeerId, SystemTime)>,
    weighted_index: Option<WeightedIndex<f64>>,
}

impl PeerManager {
    pub fn new(peer_ids: Vec<PeerId>) -> Self {
        let peers = peer_ids
            .into_iter()
            .map(|peer_id| (peer_id, PeerInfo::new(false, true, MAX_SCORE)))
            .collect();
        Self {
            peers,
            network_senders: HashMap::new(),
            requests: HashMap::new(),
            weighted_index: None,
        }
    }

    pub fn set_peers(&mut self, peer_ids: Vec<PeerId>) {
        let new_peer_ids: HashSet<_> = peer_ids.iter().collect();
        for (peer_id, info) in self.peers.iter_mut() {
            info.is_upstream = new_peer_ids.contains(peer_id);
        }
        for peer_id in new_peer_ids {
            if !self.peers.contains_key(peer_id) {
                self.peers
                    .insert(*peer_id, PeerInfo::new(false, true, MAX_SCORE));
            }
        }
        self.compute_weighted_index();
        debug!("[state sync] (set_peers) state: {:?}", self.peers);
    }

    pub fn enable_peer(&mut self, peer_id: PeerId, sender: StateSynchronizerSender) {
        debug!("[state sync] state before: {:?}", self.peers);
        self.network_senders.insert(peer_id, sender);
        if let Some(peer_info) = self.peers.get_mut(&peer_id) {
            peer_info.is_alive = true;
        } else {
            self.peers
                .insert(peer_id, PeerInfo::new(true, false, MAX_SCORE));
        }
        self.compute_weighted_index();
        debug!("[state sync] state after: {:?}", self.peers);
    }

    pub fn disable_peer(&mut self, peer_id: &PeerId) {
        self.network_senders.remove(&peer_id);
        if let Some(peer_info) = self.peers.get_mut(peer_id) {
            peer_info.is_alive = false;
        };
        self.compute_weighted_index();
    }

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

    pub fn update_score(&mut self, peer_id: &PeerId, update_type: PeerScoreUpdateType) {
        if let Some(peer_info) = self.peers.get_mut(peer_id) {
            let old_score = peer_info.score;
            match update_type {
                PeerScoreUpdateType::Success => {
                    let new_score = peer_info.score + 1.0;
                    peer_info.score = new_score.min(MAX_SCORE);
                }
                PeerScoreUpdateType::InvalidChunk => {
                    let new_score = peer_info.score * 0.8;
                    peer_info.score = new_score.max(MIN_SCORE);
                }
                PeerScoreUpdateType::TimeOut => {
                    let new_score = peer_info.score * 0.95;
                    peer_info.score = new_score.max(MIN_SCORE);
                }
            }
            if (old_score - peer_info.score).abs() > std::f64::EPSILON {
                self.compute_weighted_index();
            }
        }
    }

    fn compute_weighted_index(&mut self) {
        let active_peers = self.get_active_upstream_peers();
        if !active_peers.is_empty() {
            let weights: Vec<_> = active_peers
                .iter()
                .map(|(_, peer_info)| peer_info.score)
                .collect();
            match WeightedIndex::new(&weights) {
                Ok(weighted_index) => {
                    self.weighted_index = Some(weighted_index);
                }
                Err(e) => {
                    error!(
                        "[state sync] (pick_peer) failed to compute weighted index, {:?}",
                        e
                    );
                }
            }
        }
    }

    pub fn pick_peer(&self) -> Option<(PeerId, StateSynchronizerSender)> {
        let active_peers = self.get_active_upstream_peers();
        debug!("[state sync] (pick_peer) state: {:?}", self.peers);

        if let Some(weighted_index) = &self.weighted_index {
            let mut rng = thread_rng();
            if let Some(peer) = active_peers.get(weighted_index.sample(&mut rng)) {
                let peer_id = *peer.0;
                if let Some(sender) = self.get_network_sender(&peer_id) {
                    return Some((peer_id, sender));
                } else {
                    debug!("[state sync] (pick_peer) no sender for {}", peer_id);
                }
            }
        }
        None
    }

    fn get_active_upstream_peers(&self) -> Vec<(&PeerId, &PeerInfo)> {
        self.peers
            .iter()
            .filter(|&(_, peer_info)| peer_info.is_alive && peer_info.is_upstream)
            .collect()
    }

    pub fn get_network_sender(&self, peer_id: &PeerId) -> Option<StateSynchronizerSender> {
        self.network_senders.get(peer_id).cloned()
    }

    pub fn process_request(&mut self, version: u64, peer_id: PeerId) {
        self.requests.insert(version, (peer_id, SystemTime::now()));
    }

    pub fn process_response(&mut self, version: u64, peer_id: PeerId) {
        if let Some((id, _)) = self.requests.get(&version) {
            if *id == peer_id {
                self.requests.remove(&version);
            }
        }
    }

    pub fn process_timeout(&mut self, current_requested_version: u64, timeout: u64) {
        let request = self.requests.get(&current_requested_version).cloned();
        if let Some((peer_id, request_time)) = request {
            if let Some(timeout_threshold) =
                request_time.checked_add(Duration::from_millis(timeout))
            {
                if SystemTime::now().duration_since(timeout_threshold).is_ok() {
                    self.update_score(&peer_id, PeerScoreUpdateType::TimeOut);
                    self.requests.remove(&current_requested_version);
                }
            }
        }
    }
}
<|endoftext|>


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

//! This file defines state store APIs that are related account state Merkle tree.

#[cfg(test)]
mod state_store_test;

use crate::schema::{account_state::AccountStateSchema, state_merkle_node::StateMerkleNodeSchema};
use crypto::{hash::CryptoHash, HashValue};
use failure::prelude::*;
use schemadb::{SchemaBatch, DB};
use sparse_merkle::{node_type::Node, SparseMerkleTree, TreeReader};
use std::{collections::HashMap, sync::Arc};
use types::{
    account_address::AccountAddress,
    account_state_blob::AccountStateBlob,
    proof::{verify_sparse_merkle_element, SparseMerkleProof},
};

pub(crate) struct StateStore {
    db: Arc<DB>,
}

impl StateStore {
    pub fn new(db: Arc<DB>) -> Self {
        Self { db }
    }

    /// Get the account state blob given account address and root hash of state Merkle tree
    pub fn get_account_state_with_proof_by_state_root(
        &self,
        address: AccountAddress,
        root_hash: HashValue,
    ) -> Result<(Option<AccountStateBlob>, SparseMerkleProof)> {
        let (blob, proof) =
            SparseMerkleTree::new(self).get_with_proof(address.hash(), root_hash)?;
        debug_assert!(
            verify_sparse_merkle_element(root_hash, address.hash(), &blob, &proof).is_ok(),
            "Invalid proof."
        );
        Ok((blob, proof))
    }

    /// Put the results generated by `keyed_blob_sets` to `batch` and return the result root hashes
    /// for each write set.
    pub fn put_account_state_sets(
        &self,
        account_state_sets: Vec<HashMap<AccountAddress, AccountStateBlob>>,
        root_hash: HashValue,
        batch: &mut SchemaBatch,
    ) -> Result<Vec<HashValue>> {
        let keyed_blob_sets = account_state_sets
            .into_iter()
            .map(|account_states| {
                account_states
                    .into_iter()
                    .map(|(addr, blob)| (addr.hash(), blob))
                    .collect::<Vec<_>>()
            })
            .collect::<Vec<_>>();

        let (new_root_hash_vec, tree_update_batch) =
            SparseMerkleTree::new(self).put_keyed_blob_sets(keyed_blob_sets, root_hash)?;
        let (node_batch, blob_batch) = tree_update_batch.into();
        node_batch
            .iter()
            .map(|(node_hash, node)| batch.put::<StateMerkleNodeSchema>(node_hash, node))
            .collect::<Result<Vec<()>>>()?;
        blob_batch
            .iter()
            .map(|(blob_hash, blob)| batch.put::<AccountStateSchema>(blob_hash, blob))
            .collect::<Result<Vec<()>>>()?;
        Ok(new_root_hash_vec)
    }
}

impl TreeReader for StateStore {
    fn get_node(&self, node_hash: HashValue) -> Result<Node> {
        Ok(self
            .db
            .get::<StateMerkleNodeSchema>(&node_hash)?
            .ok_or_else(|| format_err!("Failed to find node with hash {:?}", node_hash))?)
    }

    fn get_blob(&self, blob_hash: HashValue) -> Result<AccountStateBlob> {
        Ok(self
            .db
            .get::<AccountStateSchema>(&blob_hash)?
            .ok_or_else(|| {
                format_err!(
                    "Failed to find account state blob with hash {:?}",
                    blob_hash
                )
            })?)
    }
}
<commit_msg>[Storage][trivial] doc fix on StateStore::put_account_state_sets()<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This file defines state store APIs that are related account state Merkle tree.

#[cfg(test)]
mod state_store_test;

use crate::schema::{account_state::AccountStateSchema, state_merkle_node::StateMerkleNodeSchema};
use crypto::{hash::CryptoHash, HashValue};
use failure::prelude::*;
use schemadb::{SchemaBatch, DB};
use sparse_merkle::{node_type::Node, SparseMerkleTree, TreeReader};
use std::{collections::HashMap, sync::Arc};
use types::{
    account_address::AccountAddress,
    account_state_blob::AccountStateBlob,
    proof::{verify_sparse_merkle_element, SparseMerkleProof},
};

pub(crate) struct StateStore {
    db: Arc<DB>,
}

impl StateStore {
    pub fn new(db: Arc<DB>) -> Self {
        Self { db }
    }

    /// Get the account state blob given account address and root hash of state Merkle tree
    pub fn get_account_state_with_proof_by_state_root(
        &self,
        address: AccountAddress,
        root_hash: HashValue,
    ) -> Result<(Option<AccountStateBlob>, SparseMerkleProof)> {
        let (blob, proof) =
            SparseMerkleTree::new(self).get_with_proof(address.hash(), root_hash)?;
        debug_assert!(
            verify_sparse_merkle_element(root_hash, address.hash(), &blob, &proof).is_ok(),
            "Invalid proof."
        );
        Ok((blob, proof))
    }

    /// Put the results generated by `account_state_sets` to `batch` and return the result root
    /// hashes for each write set.
    pub fn put_account_state_sets(
        &self,
        account_state_sets: Vec<HashMap<AccountAddress, AccountStateBlob>>,
        root_hash: HashValue,
        batch: &mut SchemaBatch,
    ) -> Result<Vec<HashValue>> {
        let keyed_blob_sets = account_state_sets
            .into_iter()
            .map(|account_states| {
                account_states
                    .into_iter()
                    .map(|(addr, blob)| (addr.hash(), blob))
                    .collect::<Vec<_>>()
            })
            .collect::<Vec<_>>();

        let (new_root_hash_vec, tree_update_batch) =
            SparseMerkleTree::new(self).put_keyed_blob_sets(keyed_blob_sets, root_hash)?;
        let (node_batch, blob_batch) = tree_update_batch.into();
        node_batch
            .iter()
            .map(|(node_hash, node)| batch.put::<StateMerkleNodeSchema>(node_hash, node))
            .collect::<Result<Vec<()>>>()?;
        blob_batch
            .iter()
            .map(|(blob_hash, blob)| batch.put::<AccountStateSchema>(blob_hash, blob))
            .collect::<Result<Vec<()>>>()?;
        Ok(new_root_hash_vec)
    }
}

impl TreeReader for StateStore {
    fn get_node(&self, node_hash: HashValue) -> Result<Node> {
        Ok(self
            .db
            .get::<StateMerkleNodeSchema>(&node_hash)?
            .ok_or_else(|| format_err!("Failed to find node with hash {:?}", node_hash))?)
    }

    fn get_blob(&self, blob_hash: HashValue) -> Result<AccountStateBlob> {
        Ok(self
            .db
            .get::<AccountStateSchema>(&blob_hash)?
            .ok_or_else(|| {
                format_err!(
                    "Failed to find account state blob with hash {:?}",
                    blob_hash
                )
            })?)
    }
}
<|endoftext|>


<commit_before>//! af-opencl-interop package is to used only when the application intends to mix
//! arrayfire code with raw OpenCL code.
//!
//! Functions from this crate return OpenCL C API opaque pointers typedefs
//!
//! - [cl_device_id](https://docs.rs/cl-sys/0.4.2/cl_sys/type.cl_device_id.html)
//! - [cl_context](https://docs.rs/cl-sys/0.4.2/cl_sys/type.cl_context.html)
//! - [cl_command_queue](https://docs.rs/cl-sys/0.4.2/cl_sys/type.cl_command_queue.html)

use arrayfire::{AfError, HANDLE_ERROR};
use cl_sys::{
    cl_command_queue, cl_context, cl_device_id, CL_DEVICE_TYPE_ACCELERATOR, CL_DEVICE_TYPE_ALL,
    CL_DEVICE_TYPE_CPU, CL_DEVICE_TYPE_DEFAULT, CL_DEVICE_TYPE_GPU,
};
use libc::c_int;
use std::mem;

/// OpenCL Vendor Platform
#[repr(i32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum VendorPlatform {
    AMD = 0,
    APPLE = 1,
    INTEL = 2,
    NVIDIA = 3,
    BEIGNET = 4,
    POCL = 5,
    UNKNOWN = -1,
}

/// OpenCL Device Type
#[repr(u64)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DeviceType {
    DEFAULT = CL_DEVICE_TYPE_DEFAULT,
    CPU = CL_DEVICE_TYPE_CPU,
    GPU = CL_DEVICE_TYPE_GPU,
    ACCEL = CL_DEVICE_TYPE_ACCELERATOR,
    ALL = CL_DEVICE_TYPE_ALL,
}

extern "C" {
    fn afcl_get_context(ctx: *mut cl_context, retain: bool) -> c_int;
    fn afcl_get_queue(queue: *mut cl_command_queue, retain: bool) -> c_int;
    fn afcl_get_device_id(out: *mut cl_device_id) -> c_int;
    fn afcl_set_device_id(id: cl_device_id) -> c_int;

    fn afcl_add_device_context(
        dev_id: cl_device_id,
        ctx: cl_context,
        queue: cl_command_queue,
    ) -> c_int;
    fn afcl_set_device_context(dev_id: cl_device_id, ctx: cl_context) -> c_int;
    fn afcl_delete_device_context(dev_id: cl_device_id, ctx: cl_context) -> c_int;

    fn afcl_get_device_type(dtype: *mut c_int) -> c_int;
    fn afcl_get_platform(ptype: *mut c_int) -> c_int;
}

/// Get the handle to active ArrayFire OpenCL context
pub fn get_context(retain: bool) -> cl_context {
    unsafe {
        let mut out: cl_context = std::ptr::null_mut();
        let err_val = afcl_get_context(&mut out as *mut cl_context, retain);
        HANDLE_ERROR(AfError::from(err_val));
        out
    }
}

/// Get the handle to active ArrayFire OpenCL command queue
pub fn get_queue(retain: bool) -> cl_command_queue {
    unsafe {
        let mut out: cl_command_queue = std::ptr::null_mut();
        let err_val = afcl_get_queue(&mut out as *mut cl_command_queue, retain);
        HANDLE_ERROR(AfError::from(err_val));
        out
    }
}

/// Get the handle to active ArrayFire OpenCL device
pub fn get_device_id() -> cl_device_id {
    unsafe {
        let mut out: cl_device_id = std::ptr::null_mut();
        let err_val = afcl_get_device_id(&mut out as *mut cl_device_id);
        HANDLE_ERROR(AfError::from(err_val));
        out
    }
}

/// Set the cl_device_id as the active ArrayFire OpenCL device
pub fn set_device_id(dev_id: cl_device_id) {
    unsafe {
        let err_val = afcl_set_device_id(dev_id);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Push user provided device, context and queue tuple to ArrayFire device mamanger
pub fn add_device_context(dev_id: cl_device_id, ctx: cl_context, queue: cl_command_queue) {
    unsafe {
        let err_val = afcl_add_device_context(dev_id, ctx, queue);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Set the device identified by device & context pair as the active device for ArrayFire
pub fn set_device_context(dev_id: cl_device_id, ctx: cl_context) {
    unsafe {
        let err_val = afcl_set_device_context(dev_id, ctx);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

/// Remove the user provided device, context pair from ArrayFire device mamanger
pub fn delete_device_context(dev_id: cl_device_id, ctx: cl_context) {
    unsafe {
        let err_val = afcl_delete_device_context(dev_id, ctx);
        HANDLE_ERROR(AfError::from(err_val));
    }
}

///// Fetch Active ArrayFire device's type i.e. CPU/GPU/Accelerator etc.
pub fn get_device_type() -> DeviceType {
    unsafe {
        let mut out: i32 = 0;
        let err_val = afcl_get_device_type(&mut out as *mut c_int);
        HANDLE_ERROR(AfError::from(err_val));
        match out {
            -1 => mem::transmute(out as u64),
            _ => DeviceType::ALL,
        }
    }
}

/// Fetch Active ArrayFire device's vendor platform
pub fn get_platform() -> VendorPlatform {
    unsafe {
        let mut out: i32 = 0;
        let err_val = afcl_get_platform(&mut out as *mut c_int);
        HANDLE_ERROR(AfError::from(err_val));
        mem::transmute(out)
    }
}
<commit_msg>Fix function name typo in opencl interop crate<commit_after>//! af-opencl-interop package is to used only when the application intends to mix
//! arrayfire code with raw OpenCL code.
//!
//! Functions from this crate return OpenCL C API opaque pointers typedefs
//!
//! - [cl_device_id](https://docs.rs/cl-sys/0.4.2/cl_sys/type.cl_device_id.html)
//! - [cl_context](https://docs.rs/cl-sys/0.4.2/cl_sys/type.cl_context.html)
//! - [cl_command_queue](https://docs.rs/cl-sys/0.4.2/cl_sys/type.cl_command_queue.html)

use arrayfire::{handle_error_general, AfError};
use cl_sys::{
    cl_command_queue, cl_context, cl_device_id, CL_DEVICE_TYPE_ACCELERATOR, CL_DEVICE_TYPE_ALL,
    CL_DEVICE_TYPE_CPU, CL_DEVICE_TYPE_DEFAULT, CL_DEVICE_TYPE_GPU,
};
use libc::c_int;
use std::mem;

/// OpenCL Vendor Platform
#[repr(i32)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum VendorPlatform {
    AMD = 0,
    APPLE = 1,
    INTEL = 2,
    NVIDIA = 3,
    BEIGNET = 4,
    POCL = 5,
    UNKNOWN = -1,
}

/// OpenCL Device Type
#[repr(u64)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DeviceType {
    DEFAULT = CL_DEVICE_TYPE_DEFAULT,
    CPU = CL_DEVICE_TYPE_CPU,
    GPU = CL_DEVICE_TYPE_GPU,
    ACCEL = CL_DEVICE_TYPE_ACCELERATOR,
    ALL = CL_DEVICE_TYPE_ALL,
}

extern "C" {
    fn afcl_get_context(ctx: *mut cl_context, retain: bool) -> c_int;
    fn afcl_get_queue(queue: *mut cl_command_queue, retain: bool) -> c_int;
    fn afcl_get_device_id(out: *mut cl_device_id) -> c_int;
    fn afcl_set_device_id(id: cl_device_id) -> c_int;

    fn afcl_add_device_context(
        dev_id: cl_device_id,
        ctx: cl_context,
        queue: cl_command_queue,
    ) -> c_int;
    fn afcl_set_device_context(dev_id: cl_device_id, ctx: cl_context) -> c_int;
    fn afcl_delete_device_context(dev_id: cl_device_id, ctx: cl_context) -> c_int;

    fn afcl_get_device_type(dtype: *mut c_int) -> c_int;
    fn afcl_get_platform(ptype: *mut c_int) -> c_int;
}

/// Get the handle to active ArrayFire OpenCL context
pub fn get_context(retain: bool) -> cl_context {
    unsafe {
        let mut out: cl_context = std::ptr::null_mut();
        let err_val = afcl_get_context(&mut out as *mut cl_context, retain);
        handle_error_general(AfError::from(err_val));
        out
    }
}

/// Get the handle to active ArrayFire OpenCL command queue
pub fn get_queue(retain: bool) -> cl_command_queue {
    unsafe {
        let mut out: cl_command_queue = std::ptr::null_mut();
        let err_val = afcl_get_queue(&mut out as *mut cl_command_queue, retain);
        handle_error_general(AfError::from(err_val));
        out
    }
}

/// Get the handle to active ArrayFire OpenCL device
pub fn get_device_id() -> cl_device_id {
    unsafe {
        let mut out: cl_device_id = std::ptr::null_mut();
        let err_val = afcl_get_device_id(&mut out as *mut cl_device_id);
        handle_error_general(AfError::from(err_val));
        out
    }
}

/// Set the cl_device_id as the active ArrayFire OpenCL device
pub fn set_device_id(dev_id: cl_device_id) {
    unsafe {
        let err_val = afcl_set_device_id(dev_id);
        handle_error_general(AfError::from(err_val));
    }
}

/// Push user provided device, context and queue tuple to ArrayFire device mamanger
pub fn add_device_context(dev_id: cl_device_id, ctx: cl_context, queue: cl_command_queue) {
    unsafe {
        let err_val = afcl_add_device_context(dev_id, ctx, queue);
        handle_error_general(AfError::from(err_val));
    }
}

/// Set the device identified by device & context pair as the active device for ArrayFire
pub fn set_device_context(dev_id: cl_device_id, ctx: cl_context) {
    unsafe {
        let err_val = afcl_set_device_context(dev_id, ctx);
        handle_error_general(AfError::from(err_val));
    }
}

/// Remove the user provided device, context pair from ArrayFire device mamanger
pub fn delete_device_context(dev_id: cl_device_id, ctx: cl_context) {
    unsafe {
        let err_val = afcl_delete_device_context(dev_id, ctx);
        handle_error_general(AfError::from(err_val));
    }
}

///// Fetch Active ArrayFire device's type i.e. CPU/GPU/Accelerator etc.
pub fn get_device_type() -> DeviceType {
    unsafe {
        let mut out: i32 = 0;
        let err_val = afcl_get_device_type(&mut out as *mut c_int);
        handle_error_general(AfError::from(err_val));
        match out {
            -1 => mem::transmute(out as u64),
            _ => DeviceType::ALL,
        }
    }
}

/// Fetch Active ArrayFire device's vendor platform
pub fn get_platform() -> VendorPlatform {
    unsafe {
        let mut out: i32 = 0;
        let err_val = afcl_get_platform(&mut out as *mut c_int);
        handle_error_general(AfError::from(err_val));
        mem::transmute(out)
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem::size_of;

struct t {a: u8, b: i8}
struct u {a: u8, b: i8, c: u8}
struct v {a: u8, b: i8, c: v2, d: u32}
struct v2 {u: char, v: u8}
struct w {a: isize, b: ()}
struct x {a: isize, b: (), c: ()}
struct y {x: isize}

enum e1 {
    a(u8, u32), b(u32), c
}
enum e2 {
    a(u32), b
}

enum e3 {
    a([u16; 0], u8), b
}

pub fn main() {
    assert_eq!(size_of::<u8>(), 1 as usize);
    assert_eq!(size_of::<u32>(), 4 as usize);
    assert_eq!(size_of::<char>(), 4 as usize);
    assert_eq!(size_of::<i8>(), 1 as usize);
    assert_eq!(size_of::<i32>(), 4 as usize);
    assert_eq!(size_of::<t>(), 2 as usize);
    assert_eq!(size_of::<u>(), 3 as usize);
    // Alignment causes padding before the char and the u32.

    assert_eq!(size_of::<v>(),
                16 as usize);
    assert_eq!(size_of::<isize>(), size_of::<usize>());
    assert_eq!(size_of::<w>(), size_of::<isize>());
    assert_eq!(size_of::<x>(), size_of::<isize>());
    assert_eq!(size_of::<isize>(), size_of::<y>());

    // Make sure enum types are the appropriate size, mostly
    // around ensuring alignment is handled properly

    assert_eq!(size_of::<e1>(), 8 as usize);
    assert_eq!(size_of::<e2>(), 8 as usize);
    assert_eq!(size_of::<e3>(), 4 as usize);
}
<commit_msg>Fix type-sizes test<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::mem::size_of;

struct t {a: u8, b: i8}
struct u {a: u8, b: i8, c: u8}
struct v {a: u8, b: i8, c: v2, d: u32}
struct v2 {u: char, v: u8}
struct w {a: isize, b: ()}
struct x {a: isize, b: (), c: ()}
struct y {x: isize}

enum e1 {
    a(u8, u32), b(u32), c
}
enum e2 {
    a(u32), b
}

enum e3 {
    a([u16; 0], u8), b
}

pub fn main() {
    assert_eq!(size_of::<u8>(), 1 as usize);
    assert_eq!(size_of::<u32>(), 4 as usize);
    assert_eq!(size_of::<char>(), 4 as usize);
    assert_eq!(size_of::<i8>(), 1 as usize);
    assert_eq!(size_of::<i32>(), 4 as usize);
    assert_eq!(size_of::<t>(), 2 as usize);
    assert_eq!(size_of::<u>(), 3 as usize);
    // Alignment causes padding before the char and the u32.

    assert_eq!(size_of::<v>(),
                16 as usize);
    assert_eq!(size_of::<isize>(), size_of::<usize>());
    assert_eq!(size_of::<w>(), size_of::<isize>());
    assert_eq!(size_of::<x>(), size_of::<isize>());
    assert_eq!(size_of::<isize>(), size_of::<y>());

    // Make sure enum types are the appropriate size, mostly
    // around ensuring alignment is handled properly

    assert_eq!(size_of::<e1>(), 8 as usize);
    assert_eq!(size_of::<e2>(), 8 as usize);
    assert_eq!(size_of::<e3>(), 2 as usize);
}
<|endoftext|>


<commit_before>#![no_std]

pub trait BitfieldRegister {
    type Data;
    const REGISTER_SIZE: usize;
    fn data(&self) -> & Self::Data;
}

pub trait FromBitfield<Array> {
    fn from_bitfield(array:Array) -> Self;
}

pub trait IntoBitfield<Array> {
    fn into_bitfield(self) -> Array;
}

// u8
impl FromBitfield<[u8;1]> for u8 {
    fn from_bitfield(array: [u8;1]) -> Self {
        return array[0];
    }
}

impl IntoBitfield<[u8;1]> for u8 {
    fn into_bitfield(self) -> [u8;1]{
        return [self;1];
    }
}

// u16
impl FromBitfield<[u8;2]> for u16 {
    fn from_bitfield(array: [u8;2]) -> Self {
        return
            (array[0] as u16) |
            (array[1] as u16) << 8;
    }
}

impl IntoBitfield<[u8;2]> for u16 {
    fn into_bitfield(self) -> [u8;2]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
        ];
    }
}

// u32 :3
impl IntoBitfield<[u8;3]> for u32 {
    fn into_bitfield(self) -> [u8;3]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
            (self >> 16 & 0xFF) as u8,
        ];
    }
}

impl FromBitfield<[u8;3]> for u32 {
    fn from_bitfield(array: [u8;3]) -> Self {
        return
            (array[0] as u32)      |
            (array[1] as u32) << 8 |
            (array[2] as u32) << 16;
    }
}

// u32 :4
impl IntoBitfield<[u8;4]> for u32 {
    fn into_bitfield(self) -> [u8;4]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
            (self >> 16 & 0xFF) as u8,
            (self >> 24 & 0xFF) as u8
        ];
    }
}

impl FromBitfield<[u8;4]> for u32 {
    fn from_bitfield(array: [u8;4]) -> Self {
        return
            (array[0] as u32)       |
            (array[1] as u32) << 8  |
            (array[2] as u32) << 16 |
            (array[3] as u32) << 24;

    }
}

impl FromBitfield<[u8;1]> for bool {
    fn from_bitfield(array: [u8;1]) -> Self {
        return (array[0] & 1) != 0;
    }
}

impl IntoBitfield<[u8;1]> for bool {
    fn into_bitfield(self) -> [u8;1]{
        // If you cast a bool into an integer, true will be 1 and false will be 0.
        // https://doc.rust-lang.org/std/primitive.bool.html
        return [self as u8;1];
    }
}

mod tests {
    use super::{FromBitfield, IntoBitfield};

    macro_rules! test_into {
        ($value:expr, $expected_array:expr) => (
            assert_eq!(
                $value.into_bitfield(),
                $expected_array
            );
        )
    }

    macro_rules! test_from {
        ($value_type:ty, $array_len:expr, $array:expr, $expected_value:expr) => (
            assert_eq!(
                <$value_type as FromBitfield<[u8;$array_len]>>::from_bitfield($array),
                $expected_value
            );
        )
    }

    #[test]
    fn bool_test() {
        test_into!(
            false,
            [0;1]
        );
        test_into!(
            true,
            [1;1]
        );

        test_from!(
            bool, 1,
            [0;1], false
        );
        test_from!(
            bool, 1,
            [1;1], true
        );
        test_from!(
            bool, 1,
            [0b11111110;1], false
        );
        test_from!(
            bool, 1,
            [0b11111111;1], true
        );
    }

    #[test]
    fn u8_test() {
        test_into!(
            (0 as u8),
            [0;1]
        );
        test_into!(
            (1 as u8),
            [1;1]
        );
        test_into!(
            (0xFF as u8),
            [0xFF;1]
        );

        test_from!(
            u8, 1,
            [0;1], 0
        );
        test_from!(
            u8, 1,
            [1;1], 1
        );
        test_from!(
            u8, 1,
            [0xFF;1], 0xFF
        );
    }

    #[test]
    fn u16_test() {
        test_into!(
            (0 as u16),
            { static X: [u8;2] = [0x00u8, 0x00u8]; X }
        );
        test_into!(
            (1 as u16),
            { static X: [u8;2] = [0x01u8, 0x00u8]; X }
        );
        test_into!(
            (0xFF as u16),
            { static X: [u8;2] = [0xFFu8, 0x00u8]; X }
        );

        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x00u8, 0x00u8]; X }, 0
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x01u8, 0x00u8]; X }, 1
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0xFFu8, 0x00u8]; X }, 0xFF
        );
    }
}<commit_msg>all u16 tests<commit_after>#![no_std]

pub trait BitfieldRegister {
    type Data;
    const REGISTER_SIZE: usize;
    fn data(&self) -> & Self::Data;
}

pub trait FromBitfield<Array> {
    fn from_bitfield(array:Array) -> Self;
}

pub trait IntoBitfield<Array> {
    fn into_bitfield(self) -> Array;
}

// u8
impl FromBitfield<[u8;1]> for u8 {
    fn from_bitfield(array: [u8;1]) -> Self {
        return array[0];
    }
}

impl IntoBitfield<[u8;1]> for u8 {
    fn into_bitfield(self) -> [u8;1]{
        return [self;1];
    }
}

// u16
impl FromBitfield<[u8;2]> for u16 {
    fn from_bitfield(array: [u8;2]) -> Self {
        return
            (array[0] as u16) |
            (array[1] as u16) << 8;
    }
}

impl IntoBitfield<[u8;2]> for u16 {
    fn into_bitfield(self) -> [u8;2]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
        ];
    }
}

// u32 :3
impl IntoBitfield<[u8;3]> for u32 {
    fn into_bitfield(self) -> [u8;3]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
            (self >> 16 & 0xFF) as u8,
        ];
    }
}

impl FromBitfield<[u8;3]> for u32 {
    fn from_bitfield(array: [u8;3]) -> Self {
        return
            (array[0] as u32)      |
            (array[1] as u32) << 8 |
            (array[2] as u32) << 16;
    }
}

// u32 :4
impl IntoBitfield<[u8;4]> for u32 {
    fn into_bitfield(self) -> [u8;4]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
            (self >> 16 & 0xFF) as u8,
            (self >> 24 & 0xFF) as u8
        ];
    }
}

impl FromBitfield<[u8;4]> for u32 {
    fn from_bitfield(array: [u8;4]) -> Self {
        return
            (array[0] as u32)       |
            (array[1] as u32) << 8  |
            (array[2] as u32) << 16 |
            (array[3] as u32) << 24;

    }
}

impl FromBitfield<[u8;1]> for bool {
    fn from_bitfield(array: [u8;1]) -> Self {
        return (array[0] & 1) != 0;
    }
}

impl IntoBitfield<[u8;1]> for bool {
    fn into_bitfield(self) -> [u8;1]{
        // If you cast a bool into an integer, true will be 1 and false will be 0.
        // https://doc.rust-lang.org/std/primitive.bool.html
        return [self as u8;1];
    }
}

mod tests {
    use super::{FromBitfield, IntoBitfield};

    macro_rules! test_into {
        ($value:expr, $expected_array:expr) => (
            assert_eq!(
                $value.into_bitfield(),
                $expected_array
            );
        )
    }

    macro_rules! test_from {
        ($value_type:ty, $array_len:expr, $array:expr, $expected_value:expr) => (
            assert_eq!(
                <$value_type as FromBitfield<[u8;$array_len]>>::from_bitfield($array),
                $expected_value
            );
        )
    }

    #[test]
    fn bool_test() {
        test_into!(
            false,
            [0;1]
        );
        test_into!(
            true,
            [1;1]
        );

        test_from!(
            bool, 1,
            [0;1], false
        );
        test_from!(
            bool, 1,
            [1;1], true
        );
        test_from!(
            bool, 1,
            [0b11111110;1], false
        );
        test_from!(
            bool, 1,
            [0b11111111;1], true
        );
    }

    #[test]
    fn u8_test() {
        test_into!(
            (0 as u8),
            [0;1]
        );
        test_into!(
            (1 as u8),
            [1;1]
        );
        test_into!(
            (0xFF as u8),
            [0xFF;1]
        );

        test_from!(
            u8, 1,
            [0;1], 0
        );
        test_from!(
            u8, 1,
            [1;1], 1
        );
        test_from!(
            u8, 1,
            [0xFF;1], 0xFF
        );
    }

    #[test]
    fn u16_test() {
        test_into!(
            (0 as u16),
            { static X: [u8;2] = [0x00u8, 0x00u8]; X }
        );
        test_into!(
            (1 as u16),
            { static X: [u8;2] = [0x01u8, 0x00u8]; X }
        );
        test_into!(
            (0xFF as u16),
            { static X: [u8;2] = [0xFFu8, 0x00u8]; X }
        );
        test_into!(
            (0xFF00 as u16),
            { static X: [u8;2] = [0x00u8, 0xFFu8]; X }
        );
        test_into!(
            (0xFFFF as u16),
            { static X: [u8;2] = [0xFFu8, 0xFFu8]; X }
        );

        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x00u8, 0x00u8]; X }, 0
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x01u8, 0x00u8]; X }, 1
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0xFFu8, 0x00u8]; X }, 0xFF
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x00u8, 0xFFu8]; X }, 0xFF00
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0xFFu8, 0xFFu8]; X }, 0xFFFF
        );
    }
}<|endoftext|>


<commit_before>//! Like [`std::time::Instant`], but for memory.
//!
//! Measures the total size of all currently allocated objects.
use std::fmt;

use cfg_if::cfg_if;

#[derive(Copy, Clone)]
pub struct MemoryUsage {
    pub allocated: Bytes,
}

impl fmt::Display for MemoryUsage {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.allocated)
    }
}

impl std::ops::Sub for MemoryUsage {
    type Output = MemoryUsage;
    fn sub(self, rhs: MemoryUsage) -> MemoryUsage {
        MemoryUsage { allocated: self.allocated - rhs.allocated }
    }
}

impl MemoryUsage {
    pub fn now() -> MemoryUsage {
        cfg_if! {
            if #[cfg(all(feature = "jemalloc", not(target_env = "msvc")))] {
                jemalloc_ctl::epoch::advance().unwrap();
                MemoryUsage {
                    allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize),
                }
            } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
                // Note: This is incredibly slow.
                let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
                MemoryUsage { allocated: Bytes(alloc) }
            } else if #[cfg(windows)] {
                // There doesn't seem to be an API for determining heap usage, so we try to
                // approximate that by using the Commit Charge value.

                use winapi::um::processthreadsapi::*;
                use winapi::um::psapi::*;
                use std::mem::{MaybeUninit, size_of};

                let proc = unsafe { GetCurrentProcess() };
                let mut mem_counters = MaybeUninit::uninit();
                let cb = size_of::<PROCESS_MEMORY_COUNTERS>();
                let ret = unsafe { GetProcessMemoryInfo(proc, mem_counters.as_mut_ptr(), cb as u32) };
                assert!(ret != 0);

                let usage = unsafe { mem_counters.assume_init().PagefileUsage };
                MemoryUsage { allocated: Bytes(usage as isize) }
            } else {
                MemoryUsage { allocated: Bytes(0) }
            }
        }
    }
}

#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct Bytes(isize);

impl Bytes {
    pub fn megabytes(self) -> isize {
        self.0 / 1024 / 1024
    }
}

impl fmt::Display for Bytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let bytes = self.0;
        let mut value = bytes;
        let mut suffix = "b";
        if value.abs() > 4096 {
            value /= 1024;
            suffix = "kb";
            if value.abs() > 4096 {
                value /= 1024;
                suffix = "mb";
            }
        }
        f.pad(&format!("{}{}", value, suffix))
    }
}

impl std::ops::AddAssign<usize> for Bytes {
    fn add_assign(&mut self, x: usize) {
        self.0 += x as isize;
    }
}

impl std::ops::Sub for Bytes {
    type Output = Bytes;
    fn sub(self, rhs: Bytes) -> Bytes {
        Bytes(self.0 - rhs.0)
    }
}
<commit_msg>Add support for mallinfo2 on glibc Linux<commit_after>//! Like [`std::time::Instant`], but for memory.
//!
//! Measures the total size of all currently allocated objects.
use std::fmt;

use cfg_if::cfg_if;

#[derive(Copy, Clone)]
pub struct MemoryUsage {
    pub allocated: Bytes,
}

impl fmt::Display for MemoryUsage {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.allocated)
    }
}

impl std::ops::Sub for MemoryUsage {
    type Output = MemoryUsage;
    fn sub(self, rhs: MemoryUsage) -> MemoryUsage {
        MemoryUsage { allocated: self.allocated - rhs.allocated }
    }
}

impl MemoryUsage {
    pub fn now() -> MemoryUsage {
        cfg_if! {
            if #[cfg(all(feature = "jemalloc", not(target_env = "msvc")))] {
                jemalloc_ctl::epoch::advance().unwrap();
                MemoryUsage {
                    allocated: Bytes(jemalloc_ctl::stats::allocated::read().unwrap() as isize),
                }
            } else if #[cfg(all(target_os = "linux", target_env = "gnu"))] {
                memusage_linux()
            } else if #[cfg(windows)] {
                // There doesn't seem to be an API for determining heap usage, so we try to
                // approximate that by using the Commit Charge value.

                use winapi::um::processthreadsapi::*;
                use winapi::um::psapi::*;
                use std::mem::{MaybeUninit, size_of};

                let proc = unsafe { GetCurrentProcess() };
                let mut mem_counters = MaybeUninit::uninit();
                let cb = size_of::<PROCESS_MEMORY_COUNTERS>();
                let ret = unsafe { GetProcessMemoryInfo(proc, mem_counters.as_mut_ptr(), cb as u32) };
                assert!(ret != 0);

                let usage = unsafe { mem_counters.assume_init().PagefileUsage };
                MemoryUsage { allocated: Bytes(usage as isize) }
            } else {
                MemoryUsage { allocated: Bytes(0) }
            }
        }
    }
}

#[cfg(all(target_os = "linux", target_env = "gnu"))]
fn memusage_linux() -> MemoryUsage {
    // Linux/glibc has 2 APIs for allocator introspection that we can use: mallinfo and mallinfo2.
    // mallinfo uses `int` fields and cannot handle memory usage exceeding 2 GB.
    // mallinfo2 is very recent, so its presence needs to be detected at runtime.
    // Both are abysmally slow.

    use std::ffi::CStr;
    use std::sync::atomic::{AtomicUsize, Ordering};

    static MALLINFO2: AtomicUsize = AtomicUsize::new(1);

    let mut mallinfo2 = MALLINFO2.load(Ordering::Relaxed);
    if mallinfo2 == 1 {
        let cstr = CStr::from_bytes_with_nul(b"mallinfo2\0").unwrap();
        mallinfo2 = unsafe { libc::dlsym(libc::RTLD_DEFAULT, cstr.as_ptr()) } as usize;
        // NB: races don't matter here, since they'll always store the same value
        MALLINFO2.store(mallinfo2, Ordering::Relaxed);
    }

    if mallinfo2 == 0 {
        // mallinfo2 does not exist, use mallinfo.
        let alloc = unsafe { libc::mallinfo() }.uordblks as isize;
        MemoryUsage { allocated: Bytes(alloc) }
    } else {
        let mallinfo2: fn() -> libc::mallinfo2 = unsafe { std::mem::transmute(mallinfo2) };
        let alloc = mallinfo2().uordblks as isize;
        MemoryUsage { allocated: Bytes(alloc) }
    }
}

#[derive(Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct Bytes(isize);

impl Bytes {
    pub fn megabytes(self) -> isize {
        self.0 / 1024 / 1024
    }
}

impl fmt::Display for Bytes {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let bytes = self.0;
        let mut value = bytes;
        let mut suffix = "b";
        if value.abs() > 4096 {
            value /= 1024;
            suffix = "kb";
            if value.abs() > 4096 {
                value /= 1024;
                suffix = "mb";
            }
        }
        f.pad(&format!("{}{}", value, suffix))
    }
}

impl std::ops::AddAssign<usize> for Bytes {
    fn add_assign(&mut self, x: usize) {
        self.0 += x as isize;
    }
}

impl std::ops::Sub for Bytes {
    type Output = Bytes;
    fn sub(self, rhs: Bytes) -> Bytes {
        Bytes(self.0 - rhs.0)
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

// SVG 1.1 (Second Edition)
// https://www.w3.org/TR/SVG/
<% data.new_style_struct("InheritedSVG", inherited=True, gecko_name="SVG") %>

// Section 10 - Text

${helpers.single_keyword(
    "dominant-baseline",
    """auto ideographic alphabetic hanging mathematical central middle
       text-after-edge text-before-edge""",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/css-inline-3/#propdef-dominant-baseline",
)}

${helpers.single_keyword(
    "text-anchor",
    "start middle end",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty",
    gecko_enum_prefix="StyleTextAnchor",
)}

// Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword(
    "color-interpolation",
    "srgb auto linearrgb",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty",
)}

${helpers.single_keyword(
    "color-interpolation-filters",
    "linearrgb auto srgb",
    engines="gecko",
    gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty",
)}

${helpers.predefined_type(
    "fill",
    "SVGPaint",
    "crate::values::computed::SVGPaint::black()",
    engines="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint",
)}

${helpers.predefined_type(
    "fill-opacity",
    "SVGOpacity",
    "Default::default()",
    engines="gecko",
    animation_value_type="ComputedValue",
    spec="https://svgwg.org/svg2-draft/painting.html#FillOpacity",
)}

${helpers.predefined_type(
    "fill-rule",
    "FillRule",
    "Default::default()",
    engines="gecko",
    needs_context=False,
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty",
)}

${helpers.single_keyword(
    "shape-rendering",
    "auto optimizespeed crispedges geometricprecision",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty",
    gecko_enum_prefix = "StyleShapeRendering",
)}

${helpers.predefined_type(
    "stroke",
    "SVGPaint",
    "Default::default()",
    engines="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint",
)}

${helpers.predefined_type(
    "stroke-width",
    "SVGWidth",
    "computed::SVGWidth::one()",
    engines="gecko",
    animation_value_type="crate::values::computed::SVGWidth",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth",
)}

${helpers.single_keyword(
    "stroke-linecap",
    "butt round square",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty",
    gecko_enum_prefix = "StyleStrokeLinecap",
)}

${helpers.single_keyword(
    "stroke-linejoin",
    "miter round bevel",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty",
    gecko_enum_prefix = "StyleStrokeLinejoin",
)}

${helpers.predefined_type(
    "stroke-miterlimit",
    "NonNegativeNumber",
    "From::from(4.0)",
    engines="gecko",
    animation_value_type="crate::values::computed::NonNegativeNumber",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeMiterlimitProperty",
)}

${helpers.predefined_type(
    "stroke-opacity",
    "SVGOpacity",
    "Default::default()",
    engines="gecko",
    animation_value_type="ComputedValue",
    spec="https://svgwg.org/svg2-draft/painting.html#StrokeOpacity",
)}

${helpers.predefined_type(
    "stroke-dasharray",
    "SVGStrokeDashArray",
    "Default::default()",
    engines="gecko",
    animation_value_type="crate::values::computed::SVGStrokeDashArray",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
)}

${helpers.predefined_type(
    "stroke-dashoffset",
    "SVGLength",
    "computed::SVGLength::zero()",
    engines="gecko",
    animation_value_type="ComputedValue",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
)}

// Section 14 - Clipping, Masking and Compositing
${helpers.predefined_type(
    "clip-rule",
    "FillRule",
    "Default::default()",
    engines="gecko",
    needs_context=False,
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty",
)}

${helpers.predefined_type(
    "marker-start",
    "url::UrlOrNone",
    "computed::url::UrlOrNone::none()",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
)}

${helpers.predefined_type(
    "marker-mid",
    "url::UrlOrNone",
    "computed::url::UrlOrNone::none()",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
)}

${helpers.predefined_type(
    "marker-end",
    "url::UrlOrNone",
    "computed::url::UrlOrNone::none()",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
)}

${helpers.predefined_type(
    "paint-order",
    "SVGPaintOrder",
    "computed::SVGPaintOrder::normal()",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder",
)}

${helpers.predefined_type(
    "-moz-context-properties",
    "MozContextProperties",
    "computed::MozContextProperties::default()",
    engines="gecko",
    animation_value_type="none",
    spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)",
)}
<commit_msg>style: Convert dominant-baseline #defines to an enum class.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

<%namespace name="helpers" file="/helpers.mako.rs" />

// SVG 1.1 (Second Edition)
// https://www.w3.org/TR/SVG/
<% data.new_style_struct("InheritedSVG", inherited=True, gecko_name="SVG") %>

// Section 10 - Text

${helpers.single_keyword(
    "dominant-baseline",
    """auto ideographic alphabetic hanging mathematical central middle
       text-after-edge text-before-edge""",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/css-inline-3/#propdef-dominant-baseline",
    gecko_enum_prefix="StyleDominantBaseline",
)}

${helpers.single_keyword(
    "text-anchor",
    "start middle end",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG/text.html#TextAnchorProperty",
    gecko_enum_prefix="StyleTextAnchor",
)}

// Section 11 - Painting: Filling, Stroking and Marker Symbols
${helpers.single_keyword(
    "color-interpolation",
    "srgb auto linearrgb",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty",
)}

${helpers.single_keyword(
    "color-interpolation-filters",
    "linearrgb auto srgb",
    engines="gecko",
    gecko_constant_prefix="NS_STYLE_COLOR_INTERPOLATION",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationFiltersProperty",
)}

${helpers.predefined_type(
    "fill",
    "SVGPaint",
    "crate::values::computed::SVGPaint::black()",
    engines="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingFillPaint",
)}

${helpers.predefined_type(
    "fill-opacity",
    "SVGOpacity",
    "Default::default()",
    engines="gecko",
    animation_value_type="ComputedValue",
    spec="https://svgwg.org/svg2-draft/painting.html#FillOpacity",
)}

${helpers.predefined_type(
    "fill-rule",
    "FillRule",
    "Default::default()",
    engines="gecko",
    needs_context=False,
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#FillRuleProperty",
)}

${helpers.single_keyword(
    "shape-rendering",
    "auto optimizespeed crispedges geometricprecision",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#ShapeRenderingProperty",
    gecko_enum_prefix = "StyleShapeRendering",
)}

${helpers.predefined_type(
    "stroke",
    "SVGPaint",
    "Default::default()",
    engines="gecko",
    animation_value_type="IntermediateSVGPaint",
    boxed=True,
    spec="https://www.w3.org/TR/SVG2/painting.html#SpecifyingStrokePaint",
)}

${helpers.predefined_type(
    "stroke-width",
    "SVGWidth",
    "computed::SVGWidth::one()",
    engines="gecko",
    animation_value_type="crate::values::computed::SVGWidth",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeWidth",
)}

${helpers.single_keyword(
    "stroke-linecap",
    "butt round square",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinecapProperty",
    gecko_enum_prefix = "StyleStrokeLinecap",
)}

${helpers.single_keyword(
    "stroke-linejoin",
    "miter round bevel",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/painting.html#StrokeLinejoinProperty",
    gecko_enum_prefix = "StyleStrokeLinejoin",
)}

${helpers.predefined_type(
    "stroke-miterlimit",
    "NonNegativeNumber",
    "From::from(4.0)",
    engines="gecko",
    animation_value_type="crate::values::computed::NonNegativeNumber",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeMiterlimitProperty",
)}

${helpers.predefined_type(
    "stroke-opacity",
    "SVGOpacity",
    "Default::default()",
    engines="gecko",
    animation_value_type="ComputedValue",
    spec="https://svgwg.org/svg2-draft/painting.html#StrokeOpacity",
)}

${helpers.predefined_type(
    "stroke-dasharray",
    "SVGStrokeDashArray",
    "Default::default()",
    engines="gecko",
    animation_value_type="crate::values::computed::SVGStrokeDashArray",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
)}

${helpers.predefined_type(
    "stroke-dashoffset",
    "SVGLength",
    "computed::SVGLength::zero()",
    engines="gecko",
    animation_value_type="ComputedValue",
    spec="https://www.w3.org/TR/SVG2/painting.html#StrokeDashing",
)}

// Section 14 - Clipping, Masking and Compositing
${helpers.predefined_type(
    "clip-rule",
    "FillRule",
    "Default::default()",
    engines="gecko",
    needs_context=False,
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG11/masking.html#ClipRuleProperty",
)}

${helpers.predefined_type(
    "marker-start",
    "url::UrlOrNone",
    "computed::url::UrlOrNone::none()",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
)}

${helpers.predefined_type(
    "marker-mid",
    "url::UrlOrNone",
    "computed::url::UrlOrNone::none()",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
)}

${helpers.predefined_type(
    "marker-end",
    "url::UrlOrNone",
    "computed::url::UrlOrNone::none()",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties",
)}

${helpers.predefined_type(
    "paint-order",
    "SVGPaintOrder",
    "computed::SVGPaintOrder::normal()",
    engines="gecko",
    animation_value_type="discrete",
    spec="https://www.w3.org/TR/SVG2/painting.html#PaintOrder",
)}

${helpers.predefined_type(
    "-moz-context-properties",
    "MozContextProperties",
    "computed::MozContextProperties::default()",
    engines="gecko",
    animation_value_type="none",
    spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)",
)}
<|endoftext|>


<commit_before>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// ----- string -----

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// ----- nstring ----- nil or string

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// ----- text -----

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<commit_msg>added "others" comment<commit_after>use nom::{
    self,
    bytes::streaming::{tag, take},
    character::streaming::digit1,
    sequence::tuple,
    IResult,
};

use std::str;

// ----- number -----

// number          = 1*DIGIT
//                    ; Unsigned 32-bit integer
//                    ; (0 <= n < 4,294,967,296)
named!(pub number<u32>, flat_map!(digit1, parse_to!(u32)));

// same as `number` but 64-bit
named!(pub number_64<u64>, flat_map!(digit1, parse_to!(u64)));

// ----- string -----

// string = quoted / literal
named!(pub string<&[u8]>, alt!(quoted | literal));

// string bytes as as utf8
named!(pub string_utf8<&str>, map_res!(string, str::from_utf8));

// quoted = DQUOTE *QUOTED-CHAR DQUOTE
named!(pub quoted<&[u8]>, delimited!(
    char!('"'),
    quoted_data,
    char!('"')
));

// quoted bytes as as utf8
named!(pub quoted_utf8<&str>, map_res!(quoted, str::from_utf8));

// QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
pub fn quoted_data(i: &[u8]) -> IResult<&[u8], &[u8]> {
    // Ideally this should use nom's `escaped` macro, but it suffers from broken
    // type inference unless compiled with the verbose-errors feature enabled.
    let mut escape = false;
    let mut len = 0;
    for c in i {
        if *c == b'"' && !escape {
            break;
        }
        len += 1;
        if *c == b'\\' && !escape {
            escape = true
        } else if escape {
            escape = false;
        }
    }
    Ok((&i[len..], &i[..len]))
}

// quoted-specials = DQUOTE / "\"
pub fn is_quoted_specials(c: u8) -> bool {
    c == b'"' || c == b'\\'
}

/// literal = "{" number "}" CRLF *CHAR8
///            ; Number represents the number of CHAR8s
pub fn literal(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let parser = tuple((tag(b"{"), number, tag(b"}"), tag("\r\n")));

    let (remaining, (_, count, _, _)) = parser(input)?;

    let (remaining, data) = take(count)(remaining)?;

    if !data.iter().all(|byte| is_char8(*byte)) {
        // FIXME: what ErrorKind should this have?
        return Err(nom::Err::Error((remaining, nom::error::ErrorKind::Verify)));
    }

    Ok((remaining, data))
}

/// CHAR8 = %x01-ff ; any OCTET except NUL, %x00
pub fn is_char8(i: u8) -> bool {
    i != 0
}

// ----- astring ----- atom (roughly) or string

// astring = 1*ASTRING-CHAR / string
named!(pub astring<&[u8]>, alt!(
    take_while1!(is_astring_char) |
    string
));

// astring bytes as as utf8
named!(pub astring_utf8<&str>, map_res!(astring, str::from_utf8));

// ASTRING-CHAR = ATOM-CHAR / resp-specials
pub fn is_astring_char(c: u8) -> bool {
    is_atom_char(c) || is_resp_specials(c)
}

// ATOM-CHAR = <any CHAR except atom-specials>
pub fn is_atom_char(c: u8) -> bool {
    is_char(c) && !is_atom_specials(c)
}

// atom-specials = "(" / ")" / "{" / SP / CTL / list-wildcards / quoted-specials / resp-specials
pub fn is_atom_specials(c: u8) -> bool {
    c == b'('
        || c == b')'
        || c == b'{'
        || c == b' '
        || c < 32
        || is_list_wildcards(c)
        || is_quoted_specials(c)
        || is_resp_specials(c)
}

// resp-specials = "]"
pub fn is_resp_specials(c: u8) -> bool {
    c == b']'
}

// atom = 1*ATOM-CHAR
named!(pub atom<&str>, map_res!(take_while1!(is_atom_char),
    str::from_utf8
));

// ----- nstring ----- nil or string

// nstring = string / nil
named!(pub nstring<Option<&[u8]>>, alt!(
    map!(nil, |_| None) |
    map!(string, |s| Some(s))
));

// nstring bytes as utf8
named!(pub nstring_utf8<Option<&str>>, alt!(
    map!(nil, |_| None) |
    map!(string_utf8, |s| Some(s))
));

// nil = "NIL"
named!(pub nil, tag_no_case!("NIL"));

// ----- text -----

// text = 1*TEXT-CHAR
named!(pub text<&str>, map_res!(take_while!(is_text_char),
    str::from_utf8
));

// TEXT-CHAR = <any CHAR except CR and LF>
pub fn is_text_char(c: u8) -> bool {
    is_char(c) && c != b'\r' && c != b'\n'
}

// CHAR = %x01-7F
//          ; any 7-bit US-ASCII character,
//          ;  excluding NUL
// From RFC5234
pub fn is_char(c: u8) -> bool {
    match c {
        0x01..=0x7F => true,
        _ => false,
    }
}

// ----- others -----

// list-wildcards = "%" / "*"
pub fn is_list_wildcards(c: u8) -> bool {
    c == b'%' || c == b'*'
}

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

    #[test]
    fn test_string_literal() {
        match string(b"{3}\r\nXYZ") {
            Ok((_, value)) => {
                assert_eq!(value, b"XYZ");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }

    #[test]
    fn test_astring() {
        match astring(b"text ") {
            Ok((_, value)) => {
                assert_eq!(value, b"text");
            }
            rsp => panic!("unexpected response {:?}", rsp),
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#[repr(packed)]
struct S {
    a: i32,
    b: i64,
}

#[repr(packed)]
struct Test1<'a> {
    x: u8,
    other: &'a u32,
}

#[repr(packed)]
struct Test2<'a> {
    x: u8,
    other: &'a Test1<'a>,
}

fn test(t: Test2) {
    let x = *t.other.other;
    assert_eq!(x, 42);
}

fn main() {
    let mut x = S {
        a: 42,
        b: 99,
    };
    let a = x.a;
    let b = x.b;
    assert_eq!(a, 42);
    assert_eq!(b, 99);
    // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference
    assert_eq!({x.a}, 42);
    assert_eq!({x.b}, 99);

    x.b = 77;
    assert_eq!({x.b}, 77);

    test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }});
}
<commit_msg>packed structs: test unsize coercions<commit_after>#![allow(dead_code)]
#![feature(unsize, coerce_unsized)]

#[repr(packed)]
struct S {
    a: i32,
    b: i64,
}

#[repr(packed)]
struct Test1<'a> {
    x: u8,
    other: &'a u32,
}

#[repr(packed)]
struct Test2<'a> {
    x: u8,
    other: &'a Test1<'a>,
}

fn test(t: Test2) {
    let x = *t.other.other;
    assert_eq!(x, 42);
}

fn test_unsizing() {
    #[repr(packed)]
    struct UnalignedPtr<'a, T: ?Sized>
    where T: 'a,
    {
        data: &'a T,
    }

    impl<'a, T, U> std::ops::CoerceUnsized<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T>
    where
        T: std::marker::Unsize<U> + ?Sized,
        U: ?Sized,
    { }

    let arr = [1, 2, 3];
    let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr };
    let _uns: UnalignedPtr<[i32]> = arr_unaligned;
}

fn main() {
    let mut x = S {
        a: 42,
        b: 99,
    };
    let a = x.a;
    let b = x.b;
    assert_eq!(a, 42);
    assert_eq!(b, 99);
    // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference
    assert_eq!({x.a}, 42);
    assert_eq!({x.b}, 99);

    x.b = 77;
    assert_eq!({x.b}, 77);

    test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }});

    test_unsizing();
}
<|endoftext|>


<commit_before>#![feature(phase)]
#![crate_type="staticlib"]
#![no_std]

extern crate core;
extern crate zinc;

use core::option::Some;
use zinc::hal::k20::pin;
use zinc::hal::pin::GPIO;
use zinc::hal::cortex_m4::systick;

/// Wait the given number of SysTick ticks
pub fn wait(ticks: u32) {
  let mut n = ticks;
  let mut t = systick::get_current();
  loop {
    if systick::get_current() > t {
      t = systick::get_current();
      n -= 1;
      if n == 0 {
        break;
      }
    }
  }
}

#[no_mangle]
#[no_split_stack]
#[allow(unused_variable)]
#[allow(dead_code)]
pub unsafe fn main() {
  zinc::hal::mem_init::init_stack();
  zinc::hal::mem_init::init_data();

  // Pins for MC HCK (http://www.mchck.org/)
  let led1 = pin::Pin::new(pin::PortB, 16, pin::GPIO, Some(zinc::hal::pin::Out));

  systick::setup(480000, false);
  systick::enable();
  loop {
    led1.set_high();
    wait(10);
    led1.set_low();
    wait(10);
  }
}
<commit_msg>Modify the K20 example to check the systick flag<commit_after>#![feature(phase)]
#![crate_type="staticlib"]
#![no_std]

extern crate core;
extern crate zinc;

use core::option::Some;
use zinc::hal::k20::pin;
use zinc::hal::pin::GPIO;
use zinc::hal::cortex_m4::systick;

/// Wait the given number of SysTick ticks
pub fn wait(ticks: u32) {
  let mut n = ticks;
  // Reset the tick flag
  systick::tick();
  loop {
    if systick::tick() {
      n -= 1;
      if n == 0 {
        break;
      }
    }
  }
}

#[no_mangle]
#[no_split_stack]
#[allow(unused_variable)]
#[allow(dead_code)]
pub unsafe fn main() {
  zinc::hal::mem_init::init_stack();
  zinc::hal::mem_init::init_data();

  // Pins for MC HCK (http://www.mchck.org/)
  let led1 = pin::Pin::new(pin::PortB, 16, pin::GPIO, Some(zinc::hal::pin::Out));

  systick::setup(480000, false);
  systick::enable();
  loop {
    led1.set_high();
    wait(10);
    led1.set_low();
    wait(10);
  }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{
    actor::{self, SharedState},
    Park, Poll, Result, State, StateChangeImpl, StateMachine,
};
use slog_scope::debug;

#[derive(Debug, PartialEq)]
pub(super) struct EntryPoint {}

/// Implements the state change for `State<EntryPoint>`. It has two
/// possibilities:
///
/// If polling is disabled it stays in `State<EntryPoint>`, otherwise, it moves
/// to `State<Poll>` state.
#[async_trait::async_trait(?Send)]
impl StateChangeImpl for State<EntryPoint> {
    fn name(&self) -> &'static str {
        "entry_point"
    }

    fn can_run_trigger_probe(&self) -> bool {
        true
    }

    fn can_run_local_install(&self) -> bool {
        true
    }

    fn can_run_remote_install(&self) -> bool {
        true
    }

    async fn handle(
        self,
        shared_state: &mut SharedState,
    ) -> Result<(StateMachine, actor::StepTransition)> {
        // Cleanup temporary settings from last installation
        shared_state.runtime_settings.reset_transient_settings();

        if !shared_state.settings.polling.enabled {
            debug!("Polling is disabled, parking the state machine.");
            return Ok((StateMachine::Park(self.into()), actor::StepTransition::Immediate));
        }

        debug!("Polling is enabled, moving to Poll state.");
        Ok((StateMachine::Poll(self.into()), actor::StepTransition::Immediate))
    }
}

create_state_step!(EntryPoint => Park);
create_state_step!(EntryPoint => Poll);

#[actix_rt::test]
async fn polling_disable() {
    use super::*;
    use crate::firmware::tests::{create_fake_metadata, FakeDevice};

    let mut settings = Settings::default();
    settings.polling.enabled = false;
    let runtime_settings = RuntimeSettings::default();
    let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap();
    let mut shared_state = SharedState { settings, runtime_settings, firmware };

    let machine = StateMachine::EntryPoint(State(EntryPoint {}))
        .move_to_next_state(&mut shared_state)
        .await
        .unwrap()
        .0;

    assert_state!(machine, Park);
}

#[actix_rt::test]
async fn polling_enabled() {
    use super::*;
    use crate::firmware::tests::{create_fake_metadata, FakeDevice};

    let mut settings = Settings::default();
    settings.polling.enabled = true;
    let runtime_settings = RuntimeSettings::default();
    let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap();
    let mut shared_state = SharedState { settings, runtime_settings, firmware };

    let machine = StateMachine::EntryPoint(State(EntryPoint {}))
        .move_to_next_state(&mut shared_state)
        .await
        .unwrap()
        .0;

    assert_state!(machine, Poll);
}
<commit_msg>updatehub: Move tests on entry_point to a tests module<commit_after>// Copyright (C) 2018 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

use super::{
    actor::{self, SharedState},
    Park, Poll, Result, State, StateChangeImpl, StateMachine,
};
use slog_scope::debug;

#[derive(Debug, PartialEq)]
pub(super) struct EntryPoint {}

/// Implements the state change for `State<EntryPoint>`. It has two
/// possibilities:
///
/// If polling is disabled it stays in `State<EntryPoint>`, otherwise, it moves
/// to `State<Poll>` state.
#[async_trait::async_trait(?Send)]
impl StateChangeImpl for State<EntryPoint> {
    fn name(&self) -> &'static str {
        "entry_point"
    }

    fn can_run_trigger_probe(&self) -> bool {
        true
    }

    fn can_run_local_install(&self) -> bool {
        true
    }

    fn can_run_remote_install(&self) -> bool {
        true
    }

    async fn handle(
        self,
        shared_state: &mut SharedState,
    ) -> Result<(StateMachine, actor::StepTransition)> {
        // Cleanup temporary settings from last installation
        shared_state.runtime_settings.reset_transient_settings();

        if !shared_state.settings.polling.enabled {
            debug!("Polling is disabled, parking the state machine.");
            return Ok((StateMachine::Park(self.into()), actor::StepTransition::Immediate));
        }

        debug!("Polling is enabled, moving to Poll state.");
        Ok((StateMachine::Poll(self.into()), actor::StepTransition::Immediate))
    }
}

create_state_step!(EntryPoint => Park);
create_state_step!(EntryPoint => Poll);

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        firmware::{
            tests::{create_fake_metadata, FakeDevice},
            Metadata,
        },
        runtime_settings::RuntimeSettings,
        settings::Settings,
    };

    #[actix_rt::test]
    async fn polling_disable() {
        let mut settings = Settings::default();
        settings.polling.enabled = false;
        let runtime_settings = RuntimeSettings::default();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::EntryPoint(State(EntryPoint {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        assert_state!(machine, Park);
    }

    #[actix_rt::test]
    async fn polling_enabled() {
        let mut settings = Settings::default();
        settings.polling.enabled = true;
        let runtime_settings = RuntimeSettings::default();
        let firmware = Metadata::from_path(&create_fake_metadata(FakeDevice::NoUpdate)).unwrap();
        let mut shared_state = SharedState { settings, runtime_settings, firmware };

        let machine = StateMachine::EntryPoint(State(EntryPoint {}))
            .move_to_next_state(&mut shared_state)
            .await
            .unwrap()
            .0;

        assert_state!(machine, Poll);
    }
}
<|endoftext|>