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

use crate::{HealthCheckError, Node, NodeExt, Validator};
use anyhow::{anyhow, Context, Result};
use diem_config::config::NodeConfig;
use diem_logger::{debug, warn};
use diem_sdk::types::{account_address::AccountAddress, PeerId};
use std::{
    env,
    fs::{self, OpenOptions},
    path::{Path, PathBuf},
    process::{Child, Command},
    str::FromStr,
};
use url::Url;

#[derive(Debug)]
struct Process(Child);

impl Drop for Process {
    // When the Process struct goes out of scope we need to kill the child process
    fn drop(&mut self) {
        // check if the process has already been terminated
        match self.0.try_wait() {
            // The child process has already terminated, perhaps due to a crash
            Ok(Some(_)) => {}

            // The process is still running so we need to attempt to kill it
            _ => {
                self.0.kill().expect("Process wasn't running");
                self.0.wait().unwrap();
            }
        }
    }
}

#[derive(Debug)]
pub struct LocalNode {
    process: Option<Process>,
    name: String,
    peer_id: AccountAddress,
    directory: PathBuf,
    config: NodeConfig,
    diem_node_bin_path: PathBuf,
}

impl LocalNode {
    pub fn new(diem_node_bin_path: &Path, name: String, directory: PathBuf) -> Result<Self> {
        let config_path = directory.join("node.yaml");
        let config = NodeConfig::load(&config_path)
            .with_context(|| format!("Failed to load NodeConfig from file: {:?}", config_path))?;
        let peer_id = config
            .peer_id()
            .ok_or_else(|| anyhow!("unable to retrieve PeerId from config"))?;

        Ok(Self {
            process: None,
            name,
            peer_id,
            directory,
            config,
            diem_node_bin_path: PathBuf::from(diem_node_bin_path),
        })
    }

    pub fn config_path(&self) -> PathBuf {
        self.directory.join("node.yaml")
    }

    pub fn log_path(&self) -> PathBuf {
        self.directory.join("log")
    }

    pub fn peer_id(&self) -> PeerId {
        self.peer_id
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn start(&mut self) -> Result<()> {
        // Ensure log file exists
        let log_file = OpenOptions::new()
            .create(true)
            .write(true)
            .open(self.log_path())?;

        // Start node process
        let mut node_command = Command::new(self.diem_node_bin_path.as_path());
        node_command
            .current_dir(&self.directory)
            .arg("-f")
            .arg(self.config_path());
        if env::var("RUST_LOG").is_err() {
            // Only set our RUST_LOG if its not present in environment
            node_command.env("RUST_LOG", "debug");
        }
        node_command.stdout(log_file.try_clone()?).stderr(log_file);
        let process = node_command.spawn().with_context(|| {
            format!(
                "Error launching node process with binary: {:?}",
                self.diem_node_bin_path.as_path()
            )
        })?;

        self.process = Some(Process(process));

        Ok(())
    }

    pub fn stop(&mut self) {
        self.process = None;
    }

    pub fn port(&self) -> u16 {
        self.config.json_rpc.address.port()
    }

    pub fn debug_port(&self) -> u16 {
        self.config
            .debug_interface
            .admission_control_node_debug_port
    }

    pub fn config(&self) -> &NodeConfig {
        &self.config
    }

    pub fn get_log_contents(&self) -> Result<String> {
        fs::read_to_string(self.log_path()).map_err(Into::into)
    }

    pub fn health_check(&mut self) -> Result<(), HealthCheckError> {
        debug!("Health check on node '{}'", self.name);

        if let Some(p) = &mut self.process {
            match p.0.try_wait() {
                // This would mean the child process has crashed
                Ok(Some(status)) => {
                    debug!("Node '{}' crashed with: {}", self.name, status);
                    return Err(HealthCheckError::NotRunning);
                }

                // This is the case where the node is still running
                Ok(None) => {}

                // Some other unknown error
                Err(e) => {
                    return Err(HealthCheckError::Unknown(e.into()));
                }
            }
        } else {
            warn!("Node '{}' is stopped", self.name);
            return Err(HealthCheckError::NotRunning);
        }

        self.debug_client()
            .get_node_metrics()
            .map(|_| ())
            .map_err(HealthCheckError::RpcFailure)
    }
}

impl Node for LocalNode {
    fn peer_id(&self) -> PeerId {
        self.peer_id()
    }

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

    fn json_rpc_endpoint(&self) -> reqwest::Url {
        let ip = self.config().json_rpc.address.ip();
        let port = self.config().json_rpc.address.port();
        Url::from_str(&format!("http://{}:{}/v1", ip, port)).expect("Invalid URL.")
    }

    fn debug_endpoint(&self) -> Url {
        Url::parse(&format!("http://localhost:{}", self.debug_port())).unwrap()
    }

    fn config(&self) -> &NodeConfig {
        self.config()
    }

    fn start(&mut self) -> Result<()> {
        self.start()
    }

    fn stop(&mut self) -> Result<()> {
        self.stop();
        Ok(())
    }

    fn clear_storage(&mut self) -> Result<()> {
        todo!()
    }

    fn health_check(&mut self) -> Result<(), HealthCheckError> {
        self.health_check()
    }
}

impl Validator for LocalNode {}
<commit_msg>forge: improve LocalNode health check to include jsonrpc<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{HealthCheckError, Node, NodeExt, Validator};
use anyhow::{anyhow, Context, Result};
use diem_config::config::NodeConfig;
use diem_logger::{debug, warn};
use diem_sdk::{
    client::BlockingClient,
    types::{account_address::AccountAddress, PeerId},
};
use std::{
    env,
    fs::{self, OpenOptions},
    path::{Path, PathBuf},
    process::{Child, Command},
    str::FromStr,
};
use url::Url;

#[derive(Debug)]
struct Process(Child);

impl Drop for Process {
    // When the Process struct goes out of scope we need to kill the child process
    fn drop(&mut self) {
        // check if the process has already been terminated
        match self.0.try_wait() {
            // The child process has already terminated, perhaps due to a crash
            Ok(Some(_)) => {}

            // The process is still running so we need to attempt to kill it
            _ => {
                self.0.kill().expect("Process wasn't running");
                self.0.wait().unwrap();
            }
        }
    }
}

#[derive(Debug)]
pub struct LocalNode {
    process: Option<Process>,
    name: String,
    peer_id: AccountAddress,
    directory: PathBuf,
    config: NodeConfig,
    diem_node_bin_path: PathBuf,
}

impl LocalNode {
    pub fn new(diem_node_bin_path: &Path, name: String, directory: PathBuf) -> Result<Self> {
        let config_path = directory.join("node.yaml");
        let config = NodeConfig::load(&config_path)
            .with_context(|| format!("Failed to load NodeConfig from file: {:?}", config_path))?;
        let peer_id = config
            .peer_id()
            .ok_or_else(|| anyhow!("unable to retrieve PeerId from config"))?;

        Ok(Self {
            process: None,
            name,
            peer_id,
            directory,
            config,
            diem_node_bin_path: PathBuf::from(diem_node_bin_path),
        })
    }

    pub fn config_path(&self) -> PathBuf {
        self.directory.join("node.yaml")
    }

    pub fn log_path(&self) -> PathBuf {
        self.directory.join("log")
    }

    pub fn peer_id(&self) -> PeerId {
        self.peer_id
    }

    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn start(&mut self) -> Result<()> {
        // Ensure log file exists
        let log_file = OpenOptions::new()
            .create(true)
            .write(true)
            .open(self.log_path())?;

        // Start node process
        let mut node_command = Command::new(self.diem_node_bin_path.as_path());
        node_command
            .current_dir(&self.directory)
            .arg("-f")
            .arg(self.config_path());
        if env::var("RUST_LOG").is_err() {
            // Only set our RUST_LOG if its not present in environment
            node_command.env("RUST_LOG", "debug");
        }
        node_command.stdout(log_file.try_clone()?).stderr(log_file);
        let process = node_command.spawn().with_context(|| {
            format!(
                "Error launching node process with binary: {:?}",
                self.diem_node_bin_path.as_path()
            )
        })?;

        self.process = Some(Process(process));

        Ok(())
    }

    pub fn stop(&mut self) {
        self.process = None;
    }

    pub fn port(&self) -> u16 {
        self.config.json_rpc.address.port()
    }

    pub fn debug_port(&self) -> u16 {
        self.config
            .debug_interface
            .admission_control_node_debug_port
    }

    pub fn config(&self) -> &NodeConfig {
        &self.config
    }

    pub fn get_log_contents(&self) -> Result<String> {
        fs::read_to_string(self.log_path()).map_err(Into::into)
    }

    pub fn health_check(&mut self) -> Result<(), HealthCheckError> {
        debug!("Health check on node '{}'", self.name);

        if let Some(p) = &mut self.process {
            match p.0.try_wait() {
                // This would mean the child process has crashed
                Ok(Some(status)) => {
                    debug!("Node '{}' crashed with: {}", self.name, status);
                    return Err(HealthCheckError::NotRunning);
                }

                // This is the case where the node is still running
                Ok(None) => {}

                // Some other unknown error
                Err(e) => {
                    return Err(HealthCheckError::Unknown(e.into()));
                }
            }
        } else {
            warn!("Node '{}' is stopped", self.name);
            return Err(HealthCheckError::NotRunning);
        }

        self.debug_client()
            .get_node_metrics()
            .map(|_| ())
            .map_err(HealthCheckError::RpcFailure)?;

        BlockingClient::new(self.json_rpc_endpoint())
            .get_metadata()
            .map(|_| ())
            .map_err(|e| HealthCheckError::RpcFailure(e.into()))
    }
}

impl Node for LocalNode {
    fn peer_id(&self) -> PeerId {
        self.peer_id()
    }

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

    fn json_rpc_endpoint(&self) -> reqwest::Url {
        let ip = self.config().json_rpc.address.ip();
        let port = self.config().json_rpc.address.port();
        Url::from_str(&format!("http://{}:{}/v1", ip, port)).expect("Invalid URL.")
    }

    fn debug_endpoint(&self) -> Url {
        Url::parse(&format!("http://localhost:{}", self.debug_port())).unwrap()
    }

    fn config(&self) -> &NodeConfig {
        self.config()
    }

    fn start(&mut self) -> Result<()> {
        self.start()
    }

    fn stop(&mut self) -> Result<()> {
        self.stop();
        Ok(())
    }

    fn clear_storage(&mut self) -> Result<()> {
        todo!()
    }

    fn health_check(&mut self) -> Result<(), HealthCheckError> {
        self.health_check()
    }
}

impl Validator for LocalNode {}
<|endoftext|>


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

use crate::{
    smoke_test_environment::new_local_swarm,
    test_utils::{create_and_fund_account, transfer_and_reconfig, transfer_coins},
};
use diem_config::config::{BootstrappingMode, ContinuousSyncingMode, NodeConfig};
use diem_rest_client::Client as RestClient;
use diem_sdk::{transaction_builder::TransactionFactory, types::LocalAccount};
use forge::{LocalSwarm, NodeExt, Swarm, SwarmExt};
use std::time::{Duration, Instant};
use tokio::runtime::Runtime;

const MAX_CATCH_UP_SECS: u64 = 60; // The max time we'll wait for nodes to catch up

#[test]
fn test_full_node_bootstrap_outputs() {
    // Create a validator swarm of 1 validator node
    let swarm = new_local_swarm(1);

    // Create a fullnode config that uses transaction outputs to sync
    let mut vfn_config = NodeConfig::default_for_validator_full_node();
    vfn_config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
    vfn_config.state_sync.state_sync_driver.bootstrapping_mode =
        BootstrappingMode::ApplyTransactionOutputsFromGenesis;
    vfn_config
        .state_sync
        .state_sync_driver
        .continuous_syncing_mode = ContinuousSyncingMode::ApplyTransactionOutputs;

    // Test the ability of the fullnode to sync
    test_full_node_sync(vfn_config, swarm, true)
}

#[test]
fn test_full_node_bootstrap_transactions() {
    // Create a validator swarm of 1 validator node
    let swarm = new_local_swarm(1);

    // Create a fullnode config that uses transactions to sync
    let mut vfn_config = NodeConfig::default_for_validator_full_node();
    vfn_config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
    vfn_config.state_sync.state_sync_driver.bootstrapping_mode =
        BootstrappingMode::ExecuteTransactionsFromGenesis;
    vfn_config
        .state_sync
        .state_sync_driver
        .continuous_syncing_mode = ContinuousSyncingMode::ExecuteTransactions;

    // Test the ability of the fullnode to sync
    test_full_node_sync(vfn_config, swarm, true)
}

#[test]
fn test_full_node_continuous_sync_outputs() {
    // Create a validator swarm of 1 validator node
    let swarm = new_local_swarm(1);

    // Create a fullnode config that uses transaction outputs to sync
    let mut vfn_config = NodeConfig::default_for_validator_full_node();
    vfn_config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
    vfn_config
        .state_sync
        .state_sync_driver
        .continuous_syncing_mode = ContinuousSyncingMode::ApplyTransactionOutputs;

    // Test the ability of the fullnode to sync
    test_full_node_sync(vfn_config, swarm, false)
}

#[test]
fn test_full_node_continuous_sync_transactions() {
    // Create a validator swarm of 1 validator node
    let swarm = new_local_swarm(1);

    // Create a fullnode config that uses transactions to sync
    let mut vfn_config = NodeConfig::default_for_validator_full_node();
    vfn_config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
    vfn_config
        .state_sync
        .state_sync_driver
        .continuous_syncing_mode = ContinuousSyncingMode::ExecuteTransactions;

    // Test the ability of the fullnode to sync
    test_full_node_sync(vfn_config, swarm, false)
}

/// A helper method that tests that a full node can sync from a validator after
/// a failure and continue to stay up-to-date.
fn test_full_node_sync(full_node_config: NodeConfig, mut swarm: LocalSwarm, epoch_changes: bool) {
    // Create the fullnode
    let validator_peer_id = swarm.validators().next().unwrap().peer_id();
    let vfn_peer_id = swarm
        .add_validator_fullnode(
            &swarm.versions().max().unwrap(),
            full_node_config,
            validator_peer_id,
        )
        .unwrap();

    // Start the validator and fullnode (make sure they boot up)
    swarm
        .validator_mut(validator_peer_id)
        .unwrap()
        .wait_until_healthy(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
        .unwrap();
    for fullnode in swarm.full_nodes_mut() {
        fullnode
            .wait_until_healthy(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
            .unwrap();
    }

    // Stop the fullnode
    swarm.fullnode_mut(vfn_peer_id).unwrap().stop();

    // Execute a number of transactions on the validator
    let validator_client = swarm.validator(validator_peer_id).unwrap().rest_client();
    let transaction_factory = swarm.chain_info().transaction_factory();
    let mut account_0 = create_and_fund_account(&mut swarm, 1000);
    let mut account_1 = create_and_fund_account(&mut swarm, 1000);
    execute_transactions(
        &mut swarm,
        &validator_client,
        &transaction_factory,
        &mut account_0,
        &account_1,
        epoch_changes,
    );

    // Restart the fullnode and verify it can sync
    swarm.fullnode_mut(vfn_peer_id).unwrap().restart().unwrap();
    swarm
        .wait_for_all_nodes_to_catchup(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
        .unwrap();

    // Execute more transactions on the validator and verify the fullnode catches up
    execute_transactions(
        &mut swarm,
        &validator_client,
        &transaction_factory,
        &mut account_1,
        &account_0,
        epoch_changes,
    );
    swarm
        .wait_for_all_nodes_to_catchup(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
        .unwrap();
}

/// Executes transactions using the given transaction factory, client and
/// accounts. If `force_epoch_changes` is true, also execute transactions to
/// force reconfigurations.
fn execute_transactions(
    swarm: &mut LocalSwarm,
    client: &RestClient,
    transaction_factory: &TransactionFactory,
    sender: &mut LocalAccount,
    receiver: &LocalAccount,
    execute_epoch_changes: bool,
) {
    let runtime = Runtime::new().unwrap();
    let num_transfers = 10;
    if execute_epoch_changes {
        runtime.block_on(async {
            transfer_and_reconfig(
                client,
                transaction_factory,
                swarm.chain_info().root_account,
                sender,
                receiver,
                num_transfers,
            )
            .await;
        });
    } else {
        runtime.block_on(async {
            for _ in 0..num_transfers {
                // Execute simple transfer transactions
                transfer_coins(client, transaction_factory, sender, receiver, 1).await;
            }
        });
    }
}
<commit_msg>[State Sync] Add smoke test for validator syncing.<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    smoke_test_environment::new_local_swarm,
    test_utils::{create_and_fund_account, transfer_and_reconfig, transfer_coins},
};
use diem_config::config::{BootstrappingMode, ContinuousSyncingMode, NodeConfig};
use diem_rest_client::Client as RestClient;
use diem_sdk::{transaction_builder::TransactionFactory, types::LocalAccount};
use forge::{LocalSwarm, NodeExt, Swarm, SwarmExt};
use std::{
    fs,
    time::{Duration, Instant},
};
use tokio::runtime::Runtime;

const MAX_CATCH_UP_SECS: u64 = 60; // The max time we'll wait for nodes to catch up

#[test]
fn test_full_node_bootstrap_outputs() {
    // Create a validator swarm of 1 validator node
    let swarm = new_local_swarm(1);

    // Create a fullnode config that uses transaction outputs to sync
    let mut vfn_config = NodeConfig::default_for_validator_full_node();
    vfn_config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
    vfn_config.state_sync.state_sync_driver.bootstrapping_mode =
        BootstrappingMode::ApplyTransactionOutputsFromGenesis;
    vfn_config
        .state_sync
        .state_sync_driver
        .continuous_syncing_mode = ContinuousSyncingMode::ApplyTransactionOutputs;

    // Test the ability of the fullnode to sync
    test_full_node_sync(vfn_config, swarm, true);
}

#[test]
fn test_full_node_bootstrap_transactions() {
    // Create a validator swarm of 1 validator node
    let swarm = new_local_swarm(1);

    // Create a fullnode config that uses transactions to sync
    let mut vfn_config = NodeConfig::default_for_validator_full_node();
    vfn_config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
    vfn_config.state_sync.state_sync_driver.bootstrapping_mode =
        BootstrappingMode::ExecuteTransactionsFromGenesis;
    vfn_config
        .state_sync
        .state_sync_driver
        .continuous_syncing_mode = ContinuousSyncingMode::ExecuteTransactions;

    // Test the ability of the fullnode to sync
    test_full_node_sync(vfn_config, swarm, true);
}

#[test]
fn test_full_node_continuous_sync_outputs() {
    // Create a validator swarm of 1 validator node
    let swarm = new_local_swarm(1);

    // Create a fullnode config that uses transaction outputs to sync
    let mut vfn_config = NodeConfig::default_for_validator_full_node();
    vfn_config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
    vfn_config
        .state_sync
        .state_sync_driver
        .continuous_syncing_mode = ContinuousSyncingMode::ApplyTransactionOutputs;

    // Test the ability of the fullnode to sync
    test_full_node_sync(vfn_config, swarm, false);
}

#[test]
fn test_full_node_continuous_sync_transactions() {
    // Create a validator swarm of 1 validator node
    let swarm = new_local_swarm(1);

    // Create a fullnode config that uses transactions to sync
    let mut vfn_config = NodeConfig::default_for_validator_full_node();
    vfn_config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
    vfn_config
        .state_sync
        .state_sync_driver
        .continuous_syncing_mode = ContinuousSyncingMode::ExecuteTransactions;

    // Test the ability of the fullnode to sync
    test_full_node_sync(vfn_config, swarm, false);
}

/// A helper method that tests that a full node can sync from a validator after
/// a failure and continue to stay up-to-date.
fn test_full_node_sync(full_node_config: NodeConfig, mut swarm: LocalSwarm, epoch_changes: bool) {
    // Create the fullnode
    let validator_peer_id = swarm.validators().next().unwrap().peer_id();
    let vfn_peer_id = swarm
        .add_validator_fullnode(
            &swarm.versions().max().unwrap(),
            full_node_config,
            validator_peer_id,
        )
        .unwrap();

    // Start the validator and fullnode (make sure they boot up)
    swarm
        .validator_mut(validator_peer_id)
        .unwrap()
        .wait_until_healthy(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
        .unwrap();
    for fullnode in swarm.full_nodes_mut() {
        fullnode
            .wait_until_healthy(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
            .unwrap();
    }

    // Stop the fullnode
    swarm.fullnode_mut(vfn_peer_id).unwrap().stop();

    // Execute a number of transactions on the validator
    let validator_client = swarm.validator(validator_peer_id).unwrap().rest_client();
    let transaction_factory = swarm.chain_info().transaction_factory();
    let mut account_0 = create_and_fund_account(&mut swarm, 1000);
    let mut account_1 = create_and_fund_account(&mut swarm, 1000);
    execute_transactions(
        &mut swarm,
        &validator_client,
        &transaction_factory,
        &mut account_0,
        &account_1,
        epoch_changes,
    );

    // Restart the fullnode and verify it can sync
    swarm.fullnode_mut(vfn_peer_id).unwrap().restart().unwrap();
    swarm
        .wait_for_all_nodes_to_catchup(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
        .unwrap();

    // Execute more transactions on the validator and verify the fullnode catches up
    execute_transactions(
        &mut swarm,
        &validator_client,
        &transaction_factory,
        &mut account_1,
        &account_0,
        epoch_changes,
    );
    swarm
        .wait_for_all_nodes_to_catchup(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
        .unwrap();
}

#[test]
fn test_validator_bootstrap_outputs() {
    // Create a swarm of 4 validators with state sync v2 enabled (output syncing)
    let mut swarm = new_local_swarm(4);
    for validator in swarm.validators_mut() {
        let mut config = validator.config().clone();
        config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
        config.state_sync.state_sync_driver.bootstrapping_mode =
            BootstrappingMode::ApplyTransactionOutputsFromGenesis;
        config.state_sync.state_sync_driver.continuous_syncing_mode =
            ContinuousSyncingMode::ApplyTransactionOutputs;
        config.save(validator.config_path()).unwrap();
        validator.restart().unwrap();
    }

    // Test the ability of the validators to sync
    test_validator_sync(swarm);
}

#[test]
fn test_validator_bootstrap_transactions() {
    // Create a swarm of 4 validators with state sync v2 enabled (transaction syncing)
    let mut swarm = new_local_swarm(4);
    for validator in swarm.validators_mut() {
        let mut config = validator.config().clone();
        config.state_sync.state_sync_driver.enable_state_sync_v2 = true;
        config.state_sync.state_sync_driver.bootstrapping_mode =
            BootstrappingMode::ExecuteTransactionsFromGenesis;
        config.state_sync.state_sync_driver.continuous_syncing_mode =
            ContinuousSyncingMode::ExecuteTransactions;
        config.save(validator.config_path()).unwrap();
        validator.restart().unwrap();
    }

    // Test the ability of the validators to sync
    test_validator_sync(swarm);
}

/// A helper method that tests that a validator can sync after a failure and
/// continue to stay up-to-date.
fn test_validator_sync(mut swarm: LocalSwarm) {
    // Launch the swarm and wait for it to be ready
    swarm.launch().unwrap();

    // Execute multiple transactions through validator 0
    let validator_peer_ids = swarm.validators().map(|v| v.peer_id()).collect::<Vec<_>>();
    let validator_client_0 = swarm
        .validator(validator_peer_ids[0])
        .unwrap()
        .rest_client();
    let transaction_factory = swarm.chain_info().transaction_factory();
    let mut account_0 = create_and_fund_account(&mut swarm, 1000);
    let mut account_1 = create_and_fund_account(&mut swarm, 1000);
    execute_transactions(
        &mut swarm,
        &validator_client_0,
        &transaction_factory,
        &mut account_0,
        &account_1,
        true,
    );
    swarm
        .wait_for_all_nodes_to_catchup(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
        .unwrap();

    // Stop validator 1 and delete the storage
    let validator_1 = validator_peer_ids[1];
    swarm.validator_mut(validator_1).unwrap().stop();
    let node_config = swarm.validator_mut(validator_1).unwrap().config().clone();
    let state_db_path = node_config.storage.dir().join("diemdb");
    assert!(state_db_path.as_path().exists());
    fs::remove_dir_all(state_db_path).unwrap();

    // Execute more transactions
    execute_transactions(
        &mut swarm,
        &validator_client_0,
        &transaction_factory,
        &mut account_1,
        &account_0,
        true,
    );

    // Restart validator 1 and wait for all nodes to catchup
    swarm.validator_mut(validator_1).unwrap().start().unwrap();
    swarm
        .wait_for_all_nodes_to_catchup(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
        .unwrap();

    // Execute multiple transactions and verify validator 1 can sync
    execute_transactions(
        &mut swarm,
        &validator_client_0,
        &transaction_factory,
        &mut account_0,
        &account_1,
        true,
    );
    swarm
        .wait_for_all_nodes_to_catchup(Instant::now() + Duration::from_secs(MAX_CATCH_UP_SECS))
        .unwrap();
}

/// Executes transactions using the given transaction factory, client and
/// accounts. If `force_epoch_changes` is true, also execute transactions to
/// force reconfigurations.
fn execute_transactions(
    swarm: &mut LocalSwarm,
    client: &RestClient,
    transaction_factory: &TransactionFactory,
    sender: &mut LocalAccount,
    receiver: &LocalAccount,
    execute_epoch_changes: bool,
) {
    let runtime = Runtime::new().unwrap();
    let num_transfers = 10;
    if execute_epoch_changes {
        runtime.block_on(async {
            transfer_and_reconfig(
                client,
                transaction_factory,
                swarm.chain_info().root_account,
                sender,
                receiver,
                num_transfers,
            )
            .await;
        });
    } else {
        runtime.block_on(async {
            for _ in 0..num_transfers {
                // Execute simple transfer transactions
                transfer_coins(client, transaction_factory, sender, receiver, 1).await;
            }
        });
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::hash;
use std::thunk::Invoke;

use name::*;
// pub use lazy::single::Thunk;

pub type UAr<'x,S,T> = Box<Fn<S,T> + 'x>;
// arrow-typed value (in CBPV speak),
// with explicit lifetime 'x, input tuple S, and return value of type T.
//
// Read in CBPV notation has "U(S -> T) with lifetime 'x".
//
// In rust, can be introduced by:
//   box () (move |&: args:S |{ $body }))
//
// Invoke:
//   box () (move |:  args:S |{ $body }))

pub type UF<'x,T> = Box<Invoke<(),T> + 'x>;
// value-producing value (in CBPV speak).
// with explicit lifetime 'x and return value of type T.
//
// Read in CBPV notation has "U(F(T)) with lifetime 'x".
//
// In Rust, can be introduced by:
//   box () (move |: () |{ $body }))

/// rustc says that I need an explicit lifetime parameter; I name it `'x`.
struct ArtThunk<'x,T> {
    // TODO: Memo table identity, for comparing thunks with same names
    // TODO: Access to args, for equality check, hashing
    thunk : UF<'x,T>,
    value : Option<T>
}

impl<'x,T> fmt::Show for ArtThunk<'x,T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(ArtThunk)")
    }
}

#[deriving(Show)]
struct ArtCon<'x,T> {
    name : Name,
    thunk : ArtThunk<'x,T>
}

impl<'x,T> PartialEq for ArtCon<'x,T> {
    fn eq(&self, other: &ArtCon<T>) -> bool {
        self.name.eq( &other.name )
    }
    fn ne(&self, other: &ArtCon<T>) -> bool {
        !(self.eq(other))
    }
}

impl<'x,T> Eq for ArtCon<'x,T> {
    fn assert_receiver_is_total_eq(&self) {  }
}

impl<'x,S: hash::Writer, T> hash::Hash<S> for ArtCon<'x,T> {
    fn hash(&self, state: &mut S) {
        self.name.hash( state )
    }
}

pub type Art<'x,T> = ArtCon<'x,T>;

// Create a named cell
pub fn cell<'x,T:'x> (n:Name, x:T) -> Art<'x,T> {
    //! TODO: Cache the art based on the name n
    ArtCon { name  : n,
             thunk : ArtThunk{
                 value:None,
                 thunk:box () (move|:()|{
                     x
                 } ) as Box<Invoke()->T>
             }
    }
}

// Create a named cell
pub fn nart<'x,T:'x> (n:Name, body:Box<Invoke()->T+'x>) -> Art<'x,T> {
    //! TODO: Cache the art based on the name n
    ArtCon { name  : n,
             thunk : ArtThunk{
                 value:None,
                 thunk:body
             }
    }
}

#[macro_export]
macro_rules! nart (
    ($name:expr, $body:expr) => {
        nart($name,
             box () (move|:()|{ $body }))
    }
);

// pub fn force<'x,T> (art:Art<'x,T>) -> T {
//     match art {
//         ArtCon {name:_,thunk:t} => t ()
//     }
// }

pub fn force<'x,T> (art:Art<'x,T>) -> T {
    panic!("Oh no something bad has happened!")
}
<commit_msg>compilation issue; i'm confused<commit_after>use std::fmt;
use std::hash;
use std::thunk::Invoke;

use name::*;
// pub use lazy::single::Thunk;

pub type UAr<'x,S,T> = Box<Fn<S,T> + 'x>;
// arrow-typed value (in CBPV speak),
// with explicit lifetime 'x, input tuple S, and return value of type T.
//
// Read in CBPV notation has "U(S -> T) with lifetime 'x".
//
// In rust, can be introduced by:
//   box () (move |&: args:S |{ $body }))

pub type UF<'x,T> = Box<Invoke<(),T> + 'x>;
// value-producing value (in CBPV speak).
// with explicit lifetime 'x and return value of type T.
//
// Read in CBPV notation has "U(F(T)) with lifetime 'x".
//
// In Rust, can be introduced by:
//   box () (move |: () |{ $body }))

/// rustc says that I need an explicit lifetime parameter; I name it `'x`.
struct ArtThunk<'x,T> {
    // TODO: Memo table identity, for comparing thunks with same names
    // TODO: Access to args, for equality check, hashing
    thunk : UF<'x,T>,
    value : Option<T>
}

impl<'x,T> fmt::Show for ArtThunk<'x,T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "(ArtThunk)")
    }
}

#[deriving(Show)]
struct ArtCon<'x,T> {
    name : Name,
    thunk : ArtThunk<'x,T>
}

impl<'x,T> PartialEq for ArtCon<'x,T> {
    fn eq(&self, other: &ArtCon<T>) -> bool {
        self.name.eq( &other.name )
    }
    fn ne(&self, other: &ArtCon<T>) -> bool {
        !(self.eq(other))
    }
}

impl<'x,T> Eq for ArtCon<'x,T> {
    fn assert_receiver_is_total_eq(&self) {  }
}

impl<'x,S: hash::Writer, T> hash::Hash<S> for ArtCon<'x,T> {
    fn hash(&self, state: &mut S) {
        self.name.hash( state )
    }
}

pub type Art<'x,T> = ArtCon<'x,T>;

// Create a named cell
pub fn cell<'x,T:'x> (n:Name, x:T) -> Art<'x,T> {
    //! TODO: Cache the art based on the name n
    ArtCon { name  : n,
             thunk : ArtThunk{
                 value:None,
                 thunk:box () (move|:()|{
                     x
                 } ) as Box<Invoke()->T>
             }
    }
}

// Create a named thunk
pub fn nart<'x,T:'x> (n:Name, body:Box<Invoke()->T+'x>) -> Art<'x,T> {
    //! TODO: Cache the art based on the name n
    ArtCon { name  : n,
             thunk : ArtThunk{
                 value:None,
                 thunk:body
             }
    }
}

#[macro_export]
macro_rules! nart (
    ($name:expr, $body:expr) => {
        nart($name,
             box () (move|:()|{ $body }))
    }
);

// pub fn force<'x,T> (art:Art<'x,T>) -> T {
//     match art {
//         ArtCon {name:_,thunk:t} => {
//             let result = (*t.thunk).invoke(()) ;
//             result
//         }
//     }
// }

pub fn force<'x,T> (art:Art<'x,T>) -> T {
   panic!("Oh no something bad has happened!")
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::{thread, time};
use std::cell::{RefCell, RefMut};

use reqwest::{Response};

use errors::Error;
use client::MatrixClient;
use matrix_types::Event;

#[derive(Clone)]
pub struct RoomEvent<'a> {
    pub room_id: &'a str,
    pub raw_event: Event,
}

pub struct Bot <'a, 'b> {
    client: RefCell<&'b mut MatrixClient>,
    root_services: Vec<&'a str>,
    all_services: HashMap<&'a str, RefCell<Box<Node<'a>>>>,

    rooms: RefCell<Vec<String>>,
}

impl<'a, 'b> Bot<'a, 'b> {
    pub fn new(client: &'b mut MatrixClient) -> Self{
        Bot {
            client: RefCell::new(client),
            root_services: Vec::new(),
            all_services: HashMap::new(),
            rooms: RefCell::new(Vec::new()),
        }
    }

    pub fn join(&self, room_id: &str) -> Result<Response, Error>{
        // Make sure that the bot isn't already in the room to be joined
        for room in self.rooms.borrow().iter() {
            if room_id == room {
                return Err("Already in room".into());
            }
        }

        self.rooms.borrow_mut().push(room_id.clone().to_string());

        self.client.borrow().join(room_id)
    }

    pub fn join_public(&self, room_id: &str) -> Result<Response, Error>{
        let pub_room = self.client.borrow().get_public_room_id(room_id);

        match pub_room {
            Some(id) => self.join(&id),
            None => Err("Could not join invalid room.".into()),
        }
    }

    pub fn say(&self, room_id: &str, message: &str) -> Result<Response, Error> {
        self.client.borrow_mut().send_msg(room_id, message)
    }

    pub fn reply(&self, event: &RoomEvent, message: &str) -> Result<Response, Error> {
        self.say(event.room_id, message)
    }

    pub fn kick(&self, room_id: &str, user_id: &str, reason: Option<&str>) {
        self.client.borrow().kick(room_id, user_id, reason);
    }

    /*
    pub fn action(&self, room_id: &str, action: &str) {
    }

    pub fn set_name(&self, name: &str) {
    }
    */

    pub fn register_service(&mut self,
                            name: &'a str,
                            parent: Option<&'a str>,
                            mut service: Box<Node<'a>>) -> Option<&'a str> {
        match parent {
            Some(p) => {
                self.all_services.get_mut(p).expect("Invalid parent node")
                    .borrow_mut().register_child(name)
            },
            None => self.root_services.push(name),
        };

        service.on_load();

        self.all_services.insert(name, RefCell::new(service));

        Some(name)
    }

    pub fn get_service(&self, name: &str) -> RefMut<Box<Node<'a>>> {
        self.all_services.get(name).unwrap().borrow_mut()
    }

    pub fn propagate_event(&self, event: &RoomEvent) {
        for service in &self.root_services {
            self.all_services.get(service).unwrap()
                .borrow_mut().handle(self, event.clone());
        }
    }

    pub fn run(&mut self, initial_rooms: &Vec<&str>) {
        for room in initial_rooms {
            if let Some(rid) = self.client.borrow().get_public_room_id(room) {
                println!("Joining {} id: {}", &room, &rid);
                self.join(&rid);
            } else {
                println!("Could not join room {}", &room);
            }
        }

        let mut next_batch: String = self.client.borrow().sync(None).unwrap().next_batch;

        let delay = time::Duration::from_millis(500);

        loop {
            // TODO: NLL May let this extra temp variable die
            let sync = self.client.borrow().sync(Some(&next_batch));

            match sync {
                Ok(sync_data) => {
                    let rooms = self.rooms.borrow().clone();
                    for room_id in rooms.iter() {
                        if let Some(room) = sync_data.rooms.join.get(room_id) {
                            for raw_event in &room.timeline.events {
                                self.propagate_event(
                                    &RoomEvent{room_id, raw_event: raw_event.clone()}
                                );
                            }
                        }
                    }

                    next_batch = sync_data.next_batch;
                },
                Err(e) => {
                    println!("Error: {:?}", e);
                }
            }

            thread::sleep(delay);
        }
    }
}

pub trait Node<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        None
    }

    fn register_child(&mut self, name: &'a str) {
    }

    fn propagate_event(&self, bot: &Bot, event: &RoomEvent) {
        if let Some(children) = self.children() {
            for child in children {
                bot.get_service(child).handle(bot, event.clone());
            }
        }
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        self.propagate_event(bot, &event);
    }

    fn on_load(&mut self) { }

    fn on_exit(&self) { }
}

/*
if let Ok(x) = serde_json::to_string_pretty(&res.rooms.join) {
    println!("{}", x);
} */
<commit_msg>Just a couple code beauty consistencies<commit_after>use std::collections::HashMap;
use std::{thread, time};
use std::cell::{RefCell, RefMut};

use reqwest::{Response};

use errors::Error;
use client::MatrixClient;
use matrix_types::Event;

#[derive(Clone)]
pub struct RoomEvent<'a> {
    pub room_id: &'a str,
    pub raw_event: Event,
}

pub struct Bot <'a, 'b> {
    client: RefCell<&'b mut MatrixClient>,
    root_services: Vec<&'a str>,
    all_services: HashMap<&'a str, RefCell<Box<Node<'a>>>>,

    rooms: RefCell<Vec<String>>,
}

impl<'a, 'b> Bot<'a, 'b> {
    pub fn new(client: &'b mut MatrixClient) -> Self {
        Bot {
            client: RefCell::new(client),
            root_services: Vec::new(),
            all_services: HashMap::new(),
            rooms: RefCell::new(Vec::new()),
        }
    }

    pub fn join(&self, room_id: &str) -> Result<Response, Error> {
        // Make sure that the bot isn't already in the room to be joined
        for room in self.rooms.borrow().iter() {
            if room_id == room {
                return Err("Already in room".into());
            }
        }

        self.rooms.borrow_mut().push(room_id.clone().to_string());

        self.client.borrow().join(room_id)
    }

    pub fn join_public(&self, room_id: &str) -> Result<Response, Error> {
        let pub_room = self.client.borrow().get_public_room_id(room_id);

        match pub_room {
            Some(id) => self.join(&id),
            None => Err("Could not join invalid room.".into()),
        }
    }

    pub fn say(&self, room_id: &str, message: &str) -> Result<Response, Error> {
        self.client.borrow_mut().send_msg(room_id, message)
    }

    pub fn reply(&self, event: &RoomEvent, message: &str) -> Result<Response, Error> {
        self.say(event.room_id, message)
    }

    pub fn kick(&self, room_id: &str, user_id: &str, reason: Option<&str>) {
        self.client.borrow().kick(room_id, user_id, reason);
    }

    /*
    pub fn action(&self, room_id: &str, action: &str) {
    }

    pub fn set_name(&self, name: &str) {
    }
    */

    pub fn register_service(&mut self,
                            name: &'a str,
                            parent: Option<&'a str>,
                            mut service: Box<Node<'a>>) -> Option<&'a str> {
        match parent {
            Some(p) => {
                self.all_services.get_mut(p).expect("Invalid parent node")
                    .borrow_mut().register_child(name)
            },
            None => self.root_services.push(name),
        };

        service.on_load();

        self.all_services.insert(name, RefCell::new(service));

        Some(name)
    }

    pub fn get_service(&self, name: &str) -> RefMut<Box<Node<'a>>> {
        self.all_services.get(name).unwrap().borrow_mut()
    }

    pub fn propagate_event(&self, event: &RoomEvent) {
        for service in &self.root_services {
            self.all_services.get(service).unwrap()
                .borrow_mut().handle(self, event.clone());
        }
    }

    pub fn run(&mut self, initial_rooms: &Vec<&str>) {
        for room in initial_rooms {
            if let Some(rid) = self.client.borrow().get_public_room_id(room) {
                println!("Joining {} id: {}", &room, &rid);
                self.join(&rid);
            } else {
                println!("Could not join room {}", &room);
            }
        }

        let mut next_batch: String = self.client.borrow().sync(None).unwrap().next_batch;

        let delay = time::Duration::from_millis(500);

        loop {
            // TODO: NLL May let this extra temp variable die
            let sync = self.client.borrow().sync(Some(&next_batch));

            match sync {
                Ok(sync_data) => {
                    let rooms = self.rooms.borrow().clone();
                    for room_id in rooms.iter() {
                        if let Some(room) = sync_data.rooms.join.get(room_id) {
                            for raw_event in &room.timeline.events {
                                self.propagate_event(
                                    &RoomEvent{room_id, raw_event: raw_event.clone()}
                                );
                            }
                        }
                    }

                    next_batch = sync_data.next_batch;
                },
                Err(e) => {
                    println!("Error: {:?}", e);
                }
            }

            thread::sleep(delay);
        }
    }
}

pub trait Node<'a> {
    fn children(&self) -> Option<&Vec<&'a str>> {
        None
    }

    fn register_child(&mut self, name: &'a str) {
    }

    fn propagate_event(&self, bot: &Bot, event: &RoomEvent) {
        if let Some(children) = self.children() {
            for child in children {
                bot.get_service(child).handle(bot, event.clone());
            }
        }
    }

    fn handle(&mut self, bot: &Bot, event: RoomEvent) {
        self.propagate_event(bot, &event);
    }

    fn on_load(&mut self) { }

    fn on_exit(&self) { }
}

/*
if let Ok(x) = serde_json::to_string_pretty(&res.rooms.join) {
    println!("{}", x);
} */
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::HashMap;
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
use {Bot, process};
use conn::Connection;
use data::{Config, IrcReader, IrcWriter, Message};

pub struct IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub conn: Connection<T, U>,
    pub config: Config,
    process: RefCell<|&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>>,
    pub chanlists: RefCell<HashMap<String, Vec<String>>>,
}

impl<'a> IrcBot<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
    pub fn new(process: |&IrcBot<BufferedWriter<TcpStream>, BufferedReader<TcpStream>>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>>> {
        let config = try!(Config::load());
        let conn = try!(Connection::connect(config.server.as_slice(), config.port));
        Ok(IrcBot {
            conn: conn,
            config: config,
            process: RefCell::new(process),
            chanlists: RefCell::new(HashMap::new()),
        })
    }
}

impl<'a, T, U> Bot<'a> for IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn send_nick(&self, nick: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "NICK", [nick]))
    }

    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "USER", [username, "0", "*", real_name]))
    }

    fn send_join(&self, chan: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "JOIN", [chan.as_slice()]))
    }

    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "MODE", [chan.as_slice(), mode.as_slice()]))
    }

    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "TOPIC", [chan.as_slice(), topic.as_slice()]))
    }

    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "INVITE", [person.as_slice(), chan.as_slice()]))
    }

    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "PRIVMSG", [chan.as_slice(), msg.as_slice()]))
    }

    fn identify(&self) -> IoResult<()> {
        try!(self.send_nick(self.config.nickname.as_slice()));
        self.send_user(self.config.username.as_slice(), self.config.realname.as_slice())
    }

    fn output(&mut self) -> IoResult<()> {
        let mut reader = self.conn.reader();
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = try!(process(ln.as_slice()));
                    try!(self.handle_command(source, command, args.as_slice()));
                    println!("{}", ln)
                },
                Err(e) => println!("Shit, you're fucked! {}", e),
            }
        }
        Ok(())
    }

    fn config(&self) -> &Config {
        &self.config
    }
}

impl<'a, T, U> IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub fn from_connection(conn: Connection<T, U>, process: |&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, T, U>> {
        Ok(IrcBot {
            conn: conn,
            config: try!(Config::load()),
            process: RefCell::new(process),
            chanlists: RefCell::new(HashMap::new()),
        })
    }

    fn handle_command(&self, source: &str, command: &str, args: &[&str]) -> IoResult<()> {
        match (command, args) {
            ("PING", [msg]) => {
                try!(self.conn.send(Message::new(None, "PONG", [msg])));
            },
            ("376", _) => { // End of MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("422", _) => { // Missing MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("353", [_, _, chan, users]) => { // /NAMES
                for user in users.split_str(" ") {
                    if !match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                        Some(vec) => {
                            vec.push(String::from_str(user));
                            true
                        },
                        None => false,
                    } {
                        self.chanlists.borrow_mut().insert(String::from_str(chan), vec!(String::from_str(user)));
                    }
                }
            },
            ("JOIN", [chan]) => {
                match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => vec.push(String::from_str(source.slice_to(i))),
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            ("PART", [chan, _]) => {
                match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => {
                                match vec.as_slice().position_elem(&String::from_str(source.slice_to(i))) {
                                    Some(n) => {
                                        vec.swap_remove(n);
                                    },
                                    None => (),
                                };
                            },
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            _ => {
                try!((*self.process.borrow_mut().deref_mut())(self, source, command, args));
            },
        };
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use Bot;
    use super::IrcBot;
    use std::io::MemWriter;
    use std::io::util::NullReader;
    use conn::Connection;

    #[test]
    fn from_connection() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        assert!(IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).is_ok());
    }

    #[test]
    fn send_nick() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_nick("test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "NICK :test\r\n".as_bytes());
    }

    #[test]
    fn send_user() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_user("test", "Test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "USER test 0 * :Test\r\n".as_bytes());
    }
}
<commit_msg>Implemented unit tests for the remainder of the send_* methods.<commit_after>use std::cell::RefCell;
use std::collections::HashMap;
use std::io::{BufferedReader, BufferedWriter, IoResult, TcpStream};
use {Bot, process};
use conn::Connection;
use data::{Config, IrcReader, IrcWriter, Message};

pub struct IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub conn: Connection<T, U>,
    pub config: Config,
    process: RefCell<|&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>>,
    pub chanlists: RefCell<HashMap<String, Vec<String>>>,
}

impl<'a> IrcBot<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>> {
    pub fn new(process: |&IrcBot<BufferedWriter<TcpStream>, BufferedReader<TcpStream>>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, BufferedWriter<TcpStream>, BufferedReader<TcpStream>>> {
        let config = try!(Config::load());
        let conn = try!(Connection::connect(config.server.as_slice(), config.port));
        Ok(IrcBot {
            conn: conn,
            config: config,
            process: RefCell::new(process),
            chanlists: RefCell::new(HashMap::new()),
        })
    }
}

impl<'a, T, U> Bot<'a> for IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    fn send_nick(&self, nick: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "NICK", [nick]))
    }

    fn send_user(&self, username: &str, real_name: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "USER", [username, "0", "*", real_name]))
    }

    fn send_join(&self, chan: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "JOIN", [chan.as_slice()]))
    }

    fn send_mode(&self, chan: &str, mode: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "MODE", [chan.as_slice(), mode.as_slice()]))
    }

    fn send_topic(&self, chan: &str, topic: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "TOPIC", [chan.as_slice(), topic.as_slice()]))
    }

    fn send_invite(&self, person: &str, chan: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "INVITE", [person.as_slice(), chan.as_slice()]))
    }

    fn send_privmsg(&self, chan: &str, msg: &str) -> IoResult<()> {
        self.conn.send(Message::new(None, "PRIVMSG", [chan.as_slice(), msg.as_slice()]))
    }

    fn identify(&self) -> IoResult<()> {
        try!(self.send_nick(self.config.nickname.as_slice()));
        self.send_user(self.config.username.as_slice(), self.config.realname.as_slice())
    }

    fn output(&mut self) -> IoResult<()> {
        let mut reader = self.conn.reader();
        for line in reader.lines() {
            match line {
                Ok(ln) => {
                    let (source, command, args) = try!(process(ln.as_slice()));
                    try!(self.handle_command(source, command, args.as_slice()));
                    println!("{}", ln)
                },
                Err(e) => println!("Shit, you're fucked! {}", e),
            }
        }
        Ok(())
    }

    fn config(&self) -> &Config {
        &self.config
    }
}

impl<'a, T, U> IrcBot<'a, T, U> where T: IrcWriter, U: IrcReader {
    pub fn from_connection(conn: Connection<T, U>, process: |&IrcBot<T, U>, &str, &str, &[&str]|:'a -> IoResult<()>) -> IoResult<IrcBot<'a, T, U>> {
        Ok(IrcBot {
            conn: conn,
            config: try!(Config::load()),
            process: RefCell::new(process),
            chanlists: RefCell::new(HashMap::new()),
        })
    }

    fn handle_command(&self, source: &str, command: &str, args: &[&str]) -> IoResult<()> {
        match (command, args) {
            ("PING", [msg]) => {
                try!(self.conn.send(Message::new(None, "PONG", [msg])));
            },
            ("376", _) => { // End of MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("422", _) => { // Missing MOTD
                for chan in self.config.channels.iter() {
                    try!(self.send_join(chan.as_slice()));
                }
            },
            ("353", [_, _, chan, users]) => { // /NAMES
                for user in users.split_str(" ") {
                    if !match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                        Some(vec) => {
                            vec.push(String::from_str(user));
                            true
                        },
                        None => false,
                    } {
                        self.chanlists.borrow_mut().insert(String::from_str(chan), vec!(String::from_str(user)));
                    }
                }
            },
            ("JOIN", [chan]) => {
                match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => vec.push(String::from_str(source.slice_to(i))),
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            ("PART", [chan, _]) => {
                match self.chanlists.borrow_mut().find_mut(&String::from_str(chan)) {
                    Some(vec) => {
                        match source.find('!') {
                            Some(i) => {
                                match vec.as_slice().position_elem(&String::from_str(source.slice_to(i))) {
                                    Some(n) => {
                                        vec.swap_remove(n);
                                    },
                                    None => (),
                                };
                            },
                            None => (),
                        };
                    },
                    None => (),
                }
            },
            _ => {
                try!((*self.process.borrow_mut().deref_mut())(self, source, command, args));
            },
        };
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use Bot;
    use super::IrcBot;
    use std::io::MemWriter;
    use std::io::util::NullReader;
    use conn::Connection;

    #[test]
    fn from_connection() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        assert!(IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).is_ok());
    }

    #[test]
    fn send_nick() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_nick("test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "NICK :test\r\n".as_bytes());
    }

    #[test]
    fn send_user() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_user("test", "Test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "USER test 0 * :Test\r\n".as_bytes());
    }

    #[test]
    fn send_join() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_join("#test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "JOIN :#test\r\n".as_bytes());
    }

    #[test]
    fn send_mode() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_mode("#test", "+i").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "MODE #test :+i\r\n".as_bytes());
    }

    #[test]
    fn send_topic() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_topic("#test", "This is a test topic.").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "TOPIC #test :This is a test topic.\r\n".as_bytes());
    }

    #[test]
    fn send_invite() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_invite("test2", "#test").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "INVITE test2 :#test\r\n".as_bytes());
    }

    #[test]
    fn send_privmsg() {
        let w = MemWriter::new();
        let c = Connection::new(w, NullReader).unwrap();
        let b = IrcBot::from_connection(c, |_, _, _, _| { Ok(()) }).unwrap();
        b.send_privmsg("#test", "This is a test message.").unwrap();
        assert_eq!(b.conn.writer().deref_mut().get_ref(), "PRIVMSG #test :This is a test message.\r\n".as_bytes());
    }
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate cargotest;
extern crate hamcrest;
extern crate rustc_serialize;

use cargotest::support::{project, execs};
use hamcrest::assert_that;

#[test]
fn simple() {
    let p = project("foo");

    assert_that(p.cargo_process("version"),
                execs().with_status(0).with_stdout(&format!("{}\n",
                                                            cargo::version())));

    assert_that(p.cargo_process("--version"),
                execs().with_status(0).with_stdout(&format!("{}\n",
                                                            cargo::version())));

}

#[derive(RustcDecodable)]
struct FooFlags {
    flag_version: bool,
}

fn real_main(flags: FooFlags, _config: &cargo::Config) ->
        cargo::CliResult<Option<String>> {
    if flags.flag_version {
        Ok(Some("foo <version>".to_string()))
    } else {
        Ok(None)
    }
}

#[test]
fn subcommand_with_version_using_exec_main_without_stdin() {
    let usage = "
Usage: cargo foo [--version]

Options:
    -V, --version       Print version info
";
    let args: Vec<String> = vec!["cargo", "foo", "--version"]
        .into_iter().map(|s| s.to_string()).collect();
    let result = cargo::call_main_without_stdin(
                real_main, &cargo::Config::default().unwrap(),
                usage, &args, false);
    assert_eq!(result.unwrap(), Some("foo <version>".to_string()));
}

#[test]
fn version_works_without_rustc() {
    let p = project("foo");
    assert_that(p.cargo_process("version").env("PATH", ""),
                execs().with_status(0));
}

#[test]
fn version_works_with_bad_config() {
    let p = project("foo")
        .file(".cargo/config", "this is not toml");
    assert_that(p.cargo_process("version"),
                execs().with_status(0));
}

#[test]
fn version_works_with_bad_target_dir() {
    let p = project("foo")
        .file(".cargo/config", r#"
            [build]
            target-dir = 4
        "#);
    assert_that(p.cargo_process("version"),
                execs().with_status(0));
}
<commit_msg>empty path is not a thing on Windows<commit_after>extern crate cargo;
extern crate cargotest;
extern crate hamcrest;
extern crate rustc_serialize;

use cargotest::support::{project, execs};
use hamcrest::assert_that;

#[test]
fn simple() {
    let p = project("foo");

    assert_that(p.cargo_process("version"),
                execs().with_status(0).with_stdout(&format!("{}\n",
                                                            cargo::version())));

    assert_that(p.cargo_process("--version"),
                execs().with_status(0).with_stdout(&format!("{}\n",
                                                            cargo::version())));

}

#[derive(RustcDecodable)]
struct FooFlags {
    flag_version: bool,
}

fn real_main(flags: FooFlags, _config: &cargo::Config) ->
        cargo::CliResult<Option<String>> {
    if flags.flag_version {
        Ok(Some("foo <version>".to_string()))
    } else {
        Ok(None)
    }
}

#[test]
fn subcommand_with_version_using_exec_main_without_stdin() {
    let usage = "
Usage: cargo foo [--version]

Options:
    -V, --version       Print version info
";
    let args: Vec<String> = vec!["cargo", "foo", "--version"]
        .into_iter().map(|s| s.to_string()).collect();
    let result = cargo::call_main_without_stdin(
                real_main, &cargo::Config::default().unwrap(),
                usage, &args, false);
    assert_eq!(result.unwrap(), Some("foo <version>".to_string()));
}

#[test]
#[cfg_attr(target_os = "windows", ignore)]
fn version_works_without_rustc() {
    let p = project("foo");
    assert_that(p.cargo_process("version").env("PATH", ""),
                execs().with_status(0));
}

#[test]
fn version_works_with_bad_config() {
    let p = project("foo")
        .file(".cargo/config", "this is not toml");
    assert_that(p.cargo_process("version"),
                execs().with_status(0));
}

#[test]
fn version_works_with_bad_target_dir() {
    let p = project("foo")
        .file(".cargo/config", r#"
            [build]
            target-dir = 4
        "#);
    assert_that(p.cargo_process("version"),
                execs().with_status(0));
}
<|endoftext|>


<commit_before>//! Provides the CLI option parser
//!
//! Used to parse the argv/config file into a struct that
//! the server can consume and use as configuration data.

use docopt::Docopt;

static USAGE: &'static str = "
Usage: statsd [options]
       statsd --help

Options:
  -h, --help            Print help information.
  -p, --port=<p>        The UDP port to bind to [default: 8125].
  -a, --admin-port=<p>  The TCP port for the admin interface [default: 8126].
  --flush-interval=<p>  How frequently to flush metrics to the backends in seconds. [default: 10].
  --console             Enable the console backend.
  --graphite            Enable the graphite backend.
";

/// Holds the parsed command line arguments
#[derive(RustcDecodable, Debug)]
pub struct Args {
    pub flag_port: u16,
    pub flag_admin_port: u16,
    pub flag_flush_interval: u32,
    pub flag_console: bool,
    pub flag_graphite: bool,
    pub flag_help: bool,
}

pub fn parse_args() -> Args {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    args
}
<commit_msg>Add options for graphite host/port.<commit_after>//! Provides the CLI option parser
//!
//! Used to parse the argv/config file into a struct that
//! the server can consume and use as configuration data.

use docopt::Docopt;

static USAGE: &'static str = "
Usage: statsd [options]
       statsd --help

Options:
  -h, --help            Print help information.
  -p, --port=<p>        The UDP port to bind to [default: 8125].
  -a, --admin-port=<p>  The TCP port for the admin interface [default: 8126].
  --flush-interval=<p>  How frequently to flush metrics to the backends in seconds. [default: 10].
  --console             Enable the console backend.
  --graphite            Enable the graphite backend.
  --graphite-port=<p>   The port graphite/carbon is running on [default: 2003].
  --graphite-host=<p>   The host graphite/carbon is running on [default: 127.0.0.1]
";

/// Holds the parsed command line arguments
#[derive(RustcDecodable, Debug)]
pub struct Args {
    pub flag_port: u16,
    pub flag_admin_port: u16,
    pub flag_flush_interval: u32,
    pub flag_console: bool,
    pub flag_graphite: bool,
    pub flag_graphite_port: u32,
    pub flag_graphite_host: String,
    pub flag_help: bool,
}

pub fn parse_args() -> Args {
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());
    args
}
<|endoftext|>


<commit_before>use num::Num;

#[inline(always)]
pub fn div<T: Num>(out: &mut [T; 2], a: [T; 2], b: [T; 2]) ->  &mut [T; 2] {
    if b[0] != T::zero() {out[0] = a[0] / b[0];} else {out[0] = T::zero();}
    if b[1] != T::zero() {out[1] = a[1] / b[1];} else {out[1] = T::zero();}
    out
}
#[test]
fn test_div() {
    let mut v = [0, 0];
    div(&mut v, [1, 1], [1, 1]);
    assert!(v[0] == 1);
    assert!(v[1] == 1);
}

#[inline(always)]
pub fn sdiv<T: Num>(out: &mut [T; 2], a: [T; 2], s: T) ->  &mut [T; 2] {
    let not_zero = s != T::zero();
    out[0] = if not_zero {a[0] / s} else  {T::zero()};
    out[1] = if not_zero {a[1] / s} else  {T::zero()};
    out
}
#[test]
fn test_sdiv() {
    let mut v = [0, 0];
    sdiv(&mut v, [1, 1], 1);
    assert!(v[0] == 1);
    assert!(v[1] == 1);
}
<commit_msg>updates<commit_after>use num::Num;

#[inline(always)]
pub fn div<T: Num>(out: &mut [T; 2], a: [T; 2], b: [T; 2]) ->  &mut [T; 2] {
    out[0] = if b[0] != T::zero() {a[0] / b[0]} else {T::zero()};
    out[1] = if b[1] != T::zero() {a[1] / b[1]} else {T::zero()};
    out
}
#[test]
fn test_div() {
    let mut v = [0, 0];
    div(&mut v, [1, 1], [1, 1]);
    assert!(v[0] == 1);
    assert!(v[1] == 1);
}

#[inline(always)]
pub fn sdiv<T: Num>(out: &mut [T; 2], a: [T; 2], s: T) ->  &mut [T; 2] {
    let not_zero = s != T::zero();
    out[0] = if not_zero {a[0] / s} else  {T::zero()};
    out[1] = if not_zero {a[1] / s} else  {T::zero()};
    out
}
#[test]
fn test_sdiv() {
    let mut v = [0, 0];
    sdiv(&mut v, [1, 1], 1);
    assert!(v[0] == 1);
    assert!(v[1] == 1);
}
<|endoftext|>


<commit_before>/// Elf reader module
///

const EI_NIDENT: usize = 4;

// ELF32 types
#[allow(non_camel_case_types)]
type Elf32_Addr = u32;
#[allow(non_camel_case_types)]
type Elf32_Half = u16;
#[allow(non_camel_case_types)]
type Elf32_Lworld = u64;
#[allow(non_camel_case_types)]
type Elf32_Off = u32;
#[allow(non_camel_case_types)]
type Elf32_Sword = i32;
#[allow(non_camel_case_types)]
type Elf32_Word = u32;

/// Elf32 header.
/// Source: http://www.freebsd.org/cgi/man.cgi?elf(5)
#[repr(C)]
pub struct Elf32_Ehdr {
    e_ident: [u8; EI_NIDENT],
    e_type: Elf32_Half,
    e_machine: Elf32_Half,
    e_version: Elf32_Word,
    e_entry: Elf32_Addr,
    e_phoff: Elf32_Off,
    e_shoff: Elf32_Off,
    e_flags: Elf32_Word,
    e_ehsize: Elf32_Half,
    e_phentsize: Elf32_Half,
    e_phnum: Elf32_Half,
    e_shentsize: Elf32_Half,
    e_shnum: Elf32_Half,
    e_shstrndx: Elf32_Half,
}

/// Elf32 Program header
#[repr(C)]
pub struct Elf32_Phdr {
    p_type: Elf32_Word,
    p_offset: Elf32_Off,
    p_vaddr: Elf32_Addr,
    p_paddr: Elf32_Addr,
    p_filesz: Elf32_Word,
    p_memsz: Elf32_Word,
    p_flags: Elf32_Word,
    p_align: Elf32_Word,
}
<commit_msg>Add section header definition<commit_after>/// Elf reader module
///

const EI_NIDENT: usize = 4;

// ELF32 types
#[allow(non_camel_case_types)]
type Elf32_Addr = u32;
#[allow(non_camel_case_types)]
type Elf32_Half = u16;
#[allow(non_camel_case_types)]
type Elf32_Lworld = u64;
#[allow(non_camel_case_types)]
type Elf32_Off = u32;
#[allow(non_camel_case_types)]
type Elf32_Sword = i32;
#[allow(non_camel_case_types)]
type Elf32_Word = u32;

/// Elf32 header.
/// Source: http://www.freebsd.org/cgi/man.cgi?elf(5)
#[repr(C)]
pub struct Elf32_Ehdr {
    e_ident: [u8; EI_NIDENT],
    e_type: Elf32_Half,
    e_machine: Elf32_Half,
    e_version: Elf32_Word,
    e_entry: Elf32_Addr,
    e_phoff: Elf32_Off,
    e_shoff: Elf32_Off,
    e_flags: Elf32_Word,
    e_ehsize: Elf32_Half,
    e_phentsize: Elf32_Half,
    e_phnum: Elf32_Half,
    e_shentsize: Elf32_Half,
    e_shnum: Elf32_Half,
    e_shstrndx: Elf32_Half,
}

/// Elf32 Program header
#[repr(C)]
pub struct Elf32_Phdr {
    p_type: Elf32_Word,
    p_offset: Elf32_Off,
    p_vaddr: Elf32_Addr,
    p_paddr: Elf32_Addr,
    p_filesz: Elf32_Word,
    p_memsz: Elf32_Word,
    p_flags: Elf32_Word,
    p_align: Elf32_Word,
}

/// Elf32 section header
#[repr(C)]
pub struct Elf32_Shrdr {
    sh_name: Elf32_Word,
    sh_type: Elf32_Word,
    sh_flags: Elf32_Word,
    sh_addr: Elf32_Addr,
    sh_offset: Elf32_Off,
    sh_size: Elf32_Word,
    sh_link: Elf32_Word,
    sh_info: Elf32_Word,
    sh_addalign: Elf32_Word,
    sh_entsize: Elf32_Word,
}
<|endoftext|>


<commit_before>use super::ReadBuf;
use std::io;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Reads bytes from a source.
///
/// This trait is analogous to the [`std::io::Read`] trait, but integrates with
/// the asynchronous task system. In particular, the [`poll_read`] method,
/// unlike [`Read::read`], will automatically queue the current task for wakeup
/// and return if data is not yet available, rather than blocking the calling
/// thread.
///
/// Specifically, this means that the `poll_read` function will return one of
/// the following:
///
/// * `Poll::Ready(Ok(n))` means that `n` bytes of data was immediately read
///   and placed into the output buffer, where `n` == 0 implies that EOF has
///   been reached.
///
/// * `Poll::Pending` means that no data was read into the buffer
///   provided. The I/O object is not currently readable but may become readable
///   in the future. Most importantly, **the current future's task is scheduled
///   to get unparked when the object is readable**. This means that like
///   `Future::poll` you'll receive a notification when the I/O object is
///   readable again.
///
/// * `Poll::Ready(Err(e))` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `read` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
///
/// Utilities for working with `AsyncRead` values are provided by
/// [`AsyncReadExt`].
///
/// [`poll_read`]: AsyncRead::poll_read
/// [`std::io::Read`]: std::io::Read
/// [`Read::read`]: std::io::Read::read
/// [`AsyncReadExt`]: crate::io::AsyncReadExt
pub trait AsyncRead {
    /// Attempts to read from the `AsyncRead` into `buf`.
    ///
    /// On success, returns `Poll::Ready(Ok(num_bytes_read))`.
    ///
    /// If no data is available for reading, the method returns
    /// `Poll::Pending` and arranges for the current task (via
    /// `cx.waker()`) to receive a notification when the object becomes
    /// readable or is closed.
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>>;
}

macro_rules! deref_async_read {
    () => {
        fn poll_read(
            mut self: Pin<&mut Self>,
            cx: &mut Context<'_>,
            buf: &mut ReadBuf<'_>,
        ) -> Poll<io::Result<()>> {
            Pin::new(&mut **self).poll_read(cx, buf)
        }
    };
}

impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for Box<T> {
    deref_async_read!();
}

impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for &mut T {
    deref_async_read!();
}

impl
 AsyncRead for Pin

where
    P: DerefMut + Unpin,
    P::Target: AsyncRead,
{
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        self.get_mut().as_mut().poll_read(cx, buf)
    }
}

impl AsyncRead for &[u8] {
    fn poll_read(
        mut self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        let amt = std::cmp::min(self.len(), buf.remaining());
        let (a, b) = self.split_at(amt);
        buf.put_slice(a);
        *self = b;
        Poll::Ready(Ok(()))
    }
}

impl<T: AsRef<[u8]> + Unpin> AsyncRead for io::Cursor<T> {
    fn poll_read(
        mut self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        let pos = self.position();
        let slice: &[u8] = (*self).get_ref().as_ref();

        // The position could technically be out of bounds, so don't panic...
        if pos > slice.len() as u64 {
            return Poll::Ready(Ok(()));
        }

        let start = pos as usize;
        let amt = std::cmp::min(slice.len() - start, buf.remaining());
        // Add won't overflow because of pos check above.
        let end = start + amt;
        buf.put_slice(&slice[start..end]);
        self.set_position(end as u64);

        Poll::Ready(Ok(()))
    }
}
<commit_msg>Update documentation of AsyncRead to reflect use of ReadBuf<commit_after>use super::ReadBuf;
use std::io;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::{Context, Poll};

/// Reads bytes from a source.
///
/// This trait is analogous to the [`std::io::Read`] trait, but integrates with
/// the asynchronous task system. In particular, the [`poll_read`] method,
/// unlike [`Read::read`], will automatically queue the current task for wakeup
/// and return if data is not yet available, rather than blocking the calling
/// thread.
///
/// Specifically, this means that the `poll_read` function will return one of
/// the following:
///
/// * `Poll::Ready(Ok(()))` means that data was immediately read and placed into
///   the output buffer. If no data was read (`buf.filled().is_empty()`) it
///   implies that EOF has been reached.
///
/// * `Poll::Pending` means that no data was read into the buffer
///   provided. The I/O object is not currently readable but may become readable
///   in the future. Most importantly, **the current future's task is scheduled
///   to get unparked when the object is readable**. This means that like
///   `Future::poll` you'll receive a notification when the I/O object is
///   readable again.
///
/// * `Poll::Ready(Err(e))` for other errors are standard I/O errors coming from the
///   underlying object.
///
/// This trait importantly means that the `read` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
///
/// Utilities for working with `AsyncRead` values are provided by
/// [`AsyncReadExt`].
///
/// [`poll_read`]: AsyncRead::poll_read
/// [`std::io::Read`]: std::io::Read
/// [`Read::read`]: std::io::Read::read
/// [`AsyncReadExt`]: crate::io::AsyncReadExt
pub trait AsyncRead {
    /// Attempts to read from the `AsyncRead` into `buf`.
    ///
    /// On success, returns `Poll::Ready(Ok(()))` and fills `buf` with data
    /// read. If no data was read (`buf.filled().is_empty()`) it implies that
    /// EOF has been reached.
    ///
    /// If no data is available for reading, the method returns `Poll::Pending`
    /// and arranges for the current task (via `cx.waker()`) to receive a
    /// notification when the object becomes readable or is closed.
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>>;
}

macro_rules! deref_async_read {
    () => {
        fn poll_read(
            mut self: Pin<&mut Self>,
            cx: &mut Context<'_>,
            buf: &mut ReadBuf<'_>,
        ) -> Poll<io::Result<()>> {
            Pin::new(&mut **self).poll_read(cx, buf)
        }
    };
}

impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for Box<T> {
    deref_async_read!();
}

impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for &mut T {
    deref_async_read!();
}

impl
 AsyncRead for Pin

where
    P: DerefMut + Unpin,
    P::Target: AsyncRead,
{
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        self.get_mut().as_mut().poll_read(cx, buf)
    }
}

impl AsyncRead for &[u8] {
    fn poll_read(
        mut self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        let amt = std::cmp::min(self.len(), buf.remaining());
        let (a, b) = self.split_at(amt);
        buf.put_slice(a);
        *self = b;
        Poll::Ready(Ok(()))
    }
}

impl<T: AsRef<[u8]> + Unpin> AsyncRead for io::Cursor<T> {
    fn poll_read(
        mut self: Pin<&mut Self>,
        _cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        let pos = self.position();
        let slice: &[u8] = (*self).get_ref().as_ref();

        // The position could technically be out of bounds, so don't panic...
        if pos > slice.len() as u64 {
            return Poll::Ready(Ok(()));
        }

        let start = pos as usize;
        let amt = std::cmp::min(slice.len() - start, buf.remaining());
        // Add won't overflow because of pos check above.
        let end = start + amt;
        buf.put_slice(&slice[start..end]);
        self.set_position(end as u64);

        Poll::Ready(Ok(()))
    }
}
<|endoftext|>


<commit_before>use libc::{c_char, c_void};

pub type CPmDeviceID = i32;

pub type CPortMidiStream = c_void;

#[doc(hidden)]
pub type CPmMessage = i32;

pub type CPmTimestamp = u32;

#[doc(hidden)]
#[repr(C)]
pub struct CPmEvent {
    pub message : CPmMessage,
    pub timestamp : CPmTimestamp,
}

#[repr(C)]
pub struct CPmDeviceInfo {
    pub struct_version: i32, /* < this internal structure version */
    pub interf : *const c_char, /* < underlying MIDI API, e.g. MMSystem or DirectX */
    pub name : *const c_char,    /* < device name, e.g. USB MidiSport 1x1 */
    pub input : i32, /* < true iff input is available */
    pub output : i32, /* < true iff output is available */
    pub opened : i32, /* < used by generic PortMidi code to do error checking on arguments */
}

#[deriving(Show, FromPrimitive)]
#[repr(C)]
pub enum PmError {
    PmNoError = 0,
    PmGotData = 1, /* < A "no error" return that also indicates data available */
    PmHostError = -10000,
    PmInvalidDeviceId = -9999, /* out of range or
                                * output device when input is requested or
                                * input device when output is requested or
                                * device is already opened
                                */
    PmInsufficientMemory = -9998,
    PmBufferTooSmall = -9997,
    PmBufferOverflow = -9996,
    PmBadPtr = -9995, /* PortMidiStream parameter is NULL or
                       * stream is not opened or
                       * stream is output when input is required or
                       * stream is input when output is required */
    PmBadData = -9994, /* illegal midi data, e.g. missing EOX */
    PmInternalError = -9993,
    PmBufferMaxSize = -9992, /* buffer is already as large as it can be */
}

#[link(name = "portmidi")]
extern "C" {
    pub fn Pm_Initialize() -> PmError;
    pub fn Pm_Terminate()-> PmError;
    pub fn Pm_HasHostError(stream : *const CPortMidiStream ) -> i32;
    pub fn Pm_GetErrorText(errorCode : PmError) -> *const c_char;
    pub fn Pm_GetHostErrorText(msg : *const c_char , len : i32 );
    pub fn Pm_CountDevices() -> u32;
    pub fn Pm_GetDefaultInputDeviceID() -> CPmDeviceID;
    pub fn Pm_GetDefaultOutputDeviceID() -> CPmDeviceID;
    pub fn Pm_GetDeviceInfo(id:CPmDeviceID) -> *const CPmDeviceInfo;
    pub fn Pm_OpenInput(stream: *const *const CPortMidiStream, inputDevice : CPmDeviceID, inputDriverInfo: *const c_void, bufferSize : i32, time_proc: *const c_void, time_info: *const c_void) -> PmError;
    pub fn Pm_OpenOutput(stream : *const *const CPortMidiStream, outputDevice : CPmDeviceID, inputDriverInfo: *const c_void, bufferSize : i32, time_proc: *const c_void, time_info: *const c_void, latency:i32) -> PmError;
    pub fn Pm_Read(stream : *const CPortMidiStream, buffer : *mut CPmEvent , length : i32) -> i16;
    pub fn Pm_Abort(stream : *const CPortMidiStream) -> PmError;
    pub fn Pm_Close(stream : *const CPortMidiStream) -> PmError;
    pub fn Pm_Poll(stream : *const CPortMidiStream) -> PmError;
    pub fn Pm_Write(stream : *const CPortMidiStream, buffer : *const CPmEvent , length : i32) -> PmError;
    pub fn Pm_WriteShort(stream : *const CPortMidiStream, timestamp : CPmTimestamp , message : CPmMessage) -> PmError;
}

<commit_msg>Pm_CountDevices should return i32<commit_after>use libc::{c_char, c_void};

pub type CPmDeviceID = i32;

pub type CPortMidiStream = c_void;

#[doc(hidden)]
pub type CPmMessage = i32;

pub type CPmTimestamp = u32;

#[doc(hidden)]
#[repr(C)]
pub struct CPmEvent {
    pub message : CPmMessage,
    pub timestamp : CPmTimestamp,
}

#[repr(C)]
pub struct CPmDeviceInfo {
    pub struct_version: i32, /* < this internal structure version */
    pub interf : *const c_char, /* < underlying MIDI API, e.g. MMSystem or DirectX */
    pub name : *const c_char,    /* < device name, e.g. USB MidiSport 1x1 */
    pub input : i32, /* < true iff input is available */
    pub output : i32, /* < true iff output is available */
    pub opened : i32, /* < used by generic PortMidi code to do error checking on arguments */
}

#[deriving(Show, FromPrimitive)]
#[repr(C)]
pub enum PmError {
    PmNoError = 0,
    PmGotData = 1, /* < A "no error" return that also indicates data available */
    PmHostError = -10000,
    PmInvalidDeviceId = -9999, /* out of range or
                                * output device when input is requested or
                                * input device when output is requested or
                                * device is already opened
                                */
    PmInsufficientMemory = -9998,
    PmBufferTooSmall = -9997,
    PmBufferOverflow = -9996,
    PmBadPtr = -9995, /* PortMidiStream parameter is NULL or
                       * stream is not opened or
                       * stream is output when input is required or
                       * stream is input when output is required */
    PmBadData = -9994, /* illegal midi data, e.g. missing EOX */
    PmInternalError = -9993,
    PmBufferMaxSize = -9992, /* buffer is already as large as it can be */
}

#[link(name = "portmidi")]
extern "C" {
    pub fn Pm_Initialize() -> PmError;
    pub fn Pm_Terminate()-> PmError;
    pub fn Pm_HasHostError(stream : *const CPortMidiStream ) -> i32;
    pub fn Pm_GetErrorText(errorCode : PmError) -> *const c_char;
    pub fn Pm_GetHostErrorText(msg : *const c_char , len : i32 );
    pub fn Pm_CountDevices() -> i32;
    pub fn Pm_GetDefaultInputDeviceID() -> CPmDeviceID;
    pub fn Pm_GetDefaultOutputDeviceID() -> CPmDeviceID;
    pub fn Pm_GetDeviceInfo(id:CPmDeviceID) -> *const CPmDeviceInfo;
    pub fn Pm_OpenInput(stream: *const *const CPortMidiStream, inputDevice : CPmDeviceID, inputDriverInfo: *const c_void, bufferSize : i32, time_proc: *const c_void, time_info: *const c_void) -> PmError;
    pub fn Pm_OpenOutput(stream : *const *const CPortMidiStream, outputDevice : CPmDeviceID, inputDriverInfo: *const c_void, bufferSize : i32, time_proc: *const c_void, time_info: *const c_void, latency:i32) -> PmError;
    pub fn Pm_Read(stream : *const CPortMidiStream, buffer : *mut CPmEvent , length : i32) -> i16;
    pub fn Pm_Abort(stream : *const CPortMidiStream) -> PmError;
    pub fn Pm_Close(stream : *const CPortMidiStream) -> PmError;
    pub fn Pm_Poll(stream : *const CPortMidiStream) -> PmError;
    pub fn Pm_Write(stream : *const CPortMidiStream, buffer : *const CPmEvent , length : i32) -> PmError;
    pub fn Pm_WriteShort(stream : *const CPortMidiStream, timestamp : CPmTimestamp , message : CPmMessage) -> PmError;
}

<|endoftext|>


<commit_before>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Miscellaneous `embedded-hal` trait implementations.
//!
//! The `hal` module consists of a collection of `embedded-hal` trait
//! implementations for traits that aren't tied to a specific peripheral.
//!
//! This module is only included when either the `hal` or `hal-unproven` feature
//! flag is enabled.

use std::thread;
use std::time::{Duration, Instant};

use embedded_hal::blocking::delay::{DelayMs, DelayUs};
use embedded_hal::timer::CountDown;
use void::Void;

/// Implements the `embedded-hal` `DelayMs` and `DelayUs` traits.
#[derive(Debug, Default)]
pub struct Delay {}

impl Delay {
    /// Constructs a new `Delay`.
    pub fn new() -> Delay {
        Delay {}
    }
}

impl DelayMs<u8> for Delay {
    fn delay_ms(&mut self, ms: u8) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u16> for Delay {
    fn delay_ms(&mut self, ms: u16) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u32> for Delay {
    fn delay_ms(&mut self, ms: u32) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u64> for Delay {
    fn delay_ms(&mut self, ms: u64) {
        thread::sleep(Duration::from_millis(ms));
    }
}

impl DelayUs<u8> for Delay {
    fn delay_us(&mut self, us: u8) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u16> for Delay {
    fn delay_us(&mut self, us: u16) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u32> for Delay {
    fn delay_us(&mut self, us: u32) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u64> for Delay {
    fn delay_us(&mut self, us: u64) {
        thread::sleep(Duration::from_micros(us));
    }
}

/// Implements the `embedded-hal` `CountDown` trait.
#[derive(Debug, Copy, Clone)]
pub struct Timer {
    now: Instant,
    duration: Duration,
}

impl Timer {
    /// Constructs a new `Timer`.
    pub fn new() -> Self {
        Self {
            now: Instant::now(),
            duration: Duration::from_micros(0),
        }
    }
}

impl Default for Timer {
    fn default() -> Self {
        Timer::new()
    }
}

pub struct Millisecond(pub u64);
pub struct Microsecond(pub u64);
pub struct Second(pub u64);

impl From<Millisecond> for Microsecond {
    fn from(item: Millisecond) -> Self {
        Microsecond(item.0 * 1_000)
    }
}

impl From<Second> for Microsecond {
    fn from(item: Second) -> Self {
        Microsecond(item.0 * 1_000_000)
    }
}

impl Microsecond {
    fn as_u64(&self) -> u64 {
        self.0
    }
}

impl CountDown for Timer {
    type Time = Microsecond;

    /// Starts the timer with a `timeout`.
    fn start<T>(&mut self, timeout: T)
    where
        T: Into<Microsecond>,
    {
        self.duration = Duration::from_micros(timeout.into().as_u64());
        self.now = Instant::now();
    }

    /// Returns `Ok` if the timer has wrapped.
    fn wait(&mut self) -> nb::Result<(), Void> {
        if self.now.elapsed() >= self.duration {
            Ok(())
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}
<commit_msg>Add Hertz newtype<commit_after>// Copyright (c) 2017-2019 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! Miscellaneous `embedded-hal` trait implementations.
//!
//! The `hal` module consists of a collection of `embedded-hal` trait
//! implementations for traits that aren't tied to a specific peripheral.
//!
//! This module is only included when either the `hal` or `hal-unproven` feature
//! flag is enabled.

use std::thread;
use std::time::{Duration, Instant};

use embedded_hal::blocking::delay::{DelayMs, DelayUs};
use embedded_hal::timer::CountDown;
use void::Void;

/// Implements the `embedded-hal` `DelayMs` and `DelayUs` traits.
#[derive(Debug, Default)]
pub struct Delay {}

impl Delay {
    /// Constructs a new `Delay`.
    pub fn new() -> Delay {
        Delay {}
    }
}

impl DelayMs<u8> for Delay {
    fn delay_ms(&mut self, ms: u8) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u16> for Delay {
    fn delay_ms(&mut self, ms: u16) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u32> for Delay {
    fn delay_ms(&mut self, ms: u32) {
        thread::sleep(Duration::from_millis(u64::from(ms)));
    }
}

impl DelayMs<u64> for Delay {
    fn delay_ms(&mut self, ms: u64) {
        thread::sleep(Duration::from_millis(ms));
    }
}

impl DelayUs<u8> for Delay {
    fn delay_us(&mut self, us: u8) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u16> for Delay {
    fn delay_us(&mut self, us: u16) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u32> for Delay {
    fn delay_us(&mut self, us: u32) {
        thread::sleep(Duration::from_micros(u64::from(us)));
    }
}

impl DelayUs<u64> for Delay {
    fn delay_us(&mut self, us: u64) {
        thread::sleep(Duration::from_micros(us));
    }
}

/// Implements the `embedded-hal` `CountDown` trait.
#[derive(Debug, Copy, Clone)]
pub struct Timer {
    now: Instant,
    duration: Duration,
}

impl Timer {
    /// Constructs a new `Timer`.
    pub fn new() -> Self {
        Self {
            now: Instant::now(),
            duration: Duration::from_micros(0),
        }
    }
}

impl Default for Timer {
    fn default() -> Self {
        Timer::new()
    }
}

pub struct Millisecond(pub u64);
pub struct Microsecond(pub u64);
pub struct Second(pub u64);
pub struct Hertz(pub f64);

impl From<Hertz> for Microsecond {
    fn from(item: Hertz) -> Self {
        if item.0 > 0.0 && item.0.is_finite() {
            Microsecond(((1.0 / item.0) * 1_000_000.0) as u64)
        } else {
            Microsecond(0)
        }
    }
}

impl From<Millisecond> for Microsecond {
    fn from(item: Millisecond) -> Self {
        Microsecond(item.0 * 1_000)
    }
}

impl From<Second> for Microsecond {
    fn from(item: Second) -> Self {
        Microsecond(item.0 * 1_000_000)
    }
}

impl Microsecond {
    fn as_u64(&self) -> u64 {
        self.0
    }
}

impl CountDown for Timer {
    type Time = Microsecond;

    /// Starts the timer with a `timeout`.
    fn start<T>(&mut self, timeout: T)
    where
        T: Into<Microsecond>,
    {
        self.duration = Duration::from_micros(timeout.into().as_u64());
        self.now = Instant::now();
    }

    /// Returns `Ok` if the timer has wrapped.
    fn wait(&mut self) -> nb::Result<(), Void> {
        if self.now.elapsed() >= self.duration {
            Ok(())
        } else {
            Err(nb::Error::WouldBlock)
        }
    }
}
<|endoftext|>