<commit_before>//! Implementation of a Lighthouse's peer management system.

pub use self::peerdb::*;
use crate::metrics;
use crate::rpc::MetaData;
use crate::{NetworkGlobals, PeerId};
use futures::prelude::*;
use futures::Stream;
use hashmap_delay::HashSetDelay;
use libp2p::identify::IdentifyInfo;
use slog::{crit, debug, error, warn};
use smallvec::SmallVec;
use std::sync::Arc;
use std::time::{Duration, Instant};
use types::EthSpec;

mod client;
mod peer_info;
mod peer_sync_status;
mod peerdb;

pub use peer_info::PeerInfo;
pub use peer_sync_status::{PeerSyncStatus, SyncInfo};
/// The minimum reputation before a peer is disconnected.
// Most likely this needs tweaking
const _MINIMUM_REPUTATION_BEFORE_BAN: Rep = 20;
/// The time in seconds between re-status's peers.
const STATUS_INTERVAL: u64 = 300;
/// The time in seconds between PING events. We do not send a ping if the other peer as PING'd us within
/// this time frame (Seconds)
const PING_INTERVAL: u64 = 30;

/// The main struct that handles peer's reputation and connection status.
pub struct PeerManager<TSpec: EthSpec> {
    /// Storage of network globals to access the PeerDB.
    network_globals: Arc<NetworkGlobals<TSpec>>,
    /// A queue of events that the `PeerManager` is waiting to produce.
    events: SmallVec<[PeerManagerEvent; 5]>,
    /// A collection of peers awaiting to be Ping'd.
    ping_peers: HashSetDelay<PeerId>,
    /// A collection of peers awaiting to be Status'd.
    status_peers: HashSetDelay<PeerId>,
    /// Last updated moment.
    last_updated: Instant,
    /// The logger associated with the `PeerManager`.
    log: slog::Logger,
}

/// A collection of actions a peer can perform which will adjust its reputation
/// Each variant has an associated reputation change.
pub enum PeerAction {
    /// The peer timed out on an RPC request/response.
    _TimedOut = -10,
    /// The peer sent and invalid request/response or encoding.
    _InvalidMessage = -20,
    /// The peer sent  something objectively malicious.
    _Malicious = -50,
    /// Received an expected message.
    _ValidMessage = 20,
    /// Peer disconnected.
    Disconnected = -30,
}

/// The events that the PeerManager outputs (requests).
pub enum PeerManagerEvent {
    /// Sends a STATUS to a peer.
    Status(PeerId),
    /// Sends a PING to a peer.
    Ping(PeerId),
    /// Request METADATA from a peer.
    MetaData(PeerId),
    /// The peer should be disconnected.
    _DisconnectPeer(PeerId),
    /// The peer should be disconnected and banned.
    _BanPeer(PeerId),
}

impl<TSpec: EthSpec> PeerManager<TSpec> {
    pub fn new(network_globals: Arc<NetworkGlobals<TSpec>>, log: &slog::Logger) -> Self {
        PeerManager {
            network_globals,
            events: SmallVec::new(),
            last_updated: Instant::now(),
            ping_peers: HashSetDelay::new(Duration::from_secs(PING_INTERVAL)),
            status_peers: HashSetDelay::new(Duration::from_secs(STATUS_INTERVAL)),
            log: log.clone(),
        }
    }

    /* Public accessible functions */

    /// A ping request has been received.
    // NOTE: The behaviour responds with a PONG automatically
    // TODO: Update last seen
    pub fn ping_request(&mut self, peer_id: &PeerId, seq: u64) {
        if let Some(peer_info) = self.network_globals.peers.read().peer_info(peer_id) {
            // received a ping
            // reset the to-ping timer for this peer
            debug!(self.log, "Received a ping request"; "peer_id" => format!("{}", peer_id), "seq_no" => seq);
            self.ping_peers.insert(peer_id.clone());

            // if the sequence number is unknown send update the meta data of the peer.
            if let Some(meta_data) = &peer_info.meta_data {
                if meta_data.seq_number < seq {
                    debug!(self.log, "Requesting new metadata from peer"; "peer_id" => format!("{}", peer_id), "known_seq_no" => meta_data.seq_number, "ping_seq_no" => seq);
                    self.events
                        .push(PeerManagerEvent::MetaData(peer_id.clone()));
                }
            } else {
                // if we don't know the meta-data, request it
                debug!(self.log, "Requesting first metadata from peer"; "peer_id" => format!("{}", peer_id));
                self.events
                    .push(PeerManagerEvent::MetaData(peer_id.clone()));
            }
        } else {
            crit!(self.log, "Received a PING from an unknown peer"; "peer_id" => format!("{}", peer_id));
        }
    }

    /// A PONG has been returned from a peer.
    // TODO: Update last seen
    pub fn pong_response(&mut self, peer_id: &PeerId, seq: u64) {
        if let Some(peer_info) = self.network_globals.peers.read().peer_info(peer_id) {
            // received a pong

            // if the sequence number is unknown send update the meta data of the peer.
            if let Some(meta_data) = &peer_info.meta_data {
                if meta_data.seq_number < seq {
                    debug!(self.log, "Requesting new metadata from peer"; "peer_id" => format!("{}", peer_id), "known_seq_no" => meta_data.seq_number, "pong_seq_no" => seq);
                    self.events
                        .push(PeerManagerEvent::MetaData(peer_id.clone()));
                }
            } else {
                // if we don't know the meta-data, request it
                debug!(self.log, "Requesting first metadata from peer"; "peer_id" => format!("{}", peer_id));
                self.events
                    .push(PeerManagerEvent::MetaData(peer_id.clone()));
            }
        } else {
            crit!(self.log, "Received a PONG from an unknown peer"; "peer_id" => format!("{}", peer_id));
        }
    }

    /// Received a metadata response from a peer.
    // TODO: Update last seen
    pub fn meta_data_response(&mut self, peer_id: &PeerId, meta_data: MetaData<TSpec>) {
        if let Some(peer_info) = self.network_globals.peers.write().peer_info_mut(peer_id) {
            if let Some(known_meta_data) = &peer_info.meta_data {
                if known_meta_data.seq_number < meta_data.seq_number {
                    debug!(self.log, "Updating peer's metadata"; "peer_id" => format!("{}", peer_id), "known_seq_no" => known_meta_data.seq_number, "new_seq_no" => meta_data.seq_number);
                    peer_info.meta_data = Some(meta_data);
                } else {
                    warn!(self.log, "Received old metadata"; "peer_id" => format!("{}", peer_id), "known_seq_no" => known_meta_data.seq_number, "new_seq_no" => meta_data.seq_number);
                }
            } else {
                // we have no meta-data for this peer, update
                debug!(self.log, "Obtained peer's metadata"; "peer_id" => format!("{}", peer_id), "new_seq_no" => meta_data.seq_number);
                peer_info.meta_data = Some(meta_data);
            }
        } else {
            crit!(self.log, "Received METADATA from an unknown peer"; "peer_id" => format!("{}", peer_id));
        }
    }

    /// A STATUS message has been received from a peer. This resets the status timer.
    pub fn peer_statusd(&mut self, peer_id: &PeerId) {
        self.status_peers.insert(peer_id.clone());
    }

    /// Checks the reputation of a peer and if it is too low, bans it and
    /// sends the corresponding event. Informs if it got banned
    fn _gets_banned(&mut self, peer_id: &PeerId) -> bool {
        // if the peer was already banned don't inform again
        let mut peerdb = self.network_globals.peers.write();

        if let Some(connection_status) = peerdb.connection_status(peer_id) {
            if peerdb.reputation(peer_id) < _MINIMUM_REPUTATION_BEFORE_BAN
                && !connection_status.is_banned()
            {
                peerdb.ban(peer_id);
                self.events
                    .push(PeerManagerEvent::_BanPeer(peer_id.clone()));
                return true;
            }
        }
        false
    }

    /// Requests that a peer get disconnected.
    pub fn _disconnect_peer(&mut self, peer_id: &PeerId) {
        self.events
            .push(PeerManagerEvent::_DisconnectPeer(peer_id.clone()));
    }

    /// Updates the state of the peer as disconnected.
    pub fn notify_disconnect(&mut self, peer_id: &PeerId) {
        self.update_reputations();
        {
            let mut peerdb = self.network_globals.peers.write();
            peerdb.disconnect(peer_id);
            peerdb.add_reputation(peer_id, PeerAction::Disconnected as Rep);
        }

        // remove the ping and status timer for the peer
        self.ping_peers.remove(peer_id);
        self.status_peers.remove(peer_id);
        metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT);
        metrics::set_gauge(
            &metrics::PEERS_CONNECTED,
            self.network_globals.connected_peers() as i64,
        );
    }

    /// Sets a peer as connected as long as their reputation allows it
    /// Informs if the peer was accepted
    pub fn connect_ingoing(&mut self, peer_id: &PeerId) -> bool {
        self.connect_peer(peer_id, false)
    }

    /// Sets a peer as connected as long as their reputation allows it
    /// Informs if the peer was accepted
    pub fn connect_outgoing(&mut self, peer_id: &PeerId) -> bool {
        self.connect_peer(peer_id, true)
    }

    /// Provides a given peer's reputation if it exists.
    pub fn _get_peer_rep(&self, peer_id: &PeerId) -> Rep {
        self.network_globals.peers.read().reputation(peer_id)
    }

    /// Updates the reputation of known peers according to their connection
    /// status and the time that has passed.
    pub fn update_reputations(&mut self) {
        let now = Instant::now();
        let elapsed = (now - self.last_updated).as_secs();
        // 0 seconds means now - last_updated < 0, but (most likely) not = 0.
        // In this case, do nothing (updating last_updated would propagate
        // rounding errors)
        if elapsed > 0 {
            self.last_updated = now;
            // TODO decide how reputations change with time. If they get too low
            // set the peers as banned
        }
    }

    /// Reports a peer for some action.
    ///
    /// If the peer doesn't exist, log a warning and insert defaults.
    pub fn _report_peer(&mut self, peer_id: &PeerId, action: PeerAction) {
        self.update_reputations();
        self.network_globals
            .peers
            .write()
            .add_reputation(peer_id, action as Rep);
        self.update_reputations();
    }

    /// Updates `PeerInfo` with `identify` information.
    pub fn identify(&mut self, peer_id: &PeerId, info: &IdentifyInfo) {
        if let Some(peer_info) = self.network_globals.peers.write().peer_info_mut(peer_id) {
            peer_info.client = client::Client::from_identify_info(info);
            peer_info.listening_addresses = info.listen_addrs.clone();
        } else {
            crit!(self.log, "Received an Identify response from an unknown peer"; "peer_id" => format!("{}", peer_id));
        }
    }

    /* Internal functions */

    /// Registers a peer as connected. The `ingoing` parameter determines if the peer is being
    /// dialed or connecting to us.
    ///
    /// This is called by `connect_ingoing` and `connect_outgoing`.
    ///
    /// This informs if the peer was accepted in to the db or not.
    // TODO: Drop peers if over max_peer limit
    fn connect_peer(&mut self, peer_id: &PeerId, outgoing: bool) -> bool {
        // TODO: Call this on a timer
        self.update_reputations();

        {
            let mut peerdb = self.network_globals.peers.write();
            if peerdb.connection_status(peer_id).map(|c| c.is_banned()) == Some(true) {
                // don't connect if the peer is banned
                return false;
            }

            if outgoing {
                peerdb.connect_outgoing(peer_id);
            } else {
                peerdb.connect_outgoing(peer_id);
            }
        }

        // start a ping and status timer for the peer
        self.ping_peers.insert(peer_id.clone());
        self.status_peers.insert(peer_id.clone());

        // increment prometheus metrics
        metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
        metrics::set_gauge(
            &metrics::PEERS_CONNECTED,
            self.network_globals.connected_peers() as i64,
        );

        true
    }

    /// Notifies the peer manager that this peer is being dialed.
    pub fn _dialing_peer(&mut self, peer_id: &PeerId) {
        self.network_globals.peers.write().dialing_peer(peer_id);
    }
}

impl<TSpec: EthSpec> Stream for PeerManager<TSpec> {
    type Item = PeerManagerEvent;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        // poll the timeouts for pings and status'
        while let Async::Ready(Some(peer_id)) = self.ping_peers.poll().map_err(|e| {
            error!(self.log, "Failed to check for peers to ping"; "error" => format!("{}",e));
        })? {
            debug!(self.log, "Pinging peer"; "peer_id" => format!("{}", peer_id));
            // add the ping timer back
            self.ping_peers.insert(peer_id.clone());
            self.events.push(PeerManagerEvent::Ping(peer_id));
        }

        while let Async::Ready(Some(peer_id)) = self.status_peers.poll().map_err(|e| {
            error!(self.log, "Failed to check for peers to status"; "error" => format!("{}",e));
        })? {
            debug!(self.log, "Sending Status to peer"; "peer_id" => format!("{}", peer_id));
            // add the status timer back
            self.status_peers.insert(peer_id.clone());
            self.events.push(PeerManagerEvent::Status(peer_id));
        }

        if !self.events.is_empty() {
            return Ok(Async::Ready(Some(self.events.remove(0))));
        } else {
            self.events.shrink_to_fit();
        }

        Ok(Async::NotReady)
    }
}
<commit_msg>Correctly notify delay queues (#1087)<commit_after>//! Implementation of a Lighthouse's peer management system.

pub use self::peerdb::*;
use crate::metrics;
use crate::rpc::MetaData;
use crate::{NetworkGlobals, PeerId};
use futures::prelude::*;
use futures::Stream;
use hashmap_delay::HashSetDelay;
use libp2p::identify::IdentifyInfo;
use slog::{crit, debug, error, warn};
use smallvec::SmallVec;
use std::sync::Arc;
use std::time::{Duration, Instant};
use types::EthSpec;

mod client;
mod peer_info;
mod peer_sync_status;
mod peerdb;

pub use peer_info::PeerInfo;
pub use peer_sync_status::{PeerSyncStatus, SyncInfo};
/// The minimum reputation before a peer is disconnected.
// Most likely this needs tweaking
const _MINIMUM_REPUTATION_BEFORE_BAN: Rep = 20;
/// The time in seconds between re-status's peers.
const STATUS_INTERVAL: u64 = 300;
/// The time in seconds between PING events. We do not send a ping if the other peer as PING'd us within
/// this time frame (Seconds)
const PING_INTERVAL: u64 = 30;

/// The main struct that handles peer's reputation and connection status.
pub struct PeerManager<TSpec: EthSpec> {
    /// Storage of network globals to access the PeerDB.
    network_globals: Arc<NetworkGlobals<TSpec>>,
    /// A queue of events that the `PeerManager` is waiting to produce.
    events: SmallVec<[PeerManagerEvent; 5]>,
    /// A collection of peers awaiting to be Ping'd.
    ping_peers: HashSetDelay<PeerId>,
    /// A collection of peers awaiting to be Status'd.
    status_peers: HashSetDelay<PeerId>,
    /// Last updated moment.
    last_updated: Instant,
    /// The logger associated with the `PeerManager`.
    log: slog::Logger,
}

/// A collection of actions a peer can perform which will adjust its reputation
/// Each variant has an associated reputation change.
pub enum PeerAction {
    /// The peer timed out on an RPC request/response.
    _TimedOut = -10,
    /// The peer sent and invalid request/response or encoding.
    _InvalidMessage = -20,
    /// The peer sent  something objectively malicious.
    _Malicious = -50,
    /// Received an expected message.
    _ValidMessage = 20,
    /// Peer disconnected.
    Disconnected = -30,
}

/// The events that the PeerManager outputs (requests).
pub enum PeerManagerEvent {
    /// Sends a STATUS to a peer.
    Status(PeerId),
    /// Sends a PING to a peer.
    Ping(PeerId),
    /// Request METADATA from a peer.
    MetaData(PeerId),
    /// The peer should be disconnected.
    _DisconnectPeer(PeerId),
    /// The peer should be disconnected and banned.
    _BanPeer(PeerId),
}

impl<TSpec: EthSpec> PeerManager<TSpec> {
    pub fn new(network_globals: Arc<NetworkGlobals<TSpec>>, log: &slog::Logger) -> Self {
        PeerManager {
            network_globals,
            events: SmallVec::new(),
            last_updated: Instant::now(),
            ping_peers: HashSetDelay::new(Duration::from_secs(PING_INTERVAL)),
            status_peers: HashSetDelay::new(Duration::from_secs(STATUS_INTERVAL)),
            log: log.clone(),
        }
    }

    /* Public accessible functions */

    /// A ping request has been received.
    // NOTE: The behaviour responds with a PONG automatically
    // TODO: Update last seen
    pub fn ping_request(&mut self, peer_id: &PeerId, seq: u64) {
        if let Some(peer_info) = self.network_globals.peers.read().peer_info(peer_id) {
            // received a ping
            // reset the to-ping timer for this peer
            debug!(self.log, "Received a ping request"; "peer_id" => format!("{}", peer_id), "seq_no" => seq);
            self.ping_peers.insert(peer_id.clone());

            // if the sequence number is unknown send update the meta data of the peer.
            if let Some(meta_data) = &peer_info.meta_data {
                if meta_data.seq_number < seq {
                    debug!(self.log, "Requesting new metadata from peer"; "peer_id" => format!("{}", peer_id), "known_seq_no" => meta_data.seq_number, "ping_seq_no" => seq);
                    self.events
                        .push(PeerManagerEvent::MetaData(peer_id.clone()));
                }
            } else {
                // if we don't know the meta-data, request it
                debug!(self.log, "Requesting first metadata from peer"; "peer_id" => format!("{}", peer_id));
                self.events
                    .push(PeerManagerEvent::MetaData(peer_id.clone()));
            }
        } else {
            crit!(self.log, "Received a PING from an unknown peer"; "peer_id" => format!("{}", peer_id));
        }
    }

    /// A PONG has been returned from a peer.
    // TODO: Update last seen
    pub fn pong_response(&mut self, peer_id: &PeerId, seq: u64) {
        if let Some(peer_info) = self.network_globals.peers.read().peer_info(peer_id) {
            // received a pong

            // if the sequence number is unknown send update the meta data of the peer.
            if let Some(meta_data) = &peer_info.meta_data {
                if meta_data.seq_number < seq {
                    debug!(self.log, "Requesting new metadata from peer"; "peer_id" => format!("{}", peer_id), "known_seq_no" => meta_data.seq_number, "pong_seq_no" => seq);
                    self.events
                        .push(PeerManagerEvent::MetaData(peer_id.clone()));
                }
            } else {
                // if we don't know the meta-data, request it
                debug!(self.log, "Requesting first metadata from peer"; "peer_id" => format!("{}", peer_id));
                self.events
                    .push(PeerManagerEvent::MetaData(peer_id.clone()));
            }
        } else {
            crit!(self.log, "Received a PONG from an unknown peer"; "peer_id" => format!("{}", peer_id));
        }
    }

    /// Received a metadata response from a peer.
    // TODO: Update last seen
    pub fn meta_data_response(&mut self, peer_id: &PeerId, meta_data: MetaData<TSpec>) {
        if let Some(peer_info) = self.network_globals.peers.write().peer_info_mut(peer_id) {
            if let Some(known_meta_data) = &peer_info.meta_data {
                if known_meta_data.seq_number < meta_data.seq_number {
                    debug!(self.log, "Updating peer's metadata"; "peer_id" => format!("{}", peer_id), "known_seq_no" => known_meta_data.seq_number, "new_seq_no" => meta_data.seq_number);
                    peer_info.meta_data = Some(meta_data);
                } else {
                    warn!(self.log, "Received old metadata"; "peer_id" => format!("{}", peer_id), "known_seq_no" => known_meta_data.seq_number, "new_seq_no" => meta_data.seq_number);
                }
            } else {
                // we have no meta-data for this peer, update
                debug!(self.log, "Obtained peer's metadata"; "peer_id" => format!("{}", peer_id), "new_seq_no" => meta_data.seq_number);
                peer_info.meta_data = Some(meta_data);
            }
        } else {
            crit!(self.log, "Received METADATA from an unknown peer"; "peer_id" => format!("{}", peer_id));
        }
    }

    /// A STATUS message has been received from a peer. This resets the status timer.
    pub fn peer_statusd(&mut self, peer_id: &PeerId) {
        self.status_peers.insert(peer_id.clone());
    }

    /// Checks the reputation of a peer and if it is too low, bans it and
    /// sends the corresponding event. Informs if it got banned
    fn _gets_banned(&mut self, peer_id: &PeerId) -> bool {
        // if the peer was already banned don't inform again
        let mut peerdb = self.network_globals.peers.write();

        if let Some(connection_status) = peerdb.connection_status(peer_id) {
            if peerdb.reputation(peer_id) < _MINIMUM_REPUTATION_BEFORE_BAN
                && !connection_status.is_banned()
            {
                peerdb.ban(peer_id);
                self.events
                    .push(PeerManagerEvent::_BanPeer(peer_id.clone()));
                return true;
            }
        }
        false
    }

    /// Requests that a peer get disconnected.
    pub fn _disconnect_peer(&mut self, peer_id: &PeerId) {
        self.events
            .push(PeerManagerEvent::_DisconnectPeer(peer_id.clone()));
    }

    /// Updates the state of the peer as disconnected.
    pub fn notify_disconnect(&mut self, peer_id: &PeerId) {
        self.update_reputations();
        {
            let mut peerdb = self.network_globals.peers.write();
            peerdb.disconnect(peer_id);
            peerdb.add_reputation(peer_id, PeerAction::Disconnected as Rep);
        }

        // remove the ping and status timer for the peer
        self.ping_peers.remove(peer_id);
        self.status_peers.remove(peer_id);
        metrics::inc_counter(&metrics::PEER_DISCONNECT_EVENT_COUNT);
        metrics::set_gauge(
            &metrics::PEERS_CONNECTED,
            self.network_globals.connected_peers() as i64,
        );
    }

    /// Sets a peer as connected as long as their reputation allows it
    /// Informs if the peer was accepted
    pub fn connect_ingoing(&mut self, peer_id: &PeerId) -> bool {
        self.connect_peer(peer_id, false)
    }

    /// Sets a peer as connected as long as their reputation allows it
    /// Informs if the peer was accepted
    pub fn connect_outgoing(&mut self, peer_id: &PeerId) -> bool {
        self.connect_peer(peer_id, true)
    }

    /// Provides a given peer's reputation if it exists.
    pub fn _get_peer_rep(&self, peer_id: &PeerId) -> Rep {
        self.network_globals.peers.read().reputation(peer_id)
    }

    /// Updates the reputation of known peers according to their connection
    /// status and the time that has passed.
    pub fn update_reputations(&mut self) {
        let now = Instant::now();
        let elapsed = (now - self.last_updated).as_secs();
        // 0 seconds means now - last_updated < 0, but (most likely) not = 0.
        // In this case, do nothing (updating last_updated would propagate
        // rounding errors)
        if elapsed > 0 {
            self.last_updated = now;
            // TODO decide how reputations change with time. If they get too low
            // set the peers as banned
        }
    }

    /// Reports a peer for some action.
    ///
    /// If the peer doesn't exist, log a warning and insert defaults.
    pub fn _report_peer(&mut self, peer_id: &PeerId, action: PeerAction) {
        self.update_reputations();
        self.network_globals
            .peers
            .write()
            .add_reputation(peer_id, action as Rep);
        self.update_reputations();
    }

    /// Updates `PeerInfo` with `identify` information.
    pub fn identify(&mut self, peer_id: &PeerId, info: &IdentifyInfo) {
        if let Some(peer_info) = self.network_globals.peers.write().peer_info_mut(peer_id) {
            peer_info.client = client::Client::from_identify_info(info);
            peer_info.listening_addresses = info.listen_addrs.clone();
        } else {
            crit!(self.log, "Received an Identify response from an unknown peer"; "peer_id" => format!("{}", peer_id));
        }
    }

    /* Internal functions */

    /// Registers a peer as connected. The `ingoing` parameter determines if the peer is being
    /// dialed or connecting to us.
    ///
    /// This is called by `connect_ingoing` and `connect_outgoing`.
    ///
    /// This informs if the peer was accepted in to the db or not.
    // TODO: Drop peers if over max_peer limit
    fn connect_peer(&mut self, peer_id: &PeerId, outgoing: bool) -> bool {
        // TODO: Call this on a timer
        self.update_reputations();

        {
            let mut peerdb = self.network_globals.peers.write();
            if peerdb.connection_status(peer_id).map(|c| c.is_banned()) == Some(true) {
                // don't connect if the peer is banned
                return false;
            }

            if outgoing {
                peerdb.connect_outgoing(peer_id);
            } else {
                peerdb.connect_outgoing(peer_id);
            }
        }

        // start a ping and status timer for the peer
        self.ping_peers.insert(peer_id.clone());
        self.status_peers.insert(peer_id.clone());

        // increment prometheus metrics
        metrics::inc_counter(&metrics::PEER_CONNECT_EVENT_COUNT);
        metrics::set_gauge(
            &metrics::PEERS_CONNECTED,
            self.network_globals.connected_peers() as i64,
        );

        true
    }

    /// Notifies the peer manager that this peer is being dialed.
    pub fn _dialing_peer(&mut self, peer_id: &PeerId) {
        self.network_globals.peers.write().dialing_peer(peer_id);
    }
}

impl<TSpec: EthSpec> Stream for PeerManager<TSpec> {
    type Item = PeerManagerEvent;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        // poll the timeouts for pings and status'
        // TODO: Remove task notifies and temporary vecs for stable futures
        // These exist to handle a bug in delayqueue
        let mut peers_to_add = Vec::new();
        while let Async::Ready(Some(peer_id)) = self.ping_peers.poll().map_err(|e| {
            error!(self.log, "Failed to check for peers to ping"; "error" => format!("{}",e));
        })? {
            debug!(self.log, "Pinging peer"; "peer_id" => format!("{}", peer_id));
            // add the ping timer back
            peers_to_add.push(peer_id.clone());
            self.events.push(PeerManagerEvent::Ping(peer_id));
        }

        if !peers_to_add.is_empty() {
            futures::task::current().notify();
        }
        while let Some(peer) = peers_to_add.pop() {
            self.ping_peers.insert(peer);
        }

        while let Async::Ready(Some(peer_id)) = self.status_peers.poll().map_err(|e| {
            error!(self.log, "Failed to check for peers to status"; "error" => format!("{}",e));
        })? {
            debug!(self.log, "Sending Status to peer"; "peer_id" => format!("{}", peer_id));
            // add the status timer back
            peers_to_add.push(peer_id.clone());
            self.events.push(PeerManagerEvent::Status(peer_id));
        }

        if !peers_to_add.is_empty() {
            futures::task::current().notify();
        }
        while let Some(peer) = peers_to_add.pop() {
            self.status_peers.insert(peer);
        }

        if !self.events.is_empty() {
            return Ok(Async::Ready(Some(self.events.remove(0))));
        } else {
            self.events.shrink_to_fit();
        }

        Ok(Async::NotReady)
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("02.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn run_program(program: &mut Vec<usize>) -> &mut Vec<usize> {
  let mut pointer = 0;

  loop {
    let v = |p| program[program[p]];
    let value = match program[pointer] {
      1 => v(pointer + 1) + v(pointer + 2),
      2 => v(pointer + 1) * v(pointer + 2),
      99 => break,
      _ => panic!()
    };

    let target_index = program[pointer + 3];
    program[target_index] = value;

    pointer += 4;
  }

  program
}

fn calculate_output(mut program: Vec<usize>, input: (usize, usize)) -> usize {
  program[1] = input.0;
  program[2] = input.1;

  run_program(&mut program);

  program[0]
}

fn main() {
  let input = get_input().unwrap();
  let program = input.split(',')
    .filter_map(|x| x.trim().parse::<usize>().ok())
    .collect::<Vec<_>>();

  println!("Part 1: {}", calculate_output(program.clone(), (12, 2)));

  for i in 0..100 {
    for j in 0..100 {
      let output = calculate_output(program.clone(), (i, j));

      if output == 19690720 {
        println!("Part 2: {}", i * 100 + j);
        return;
      }
    }
  }
}
<commit_msg>Clearer code<commit_after>use std::fs::File;
use std::io::prelude::*;

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("02.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn run_program(program: &mut Vec<usize>) {
  let mut pointer = 0;

  loop {
    let target_value = {
      let get = |p| program[program[p]];

      match program[pointer] {
        1 => get(pointer + 1) + get(pointer + 2),
        2 => get(pointer + 1) * get(pointer + 2),
        99 => break,
        _ => panic!()
      }
    };

    let target_index = program[pointer + 3];
    program[target_index] = target_value;

    pointer += 4;
  }
}

fn calculate_output(mut program: Vec<usize>, input: (usize, usize)) -> usize {
  program[1] = input.0;
  program[2] = input.1;

  run_program(&mut program);

  program[0]
}

fn main() {
  let input = get_input().unwrap();
  let program = input.split(',')
    .filter_map(|x| x.trim().parse::<usize>().ok())
    .collect::<Vec<_>>();

  println!("Part 1: {}", calculate_output(program.clone(), (12, 2)));

  for i in 0..100 {
    for j in 0..100 {
      let output = calculate_output(program.clone(), (i, j));

      if output == 19690720 {
        println!("Part 2: {}", i * 100 + j);
        return;
      }
    }
  }
}
<|endoftext|>


<commit_before>//!
//! Plan
//!

use std::fmt;
use std::result::Result;

use util::tree::{Tree, TreeBuildError};

pub enum AlgebraError
{
  EmptyStack,
  StillRemainStackItem
}

impl From<TreeBuildError> for AlgebraError {
  fn from(e: TreeBuildError) -> AlgebraError {
    match e {
      TreeBuildError::EmptyStack => AlgebraError::EmptyStack,
      TreeBuildError::StillRemainStackItem => AlgebraError::StillRemainStackItem,
    }
  }
}

pub trait DataSet : fmt::Display
{
  fn id    (&self) -> &str;
  fn kind  (&self) -> &str;
  fn schema(&self) -> &Vec<String>;
  fn uri   (&self) -> Option<&str>;
}

pub struct RegistredFormatData
{
  id: String,
  kind: String,
  schema: Option<Vec<String>>,
  props : Option<Vec<(String, String)>>
}

impl RegistredFormatData
{
  pub fn new(
      id   : &str,
      kind : &str,
      types: Option<Vec<&str>>,
      props: Option<Vec<(&str, &str)>>) -> RegistredFormatData
  {
    RegistredFormatData {
      id     : id.to_string(),
      kind   : kind.to_string(),

      schema : match types {
                 Some(t) => {
                   Some(t.iter()
                   .map(|s| s.to_string())
                   .collect::<Vec<String>>())
                 },
                 None => None
               },

      props  : match props {
                 Some(p) => {
                   Some(p.iter()
                   .map(|p| (p.0.to_string(), p.1.to_string()))
                   .collect::<Vec<(String, String)>>())
                 },
                 None => None
               }
    }
  }
}

impl fmt::Display for RegistredFormatData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "id={}, kind={}", self.id, self.kind)
    }
}

impl DataSet for RegistredFormatData
{
  fn id(&self) -> &str
  {
    &self.id
  }

  fn kind(&self) -> &str
  {
    &self.kind
  }

  fn schema(&self) -> &Vec<String>
  {
    self.schema.as_ref().unwrap()
  }

  fn uri(&self) -> Option<&str>
  {
    None
  }
}

pub enum JoinType
{
  INNER,
  LeftOuter,
  RightOuter,
  FullOuter
}

pub enum Operator
{
  Scan      (Box<DataSet>),
  Project   (Vec<Operator>),                               // child, exprs
  Filter    (Vec<Operator>),                               // child, bool exprs in a CNF form
  Join      (JoinType, Box<Operator>, Vec<Operator>),      // join type, left, right, join condition
  Aggregate (Vec<Operator>, Vec<Operator>),                // keys, exprs
  Head      (usize),                                       // row number to fetch
  Tail      (usize),                                       // row number to fetch
}

pub struct AlgebraBuilder
{
  builder: TreeBuilder<Operator>
}

impl AlgebraBuilder
{
  #[inline]
  pub fn new() -> AlgebraBuilder
  {
    AlgebraBuilder {
      builder: TreeBuilder::new();
    }
  }

  #[inline]
  pub fn build(mut self) -> Result<Operator, AlgebraError>
  {
    try!(self.builder.build())
  }

  #[inline]
  fn push(&mut self, op: Operator) -> &mut AlgebraBuilder
  {
    self.builder.push(op);
    self
  }

  pub fn dataset(&mut self, dataset: Box<DataSet>) -> &mut AlgebraBuilder
  {
    self.push(TreeNode::Leaf(Operator::Scan(dataset)));
    self
  }

  #[inline]
  pub fn filter(&mut self, filter: Vec<Operator>) -> &mut AlgebraBuilder
  {
    self.builder.
    self.push(TreeNode::Branch(op))
  }

  pub fn join(
      &mut self,
      join_type: JoinType,
      cond: Vec<Operator>) -> &mut AlgebraBuilder
  {
    debug_assert!(self.stack.len() > 1);
    let left = self.stack.pop().unwrap();
    let right = self.stack.pop().unwrap();
    self.push(Operator::Join(join_type, Box::new(left), Box::new(right), cond));
    self
  }

  pub fn join_with(
      &mut self,
      join_type: JoinType,
      right: Operator,
      cond: Vec<Operator>) -> &mut AlgebraBuilder
  {
    debug_assert!(self.stack.len() > 0);
    let left = self.stack.pop().unwrap();
    self.push(Operator::Join(join_type, Box::new(left), Box::new(right), cond));
    self
  }
}

impl fmt::Display for AlgebraBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "stack={}", self.stack.len())
    }
}

/// Visitor for Expr Tree
#[allow(unused_variables)]
pub trait Visitor<'v, T>: Sized {

  fn visit_dataset(
      &self,
      &mut T,
      dataset: &'v DataSet) {}

  fn visit_project(
      &self,
      context: &mut T,
      child: &'v Operator,
      exprs: &Vec<Operator>) {

    walk_op(self, context, child);
  }

  fn visit_filter(
      &self,
      context:
      &mut T,
      child: &'v Operator,
      filter: &Vec<Operator>) {

    walk_op(self, context, child);
  }

  fn visit_join(
      &self,
      context:
      &mut T,
      join_type: &JoinType,
      left: &'v Operator,
      right: &'v Operator,
      cond: &Vec<Operator>) {

    walk_op(self, context, left);
    walk_op(self, context, right);
  }

  fn visit_aggregate(
      &self,
      context:
      &mut T,
      child: &'v Operator,
      keys: &Vec<Operator>,
      exprs:&Vec<Operator>) {

    walk_op(self, context, child);
  }

  fn visit_head(
      &self,
      context: &mut T,
      child: &'v Operator,
      fetch_row: usize) {

    walk_op(self, context, child);
  }

  fn visit_tail(
      &self,
      context: &mut T,
      child: &'v Operator,
      fetch_row: usize) {

    walk_op(self, context, child);
  }
}

/// Walker for Expr Tree
pub fn walk_op<'v, T, V>(v: &V, ctx: &mut T, op: &'v Operator)
    where V: Visitor<'v, T> {
  match *op {
    Operator::Scan     (ref ds)                        => { v.visit_dataset(ctx, &**ds)},
    Operator::Project  (ref child,ref exprs)           => { v.visit_project(ctx, &**child, exprs) },
    Operator::Filter   (ref child,ref filters)         => { v.visit_filter(ctx, &**child, filters) },
    Operator::Aggregate(ref child,ref keys, ref exprs) => { v.visit_aggregate(ctx, &**child, keys, exprs) },
    Operator::Join     (ref join_type, ref left, ref right, ref cond) => {  v.visit_join(ctx, join_type, &**left, &**right, cond) },
    Operator::Head     (ref child,num)                 => { v.visit_head(ctx, &**child,num) },
    Operator::Tail     (ref child,num)                => { v.visit_tail(ctx, &**child,num) },
  }
}

   <commit_msg>Revert lib.rs in algebra.<commit_after>//!
//! Plan
//!

use std::fmt;
use std::result::Result;

pub enum AlgebraError
{
  EmptyStack,
  MismatchedStackType,
  NotConsumedStackItem
}

pub trait DataSet : fmt::Display
{
  fn id    (&self) -> &str;
  fn kind  (&self) -> &str;
  fn schema(&self) -> &Vec<String>;
  fn uri   (&self) -> Option<&str>;
}

pub struct RegistredFormatData
{
  id: String,
  kind: String,
  schema: Option<Vec<String>>,
  props : Option<Vec<(String, String)>>
}

impl RegistredFormatData
{
  pub fn new(
      id   : &str,
      kind : &str,
      types: Option<Vec<&str>>,
      props: Option<Vec<(&str, &str)>>) -> RegistredFormatData
  {
    RegistredFormatData {
      id     : id.to_string(),
      kind   : kind.to_string(),

      schema : match types {
                 Some(t) => {
                   Some(t.iter()
                   .map(|s| s.to_string())
                   .collect::<Vec<String>>())
                 },
                 None => None
               },

      props  : match props {
                 Some(p) => {
                   Some(p.iter()
                   .map(|p| (p.0.to_string(), p.1.to_string()))
                   .collect::<Vec<(String, String)>>())
                 },
                 None => None
               }
    }
  }
}

impl fmt::Display for RegistredFormatData {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "id={}, kind={}", self.id, self.kind)
    }
}

impl DataSet for RegistredFormatData
{
  fn id(&self) -> &str
  {
    &self.id
  }

  fn kind(&self) -> &str
  {
    &self.kind
  }

  fn schema(&self) -> &Vec<String>
  {
    self.schema.as_ref().unwrap()
  }

  fn uri(&self) -> Option<&str>
  {
    None
  }
}

pub enum JoinType
{
  INNER,
  LeftOuter,
  RightOuter,
  FullOuter
}

pub enum Operator
{
  Scan      (Box<DataSet>),
  Project   (Box<Operator>, Vec<Operator>),                // child, exprs
  Filter    (Box<Operator>, Vec<Operator>),                // child, bool exprs in a CNF form
  Join      (JoinType, Box<Operator>, Box<Operator>, Vec<Operator>), // join type, left, right, join condition
  Aggregate (Box<Operator>, Vec<Operator>, Vec<Operator>), // child, keys, exprs
  Head      (Box<Operator>, usize),                        // child, row number to fetch
  Tail      (Box<Operator>, usize),                        // child, row number to fetch
}

pub struct AlgebraBuilder
{
  stack: Vec<Operator>
}

impl AlgebraBuilder
{
  #[inline]
  pub fn new() -> AlgebraBuilder
  {
    AlgebraBuilder {
      stack: Vec::new()
    }
  }

  #[inline]
  pub fn build(mut self) -> Result<Operator, AlgebraError>
  {
    match self.stack.len() {
      0 => { Err(AlgebraError::EmptyStack) },
      1 => { Ok(self.stack.pop().unwrap()) },
      _ => { Err(AlgebraError::NotConsumedStackItem) }
    }
  }

  #[inline]
  fn push(&mut self, op: Operator) -> &mut AlgebraBuilder
  {
    self.stack.push(op);
    self
  }

  pub fn dataset(&mut self, dataset: Box<DataSet>) -> &mut AlgebraBuilder
  {
    self.push(Operator::Scan(dataset));
    self
  }

  #[inline]
  pub fn filter(&mut self, op: Operator) -> &mut AlgebraBuilder
  {
    self.push(op)
  }

  pub fn join(
      &mut self,
      join_type: JoinType,
      cond: Vec<Operator>) -> &mut AlgebraBuilder
  {
    debug_assert!(self.stack.len() > 1);
    let left = self.stack.pop().unwrap();
    let right = self.stack.pop().unwrap();
    self.push(Operator::Join(join_type, Box::new(left), Box::new(right), cond));
    self
  }

  pub fn join_with(
      &mut self,
      join_type: JoinType,
      right: Operator,
      cond: Vec<Operator>) -> &mut AlgebraBuilder
  {
    debug_assert!(self.stack.len() > 0);
    let left = self.stack.pop().unwrap();
    self.push(Operator::Join(join_type, Box::new(left), Box::new(right), cond));
    self
  }
}

impl fmt::Display for AlgebraBuilder {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      write!(f, "stack={}", self.stack.len())
    }
}

/// Visitor for Expr Tree
#[allow(unused_variables)]
pub trait Visitor<'v, T>: Sized {

  fn visit_dataset(
      &self,
      &mut T,
      dataset: &'v DataSet) {}

  fn visit_project(
      &self,
      context: &mut T,
      child: &'v Operator,
      exprs: &Vec<Operator>) {

    walk_op(self, context, child);
  }

  fn visit_filter(
      &self,
      context:
      &mut T,
      child: &'v Operator,
      filter: &Vec<Operator>) {

    walk_op(self, context, child);
  }

  fn visit_join(
      &self,
      context:
      &mut T,
      join_type: &JoinType,
      left: &'v Operator,
      right: &'v Operator,
      cond: &Vec<Operator>) {

    walk_op(self, context, left);
    walk_op(self, context, right);
  }

  fn visit_aggregate(
      &self,
      context:
      &mut T,
      child: &'v Operator,
      keys: &Vec<Operator>,
      exprs:&Vec<Operator>) {

    walk_op(self, context, child);
  }

  fn visit_head(
      &self,
      context: &mut T,
      child: &'v Operator,
      fetch_row: usize) {

    walk_op(self, context, child);
  }

  fn visit_tail(
      &self,
      context: &mut T,
      child: &'v Operator,
      fetch_row: usize) {

    walk_op(self, context, child);
  }
}

/// Walker for Expr Tree
pub fn walk_op<'v, T, V>(v: &V, ctx: &mut T, op: &'v Operator)
    where V: Visitor<'v, T> {
  match *op {
    Operator::Scan     (ref ds)                        => { v.visit_dataset(ctx, &**ds)},
    Operator::Project  (ref child,ref exprs)           => { v.visit_project(ctx, &**child, exprs) },
    Operator::Filter   (ref child,ref filters)         => { v.visit_filter(ctx, &**child, filters) },
    Operator::Aggregate(ref child,ref keys, ref exprs) => { v.visit_aggregate(ctx, &**child, keys, exprs) },
    Operator::Join     (ref join_type, ref left, ref right, ref cond) => {  v.visit_join(ctx, join_type, &**left, &**right, cond) },
    Operator::Head     (ref child,num)                 => { v.visit_head(ctx, &**child,num) },
    Operator::Tail     (ref child,num)                => { v.visit_tail(ctx, &**child,num) },
  }
}

    <|endoftext|>


<commit_before>pub fn sync() {
    atomic_module();
}

fn atomic_module() {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::thread;

    let spinlock = Arc::new(AtomicUsize::new(1));

    let spinlock_clone = spinlock.clone();
    let thread = thread::spawn(move || {
        spinlock_clone.store(0, Ordering::SeqCst);
    });

    // wait for the other thread to release the lock
    while spinlock.load(Ordering::SeqCst) != 0 { }

    if let Err(panic) = thread.join() {
        println!("Thread had an error: {:?}", panic);
    }

    use std::sync::atomic::ATOMIC_USIZE_INIT;

    static GLOBAL_THREAD_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;

    let old_thread_count = GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::SeqCst);
    println!("live threads: {}", old_thread_count + 1);

    use std::sync::atomic::AtomicBool;

    let atomic_true = AtomicBool::new(true);
    let atomic_false = AtomicBool::new(false);

    let mut some_bool = AtomicBool::new(true);
    assert_eq!(true, *some_bool.get_mut());
    *some_bool.get_mut() = false;
    assert_eq!(false, some_bool.load(Ordering::SeqCst));

    let some_bool = AtomicBool::new(true);
    assert_eq!(true, some_bool.into_inner());

    let some_bool = AtomicBool::new(true);
    assert_eq!(true, some_bool.load(Ordering::Relaxed));

    let some_bool = AtomicBool::new(true);
    some_bool.store(false, Ordering::Relaxed);
    assert_eq!(false, some_bool.load(Ordering::Relaxed));

    let some_bool = AtomicBool::new(true);
    assert_eq!(true, some_bool.swap(false, Ordering::Relaxed));
    assert_eq!(false, some_bool.load(Ordering::Relaxed));

}
<commit_msg>[Rust] STD Library - Modules - sync::mpsc<commit_after>pub fn sync() {
    atomic_module();
    mpsc_module();
}

fn atomic_module() {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::thread;

    let spinlock = Arc::new(AtomicUsize::new(1));

    let spinlock_clone = spinlock.clone();
    let thread = thread::spawn(move || {
        spinlock_clone.store(0, Ordering::SeqCst);
    });

    // wait for the other thread to release the lock
    while spinlock.load(Ordering::SeqCst) != 0 { }

    if let Err(panic) = thread.join() {
        println!("Thread had an error: {:?}", panic);
    }

    use std::sync::atomic::ATOMIC_USIZE_INIT;

    static GLOBAL_THREAD_COUNT: AtomicUsize = ATOMIC_USIZE_INIT;

    let old_thread_count = GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::SeqCst);
    println!("live threads: {}", old_thread_count + 1);

    use std::sync::atomic::AtomicBool;

    let atomic_true = AtomicBool::new(true);
    let atomic_false = AtomicBool::new(false);

    let mut some_bool = AtomicBool::new(true);
    assert_eq!(true, *some_bool.get_mut());
    *some_bool.get_mut() = false;
    assert_eq!(false, some_bool.load(Ordering::SeqCst));

    let some_bool = AtomicBool::new(true);
    assert_eq!(true, some_bool.into_inner());

    let some_bool = AtomicBool::new(true);
    assert_eq!(true, some_bool.load(Ordering::Relaxed));

    let some_bool = AtomicBool::new(true);
    some_bool.store(false, Ordering::Relaxed);
    assert_eq!(false, some_bool.load(Ordering::Relaxed));

    let some_bool = AtomicBool::new(true);
    assert_eq!(true, some_bool.swap(false, Ordering::Relaxed));
    assert_eq!(false, some_bool.load(Ordering::Relaxed));
}

fn mpsc_module() {
    use std::thread;
    use std::sync::mpsc::channel;

    let (tx, rx) = channel();
    thread::spawn(move || {
        tx.send(10).unwrap();
    });
    assert_eq!(10, rx.recv().unwrap());

    // shared usage

    // create a shared channel that can be sent along from many threads
    // tx (transmission) is the sending half, and rx (receiving) is the receiving half
    let (tx, rx) = channel();
    for i in 0..10 {
        let tx = tx.clone();
        thread::spawn(move || {
            tx.send(i).unwrap();
        });
    }

    for _ in 0..10 {
        let j = rx.recv().unwrap();
        assert!(0 <= j && j < 10);
    }

    // propagating panics

    // the call to recv() will return an error because the channel has already hung up (or been deallocated)
    let (tx, rx) = channel::<i32>();
    drop(tx);
    assert!(rx.recv().is_err());

    use std::sync::mpsc::sync_channel;

    let (tx, rx) = sync_channel::<i32>(0);
    thread::spawn(move || {
        // this will wait for the parent thread to start receiving
        tx.send(53).unwrap();
    });
    rx.recv().unwrap();
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate ruyi;

use ruyi::buf::ByteBuf;
use ruyi::buf::codec::*;

use test::Bencher;

const SIZE: usize = 16 * 1024;

#[bench]
fn bench_find(b: &mut Bencher) {
    let mut buf = ByteBuf::with_capacity(SIZE);
    buf.append(u8s::filling(0, SIZE), u8s::append_fill).unwrap();
    let needle = b"\r\n";
    b.iter(|| { buf.find(needle); });
}

#[bench]
fn bench_windows(b: &mut Bencher) {
    let mut buf = ByteBuf::with_capacity(SIZE);
    buf.append(u8s::filling(0, SIZE), u8s::append_fill).unwrap();
    let needle = b"\r\n";
    b.iter(|| { buf.windows(needle.len()).position(|w| w == needle); });
}
<commit_msg>Add bench_append_slice and bench_append_vec<commit_after>#![feature(test)]

extern crate test;
extern crate ruyi;

use ruyi::buf::ByteBuf;
use ruyi::buf::codec::*;

use test::Bencher;

const SIZE: usize = 16 * 1024;

#[bench]
fn bench_find(b: &mut Bencher) {
    let mut buf = ByteBuf::with_capacity(SIZE);
    buf.append(u8s::filling(0, SIZE), u8s::append_fill).unwrap();
    let needle = b"\r\n";
    b.iter(|| { buf.find(needle); });
}

#[bench]
fn bench_windows(b: &mut Bencher) {
    let mut buf = ByteBuf::with_capacity(SIZE);
    buf.append(u8s::filling(0, SIZE), u8s::append_fill).unwrap();
    let needle = b"\r\n";
    b.iter(|| { buf.windows(needle.len()).position(|w| w == needle); });
}

const BYTES_SIZE: usize = 1024 * 6;

#[bench]
fn bench_append_slice(b: &mut Bencher) {
    let mut bytes = Vec::with_capacity(BYTES_SIZE);
    unsafe {
        bytes.set_len(BYTES_SIZE);
    }
    b.iter(|| for _ in 0..100 {
        let bytes2 = bytes.to_vec();
        let mut buf = ByteBuf::with_capacity(SIZE);
        buf.append(bytes2.as_slice(), u8s::append).unwrap();
    });
}

#[bench]
fn bench_append_vec(b: &mut Bencher) {
    let mut bytes = Vec::with_capacity(BYTES_SIZE);
    unsafe {
        bytes.set_len(BYTES_SIZE);
    }
    b.iter(|| for _ in 0..100 {
        let bytes2 = bytes.to_vec();
        let mut buf = ByteBuf::with_capacity(SIZE);
        buf.append(bytes2, u8s::append_vec).unwrap();
    });
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use smallvec::SmallVec;
use std::iter::Empty;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

use device::Device;
use device::Queue;
use format::ClearValue;
use format::FormatDesc;
use format::FormatTy;
use image::Dimensions;
use image::ImageInner;
use image::ImageLayout;
use image::ImageUsage;
use image::sys::ImageCreationError;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::traits::ImageAccess;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
use image::traits::ImageViewAccess;
use instance::QueueFamily;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::Sharing;

/// General-purpose image in device memory. Can be used for any usage, but will be slower than a
/// specialized image.
#[derive(Debug)]
pub struct StorageImage<F, A = Arc<StdMemoryPool>>
    where A: MemoryPool
{
    // Inner implementation.
    image: UnsafeImage,

    // We maintain a view of the whole image.
    view: UnsafeImageView,

    // Memory used to back the image.
    memory: A::Alloc,

    // Dimensions of the image view.
    dimensions: Dimensions,

    // Format.
    format: F,

    // Queue families allowed to access this image.
    queue_families: SmallVec<[u32; 4]>,

    // Number of times this image is locked on the GPU side.
    gpu_lock: AtomicUsize,
}

impl<F> StorageImage<F> {
    /// Creates a new image with the given dimensions and format.
    pub fn new<'a, I>(device: Arc<Device>, dimensions: Dimensions, format: F, queue_families: I)
                      -> Result<Arc<StorageImage<F>>, ImageCreationError>
        where F: FormatDesc,
              I: IntoIterator<Item = QueueFamily<'a>>
    {
        let is_depth = match format.format().ty() {
            FormatTy::Depth => true,
            FormatTy::DepthStencil => true,
            FormatTy::Stencil => true,
            FormatTy::Compressed => panic!(),
            _ => false,
        };

        let usage = ImageUsage {
            transfer_source: true,
            transfer_destination: true,
            sampled: true,
            storage: true,
            color_attachment: !is_depth,
            depth_stencil_attachment: is_depth,
            input_attachment: true,
            transient_attachment: false,
        };

        let queue_families = queue_families
            .into_iter()
            .map(|f| f.id())
            .collect::<SmallVec<[u32; 4]>>();

        let (image, mem_reqs) = unsafe {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            UnsafeImage::new(device.clone(),
                             usage,
                             format.format(),
                             dimensions.to_image_dimensions(),
                             1,
                             1,
                             Sharing::Exclusive::<Empty<u32>>,
                             false,
                             false)?
        };

        let mem_ty = {
            let device_local = device
                .physical_device()
                .memory_types()
                .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                .filter(|t| t.is_device_local());
            let any = device
                .physical_device()
                .memory_types()
                .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = MemoryPool::alloc(&Device::standard_pool(&device),
                                    mem_ty,
                                    mem_reqs.size,
                                    mem_reqs.alignment,
                                    AllocLayout::Optimal)?;
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        unsafe {
            image.bind_memory(mem.memory(), mem.offset())?;
        }

        let view = unsafe {
            UnsafeImageView::raw(&image,
                                 dimensions.to_view_type(),
                                 0 .. image.mipmap_levels(),
                                 0 .. image.dimensions().array_layers())?
        };

        Ok(Arc::new(StorageImage {
                        image: image,
                        view: view,
                        memory: mem,
                        dimensions: dimensions,
                        format: format,
                        queue_families: queue_families,
                        gpu_lock: AtomicUsize::new(0),
                    }))
    }
}

impl<F, A> StorageImage<F, A>
    where A: MemoryPool
{
    /// Returns the dimensions of the image.
    #[inline]
    pub fn dimensions(&self) -> Dimensions {
        self.dimensions
    }
}

unsafe impl<F, A> ImageAccess for StorageImage<F, A>
    where F: 'static + Send + Sync,
          A: MemoryPool
{
    #[inline]
    fn inner(&self) -> ImageInner {
        ImageInner {
            image: &self.image,
            first_layer: 0,
            num_layers: self.dimensions.array_layers() as usize,
            first_mipmap_level: 0,
            num_mipmap_levels: 1,
        }
    }

    #[inline]
    fn initial_layout_requirement(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn final_layout_requirement(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn conflict_key(&self, _: u32, _: u32, _: u32, _: u32) -> u64 {
        self.image.key()
    }

    #[inline]
    fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
        let val = self.gpu_lock.fetch_add(1, Ordering::SeqCst);
        if val == 1 {
            Ok(())
        } else {
            self.gpu_lock.fetch_sub(1, Ordering::SeqCst);
            Err(AccessError::AlreadyInUse)
        }
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        let val = self.gpu_lock.fetch_add(1, Ordering::SeqCst);
        debug_assert!(val >= 1);
    }

    #[inline]
    unsafe fn unlock(&self) {
        self.gpu_lock.fetch_sub(1, Ordering::SeqCst);
    }
}

unsafe impl<F, A> ImageClearValue<F::ClearValue> for StorageImage<F, A>
    where F: FormatDesc + 'static + Send + Sync,
          A: MemoryPool
{
    #[inline]
    fn decode(&self, value: F::ClearValue) -> Option<ClearValue> {
        Some(self.format.decode_clear_value(value))
    }
}

unsafe impl<P, F, A> ImageContent<P> for StorageImage<F, A>
    where F: 'static + Send + Sync,
          A: MemoryPool
{
    #[inline]
    fn matches_format(&self) -> bool {
        true // FIXME:
    }
}

unsafe impl<F, A> ImageViewAccess for StorageImage<F, A>
    where F: 'static + Send + Sync,
          A: MemoryPool
{
    #[inline]
    fn parent(&self) -> &ImageAccess {
        self
    }

    #[inline]
    fn dimensions(&self) -> Dimensions {
        self.dimensions
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        &self.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}

#[cfg(test)]
mod tests {
    use super::StorageImage;
    use format::Format;
    use image::Dimensions;

    #[test]
    fn create() {
        let (device, queue) = gfx_dev_and_queue!();
        let _img = StorageImage::new(device,
                                     Dimensions::Dim2d {
                                         width: 32,
                                         height: 32,
                                     },
                                     Format::R8G8B8A8Unorm,
                                     Some(queue.family()))
            .unwrap();
    }
}
<commit_msg>Fix the storage image wrong GPU lock impl<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use smallvec::SmallVec;
use std::iter::Empty;
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;

use device::Device;
use device::Queue;
use format::ClearValue;
use format::FormatDesc;
use format::FormatTy;
use image::Dimensions;
use image::ImageInner;
use image::ImageLayout;
use image::ImageUsage;
use image::sys::ImageCreationError;
use image::sys::UnsafeImage;
use image::sys::UnsafeImageView;
use image::traits::ImageAccess;
use image::traits::ImageClearValue;
use image::traits::ImageContent;
use image::traits::ImageViewAccess;
use instance::QueueFamily;
use memory::pool::AllocLayout;
use memory::pool::MemoryPool;
use memory::pool::MemoryPoolAlloc;
use memory::pool::StdMemoryPool;
use sync::AccessError;
use sync::Sharing;

/// General-purpose image in device memory. Can be used for any usage, but will be slower than a
/// specialized image.
#[derive(Debug)]
pub struct StorageImage<F, A = Arc<StdMemoryPool>>
    where A: MemoryPool
{
    // Inner implementation.
    image: UnsafeImage,

    // We maintain a view of the whole image.
    view: UnsafeImageView,

    // Memory used to back the image.
    memory: A::Alloc,

    // Dimensions of the image view.
    dimensions: Dimensions,

    // Format.
    format: F,

    // Queue families allowed to access this image.
    queue_families: SmallVec<[u32; 4]>,

    // Number of times this image is locked on the GPU side.
    gpu_lock: AtomicUsize,
}

impl<F> StorageImage<F> {
    /// Creates a new image with the given dimensions and format.
    pub fn new<'a, I>(device: Arc<Device>, dimensions: Dimensions, format: F, queue_families: I)
                      -> Result<Arc<StorageImage<F>>, ImageCreationError>
        where F: FormatDesc,
              I: IntoIterator<Item = QueueFamily<'a>>
    {
        let is_depth = match format.format().ty() {
            FormatTy::Depth => true,
            FormatTy::DepthStencil => true,
            FormatTy::Stencil => true,
            FormatTy::Compressed => panic!(),
            _ => false,
        };

        let usage = ImageUsage {
            transfer_source: true,
            transfer_destination: true,
            sampled: true,
            storage: true,
            color_attachment: !is_depth,
            depth_stencil_attachment: is_depth,
            input_attachment: true,
            transient_attachment: false,
        };

        let queue_families = queue_families
            .into_iter()
            .map(|f| f.id())
            .collect::<SmallVec<[u32; 4]>>();

        let (image, mem_reqs) = unsafe {
            let sharing = if queue_families.len() >= 2 {
                Sharing::Concurrent(queue_families.iter().cloned())
            } else {
                Sharing::Exclusive
            };

            UnsafeImage::new(device.clone(),
                             usage,
                             format.format(),
                             dimensions.to_image_dimensions(),
                             1,
                             1,
                             Sharing::Exclusive::<Empty<u32>>,
                             false,
                             false)?
        };

        let mem_ty = {
            let device_local = device
                .physical_device()
                .memory_types()
                .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0)
                .filter(|t| t.is_device_local());
            let any = device
                .physical_device()
                .memory_types()
                .filter(|t| (mem_reqs.memory_type_bits & (1 << t.id())) != 0);
            device_local.chain(any).next().unwrap()
        };

        let mem = MemoryPool::alloc(&Device::standard_pool(&device),
                                    mem_ty,
                                    mem_reqs.size,
                                    mem_reqs.alignment,
                                    AllocLayout::Optimal)?;
        debug_assert!((mem.offset() % mem_reqs.alignment) == 0);
        unsafe {
            image.bind_memory(mem.memory(), mem.offset())?;
        }

        let view = unsafe {
            UnsafeImageView::raw(&image,
                                 dimensions.to_view_type(),
                                 0 .. image.mipmap_levels(),
                                 0 .. image.dimensions().array_layers())?
        };

        Ok(Arc::new(StorageImage {
                        image: image,
                        view: view,
                        memory: mem,
                        dimensions: dimensions,
                        format: format,
                        queue_families: queue_families,
                        gpu_lock: AtomicUsize::new(0),
                    }))
    }
}

impl<F, A> StorageImage<F, A>
    where A: MemoryPool
{
    /// Returns the dimensions of the image.
    #[inline]
    pub fn dimensions(&self) -> Dimensions {
        self.dimensions
    }
}

unsafe impl<F, A> ImageAccess for StorageImage<F, A>
    where F: 'static + Send + Sync,
          A: MemoryPool
{
    #[inline]
    fn inner(&self) -> ImageInner {
        ImageInner {
            image: &self.image,
            first_layer: 0,
            num_layers: self.dimensions.array_layers() as usize,
            first_mipmap_level: 0,
            num_mipmap_levels: 1,
        }
    }

    #[inline]
    fn initial_layout_requirement(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn final_layout_requirement(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn conflict_key(&self, _: u32, _: u32, _: u32, _: u32) -> u64 {
        self.image.key()
    }

    #[inline]
    fn try_gpu_lock(&self, _: bool, _: &Queue) -> Result<(), AccessError> {
        let val = self.gpu_lock.compare_and_swap(0, 1, Ordering::SeqCst);
        if val == 0 {
            Ok(())
        } else {
            Err(AccessError::AlreadyInUse)
        }
    }

    #[inline]
    unsafe fn increase_gpu_lock(&self) {
        let val = self.gpu_lock.fetch_add(1, Ordering::SeqCst);
        debug_assert!(val >= 1);
    }

    #[inline]
    unsafe fn unlock(&self) {
        self.gpu_lock.fetch_sub(1, Ordering::SeqCst);
    }
}

unsafe impl<F, A> ImageClearValue<F::ClearValue> for StorageImage<F, A>
    where F: FormatDesc + 'static + Send + Sync,
          A: MemoryPool
{
    #[inline]
    fn decode(&self, value: F::ClearValue) -> Option<ClearValue> {
        Some(self.format.decode_clear_value(value))
    }
}

unsafe impl<P, F, A> ImageContent<P> for StorageImage<F, A>
    where F: 'static + Send + Sync,
          A: MemoryPool
{
    #[inline]
    fn matches_format(&self) -> bool {
        true // FIXME:
    }
}

unsafe impl<F, A> ImageViewAccess for StorageImage<F, A>
    where F: 'static + Send + Sync,
          A: MemoryPool
{
    #[inline]
    fn parent(&self) -> &ImageAccess {
        self
    }

    #[inline]
    fn dimensions(&self) -> Dimensions {
        self.dimensions
    }

    #[inline]
    fn inner(&self) -> &UnsafeImageView {
        &self.view
    }

    #[inline]
    fn descriptor_set_storage_image_layout(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn descriptor_set_combined_image_sampler_layout(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn descriptor_set_sampled_image_layout(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn descriptor_set_input_attachment_layout(&self) -> ImageLayout {
        ImageLayout::General
    }

    #[inline]
    fn identity_swizzle(&self) -> bool {
        true
    }
}

#[cfg(test)]
mod tests {
    use super::StorageImage;
    use format::Format;
    use image::Dimensions;

    #[test]
    fn create() {
        let (device, queue) = gfx_dev_and_queue!();
        let _img = StorageImage::new(device,
                                     Dimensions::Dim2d {
                                         width: 32,
                                         height: 32,
                                     },
                                     Format::R8G8B8A8Unorm,
                                     Some(queue.family()))
            .unwrap();
    }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! strcmp_tests {
    ( $( $region_id:ident => $TestRegion:path ),* ) => {
        use libc::c_char;
        use lucet_runtime::vmctx::Vmctx;
        use lucet_runtime::lucet_hostcall;
        #[lucet_hostcall]
        #[no_mangle]
        pub fn hostcall_host_fault(_vmctx: &mut Vmctx) {
            let oob = (-1isize) as *mut c_char;
            unsafe {
                *oob = 'x' as c_char;
            }
        }

        $(
            mod $region_id {
                use libc::{c_char, c_int, c_void, strcmp};
                use lucet_runtime::vmctx::{lucet_vmctx, Vmctx};
                use lucet_runtime::{Error, Limits, Region, Val, WASM_PAGE_SIZE};
                use std::ffi::CString;
                use std::sync::Arc;
                use $TestRegion as TestRegion;
                use $crate::build::test_module_c;

                fn strcmp_compare(s1: &str, s2: &str) {
                    let s1 = CString::new(s1)
                        .expect("s1 is a valid CString")
                        .into_bytes_with_nul();
                    let s2 = CString::new(s2)
                        .expect("s2 is a valid CString")
                        .into_bytes_with_nul();

                    assert!(s1.len() + s2.len() < WASM_PAGE_SIZE as usize);

                    let module = test_module_c("strcmp", "guest.c").expect("compile module");
                    let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
                    let mut inst = region
                        .new_instance(module)
                        .expect("instance can be created");

                    let newpage_start = inst.grow_memory(1).expect("grow_memory succeeds");
                    let heap = inst.heap_mut();

                    let s1_ptr = (newpage_start * WASM_PAGE_SIZE) as usize;
                    let s2_ptr = s1_ptr + s1.len();
                    heap[s1_ptr..s2_ptr].copy_from_slice(&s1);
                    heap[s2_ptr..s2_ptr + s2.len()].copy_from_slice(&s2);

                    let res = c_int::from(
                        inst.run(
                            "run_strcmp",
                            &[Val::GuestPtr(s1_ptr as u32), Val::GuestPtr(s2_ptr as u32)],
                        )
                            .expect("instance runs")
                            .unwrap_returned(),
                    );

                    let host_strcmp_res =
                        unsafe { strcmp(s1.as_ptr() as *const c_char, s2.as_ptr() as *const c_char) };
                    assert_eq!(res, host_strcmp_res);
                }

                #[test]
                fn strcmp_abc_abc() {
                    strcmp_compare("abc", "abc");
                }

                #[test]
                fn strcmp_def_abc() {
                    strcmp_compare("def", "abc");
                }

                #[test]
                fn strcmp_abcd_abc() {
                    strcmp_compare("abcd", "abc");
                }

                #[test]
                fn strcmp_abc_abcd() {
                    strcmp_compare("abc", "abcd");
                }

                #[test]
                fn strcmp_fault_test() {
                    let module = test_module_c("strcmp", "guest.c").expect("compile module");
                    let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
                    let mut inst = region
                        .new_instance(module)
                        .expect("instance can be created");

                    match inst.run("wasm_fault", &[]) {
                        Err(Error::RuntimeFault { .. }) => (),
                        res => panic!("unexpected result: {:?}", res),
                    }
                }

                #[test]
                fn ensure_linked() {
                    lucet_runtime::lucet_internal_ensure_linked();
                }
            }
        )*
    };
}
<commit_msg>Fix indentation problem from rebase conflict<commit_after>#[macro_export]
macro_rules! strcmp_tests {
    ( $( $region_id:ident => $TestRegion:path ),* ) => {
        use libc::c_char;
        use lucet_runtime::vmctx::Vmctx;
        use lucet_runtime::lucet_hostcall;
        #[lucet_hostcall]
        #[no_mangle]
        pub fn hostcall_host_fault(_vmctx: &mut Vmctx) {
            let oob = (-1isize) as *mut c_char;
            unsafe {
                *oob = 'x' as c_char;
            }
        }

        $(
            mod $region_id {
                use libc::{c_char, c_int, c_void, strcmp};
                use lucet_runtime::vmctx::{lucet_vmctx, Vmctx};
                use lucet_runtime::{Error, Limits, Region, Val, WASM_PAGE_SIZE};
                use std::ffi::CString;
                use std::sync::Arc;
                use $TestRegion as TestRegion;
                use $crate::build::test_module_c;

                fn strcmp_compare(s1: &str, s2: &str) {
                    let s1 = CString::new(s1)
                        .expect("s1 is a valid CString")
                        .into_bytes_with_nul();
                    let s2 = CString::new(s2)
                        .expect("s2 is a valid CString")
                        .into_bytes_with_nul();

                    assert!(s1.len() + s2.len() < WASM_PAGE_SIZE as usize);

                    let module = test_module_c("strcmp", "guest.c").expect("compile module");
                    let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
                    let mut inst = region
                        .new_instance(module)
                        .expect("instance can be created");

                    let newpage_start = inst.grow_memory(1).expect("grow_memory succeeds");
                    let heap = inst.heap_mut();

                    let s1_ptr = (newpage_start * WASM_PAGE_SIZE) as usize;
                    let s2_ptr = s1_ptr + s1.len();
                    heap[s1_ptr..s2_ptr].copy_from_slice(&s1);
                    heap[s2_ptr..s2_ptr + s2.len()].copy_from_slice(&s2);

                    let res = c_int::from(
                        inst.run(
                            "run_strcmp",
                            &[Val::GuestPtr(s1_ptr as u32), Val::GuestPtr(s2_ptr as u32)],
                        )
                            .expect("instance runs")
                            .unwrap_returned(),
                    );

                    let host_strcmp_res =
                        unsafe { strcmp(s1.as_ptr() as *const c_char, s2.as_ptr() as *const c_char) };
                    assert_eq!(res, host_strcmp_res);
                }

                #[test]
                fn strcmp_abc_abc() {
                    strcmp_compare("abc", "abc");
                }

                #[test]
                fn strcmp_def_abc() {
                    strcmp_compare("def", "abc");
                }

                #[test]
                fn strcmp_abcd_abc() {
                    strcmp_compare("abcd", "abc");
                }

                #[test]
                fn strcmp_abc_abcd() {
                    strcmp_compare("abc", "abcd");
                }

                #[test]
                fn strcmp_fault_test() {
                    let module = test_module_c("strcmp", "guest.c").expect("compile module");
                    let region = TestRegion::create(10, &Limits::default()).expect("region can be created");
                    let mut inst = region
                        .new_instance(module)
                        .expect("instance can be created");

                    match inst.run("wasm_fault", &[]) {
                        Err(Error::RuntimeFault { .. }) => (),
                        res => panic!("unexpected result: {:?}", res),
                    }
                }

                #[test]
                fn ensure_linked() {
                    lucet_runtime::lucet_internal_ensure_linked();
                }
            }
        )*
    };
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use super::fun::{FnAnalysis, FnAnalysisBody, FnKind, MethodKind};
use crate::conversion::api::ApiDetail;
use crate::conversion::api::{Api, TypeKind};
use std::collections::HashSet;

/// Spot types with pure virtual functions and mark them abstract.
pub(crate) fn mark_types_abstract(apis: &mut Vec<Api<FnAnalysis>>) {
    let abstract_types: HashSet<_> = apis
        .iter()
        .filter_map(|api| match &api.detail {
            ApiDetail::Function {
                fun: _,
                analysis:
                    FnAnalysisBody {
                        kind: FnKind::Method(self_ty_name, MethodKind::PureVirtual),
                        ..
                    },
            } => Some(self_ty_name.clone()),
            _ => None,
        })
        .collect();
    if abstract_types.is_empty() {
        return;
    }

    for api in apis.iter_mut() {
        let tyname = api.typename();
        match &mut api.detail {
            ApiDetail::Type { analysis, .. } if abstract_types.contains(&tyname) => {
                *analysis = TypeKind::Abstract;
            }
            _ => {}
        }
    }

    // We also need to remove any constructors belonging to these
    // abstract types.
    apis.retain(|api| match &api.detail {
        ApiDetail::Function {
            fun: _,
            analysis:
                FnAnalysisBody {
                    kind: FnKind::Method(self_ty, MethodKind::Constructor),
                    ..
                },
        } if abstract_types.contains(&self_ty) => false,
        _ => true,
    })
}
<commit_msg>Clippy recommendation.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use super::fun::{FnAnalysis, FnAnalysisBody, FnKind, MethodKind};
use crate::conversion::api::ApiDetail;
use crate::conversion::api::{Api, TypeKind};
use std::collections::HashSet;

/// Spot types with pure virtual functions and mark them abstract.
pub(crate) fn mark_types_abstract(apis: &mut Vec<Api<FnAnalysis>>) {
    let abstract_types: HashSet<_> = apis
        .iter()
        .filter_map(|api| match &api.detail {
            ApiDetail::Function {
                fun: _,
                analysis:
                    FnAnalysisBody {
                        kind: FnKind::Method(self_ty_name, MethodKind::PureVirtual),
                        ..
                    },
            } => Some(self_ty_name.clone()),
            _ => None,
        })
        .collect();
    if abstract_types.is_empty() {
        return;
    }

    for api in apis.iter_mut() {
        let tyname = api.typename();
        match &mut api.detail {
            ApiDetail::Type { analysis, .. } if abstract_types.contains(&tyname) => {
                *analysis = TypeKind::Abstract;
            }
            _ => {}
        }
    }

    // We also need to remove any constructors belonging to these
    // abstract types.
    apis.retain(|api| {
        !matches!(&api.detail,
        ApiDetail::Function {
            fun: _,
            analysis:
                FnAnalysisBody {
                    kind: FnKind::Method(self_ty, MethodKind::Constructor),
                    ..
                },
        } if abstract_types.contains(&self_ty))
    })
}
<|endoftext|>


<commit_before>use getopts::{getopts,optflag,optopt};
use std;
use std::io::{println,print};
use common;
use time;

static WEEK_HEADER : &'static str = "Su Mo Tu We Th Fr Sa";
static MONTH_NAMES : [&'static str, ..13] = ["", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
static CUMULATIVE_DAYS : [int, ..14] = [0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];

pub fn main(args: &[~str]) {
    let opts = ~[
        optopt("m", "", "Display the specified month.", "month"),
        optflag("y", "", "Display a calendar for the specified year."),
    ];
    let usage = "cal [-y] [-m month] [[month] year]";
    let matches = match getopts(args.tail(), opts) {
        Err(f) => {
            common::err_write_line(f.to_err_msg());
            common::print_usage(usage, opts);
            std::os::set_exit_status(1);
            return;
        }
        Ok(m) => { m }
    };

    let (mut month_specified, mut month, year) = match matches.free.as_slice() {
        [ref m, ref y] => {
            let month = match convert_month(*m) {
                Some(m) => m,
                None => {
                    std::os::set_exit_status(1);
                    return;
                }
            };
            let year = match convert_year(*y) {
                Some(y) => y,
                None => {
                    std::os::set_exit_status(1);
                    return;
                }
            };
            (true, month, year)
        }
        [ref y] => {
            let year = match convert_year(*y) {
                Some(y) => y,
                None => {
                    std::os::set_exit_status(1);
                    return;
                }
            };
            (false, 1, year)
        }
        [] => {
            //current month, current year
            let tm = time::now();
            (true, (tm.tm_mon + 1) as int, (tm.tm_year + 1900) as int)
        }
        _ => {
            //show error
            common::print_usage(usage, opts);
            std::os::set_exit_status(1);
            return;
        }
    };

    if !month_specified && matches.opt_present("m") {
        month_specified = true;
        month = match convert_month(matches.opt_str("m").unwrap()) {
            Some(m) => m,
            None => {
                std::os::set_exit_status(1);
                return;
            }
        };
    }

    if month_specified {
        let month_grid = build_month(month, year, true);
        for i in month_grid.iter() {
            println(*i);
        }
    } else {
        println(build_year_title(year));
        println("");
        for i in range(0, 4) {
            let mut months = ~[];
            for j in range(1, 4) {
                let m = i*3 + j;
                months.push(build_month(m, year, false));
            }
            // print three months
            let row_len = WEEK_HEADER.len();
            for i in range(0, months[0].len()) {
                print(months[0][i]);
                print(" ".repeat(row_len - months[0][i].len() + 2));
                print(months[1][i]);
                print(" ".repeat(row_len - months[1][i].len() + 2));
                println(months[2][i]);
            }
        }
    }
}

fn convert_month(m: &str) -> Option<int> {
    match from_str::<int>(m) {
        Some(m) if m >= 1 && m <= 12 => Some(m),
        _ => {
            common::err_write_line(format!("cal: {:s} is neither a month number (1..12) nor a name", m));
            None
        }
    }
}

fn convert_year(y: &str) -> Option<int> {
    match from_str::<int>(y) {
        Some(y) if y >= 1 && y <= 9999 => Some(y),
        _ => {
            common::err_write_line(format!("cal: year {:s} not in range 1..9999", y));
            None
        }
    }
}

fn number_of_days_in_month(month: int, year: int) -> int {
    match month {
        1|3|5|7|8|10|12 => 31,
        2 if year%400 == 0 || (year%4 == 0 && year%100 != 0) => 29,
        2 => 28,
        _ => 30
    }
}

fn day_of_week(d: int, m: int, y: int) -> int {
    // number of days since year 1
    // gregorian calendar expected
    let days = (y-1) * 365 // all days for previous years
             + (y-1)/4 // plus leap days
             - (y-1)/100 // it is not a leap year if year is divisible by 100
             + (y-1)/400 // but it is a leap year if year is divisible by 400
             + CUMULATIVE_DAYS[m] // cumulative days for a given month
             + if (y%400 == 0 || (y%4 == 0 && y%100 != 0)) && m >= 2 {1} else {0} // adjustment for leap year
             + d;

    return days%7;
}

fn build_title(month: int, year: int) -> ~str {
    let title = if year > 0 {
        format!("{:s} {:d}", MONTH_NAMES[month], year)
    } else {
        format!("{:s}", MONTH_NAMES[month])
    };
    let prepend_len = (WEEK_HEADER.len() - title.len())/2;
    return " ".repeat(prepend_len) + title;
}

fn build_year_title(year: int) -> ~str {
    let title = format!("{:d}", year);
    let prepend_len = (WEEK_HEADER.len()*3 + 4 - title.len())/2;
    return " ".repeat(prepend_len) + title;
}

fn build_month(month: int, year: int, year_in_title: bool) -> ~[~str] {
    let first_day = day_of_week(1, month, year);
    let day_num = number_of_days_in_month(month, year);

    let mut out = ~[];

    out.push(build_title(month, if year_in_title { year } else { 0 }));
    out.push(WEEK_HEADER.to_owned());

    let mut s = ~"";
    let mut count = 0;
    for i in range(-first_day + 1, day_num+1) {
        if i <= 0 {
            s.push_str("  ");
        } else {
            s.push_str(format!("{:>2d}", i));
        }
        count += 1;
        if count%7 == 0 {
            out.push(s);
            s = ~"";
        } else if i != day_num {
            s.push_char(' ');
        }
    }
    out.push(s);
    while out.len() < 8 {
        out.push(~"");
    }
    return out;
}
<commit_msg>Fix bug in cal, wrong output for february of leap year<commit_after>use getopts::{getopts,optflag,optopt};
use std;
use std::io::{println,print};
use common;
use time;

static WEEK_HEADER : &'static str = "Su Mo Tu We Th Fr Sa";
static MONTH_NAMES : [&'static str, ..13] = ["", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
static CUMULATIVE_DAYS : [int, ..14] = [0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];

pub fn main(args: &[~str]) {
    let opts = ~[
        optopt("m", "", "Display the specified month.", "month"),
        optflag("y", "", "Display a calendar for the specified year."),
    ];
    let usage = "cal [-y] [-m month] [[month] year]";
    let matches = match getopts(args.tail(), opts) {
        Err(f) => {
            common::err_write_line(f.to_err_msg());
            common::print_usage(usage, opts);
            std::os::set_exit_status(1);
            return;
        }
        Ok(m) => { m }
    };

    let (mut month_specified, mut month, year) = match matches.free.as_slice() {
        [ref m, ref y] => {
            let month = match convert_month(*m) {
                Some(m) => m,
                None => {
                    std::os::set_exit_status(1);
                    return;
                }
            };
            let year = match convert_year(*y) {
                Some(y) => y,
                None => {
                    std::os::set_exit_status(1);
                    return;
                }
            };
            (true, month, year)
        }
        [ref y] => {
            let year = match convert_year(*y) {
                Some(y) => y,
                None => {
                    std::os::set_exit_status(1);
                    return;
                }
            };
            (false, 1, year)
        }
        [] => {
            //current month, current year
            let tm = time::now();
            (true, (tm.tm_mon + 1) as int, (tm.tm_year + 1900) as int)
        }
        _ => {
            //show error
            common::print_usage(usage, opts);
            std::os::set_exit_status(1);
            return;
        }
    };

    if !month_specified && matches.opt_present("m") {
        month_specified = true;
        month = match convert_month(matches.opt_str("m").unwrap()) {
            Some(m) => m,
            None => {
                std::os::set_exit_status(1);
                return;
            }
        };
    }

    if month_specified {
        let month_grid = build_month(month, year, true);
        for i in month_grid.iter() {
            println(*i);
        }
    } else {
        println(build_year_title(year));
        println("");
        for i in range(0, 4) {
            let mut months = ~[];
            for j in range(1, 4) {
                let m = i*3 + j;
                months.push(build_month(m, year, false));
            }
            // print three months
            let row_len = WEEK_HEADER.len();
            for i in range(0, months[0].len()) {
                print(months[0][i]);
                print(" ".repeat(row_len - months[0][i].len() + 2));
                print(months[1][i]);
                print(" ".repeat(row_len - months[1][i].len() + 2));
                println(months[2][i]);
            }
        }
    }
}

fn convert_month(m: &str) -> Option<int> {
    match from_str::<int>(m) {
        Some(m) if m >= 1 && m <= 12 => Some(m),
        _ => {
            common::err_write_line(format!("cal: {:s} is neither a month number (1..12) nor a name", m));
            None
        }
    }
}

fn convert_year(y: &str) -> Option<int> {
    match from_str::<int>(y) {
        Some(y) if y >= 1 && y <= 9999 => Some(y),
        _ => {
            common::err_write_line(format!("cal: year {:s} not in range 1..9999", y));
            None
        }
    }
}

fn number_of_days_in_month(month: int, year: int) -> int {
    match month {
        1|3|5|7|8|10|12 => 31,
        2 if year%400 == 0 || (year%4 == 0 && year%100 != 0) => 29,
        2 => 28,
        _ => 30
    }
}

fn day_of_week(d: int, m: int, y: int) -> int {
    // number of days since year 1
    // gregorian calendar expected
    let days = (y-1) * 365 // all days for previous years
             + (y-1)/4 // plus leap days
             - (y-1)/100 // it is not a leap year if year is divisible by 100
             + (y-1)/400 // but it is a leap year if year is divisible by 400
             + CUMULATIVE_DAYS[m] // cumulative days for a given month
             + if (y%400 == 0 || (y%4 == 0 && y%100 != 0)) && m > 2 {1} else {0} // adjustment for leap year
             + d;

    return days%7;
}

fn build_title(month: int, year: int) -> ~str {
    let title = if year > 0 {
        format!("{:s} {:d}", MONTH_NAMES[month], year)
    } else {
        format!("{:s}", MONTH_NAMES[month])
    };
    let prepend_len = (WEEK_HEADER.len() - title.len())/2;
    return " ".repeat(prepend_len) + title;
}

fn build_year_title(year: int) -> ~str {
    let title = format!("{:d}", year);
    let prepend_len = (WEEK_HEADER.len()*3 + 4 - title.len())/2;
    return " ".repeat(prepend_len) + title;
}

fn build_month(month: int, year: int, year_in_title: bool) -> ~[~str] {
    let first_day = day_of_week(1, month, year);
    let day_num = number_of_days_in_month(month, year);

    let mut out = ~[];

    out.push(build_title(month, if year_in_title { year } else { 0 }));
    out.push(WEEK_HEADER.to_owned());

    let mut s = ~"";
    let mut count = 0;
    for i in range(-first_day + 1, day_num+1) {
        if i <= 0 {
            s.push_str("  ");
        } else {
            s.push_str(format!("{:>2d}", i));
        }
        count += 1;
        if count%7 == 0 {
            out.push(s);
            s = ~"";
        } else if i != day_num {
            s.push_char(' ');
        }
    }
    out.push(s);
    while out.len() < 8 {
        out.push(~"");
    }
    return out;
}
<|endoftext|>


<commit_before>use std::sync::{Arc, RwLock};
use std::option::Option;
use std::clone::Clone;

use uuid::Uuid;

type OptInt32 = Option<i32>;
type OptInt64 = Option<i64>;
type OptString = Option<String>;

#[derive(Clone)]
pub enum CellType {
    Int32 (OptInt32),
    Int64 (OptInt64),
    Text  (OptString)
}

pub struct CellFormat {
    pub name: String,
    pub type_: CellType
}

pub struct RecFormat {
    pub cols: Vec<CellFormat>
}

pub fn construct_recformat(fields: Vec<CellFormat>) -> Arc<RwLock<RecFormat>> {
    Arc::new(RwLock::new(RecFormat{cols: fields}));
}

pub struct Rec {
    pub guid: Uuid,
    pub cells: Vec<CellType>,
    pub format: Arc<RwLock<RecFormat>>
}

pub fn construct_rec(format: Arc<RwLock<RecFormat>>) -> Rec {
    let cells = format.read().unwrap().cols.iter().map(|x| x.type_.clone()).collect::<Vec<CellType>>();
    return Rec{guid: Uuid::new_v4(),
        cells: cells,
        format: format}
}

pub struct Table {
    pub name: String,
    pub rows: Vec<Rec>,
    pub format: Arc<RwLock<RecFormat>>
}
<commit_msg>Miss return<commit_after>use std::sync::{Arc, RwLock};
use std::option::Option;
use std::clone::Clone;

use uuid::Uuid;

type OptInt32 = Option<i32>;
type OptInt64 = Option<i64>;
type OptString = Option<String>;

#[derive(Clone)]
pub enum CellType {
    Int32 (OptInt32),
    Int64 (OptInt64),
    Text  (OptString)
}

pub struct CellFormat {
    pub name: String,
    pub type_: CellType
}

pub struct RecFormat {
    pub cols: Vec<CellFormat>
}

pub fn construct_recformat(fields: Vec<CellFormat>) -> Arc<RwLock<RecFormat>> {
    return Arc::new(RwLock::new(RecFormat{cols: fields}));
}

pub struct Rec {
    pub guid: Uuid,
    pub cells: Vec<CellType>,
    pub format: Arc<RwLock<RecFormat>>
}

pub fn construct_rec(format: Arc<RwLock<RecFormat>>) -> Rec {
    let cells = format.read().unwrap().cols.iter().map(|x| x.type_.clone()).collect::<Vec<CellType>>();
    return Rec{guid: Uuid::new_v4(),
        cells: cells,
        format: format}
}

pub struct Table {
    pub name: String,
    pub rows: Vec<Rec>,
    pub format: Arc<RwLock<RecFormat>>
}
<|endoftext|>


<commit_before>use std::sync::{Arc, RwLock};
use std::option::Option;

use uuid::Uuid;

type OptInt32 = Option<i32>;
type OptInt64 = Option<i64>;
type OptString = Option<String>;

pub enum CellType {
    Int32 (OptInt32),
    Int64 (OptInt64),
    Text  (OptString)
}

trait Metainf {
    fn name(&self) -> String;
}

impl Metainf for CellType {
    fn name(&self) -> String {
        return match *self {
            CellType::Int32(_) => "INT32".to_string(),
            CellType::Int64(_) => "INT64".to_string(),
            CellType::Text(_) => "TEXT".to_string()
        }
    }
}

pub struct CellFormat {
    name: String,
    type_: CellType
}

pub struct RecFormat {
    cols: Vec<CellFormat>
}

trait Metaformat<T> {
    fn construct(format_: CellFormat) -> T;
}

pub struct Cell {
    value: CellType
}

impl Metaformat<Cell> for Cell {
    fn construct(format_: CellFormat) -> Cell {
        return match format_.type_ {
            CellType::Int32(_) => Cell { value: CellType::Int32(None) },
            CellType::Int64(_) => Cell { value: CellType::Int64(None) },
            CellType::Text(_) => Cell { value: CellType::Text(None) }
        }
    }
}

trait Container<T> {
    fn size(&self) -> usize;
    fn push(&mut self, item: T);
    //fn remove
}

pub struct Rec {
    pub guid: Uuid,
    pub cells: Vec<Cell>,
    pub format: Arc<RwLock<RecFormat>>
}

pub fn construct_rec(format: Arc<RwLock<RecFormat>>) -> Rec {
    let cells = format.read().unwrap().iter().map(|x| x.type_).collect::<Vec<CellType>>();
    return Rec{guid: Uuid::new_v4(),
        cells: cells,
        format: format}
}

impl Container<Cell> for Rec {

    fn size(&self) -> usize {
        return self.cells.len();
    }

    fn push(&mut self, item: Cell) {
        self.cells.push(item);
    }
}

pub struct Table {
    pub name: String,
    pub rows: Vec<Rec>,
    pub format: Arc<RwLock<RecFormat>>
}

impl Container<Rec> for Table {
    fn size(&self) -> usize {
        return self.rows.len();
    }

    fn push(&mut self, item: Rec) {
        self.rows.push(item);
    }
}
<commit_msg>Forgot cols<commit_after>use std::sync::{Arc, RwLock};
use std::option::Option;

use uuid::Uuid;

type OptInt32 = Option<i32>;
type OptInt64 = Option<i64>;
type OptString = Option<String>;

pub enum CellType {
    Int32 (OptInt32),
    Int64 (OptInt64),
    Text  (OptString)
}

trait Metainf {
    fn name(&self) -> String;
}

impl Metainf for CellType {
    fn name(&self) -> String {
        return match *self {
            CellType::Int32(_) => "INT32".to_string(),
            CellType::Int64(_) => "INT64".to_string(),
            CellType::Text(_) => "TEXT".to_string()
        }
    }
}

pub struct CellFormat {
    name: String,
    type_: CellType
}

pub struct RecFormat {
    cols: Vec<CellFormat>
}

trait Metaformat<T> {
    fn construct(format_: CellFormat) -> T;
}

pub struct Cell {
    value: CellType
}

impl Metaformat<Cell> for Cell {
    fn construct(format_: CellFormat) -> Cell {
        return match format_.type_ {
            CellType::Int32(_) => Cell { value: CellType::Int32(None) },
            CellType::Int64(_) => Cell { value: CellType::Int64(None) },
            CellType::Text(_) => Cell { value: CellType::Text(None) }
        }
    }
}

trait Container<T> {
    fn size(&self) -> usize;
    fn push(&mut self, item: T);
    //fn remove
}

pub struct Rec {
    pub guid: Uuid,
    pub cells: Vec<Cell>,
    pub format: Arc<RwLock<RecFormat>>
}

pub fn construct_rec(format: Arc<RwLock<RecFormat>>) -> Rec {
    let cells = format.read().unwrap().cols.iter().map(|x| x.type_).collect::<Vec<CellType>>();
    return Rec{guid: Uuid::new_v4(),
        cells: cells,
        format: format}
}

impl Container<Cell> for Rec {

    fn size(&self) -> usize {
        return self.cells.len();
    }

    fn push(&mut self, item: Cell) {
        self.cells.push(item);
    }
}

pub struct Table {
    pub name: String,
    pub rows: Vec<Rec>,
    pub format: Arc<RwLock<RecFormat>>
}

impl Container<Rec> for Table {
    fn size(&self) -> usize {
        return self.rows.len();
    }

    fn push(&mut self, item: Rec) {
        self.rows.push(item);
    }
}
<|endoftext|>