<commit_before>use geomorph::add_cache_chunk;
use {Overland, Dungeon};

// Geomorph data.

/*
1######B222 Template for herringbone prefabs
1##########
1########## Cells at positions A, B and C must have an open tile.
A########## On each half, the openings A, B and C must be connected.
########### The two halves may or may not be connected.
########### This ensures automatic map connectivity, while not
########### making the map trivially open.
##########B
##########2 The numbered lines are parameters by which the openings
##########2 are positioned. When changing the position of an opening
##########2 for an alternative set, lines with the same symbol must
3*********1 remain at equal length.
3*********1
3*********1
3*********A
3**********
C**********
***********
***********
***********
***********
33333C*****
*/

/// Initialize global geomorph cache.
pub fn init_geomorphs() {
    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%%%%%,%%%
%%%%%%%,%%%
,,,%%%,,%%%
%%,,,,,%%%%
%%,%,,,%%%%
%%%,,%,%%%%
%%%%%%%,,,,
%%%%%%%,%%%
%%%%%%%%%%%
%%%%%%%%%%%
%%%%%%%%%%%
%%%%%%%%%%%
%%%%%%%,%%%
%%%%%%,,,,,
%%%%%,,%%%%
,,,,%,,%%%%
%%%,,,%%%%%
%%%,,%%%%%%
%%%%,%%%%%%
%%%%,%%%%%%
%%%%%,%%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%%%%,,%%%
%%%%,,,%%%%
,,,%%,,%%%%
%%,,%%,,%%%
%%%%,,,%%%%
%%%%,,%%%%%
%%%%,,%%,,,
%%%%%,,,,%%
%%%%%,,%%%%
%%%,,,%%%%%
%%%%,,%%%%%
%%%%,,%%%%%
%%%%,%%%%%%
%%%%,,%,,,,
%%%%%%,,%%%
,,%%%,,%%%%
%%,,,,%%%%%
%%%%,,%%%%%
%%%%%,,%%%%
%%%%%,,%%%%
%%%%%,%%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%,,,%%%
%%,,,,,,,%%
%,,,%,,,,,%
,,,,,,%,,%%
,,,,,,,,,,%
%,,,,,,,,,%
%,,,%,,%,,,
%%o,,,,,,,,
%%,,,,,%,,,
%,,,,%,,,,%
%%,,,,,,,%%
%%,%,,,o,,%
%%,,,,,,,%%
%%%,,,,o%%%
%%%%%,,,,,,
%%%%%%%%%,%
,,,,%%%%,,%
%%%,%%%%,%%
%%%%,%%,,%%
%%%%%,,,%%%
%%%%%,%%%%%
%%%%%,%%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%,,,%%%
%%%,,,,,,,%
%%,,,,,,,,%
,,,,%,%,,,%
,,,,,,,,,,%
,,,%,,,,,,%
%,,,o,,,,,,
%,,,,%,,,,,
%,%,,,,%,,%
%,,,,,o,,,%
%%,%,,,,%%%
%,,,,,,,o%%
%%o,,,,,,,%
%%,,,,,,,,,
%,,,%,,,,,,
%,,,,,,,,,%
,,,%,,,%,,%
,,,,,,,,,%%
%,,,,,,,,,%
%%o%,,,,,%%
%%%,,,,,%%%
%%%%,,,%%%%");

    add_cache_chunk(Overland, 0, "\
%%%oo,,,%%%
%,,o=o,,%%%
%%,,=%,,,%%
,,,,=%,,,%%
%,%,==,,,%%
%,,,,=,%,%%
%,,%,=,,,,%
%,,,==,,,,,
,,,,=o,,,%%
,,%,=,,%,%%
%,,,==,,,%%
%,,,,=,,%%%
,,%%,=,,,%%
,,%,,=o,,%%
%,,,==,,,,,
,,,~===~~,,
,,~=====~~,
,,~====~~,,
,,~=====~,,
,,~~===~~,,
,,,~~~~~~,,
%,,,,,,,,%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%,,,,,%%%
%%,,%%%,%%%
,,,%%%%,,%%
%%,,%%,,,%%
%%%,,,,%%%%
%%,,,,,,,,%
%%,,,,,%%%,
%%%%%%%%%%%
%%%%%%%%%%%
%%%%%,,,%%%
%%%,,,,,%%%
%%%,,,,,,,%
%%,,..,,,,%
%%,A./..,,,
%,,..//.,,%
,,,.//.A,%%
%%,,./.,,%%
%,,,A,.,,%%
%%,,,,,,,%%
%%%,,,,,%%%
%%%%%,%%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%%%,,,%%%
%%,,,,,,%%%
,,,,,,,%,,%
%%,,,,,%%,%
%/%,,,,,%%%
%%%%/%%,/%%
%%%%%%%,,,,
%%%%%%%,/%%
%%%%%,,,%%%
%///..//%%%
%/.A..../%%
%.A..A..,%%
%./.a../%,%
%%.A..A/%,,
%%...A,,%%%
,,,,,//%/%%
%%%,,%%%%%%
%%%%,%%/%%%
%%%%%,%%%%%
%%%%%,,%%%%
%%%%%,,%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%%%%,,,%%
%%%%,,,,,%%
,,,,,,,,,%%
%%,,%%,,,%%
%%%%%,,,%%%
%%%%%%,,%,%
%%%%,,,,,,,
%%%%,%%,,,%
%%%%%%%,,%%
%%%%%%%,,%%
%%%%%,,,%%%
%%%%%,%%%%%
%%%%%,%%%%%
%%%%%,,,,,,
%%,,,,,,,,%
,,,,,,,%%%%
%%%,,,%%%%%
%%%%,,,%%%%
%%%%%,,,%%%
%%%%%,,%%%%
%%%%%,,%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%,,%%%
%%%%%%,,,%%
%%%%,,,,,%%
,,,,,,,,,%%
%%,,%%,,,%%
%%%%%,,,%%%
%%%%%%,,%,%
%%%o,,,,,,,
%%%~~%%,,,%
==%~~~o,,~%
=======~~~=
===========
~====~~~===
,,,~~~%%%%%
,%%%%,,,,,,
%%,,,,,,,,%
,,,,,,,%%%%
%%%,,,%%%%%
%%%%,,,%%%%
%%%%%,,,%%%
%%%%%,,%%%%
%%%%%,,%%%%");

    add_cache_chunk(Overland, 0, "\
,,,,,,,,,,,
,========,,
,=#|#=#|#=,
,=|.###.|=,
,=#.+.+.#=,
,=###+###=,
,==#b.b#==,
,==#>.b#==,
,==|...|==,
,==##+##==,
,..+...+..,
,..+...+..,
,==##+##==,
,==|...|==,
,==#.T.#==,
,==#...#==,
,=###+###=,
,=#.+.+.#=,
,=|.###.|=,
,=#|#=#|#=,
,,========,
,,,,,,,,,,,");

    add_cache_chunk(Overland, 0, "\
,,,,,,,,,,,
,,,,,,,,,,,
,,******,,,
,****..**,,
,*.*.....,,
,*.**!..*,,
,*.**..**,,
,*....***,,
,**I.III**,
,,**..****,
,**....!**,
,**.*.***,,
,***.**X*,,
,*...XXX*,,
,**...X**,,
,*##+#XX*,,
,*#....X**,
,*#..>X#**,
,**!..X#**,
,,**###***,
,,*******,,
,,,,,,,,,,,");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#######+###
##......###
.+......###
##......###
##g.....###
##......###
##g.....+..
##......###
###+#######
###.#######
###.#######
###.#######
###.#######
###........
#####.#####
......#####
#####.#####
#####.#####
#####.#####
#####.#####
#####.#####");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#######.###
#######.###
........###
#######.###
#######.###
#######.###
#######....
###########
###########
###########
###########
###########
###########
#####......
#####.#####
......#####
#####.#####
#####.#####
#####.#####
#####.#####
#####.#####");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#######+###
##.......##
.+...#...##
##..###..##
##...#...##
##.#...#.##
##.......+.
##.......##
##.#...#.##
##.......##
##.......##
##.#...#.##
##.......##
##.......+.
##.#...#.##
.+...#...##
##..###..##
##...#...##
##.......##
#####+#####
#####.#####");

    add_cache_chunk(Dungeon, 0, "\
*******.***
****#...***
#####...#**
.......##**
##.....+..*
*..##..#..*
**..#++##**
**#|#......
**....!..**
**..!.....*
**..XX..!.*
**!.XXX..**
**...XX..**
**X......**
**XXXXX....
**.XXX...**
.......X.**
**..!..XX**
***....XX**
****..**XX*
*****.*XXX*
*****.*****");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#######.###
#######.###
........###
#.......###
#.......###
#.......###
#..........
###=====###
###=====###
###=====###
###=====###
###IIIII###
###.....###
###........
###.....###
........###
###.....###
###.....###
###.....###
#####.#####
#####.#####");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#.........#
#.........#
..........#
#.........#
#.........#
#.........#
#..........
#..#.#....#
#.........#
#..#.>.#..#
#.........#
#....#.#..#
#.........#
#..........
#.........#
..........#
#.........#
#.........#
#.........#
#.........#
#####.#####");
}
<commit_msg>Remove the annoying water geomorph<commit_after>use geomorph::add_cache_chunk;
use {Overland, Dungeon};

// Geomorph data.

/*
1######B222 Template for herringbone prefabs
1##########
1########## Cells at positions A, B and C must have an open tile.
A########## On each half, the openings A, B and C must be connected.
########### The two halves may or may not be connected.
########### This ensures automatic map connectivity, while not
########### making the map trivially open.
##########B
##########2 The numbered lines are parameters by which the openings
##########2 are positioned. When changing the position of an opening
##########2 for an alternative set, lines with the same symbol must
3*********1 remain at equal length.
3*********1
3*********1
3*********A
3**********
C**********
***********
***********
***********
***********
33333C*****
*/

/// Initialize global geomorph cache.
pub fn init_geomorphs() {
    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%%%%%,%%%
%%%%%%%,%%%
,,,%%%,,%%%
%%,,,,,%%%%
%%,%,,,%%%%
%%%,,%,%%%%
%%%%%%%,,,,
%%%%%%%,%%%
%%%%%%%%%%%
%%%%%%%%%%%
%%%%%%%%%%%
%%%%%%%%%%%
%%%%%%%,%%%
%%%%%%,,,,,
%%%%%,,%%%%
,,,,%,,%%%%
%%%,,,%%%%%
%%%,,%%%%%%
%%%%,%%%%%%
%%%%,%%%%%%
%%%%%,%%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%%%%,,%%%
%%%%,,,%%%%
,,,%%,,%%%%
%%,,%%,,%%%
%%%%,,,%%%%
%%%%,,%%%%%
%%%%,,%%,,,
%%%%%,,,,%%
%%%%%,,%%%%
%%%,,,%%%%%
%%%%,,%%%%%
%%%%,,%%%%%
%%%%,%%%%%%
%%%%,,%,,,,
%%%%%%,,%%%
,,%%%,,%%%%
%%,,,,%%%%%
%%%%,,%%%%%
%%%%%,,%%%%
%%%%%,,%%%%
%%%%%,%%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%,,,%%%
%%,,,,,,,%%
%,,,%,,,,,%
,,,,,,%,,%%
,,,,,,,,,,%
%,,,,,,,,,%
%,,,%,,%,,,
%%o,,,,,,,,
%%,,,,,%,,,
%,,,,%,,,,%
%%,,,,,,,%%
%%,%,,,o,,%
%%,,,,,,,%%
%%%,,,,o%%%
%%%%%,,,,,,
%%%%%%%%%,%
,,,,%%%%,,%
%%%,%%%%,%%
%%%%,%%,,%%
%%%%%,,,%%%
%%%%%,%%%%%
%%%%%,%%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%,,,%%%
%%%,,,,,,,%
%%,,,,,,,,%
,,,,%,%,,,%
,,,,,,,,,,%
,,,%,,,,,,%
%,,,o,,,,,,
%,,,,%,,,,,
%,%,,,,%,,%
%,,,,,o,,,%
%%,%,,,,%%%
%,,,,,,,o%%
%%o,,,,,,,%
%%,,,,,,,,,
%,,,%,,,,,,
%,,,,,,,,,%
,,,%,,,%,,%
,,,,,,,,,%%
%,,,,,,,,,%
%%o%,,,,,%%
%%%,,,,,%%%
%%%%,,,%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%,,,,,%%%
%%,,%%%,%%%
,,,%%%%,,%%
%%,,%%,,,%%
%%%,,,,%%%%
%%,,,,,,,,%
%%,,,,,%%%,
%%%%%%%%%%%
%%%%%%%%%%%
%%%%%,,,%%%
%%%,,,,,%%%
%%%,,,,,,,%
%%,,..,,,,%
%%,A./..,,,
%,,..//.,,%
,,,.//.A,%%
%%,,./.,,%%
%,,,A,.,,%%
%%,,,,,,,%%
%%%,,,,,%%%
%%%%%,%%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%%%,,,%%%
%%,,,,,,%%%
,,,,,,,%,,%
%%,,,,,%%,%
%/%,,,,,%%%
%%%%/%%,/%%
%%%%%%%,,,,
%%%%%%%,/%%
%%%%%,,,%%%
%///..//%%%
%/.A..../%%
%.A..A..,%%
%./.a../%,%
%%.A..A/%,,
%%...A,,%%%
,,,,,//%/%%
%%%,,%%%%%%
%%%%,%%/%%%
%%%%%,%%%%%
%%%%%,,%%%%
%%%%%,,%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%%,%%%
%%%%%%,,,%%
%%%%,,,,,%%
,,,,,,,,,%%
%%,,%%,,,%%
%%%%%,,,%%%
%%%%%%,,%,%
%%%%,,,,,,,
%%%%,%%,,,%
%%%%%%%,,%%
%%%%%%%,,%%
%%%%%,,,%%%
%%%%%,%%%%%
%%%%%,%%%%%
%%%%%,,,,,,
%%,,,,,,,,%
,,,,,,,%%%%
%%%,,,%%%%%
%%%%,,,%%%%
%%%%%,,,%%%
%%%%%,,%%%%
%%%%%,,%%%%");

    add_cache_chunk(Overland, 0, "\
%%%%%%,,%%%
%%%%%%,,,%%
%%%%,,,,,%%
,,,,,,,,,%%
%%,,%%,,,%%
%%%%%,,,%%%
%%%%%%,,%,%
%%%o,,,,,,,
%%%~~%%,,,%
==%~~~o,,~%
=======~~~=
===========
~====~~~===
,,,~~~%%%%%
,%%%%,,,,,,
%%,,,,,,,,%
,,,,,,,%%%%
%%%,,,%%%%%
%%%%,,,%%%%
%%%%%,,,%%%
%%%%%,,%%%%
%%%%%,,%%%%");

    add_cache_chunk(Overland, 0, "\
,,,,,,,,,,,
,========,,
,=#|#=#|#=,
,=|.###.|=,
,=#.+.+.#=,
,=###+###=,
,==#b.b#==,
,==#>.b#==,
,==|...|==,
,==##+##==,
,..+...+..,
,..+...+..,
,==##+##==,
,==|...|==,
,==#.T.#==,
,==#...#==,
,=###+###=,
,=#.+.+.#=,
,=|.###.|=,
,=#|#=#|#=,
,,========,
,,,,,,,,,,,");

    add_cache_chunk(Overland, 0, "\
,,,,,,,,,,,
,,,,,,,,,,,
,,******,,,
,****..**,,
,*.*.....,,
,*.**!..*,,
,*.**..**,,
,*....***,,
,**I.III**,
,,**..****,
,**....!**,
,**.*.***,,
,***.**X*,,
,*...XXX*,,
,**...X**,,
,*##+#XX*,,
,*#....X**,
,*#..>X#**,
,**!..X#**,
,,**###***,
,,*******,,
,,,,,,,,,,,");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#######+###
##......###
.+......###
##......###
##g.....###
##......###
##g.....+..
##......###
###+#######
###.#######
###.#######
###.#######
###.#######
###........
#####.#####
......#####
#####.#####
#####.#####
#####.#####
#####.#####
#####.#####");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#######.###
#######.###
........###
#######.###
#######.###
#######.###
#######....
###########
###########
###########
###########
###########
###########
#####......
#####.#####
......#####
#####.#####
#####.#####
#####.#####
#####.#####
#####.#####");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#######+###
##.......##
.+...#...##
##..###..##
##...#...##
##.#...#.##
##.......+.
##.......##
##.#...#.##
##.......##
##.......##
##.#...#.##
##.......##
##.......+.
##.#...#.##
.+...#...##
##..###..##
##...#...##
##.......##
#####+#####
#####.#####");

    add_cache_chunk(Dungeon, 0, "\
*******.***
****#...***
#####...#**
.......##**
##.....+..*
*..##..#..*
**..#++##**
**#|#......
**....!..**
**..!.....*
**..XX..!.*
**!.XXX..**
**...XX..**
**X......**
**XXXXX....
**.XXX...**
.......X.**
**..!..XX**
***....XX**
****..**XX*
*****.*XXX*
*****.*****");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#######.###
#######.###
........###
#.......###
#.......###
#.......###
#..........
###=====###
###=====###
###=====###
###=====###
###IIIII###
###.....###
###........
###.....###
........###
###.....###
###.....###
###.....###
#####.#####
#####.#####");

    add_cache_chunk(Dungeon, 0, "\
#######.###
#.........#
#.........#
..........#
#.........#
#.........#
#.........#
#..........
#..#.#....#
#.........#
#..#.>.#..#
#.........#
#....#.#..#
#.........#
#..........
#.........#
..........#
#.........#
#.........#
#.........#
#.........#
#####.#####");
}
<|endoftext|>


<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::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::test_utils::generate_deterministic_keypairs;
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,
    /// 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();
        let genesis_slot = Slot::from(node_info.get_genesis_slot());

        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_slot, 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");

        Ok(Self {
            connected_node_version: node_info.version,
            chain_id: node_info.chain_id as u16,
            fork,
            slot_clock,
            current_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))?;

        let duration_to_next_slot = service
            .slot_clock
            .duration_to_next_slot()
            .map_err(|e| format!("System clock error: {:?}", e))?
            .expect("Cannot start before genesis");

        // 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() + 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(generate_deterministic_keypairs(8));

        /* 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 and epoch */
                    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 cloned_manager = manager.clone();
                    let cloned_log = log.clone();
                    // spawn a new thread separate to the runtime
                    std::thread::spawn(move || {
                        cloned_manager.run_update(current_epoch.clone(), cloned_log.clone());
                        dbg!("Finished thread");
                    });

                    /* execute any specified duties */

                    if let Some(work) = manager.get_current_work(current_slot) {
                        for (_public_key, work_type) in work {
                            if work_type.produce_block {
                                // TODO: Produce a beacon block in a new thread
                            }
                            if work_type.attestation_duty.is_some() {
                                // available AttestationDuty info
                                let attestation_duty =
                                    work_type.attestation_duty.expect("Cannot be None");
                                //TODO: Produce an attestation in a new thread
                            }
                        }
                    }

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

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

    /*

        // 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>Clean up validator output<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::test_utils::generate_deterministic_keypairs;
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,
    /// 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();
        let genesis_slot = Slot::from(node_info.get_genesis_slot());

        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_slot, 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");

        Ok(Self {
            connected_node_version: node_info.version,
            chain_id: node_info.chain_id as u16,
            fork,
            slot_clock,
            current_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))?;

        let duration_to_next_slot = service
            .slot_clock
            .duration_to_next_slot()
            .map_err(|e| format!("System clock error: {:?}", e))?
            .expect("Cannot start before genesis");

        // 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() + 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(generate_deterministic_keypairs(8));

        /* 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 and epoch */
                    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(), "epoch" => current_epoch.as_u64());

                    /* check for new duties */

                    let cloned_manager = manager.clone();
                    let cloned_log = log.clone();
                    // spawn a new thread separate to the runtime
                    std::thread::spawn(move || {
                        let _empty_error = cloned_manager.run_update(current_epoch.clone(), cloned_log.clone());
                    });

                    /* execute any specified duties */

                    if let Some(work) = manager.get_current_work(current_slot) {
                        for (_public_key, work_type) in work {
                            if work_type.produce_block {
                                // TODO: Produce a beacon block in a new thread
                            }
                            if work_type.attestation_duty.is_some() {
                                // available AttestationDuty info
                                let attestation_duty =
                                    work_type.attestation_duty.expect("Cannot be None");
                                //TODO: Produce an attestation in a new thread
                            }
                        }
                    }

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

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

    /*

        // 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>#[macro_use]
extern crate validator_derive;
extern crate validator;

use validator::{Validate, ValidationErrors};

#[test]
fn can_validate_range_ok() {
    #[derive(Debug, Validate)]
    struct TestStruct {
        #[validate(range(min = 5, max = 10))]
        val: usize,
    }

    let s = TestStruct { val: 6 };

    assert!(s.validate().is_ok());
}

#[test]
fn value_out_of_range_fails_validation() {
    #[derive(Debug, Validate)]
    struct TestStruct {
        #[validate(range(min = 5, max = 10))]
        val: usize,
    }

    let s = TestStruct { val: 11 };
    let res = s.validate();
    assert!(res.is_err());
    let err = res.unwrap_err();
    let errs = err.field_errors();
    assert!(errs.contains_key("val"));
    assert_eq!(errs["val"].len(), 1);
    assert_eq!(errs["val"][0].code, "range");
}

#[test]
fn can_specify_code_for_range() {
    #[derive(Debug, Validate)]
    struct TestStruct {
        #[validate(range(min = 5, max = 10, code = "oops"))]
        val: usize,
    }
    let s = TestStruct { val: 11 };
    let res = s.validate();
    assert!(res.is_err());
    let err = res.unwrap_err();
    let errs = err.field_errors();
    assert!(errs.contains_key("val"));
    assert_eq!(errs["val"].len(), 1);
    assert_eq!(errs["val"][0].code, "oops");
    assert_eq!(errs["val"][0].params["value"], 11);
    assert_eq!(errs["val"][0].params["min"], 5f64);
    assert_eq!(errs["val"][0].params["max"], 10f64);
}

#[test]
fn can_specify_message_for_range() {
    #[derive(Debug, Validate)]
    struct TestStruct {
        #[validate(range(min = 5, max = 10, message = "oops"))]
        val: usize,
    }
    let s = TestStruct { val: 1 };
    let res = s.validate();
    assert!(res.is_err());
    let err = res.unwrap_err();
    let errs = err.field_errors();
    assert!(errs.contains_key("val"));
    assert_eq!(errs["val"].len(), 1);
    assert_eq!(errs["val"][0].clone().message.unwrap(), "oops");
}

#[test]
fn can_pass_reference_as_validate() {
    // This tests that the blanket Validate implementation on
    // `&T where T:Validate` works properly

    #[derive(Validate)]
    struct TestStruct {
        #[validate(range(min = 100))]
        num_field: u32,
    }

    fn validate<T: Validate>(value: T) -> Result<(), ValidationErrors> {
        value.validate()
    }

    let val = TestStruct { num_field: 10 };
    validate(&val).unwrap_err();
}
<commit_msg>Slight tweak on a test<commit_after>#[macro_use]
extern crate validator_derive;
extern crate validator;

use validator::{Validate, ValidationErrors};

#[test]
fn can_validate_range_ok() {
    #[derive(Debug, Validate)]
    struct TestStruct {
        #[validate(range(min = 5, max = 10))]
        val: usize,
    }

    let s = TestStruct { val: 6 };

    assert!(s.validate().is_ok());
}

#[test]
fn value_out_of_range_fails_validation() {
    #[derive(Debug, Validate)]
    struct TestStruct {
        #[validate(range(min = 5, max = 10))]
        val: usize,
    }

    let s = TestStruct { val: 11 };
    let res = s.validate();
    assert!(res.is_err());
    let err = res.unwrap_err();
    let errs = err.field_errors();
    assert!(errs.contains_key("val"));
    assert_eq!(errs["val"].len(), 1);
    assert_eq!(errs["val"][0].code, "range");
}

#[test]
fn can_specify_code_for_range() {
    #[derive(Debug, Validate)]
    struct TestStruct {
        #[validate(range(min = 5, max = 10, code = "oops"))]
        val: usize,
    }
    let s = TestStruct { val: 11 };
    let res = s.validate();
    assert!(res.is_err());
    let err = res.unwrap_err();
    let errs = err.field_errors();
    assert!(errs.contains_key("val"));
    assert_eq!(errs["val"].len(), 1);
    assert_eq!(errs["val"][0].code, "oops");
    assert_eq!(errs["val"][0].params["value"], 11);
    assert_eq!(errs["val"][0].params["min"], 5f64);
    assert_eq!(errs["val"][0].params["max"], 10f64);
}

#[test]
fn can_specify_message_for_range() {
    #[derive(Debug, Validate)]
    struct TestStruct {
        #[validate(range(min = 5, max = 10, message = "oops"))]
        val: usize,
    }
    let s = TestStruct { val: 1 };
    let res = s.validate();
    assert!(res.is_err());
    let err = res.unwrap_err();
    let errs = err.field_errors();
    assert!(errs.contains_key("val"));
    assert_eq!(errs["val"].len(), 1);
    assert_eq!(errs["val"][0].clone().message.unwrap(), "oops");
}

#[test]
fn can_pass_reference_as_validate() {
    // This tests that the blanket Validate implementation on
    // `&T where T:Validate` works properly

    #[derive(Validate)]
    struct TestStruct {
        #[validate(range(min = 100))]
        num_field: u32,
    }

    fn validate<T: Validate>(value: T) -> Result<(), ValidationErrors> {
        value.validate()
    }

    let val = TestStruct { num_field: 10 };
    validate(&val).unwrap_err();
    assert_eq!(val.num_field, 10);
}
<|endoftext|>


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

use std::sync::Arc;

use buffer::Buffer;
use device::DeviceOwned;
use command_buffer::DynamicState;
use command_buffer::cb::AddCommand;
use command_buffer::cb::CommandBufferBuild;
use command_buffer::cmd;
use descriptor::descriptor_set::DescriptorSetsCollection;
use framebuffer::FramebufferAbstract;
use framebuffer::RenderPassAbstract;
use framebuffer::RenderPassDescClearValues;
use image::Image;
use pipeline::ComputePipelineAbstract;
use pipeline::GraphicsPipelineAbstract;
use pipeline::vertex::VertexSource;

///
/// > **Note**: This trait is just a utility trait. Do not implement it yourself. Instead
/// > implement the `AddCommand` and `CommandBufferBuild` traits.
pub unsafe trait CommandBufferBuilder: DeviceOwned {
    /// Adds a command that writes the content of a buffer.
    ///
    /// This function is similar to the `memset` function in C. The `data` parameter is a number
    /// that will be repeatidely written through the entire buffer.
    ///
    /// > **Note**: This function is technically safe because buffers can only contain integers or
    /// > floating point numbers, which are always valid whatever their memory representation is.
    /// > But unless your buffer actually contains only 32-bits integers, you are encouraged to use
    /// > this function only for zeroing the content of a buffer by passing `0` for the data.
    // TODO: not safe because of signalling NaNs
    #[inline]
    fn fill_buffer<B, O>(self, buffer: B, data: u32) -> Result<O, cmd::CmdFillBufferError>
        where Self: Sized + AddCommand<cmd::CmdFillBuffer<B>, Out = O>,
              B: Buffer
    {
        let cmd = cmd::CmdFillBuffer::new(buffer, data)?;
        Ok(self.add(cmd))
    }

    /// Adds a command that copies the content of a buffer to an image.
    ///
    /// For color images (ie. all formats except depth and/or stencil formats) this command does
    /// not perform any conversion. The data inside the buffer must already have the right format.
    /// TODO: talk about depth/stencil
    ///
    /// > **Note**: This function is technically safe because buffers can only contain integers or
    /// > floating point numbers, which are always valid whatever their memory representation is.
    /// > But unless your buffer actually contains only 32-bits integers, you are encouraged to use
    /// > this function only for zeroing the content of a buffer by passing `0` for the data.
    // TODO: not safe because of signalling NaNs
    #[inline]
    fn copy_buffer_to_image<B, I, O>(self, buffer: B, image: I)
                                     -> Result<O, cmd::CmdCopyBufferToImageError>
        where Self: Sized + AddCommand<cmd::CmdCopyBufferToImage<B, I>, Out = O>,
              B: Buffer, I: Image
    {
        let cmd = cmd::CmdCopyBufferToImage::new(buffer, image)?;
        Ok(self.add(cmd))
    }

    /// Same as `copy_buffer_to_image` but lets you specify a range for the destination image.
    #[inline]
    fn copy_buffer_to_image_dimensions<B, I, O>(self, buffer: B, image: I, offset: [u32; 3],
                                                size: [u32; 3], first_layer: u32, num_layers: u32,
                                                mipmap: u32) -> Result<O, cmd::CmdCopyBufferToImageError>
        where Self: Sized + AddCommand<cmd::CmdCopyBufferToImage<B, I>, Out = O>,
              B: Buffer, I: Image
    {
        let cmd = cmd::CmdCopyBufferToImage::new(buffer, image)?;
        Ok(self.add(cmd))
    }

    /// Adds a command that starts a render pass.
    ///
    /// If `secondary` is true, then you will only be able to add secondary command buffers while
    /// you're inside the first subpass of the render pass. If `secondary` is false, you will only
    /// be able to add inline draw commands and not secondary command buffers.
    ///
    /// You must call this before you can add draw commands.
    #[inline]
    fn begin_render_pass<F, C, O>(self, framebuffer: F, secondary: bool, clear_values: C)
                                  -> O
        where Self: Sized + AddCommand<cmd::CmdBeginRenderPass<Arc<RenderPassAbstract>, F>, Out = O>,
              F: FramebufferAbstract + RenderPassDescClearValues<C>
    {
        let cmd = cmd::CmdBeginRenderPass::new(framebuffer, secondary, clear_values);
        self.add(cmd)
    }

    /// Adds a command that jumps to the next subpass of the current render pass.
    #[inline]
    fn next_subpass<O>(self, secondary: bool) -> O
        where Self: Sized + AddCommand<cmd::CmdNextSubpass, Out = O>
    {
        let cmd = cmd::CmdNextSubpass::new(secondary);
        self.add(cmd)
    }

    /// Adds a command that ends the current render pass.
    ///
    /// This must be called after you went through all the subpasses and before you can build
    /// the command buffer or add further commands.
    #[inline]
    fn end_render_pass<O>(self) -> O
        where Self: Sized + AddCommand<cmd::CmdEndRenderPass, Out = O>
    {
        let cmd = cmd::CmdEndRenderPass::new();
        self.add(cmd)
    }

    /// Adds a command that draws.
    ///
    /// Can only be used from inside a render pass.
    #[inline]
    fn draw<P, S, Pc, V, O>(self, pipeline: P, dynamic: DynamicState, vertices: V, sets: S,
                            push_constants: Pc) -> O
        where Self: Sized + AddCommand<cmd::CmdDraw<V, P, S, Pc>, Out = O>,
              S: DescriptorSetsCollection,
              P: VertexSource<V> + GraphicsPipelineAbstract + Clone
    {
        let cmd = cmd::CmdDraw::new(pipeline, dynamic, vertices, sets, push_constants);
        self.add(cmd)
    }

    /// Executes a compute shader.
    fn dispatch<P, S, Pc, O>(self, dimensions: [u32; 3], pipeline: P, sets: S, push_constants: Pc)
                             -> Result<O, cmd::CmdDispatchError>
        where Self: Sized + AddCommand<cmd::CmdDispatch<P, S, Pc>, Out = O>,
              S: DescriptorSetsCollection,
              P: Clone + ComputePipelineAbstract,
    {
        let cmd = try!(cmd::CmdDispatch::new(dimensions, pipeline, sets, push_constants));
        Ok(self.add(cmd))
    }

    #[inline]
    fn build<O>(self) -> O
        where Self: Sized + CommandBufferBuild<Out = O>
    {
        CommandBufferBuild::build(self)
    }
}

pub unsafe trait CommandBufferBuilderBuffered {
    /// Adds a pipeline barrier to the underlying command buffer and bypasses the flushing
    /// mechanism.
    fn add_non_buffered_pipeline_barrier(&mut self, cmd: &cmd::CmdPipelineBarrier);

    /// Flushes all the commands that haven't been flushed to the inner builder.
    fn flush(&mut self);
}
<commit_msg>Fix copy_buffer_to_image_dimensions<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::sync::Arc;

use buffer::Buffer;
use device::DeviceOwned;
use command_buffer::DynamicState;
use command_buffer::cb::AddCommand;
use command_buffer::cb::CommandBufferBuild;
use command_buffer::cmd;
use descriptor::descriptor_set::DescriptorSetsCollection;
use framebuffer::FramebufferAbstract;
use framebuffer::RenderPassAbstract;
use framebuffer::RenderPassDescClearValues;
use image::Image;
use pipeline::ComputePipelineAbstract;
use pipeline::GraphicsPipelineAbstract;
use pipeline::vertex::VertexSource;

///
/// > **Note**: This trait is just a utility trait. Do not implement it yourself. Instead
/// > implement the `AddCommand` and `CommandBufferBuild` traits.
pub unsafe trait CommandBufferBuilder: DeviceOwned {
    /// Adds a command that writes the content of a buffer.
    ///
    /// This function is similar to the `memset` function in C. The `data` parameter is a number
    /// that will be repeatidely written through the entire buffer.
    ///
    /// > **Note**: This function is technically safe because buffers can only contain integers or
    /// > floating point numbers, which are always valid whatever their memory representation is.
    /// > But unless your buffer actually contains only 32-bits integers, you are encouraged to use
    /// > this function only for zeroing the content of a buffer by passing `0` for the data.
    // TODO: not safe because of signalling NaNs
    #[inline]
    fn fill_buffer<B, O>(self, buffer: B, data: u32) -> Result<O, cmd::CmdFillBufferError>
        where Self: Sized + AddCommand<cmd::CmdFillBuffer<B>, Out = O>,
              B: Buffer
    {
        let cmd = cmd::CmdFillBuffer::new(buffer, data)?;
        Ok(self.add(cmd))
    }

    /// Adds a command that copies the content of a buffer to an image.
    ///
    /// For color images (ie. all formats except depth and/or stencil formats) this command does
    /// not perform any conversion. The data inside the buffer must already have the right format.
    /// TODO: talk about depth/stencil
    ///
    /// > **Note**: This function is technically safe because buffers can only contain integers or
    /// > floating point numbers, which are always valid whatever their memory representation is.
    /// > But unless your buffer actually contains only 32-bits integers, you are encouraged to use
    /// > this function only for zeroing the content of a buffer by passing `0` for the data.
    // TODO: not safe because of signalling NaNs
    #[inline]
    fn copy_buffer_to_image<B, I, O>(self, buffer: B, image: I)
                                     -> Result<O, cmd::CmdCopyBufferToImageError>
        where Self: Sized + AddCommand<cmd::CmdCopyBufferToImage<B, I>, Out = O>,
              B: Buffer, I: Image
    {
        let cmd = cmd::CmdCopyBufferToImage::new(buffer, image)?;
        Ok(self.add(cmd))
    }

    /// Same as `copy_buffer_to_image` but lets you specify a range for the destination image.
    #[inline]
    fn copy_buffer_to_image_dimensions<B, I, O>(self, buffer: B, image: I, offset: [u32; 3],
                                                size: [u32; 3], first_layer: u32, num_layers: u32,
                                                mipmap: u32) -> Result<O, cmd::CmdCopyBufferToImageError>
        where Self: Sized + AddCommand<cmd::CmdCopyBufferToImage<B, I>, Out = O>,
              B: Buffer, I: Image
    {
        let cmd = cmd::CmdCopyBufferToImage::with_dimensions(buffer, image, offset, size,
                                                             first_layer, num_layers, mipmap)?;
        Ok(self.add(cmd))
    }

    /// Adds a command that starts a render pass.
    ///
    /// If `secondary` is true, then you will only be able to add secondary command buffers while
    /// you're inside the first subpass of the render pass. If `secondary` is false, you will only
    /// be able to add inline draw commands and not secondary command buffers.
    ///
    /// You must call this before you can add draw commands.
    #[inline]
    fn begin_render_pass<F, C, O>(self, framebuffer: F, secondary: bool, clear_values: C)
                                  -> O
        where Self: Sized + AddCommand<cmd::CmdBeginRenderPass<Arc<RenderPassAbstract>, F>, Out = O>,
              F: FramebufferAbstract + RenderPassDescClearValues<C>
    {
        let cmd = cmd::CmdBeginRenderPass::new(framebuffer, secondary, clear_values);
        self.add(cmd)
    }

    /// Adds a command that jumps to the next subpass of the current render pass.
    #[inline]
    fn next_subpass<O>(self, secondary: bool) -> O
        where Self: Sized + AddCommand<cmd::CmdNextSubpass, Out = O>
    {
        let cmd = cmd::CmdNextSubpass::new(secondary);
        self.add(cmd)
    }

    /// Adds a command that ends the current render pass.
    ///
    /// This must be called after you went through all the subpasses and before you can build
    /// the command buffer or add further commands.
    #[inline]
    fn end_render_pass<O>(self) -> O
        where Self: Sized + AddCommand<cmd::CmdEndRenderPass, Out = O>
    {
        let cmd = cmd::CmdEndRenderPass::new();
        self.add(cmd)
    }

    /// Adds a command that draws.
    ///
    /// Can only be used from inside a render pass.
    #[inline]
    fn draw<P, S, Pc, V, O>(self, pipeline: P, dynamic: DynamicState, vertices: V, sets: S,
                            push_constants: Pc) -> O
        where Self: Sized + AddCommand<cmd::CmdDraw<V, P, S, Pc>, Out = O>,
              S: DescriptorSetsCollection,
              P: VertexSource<V> + GraphicsPipelineAbstract + Clone
    {
        let cmd = cmd::CmdDraw::new(pipeline, dynamic, vertices, sets, push_constants);
        self.add(cmd)
    }

    /// Executes a compute shader.
    fn dispatch<P, S, Pc, O>(self, dimensions: [u32; 3], pipeline: P, sets: S, push_constants: Pc)
                             -> Result<O, cmd::CmdDispatchError>
        where Self: Sized + AddCommand<cmd::CmdDispatch<P, S, Pc>, Out = O>,
              S: DescriptorSetsCollection,
              P: Clone + ComputePipelineAbstract,
    {
        let cmd = try!(cmd::CmdDispatch::new(dimensions, pipeline, sets, push_constants));
        Ok(self.add(cmd))
    }

    #[inline]
    fn build<O>(self) -> O
        where Self: Sized + CommandBufferBuild<Out = O>
    {
        CommandBufferBuild::build(self)
    }
}

pub unsafe trait CommandBufferBuilderBuffered {
    /// Adds a pipeline barrier to the underlying command buffer and bypasses the flushing
    /// mechanism.
    fn add_non_buffered_pipeline_barrier(&mut self, cmd: &cmd::CmdPipelineBarrier);

    /// Flushes all the commands that haven't been flushed to the inner builder.
    fn flush(&mut self);
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::env;
use std::io::BufReader;
use std::io::BufRead;
use std::io::Write;
use std::collections::HashMap;
use std::collections::BTreeMap;
use std::collections::BTreeSet;

extern crate tools;
use tools::find_source_file;
use tools::file_format::analysis::{read_analysis, read_target, AnalysisKind};
use tools::config;

extern crate rustc_serialize;
use rustc_serialize::json::{Json, ToJson};

#[derive(Debug)]
struct SearchResult {
    lineno: u32,
    bounds: (u32, u32),
    line: String,
    context: String,
    contextsym: String,
}

impl ToJson for SearchResult {
    fn to_json(&self) -> Json {
        let (st, en) = self.bounds;
        let bounds = vec![st, en];

        let mut obj = BTreeMap::new();
        obj.insert("lno".to_string(), self.lineno.to_json());
        obj.insert("bounds".to_string(), bounds.to_json());
        obj.insert("line".to_string(), self.line.to_json());
        obj.insert("context".to_string(), self.context.to_json());
        obj.insert("contextsym".to_string(), self.contextsym.to_json());
        Json::Object(obj)
    }
}

fn split_scopes(id: &str) -> Vec<String> {
    let mut result = Vec::new();
    let mut start = 0;
    let mut argument_nesting = 0;
    for (index, m) in id.match_indices(|c| c == ':' || c == '<' || c == '>') {
        if m == ":" && argument_nesting == 0 {
            if start != index {
                result.push(id[start .. index].to_owned());
                start = index + 1;
            } else {
                start = index + 1;
            }
        } else if m == "<" {
            argument_nesting += 1;
        } else if m == ">" {
            argument_nesting -= 1;
        }
    }
    result.push(id[start ..].to_owned());
    return result;
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let cfg = config::load(&args[1], false);

    let tree_name = &args[2];
    let tree_config = cfg.trees.get(tree_name).unwrap();

    let filenames_file = &args[3];

    let output_file = format!("{}/crossref", tree_config.paths.index_path);
    let jump_file = format!("{}/jumps", tree_config.paths.index_path);
    let id_file = format!("{}/identifiers", tree_config.paths.index_path);

    let mut table = BTreeMap::new();
    let mut pretty_table = HashMap::new();
    let mut id_table = BTreeMap::new();
    let mut jumps = Vec::new();

    {
        let mut process_file = |path: &str| {
            print!("File {}\n", path);

            let analysis_fname = format!("{}/analysis/{}", tree_config.paths.index_path, path);
            let analysis = read_analysis(&analysis_fname, &read_target);

            let source_fname = find_source_file(path, &tree_config.paths.files_path, &tree_config.paths.objdir_path);
            let source_file = match File::open(source_fname) {
                Ok(f) => f,
                Err(_) => {
                    println!("Unable to open source file");
                    return;
                },
            };
            let reader = BufReader::new(&source_file);
            let mut lines = Vec::new();
            for line in reader.lines() {
                match line {
                    Ok(l) => lines.push(l),
                    Err(_) => lines.push("".to_string()),
                }
            }

            for datum in analysis {
                for piece in datum.data {
                    let t1 = table.entry(piece.sym.to_owned()).or_insert(BTreeMap::new());
                    let t2 = t1.entry(piece.kind).or_insert(BTreeMap::new());
                    let t3 = t2.entry(path.to_owned()).or_insert(Vec::new());
                    let lineno = (datum.loc.lineno - 1) as usize;
                    if lineno >= lines.len() {
                        print!("Bad line number in file {} (line {})\n", path, lineno);
                        return;
                    }
                    let line = lines[lineno].clone();
                    let line_cut = line.trim_right();
                    let len = line_cut.len();
                    let line_cut = line_cut.trim_left();
                    let offset = (len - line_cut.len()) as u32;
                    let mut buf = String::new();
                    let mut i = 0;
                    for c in line_cut.chars() {
                        buf.push(c);
                        i += 1;
                        if i > 100 {
                            break;
                        }
                    }
                    t3.push(SearchResult {
                        lineno: datum.loc.lineno,
                        bounds: (datum.loc.col_start - offset, datum.loc.col_end - offset),
                        line: buf,
                        context: piece.context,
                        contextsym: piece.contextsym,
                    });

                    pretty_table.insert(piece.sym.to_owned(), piece.pretty.to_owned());

                    let ch = piece.sym.chars().nth(0).unwrap();
                    if !(ch >= '0' && ch <= '9') && !piece.sym.contains(' ') {
                        let t1 = id_table.entry(piece.pretty.to_owned()).or_insert(BTreeSet::new());
                        t1.insert(piece.sym.to_owned());
                    }
                }
            }
        };

        let f = File::open(filenames_file).unwrap();
        let file = BufReader::new(&f);
        for line in file.lines() {
            process_file(&line.unwrap());
        }
    }

    let mut outputf = File::create(output_file).unwrap();

    for (id, id_data) in table {
        let mut kindmap = BTreeMap::new();
        for (kind, kind_data) in &id_data {
            let mut result = Vec::new();
            for (path, results) in kind_data {
                let mut obj = BTreeMap::new();
                obj.insert("path".to_string(), path.to_json());
                obj.insert("lines".to_string(), results.to_json());
                result.push(Json::Object(obj));
            }
            let kindstr = match *kind {
                AnalysisKind::Use => "Uses",
                AnalysisKind::Def => "Definitions",
                AnalysisKind::Assign => "Assignments",
                AnalysisKind::Decl => "Declarations",
                AnalysisKind::Idl => "IDL",
            };
            kindmap.insert(kindstr.to_string(), Json::Array(result));
        }
        let kindmap = Json::Object(kindmap);

        let _ = outputf.write_all(format!("{}\n{}\n", id, kindmap.to_string()).as_bytes());

        if id_data.contains_key(&AnalysisKind::Def) {
            let defs = id_data.get(&AnalysisKind::Def).unwrap();
            if defs.len() == 1 {
                for (path, results) in defs {
                    if results.len() == 1 {
                        let mut v = Vec::new();
                        v.push(id.to_json());
                        v.push(path.to_json());
                        v.push(results[0].lineno.to_json());
                        let pretty = pretty_table.get(&id).unwrap();
                        v.push(pretty.to_json());
                        jumps.push(Json::Array(v));
                    }
                }
            }
        }
    }

    let mut jumpf = File::create(jump_file).unwrap();
    for jump in jumps {
        let _ = jumpf.write_all((jump.to_string() + "\n").as_bytes());
    }

    let mut idf = File::create(id_file).unwrap();
    for (id, syms) in id_table {
        for sym in syms {
            let components = split_scopes(&id);
            for i in 0..components.len() {
                let sub = &components[i..components.len()];
                let sub = sub.join("::");

                if !sub.is_empty() {
                    let line = format!("{} {}\n", sub, sym);
                    let _ = idf.write_all(line.as_bytes());
                }
            }
        }
    }
}
<commit_msg>Bug 1415700, part 1 - Don't duplicate file paths in crossref.rs.<commit_after>use std::fs::File;
use std::env;
use std::io::BufReader;
use std::io::BufRead;
use std::io::Write;
use std::collections::HashMap;
use std::collections::BTreeMap;
use std::collections::BTreeSet;

extern crate tools;
use tools::find_source_file;
use tools::file_format::analysis::{read_analysis, read_target, AnalysisKind};
use tools::config;

extern crate rustc_serialize;
use rustc_serialize::json::{Json, ToJson};

#[derive(Debug)]
struct SearchResult {
    lineno: u32,
    bounds: (u32, u32),
    line: String,
    context: String,
    contextsym: String,
}

impl ToJson for SearchResult {
    fn to_json(&self) -> Json {
        let (st, en) = self.bounds;
        let bounds = vec![st, en];

        let mut obj = BTreeMap::new();
        obj.insert("lno".to_string(), self.lineno.to_json());
        obj.insert("bounds".to_string(), bounds.to_json());
        obj.insert("line".to_string(), self.line.to_json());
        obj.insert("context".to_string(), self.context.to_json());
        obj.insert("contextsym".to_string(), self.contextsym.to_json());
        Json::Object(obj)
    }
}

fn split_scopes(id: &str) -> Vec<String> {
    let mut result = Vec::new();
    let mut start = 0;
    let mut argument_nesting = 0;
    for (index, m) in id.match_indices(|c| c == ':' || c == '<' || c == '>') {
        if m == ":" && argument_nesting == 0 {
            if start != index {
                result.push(id[start .. index].to_owned());
                start = index + 1;
            } else {
                start = index + 1;
            }
        } else if m == "<" {
            argument_nesting += 1;
        } else if m == ">" {
            argument_nesting -= 1;
        }
    }
    result.push(id[start ..].to_owned());
    return result;
}

fn main() {
    let args: Vec<_> = env::args().collect();

    let cfg = config::load(&args[1], false);

    let tree_name = &args[2];
    let tree_config = cfg.trees.get(tree_name).unwrap();

    let filenames_file = &args[3];

    let file_paths: Vec<String> = BufReader::new(File::open(filenames_file).unwrap())
        .lines().map(|x| x.unwrap()).collect();
    let output_file = format!("{}/crossref", tree_config.paths.index_path);
    let jump_file = format!("{}/jumps", tree_config.paths.index_path);
    let id_file = format!("{}/identifiers", tree_config.paths.index_path);

    let mut table = BTreeMap::new();
    let mut pretty_table = HashMap::new();
    let mut id_table = BTreeMap::new();
    let mut jumps = Vec::new();

    {
        for path in &file_paths {
            print!("File {}\n", path);

            let analysis_fname = format!("{}/analysis/{}", tree_config.paths.index_path, path);
            let analysis = read_analysis(&analysis_fname, &read_target);

            let source_fname = find_source_file(path, &tree_config.paths.files_path, &tree_config.paths.objdir_path);
            let source_file = match File::open(source_fname) {
                Ok(f) => f,
                Err(_) => {
                    println!("Unable to open source file");
                    continue;
                },
            };
            let reader = BufReader::new(&source_file);
            let mut lines = Vec::new();
            for line in reader.lines() {
                match line {
                    Ok(l) => lines.push(l),
                    Err(_) => lines.push("".to_string()),
                }
            }

            for datum in analysis {
                for piece in datum.data {
                    let t1 = table.entry(piece.sym.to_owned()).or_insert(BTreeMap::new());
                    let t2 = t1.entry(piece.kind).or_insert(BTreeMap::new());
                    let p: &str = &path;
                    let t3 = t2.entry(p).or_insert(Vec::new());
                    let lineno = (datum.loc.lineno - 1) as usize;
                    if lineno >= lines.len() {
                        print!("Bad line number in file {} (line {})\n", path, lineno);
                        continue;
                    }
                    let line = lines[lineno].clone();
                    let line_cut = line.trim_right();
                    let len = line_cut.len();
                    let line_cut = line_cut.trim_left();
                    let offset = (len - line_cut.len()) as u32;
                    let mut buf = String::new();
                    let mut i = 0;
                    for c in line_cut.chars() {
                        buf.push(c);
                        i += 1;
                        if i > 100 {
                            break;
                        }
                    }
                    t3.push(SearchResult {
                        lineno: datum.loc.lineno,
                        bounds: (datum.loc.col_start - offset, datum.loc.col_end - offset),
                        line: buf,
                        context: piece.context,
                        contextsym: piece.contextsym,
                    });

                    pretty_table.insert(piece.sym.to_owned(), piece.pretty.to_owned());

                    let ch = piece.sym.chars().nth(0).unwrap();
                    if !(ch >= '0' && ch <= '9') && !piece.sym.contains(' ') {
                        let t1 = id_table.entry(piece.pretty.to_owned()).or_insert(BTreeSet::new());
                        t1.insert(piece.sym.to_owned());
                    }
                }
            }
        }
    }

    let mut outputf = File::create(output_file).unwrap();

    for (id, id_data) in table {
        let mut kindmap = BTreeMap::new();
        for (kind, kind_data) in &id_data {
            let mut result = Vec::new();
            for (path, results) in kind_data {
                let mut obj = BTreeMap::new();
                obj.insert("path".to_string(), path.to_json());
                obj.insert("lines".to_string(), results.to_json());
                result.push(Json::Object(obj));
            }
            let kindstr = match *kind {
                AnalysisKind::Use => "Uses",
                AnalysisKind::Def => "Definitions",
                AnalysisKind::Assign => "Assignments",
                AnalysisKind::Decl => "Declarations",
                AnalysisKind::Idl => "IDL",
            };
            kindmap.insert(kindstr.to_string(), Json::Array(result));
        }
        let kindmap = Json::Object(kindmap);

        let _ = outputf.write_all(format!("{}\n{}\n", id, kindmap.to_string()).as_bytes());

        if id_data.contains_key(&AnalysisKind::Def) {
            let defs = id_data.get(&AnalysisKind::Def).unwrap();
            if defs.len() == 1 {
                for (path, results) in defs {
                    if results.len() == 1 {
                        let mut v = Vec::new();
                        v.push(id.to_json());
                        v.push(path.to_json());
                        v.push(results[0].lineno.to_json());
                        let pretty = pretty_table.get(&id).unwrap();
                        v.push(pretty.to_json());
                        jumps.push(Json::Array(v));
                    }
                }
            }
        }
    }

    let mut jumpf = File::create(jump_file).unwrap();
    for jump in jumps {
        let _ = jumpf.write_all((jump.to_string() + "\n").as_bytes());
    }

    let mut idf = File::create(id_file).unwrap();
    for (id, syms) in id_table {
        for sym in syms {
            let components = split_scopes(&id);
            for i in 0..components.len() {
                let sub = &components[i..components.len()];
                let sub = sub.join("::");

                if !sub.is_empty() {
                    let line = format!("{} {}\n", sub, sym);
                    let _ = idf.write_all(line.as_bytes());
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Clippy wrappers around rustc's diagnostic functions.
//!
//! These functions are used by the `INTERNAL_METADATA_COLLECTOR` lint to collect the corresponding
//! lint applicability. Please make sure that you update the `LINT_EMISSION_FUNCTIONS` variable in
//! `clippy_lints::utils::internal_lints::metadata_collector` when a new function is added
//! or renamed.
//!
//! Thank you!
//! ~The `INTERNAL_METADATA_COLLECTOR` lint

use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir::HirId;
use rustc_lint::{LateContext, Lint, LintContext};
use rustc_span::source_map::{MultiSpan, Span};
use std::env;

fn docs_link(diag: &mut DiagnosticBuilder<'_>, lint: &'static Lint) {
    if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
        if let Some(lint) = lint.name_lower().strip_prefix("clippy::") {
            diag.help(&format!(
                "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
                &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
                    // extract just major + minor version and ignore patch versions
                    format!("rust-{}", n.rsplit_once('.').unwrap().1)
                }),
                lint
            ));
        }
    }
}

/// Emit a basic lint message with a `msg` and a `span`.
///
/// This is the most primitive of our lint emission methods and can
/// be a good way to get a new lint started.
///
/// Usually it's nicer to provide more context for lint messages.
/// Be sure the output is understandable when you use this method.
///
/// # Example
///
/// ```ignore
/// error: usage of mem::forget on Drop type
///   --> $DIR/mem_forget.rs:17:5
///    |
/// 17 |     std::mem::forget(seven);
///    |     ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
    cx.struct_span_lint(lint, sp, |diag| {
        let mut diag = diag.build(msg);
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

/// Same as `span_lint` but with an extra `help` message.
///
/// Use this if you want to provide some general help but
/// can't provide a specific machine applicable suggestion.
///
/// The `help` message can be optionally attached to a `Span`.
///
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
///
/// # Example
///
/// ```text
/// error: constant division of 0.0 with 0.0 will always result in NaN
///   --> $DIR/zero_div_zero.rs:6:25
///    |
/// 6  |     let other_f64_nan = 0.0f64 / 0.0;
///    |                         ^^^^^^^^^^^^
///    |
///    = help: Consider using `f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    span: Span,
    msg: &str,
    help_span: Option<Span>,
    help: &str,
) {
    cx.struct_span_lint(lint, span, |diag| {
        let mut diag = diag.build(msg);
        if let Some(help_span) = help_span {
            diag.span_help(help_span, help);
        } else {
            diag.help(help);
        }
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

/// Like `span_lint` but with a `note` section instead of a `help` message.
///
/// The `note` message is presented separately from the main lint message
/// and is attached to a specific span:
///
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
///
/// # Example
///
/// ```text
/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
///   --> $DIR/drop_forget_ref.rs:10:5
///    |
/// 10 |     forget(&SomeStruct);
///    |     ^^^^^^^^^^^^^^^^^^^
///    |
///    = note: `-D clippy::forget-ref` implied by `-D warnings`
/// note: argument has type &SomeStruct
///   --> $DIR/drop_forget_ref.rs:10:12
///    |
/// 10 |     forget(&SomeStruct);
///    |            ^^^^^^^^^^^
/// ```
pub fn span_lint_and_note<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    span: impl Into<MultiSpan>,
    msg: &str,
    note_span: Option<Span>,
    note: &str,
) {
    cx.struct_span_lint(lint, span, |diag| {
        let mut diag = diag.build(msg);
        if let Some(note_span) = note_span {
            diag.span_note(note_span, note);
        } else {
            diag.note(note);
        }
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

/// Like `span_lint` but allows to add notes, help and suggestions using a closure.
///
/// If you need to customize your lint output a lot, use this function.
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
pub fn span_lint_and_then<C, S, F>(cx: &C, lint: &'static Lint, sp: S, msg: &str, f: F)
where
    C: LintContext,
    S: Into<MultiSpan>,
    F: FnOnce(&mut DiagnosticBuilder<'_>),
{
    cx.struct_span_lint(lint, sp, |diag| {
        let mut diag = diag.build(msg);
        f(&mut diag);
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
        let mut diag = diag.build(msg);
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

pub fn span_lint_hir_and_then(
    cx: &LateContext<'_>,
    lint: &'static Lint,
    hir_id: HirId,
    sp: impl Into<MultiSpan>,
    msg: &str,
    f: impl FnOnce(&mut DiagnosticBuilder<'_>),
) {
    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
        let mut diag = diag.build(msg);
        f(&mut diag);
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

/// Add a span lint with a suggestion on how to fix it.
///
/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
/// 2)"`.
///
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
///
/// # Example
///
/// ```text
/// error: This `.fold` can be more succinctly expressed as `.any`
/// --> $DIR/methods.rs:390:13
///     |
/// 390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
///     |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
///     |
///     = note: `-D fold-any` implied by `-D warnings`
/// ```
#[cfg_attr(feature = "internal-lints", allow(clippy::collapsible_span_lint_calls))]
pub fn span_lint_and_sugg<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    sp: Span,
    msg: &str,
    help: &str,
    sugg: String,
    applicability: Applicability,
) {
    span_lint_and_then(cx, lint, sp, msg, |diag| {
        diag.span_suggestion(sp, help, sugg, applicability);
    });
}

/// Create a suggestion made from several `span → replacement`.
///
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
/// appear once per
/// replacement. In human-readable format though, it only appears once before
/// the whole suggestion.
pub fn multispan_sugg<I>(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: I)
where
    I: IntoIterator<Item = (Span, String)>,
{
    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg);
}

/// Create a suggestion made from several `span → replacement`.
///
/// rustfix currently doesn't support the automatic application of suggestions with
/// multiple spans. This is tracked in issue [rustfix#141](https://github.com/rust-lang/rustfix/issues/141).
/// Suggestions with multiple spans will be silently ignored.
pub fn multispan_sugg_with_applicability<I>(
    diag: &mut DiagnosticBuilder<'_>,
    help_msg: &str,
    applicability: Applicability,
    sugg: I,
) where
    I: IntoIterator<Item = (Span, String)>,
{
    diag.multipart_suggestion(help_msg, sugg.into_iter().collect(), applicability);
}
<commit_msg>Auto merge of #7926 - lengyijun:patch-1, r=giraffate<commit_after>//! Clippy wrappers around rustc's diagnostic functions.
//!
//! These functions are used by the `INTERNAL_METADATA_COLLECTOR` lint to collect the corresponding
//! lint applicability. Please make sure that you update the `LINT_EMISSION_FUNCTIONS` variable in
//! `clippy_lints::utils::internal_lints::metadata_collector` when a new function is added
//! or renamed.
//!
//! Thank you!
//! ~The `INTERNAL_METADATA_COLLECTOR` lint

use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir::HirId;
use rustc_lint::{LateContext, Lint, LintContext};
use rustc_span::source_map::{MultiSpan, Span};
use std::env;

fn docs_link(diag: &mut DiagnosticBuilder<'_>, lint: &'static Lint) {
    if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
        if let Some(lint) = lint.name_lower().strip_prefix("clippy::") {
            diag.help(&format!(
                "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{}",
                &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
                    // extract just major + minor version and ignore patch versions
                    format!("rust-{}", n.rsplit_once('.').unwrap().1)
                }),
                lint
            ));
        }
    }
}

/// Emit a basic lint message with a `msg` and a `span`.
///
/// This is the most primitive of our lint emission methods and can
/// be a good way to get a new lint started.
///
/// Usually it's nicer to provide more context for lint messages.
/// Be sure the output is understandable when you use this method.
///
/// # Example
///
/// ```ignore
/// error: usage of mem::forget on Drop type
///   --> $DIR/mem_forget.rs:17:5
///    |
/// 17 |     std::mem::forget(seven);
///    |     ^^^^^^^^^^^^^^^^^^^^^^^
/// ```
pub fn span_lint<T: LintContext>(cx: &T, lint: &'static Lint, sp: impl Into<MultiSpan>, msg: &str) {
    cx.struct_span_lint(lint, sp, |diag| {
        let mut diag = diag.build(msg);
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

/// Same as `span_lint` but with an extra `help` message.
///
/// Use this if you want to provide some general help but
/// can't provide a specific machine applicable suggestion.
///
/// The `help` message can be optionally attached to a `Span`.
///
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
///
/// # Example
///
/// ```text
/// error: constant division of 0.0 with 0.0 will always result in NaN
///   --> $DIR/zero_div_zero.rs:6:25
///    |
/// 6  |     let other_f64_nan = 0.0f64 / 0.0;
///    |                         ^^^^^^^^^^^^
///    |
///    = help: consider using `f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    span: Span,
    msg: &str,
    help_span: Option<Span>,
    help: &str,
) {
    cx.struct_span_lint(lint, span, |diag| {
        let mut diag = diag.build(msg);
        if let Some(help_span) = help_span {
            diag.span_help(help_span, help);
        } else {
            diag.help(help);
        }
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

/// Like `span_lint` but with a `note` section instead of a `help` message.
///
/// The `note` message is presented separately from the main lint message
/// and is attached to a specific span:
///
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
///
/// # Example
///
/// ```text
/// error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing.
///   --> $DIR/drop_forget_ref.rs:10:5
///    |
/// 10 |     forget(&SomeStruct);
///    |     ^^^^^^^^^^^^^^^^^^^
///    |
///    = note: `-D clippy::forget-ref` implied by `-D warnings`
/// note: argument has type &SomeStruct
///   --> $DIR/drop_forget_ref.rs:10:12
///    |
/// 10 |     forget(&SomeStruct);
///    |            ^^^^^^^^^^^
/// ```
pub fn span_lint_and_note<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    span: impl Into<MultiSpan>,
    msg: &str,
    note_span: Option<Span>,
    note: &str,
) {
    cx.struct_span_lint(lint, span, |diag| {
        let mut diag = diag.build(msg);
        if let Some(note_span) = note_span {
            diag.span_note(note_span, note);
        } else {
            diag.note(note);
        }
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

/// Like `span_lint` but allows to add notes, help and suggestions using a closure.
///
/// If you need to customize your lint output a lot, use this function.
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
pub fn span_lint_and_then<C, S, F>(cx: &C, lint: &'static Lint, sp: S, msg: &str, f: F)
where
    C: LintContext,
    S: Into<MultiSpan>,
    F: FnOnce(&mut DiagnosticBuilder<'_>),
{
    cx.struct_span_lint(lint, sp, |diag| {
        let mut diag = diag.build(msg);
        f(&mut diag);
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

pub fn span_lint_hir(cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, sp: Span, msg: &str) {
    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
        let mut diag = diag.build(msg);
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

pub fn span_lint_hir_and_then(
    cx: &LateContext<'_>,
    lint: &'static Lint,
    hir_id: HirId,
    sp: impl Into<MultiSpan>,
    msg: &str,
    f: impl FnOnce(&mut DiagnosticBuilder<'_>),
) {
    cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |diag| {
        let mut diag = diag.build(msg);
        f(&mut diag);
        docs_link(&mut diag, lint);
        diag.emit();
    });
}

/// Add a span lint with a suggestion on how to fix it.
///
/// These suggestions can be parsed by rustfix to allow it to automatically fix your code.
/// In the example below, `help` is `"try"` and `sugg` is the suggested replacement `".any(|x| x >
/// 2)"`.
///
/// If you change the signature, remember to update the internal lint `CollapsibleCalls`
///
/// # Example
///
/// ```text
/// error: This `.fold` can be more succinctly expressed as `.any`
/// --> $DIR/methods.rs:390:13
///     |
/// 390 |     let _ = (0..3).fold(false, |acc, x| acc || x > 2);
///     |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.any(|x| x > 2)`
///     |
///     = note: `-D fold-any` implied by `-D warnings`
/// ```
#[cfg_attr(feature = "internal-lints", allow(clippy::collapsible_span_lint_calls))]
pub fn span_lint_and_sugg<'a, T: LintContext>(
    cx: &'a T,
    lint: &'static Lint,
    sp: Span,
    msg: &str,
    help: &str,
    sugg: String,
    applicability: Applicability,
) {
    span_lint_and_then(cx, lint, sp, msg, |diag| {
        diag.span_suggestion(sp, help, sugg, applicability);
    });
}

/// Create a suggestion made from several `span → replacement`.
///
/// Note: in the JSON format (used by `compiletest_rs`), the help message will
/// appear once per
/// replacement. In human-readable format though, it only appears once before
/// the whole suggestion.
pub fn multispan_sugg<I>(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: I)
where
    I: IntoIterator<Item = (Span, String)>,
{
    multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg);
}

/// Create a suggestion made from several `span → replacement`.
///
/// rustfix currently doesn't support the automatic application of suggestions with
/// multiple spans. This is tracked in issue [rustfix#141](https://github.com/rust-lang/rustfix/issues/141).
/// Suggestions with multiple spans will be silently ignored.
pub fn multispan_sugg_with_applicability<I>(
    diag: &mut DiagnosticBuilder<'_>,
    help_msg: &str,
    applicability: Applicability,
    sugg: I,
) where
    I: IntoIterator<Item = (Span, String)>,
{
    diag.multipart_suggestion(help_msg, sugg.into_iter().collect(), applicability);
}
<|endoftext|>


<commit_before>//!
//!

use std::io;

use common;
use common::{Error, XmlVersion, Name, NamespaceStack, is_name_start_char, is_name_char, is_whitespace_char};
use events;
use events::XmlEvent;

use writer::config::EmitterConfig;

pub enum EmitterErrorKind {
    IoError,
    UnexpectedEvent,
    InvalidWhitespaceEvent
}

pub struct EmitterError {
    kind: EmitterErrorKind,
    message: &'static str,
    cause: Option<io::IoError>
}

fn error(kind: EmitterErrorKind, message: &'static str) -> EmitterError {
    EmitterError {
        kind: kind,
        message: message,
        cause: None
    }
}

#[inline]
fn io_error(err: io::IoError) -> EmitterError {
    EmitterError { kind: IoError, message: "Input/output error", cause: Some(err) }
}

pub type EmitterResult<T> = Result<T, EmitterError>;
pub type Chunk = EmitterResult<~str>;

#[inline]
fn io_wrap<T>(result: io::IoResult<T>) -> EmitterResult<T> {
    result.map_err(io_error)
}

pub struct EventEmitter {
    priv config: EmitterConfig,
    priv indent_level: uint,
    priv indent_stack: Vec<u8>,
    priv nst: NamespaceStack
}

pub fn new(config: EmitterConfig) -> Emitter {
    Emitter {
        config: config,
        nst: NamespaceStack::empty(),
        indent_level: 0,
        indent_stack: vec!()
    }
}

macro_rules! io_try(
    ($e:expr) => (
        match $e {
            Ok(value) => value,
            Err(err) => return Err(io_error(err))
        }
    )
)

impl EventEmitter {
    /// Returns current state of namespaces.
    pub fn namespace_stack<'a>(&'a self) -> &'a NamespaceStack {
        & self.nst
    }

    pub fn emit<W: Writer>(&mut self, mut target: W, event: XmlEvent) -> EmitterResult<()> {
        let chunk = try!(self.dispatch_event(event));
        io_wrap(target.write_str(chunk))
    }

    fn dispatch_event(&mut self, event: XmlEvent) -> Chunk {
        match event {
            StartDocument { version, encoding, standalone } =>
                self.emit_start_document(version, encoding, standalone),
            EndDocument => self.emit_end_document(),
            ProcessingInstruction { name, data } =>
                self.emit_processing_instruction(name, data),
            StartElement { name, attributes, namespace } =>
                self.emit_start_element(name, attributes, namespace),
            EndElement { name } =>
                self.emit_end_element(name),
            CData(content) => self.emit_cdata(content),
            Characters(content) => self.emit_characters(content),
            Whitespace(content) => self.emit_whitespace(content),
            Error(_) => error(UnexpectedError, "Error event cannot be emitted")
        }
    }

    fn emit_start_document(version: XmlVersion, encoding: ~str, standalone: Option<bool>) -> Chunk {
        Ok(box "")
    }

    fn emit_processing_instruction(name: ~str, data: Option<~str>) -> Chunk {
        Ok(box "")
    }

    fn emit_start_element(name: Name, attributes: Vec<Attribute>, namespace: Namespace) -> Chunk {
        Ok(box "")
    }

    fn emit_end_element(name: Name) -> Chunk {
        Ok(box "")
    }

    fn emit_cdata(content: ~str) -> Chunk {
        Ok(box "")
    }

    fn emit_whitespace(content: ~str) -> Chunk {

    }
}
<commit_msg>Removed weird file<commit_after><|endoftext|>