<commit_before>/// The validator service. Connects to a beacon node and signs blocks when required.
use crate::attester_service::{AttestationGrpcClient, AttesterService};
use crate::block_producer_service::{BeaconBlockGrpcClient, BlockProducerService};
use crate::config::Config as ValidatorConfig;
use crate::duties::UpdateOutcome;
use crate::duties::{DutiesManager, EpochDutiesMap};
use crate::error as error_chain;
use crate::error::ErrorKind;
use attester::test_utils::EpochMap;
use attester::{test_utils::LocalSigner as AttesterLocalSigner, Attester};
use block_proposer::{test_utils::LocalSigner as BlockProposerLocalSigner, BlockProducer};
use bls::Keypair;
use grpcio::{ChannelBuilder, EnvBuilder};
use protos::services::Empty;
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{debug, error, info, warn};
use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::sync::Arc;
use std::time::{Duration, Instant, SystemTime};
use tokio::prelude::*;
use tokio::runtime::Builder;
use tokio::timer::Interval;
use tokio_timer::clock::Clock;
use types::{Epoch, Fork, Slot};

//TODO: This service should be simplified in the future. Can be made more steamlined.

/// The validator service. This is the main thread that executes and maintains validator
/// duties.
pub struct Service {
    /// The node we currently connected to.
    connected_node_version: String,
    /// The chain id we are processing on.
    chain_id: u16,
    /// The fork state we processing on.
    fork: Fork,
    /// The slot clock for this service.
    slot_clock: SystemTimeSlotClock,
    /// The current slot we are processing.
    current_slot: Slot,
    /// Duration until the next slot. This is used for initializing the tokio timer interval.
    duration_to_next_slot: Duration,
    /// The number of slots per epoch to allow for converting slots to epochs.
    slots_per_epoch: u64,
    // GRPC Clients
    /// The beacon block GRPC client.
    beacon_block_client: Arc<BeaconBlockServiceClient>,
    /// The validator GRPC client.
    validator_client: Arc<ValidatorServiceClient>,
    /// The attester GRPC client.
    attester_client: Arc<AttestationServiceClient>,
    /// The validator client logger.
    log: slog::Logger,
}

impl Service {
    ///  Initial connection to the beacon node to determine its properties.
    ///
    ///  This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
    ///  and returns an instance of the service.
    fn initialize_service(
        config: &ValidatorConfig,
        log: slog::Logger,
    ) -> error_chain::Result<Self> {
        // initialise the beacon node client to check for a connection

        let env = Arc::new(EnvBuilder::new().build());
        // Beacon node gRPC beacon node endpoints.
        let beacon_node_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(BeaconNodeServiceClient::new(ch))
        };

        // retrieve node information
        let node_info = loop {
            match beacon_node_client.info(&Empty::new()) {
                Err(e) => {
                    warn!(log, "Could not connect to node. Error: {}", e);
                    info!(log, "Retrying in 5 seconds...");
                    std::thread::sleep(Duration::from_secs(5));
                    continue;
                }
                Ok(info) => {
                    if SystemTime::now()
                        .duration_since(SystemTime::UNIX_EPOCH)
                        .unwrap()
                        .as_secs()
                        < info.genesis_time
                    {
                        warn!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err("Genesis time in the future".into());
                    }
                    break info;
                }
            };
        };

        // build requisite objects to form Self
        let genesis_time = node_info.get_genesis_time();

        info!(log,"Beacon node connected"; "Node Version" => node_info.version.clone(), "Chain ID" => node_info.chain_id, "Genesis time" => genesis_time);

        let proto_fork = node_info.get_fork();
        let mut previous_version: [u8; 4] = [0; 4];
        let mut current_version: [u8; 4] = [0; 4];
        previous_version.copy_from_slice(&proto_fork.get_previous_version()[..4]);
        current_version.copy_from_slice(&proto_fork.get_current_version()[..4]);
        let fork = Fork {
            previous_version,
            current_version,
            epoch: Epoch::from(proto_fork.get_epoch()),
        };

        // initialize the RPC clients

        // Beacon node gRPC beacon block endpoints.
        let beacon_block_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(BeaconBlockServiceClient::new(ch))
        };

        // Beacon node gRPC validator endpoints.
        let validator_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(ValidatorServiceClient::new(ch))
        };

        //Beacon node gRPC attester endpoints.
        let attester_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(AttestationServiceClient::new(ch))
        };

        // build the validator slot clock
        let slot_clock = SystemTimeSlotClock::new(genesis_time, config.spec.seconds_per_slot)
            .expect("Unable to instantiate SystemTimeSlotClock.");

        let current_slot = slot_clock
            .present_slot()
            .map_err(|e| ErrorKind::SlotClockError(e))?
            .expect("Genesis must be in the future");

        // calculate the duration to the next slot
        let duration_to_next_slot = {
            let seconds_per_slot = config.spec.seconds_per_slot;
            let syslot_time = SystemTime::now();
            let duration_since_epoch = syslot_time
                .duration_since(SystemTime::UNIX_EPOCH)
                .map_err(|e| ErrorKind::SystemTimeError(e.to_string()))?;
            let duration_since_genesis = duration_since_epoch
                .checked_sub(Duration::from_secs(genesis_time))
                .expect("Genesis must be in the future. Checked on connection");
            let elapsed_slots = duration_since_epoch
                .as_secs()
                .checked_div(seconds_per_slot as u64)
                .expect("Seconds per slot should not be 0");

            // the duration to the next slot
            Duration::from_secs(
                (elapsed_slots + 1)
                    .checked_mul(seconds_per_slot)
                    .expect("Next slot time should not overflow u64"),
            )
            .checked_sub(duration_since_genesis)
            .expect("This should never saturate")
        };

        Ok(Self {
            connected_node_version: node_info.version,
            chain_id: node_info.chain_id as u16,
            fork,
            slot_clock,
            current_slot,
            duration_to_next_slot,
            slots_per_epoch: config.spec.slots_per_epoch,
            beacon_block_client,
            validator_client,
            attester_client,
            log,
        })
    }

    /// Initialise the service then run the core thread.
    pub fn start(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result<()> {
        // connect to the node and retrieve its properties and initialize the gRPC clients
        let service = Service::initialize_service(&config, log)?;

        // we have connected to a node and established its parameters. Spin up the core service

        // set up the validator service runtime
        let mut runtime = Builder::new()
            .clock(Clock::system())
            .name_prefix("validator-client-")
            .build()
            .map_err(|e| format!("Tokio runtime failed: {}", e))?;

        // set up the validator work interval - start at next slot and proceed every slot
        let interval = {
            // Set the interval to start at the next slot, and every slot after
            let slot_duration = Duration::from_secs(config.spec.seconds_per_slot);
            //TODO: Handle checked add correctly
            Interval::new(
                Instant::now() + service.duration_to_next_slot,
                slot_duration,
            )
        };

        /* kick off core service */

        // generate keypairs

        // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
        // https://github.com/sigp/lighthouse/issues/160
        let keypairs = Arc::new(vec![Keypair::random()]);

        /* build requisite objects to pass to core thread */

        // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
        // where EpochDuty contains slot numbers and attestation data that each validator needs to
        // produce work on.
        let duties_map = EpochDutiesMap::new(config.spec.slots_per_epoch);

        // builds a manager which maintains the list of current duties for all known validators
        // and can check when a validator needs to perform a task.
        let manager = Arc::new(DutiesManager {
            duties_map,
            pubkeys: keypairs.iter().map(|keypair| keypair.pk.clone()).collect(),
            beacon_node: service.validator_client.clone(),
        });

        // run the core thread
        runtime
            .block_on(interval.for_each(move |_| {
                let log = service.log.clone();

                // get the current slot
                let current_slot = match service.slot_clock.present_slot() {
                    Err(e) => {
                        error!(log, "SystemTimeError {:?}", e);
                        return Ok(());
                    }
                    Ok(slot) => slot.expect("Genesis is in the future"),
                };

                let current_epoch = current_slot.epoch(service.slots_per_epoch);

                debug_assert!(
                    current_slot > service.current_slot,
                    "The Timer should poll a new slot"
                );

                info!(log, "Processing slot: {}", current_slot.as_u64());

                // check for new duties
                let mut cloned_manager = manager.clone();
                tokio::spawn(futures::future::poll_fn(move || {
                    cloned_manager.run_update(current_epoch.clone(), log.clone())
                }));

                // execute any specified duties

                Ok(())
            }))
            .map_err(|e| format!("Service thread failed: {:?}", e))?;

        // completed a slot process
        Ok(())
    }

    /*

    for keypair in keypairs {
        info!(self.log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id());

        // Spawn a new thread to maintain the validator's `EpochDuties`.
        let duties_manager_thread = {
            let spec = spec.clone();
            let duties_map = duties_map.clone();
            let slot_clock = self.slot_clock.clone();
            let log = self.log.clone();
            let beacon_node = self.validator_client.clone();
            let pubkey = keypair.pk.clone();
            thread::spawn(move || {
                let manager = DutiesManager {
                    duties_map,
                    pubkey,
                    spec,
                    slot_clock,
                    beacon_node,
                };
                let mut duties_manager_service = DutiesManagerService {
                    manager,
                    poll_interval_millis,
                    log,
                };

                duties_manager_service.run();
            })
        };

        // Spawn a new thread to perform block production for the validator.
        let producer_thread = {
            let spec = spec.clone();
            let signer = Arc::new(BlockProposerLocalSigner::new(keypair.clone()));
            let duties_map = duties_map.clone();
            let slot_clock = slot_clock.clone();
            let log = log.clone();
            let client = Arc::new(BeaconBlockGrpcClient::new(beacon_block_grpc_client.clone()));
            thread::spawn(move || {
                let block_producer =
                    BlockProducer::new(spec, duties_map, slot_clock, client, signer);
                let mut block_producer_service = BlockProducerService {
                    block_producer,
                    poll_interval_millis,
                    log,
                };

                block_producer_service.run();
            })
        };

        // Spawn a new thread for attestation for the validator.
        let attester_thread = {
            let signer = Arc::new(AttesterLocalSigner::new(keypair.clone()));
            let epoch_map = epoch_map_for_attester.clone();
            let slot_clock = slot_clock.clone();
            let log = log.clone();
            let client = Arc::new(AttestationGrpcClient::new(attester_grpc_client.clone()));
            thread::spawn(move || {
                let attester = Attester::new(epoch_map, slot_clock, client, signer);
                let mut attester_service = AttesterService {
                    attester,
                    poll_interval_millis,
                    log,
                };

                attester_service.run();
            })
        };

        threads.push((duties_manager_thread, producer_thread, attester_thread));
    }

    // Naively wait for all the threads to complete.
    for tuple in threads {
        let (manager, producer, attester) = tuple;
        let _ = producer.join();
        let _ = manager.join();
        let _ = attester.join();
    }
    */
}
<commit_msg>Adds RwLock to EpochDuty<commit_after>/// The validator service. Connects to a beacon node and signs blocks when required.
use crate::attester_service::{AttestationGrpcClient, AttesterService};
use crate::block_producer_service::{BeaconBlockGrpcClient, BlockProducerService};
use crate::config::Config as ValidatorConfig;
use crate::duties::UpdateOutcome;
use crate::duties::{DutiesManager, EpochDutiesMap};
use crate::error as error_chain;
use crate::error::ErrorKind;
use attester::test_utils::EpochMap;
use attester::{test_utils::LocalSigner as AttesterLocalSigner, Attester};
use block_proposer::{test_utils::LocalSigner as BlockProposerLocalSigner, BlockProducer};
use bls::Keypair;
use grpcio::{ChannelBuilder, EnvBuilder};
use protos::services::Empty;
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{debug, error, info, warn};
use slot_clock::{SlotClock, SystemTimeSlotClock};
use std::sync::Arc;
use std::sync::RwLock;
use std::time::{Duration, Instant, SystemTime};
use tokio::prelude::*;
use tokio::runtime::Builder;
use tokio::timer::Interval;
use tokio_timer::clock::Clock;
use types::{Epoch, Fork, Slot};

//TODO: This service should be simplified in the future. Can be made more steamlined.

/// The validator service. This is the main thread that executes and maintains validator
/// duties.
pub struct Service {
    /// The node we currently connected to.
    connected_node_version: String,
    /// The chain id we are processing on.
    chain_id: u16,
    /// The fork state we processing on.
    fork: Fork,
    /// The slot clock for this service.
    slot_clock: SystemTimeSlotClock,
    /// The current slot we are processing.
    current_slot: Slot,
    /// Duration until the next slot. This is used for initializing the tokio timer interval.
    duration_to_next_slot: Duration,
    /// The number of slots per epoch to allow for converting slots to epochs.
    slots_per_epoch: u64,
    // GRPC Clients
    /// The beacon block GRPC client.
    beacon_block_client: Arc<BeaconBlockServiceClient>,
    /// The validator GRPC client.
    validator_client: Arc<ValidatorServiceClient>,
    /// The attester GRPC client.
    attester_client: Arc<AttestationServiceClient>,
    /// The validator client logger.
    log: slog::Logger,
}

impl Service {
    ///  Initial connection to the beacon node to determine its properties.
    ///
    ///  This tries to connect to a beacon node. Once connected, it initialised the gRPC clients
    ///  and returns an instance of the service.
    fn initialize_service(
        config: &ValidatorConfig,
        log: slog::Logger,
    ) -> error_chain::Result<Self> {
        // initialise the beacon node client to check for a connection

        let env = Arc::new(EnvBuilder::new().build());
        // Beacon node gRPC beacon node endpoints.
        let beacon_node_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(BeaconNodeServiceClient::new(ch))
        };

        // retrieve node information
        let node_info = loop {
            match beacon_node_client.info(&Empty::new()) {
                Err(e) => {
                    warn!(log, "Could not connect to node. Error: {}", e);
                    info!(log, "Retrying in 5 seconds...");
                    std::thread::sleep(Duration::from_secs(5));
                    continue;
                }
                Ok(info) => {
                    if SystemTime::now()
                        .duration_since(SystemTime::UNIX_EPOCH)
                        .unwrap()
                        .as_secs()
                        < info.genesis_time
                    {
                        warn!(
                            log,
                            "Beacon Node's genesis time is in the future. No work to do.\n Exiting"
                        );
                        return Err("Genesis time in the future".into());
                    }
                    break info;
                }
            };
        };

        // build requisite objects to form Self
        let genesis_time = node_info.get_genesis_time();

        info!(log,"Beacon node connected"; "Node Version" => node_info.version.clone(), "Chain ID" => node_info.chain_id, "Genesis time" => genesis_time);

        let proto_fork = node_info.get_fork();
        let mut previous_version: [u8; 4] = [0; 4];
        let mut current_version: [u8; 4] = [0; 4];
        previous_version.copy_from_slice(&proto_fork.get_previous_version()[..4]);
        current_version.copy_from_slice(&proto_fork.get_current_version()[..4]);
        let fork = Fork {
            previous_version,
            current_version,
            epoch: Epoch::from(proto_fork.get_epoch()),
        };

        // initialize the RPC clients

        // Beacon node gRPC beacon block endpoints.
        let beacon_block_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(BeaconBlockServiceClient::new(ch))
        };

        // Beacon node gRPC validator endpoints.
        let validator_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(ValidatorServiceClient::new(ch))
        };

        //Beacon node gRPC attester endpoints.
        let attester_client = {
            let ch = ChannelBuilder::new(env.clone()).connect(&config.server);
            Arc::new(AttestationServiceClient::new(ch))
        };

        // build the validator slot clock
        let slot_clock = SystemTimeSlotClock::new(genesis_time, config.spec.seconds_per_slot)
            .expect("Unable to instantiate SystemTimeSlotClock.");

        let current_slot = slot_clock
            .present_slot()
            .map_err(|e| ErrorKind::SlotClockError(e))?
            .expect("Genesis must be in the future");

        // calculate the duration to the next slot
        let duration_to_next_slot = {
            let seconds_per_slot = config.spec.seconds_per_slot;
            let syslot_time = SystemTime::now();
            let duration_since_epoch = syslot_time
                .duration_since(SystemTime::UNIX_EPOCH)
                .map_err(|e| ErrorKind::SystemTimeError(e.to_string()))?;
            let duration_since_genesis = duration_since_epoch
                .checked_sub(Duration::from_secs(genesis_time))
                .expect("Genesis must be in the future. Checked on connection");
            let elapsed_slots = duration_since_epoch
                .as_secs()
                .checked_div(seconds_per_slot as u64)
                .expect("Seconds per slot should not be 0");

            // the duration to the next slot
            Duration::from_secs(
                (elapsed_slots + 1)
                    .checked_mul(seconds_per_slot)
                    .expect("Next slot time should not overflow u64"),
            )
            .checked_sub(duration_since_genesis)
            .expect("This should never saturate")
        };

        Ok(Self {
            connected_node_version: node_info.version,
            chain_id: node_info.chain_id as u16,
            fork,
            slot_clock,
            current_slot,
            duration_to_next_slot,
            slots_per_epoch: config.spec.slots_per_epoch,
            beacon_block_client,
            validator_client,
            attester_client,
            log,
        })
    }

    /// Initialise the service then run the core thread.
    pub fn start(config: ValidatorConfig, log: slog::Logger) -> error_chain::Result<()> {
        // connect to the node and retrieve its properties and initialize the gRPC clients
        let service = Service::initialize_service(&config, log)?;

        // we have connected to a node and established its parameters. Spin up the core service

        // set up the validator service runtime
        let mut runtime = Builder::new()
            .clock(Clock::system())
            .name_prefix("validator-client-")
            .build()
            .map_err(|e| format!("Tokio runtime failed: {}", e))?;

        // set up the validator work interval - start at next slot and proceed every slot
        let interval = {
            // Set the interval to start at the next slot, and every slot after
            let slot_duration = Duration::from_secs(config.spec.seconds_per_slot);
            //TODO: Handle checked add correctly
            Interval::new(
                Instant::now() + service.duration_to_next_slot,
                slot_duration,
            )
        };

        /* kick off core service */

        // generate keypairs

        // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
        // https://github.com/sigp/lighthouse/issues/160
        let keypairs = Arc::new(vec![Keypair::random()]);

        /* build requisite objects to pass to core thread */

        // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty)
        // where EpochDuty contains slot numbers and attestation data that each validator needs to
        // produce work on.
        let duties_map = RwLock::new(EpochDutiesMap::new(config.spec.slots_per_epoch));

        // builds a manager which maintains the list of current duties for all known validators
        // and can check when a validator needs to perform a task.
        let manager = Arc::new(DutiesManager {
            duties_map,
            pubkeys: keypairs.iter().map(|keypair| keypair.pk.clone()).collect(),
            beacon_node: service.validator_client.clone(),
        });

        // run the core thread
        runtime
            .block_on(interval.for_each(move |_| {
                let log = service.log.clone();

                // get the current slot
                let current_slot = match service.slot_clock.present_slot() {
                    Err(e) => {
                        error!(log, "SystemTimeError {:?}", e);
                        return Ok(());
                    }
                    Ok(slot) => slot.expect("Genesis is in the future"),
                };

                let current_epoch = current_slot.epoch(service.slots_per_epoch);

                debug_assert!(
                    current_slot > service.current_slot,
                    "The Timer should poll a new slot"
                );

                info!(log, "Processing slot: {}", current_slot.as_u64());

                // check for new duties
                let mut cloned_manager = manager.clone();
                tokio::spawn(futures::future::poll_fn(move || {
                    cloned_manager.run_update(current_epoch.clone(), log.clone())
                }));

                // execute any specified duties

                Ok(())
            }))
            .map_err(|e| format!("Service thread failed: {:?}", e))?;

        // completed a slot process
        Ok(())
    }

    /*

    for keypair in keypairs {
        info!(self.log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id());

        // Spawn a new thread to maintain the validator's `EpochDuties`.
        let duties_manager_thread = {
            let spec = spec.clone();
            let duties_map = duties_map.clone();
            let slot_clock = self.slot_clock.clone();
            let log = self.log.clone();
            let beacon_node = self.validator_client.clone();
            let pubkey = keypair.pk.clone();
            thread::spawn(move || {
                let manager = DutiesManager {
                    duties_map,
                    pubkey,
                    spec,
                    slot_clock,
                    beacon_node,
                };
                let mut duties_manager_service = DutiesManagerService {
                    manager,
                    poll_interval_millis,
                    log,
                };

                duties_manager_service.run();
            })
        };

        // Spawn a new thread to perform block production for the validator.
        let producer_thread = {
            let spec = spec.clone();
            let signer = Arc::new(BlockProposerLocalSigner::new(keypair.clone()));
            let duties_map = duties_map.clone();
            let slot_clock = slot_clock.clone();
            let log = log.clone();
            let client = Arc::new(BeaconBlockGrpcClient::new(beacon_block_grpc_client.clone()));
            thread::spawn(move || {
                let block_producer =
                    BlockProducer::new(spec, duties_map, slot_clock, client, signer);
                let mut block_producer_service = BlockProducerService {
                    block_producer,
                    poll_interval_millis,
                    log,
                };

                block_producer_service.run();
            })
        };

        // Spawn a new thread for attestation for the validator.
        let attester_thread = {
            let signer = Arc::new(AttesterLocalSigner::new(keypair.clone()));
            let epoch_map = epoch_map_for_attester.clone();
            let slot_clock = slot_clock.clone();
            let log = log.clone();
            let client = Arc::new(AttestationGrpcClient::new(attester_grpc_client.clone()));
            thread::spawn(move || {
                let attester = Attester::new(epoch_map, slot_clock, client, signer);
                let mut attester_service = AttesterService {
                    attester,
                    poll_interval_millis,
                    log,
                };

                attester_service.run();
            })
        };

        threads.push((duties_manager_thread, producer_thread, attester_thread));
    }

    // Naively wait for all the threads to complete.
    for tuple in threads {
        let (manager, producer, attester) = tuple;
        let _ = producer.join();
        let _ = manager.join();
        let _ = attester.join();
    }
    */
}
<|endoftext|>


<commit_before>static LANGUAGE: &'static str = "Rust";
static THRESHOLD: int = 10;

fn is_big(n: int) -> bool {
    // Access constant in some function
    n > THRESHOLD
}

fn main() {
    let n = 16;

    // Access constant in the main task
    println!("This is {}", LANGUAGE);
    println!("The threshold is {}", THRESHOLD);
    println!("{} is {}", n, if is_big(n) { "big" } else { "small" });

    // Error! Cannot modify an static item
    THRESHOLD = 5;
    // FIXME ^ Comment out this line

    {
        // String literals are references to read-only memory
        let _static_string: &'static str = "In read-only memory";

        // When `_static_string` goes out of scope, we can no longer refer to
        // the underlying data, but the string remains in the read-only memory
    }
}
<commit_msg>Update constants.rs<commit_after>static LANGUAGE: &'static str = "Rust";
static THRESHOLD: int = 10;

fn is_big(n: int) -> bool {
    // Access constant in some function
    n > THRESHOLD
}

fn main() {
    let n = 16;

    // Access constant in the main task
    println!("This is {}", LANGUAGE);
    println!("The threshold is {}", THRESHOLD);
    println!("{} is {}", n, if is_big(n) { "big" } else { "small" });

    // Error! Cannot modify a static item
    THRESHOLD = 5;
    // FIXME ^ Comment out this line

    {
        // String literals are references to read-only memory
        let _static_string: &'static str = "In read-only memory";

        // When `_static_string` goes out of scope, we can no longer refer to
        // the underlying data, but the string remains in the read-only memory
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use diesel::result::Error;
use diesel;
use diesel::*;
use self::models::{ImageLocation, SubmitImageLocation};
use database::schema::image_locations::dsl::*;
use database::schema::image_locations;
use super::database;

pub mod models;

static IMAGE_PATH: &'static str = "./static/media";

pub fn load_image(file_name: String) -> Option<File> {
    let conn = database::get_db_connection();

    let image_location: ImageLocation = match image_locations.filter(name.eq(file_name)).
        first::<ImageLocation>(&*conn) {
        Ok(image_location) => image_location,
        Err(_) => return None,
    };

    match File::open(image_location.url) {
        Ok(file) => Some(file),
        Err(_) => None,
    }
}

/// Uploads the image to the server with the given filename.
/// Returns the identifier of the image.
pub fn store_image(image_name: String, image: Vec<u8>) -> io::Result<String> {
    let file_path: String = format!("{path}/{filename}", path = IMAGE_PATH, filename = image_name);
    let mut file = File::create(Path::new(file_path.as_str())).unwrap();
    file.write(image.as_slice()).unwrap();

    Ok(file_path)
}

pub fn insert_image_location(image_name: String, image_path: String) -> Result<i32, Error> {
    let conn = &*database::get_db_connection();

    let image_location = SubmitImageLocation { name: image_name, url: image_path };

    match diesel::insert(&image_location)
        .into(image_locations)
        .execute(conn) {
        Ok(_) => (),
        Err(e) => return Err(e),
    };

    match image_locations::table
        .order(image_locations::id.desc())
        .first::<ImageLocation>(conn) {
        Ok(img_loc) => Ok(img_loc.id),
        Err(e) => Err(e),
    }
}<commit_msg>Galleries: - Fixed: Removed the leading . in the location. (./static/... -> /static/...)<commit_after>use std::io;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;
use diesel::result::Error;
use diesel;
use diesel::*;
use self::models::{ImageLocation, SubmitImageLocation};
use database::schema::image_locations::dsl::*;
use database::schema::image_locations;
use super::database;

pub mod models;

static IMAGE_PATH: &'static str = "/static/media";

pub fn load_image(file_name: String) -> Option<File> {
    let conn = database::get_db_connection();

    let image_location: ImageLocation = match image_locations.filter(name.eq(file_name)).
        first::<ImageLocation>(&*conn) {
        Ok(image_location) => image_location,
        Err(_) => return None,
    };

    match File::open(image_location.url) {
        Ok(file) => Some(file),
        Err(_) => None,
    }
}

/// Uploads the image to the server with the given filename.
/// Returns the identifier of the image.
pub fn store_image(image_name: String, image: Vec<u8>) -> io::Result<String> {
    let file_path: String = format!("{path}/{filename}", path = IMAGE_PATH, filename = image_name);
    let mut file = File::create(Path::new(file_path.as_str())).unwrap();
    file.write(image.as_slice()).unwrap();

    Ok(file_path)
}

pub fn insert_image_location(image_name: String, image_path: String) -> Result<i32, Error> {
    let conn = &*database::get_db_connection();

    let image_location = SubmitImageLocation { name: image_name, url: image_path };

    match diesel::insert(&image_location)
        .into(image_locations)
        .execute(conn) {
        Ok(_) => (),
        Err(e) => return Err(e),
    };

    match image_locations::table
        .order(image_locations::id.desc())
        .first::<ImageLocation>(conn) {
        Ok(img_loc) => Ok(img_loc.id),
        Err(e) => Err(e),
    }
}<|endoftext|>


<commit_before>extern crate breakpad_symbols;
extern crate disasm;
extern crate env_logger;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate log;
extern crate minidump;
extern crate minidump_common;
extern crate reqwest;
#[allow(unused_imports)]
#[macro_use]
extern crate structopt;

use breakpad_symbols::{SimpleFrame, HttpSymbolSupplier, Symbolizer};
use disasm::{Color, CpuArch, SourceLocation, SourceLookup};
use failure::Error;
use minidump_common::traits::Module;
use minidump::{Minidump, MinidumpException, MinidumpMemoryList, MinidumpModule, MinidumpModuleList,
               MinidumpSystemInfo};
use minidump::system_info::Cpu;
use reqwest::Client;
use std::env;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use structopt::StructOpt;

#[derive(StructOpt)]
#[structopt(name = "get-minidump-instructions", about = "Display instructions from a minidump")]
struct GetMinidumpInstructions {
    #[structopt(long = "color", help = "Enable colored output")]
    color: Option<Color>,
    #[structopt(help = "Input minidump", parse(from_os_str))]
    minidump: PathBuf,
    #[structopt(help = "Symbol paths", parse(from_os_str))]
    symbol_paths: Vec<PathBuf>,
}

#[derive(StructOpt)]
#[structopt(name = "dumpstack", about = "Display possible stack frames from a minidump")]
struct DumpStack {
    #[structopt(help = "Input minidump", parse(from_os_str))]
    minidump: PathBuf,
    #[structopt(help = "Symbol paths", parse(from_os_str))]
    symbol_paths: Vec<PathBuf>,
    #[structopt(short = "a", help = "Show stack addresses that don't resolve to functions")]
    all: bool,
}

struct SymLookup {
    modules: MinidumpModuleList,
    symbolizer: Symbolizer,
    client: Client,
}

struct HgWebFile {
    host: String,
    repo: String,
    rev: String,
    path: String,
}

struct GitHubFile {
    repo: String,
    rev: String,
    path: String,
}

trait VCSFile {
    fn raw_url(&self) -> String;
    fn annotate_url(&self, line: u64) -> String;
    fn as_local_filename(&self) -> String;
}

impl VCSFile for HgWebFile {
    fn raw_url(&self) -> String {
        format!("https://{}/{}/raw-file/{}/{}",
                self.host, self.repo, self.rev, self.path)
    }

    fn annotate_url(&self, line: u64) -> String {
        format!("https://{}/{}/annotate/{}/{}#l{}",
                self.host, self.repo, self.rev, self.path, line)
    }
    fn as_local_filename(&self) -> String {
        format!("{}_{}_{}", self.host, self.rev, self.path).replace('/', "_")
    }
}

impl VCSFile for GitHubFile {
    fn raw_url(&self) -> String {
        format!("http://raw.githubusercontent.com/{}/{}/{}", self.repo, self.rev, self.path)
    }
    fn annotate_url(&self, line: u64) -> String {
        format!("https://github.com/{}/blob/{}/{}#L{}", self.repo, self.rev, self.path, line)
    }
    fn as_local_filename(&self) -> String {
        format!("{}_{}_{}", self.repo, self.rev, self.path).replace('/', "_")
    }
}

fn file_exists(path: &Path) -> bool {
    fs::metadata(path).is_ok()
}

fn fetch_url_to_path(client: &Client, url: &str, path: &Path) -> Result<(), Error> {
    debug!("fetch_url_to_path({}, {:?})", url, path);
    let mut res = client.get(url).send()?.error_for_status()?;
    debug!("fetch_url_to_path: HTTP success");
    let mut tmp_path = path.to_owned().into_os_string();
    tmp_path.push(".tmp");
    {
        let mut f = File::create(&tmp_path)?;
        res.copy_to(&mut f)?;
    }
    fs::rename(&tmp_path, &path)?;
    Ok(())
}

fn parse_vcs_info(filename: &str) -> Result<Box<VCSFile>, Error> {
    let mut bits = filename.split(':');
    Ok(match (bits.next(), bits.next(), bits.next(), bits.next()) {
        (Some("hg"), Some(repo), Some(path), Some(rev)) if repo.starts_with("hg.mozilla.org/") => {
            let mut s = repo.splitn(2, '/');
            let host = s.next().unwrap().to_owned();
            let repo = s.next().unwrap().to_owned();
            let path = path.to_owned();
            let rev = rev.to_owned();
            Box::new(HgWebFile {
                host,
                repo,
                rev,
                path,
            })
        }
        (Some("git"), Some(repo), Some(path), Some(rev)) if repo.starts_with("github.com/") => {
            let repo = repo.splitn(2, '/').nth(1).unwrap().to_owned();
            let path = path.to_owned();
            let rev = rev.to_owned();
            Box::new(GitHubFile {
                repo,
                rev,
                path,
            })
        }
        _ => return Err(format_err!("No VCS info in filename")),
    })
}

fn maybe_fetch_source_file(client: &Client, url: &str, path: &Path) -> Result<(), Error> {
    if file_exists(path) {
        Ok(())
    } else {
        fetch_url_to_path(client, url, path)
    }
}

impl SourceLookup for SymLookup {
    fn lookup(&mut self, address: u64) -> Option<SourceLocation> {
        self.modules.module_at_address(address).and_then(|module| {
            let mut frame = SimpleFrame::with_instruction(address);
            self.symbolizer.fill_symbol(module, &mut frame);
            let SimpleFrame { source_file, source_line, .. } = frame;
            if let (Some(file), Some(line)) = (source_file, source_line) {
                let line = line as u64;
                match parse_vcs_info(&file) {
                    Ok(info) => {
                        let url = info.raw_url();
                        let local = env::temp_dir().join(info.as_local_filename());
                        if maybe_fetch_source_file(&self.client, &url, &local).is_ok() {
                            return Some(SourceLocation {
                                file: local.to_string_lossy().into_owned(),
                                file_display: Some(info.annotate_url(line)),
                                line
                            })
                        }
                    }
                    _ => {}
                }
                // If fetching the file doesn't work, just hand back the original filename.
                Some(SourceLocation { file: file.into(), file_display: None, line })
            } else {
                // We didn't find any source info.
                None
            }
        })
    }
}

fn handle_symbol_paths(symbol_paths: Vec<PathBuf>) -> Result<Symbolizer, Error> {
    let tmp_path = env::temp_dir().join("symbols");
    fs::create_dir_all(&tmp_path)?;
    let (symbol_paths, symbol_urls) = if symbol_paths.is_empty() {
        // Use the Mozilla symbol server if no symbol paths are supplied.
        let symbol_urls = vec!["https://symbols.mozilla.org/".to_owned()];
        (symbol_paths, symbol_urls)
    } else {
        let urls = symbol_paths.iter()
            .filter(|p| p.starts_with("http"))
            .filter_map(|p| p.to_str().map(str::to_owned)).collect();
        let paths = symbol_paths.into_iter().filter(|p| !p.starts_with("http")).collect();
        (paths, urls)
    };
    let supplier = HttpSymbolSupplier::new(symbol_urls, tmp_path, symbol_paths);
    Ok(Symbolizer::new(supplier))
}

pub fn get_minidump_instructions() -> Result<(), Error> {
    env_logger::init();
    let GetMinidumpInstructions { color, minidump, symbol_paths } =
        GetMinidumpInstructions::from_args();
    let dump = Minidump::read_path(&minidump)?;
    let modules = dump.get_stream::<MinidumpModuleList>()?;
    let exception = dump.get_stream::<MinidumpException>()?;
    let context = exception.context.as_ref().ok_or(format_err!("Missing exception context"))?;
    let ip = context.get_instruction_pointer();
    let memory_list = dump.get_stream::<MinidumpMemoryList>()?;
    let memory = memory_list.memory_at_address(ip)
        .ok_or(format_err!("Minidump doesn't contain a memory region that contains the instruction pointer from the exception record"))?;
    let sys_info = dump.get_stream::<MinidumpSystemInfo>()?;
    let arch = match sys_info.cpu {
        Cpu::X86 => CpuArch::X86,
        Cpu::X86_64 => CpuArch::X86_64,
        _ => return Err(format_err!("Unsupported CPU architecture: {}", sys_info.cpu)),
    };
    let symbolizer = handle_symbol_paths(symbol_paths)?;
    let client = Client::new();
    let mut lookup = SymLookup { modules, symbolizer, client };
    println!("Faulting instruction pointer: {:#x}", ip);
    info!("Disassembling {} bytes starting at {:#x} of arch {:?}",
          memory.bytes.len(), memory.base_address, arch);
    disasm::disasm_bytes(&memory.bytes,
                         memory.base_address,
                         arch,
                         color.unwrap_or(Color::Auto),
                         Some(ip),
                         &mut lookup)?;
    Ok(())
}

    fn basename(f: &str) -> &str {
        match f.rfind(|c| c == '/' || c == '\\') {
            None => f,
            Some(index) => &f[(index + 1)..],
        }
    }

fn print_frame(module: &MinidumpModule, frame: SimpleFrame) {
    print!("{}", basename(&module.code_file()));
    if let Some(ref func) = frame.function {
        print!("!{}", func);
        if let (Some(ref file), Some(line)) = (frame.source_file, frame.source_line) {
            print!(" [");
            match parse_vcs_info(file) {
                Ok(info) => print!("{}", info.annotate_url(line as u64)),
                _ => print!("{} : {}", basename(file), line),
            }
            if let Some(line_base) = frame.source_line_base {
                print!(" + {}", frame.instruction - line_base);
            }
            print!("]");
        } else if let Some(func_base) = frame.function_base {
            print!(" + {:#x}", frame.instruction - func_base);
        }
    } else {
        print!(" + {:#x}", frame.instruction - module.base_address());
    }
    println!("");
}

pub fn dump_minidump_stack() -> Result<(), Error> {
    env_logger::init();
    let DumpStack { all, minidump, symbol_paths } =
        DumpStack::from_args();
    info!("Reading minidump {:?}", minidump);
    let dump = Minidump::read_path(&minidump)?;
    let symbolizer = handle_symbol_paths(symbol_paths)?;
    let modules = dump.get_stream::<MinidumpModuleList>()?;
    let memory_list = dump.get_stream::<MinidumpMemoryList>()?;
    let sys_info = dump.get_stream::<MinidumpSystemInfo>()?;
    let wordsize = match sys_info.cpu {
        Cpu::X86 | Cpu::Ppc | Cpu::Sparc | Cpu::Arm => 4,
        Cpu::X86_64 | Cpu::Ppc64 | Cpu::Arm64 => 8,
        Cpu::Unknown(u) => bail!("Unknown cpu: {:#x}", u),
    };
    // TODO: provide a commandline option for the address.
    // Default to the top of the crashing stack.
    let exception = dump.get_stream::<MinidumpException>()?;
    let context = exception.context.as_ref().ok_or(format_err!("Missing exception context"))?;
    let sp = context.get_stack_pointer();
    info!("Stack pointer: {:#x}", sp);
    let memory = memory_list.memory_at_address(sp)
        .ok_or_else(|| format_err!("Minidump doesn't contain a memory region that contains address {:#x}", sp))?;
    for addr in (memory.base_address..memory.base_address + memory.size).step_by(wordsize) {
        let instruction = match wordsize {
            4 => memory.get_memory_at_address::<u32>(addr).map(|i| i as u64),
            8 => memory.get_memory_at_address::<u64>(addr),
            _ => unreachable!(),
        };
        if let Some(instruction) = instruction {
            if let Some(module) = modules.module_at_address(instruction) {
                let mut frame = SimpleFrame::with_instruction(instruction);
                symbolizer.fill_symbol(module, &mut frame);
                if frame.function.is_some() || all {
                    print!("{:#0width$x} ", addr, width=wordsize*2);
                    print_frame(module, frame);
                }
            }
        }
    }
    Ok(())
}
<commit_msg>add aarch64 support to get_minidump_instructions<commit_after>extern crate breakpad_symbols;
extern crate disasm;
extern crate env_logger;
#[macro_use]
extern crate failure;
#[macro_use]
extern crate log;
extern crate minidump;
extern crate minidump_common;
extern crate reqwest;
#[allow(unused_imports)]
#[macro_use]
extern crate structopt;

use breakpad_symbols::{SimpleFrame, HttpSymbolSupplier, Symbolizer};
use disasm::{Color, CpuArch, SourceLocation, SourceLookup};
use failure::Error;
use minidump_common::traits::Module;
use minidump::{Minidump, MinidumpException, MinidumpMemoryList, MinidumpModule, MinidumpModuleList,
               MinidumpSystemInfo};
use minidump::system_info::Cpu;
use reqwest::Client;
use std::env;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use structopt::StructOpt;

#[derive(StructOpt)]
#[structopt(name = "get-minidump-instructions", about = "Display instructions from a minidump")]
struct GetMinidumpInstructions {
    #[structopt(long = "color", help = "Enable colored output")]
    color: Option<Color>,
    #[structopt(help = "Input minidump", parse(from_os_str))]
    minidump: PathBuf,
    #[structopt(help = "Symbol paths", parse(from_os_str))]
    symbol_paths: Vec<PathBuf>,
}

#[derive(StructOpt)]
#[structopt(name = "dumpstack", about = "Display possible stack frames from a minidump")]
struct DumpStack {
    #[structopt(help = "Input minidump", parse(from_os_str))]
    minidump: PathBuf,
    #[structopt(help = "Symbol paths", parse(from_os_str))]
    symbol_paths: Vec<PathBuf>,
    #[structopt(short = "a", help = "Show stack addresses that don't resolve to functions")]
    all: bool,
}

struct SymLookup {
    modules: MinidumpModuleList,
    symbolizer: Symbolizer,
    client: Client,
}

struct HgWebFile {
    host: String,
    repo: String,
    rev: String,
    path: String,
}

struct GitHubFile {
    repo: String,
    rev: String,
    path: String,
}

trait VCSFile {
    fn raw_url(&self) -> String;
    fn annotate_url(&self, line: u64) -> String;
    fn as_local_filename(&self) -> String;
}

impl VCSFile for HgWebFile {
    fn raw_url(&self) -> String {
        format!("https://{}/{}/raw-file/{}/{}",
                self.host, self.repo, self.rev, self.path)
    }

    fn annotate_url(&self, line: u64) -> String {
        format!("https://{}/{}/annotate/{}/{}#l{}",
                self.host, self.repo, self.rev, self.path, line)
    }
    fn as_local_filename(&self) -> String {
        format!("{}_{}_{}", self.host, self.rev, self.path).replace('/', "_")
    }
}

impl VCSFile for GitHubFile {
    fn raw_url(&self) -> String {
        format!("http://raw.githubusercontent.com/{}/{}/{}", self.repo, self.rev, self.path)
    }
    fn annotate_url(&self, line: u64) -> String {
        format!("https://github.com/{}/blob/{}/{}#L{}", self.repo, self.rev, self.path, line)
    }
    fn as_local_filename(&self) -> String {
        format!("{}_{}_{}", self.repo, self.rev, self.path).replace('/', "_")
    }
}

fn file_exists(path: &Path) -> bool {
    fs::metadata(path).is_ok()
}

fn fetch_url_to_path(client: &Client, url: &str, path: &Path) -> Result<(), Error> {
    debug!("fetch_url_to_path({}, {:?})", url, path);
    let mut res = client.get(url).send()?.error_for_status()?;
    debug!("fetch_url_to_path: HTTP success");
    let mut tmp_path = path.to_owned().into_os_string();
    tmp_path.push(".tmp");
    {
        let mut f = File::create(&tmp_path)?;
        res.copy_to(&mut f)?;
    }
    fs::rename(&tmp_path, &path)?;
    Ok(())
}

fn parse_vcs_info(filename: &str) -> Result<Box<VCSFile>, Error> {
    let mut bits = filename.split(':');
    Ok(match (bits.next(), bits.next(), bits.next(), bits.next()) {
        (Some("hg"), Some(repo), Some(path), Some(rev)) if repo.starts_with("hg.mozilla.org/") => {
            let mut s = repo.splitn(2, '/');
            let host = s.next().unwrap().to_owned();
            let repo = s.next().unwrap().to_owned();
            let path = path.to_owned();
            let rev = rev.to_owned();
            Box::new(HgWebFile {
                host,
                repo,
                rev,
                path,
            })
        }
        (Some("git"), Some(repo), Some(path), Some(rev)) if repo.starts_with("github.com/") => {
            let repo = repo.splitn(2, '/').nth(1).unwrap().to_owned();
            let path = path.to_owned();
            let rev = rev.to_owned();
            Box::new(GitHubFile {
                repo,
                rev,
                path,
            })
        }
        _ => return Err(format_err!("No VCS info in filename")),
    })
}

fn maybe_fetch_source_file(client: &Client, url: &str, path: &Path) -> Result<(), Error> {
    if file_exists(path) {
        Ok(())
    } else {
        fetch_url_to_path(client, url, path)
    }
}

impl SourceLookup for SymLookup {
    fn lookup(&mut self, address: u64) -> Option<SourceLocation> {
        self.modules.module_at_address(address).and_then(|module| {
            let mut frame = SimpleFrame::with_instruction(address);
            self.symbolizer.fill_symbol(module, &mut frame);
            let SimpleFrame { source_file, source_line, .. } = frame;
            if let (Some(file), Some(line)) = (source_file, source_line) {
                let line = line as u64;
                match parse_vcs_info(&file) {
                    Ok(info) => {
                        let url = info.raw_url();
                        let local = env::temp_dir().join(info.as_local_filename());
                        if maybe_fetch_source_file(&self.client, &url, &local).is_ok() {
                            return Some(SourceLocation {
                                file: local.to_string_lossy().into_owned(),
                                file_display: Some(info.annotate_url(line)),
                                line
                            })
                        }
                    }
                    _ => {}
                }
                // If fetching the file doesn't work, just hand back the original filename.
                Some(SourceLocation { file: file.into(), file_display: None, line })
            } else {
                // We didn't find any source info.
                None
            }
        })
    }
}

fn handle_symbol_paths(symbol_paths: Vec<PathBuf>) -> Result<Symbolizer, Error> {
    let tmp_path = env::temp_dir().join("symbols");
    fs::create_dir_all(&tmp_path)?;
    let (symbol_paths, symbol_urls) = if symbol_paths.is_empty() {
        // Use the Mozilla symbol server if no symbol paths are supplied.
        let symbol_urls = vec!["https://symbols.mozilla.org/".to_owned()];
        (symbol_paths, symbol_urls)
    } else {
        let urls = symbol_paths.iter()
            .filter(|p| p.starts_with("http"))
            .filter_map(|p| p.to_str().map(str::to_owned)).collect();
        let paths = symbol_paths.into_iter().filter(|p| !p.starts_with("http")).collect();
        (paths, urls)
    };
    let supplier = HttpSymbolSupplier::new(symbol_urls, tmp_path, symbol_paths);
    Ok(Symbolizer::new(supplier))
}

pub fn get_minidump_instructions() -> Result<(), Error> {
    env_logger::init();
    let GetMinidumpInstructions { color, minidump, symbol_paths } =
        GetMinidumpInstructions::from_args();
    let dump = Minidump::read_path(&minidump)?;
    let modules = dump.get_stream::<MinidumpModuleList>()?;
    let exception = dump.get_stream::<MinidumpException>()?;
    let context = exception.context.as_ref().ok_or(format_err!("Missing exception context"))?;
    let ip = context.get_instruction_pointer();
    let memory_list = dump.get_stream::<MinidumpMemoryList>()?;
    let memory = memory_list.memory_at_address(ip)
        .ok_or(format_err!("Minidump doesn't contain a memory region that contains the instruction pointer from the exception record"))?;
    let sys_info = dump.get_stream::<MinidumpSystemInfo>()?;
    let arch = match sys_info.cpu {
        Cpu::X86 => CpuArch::X86,
        Cpu::X86_64 => CpuArch::X86_64,
        Cpu::Arm64 => CpuArch::ARM64,
        _ => return Err(format_err!("Unsupported CPU architecture: {}", sys_info.cpu)),
    };
    let symbolizer = handle_symbol_paths(symbol_paths)?;
    let client = Client::new();
    let mut lookup = SymLookup { modules, symbolizer, client };
    println!("Faulting instruction pointer: {:#x}", ip);
    info!("Disassembling {} bytes starting at {:#x} of arch {:?}",
          memory.bytes.len(), memory.base_address, arch);
    disasm::disasm_bytes(&memory.bytes,
                         memory.base_address,
                         arch,
                         color.unwrap_or(Color::Auto),
                         Some(ip),
                         &mut lookup)?;
    Ok(())
}

    fn basename(f: &str) -> &str {
        match f.rfind(|c| c == '/' || c == '\\') {
            None => f,
            Some(index) => &f[(index + 1)..],
        }
    }

fn print_frame(module: &MinidumpModule, frame: SimpleFrame) {
    print!("{}", basename(&module.code_file()));
    if let Some(ref func) = frame.function {
        print!("!{}", func);
        if let (Some(ref file), Some(line)) = (frame.source_file, frame.source_line) {
            print!(" [");
            match parse_vcs_info(file) {
                Ok(info) => print!("{}", info.annotate_url(line as u64)),
                _ => print!("{} : {}", basename(file), line),
            }
            if let Some(line_base) = frame.source_line_base {
                print!(" + {}", frame.instruction - line_base);
            }
            print!("]");
        } else if let Some(func_base) = frame.function_base {
            print!(" + {:#x}", frame.instruction - func_base);
        }
    } else {
        print!(" + {:#x}", frame.instruction - module.base_address());
    }
    println!("");
}

pub fn dump_minidump_stack() -> Result<(), Error> {
    env_logger::init();
    let DumpStack { all, minidump, symbol_paths } =
        DumpStack::from_args();
    info!("Reading minidump {:?}", minidump);
    let dump = Minidump::read_path(&minidump)?;
    let symbolizer = handle_symbol_paths(symbol_paths)?;
    let modules = dump.get_stream::<MinidumpModuleList>()?;
    let memory_list = dump.get_stream::<MinidumpMemoryList>()?;
    let sys_info = dump.get_stream::<MinidumpSystemInfo>()?;
    let wordsize = match sys_info.cpu {
        Cpu::X86 | Cpu::Ppc | Cpu::Sparc | Cpu::Arm => 4,
        Cpu::X86_64 | Cpu::Ppc64 | Cpu::Arm64 => 8,
        Cpu::Unknown(u) => bail!("Unknown cpu: {:#x}", u),
    };
    // TODO: provide a commandline option for the address.
    // Default to the top of the crashing stack.
    let exception = dump.get_stream::<MinidumpException>()?;
    let context = exception.context.as_ref().ok_or(format_err!("Missing exception context"))?;
    let sp = context.get_stack_pointer();
    info!("Stack pointer: {:#x}", sp);
    let memory = memory_list.memory_at_address(sp)
        .ok_or_else(|| format_err!("Minidump doesn't contain a memory region that contains address {:#x}", sp))?;
    for addr in (memory.base_address..memory.base_address + memory.size).step_by(wordsize) {
        let instruction = match wordsize {
            4 => memory.get_memory_at_address::<u32>(addr).map(|i| i as u64),
            8 => memory.get_memory_at_address::<u64>(addr),
            _ => unreachable!(),
        };
        if let Some(instruction) = instruction {
            if let Some(module) = modules.module_at_address(instruction) {
                let mut frame = SimpleFrame::with_instruction(instruction);
                symbolizer.fill_symbol(module, &mut frame);
                if frame.function.is_some() || all {
                    print!("{:#0width$x} ", addr, width=wordsize*2);
                    print_frame(module, frame);
                }
            }
        }
    }
    Ok(())
}
<|endoftext|>


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

extern crate env_logger;
extern crate euclid;

use gleam::gl;
use glutin::{self, GlContext};
use std::env;
use std::path::PathBuf;
use webrender;
use winit;
use webrender::api::*;

struct Notifier {
    events_proxy: winit::EventsLoopProxy,
}

impl Notifier {
    fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
        Notifier { events_proxy }
    }
}

impl RenderNotifier for Notifier {
    fn clone(&self) -> Box<RenderNotifier> {
        Box::new(Notifier {
            events_proxy: self.events_proxy.clone(),
        })
    }

    fn wake_up(&self) {
        #[cfg(not(target_os = "android"))]
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: DocumentId,
                       _scrolled: bool,
                       _composite_needed: bool,
                       _render_time: Option<u64>) {
        self.wake_up();
    }
}

pub trait HandyDandyRectBuilder {
    fn to(&self, x2: i32, y2: i32) -> LayoutRect;
    fn by(&self, w: i32, h: i32) -> LayoutRect;
}
// Allows doing `(x, y).to(x2, y2)` or `(x, y).by(width, height)` with i32
// values to build a f32 LayoutRect
impl HandyDandyRectBuilder for (i32, i32) {
    fn to(&self, x2: i32, y2: i32) -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(self.0 as f32, self.1 as f32),
            LayoutSize::new((x2 - self.0) as f32, (y2 - self.1) as f32),
        )
    }

    fn by(&self, w: i32, h: i32) -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(self.0 as f32, self.1 as f32),
            LayoutSize::new(w as f32, h as f32),
        )
    }
}

pub trait Example {
    const TITLE: &'static str = "WebRender Sample App";
    const PRECACHE_SHADERS: bool = false;
    const WIDTH: u32 = 1920;
    const HEIGHT: u32 = 1080;

    fn render(
        &mut self,
        api: &RenderApi,
        builder: &mut DisplayListBuilder,
        txn: &mut Transaction,
        framebuffer_size: DeviceUintSize,
        pipeline_id: PipelineId,
        document_id: DocumentId,
    );
    fn on_event(&mut self, winit::WindowEvent, &RenderApi, DocumentId) -> bool {
        false
    }
    fn get_image_handlers(
        &mut self,
        _gl: &gl::Gl,
    ) -> (Option<Box<webrender::ExternalImageHandler>>,
          Option<Box<webrender::OutputImageHandler>>) {
        (None, None)
    }
    fn draw_custom(&self, _gl: &gl::Gl) {
    }
}

pub fn main_wrapper<E: Example>(
    example: &mut E,
    options: Option<webrender::RendererOptions>,
) {
    env_logger::init();

    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let mut events_loop = winit::EventsLoop::new();
    let context_builder = glutin::ContextBuilder::new()
        .with_gl(glutin::GlRequest::GlThenGles {
            opengl_version: (3, 2),
            opengles_version: (3, 0),
        });
    let window_builder = winit::WindowBuilder::new()
        .with_title(E::TITLE)
        .with_multitouch()
        .with_dimensions(winit::dpi::LogicalSize::new(E::WIDTH as f64, E::HEIGHT as f64));
    let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop)
        .unwrap();

    unsafe {
        window.make_current().ok();
    }

    let gl = match window.get_api() {
        glutin::Api::OpenGl => unsafe {
            gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
        },
        glutin::Api::OpenGlEs => unsafe {
            gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
        },
        glutin::Api::WebGl => unimplemented!(),
    };

    println!("OpenGL version {}", gl.get_string(gl::VERSION));
    println!("Shader resource path: {:?}", res_path);
    let device_pixel_ratio = window.get_hidpi_factor() as f32;
    println!("Device pixel ratio: {}", device_pixel_ratio);

    println!("Loading shaders...");
    let opts = webrender::RendererOptions {
        resource_override_path: res_path,
        precache_shaders: E::PRECACHE_SHADERS,
        device_pixel_ratio,
        clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
        //scatter_gpu_cache_updates: false,
        debug_flags: webrender::DebugFlags::ECHO_DRIVER_MESSAGES,
        ..options.unwrap_or(webrender::RendererOptions::default())
    };

    let framebuffer_size = {
        let size = window.get_inner_size().unwrap();
        DeviceUintSize::new(size.width as u32, size.height as u32)
    };
    let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
    let (mut renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts).unwrap();
    let api = sender.create_api();
    let document_id = api.add_document(framebuffer_size, 0);

    let (external, output) = example.get_image_handlers(&*gl);

    if let Some(output_image_handler) = output {
        renderer.set_output_image_handler(output_image_handler);
    }

    if let Some(external_image_handler) = external {
        renderer.set_external_image_handler(external_image_handler);
    }

    let epoch = Epoch(0);
    let pipeline_id = PipelineId(0, 0);
    let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
    let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
    let mut txn = Transaction::new();

    example.render(
        &api,
        &mut builder,
        &mut txn,
        framebuffer_size,
        pipeline_id,
        document_id,
    );
    txn.set_display_list(
        epoch,
        None,
        layout_size,
        builder.finalize(),
        true,
    );
    txn.set_root_pipeline(pipeline_id);
    txn.generate_frame();
    api.send_transaction(document_id, txn);

    println!("Entering event loop");
    events_loop.run_forever(|global_event| {
        let mut txn = Transaction::new();
        let mut custom_event = true;

        match global_event {
            winit::Event::WindowEvent {
                event: winit::WindowEvent::CloseRequested,
                ..
            } => return winit::ControlFlow::Break,
            winit::Event::WindowEvent {
                event: winit::WindowEvent::KeyboardInput {
                    input: winit::KeyboardInput {
                        state: winit::ElementState::Pressed,
                        virtual_keycode: Some(key),
                        ..
                    },
                    ..
                },
                ..
            } => match key {
                winit::VirtualKeyCode::Escape => return winit::ControlFlow::Break,
                winit::VirtualKeyCode::P => renderer.toggle_debug_flags(webrender::DebugFlags::PROFILER_DBG),
                winit::VirtualKeyCode::O => renderer.toggle_debug_flags(webrender::DebugFlags::RENDER_TARGET_DBG),
                winit::VirtualKeyCode::I => renderer.toggle_debug_flags(webrender::DebugFlags::TEXTURE_CACHE_DBG),
                winit::VirtualKeyCode::S => renderer.toggle_debug_flags(webrender::DebugFlags::COMPACT_PROFILER),
                winit::VirtualKeyCode::Q => renderer.toggle_debug_flags(
                    webrender::DebugFlags::GPU_TIME_QUERIES | webrender::DebugFlags::GPU_SAMPLE_QUERIES
                ),
                winit::VirtualKeyCode::Key1 => txn.set_window_parameters(
                    framebuffer_size,
                    DeviceUintRect::new(DeviceUintPoint::zero(), framebuffer_size),
                    1.0
                ),
                winit::VirtualKeyCode::Key2 => txn.set_window_parameters(
                    framebuffer_size,
                    DeviceUintRect::new(DeviceUintPoint::zero(), framebuffer_size),
                    2.0
                ),
                winit::VirtualKeyCode::M => api.notify_memory_pressure(),
                #[cfg(feature = "capture")]
                winit::VirtualKeyCode::C => {
                    let path: PathBuf = "../captures/example".into();
                    //TODO: switch between SCENE/FRAME capture types
                    // based on "shift" modifier, when `glutin` is updated.
                    let bits = CaptureBits::all();
                    api.save_capture(path, bits);
                },
                _ => {
                    let win_event = match global_event {
                        winit::Event::WindowEvent { event, .. } => event,
                        _ => unreachable!()
                    };
                    custom_event = example.on_event(win_event, &api, document_id)
                },
            },
            winit::Event::WindowEvent { event, .. } => custom_event = example.on_event(event, &api, document_id),
            _ => return winit::ControlFlow::Continue,
        };

        if custom_event {
            let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);

            example.render(
                &api,
                &mut builder,
                &mut txn,
                framebuffer_size,
                pipeline_id,
                document_id,
            );
            txn.set_display_list(
                epoch,
                None,
                layout_size,
                builder.finalize(),
                true,
            );
            txn.generate_frame();
        }
        api.send_transaction(document_id, txn);

        renderer.update();
        renderer.render(framebuffer_size).unwrap();
        let _ = renderer.flush_pipeline_info();
        example.draw_custom(&*gl);
        window.swap_buffers().ok();

        winit::ControlFlow::Continue
    });

    renderer.deinit();
}
<commit_msg>fix: proper framebuffer size<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate env_logger;
extern crate euclid;

use gleam::gl;
use glutin::{self, GlContext};
use std::env;
use std::path::PathBuf;
use webrender;
use winit;
use webrender::api::*;

struct Notifier {
    events_proxy: winit::EventsLoopProxy,
}

impl Notifier {
    fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
        Notifier { events_proxy }
    }
}

impl RenderNotifier for Notifier {
    fn clone(&self) -> Box<RenderNotifier> {
        Box::new(Notifier {
            events_proxy: self.events_proxy.clone(),
        })
    }

    fn wake_up(&self) {
        #[cfg(not(target_os = "android"))]
        let _ = self.events_proxy.wakeup();
    }

    fn new_frame_ready(&self,
                       _: DocumentId,
                       _scrolled: bool,
                       _composite_needed: bool,
                       _render_time: Option<u64>) {
        self.wake_up();
    }
}

pub trait HandyDandyRectBuilder {
    fn to(&self, x2: i32, y2: i32) -> LayoutRect;
    fn by(&self, w: i32, h: i32) -> LayoutRect;
}
// Allows doing `(x, y).to(x2, y2)` or `(x, y).by(width, height)` with i32
// values to build a f32 LayoutRect
impl HandyDandyRectBuilder for (i32, i32) {
    fn to(&self, x2: i32, y2: i32) -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(self.0 as f32, self.1 as f32),
            LayoutSize::new((x2 - self.0) as f32, (y2 - self.1) as f32),
        )
    }

    fn by(&self, w: i32, h: i32) -> LayoutRect {
        LayoutRect::new(
            LayoutPoint::new(self.0 as f32, self.1 as f32),
            LayoutSize::new(w as f32, h as f32),
        )
    }
}

pub trait Example {
    const TITLE: &'static str = "WebRender Sample App";
    const PRECACHE_SHADERS: bool = false;
    const WIDTH: u32 = 1920;
    const HEIGHT: u32 = 1080;

    fn render(
        &mut self,
        api: &RenderApi,
        builder: &mut DisplayListBuilder,
        txn: &mut Transaction,
        framebuffer_size: DeviceUintSize,
        pipeline_id: PipelineId,
        document_id: DocumentId,
    );
    fn on_event(&mut self, winit::WindowEvent, &RenderApi, DocumentId) -> bool {
        false
    }
    fn get_image_handlers(
        &mut self,
        _gl: &gl::Gl,
    ) -> (Option<Box<webrender::ExternalImageHandler>>,
          Option<Box<webrender::OutputImageHandler>>) {
        (None, None)
    }
    fn draw_custom(&self, _gl: &gl::Gl) {
    }
}

pub fn main_wrapper<E: Example>(
    example: &mut E,
    options: Option<webrender::RendererOptions>,
) {
    env_logger::init();

    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let mut events_loop = winit::EventsLoop::new();
    let context_builder = glutin::ContextBuilder::new()
        .with_gl(glutin::GlRequest::GlThenGles {
            opengl_version: (3, 2),
            opengles_version: (3, 0),
        });
    let window_builder = winit::WindowBuilder::new()
        .with_title(E::TITLE)
        .with_multitouch()
        .with_dimensions(winit::dpi::LogicalSize::new(E::WIDTH as f64, E::HEIGHT as f64));
    let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop)
        .unwrap();

    unsafe {
        window.make_current().ok();
    }

    let gl = match window.get_api() {
        glutin::Api::OpenGl => unsafe {
            gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
        },
        glutin::Api::OpenGlEs => unsafe {
            gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
        },
        glutin::Api::WebGl => unimplemented!(),
    };

    println!("OpenGL version {}", gl.get_string(gl::VERSION));
    println!("Shader resource path: {:?}", res_path);
    let device_pixel_ratio = window.get_hidpi_factor() as f32;
    println!("Device pixel ratio: {}", device_pixel_ratio);

    println!("Loading shaders...");
    let opts = webrender::RendererOptions {
        resource_override_path: res_path,
        precache_shaders: E::PRECACHE_SHADERS,
        device_pixel_ratio,
        clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)),
        //scatter_gpu_cache_updates: false,
        debug_flags: webrender::DebugFlags::ECHO_DRIVER_MESSAGES,
        ..options.unwrap_or(webrender::RendererOptions::default())
    };

    let framebuffer_size = {
        let size = window
            .get_inner_size()
            .unwrap()
            .to_physical(device_pixel_ratio as f64);
        DeviceUintSize::new(size.width as u32, size.height as u32)
    };
    let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
    let (mut renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts).unwrap();
    let api = sender.create_api();
    let document_id = api.add_document(framebuffer_size, 0);

    let (external, output) = example.get_image_handlers(&*gl);

    if let Some(output_image_handler) = output {
        renderer.set_output_image_handler(output_image_handler);
    }

    if let Some(external_image_handler) = external {
        renderer.set_external_image_handler(external_image_handler);
    }

    let epoch = Epoch(0);
    let pipeline_id = PipelineId(0, 0);
    let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
    let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
    let mut txn = Transaction::new();

    example.render(
        &api,
        &mut builder,
        &mut txn,
        framebuffer_size,
        pipeline_id,
        document_id,
    );
    txn.set_display_list(
        epoch,
        None,
        layout_size,
        builder.finalize(),
        true,
    );
    txn.set_root_pipeline(pipeline_id);
    txn.generate_frame();
    api.send_transaction(document_id, txn);

    println!("Entering event loop");
    events_loop.run_forever(|global_event| {
        let mut txn = Transaction::new();
        let mut custom_event = true;

        match global_event {
            winit::Event::WindowEvent {
                event: winit::WindowEvent::CloseRequested,
                ..
            } => return winit::ControlFlow::Break,
            winit::Event::WindowEvent {
                event: winit::WindowEvent::KeyboardInput {
                    input: winit::KeyboardInput {
                        state: winit::ElementState::Pressed,
                        virtual_keycode: Some(key),
                        ..
                    },
                    ..
                },
                ..
            } => match key {
                winit::VirtualKeyCode::Escape => return winit::ControlFlow::Break,
                winit::VirtualKeyCode::P => renderer.toggle_debug_flags(webrender::DebugFlags::PROFILER_DBG),
                winit::VirtualKeyCode::O => renderer.toggle_debug_flags(webrender::DebugFlags::RENDER_TARGET_DBG),
                winit::VirtualKeyCode::I => renderer.toggle_debug_flags(webrender::DebugFlags::TEXTURE_CACHE_DBG),
                winit::VirtualKeyCode::S => renderer.toggle_debug_flags(webrender::DebugFlags::COMPACT_PROFILER),
                winit::VirtualKeyCode::Q => renderer.toggle_debug_flags(
                    webrender::DebugFlags::GPU_TIME_QUERIES | webrender::DebugFlags::GPU_SAMPLE_QUERIES
                ),
                winit::VirtualKeyCode::Key1 => txn.set_window_parameters(
                    framebuffer_size,
                    DeviceUintRect::new(DeviceUintPoint::zero(), framebuffer_size),
                    1.0
                ),
                winit::VirtualKeyCode::Key2 => txn.set_window_parameters(
                    framebuffer_size,
                    DeviceUintRect::new(DeviceUintPoint::zero(), framebuffer_size),
                    2.0
                ),
                winit::VirtualKeyCode::M => api.notify_memory_pressure(),
                #[cfg(feature = "capture")]
                winit::VirtualKeyCode::C => {
                    let path: PathBuf = "../captures/example".into();
                    //TODO: switch between SCENE/FRAME capture types
                    // based on "shift" modifier, when `glutin` is updated.
                    let bits = CaptureBits::all();
                    api.save_capture(path, bits);
                },
                _ => {
                    let win_event = match global_event {
                        winit::Event::WindowEvent { event, .. } => event,
                        _ => unreachable!()
                    };
                    custom_event = example.on_event(win_event, &api, document_id)
                },
            },
            winit::Event::WindowEvent { event, .. } => custom_event = example.on_event(event, &api, document_id),
            _ => return winit::ControlFlow::Continue,
        };

        if custom_event {
            let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);

            example.render(
                &api,
                &mut builder,
                &mut txn,
                framebuffer_size,
                pipeline_id,
                document_id,
            );
            txn.set_display_list(
                epoch,
                None,
                layout_size,
                builder.finalize(),
                true,
            );
            txn.generate_frame();
        }
        api.send_transaction(document_id, txn);

        renderer.update();
        renderer.render(framebuffer_size).unwrap();
        let _ = renderer.flush_pipeline_info();
        example.draw_custom(&*gl);
        window.swap_buffers().ok();

        winit::ControlFlow::Continue
    });

    renderer.deinit();
}
<|endoftext|>


<commit_before>use super::{Index, Range};
use small;
use std::{cmp::Ordering, u8};

fn numeric_range<'a>(
    start: isize,
    end: isize,
    step: isize,
    inclusive: bool,
    nb_digits: usize,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };

    if step == 0 || (start < end && step < 0) || (start > end && step > 0) {
        None
    } else {
        let (x, y, ordering) = if start < end {
            (start, end, Ordering::Greater)
        } else {
            (end, start, Ordering::Less)
        };

        let iter = (x..y).scan(start, move |index, _| {
            if end.cmp(index) == ordering {
                let index_holder = *index;
                *index += step; // This step adds
                Some(format!("{:0width$}", index_holder, width = nb_digits).into())
            } else {
                None
            }
        });

        Some(Box::new(iter))
    }
}

#[inline]
fn byte_is_valid_range(b: u8) -> bool { (b >= b'a' && b <= b'z') || (b >= b'A' && b <= b'Z') }

fn char_range<'a>(
    start: u8,
    end: u8,
    step: isize,
    inclusive: bool,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let char_step = step.checked_abs()?;
    if !byte_is_valid_range(start) || !byte_is_valid_range(end) || step == 0 || char_step > u8::MAX as isize {
        return None;
    }

    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };
    let (x, y, ordering) = if start < end {
        (start, end, Ordering::Greater)
    } else {
        (end, start, Ordering::Less)
    };

    let iter = (x..y).scan(start, move |index, _| {
        if end.cmp(index) == ordering {
            let index_holder = *index;
            *index = match ordering {
                Ordering::Greater => index.wrapping_add(char_step as u8),
                Ordering::Less => index.wrapping_sub(char_step as u8),
                _ => unreachable!(),
            };
            Some((index_holder as char).to_string().into())
        } else {
            None
        }
    });

    Some(Box::new(iter))
}

fn count_minimum_digits(a: &str) -> usize {
    for c in a.chars() {
        match c {
            '-' => (),
            '0' => return a.len(),
            '1'...'9' => break,
            _ => panic!("count_minimum_digits should only be called for a valid number."),
        }
    }
    0
}

fn finish(inclusive: bool, start_str: &str, end_str: &str, step: isize) -> Option<Box<Iterator<Item = small::String>>> {
    if let (Ok(start), Ok(end)) = (start_str.parse::<isize>(), end_str.parse::<isize>())  {
        let step = if step == 1 {
            if start < end { step } else { -step }
        } else {
            step
        };
        let nb_digits = usize::max(count_minimum_digits(start_str), count_minimum_digits(end_str));
        numeric_range(start, end, step, inclusive, nb_digits)
    } else {
        char_range(start_str.bytes().next()?, end_str.bytes().next()?, step, inclusive)
    }
}

// TODO: Make this an iterator structure.
// In a range we allow the following syntax:
//      Exclusive nonstepped: {start..end}
//      Inclusive nonstepped: {start...end}
//      Exclusive stepped: {start..step..end}
//      Inclusive stepped: {start..step...end}
pub fn parse_range(input: &str) -> Option<Box<Iterator<Item = small::String>>> {
    let mut read = 0;
    let mut bytes_iterator = input.bytes();
    while let Some(byte) = bytes_iterator.next() {
        match byte {
            // can only find these as the first byte, otherwise the syntax is bad
            b'a'...b'z' | b'-' | b'A'...b'Z' if read == 0 => read += 1,
            b'0'...b'9' => read += 1,
            b'.' => {
                let start_str = &input[..read];
                read += 1;
                // The next byte has to be a dot to be valid range
                // syntax
                match bytes_iterator.next() {
                    Some(b'.') => read += 1,
                    _ => return None,
                }

                // if the next byte is a dot we're certain it is an inclusive
                // unstepped range otherwise it has to be [-0-9a-zA-Z]
                if let Some(b) = bytes_iterator.next() {
                    read += 1;
                    match b {
                        b'.' | b'=' => {
                            // this can only be an inclusive range
                            return finish(true, start_str, &input[read..], 1);
                        }
                        b'0'...b'9' | b'-' | b'a'...b'z' | b'A'...b'Z' => {
                            // further processing needed to find out if we're reading a step or
                            // the end of an exclusive range. Step until we find another dot or
                            // the iterator ends
                            let start = read - 1;
                            while let Some(b) = bytes_iterator.next() {
                                read += 1;
                                match b {
                                    b'.' => {
                                        // stepped range input[start..read - 1] contains the step
                                        // size
                                        let step = (&input[start..read - 1]).parse::<isize>().ok()?;
                                        // count the dots to determine inclusive/exclusive
                                        let mut dots = 1;
                                        while let Some(b) = bytes_iterator.next() {
                                            read += 1;
                                            match b {
                                                b'.' => dots += 1,
                                                _ => break,
                                            }
                                        }
                                        return finish(dots == 3, start_str, &input[read - 1..], step);
                                    }
                                    // numeric values are OK but no letters anymore
                                    b'0'...b'9' => {}
                                    // unexpected
                                    _ => return None,
                                }
                            }
                            // exhausted the iterator without finding anything new means
                            // exclusive unstepped range
                            return finish(false, start_str, &input[start..], 1);
                        }
                        // not a valid byte for ranges
                        _ => return None,
                    }
                }
            }
            _ => break,
        }
    }
    None
}

pub fn parse_index_range(input: &str) -> Option<Range> {
    let mut bytes_iterator = input.bytes().enumerate();
    while let Some((id, byte)) = bytes_iterator.next() {
        match byte {
            b'0'...b'9' | b'-' => continue,
            b'.' => {
                let first = &input[..id];

                let mut dots = 1;
                let mut last_byte = 0;

                for (_, byte) in bytes_iterator {
                    last_byte = byte;
                    if byte == b'.' {
                        dots += 1
                    } else {
                        break;
                    }
                }

                if dots < 2 || dots > 3 {
                    break;
                }

                let inclusive = dots == 3 || (dots == 2 && last_byte == b'=');

                let end = &input[id + if inclusive { 3 } else { 2 }..];

                return if first.is_empty() && !end.is_empty() {
                    end.parse::<isize>().map(|end| Range::to(Index::new(end))).ok()
                } else if end.is_empty() {
                    first.parse::<isize>().map(|start| Range::from(Index::new(start))).ok()
                } else {
                    first
                        .parse::<isize>()
                        .and_then(|start| end.parse::<isize>().map(|end| (start, end)))
                        .map(|(start, end)| {
                            if inclusive {
                                Range::inclusive(Index::new(start), Index::new(end))
                            } else {
                                Range::exclusive(Index::new(start), Index::new(end))
                            }
                        })
                        .ok()
                };

            }
            _ => break,
        }
    }

    None
}
<commit_msg>Refactor range parsing to remove returns and reduce nesting<commit_after>use super::{Index, Range};
use small;
use std::{cmp::Ordering, u8};

fn numeric_range<'a>(
    start: isize,
    end: isize,
    step: isize,
    inclusive: bool,
    nb_digits: usize,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };

    if step == 0 || (start < end && step < 0) || (start > end && step > 0) {
        None
    } else {
        let (x, y, ordering) = if start < end {
            (start, end, Ordering::Greater)
        } else {
            (end, start, Ordering::Less)
        };

        let iter = (x..y).scan(start, move |index, _| {
            if end.cmp(index) == ordering {
                let index_holder = *index;
                *index += step; // This step adds
                Some(format!("{:0width$}", index_holder, width = nb_digits).into())
            } else {
                None
            }
        });

        Some(Box::new(iter))
    }
}

#[inline]
fn byte_is_valid_range(b: u8) -> bool { (b >= b'a' && b <= b'z') || (b >= b'A' && b <= b'Z') }

fn char_range<'a>(
    start: u8,
    end: u8,
    step: isize,
    inclusive: bool,
) -> Option<Box<Iterator<Item = small::String> + 'a>> {
    let char_step = step.checked_abs()?;
    if !byte_is_valid_range(start) || !byte_is_valid_range(end) || step == 0 || char_step > u8::MAX as isize {
        return None;
    }

    let end = if start < end && inclusive {
        end + 1
    } else if start > end && inclusive {
        end - 1
    } else {
        end
    };
    let (x, y, ordering) = if start < end {
        (start, end, Ordering::Greater)
    } else {
        (end, start, Ordering::Less)
    };

    let iter = (x..y).scan(start, move |index, _| {
        if end.cmp(index) == ordering {
            let index_holder = *index;
            *index = match ordering {
                Ordering::Greater => index.wrapping_add(char_step as u8),
                Ordering::Less => index.wrapping_sub(char_step as u8),
                _ => unreachable!(),
            };
            Some((index_holder as char).to_string().into())
        } else {
            None
        }
    });

    Some(Box::new(iter))
}

fn count_minimum_digits(a: &str) -> usize {
    for c in a.chars() {
        match c {
            '-' => (),
            '0' => return a.len(),
            '1'...'9' => break,
            _ => panic!("count_minimum_digits should only be called for a valid number."),
        }
    }
    0
}

fn finish(inclusive: bool, start_str: &str, end_str: &str, step: isize) -> Option<Box<Iterator<Item = small::String>>> {
    if let (Ok(start), Ok(end)) = (start_str.parse::<isize>(), end_str.parse::<isize>())  {
        let step = if step == 1 {
            if start < end { step } else { -step }
        } else {
            step
        };
        let nb_digits = usize::max(count_minimum_digits(start_str), count_minimum_digits(end_str));
        numeric_range(start, end, step, inclusive, nb_digits)
    } else {
        char_range(start_str.bytes().next()?, end_str.bytes().next()?, step, inclusive)
    }
}

// TODO: Make this an iterator structure.
// In a range we allow the following syntax:
//      Exclusive nonstepped: {start..end}
//      Inclusive nonstepped: {start...end}
//      Exclusive stepped: {start..step..end}
//      Inclusive stepped: {start..step...end}
pub fn parse_range(input: &str) -> Option<Box<Iterator<Item = small::String>>> {
    let mut bytes_iterator = input.bytes().enumerate();
    let separator = bytes_iterator.by_ref().take_while(|&(i, b)| match b {
        b'a'...b'z' | b'-' | b'A'...b'Z' if i == 0 => true,
        b'0'...b'9' | b'.' => true,
        _ => false,
    }).position(|(_, b)| b == b'.')?;
    let start_str = &input[..separator];
    // The next byte has to be a dot to be valid range
    // syntax
    bytes_iterator.next().filter(|&(_, b)| b == b'.')?;

    // if the next byte is a dot we're certain it is an inclusive
    // unstepped range otherwise it has to be [-0-9a-zA-Z]
    bytes_iterator.next().and_then(|(i, b)| match b {
        b'.' | b'=' => {
            // this can only be an inclusive range
            finish(true, start_str, &input[i+1..], 1)
        }
        b'0'...b'9' | b'-' | b'a'...b'z' | b'A'...b'Z' => {
            // further processing needed to find out if we're reading a step or
            // the end of an exclusive range. Step until we find another dot or
            // the iterator ends
            let start = i;
            if let Some(end) = bytes_iterator.position(|(_, b)| b == b'.') {
                // stepped range input[start..read - 1] contains the step
                // size
                let step = (&input[start..end]).parse::<isize>().ok()?;
                // count the dots to determine inclusive/exclusive
                let dots = bytes_iterator.take_while(|&(_, b)| b == b'.').count();
                finish(dots == 2, start_str, &input[i..], step)
            } else {
                // exhausted the iterator without finding anything new means
                // exclusive unstepped range
                finish(false, start_str, &input[start..], 1)
            }
        }
        // not a valid byte for ranges
        _ => None,
    })
}

pub fn parse_index_range(input: &str) -> Option<Range> {
    let mut bytes_iterator = input.bytes().enumerate();
    while let Some((id, byte)) = bytes_iterator.next() {
        match byte {
            b'0'...b'9' | b'-' => continue,
            b'.' => {
                let first = &input[..id];

                let mut dots = 1;
                let mut last_byte = 0;

                for (_, byte) in bytes_iterator {
                    last_byte = byte;
                    if byte == b'.' {
                        dots += 1
                    } else {
                        break;
                    }
                }

                if dots < 2 || dots > 3 {
                    break;
                }

                let inclusive = dots == 3 || (dots == 2 && last_byte == b'=');

                let end = &input[id + if inclusive { 3 } else { 2 }..];

                return if first.is_empty() && !end.is_empty() {
                    end.parse::<isize>().map(|end| Range::to(Index::new(end))).ok()
                } else if end.is_empty() {
                    first.parse::<isize>().map(|start| Range::from(Index::new(start))).ok()
                } else {
                    first
                        .parse::<isize>()
                        .and_then(|start| end.parse::<isize>().map(|end| (start, end)))
                        .map(|(start, end)| {
                            if inclusive {
                                Range::inclusive(Index::new(start), Index::new(end))
                            } else {
                                Range::exclusive(Index::new(start), Index::new(end))
                            }
                        })
                        .ok()
                };

            }
            _ => break,
        }
    }

    None
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate seahash;

#[bench]
fn gigabyte(b: &mut test::Bencher) {
    b.iter(|| {
        let mut x = 0;
        let mut buf = [15; 4096];

        for _ in 0..250000 {
            x ^= seahash::hash(&buf);
            buf[x as usize % 4096] += 1;
        }

        x
    })
}
<commit_msg>Make the benchmarking cheaper (more accurate).<commit_after>#![feature(test)]

extern crate test;
extern crate seahash;

#[bench]
fn gigabyte(b: &mut test::Bencher) {
    b.iter(|| {
        let mut x = 0;
        let mut buf = [15; 4096];

        for _ in 0..250000 {
            x ^= seahash::hash(&buf);
            buf[0] += buf[0].wrapping_add(1);
        }

        x
    })
}
<|endoftext|>


<commit_before>use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};

fn main() {
    let args = env::args_os()
        .skip(1)
        .filter(|arg| arg != "--quiet")
        .collect::<Vec<_>>();
    assert_eq!(args.len(), 1);
    let test = PathBuf::from(&args[0]);
    let dst = Path::new("/data/local/tmp").join(test.file_name().unwrap());

    let status = Command::new("adb")
        .arg("wait-for-device")
        .status()
        .expect("failed to run: adb wait-for-device");
    assert!(status.success());

    let status = Command::new("adb")
        .arg("push")
        .arg(&test)
        .arg(&dst)
        .status()
        .expect("failed to run: adb pushr");
    assert!(status.success());

    let output = Command::new("adb")
        .arg("shell")
        .arg("RUST_BACKTRACE=1")
        .arg(&dst)
        .output()
        .expect("failed to run: adb shell");
    assert!(status.success());

    println!("status: {}\nstdout ---\n{}\nstderr ---\n{}",
             output.status,
             String::from_utf8_lossy(&output.stdout),
             String::from_utf8_lossy(&output.stderr));

    let stdout = String::from_utf8_lossy(&output.stdout);
    stdout.lines().find(|l|
        (l.starts_with("PASSED ") && l.contains(" tests")) ||
        l.starts_with("test result: ok")
    ).unwrap_or_else(|| {
        panic!("failed to find successful test run");
    });
}
<commit_msg>ci: Read test output from stderr<commit_after>use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};

fn main() {
    let args = env::args_os()
        .skip(1)
        .filter(|arg| arg != "--quiet")
        .collect::<Vec<_>>();
    assert_eq!(args.len(), 1);
    let test = PathBuf::from(&args[0]);
    let dst = Path::new("/data/local/tmp").join(test.file_name().unwrap());

    let status = Command::new("adb")
        .arg("wait-for-device")
        .status()
        .expect("failed to run: adb wait-for-device");
    assert!(status.success());

    let status = Command::new("adb")
        .arg("push")
        .arg(&test)
        .arg(&dst)
        .status()
        .expect("failed to run: adb push");
    assert!(status.success());

    let output = Command::new("adb")
        .arg("shell")
        .arg("RUST_BACKTRACE=1")
        .arg(&dst)
        .output()
        .expect("failed to run: adb shell");
    assert!(status.success());

    let stdout = String::from_utf8_lossy(&output.stdout);
    let stderr = String::from_utf8_lossy(&output.stderr);

    println!("status: {}\nstdout ---\n{}\nstderr ---\n{}",
             output.status,
             stdout,
             stderr);

    if !stderr.lines().any(|l| (l.starts_with("PASSED ") && l.contains(" tests")) || l.starts_with("test result: ok"))
        && !stdout.lines().any(|l| (l.starts_with("PASSED ") && l.contains(" tests")) || l.starts_with("test result: ok"))
    {
        panic!("failed to find successful test run");
    };
}
<|endoftext|>