<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::{DutiesManager, DutiesManagerService, EpochDutiesMap};
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, NodeInfo};
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{info, o, warn, Drain};
use slot_clock::SystemTimeSlotClock;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use types::{Epoch, Fork};

/// 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 keeping track of time.
    slot_clock: Arc<SystemTimeSlotClock>,
}

impl Service {
    ///  Initial connection to the beacon node to determine its properties.
    fn connect_to_node(
        node_client: Arc<BeaconNodeServiceClient>,
        seconds_per_slot: u64,
        log: &slog::Logger,
    ) -> Self {
        // retrieve node information
        let node_info = loop {
            let info = match 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) => 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()),
        };

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

        Self {
            connected_node_version: node_info.version,
            chain_id: node_info.chain_id as u16,
            fork,
            slot_clock,
        }
    }

    pub fn start(config: ValidatorConfig, log: slog::Logger) {
        // initialize the RPC clients

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

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

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

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

        let spec = Arc::new(config.spec);
        // connect to the node and retrieve its properties
        let service =
            Service::connect_to_node(beacon_node_grpc_client, spec.seconds_per_slot, &log);

        let poll_interval_millis = spec.seconds_per_slot * 1000 / 10; // 10% epoch time precision.
        info!(log, "Starting block producer service"; "polls_per_epoch" => spec.seconds_per_slot * 1000 / poll_interval_millis);

        let genesis_time = 1_549_935_547;
        let slot_clock = {
            info!(log, "Genesis time"; "unix_epoch_seconds" => genesis_time);
            let clock = SystemTimeSlotClock::new(genesis_time, spec.seconds_per_slot)
                .expect("Unable to instantiate SystemTimeSlotClock.");
            Arc::new(clock)
        };

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

        for keypair in keypairs {
            info!(log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id());
            let duties_map = Arc::new(EpochDutiesMap::new(spec.slots_per_epoch));
            let epoch_map_for_attester = Arc::new(EpochMap::new(spec.slots_per_epoch));

            // 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 = slot_clock.clone();
                let log = log.clone();
                let beacon_node = validator_grpc_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>Setup basic structure before tokio runtime addition<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::{DutiesManager, DutiesManagerService, EpochDutiesMap};
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, NodeInfo};
use protos::services_grpc::{
    AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient,
    ValidatorServiceClient,
};
use slog::{info, o, warn, Drain};
use slot_clock::SystemTimeSlotClock;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use types::{Epoch, Fork};

/// 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 keeping track of time.
    slot_clock: Arc<SystemTimeSlotClock>,
    // 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 {
    /// Initialise the service then run the core thread.
    pub fn start(config: ValidatorConfig, log: slog::Logger) {
        // 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
        service.run(config);
    }

    ///  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) -> 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 {
            let info = 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) => 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()),
        };

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

        // 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))
        };

        Self {
            connected_node_version: node_info.version,
            chain_id: node_info.chain_id as u16,
            fork,
            slot_clock,
            beacon_block_client,
            validator_client,
            attester_client,
            log,
        }
    }

    fn run(&mut self, config: ValidatorConfig) {
        /*
         * Start threads.
         */
        let mut threads = vec![];
        // TODO: keypairs are randomly generated; they should be loaded from a file or generated.
        // https://github.com/sigp/lighthouse/issues/160
        let keypairs = vec![Keypair::random()];

        let spec = config.spec;

        for keypair in keypairs {
            info!(self.log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id());
            let duties_map = Arc::new(EpochDutiesMap::new(spec.slots_per_epoch));
            let epoch_map_for_attester = Arc::new(EpochMap::new(spec.slots_per_epoch));

            // 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>use std::marker::PhantomData;

use common::err::{Error, TResult};
use common::plan::{Plan, Visitor};
use common::plugin::{PackageManager};

pub fn create_plan(pkg_mgr: &PackageManager, plan: &Plan) -> TResult<ExecutionPlan> {
  Err(Error::NotImplemented)
}

pub struct ExecutionPlanner;

impl<'a> Visitor<'a> for ExecutionPlanner {
}

pub struct ExecutionPlan;
<commit_msg>Improved skeleton code for the execution planner.<commit_after>use std::marker::PhantomData;

use common::err::{Error, TResult};
use common::plan::*;
use common::plugin::{PackageManager};
use exec::Executor;

pub fn create_plan(pkg_mgr: &PackageManager, plan: &Plan) -> TResult<ExecutionPlan> {
  let mut planner = ExecutionPlanner::new();
  walk_plan(&mut planner, plan);
  planner.plan()
}

pub struct ExecutionPlan {
  stack: Vec<Box<Executor>>
}

impl ExecutionPlan {
  pub fn new() -> ExecutionPlan
  {
    ExecutionPlan {stack: Vec::new()}
  }
}

pub struct ExecutionPlanner {
  plan: ExecutionPlan,
  err: Option<Error>
}

impl ExecutionPlanner
{
  pub fn new() -> ExecutionPlanner
  {
    ExecutionPlanner {
      plan: ExecutionPlan::new(),
      err : None
    }
  }

  pub fn plan(self) -> TResult<ExecutionPlan>
  {
    match self.err {
      Some(e) => Err(e),
      None    => Ok(self.plan)
    }
  }
}

impl<'a> Visitor<'a> for ExecutionPlanner
{
  fn visit_from(&mut self, ds: &DataSet)
  {
  }

  fn visit_head(&mut self, child: &Plan, rownum: usize)
  {
    walk_plan(self, child);
  }

  fn visit_tail(&mut self, child: &Plan, rownum: usize)
  {
    walk_plan(self, child);
  }
}

<|endoftext|>


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

extern crate env_logger;
extern crate grin_chain as chain;
extern crate grin_core as core;
extern crate grin_keychain as keychain;
extern crate grin_pow as pow;
extern crate rand;

use std::fs;

use chain::{ChainStore, Tip};
use core::core::hash::Hashed;
use core::core::Block;
use core::core::BlockHeader;
use core::core::target::Difficulty;
use keychain::Keychain;
use core::global;
use core::global::ChainTypes;

fn clean_output_dir(dir_name: &str) {
	let _ = fs::remove_dir_all(dir_name);
}

#[test]
fn test_various_store_indices() {
	let _ = env_logger::init();
	clean_output_dir(".grin");

	let keychain = Keychain::from_random_seed().unwrap();
	let key_id = keychain.derive_key_id(1).unwrap();

	let chain_store = &chain::store::ChainKVStore::new(".grin".to_string()).unwrap() as &ChainStore;

	global::set_mining_mode(ChainTypes::AutomatedTesting);
	let genesis = pow::mine_genesis_block(None).unwrap();
	chain_store.save_block(&genesis).unwrap();
	chain_store
		.setup_height(&genesis.header, &Tip::new(genesis.hash()))
		.unwrap();

	let block = Block::new(
		&genesis.header,
		vec![],
		&keychain,
		&key_id,
		Difficulty::one(),
	).unwrap();
	let block_hash = block.hash();

	chain_store.save_block(&block).unwrap();
	chain_store
		.setup_height(&block.header, &Tip::from_block(&block.header))
		.unwrap();

	let block_header = chain_store.get_block_header(&block_hash).unwrap();
	assert_eq!(block_header.hash(), block_hash);

	let block_header = chain_store.get_header_by_height(1).unwrap();
	assert_eq!(block_header.hash(), block_hash);
}

#[test]
fn test_store_header_height() {
	let _ = env_logger::init();
	clean_output_dir(".grin");

	let chain_store = &chain::store::ChainKVStore::new(".grin".to_string()).unwrap() as &ChainStore;

	let mut block_header = BlockHeader::default();
	block_header.height = 1;

	chain_store.save_block_header(&block_header).unwrap();
	chain_store.save_header_height(&block_header).unwrap();

	let stored_block_header = chain_store.get_header_by_height(1).unwrap();
	assert_eq!(block_header.hash(), stored_block_header.hash());

	chain_store.delete_header_by_height(1).unwrap();

	let result = chain_store.get_header_by_height(1);
	assert_eq!(result.is_err(), true);
}
<commit_msg>Fix test dirs to isolate the tests (#786)<commit_after>// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate env_logger;
extern crate grin_chain as chain;
extern crate grin_core as core;
extern crate grin_keychain as keychain;
extern crate grin_pow as pow;
extern crate rand;

use std::fs;

use chain::{ChainStore, Tip};
use core::core::hash::Hashed;
use core::core::Block;
use core::core::BlockHeader;
use core::core::target::Difficulty;
use keychain::Keychain;
use core::global;
use core::global::ChainTypes;

fn clean_output_dir(dir_name: &str) {
	let _ = fs::remove_dir_all(dir_name);
}

#[test]
fn test_various_store_indices() {
	let _ = env_logger::init();
	let chain_dir = ".grin_idx_1";
	clean_output_dir(chain_dir);

	let keychain = Keychain::from_random_seed().unwrap();
	let key_id = keychain.derive_key_id(1).unwrap();

	let chain_store =
		&chain::store::ChainKVStore::new(chain_dir.to_string()).unwrap() as &ChainStore;

	global::set_mining_mode(ChainTypes::AutomatedTesting);
	let genesis = pow::mine_genesis_block(None).unwrap();
	chain_store.save_block(&genesis).unwrap();
	chain_store
		.setup_height(&genesis.header, &Tip::new(genesis.hash()))
		.unwrap();

	let block = Block::new(
		&genesis.header,
		vec![],
		&keychain,
		&key_id,
		Difficulty::one(),
	).unwrap();
	let block_hash = block.hash();

	chain_store.save_block(&block).unwrap();
	chain_store
		.setup_height(&block.header, &Tip::from_block(&block.header))
		.unwrap();

	let block_header = chain_store.get_block_header(&block_hash).unwrap();
	assert_eq!(block_header.hash(), block_hash);

	let block_header = chain_store.get_header_by_height(1).unwrap();
	assert_eq!(block_header.hash(), block_hash);
}

#[test]
fn test_store_header_height() {
	let _ = env_logger::init();
	let chain_dir = ".grin_idx_2";
	clean_output_dir(chain_dir);

	let chain_store =
		&chain::store::ChainKVStore::new(chain_dir.to_string()).unwrap() as &ChainStore;

	let mut block_header = BlockHeader::default();
	block_header.height = 1;

	chain_store.save_block_header(&block_header).unwrap();
	chain_store.save_header_height(&block_header).unwrap();

	let stored_block_header = chain_store.get_header_by_height(1).unwrap();
	assert_eq!(block_header.hash(), stored_block_header.hash());

	chain_store.delete_header_by_height(1).unwrap();

	let result = chain_store.get_header_by_height(1);
	assert_eq!(result.is_err(), true);
}
<|endoftext|>


<commit_before>//! Parser event.

use std::io;
use std::io::Read;

use super::BinaryParser;
use super::error::{Result, Error, Warning};

mod attribute;

/// Parser event.
#[derive(Debug)]
pub enum Event<'a, R: 'a + Read> {
    /// Start of the FBX document.
    StartFbx(FbxHeader),
    /// End of the FBX document.
    EndFbx(FbxFooter),
    /// Start of a node.
    StartNode(StartNode<'a, R>),
    /// End of a node.
    EndNode,
}

impl<'a, R: 'a + Read> From<FbxHeader> for Event<'a, R> {
    fn from(h: FbxHeader) -> Self {
        Event::StartFbx(h)
    }
}

impl<'a, R: 'a + Read> From<FbxFooter> for Event<'a, R> {
    fn from(f: FbxFooter) -> Self {
        Event::EndFbx(f)
    }
}

impl<'a, R: 'a + Read> From<StartNode<'a, R>> for Event<'a, R> {
    fn from(h: StartNode<'a, R>) -> Self {
        Event::StartNode(h)
    }
}

/// FBX header.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FbxHeader {
    /// FBX version.
    pub version: u32,
}

/// Read FBX header.
pub fn read_fbx_header<R: Read>(parser: &mut BinaryParser<R>) -> Result<FbxHeader> {
    assert!(parser.fbx_version.is_none(),
            "Parser should read FBX header only once");
    // Check magic binary.
    {
        const MAGIC_LEN: usize = 21;
        const MAGIC: &'static [u8; MAGIC_LEN] = b"Kaydara FBX Binary  \x00";
        let mut buf = [0u8; MAGIC_LEN];
        try!(parser.source.read_exact(&mut buf));
        if buf != *MAGIC {
            return Err(Error::MagicNotDetected(buf));
        }
    }
    // Read unknown 2 bytes.
    {
        const UNKNOWN_BYTES_LEN: usize = 2;
        const UNKNOWN_BYTES: &'static [u8; UNKNOWN_BYTES_LEN] = b"\x1a\x00";
        let mut buf = [0u8; UNKNOWN_BYTES_LEN];
        try!(parser.source.read_exact(&mut buf));
        if buf != *UNKNOWN_BYTES {
            parser.warn(Warning::UnexpectedBytesAfterMagic(buf));
        }
    }
    // Get FBX version.
    let fbx_version = try!(parser.source.read_u32());

    info!("FBX header is successfully read, FBX version: {}",
          fbx_version);
    Ok(FbxHeader { version: fbx_version })
}

/// FBX footer.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FbxFooter {
    /// Unknown part 1.
    pub unknown1: [u8; 16],
    /// FBX version.
    pub version: u32,
    /// Unknown part 2.
    pub unknown2: [u8; 16],
}

impl FbxFooter {
    /// Reads node header from the given parser and returns it.
    pub fn read_from_parser<R: Read>(parser: &mut BinaryParser<R>) -> Result<Self> {
        // Read unknown 16 bytes footer.
        let mut unknown1 = [0u8; 16];
        try!(parser.source.read_exact(&mut unknown1));
        // Read padding (0--15 bytes), zeroes (4 bytes), FBX version (4 bytes), zeroes (120 bytes),
        // and optionally partial unknown footer 2 (16 bytes).
        // Note that some exporters (like Blender's "FBX format" plugin version 3.2.0) creates
        // wrong FBX file without padding.
        // For such file without padding, unknown footer 2 would be partially read.
        let expected_padding_len = ((16 - (parser.source.count() & 0x0f)) & 0x0f) as usize;
        debug!("Current position = {}, Expected padding length = {}",
               parser.source.count(),
               expected_padding_len);

        const BUF_LEN: usize = 144;
        let mut buf = [0u8; BUF_LEN];
        try!(parser.source.read_exact(&mut buf));
        // If there is no padding before the footer, unknown footer 2 is partially read into the
        // buf.
        // Count length of partially read unknown footer 2.
        let partial_footer2_len = {
            let mut count = 0;
            // Unknown footer 2 doesn't contain 0x00 byte, therefore the last 0x00 should be
            // the last byte of a padding.
            while (buf[BUF_LEN - 1 - count] != 0) && count <= 16 {
                count += 1;
            }
            if count > 16 {
                error!("FBX footer should have continuous 112 bytes of zeroes, but not found");
                return Err(Error::BrokenFbxFooter);
            }
            count
        };
        let mut unknown2 = [0u8; 16];
        // Copy partially read unknown header 2.
        unknown2[0..partial_footer2_len]
            .clone_from_slice(&buf[BUF_LEN - partial_footer2_len..BUF_LEN]);
        // Read the rest of the unknown footer 2 (max 16 bytes).
        try!(parser.source.read_exact(&mut unknown2[partial_footer2_len..]));

        // Check whether padding before the footer exists.
        if 16 - partial_footer2_len == expected_padding_len {
            // Padding exists.
            // Note that its length might be 0.
            info!("Padding exists (as expected) before the footer (len={})",
                  expected_padding_len);
        } else if partial_footer2_len == 16 {
            // Padding doesn't exist while it should.
            warn!("Expected padding (len={}) but not found",
                  expected_padding_len);
        } else {
            error!("Unexpected padding length: expected={}, got={}",
                   expected_padding_len,
                   16 - partial_footer2_len);
            return Err(Error::BrokenFbxFooter);
        }

        // Check the FBX version.
        let footer_fbx_version = {
            // 20 - partial_footer2_len == BUF_LEN - partial_footer2_len - 120 - 4
            let ver_offset = 20 - partial_footer2_len;
            // FBX version is stored as `u32` in Little Endian.
            (buf[ver_offset] as u32) | (buf[ver_offset + 1] as u32) << 8 |
            (buf[ver_offset + 2] as u32) << 16 | (buf[ver_offset + 3] as u32) << 24
        };
        let header_fbx_version = parser.fbx_version
            .expect("Parser should remember FBX version in the FBX header but it doesn't");
        if header_fbx_version != footer_fbx_version {
            return Err(Error::HeaderFooterVersionMismatch {
                header: header_fbx_version,
                footer: footer_fbx_version,
            });
        }

        Ok(FbxFooter {
            unknown1: unknown1,
            version: footer_fbx_version,
            unknown2: unknown2,
        })
    }
}

/// FBX node info.
#[derive(Debug)]
pub struct StartNode<'a, R: 'a + Read> {
    /// Node name.
    pub name: String,
    /// Parser.
    _parser: &'a mut BinaryParser<R>,
}

/// Parser event without reference to a parser.
#[derive(Debug, Clone)]
pub enum EventBuilder {
    /// Start of the FBX document.
    StartFbx(FbxHeader),
    /// End of the FBX document.
    EndFbx(FbxFooter),
    /// Start of a node.
    StartNode(StartNodeBuilder),
    /// End of a node.
    EndNode,
}

impl EventBuilder {
    /// Creates `Event` from the `EventBuilder` and the given parser.
    pub fn build<R: Read>(self, parser: &mut BinaryParser<R>) -> Event<R> {
        match self {
            EventBuilder::StartFbx(header) => header.into(),
            EventBuilder::EndFbx(footer) => footer.into(),
            EventBuilder::StartNode(builder) => builder.build(parser).into(),
            EventBuilder::EndNode => Event::EndNode,
        }
    }
}

impl From<FbxHeader> for EventBuilder {
    fn from(h: FbxHeader) -> Self {
        EventBuilder::StartFbx(h)
    }
}

impl From<FbxFooter> for EventBuilder {
    fn from(f: FbxFooter) -> Self {
        EventBuilder::EndFbx(f)
    }
}

impl From<StartNodeBuilder> for EventBuilder {
    fn from(h: StartNodeBuilder) -> Self {
        EventBuilder::StartNode(h)
    }
}

/// `StartNode` without reference to a parser.
#[derive(Debug, Clone)]
pub struct StartNodeBuilder {
    /// Node name.
    pub name: String,
}

impl StartNodeBuilder {
    /// Creates `StartNode` from the `StartNodeBuilder` and the given parser.
    pub fn build<R: Read>(self, parser: &mut BinaryParser<R>) -> StartNode<R> {
        StartNode {
            name: self.name,
            _parser: parser,
        }
    }
}

/// Fixed size node header (without node name field).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NodeHeader {
    /// End offset of the node.
    pub end_offset: u64,
    /// Number of the node attributes.
    pub num_attributes: u64,
    /// Byte length of the node attributes.
    pub len_attributes: u64,
    /// Length of the node name.
    pub len_name: u8,
}

impl NodeHeader {
    /// Returns true if all fields of the node header is `0`.
    pub fn is_node_end(&self) -> bool {
        self.end_offset == 0 && self.num_attributes == 0 && self.len_attributes == 0 &&
        self.len_name == 0
    }

    /// Reads node header from the given parser and returns it.
    pub fn read_from_parser<R: Read>(parser: &mut BinaryParser<R>) -> io::Result<Self> {
        let fbx_version = parser.fbx_version
            .expect("Attempt to read FBX node header but the parser doesn't know FBX version");
        let (end_offset, num_attributes, len_attributes) = if fbx_version < 7500 {
            let eo = try!(parser.source.read_u32()) as u64;
            let na = try!(parser.source.read_u32()) as u64;
            let la = try!(parser.source.read_u32()) as u64;
            (eo, na, la)
        } else {
            let eo = try!(parser.source.read_u64());
            let na = try!(parser.source.read_u64());
            let la = try!(parser.source.read_u64());
            (eo, na, la)
        };
        let len_name = try!(parser.source.read_u8());
        Ok(NodeHeader {
            end_offset: end_offset,
            num_attributes: num_attributes,
            len_attributes: len_attributes,
            len_name: len_name,
        })
    }
}
<commit_msg>Replace `super` in module paths with absolute paths<commit_after>//! Parser event.

use std::io;
use std::io::Read;

use parser::binary::BinaryParser;
use parser::binary::error::{Result, Error, Warning};

mod attribute;

/// Parser event.
#[derive(Debug)]
pub enum Event<'a, R: 'a + Read> {
    /// Start of the FBX document.
    StartFbx(FbxHeader),
    /// End of the FBX document.
    EndFbx(FbxFooter),
    /// Start of a node.
    StartNode(StartNode<'a, R>),
    /// End of a node.
    EndNode,
}

impl<'a, R: 'a + Read> From<FbxHeader> for Event<'a, R> {
    fn from(h: FbxHeader) -> Self {
        Event::StartFbx(h)
    }
}

impl<'a, R: 'a + Read> From<FbxFooter> for Event<'a, R> {
    fn from(f: FbxFooter) -> Self {
        Event::EndFbx(f)
    }
}

impl<'a, R: 'a + Read> From<StartNode<'a, R>> for Event<'a, R> {
    fn from(h: StartNode<'a, R>) -> Self {
        Event::StartNode(h)
    }
}

/// FBX header.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FbxHeader {
    /// FBX version.
    pub version: u32,
}

/// Read FBX header.
pub fn read_fbx_header<R: Read>(parser: &mut BinaryParser<R>) -> Result<FbxHeader> {
    assert!(parser.fbx_version.is_none(),
            "Parser should read FBX header only once");
    // Check magic binary.
    {
        const MAGIC_LEN: usize = 21;
        const MAGIC: &'static [u8; MAGIC_LEN] = b"Kaydara FBX Binary  \x00";
        let mut buf = [0u8; MAGIC_LEN];
        try!(parser.source.read_exact(&mut buf));
        if buf != *MAGIC {
            return Err(Error::MagicNotDetected(buf));
        }
    }
    // Read unknown 2 bytes.
    {
        const UNKNOWN_BYTES_LEN: usize = 2;
        const UNKNOWN_BYTES: &'static [u8; UNKNOWN_BYTES_LEN] = b"\x1a\x00";
        let mut buf = [0u8; UNKNOWN_BYTES_LEN];
        try!(parser.source.read_exact(&mut buf));
        if buf != *UNKNOWN_BYTES {
            parser.warn(Warning::UnexpectedBytesAfterMagic(buf));
        }
    }
    // Get FBX version.
    let fbx_version = try!(parser.source.read_u32());

    info!("FBX header is successfully read, FBX version: {}",
          fbx_version);
    Ok(FbxHeader { version: fbx_version })
}

/// FBX footer.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FbxFooter {
    /// Unknown part 1.
    pub unknown1: [u8; 16],
    /// FBX version.
    pub version: u32,
    /// Unknown part 2.
    pub unknown2: [u8; 16],
}

impl FbxFooter {
    /// Reads node header from the given parser and returns it.
    pub fn read_from_parser<R: Read>(parser: &mut BinaryParser<R>) -> Result<Self> {
        // Read unknown 16 bytes footer.
        let mut unknown1 = [0u8; 16];
        try!(parser.source.read_exact(&mut unknown1));
        // Read padding (0--15 bytes), zeroes (4 bytes), FBX version (4 bytes), zeroes (120 bytes),
        // and optionally partial unknown footer 2 (16 bytes).
        // Note that some exporters (like Blender's "FBX format" plugin version 3.2.0) creates
        // wrong FBX file without padding.
        // For such file without padding, unknown footer 2 would be partially read.
        let expected_padding_len = ((16 - (parser.source.count() & 0x0f)) & 0x0f) as usize;
        debug!("Current position = {}, Expected padding length = {}",
               parser.source.count(),
               expected_padding_len);

        const BUF_LEN: usize = 144;
        let mut buf = [0u8; BUF_LEN];
        try!(parser.source.read_exact(&mut buf));
        // If there is no padding before the footer, unknown footer 2 is partially read into the
        // buf.
        // Count length of partially read unknown footer 2.
        let partial_footer2_len = {
            let mut count = 0;
            // Unknown footer 2 doesn't contain 0x00 byte, therefore the last 0x00 should be
            // the last byte of a padding.
            while (buf[BUF_LEN - 1 - count] != 0) && count <= 16 {
                count += 1;
            }
            if count > 16 {
                error!("FBX footer should have continuous 112 bytes of zeroes, but not found");
                return Err(Error::BrokenFbxFooter);
            }
            count
        };
        let mut unknown2 = [0u8; 16];
        // Copy partially read unknown header 2.
        unknown2[0..partial_footer2_len]
            .clone_from_slice(&buf[BUF_LEN - partial_footer2_len..BUF_LEN]);
        // Read the rest of the unknown footer 2 (max 16 bytes).
        try!(parser.source.read_exact(&mut unknown2[partial_footer2_len..]));

        // Check whether padding before the footer exists.
        if 16 - partial_footer2_len == expected_padding_len {
            // Padding exists.
            // Note that its length might be 0.
            info!("Padding exists (as expected) before the footer (len={})",
                  expected_padding_len);
        } else if partial_footer2_len == 16 {
            // Padding doesn't exist while it should.
            warn!("Expected padding (len={}) but not found",
                  expected_padding_len);
        } else {
            error!("Unexpected padding length: expected={}, got={}",
                   expected_padding_len,
                   16 - partial_footer2_len);
            return Err(Error::BrokenFbxFooter);
        }

        // Check the FBX version.
        let footer_fbx_version = {
            // 20 - partial_footer2_len == BUF_LEN - partial_footer2_len - 120 - 4
            let ver_offset = 20 - partial_footer2_len;
            // FBX version is stored as `u32` in Little Endian.
            (buf[ver_offset] as u32) | (buf[ver_offset + 1] as u32) << 8 |
            (buf[ver_offset + 2] as u32) << 16 | (buf[ver_offset + 3] as u32) << 24
        };
        let header_fbx_version = parser.fbx_version
            .expect("Parser should remember FBX version in the FBX header but it doesn't");
        if header_fbx_version != footer_fbx_version {
            return Err(Error::HeaderFooterVersionMismatch {
                header: header_fbx_version,
                footer: footer_fbx_version,
            });
        }

        Ok(FbxFooter {
            unknown1: unknown1,
            version: footer_fbx_version,
            unknown2: unknown2,
        })
    }
}

/// FBX node info.
#[derive(Debug)]
pub struct StartNode<'a, R: 'a + Read> {
    /// Node name.
    pub name: String,
    /// Parser.
    _parser: &'a mut BinaryParser<R>,
}

/// Parser event without reference to a parser.
#[derive(Debug, Clone)]
pub enum EventBuilder {
    /// Start of the FBX document.
    StartFbx(FbxHeader),
    /// End of the FBX document.
    EndFbx(FbxFooter),
    /// Start of a node.
    StartNode(StartNodeBuilder),
    /// End of a node.
    EndNode,
}

impl EventBuilder {
    /// Creates `Event` from the `EventBuilder` and the given parser.
    pub fn build<R: Read>(self, parser: &mut BinaryParser<R>) -> Event<R> {
        match self {
            EventBuilder::StartFbx(header) => header.into(),
            EventBuilder::EndFbx(footer) => footer.into(),
            EventBuilder::StartNode(builder) => builder.build(parser).into(),
            EventBuilder::EndNode => Event::EndNode,
        }
    }
}

impl From<FbxHeader> for EventBuilder {
    fn from(h: FbxHeader) -> Self {
        EventBuilder::StartFbx(h)
    }
}

impl From<FbxFooter> for EventBuilder {
    fn from(f: FbxFooter) -> Self {
        EventBuilder::EndFbx(f)
    }
}

impl From<StartNodeBuilder> for EventBuilder {
    fn from(h: StartNodeBuilder) -> Self {
        EventBuilder::StartNode(h)
    }
}

/// `StartNode` without reference to a parser.
#[derive(Debug, Clone)]
pub struct StartNodeBuilder {
    /// Node name.
    pub name: String,
}

impl StartNodeBuilder {
    /// Creates `StartNode` from the `StartNodeBuilder` and the given parser.
    pub fn build<R: Read>(self, parser: &mut BinaryParser<R>) -> StartNode<R> {
        StartNode {
            name: self.name,
            _parser: parser,
        }
    }
}

/// Fixed size node header (without node name field).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NodeHeader {
    /// End offset of the node.
    pub end_offset: u64,
    /// Number of the node attributes.
    pub num_attributes: u64,
    /// Byte length of the node attributes.
    pub len_attributes: u64,
    /// Length of the node name.
    pub len_name: u8,
}

impl NodeHeader {
    /// Returns true if all fields of the node header is `0`.
    pub fn is_node_end(&self) -> bool {
        self.end_offset == 0 && self.num_attributes == 0 && self.len_attributes == 0 &&
        self.len_name == 0
    }

    /// Reads node header from the given parser and returns it.
    pub fn read_from_parser<R: Read>(parser: &mut BinaryParser<R>) -> io::Result<Self> {
        let fbx_version = parser.fbx_version
            .expect("Attempt to read FBX node header but the parser doesn't know FBX version");
        let (end_offset, num_attributes, len_attributes) = if fbx_version < 7500 {
            let eo = try!(parser.source.read_u32()) as u64;
            let na = try!(parser.source.read_u32()) as u64;
            let la = try!(parser.source.read_u32()) as u64;
            (eo, na, la)
        } else {
            let eo = try!(parser.source.read_u64());
            let na = try!(parser.source.read_u64());
            let la = try!(parser.source.read_u64());
            (eo, na, la)
        };
        let len_name = try!(parser.source.read_u8());
        Ok(NodeHeader {
            end_offset: end_offset,
            num_attributes: num_attributes,
            len_attributes: len_attributes,
            len_name: len_name,
        })
    }
}
<|endoftext|>


<commit_before><commit_msg>Drop rows after clearing lines by the number of clears made<commit_after><|endoftext|>


<commit_before><commit_msg>Fix redo typo in docs<commit_after><|endoftext|>


<commit_before><commit_msg>Fix break condition in read_c_to_string<commit_after><|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::default::Default;

use progress::{Timestamp, PathSummary};
use progress::nested::product::Product;

use progress::nested::summary::Summary::{Local, Outer};

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Summary<S, T> {
    Local(T),    // reachable within inner scope.
    Outer(S, T), // unreachable within scope, reachable through outer scope and then inner.
}

impl<S, T: Default> Default for Summary<S, T> {
    fn default() -> Summary<S, T> { Local(Default::default()) }
}

impl<S:PartialOrd+Copy, T:PartialOrd+Copy> PartialOrd for Summary<S, T> {
    fn partial_cmp(&self, other: &Summary<S, T>) -> Option<Ordering> {
        match (*self, *other) {
            (Local(t1), Local(t2))       => t1.partial_cmp(&t2),
            (Local(_), Outer(_,_))       => Some(Ordering::Less),
            (Outer(s1,t1), Outer(s2,t2)) => (s1,t1).partial_cmp(&(s2,t2)),
            (Outer(_,_), Local(_))       => Some(Ordering::Greater),
        }
    }
}

impl<TOuter, SOuter, TInner, SInner>
PathSummary<Product<TOuter, TInner>>
for Summary<SOuter, SInner>
where TOuter: Timestamp,
      TInner: Timestamp,
      SOuter: PathSummary<TOuter>,
      SInner: PathSummary<TInner>,
{
    // this makes sense for a total order, but less clear for a partial order.
    fn results_in(&self, product: &Product<TOuter, TInner>) -> Product<TOuter, TInner> {
        match *self {
            Local(ref iters)              => Product::new(product.outer.clone(), iters.results_in(&product.inner)),
            Outer(ref summary, ref iters) => Product::new(summary.results_in(&product.outer), iters.results_in(&Default::default())),
        }
    }
    fn followed_by(&self, other: &Summary<SOuter, SInner>) -> Summary<SOuter, SInner> {
        match (*self, *other) {
            (Local(inner1), Local(inner2))             => Local(inner1.followed_by(&inner2)),
            (Local(_), Outer(_, _))                    => *other,
            (Outer(outer1, inner1), Local(inner2))     => Outer(outer1, inner1.followed_by(&inner2)),
            (Outer(outer1, _), Outer(outer2, inner2))  => Outer(outer1.followed_by(&outer2), inner2),
        }
    }
}

// TODO : Would prefer this version, but something breaks down wrt type inference ...
// impl<TOuter: Timestamp, TInner: Timestamp> PathSummary<(TOuter, TInner)> for Summary<TOuter::Summary, TInner::Summary> {
//     // this makes sense for a total order, but less clear for a partial order.
//     fn results_in(&self, &(ref outer, ref inner): &(TOuter, TInner)) -> (TOuter, TInner) {
//         match *self {
//             Local(ref iters)              => (outer.clone(), iters.results_in(inner)),
//             Outer(ref summary, ref iters) => (summary.results_in(outer), iters.results_in(&Default::default())),
//         }
//     }
//     fn followed_by(&self, other: &Summary<TOuter::Summary, TInner::Summary>) -> Summary<TOuter::Summary, TInner::Summary>
//     {
//         match (*self, *other) {
//             (Local(inner1), Local(inner2))             => Local(inner1.followed_by(&inner2)),
//             (Local(_), Outer(_, _))                    => *other,
//             (Outer(outer1, inner1), Local(inner2))     => Outer(outer1, inner1.followed_by(&inner2)),
//             (Outer(outer1, _), Outer(outer2, inner2))  => Outer(outer1.followed_by(&outer2), inner2),
//         }
//     }
// }
<commit_msg>logic upgrade (more correct); not done<commit_after>use std::cmp::Ordering;
use std::default::Default;

use progress::{Timestamp, PathSummary};
use progress::nested::product::Product;
use progress::nested::summary::Summary::{Local, Outer};

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Summary<S, T> {
    Local(T),    // reachable within inner scope.
    Outer(S, T), // unreachable within scope, reachable through outer scope and then inner.
}

impl<S, T: Default> Default for Summary<S, T> {
    fn default() -> Summary<S, T> { Local(Default::default()) }
}

impl<S:PartialOrd+Copy, T:PartialOrd+Copy> PartialOrd for Summary<S, T> {
    fn partial_cmp(&self, other: &Summary<S, T>) -> Option<Ordering> {
        match (*self, *other) {
            (Local(t1),    Local(t2))    => t1.partial_cmp(&t2),
            (Local(t1),    Outer(_,t2))  => match t1.partial_cmp(&t2) {
                Some(Ordering::Less)    => Some(Ordering::Less),
                Some(Ordering::Equal)   => Some(Ordering::Less), // might not be strict if s2~=0, but lets break ties
                Some(Ordering::Greater) => None,                 // if s2 = 0 we could be leaving something else out
                None                    => None,
            },
            (Outer(s1,t1), Outer(s2,t2)) => (s1,t1).partial_cmp(&(s2,t2)),
            (Outer(_,t1),   Local(t2))   => match t1.partial_cmp(&t2) {
                Some(Ordering::Less)    => None,
                Some(Ordering::Equal)   => Some(Ordering::Greater), // might not be strict if s2~=0, but lets break ties
                Some(Ordering::Greater) => Some(Ordering::Greater), // if s2 = 0 we could be leaving something else out
                None                    => None,
            },
        }
    }
}

impl<TOuter, SOuter, TInner, SInner> PathSummary<Product<TOuter, TInner>> for Summary<SOuter, SInner>
where TOuter: Timestamp,
      TInner: Timestamp,
      SOuter: PathSummary<TOuter>,
      SInner: PathSummary<TInner>,
{
    // this makes sense for a total order, but less clear for a partial order.
    fn results_in(&self, product: &Product<TOuter, TInner>) -> Product<TOuter, TInner> {
        match *self {
            Local(ref iters)              => Product::new(product.outer.clone(), iters.results_in(&product.inner)),
            Outer(ref summary, ref iters) => Product::new(summary.results_in(&product.outer), iters.results_in(&Default::default())),
        }
    }
    fn followed_by(&self, other: &Summary<SOuter, SInner>) -> Summary<SOuter, SInner> {
        match (*self, *other) {
            (Local(inner1), Local(inner2))             => Local(inner1.followed_by(&inner2)),
            (Local(_), Outer(_, _))                    => *other,
            (Outer(outer1, inner1), Local(inner2))     => Outer(outer1, inner1.followed_by(&inner2)),
            (Outer(outer1, _), Outer(outer2, inner2))  => Outer(outer1.followed_by(&outer2), inner2),
        }
    }
}
<|endoftext|>


<commit_before>use crate::context::{BlockParams, Context};
use crate::error::RenderError;
use crate::helpers::{HelperDef, HelperResult};
use crate::json::value::JsonTruthy;
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{Helper, RenderContext, Renderable};

#[derive(Clone, Copy)]
pub struct WithHelper;

impl HelperDef for WithHelper {
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg>,
        out: &mut dyn Output,
    ) -> HelperResult {
        let param = h
            .param(0)
            .ok_or_else(|| RenderError::new("Param not found for helper \"with\""))?;

        let saved_base_path = rc.get_path().to_vec();
        rc.promote_local_vars();

        let not_empty = param.value().is_truthy(false);
        let template = if not_empty { h.template() } else { h.inverse() };

        let local_path_root = param.path_root();
        if let Some(path_root) = local_path_root {
            rc.push_local_path_root(path_root.to_vec());
        }

        if not_empty {
            let new_path = param.context_path();
            if let Some(new_path) = new_path {
                rc.set_path(new_path.clone());
            }

            if let Some(block_param) = h.block_param() {
                let mut params = BlockParams::new();
                if new_path.is_some() {
                    params.add_path(block_param, rc.get_path().clone())?;
                } else {
                    params.add_value(block_param, param.value().clone())?;
                }

                rc.push_block_context(params)?;
            }
        }

        let result = match template {
            Some(t) => t.render(r, ctx, rc, out),
            None => Ok(()),
        };

        if h.has_block_param() {
            rc.pop_block_context();
        }

        if local_path_root.is_some() {
            rc.pop_local_path_root();
        }

        rc.demote_local_vars();
        rc.set_path(saved_base_path);
        result
    }
}

pub static WITH_HELPER: WithHelper = WithHelper;

#[cfg(test)]
mod test {
    use crate::json::value::to_json;
    use crate::registry::Registry;

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_with() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#with addr}}{{city}}{{/with}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#with notfound}}hello{{else}}world{{/with}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t2", "{{#with addr/country}}{{this}}{{/with}}")
            .is_ok());

        let r0 = handlebars.render("t0", &person);
        assert_eq!(r0.ok().unwrap(), "Beijing".to_string());

        let r1 = handlebars.render("t1", &person);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t2", &person);
        assert_eq!(r2.ok().unwrap(), "China".to_string());
    }

    #[test]
    fn test_with_block_param() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#with addr as |a|}}{{a.city}}{{/with}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#with notfound as |c|}}hello{{else}}world{{/with}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t2", "{{#with addr/country as |t|}}{{t}}{{/with}}")
            .is_ok());

        let r0 = handlebars.render("t0", &person);
        assert_eq!(r0.ok().unwrap(), "Beijing".to_string());

        let r1 = handlebars.render("t1", &person);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t2", &person);
        assert_eq!(r2.ok().unwrap(), "China".to_string());
    }

    #[test]
    fn test_with_in_each() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let addr2 = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person2 = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr2,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let people = vec![person, person2];

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each this}}{{#with addr}}{{city}}{{/with}}{{/each}}"
            )
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t1",
                "{{#each this}}{{#with addr}}{{../age}}{{/with}}{{/each}}"
            )
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t2",
                "{{#each this}}{{#with addr}}{{@../index}}{{/with}}{{/each}}"
            )
            .is_ok());

        let r0 = handlebars.render("t0", &people);
        assert_eq!(r0.ok().unwrap(), "BeijingBeijing".to_string());

        let r1 = handlebars.render("t1", &people);
        assert_eq!(r1.ok().unwrap(), "2727".to_string());

        let r2 = handlebars.render("t2", &people);
        dbg!(&r2);
        assert_eq!(r2.ok().unwrap(), "01".to_string());
    }

    #[test]
    fn test_path_up() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#with a}}{{#with b}}{{../../d}}{{/with}}{{/with}}")
            .is_ok());
        let data = btreemap! {
            "a".to_string() => to_json(&btreemap! {
                "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}]
            }),
            "d".to_string() => to_json(1)
        };

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "1".to_string());
    }
}
<commit_msg>(fix) remove dbg print<commit_after>use crate::context::{BlockParams, Context};
use crate::error::RenderError;
use crate::helpers::{HelperDef, HelperResult};
use crate::json::value::JsonTruthy;
use crate::output::Output;
use crate::registry::Registry;
use crate::render::{Helper, RenderContext, Renderable};

#[derive(Clone, Copy)]
pub struct WithHelper;

impl HelperDef for WithHelper {
    fn call<'reg: 'rc, 'rc>(
        &self,
        h: &Helper<'reg, 'rc>,
        r: &'reg Registry,
        ctx: &'rc Context,
        rc: &mut RenderContext<'reg>,
        out: &mut dyn Output,
    ) -> HelperResult {
        let param = h
            .param(0)
            .ok_or_else(|| RenderError::new("Param not found for helper \"with\""))?;

        let saved_base_path = rc.get_path().to_vec();
        rc.promote_local_vars();

        let not_empty = param.value().is_truthy(false);
        let template = if not_empty { h.template() } else { h.inverse() };

        let local_path_root = param.path_root();
        if let Some(path_root) = local_path_root {
            rc.push_local_path_root(path_root.to_vec());
        }

        if not_empty {
            let new_path = param.context_path();
            if let Some(new_path) = new_path {
                rc.set_path(new_path.clone());
            }

            if let Some(block_param) = h.block_param() {
                let mut params = BlockParams::new();
                if new_path.is_some() {
                    params.add_path(block_param, rc.get_path().clone())?;
                } else {
                    params.add_value(block_param, param.value().clone())?;
                }

                rc.push_block_context(params)?;
            }
        }

        let result = match template {
            Some(t) => t.render(r, ctx, rc, out),
            None => Ok(()),
        };

        if h.has_block_param() {
            rc.pop_block_context();
        }

        if local_path_root.is_some() {
            rc.pop_local_path_root();
        }

        rc.demote_local_vars();
        rc.set_path(saved_base_path);
        result
    }
}

pub static WITH_HELPER: WithHelper = WithHelper;

#[cfg(test)]
mod test {
    use crate::json::value::to_json;
    use crate::registry::Registry;

    #[derive(Serialize)]
    struct Address {
        city: String,
        country: String,
    }

    #[derive(Serialize)]
    struct Person {
        name: String,
        age: i16,
        addr: Address,
        titles: Vec<String>,
    }

    #[test]
    fn test_with() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#with addr}}{{city}}{{/with}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#with notfound}}hello{{else}}world{{/with}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t2", "{{#with addr/country}}{{this}}{{/with}}")
            .is_ok());

        let r0 = handlebars.render("t0", &person);
        assert_eq!(r0.ok().unwrap(), "Beijing".to_string());

        let r1 = handlebars.render("t1", &person);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t2", &person);
        assert_eq!(r2.ok().unwrap(), "China".to_string());
    }

    #[test]
    fn test_with_block_param() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#with addr as |a|}}{{a.city}}{{/with}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t1", "{{#with notfound as |c|}}hello{{else}}world{{/with}}")
            .is_ok());
        assert!(handlebars
            .register_template_string("t2", "{{#with addr/country as |t|}}{{t}}{{/with}}")
            .is_ok());

        let r0 = handlebars.render("t0", &person);
        assert_eq!(r0.ok().unwrap(), "Beijing".to_string());

        let r1 = handlebars.render("t1", &person);
        assert_eq!(r1.ok().unwrap(), "world".to_string());

        let r2 = handlebars.render("t2", &person);
        assert_eq!(r2.ok().unwrap(), "China".to_string());
    }

    #[test]
    fn test_with_in_each() {
        let addr = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let addr2 = Address {
            city: "Beijing".to_string(),
            country: "China".to_string(),
        };

        let person2 = Person {
            name: "Ning Sun".to_string(),
            age: 27,
            addr: addr2,
            titles: vec!["programmer".to_string(), "cartographier".to_string()],
        };

        let people = vec![person, person2];

        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string(
                "t0",
                "{{#each this}}{{#with addr}}{{city}}{{/with}}{{/each}}"
            )
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t1",
                "{{#each this}}{{#with addr}}{{../age}}{{/with}}{{/each}}"
            )
            .is_ok());
        assert!(handlebars
            .register_template_string(
                "t2",
                "{{#each this}}{{#with addr}}{{@../index}}{{/with}}{{/each}}"
            )
            .is_ok());

        let r0 = handlebars.render("t0", &people);
        assert_eq!(r0.ok().unwrap(), "BeijingBeijing".to_string());

        let r1 = handlebars.render("t1", &people);
        assert_eq!(r1.ok().unwrap(), "2727".to_string());

        let r2 = handlebars.render("t2", &people);
        assert_eq!(r2.ok().unwrap(), "01".to_string());
    }

    #[test]
    fn test_path_up() {
        let mut handlebars = Registry::new();
        assert!(handlebars
            .register_template_string("t0", "{{#with a}}{{#with b}}{{../../d}}{{/with}}{{/with}}")
            .is_ok());
        let data = btreemap! {
            "a".to_string() => to_json(&btreemap! {
                "b".to_string() => vec![btreemap!{"c".to_string() => vec![1]}]
            }),
            "d".to_string() => to_json(1)
        };

        let r0 = handlebars.render("t0", &data);
        assert_eq!(r0.ok().unwrap(), "1".to_string());
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
// Copyright 2013 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The dirichlet distribution.

use rand::Rng;
use crate::{Distribution, Gamma, StandardNormal, Exp1, Open01};
use crate::utils::Float;

/// The dirichelet distribution `Dirichlet(alpha)`.
///
/// The Dirichlet distribution is a family of continuous multivariate
/// probability distributions parameterized by a vector alpha of positive reals.
/// It is a multivariate generalization of the beta distribution.
///
/// # Example
///
/// ```
/// use rand::prelude::*;
/// use rand_distr::Dirichlet;
///
/// let dirichlet = Dirichlet::new(vec![1.0, 2.0, 3.0]).unwrap();
/// let samples = dirichlet.sample(&mut rand::thread_rng());
/// println!("{:?} is from a Dirichlet([1.0, 2.0, 3.0]) distribution", samples);
/// ```
#[derive(Clone, Debug)]
pub struct Dirichlet<N> {
    /// Concentration parameters (alpha)
    alpha: Vec<N>,
}

/// Error type returned from `Dirchlet::new`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
    /// `alpha.len() < 2`.
    AlphaTooShort,
    /// `alpha <= 0.0` or `nan`.
    AlphaTooSmall,
    /// `size < 2`.
    SizeTooSmall,
}

impl<N: Float> Dirichlet<N>
where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N>
{
    /// Construct a new `Dirichlet` with the given alpha parameter `alpha`.
    ///
    /// Requires `alpha.len() >= 2`.
    #[inline]
    pub fn new<V: Into<Vec<N>>>(alpha: V) -> Result<Dirichlet<N>, Error> {
        let a = alpha.into();
        if a.len() < 2 {
            return Err(Error::AlphaTooShort);
        }
        for i in 0..a.len() {
            if !(a[i] > N::from(0.0)) {
                return Err(Error::AlphaTooSmall);
            }
        }

        Ok(Dirichlet { alpha: a })
    }

    /// Construct a new `Dirichlet` with the given shape parameter `alpha` and `size`.
    ///
    /// Requires `size >= 2`.
    #[inline]
    pub fn new_with_size(alpha: N, size: usize) -> Result<Dirichlet<N>, Error> {
        if !(alpha > N::from(0.0)) {
            return Err(Error::AlphaTooSmall);
        }
        if size < 2 {
            return Err(Error::SizeTooSmall);
        }
        Ok(Dirichlet {
            alpha: vec![alpha; size],
        })
    }
}

impl<N: Float> Distribution<Vec<N>> for Dirichlet<N>
where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N>
{
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<N> {
        let n = self.alpha.len();
        let mut samples = vec![N::from(0.0); n];
        let mut sum = N::from(0.0);

        for i in 0..n {
            let g = Gamma::new(self.alpha[i], N::from(1.0)).unwrap();
            samples[i] = g.sample(rng);
            sum += samples[i];
        }
        let invacc = N::from(1.0) / sum;
        for i in 0..n {
            samples[i] *= invacc;
        }
        samples
    }
}

#[cfg(test)]
mod test {
    use super::Dirichlet;
    use crate::Distribution;

    #[test]
    fn test_dirichlet() {
        let d = Dirichlet::new(vec![1.0, 2.0, 3.0]).unwrap();
        let mut rng = crate::test::rng(221);
        let samples = d.sample(&mut rng);
        let _: Vec<f64> = samples
            .into_iter()
            .map(|x| {
                assert!(x > 0.0);
                x
            })
            .collect();
    }

    #[test]
    fn test_dirichlet_with_param() {
        let alpha = 0.5f64;
        let size = 2;
        let d = Dirichlet::new_with_size(alpha, size).unwrap();
        let mut rng = crate::test::rng(221);
        let samples = d.sample(&mut rng);
        let _: Vec<f64> = samples
            .into_iter()
            .map(|x| {
                assert!(x > 0.0);
                x
            })
            .collect();
    }

    #[test]
    #[should_panic]
    fn test_dirichlet_invalid_length() {
        Dirichlet::new_with_size(0.5f64, 1).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_dirichlet_invalid_alpha() {
        Dirichlet::new_with_size(0.0f64, 2).unwrap();
    }
}
<commit_msg>Dirichlet: Prefer iterators over index variables<commit_after>// Copyright 2018 Developers of the Rand project.
// Copyright 2013 The Rust Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The dirichlet distribution.

use rand::Rng;
use crate::{Distribution, Gamma, StandardNormal, Exp1, Open01};
use crate::utils::Float;

/// The dirichelet distribution `Dirichlet(alpha)`.
///
/// The Dirichlet distribution is a family of continuous multivariate
/// probability distributions parameterized by a vector alpha of positive reals.
/// It is a multivariate generalization of the beta distribution.
///
/// # Example
///
/// ```
/// use rand::prelude::*;
/// use rand_distr::Dirichlet;
///
/// let dirichlet = Dirichlet::new(vec![1.0, 2.0, 3.0]).unwrap();
/// let samples = dirichlet.sample(&mut rand::thread_rng());
/// println!("{:?} is from a Dirichlet([1.0, 2.0, 3.0]) distribution", samples);
/// ```
#[derive(Clone, Debug)]
pub struct Dirichlet<N> {
    /// Concentration parameters (alpha)
    alpha: Vec<N>,
}

/// Error type returned from `Dirchlet::new`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
    /// `alpha.len() < 2`.
    AlphaTooShort,
    /// `alpha <= 0.0` or `nan`.
    AlphaTooSmall,
    /// `size < 2`.
    SizeTooSmall,
}

impl<N: Float> Dirichlet<N>
where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N>
{
    /// Construct a new `Dirichlet` with the given alpha parameter `alpha`.
    ///
    /// Requires `alpha.len() >= 2`.
    #[inline]
    pub fn new<V: Into<Vec<N>>>(alpha: V) -> Result<Dirichlet<N>, Error> {
        let a = alpha.into();
        if a.len() < 2 {
            return Err(Error::AlphaTooShort);
        }
        for &ai in &a {
            if !(ai > N::from(0.0)) {
                return Err(Error::AlphaTooSmall);
            }
        }

        Ok(Dirichlet { alpha: a })
    }

    /// Construct a new `Dirichlet` with the given shape parameter `alpha` and `size`.
    ///
    /// Requires `size >= 2`.
    #[inline]
    pub fn new_with_size(alpha: N, size: usize) -> Result<Dirichlet<N>, Error> {
        if !(alpha > N::from(0.0)) {
            return Err(Error::AlphaTooSmall);
        }
        if size < 2 {
            return Err(Error::SizeTooSmall);
        }
        Ok(Dirichlet {
            alpha: vec![alpha; size],
        })
    }
}

impl<N: Float> Distribution<Vec<N>> for Dirichlet<N>
where StandardNormal: Distribution<N>, Exp1: Distribution<N>, Open01: Distribution<N>
{
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<N> {
        let n = self.alpha.len();
        let mut samples = vec![N::from(0.0); n];
        let mut sum = N::from(0.0);

        for (s, &a) in samples.iter_mut().zip(self.alpha.iter()) {
            let g = Gamma::new(a, N::from(1.0)).unwrap();
            *s = g.sample(rng);
            sum += *s;
        }
        let invacc = N::from(1.0) / sum;
        for s in samples.iter_mut() {
            *s *= invacc;
        }
        samples
    }
}

#[cfg(test)]
mod test {
    use super::Dirichlet;
    use crate::Distribution;

    #[test]
    fn test_dirichlet() {
        let d = Dirichlet::new(vec![1.0, 2.0, 3.0]).unwrap();
        let mut rng = crate::test::rng(221);
        let samples = d.sample(&mut rng);
        let _: Vec<f64> = samples
            .into_iter()
            .map(|x| {
                assert!(x > 0.0);
                x
            })
            .collect();
    }

    #[test]
    fn test_dirichlet_with_param() {
        let alpha = 0.5f64;
        let size = 2;
        let d = Dirichlet::new_with_size(alpha, size).unwrap();
        let mut rng = crate::test::rng(221);
        let samples = d.sample(&mut rng);
        let _: Vec<f64> = samples
            .into_iter()
            .map(|x| {
                assert!(x > 0.0);
                x
            })
            .collect();
    }

    #[test]
    #[should_panic]
    fn test_dirichlet_invalid_length() {
        Dirichlet::new_with_size(0.5f64, 1).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_dirichlet_invalid_alpha() {
        Dirichlet::new_with_size(0.0f64, 2).unwrap();
    }
}
<|endoftext|>


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

/*!
 * Name resolution for lifetimes.
 *
 * Name resolution for lifetimes follows MUCH simpler rules than the
 * full resolve. For example, lifetime names are never exported or
 * used between functions, and they operate in a purely top-down
 * way. Therefore we break lifetime name resolution into a separate pass.
 */

use driver::session;
use std::cell::RefCell;
use util::nodemap::NodeMap;
use syntax::ast;
use syntax::codemap::Span;
use syntax::opt_vec::OptVec;
use syntax::parse::token::special_idents;
use syntax::parse::token;
use syntax::print::pprust::{lifetime_to_str};
use syntax::visit;
use syntax::visit::Visitor;

// maps the id of each lifetime reference to the lifetime decl
// that it corresponds to
pub type NamedRegionMap = NodeMap<ast::DefRegion>;

struct LifetimeContext {
    sess: session::Session,
    named_region_map: @RefCell<NamedRegionMap>,
}

enum ScopeChain<'a> {
    ItemScope(&'a OptVec<ast::Lifetime>),
    FnScope(ast::NodeId, &'a OptVec<ast::Lifetime>, &'a ScopeChain<'a>),
    BlockScope(ast::NodeId, &'a ScopeChain<'a>),
    RootScope
}

pub fn krate(sess: session::Session, krate: &ast::Crate)
             -> @RefCell<NamedRegionMap> {
    let mut ctxt = LifetimeContext {
        sess: sess,
        named_region_map: @RefCell::new(NodeMap::new())
    };
    visit::walk_crate(&mut ctxt, krate, &RootScope);
    sess.abort_if_errors();
    ctxt.named_region_map
}

impl<'a> Visitor<&'a ScopeChain<'a>> for LifetimeContext {
    fn visit_item(&mut self,
                  item: &ast::Item,
                  _: &'a ScopeChain<'a>) {
        let scope = match item.node {
            ast::ItemFn(..) | // fn lifetimes get added in visit_fn below
            ast::ItemMod(..) |
            ast::ItemMac(..) |
            ast::ItemForeignMod(..) |
            ast::ItemStatic(..) => {
                RootScope
            }
            ast::ItemTy(_, ref generics) |
            ast::ItemEnum(_, ref generics) |
            ast::ItemStruct(_, ref generics) |
            ast::ItemImpl(ref generics, _, _, _) |
            ast::ItemTrait(ref generics, _, _) => {
                self.check_lifetime_names(&generics.lifetimes);
                ItemScope(&generics.lifetimes)
            }
        };
        debug!("entering scope {:?}", scope);
        visit::walk_item(self, item, &scope);
        debug!("exiting scope {:?}", scope);
    }

    fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
                b: &ast::Block, s: Span, n: ast::NodeId,
                scope: &'a ScopeChain<'a>) {
        match *fk {
            visit::FkItemFn(_, generics, _, _) |
            visit::FkMethod(_, generics, _) => {
                let scope1 = FnScope(n, &generics.lifetimes, scope);
                self.check_lifetime_names(&generics.lifetimes);
                debug!("pushing fn scope id={} due to item/method", n);
                visit::walk_fn(self, fk, fd, b, s, n, &scope1);
                debug!("popping fn scope id={} due to item/method", n);
            }
            visit::FkFnBlock(..) => {
                visit::walk_fn(self, fk, fd, b, s, n, scope);
            }
        }
    }

    fn visit_ty(&mut self, ty: &ast::Ty,
                scope: &'a ScopeChain<'a>) {
        match ty.node {
            ast::TyClosure(closure) => {
                let scope1 = FnScope(ty.id, &closure.lifetimes, scope);
                self.check_lifetime_names(&closure.lifetimes);
                debug!("pushing fn scope id={} due to type", ty.id);
                visit::walk_ty(self, ty, &scope1);
                debug!("popping fn scope id={} due to type", ty.id);
            }
            ast::TyBareFn(bare_fn) => {
                let scope1 = FnScope(ty.id, &bare_fn.lifetimes, scope);
                self.check_lifetime_names(&bare_fn.lifetimes);
                debug!("pushing fn scope id={} due to type", ty.id);
                visit::walk_ty(self, ty, &scope1);
                debug!("popping fn scope id={} due to type", ty.id);
            }
            _ => {
                visit::walk_ty(self, ty, scope);
            }
        }
    }

    fn visit_ty_method(&mut self,
                       m: &ast::TypeMethod,
                       scope: &'a ScopeChain<'a>) {
        let scope1 = FnScope(m.id, &m.generics.lifetimes, scope);
        self.check_lifetime_names(&m.generics.lifetimes);
        debug!("pushing fn scope id={} due to ty_method", m.id);
        visit::walk_ty_method(self, m, &scope1);
        debug!("popping fn scope id={} due to ty_method", m.id);
    }

    fn visit_block(&mut self,
                   b: &ast::Block,
                   scope: &'a ScopeChain<'a>) {
        let scope1 = BlockScope(b.id, scope);
        debug!("pushing block scope {}", b.id);
        visit::walk_block(self, b, &scope1);
        debug!("popping block scope {}", b.id);
    }

    fn visit_lifetime_ref(&mut self,
                          lifetime_ref: &ast::Lifetime,
                          scope: &'a ScopeChain<'a>) {
        if lifetime_ref.name == special_idents::statik.name {
            self.insert_lifetime(lifetime_ref, ast::DefStaticRegion);
            return;
        }
        self.resolve_lifetime_ref(lifetime_ref, scope);
    }
}

impl LifetimeContext {
    fn resolve_lifetime_ref(&self,
                            lifetime_ref: &ast::Lifetime,
                            scope: &ScopeChain) {
        // Walk up the scope chain, tracking the number of fn scopes
        // that we pass through, until we find a lifetime with the
        // given name or we run out of scopes. If we encounter a code
        // block, then the lifetime is not bound but free, so switch
        // over to `resolve_free_lifetime_ref()` to complete the
        // search.
        let mut depth = 0;
        let mut scope = scope;
        loop {
            match *scope {
                BlockScope(id, s) => {
                    return self.resolve_free_lifetime_ref(id, lifetime_ref, s);
                }

                RootScope => {
                    break;
                }

                ItemScope(lifetimes) => {
                    match search_lifetimes(lifetimes, lifetime_ref) {
                        Some((index, decl_id)) => {
                            let def = ast::DefEarlyBoundRegion(index, decl_id);
                            self.insert_lifetime(lifetime_ref, def);
                            return;
                        }
                        None => {
                            break;
                        }
                    }
                }

                FnScope(id, lifetimes, s) => {
                    match search_lifetimes(lifetimes, lifetime_ref) {
                        Some((_index, decl_id)) => {
                            let def = ast::DefLateBoundRegion(id, depth, decl_id);
                            self.insert_lifetime(lifetime_ref, def);
                            return;
                        }

                        None => {
                            depth += 1;
                            scope = s;
                        }
                    }
                }
            }
        }

        self.unresolved_lifetime_ref(lifetime_ref);
    }

    fn resolve_free_lifetime_ref(&self,
                                 scope_id: ast::NodeId,
                                 lifetime_ref: &ast::Lifetime,
                                 scope: &ScopeChain) {
        // Walk up the scope chain, tracking the outermost free scope,
        // until we encounter a scope that contains the named lifetime
        // or we run out of scopes.
        let mut scope_id = scope_id;
        let mut scope = scope;
        let mut search_result = None;
        loop {
            match *scope {
                BlockScope(id, s) => {
                    scope_id = id;
                    scope = s;
                }

                RootScope => {
                    break;
                }

                ItemScope(lifetimes) => {
                    search_result = search_lifetimes(lifetimes, lifetime_ref);
                    break;
                }

                FnScope(_, lifetimes, s) => {
                    search_result = search_lifetimes(lifetimes, lifetime_ref);
                    if search_result.is_some() {
                        break;
                    }
                    scope = s;
                }
            }
        }

        match search_result {
            Some((_depth, decl_id)) => {
                let def = ast::DefFreeRegion(scope_id, decl_id);
                self.insert_lifetime(lifetime_ref, def);
            }

            None => {
                self.unresolved_lifetime_ref(lifetime_ref);
            }
        }

    }

    fn unresolved_lifetime_ref(&self,
                               lifetime_ref: &ast::Lifetime) {
        self.sess.span_err(
            lifetime_ref.span,
            format!("use of undeclared lifetime name `'{}`",
                    token::get_name(lifetime_ref.name)));
    }

    fn check_lifetime_names(&self, lifetimes: &OptVec<ast::Lifetime>) {
        for i in range(0, lifetimes.len()) {
            let lifetime_i = lifetimes.get(i);

            let special_idents = [special_idents::statik];
            for lifetime in lifetimes.iter() {
                if special_idents.iter().any(|&i| i.name == lifetime.name) {
                    self.sess.span_err(
                        lifetime.span,
                        format!("illegal lifetime parameter name: `{}`",
                                token::get_name(lifetime.name)));
                }
            }

            for j in range(i + 1, lifetimes.len()) {
                let lifetime_j = lifetimes.get(j);

                if lifetime_i.name == lifetime_j.name {
                    self.sess.span_err(
                        lifetime_j.span,
                        format!("lifetime name `'{}` declared twice in \
                                the same scope",
                                token::get_name(lifetime_j.name)));
                }
            }
        }
    }

    fn insert_lifetime(&self,
                       lifetime_ref: &ast::Lifetime,
                       def: ast::DefRegion) {
        if lifetime_ref.id == ast::DUMMY_NODE_ID {
            self.sess.span_bug(lifetime_ref.span,
                               "lifetime reference not renumbered, \
                               probably a bug in syntax::fold");
        }

        debug!("lifetime_ref={} id={} resolved to {:?}",
                lifetime_to_str(lifetime_ref),
                lifetime_ref.id,
                def);
        let mut named_region_map = self.named_region_map.borrow_mut();
        named_region_map.get().insert(lifetime_ref.id, def);
    }
}

fn search_lifetimes(lifetimes: &OptVec<ast::Lifetime>,
                    lifetime_ref: &ast::Lifetime)
                    -> Option<(uint, ast::NodeId)> {
    for (i, lifetime_decl) in lifetimes.iter().enumerate() {
        if lifetime_decl.name == lifetime_ref.name {
            return Some((i, lifetime_decl.id));
        }
    }
    return None;
}
<commit_msg>Introduce Scope<'a> shorthand for &'a ScopeChain<'a>.<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
 * Name resolution for lifetimes.
 *
 * Name resolution for lifetimes follows MUCH simpler rules than the
 * full resolve. For example, lifetime names are never exported or
 * used between functions, and they operate in a purely top-down
 * way. Therefore we break lifetime name resolution into a separate pass.
 */

use driver::session;
use std::cell::RefCell;
use util::nodemap::NodeMap;
use syntax::ast;
use syntax::codemap::Span;
use syntax::opt_vec::OptVec;
use syntax::parse::token::special_idents;
use syntax::parse::token;
use syntax::print::pprust::{lifetime_to_str};
use syntax::visit;
use syntax::visit::Visitor;

// maps the id of each lifetime reference to the lifetime decl
// that it corresponds to
pub type NamedRegionMap = NodeMap<ast::DefRegion>;

struct LifetimeContext {
    sess: session::Session,
    named_region_map: @RefCell<NamedRegionMap>,
}

enum ScopeChain<'a> {
    ItemScope(&'a OptVec<ast::Lifetime>),
    FnScope(ast::NodeId, &'a OptVec<ast::Lifetime>, Scope<'a>),
    BlockScope(ast::NodeId, Scope<'a>),
    RootScope
}

type Scope<'a> = &'a ScopeChain<'a>;

pub fn krate(sess: session::Session, krate: &ast::Crate)
             -> @RefCell<NamedRegionMap> {
    let mut ctxt = LifetimeContext {
        sess: sess,
        named_region_map: @RefCell::new(NodeMap::new())
    };
    visit::walk_crate(&mut ctxt, krate, &RootScope);
    sess.abort_if_errors();
    ctxt.named_region_map
}

impl<'a> Visitor<Scope<'a>> for LifetimeContext {
    fn visit_item(&mut self,
                  item: &ast::Item,
                  _: Scope<'a>) {
        let scope = match item.node {
            ast::ItemFn(..) | // fn lifetimes get added in visit_fn below
            ast::ItemMod(..) |
            ast::ItemMac(..) |
            ast::ItemForeignMod(..) |
            ast::ItemStatic(..) => {
                RootScope
            }
            ast::ItemTy(_, ref generics) |
            ast::ItemEnum(_, ref generics) |
            ast::ItemStruct(_, ref generics) |
            ast::ItemImpl(ref generics, _, _, _) |
            ast::ItemTrait(ref generics, _, _) => {
                self.check_lifetime_names(&generics.lifetimes);
                ItemScope(&generics.lifetimes)
            }
        };
        debug!("entering scope {:?}", scope);
        visit::walk_item(self, item, &scope);
        debug!("exiting scope {:?}", scope);
    }

    fn visit_fn(&mut self, fk: &visit::FnKind, fd: &ast::FnDecl,
                b: &ast::Block, s: Span, n: ast::NodeId,
                scope: Scope<'a>) {
        match *fk {
            visit::FkItemFn(_, generics, _, _) |
            visit::FkMethod(_, generics, _) => {
                let scope1 = FnScope(n, &generics.lifetimes, scope);
                self.check_lifetime_names(&generics.lifetimes);
                debug!("pushing fn scope id={} due to item/method", n);
                visit::walk_fn(self, fk, fd, b, s, n, &scope1);
                debug!("popping fn scope id={} due to item/method", n);
            }
            visit::FkFnBlock(..) => {
                visit::walk_fn(self, fk, fd, b, s, n, scope);
            }
        }
    }

    fn visit_ty(&mut self, ty: &ast::Ty,
                scope: Scope<'a>) {
        match ty.node {
            ast::TyClosure(closure) => {
                let scope1 = FnScope(ty.id, &closure.lifetimes, scope);
                self.check_lifetime_names(&closure.lifetimes);
                debug!("pushing fn scope id={} due to type", ty.id);
                visit::walk_ty(self, ty, &scope1);
                debug!("popping fn scope id={} due to type", ty.id);
            }
            ast::TyBareFn(bare_fn) => {
                let scope1 = FnScope(ty.id, &bare_fn.lifetimes, scope);
                self.check_lifetime_names(&bare_fn.lifetimes);
                debug!("pushing fn scope id={} due to type", ty.id);
                visit::walk_ty(self, ty, &scope1);
                debug!("popping fn scope id={} due to type", ty.id);
            }
            _ => {
                visit::walk_ty(self, ty, scope);
            }
        }
    }

    fn visit_ty_method(&mut self,
                       m: &ast::TypeMethod,
                       scope: Scope<'a>) {
        let scope1 = FnScope(m.id, &m.generics.lifetimes, scope);
        self.check_lifetime_names(&m.generics.lifetimes);
        debug!("pushing fn scope id={} due to ty_method", m.id);
        visit::walk_ty_method(self, m, &scope1);
        debug!("popping fn scope id={} due to ty_method", m.id);
    }

    fn visit_block(&mut self,
                   b: &ast::Block,
                   scope: Scope<'a>) {
        let scope1 = BlockScope(b.id, scope);
        debug!("pushing block scope {}", b.id);
        visit::walk_block(self, b, &scope1);
        debug!("popping block scope {}", b.id);
    }

    fn visit_lifetime_ref(&mut self,
                          lifetime_ref: &ast::Lifetime,
                          scope: Scope<'a>) {
        if lifetime_ref.name == special_idents::statik.name {
            self.insert_lifetime(lifetime_ref, ast::DefStaticRegion);
            return;
        }
        self.resolve_lifetime_ref(lifetime_ref, scope);
    }
}

impl LifetimeContext {
    fn resolve_lifetime_ref(&self,
                            lifetime_ref: &ast::Lifetime,
                            scope: Scope) {
        // Walk up the scope chain, tracking the number of fn scopes
        // that we pass through, until we find a lifetime with the
        // given name or we run out of scopes. If we encounter a code
        // block, then the lifetime is not bound but free, so switch
        // over to `resolve_free_lifetime_ref()` to complete the
        // search.
        let mut depth = 0;
        let mut scope = scope;
        loop {
            match *scope {
                BlockScope(id, s) => {
                    return self.resolve_free_lifetime_ref(id, lifetime_ref, s);
                }

                RootScope => {
                    break;
                }

                ItemScope(lifetimes) => {
                    match search_lifetimes(lifetimes, lifetime_ref) {
                        Some((index, decl_id)) => {
                            let def = ast::DefEarlyBoundRegion(index, decl_id);
                            self.insert_lifetime(lifetime_ref, def);
                            return;
                        }
                        None => {
                            break;
                        }
                    }
                }

                FnScope(id, lifetimes, s) => {
                    match search_lifetimes(lifetimes, lifetime_ref) {
                        Some((_index, decl_id)) => {
                            let def = ast::DefLateBoundRegion(id, depth, decl_id);
                            self.insert_lifetime(lifetime_ref, def);
                            return;
                        }

                        None => {
                            depth += 1;
                            scope = s;
                        }
                    }
                }
            }
        }

        self.unresolved_lifetime_ref(lifetime_ref);
    }

    fn resolve_free_lifetime_ref(&self,
                                 scope_id: ast::NodeId,
                                 lifetime_ref: &ast::Lifetime,
                                 scope: Scope) {
        // Walk up the scope chain, tracking the outermost free scope,
        // until we encounter a scope that contains the named lifetime
        // or we run out of scopes.
        let mut scope_id = scope_id;
        let mut scope = scope;
        let mut search_result = None;
        loop {
            match *scope {
                BlockScope(id, s) => {
                    scope_id = id;
                    scope = s;
                }

                RootScope => {
                    break;
                }

                ItemScope(lifetimes) => {
                    search_result = search_lifetimes(lifetimes, lifetime_ref);
                    break;
                }

                FnScope(_, lifetimes, s) => {
                    search_result = search_lifetimes(lifetimes, lifetime_ref);
                    if search_result.is_some() {
                        break;
                    }
                    scope = s;
                }
            }
        }

        match search_result {
            Some((_depth, decl_id)) => {
                let def = ast::DefFreeRegion(scope_id, decl_id);
                self.insert_lifetime(lifetime_ref, def);
            }

            None => {
                self.unresolved_lifetime_ref(lifetime_ref);
            }
        }

    }

    fn unresolved_lifetime_ref(&self,
                               lifetime_ref: &ast::Lifetime) {
        self.sess.span_err(
            lifetime_ref.span,
            format!("use of undeclared lifetime name `'{}`",
                    token::get_name(lifetime_ref.name)));
    }

    fn check_lifetime_names(&self, lifetimes: &OptVec<ast::Lifetime>) {
        for i in range(0, lifetimes.len()) {
            let lifetime_i = lifetimes.get(i);

            let special_idents = [special_idents::statik];
            for lifetime in lifetimes.iter() {
                if special_idents.iter().any(|&i| i.name == lifetime.name) {
                    self.sess.span_err(
                        lifetime.span,
                        format!("illegal lifetime parameter name: `{}`",
                                token::get_name(lifetime.name)));
                }
            }

            for j in range(i + 1, lifetimes.len()) {
                let lifetime_j = lifetimes.get(j);

                if lifetime_i.name == lifetime_j.name {
                    self.sess.span_err(
                        lifetime_j.span,
                        format!("lifetime name `'{}` declared twice in \
                                the same scope",
                                token::get_name(lifetime_j.name)));
                }
            }
        }
    }

    fn insert_lifetime(&self,
                       lifetime_ref: &ast::Lifetime,
                       def: ast::DefRegion) {
        if lifetime_ref.id == ast::DUMMY_NODE_ID {
            self.sess.span_bug(lifetime_ref.span,
                               "lifetime reference not renumbered, \
                               probably a bug in syntax::fold");
        }

        debug!("lifetime_ref={} id={} resolved to {:?}",
                lifetime_to_str(lifetime_ref),
                lifetime_ref.id,
                def);
        let mut named_region_map = self.named_region_map.borrow_mut();
        named_region_map.get().insert(lifetime_ref.id, def);
    }
}

fn search_lifetimes(lifetimes: &OptVec<ast::Lifetime>,
                    lifetime_ref: &ast::Lifetime)
                    -> Option<(uint, ast::NodeId)> {
    for (i, lifetime_decl) in lifetimes.iter().enumerate() {
        if lifetime_decl.name == lifetime_ref.name {
            return Some((i, lifetime_decl.id));
        }
    }
    return None;
}
<|endoftext|>