<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: Ord+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol> {
    state_id: StateId,
    transitions: Vec<(InputSymbol, DfaState)>
}

impl<InputSymbol: Ord+Clone> DfaTransitions<InputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                symbol_a.cmp(symbol_b)
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }
}

impl<InputSymbol: Ord+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashSet::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);

        states.push(DfaTransitions { state_id: 0, transitions: vec![] });
        known_states.insert(state_zero.clone());
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions};
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone());
            states.push(dfa_transitions);
        }

        // TODO: Build the DFA

        // TODO: output symbols

        unimplemented!()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::build(ndfa, builder);
    }
}
<commit_msg>Move on to building the DFA pattern matcher itself<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   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.
//

//!
//! # DFA compiler
//!
//! The DFA compiler converts NDFAs into DFAs, using a DFA builder.
//!

use std::marker::PhantomData;
use std::collections::HashSet;
use std::collections::HashMap;
use std::iter::*;

use super::dfa_builder::*;
use super::state_machine::*;

///
/// Builds a deterministic finite automaton from a NDFA
///
pub struct DfaCompiler<InputSymbol: Ord+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>> {
    /// State machine that is to be compiled
    ndfa: Ndfa,

    /// Builder where the state machine should be generated
    builder: Builder,

    // Phantom data to poke Rust's type system (it's too dumb to see that InputSymbol is used in both Ndfa and Builder there via the type constraint)
    #[allow(dead_code)]
    phantom: (PhantomData<InputSymbol>, PhantomData<OutputSymbol>, PhantomData<DfaType>)
}

/// Represents a state in the DFA (one or more states from the source)
#[derive(Eq, PartialEq, Hash, Clone)]
struct DfaState {
    source_states: Vec<StateId>
}

impl DfaState {
    /// Creates a DFA state from a set of source states
    fn create(source_states: Vec<StateId>) -> DfaState {
        let mut set = HashSet::new();
        for state in source_states {
            set.insert(state);
        }

        DfaState { source_states: Vec::from_iter(set.into_iter()) }
    }

    /// Removes any duplicate states from source_states
    fn dedupe(&mut self) {
        self.source_states.sort();
        self.source_states.dedup();
    }
}

/// Represents the transitions for a source state
struct DfaTransitions<InputSymbol> {
    state_id: StateId,
    transitions: Vec<(InputSymbol, DfaState)>
}

impl<InputSymbol: Ord+Clone> DfaTransitions<InputSymbol> {
    /// Goes through the transitions in the object and merges the states of any with the same symbol
    fn merge_states(&mut self) {
        if self.transitions.len() > 0 {
            // Order the transitions so that if two transitions have the same input symbol, they are neighbours
            self.transitions.sort_by(|a, b| {
                let &(ref symbol_a, _) = a;
                let &(ref symbol_b, _) = b;

                symbol_a.cmp(symbol_b)
            });

            // For any transition that has a duplicate state, combine it with the previous state
            let mut new_transitions = vec![];
            new_transitions.push(self.transitions[0].clone());

            for transit_idx in 1..self.transitions.len() {
                let len          = new_transitions.len();
                let this_transit = &mut self.transitions[transit_idx];

                if new_transitions[len-1].0 == this_transit.0 {
                    // Same symbol: expand this state
                    new_transitions[len-1].1.source_states.append(&mut this_transit.1.source_states);
                } else {
                    // Different symbol: add new state
                    new_transitions.push(this_transit.clone());
                }
            }

            // Ensure all of the states are sorted and de-duplicated
            for transit in &mut new_transitions {
                transit.1.dedupe();
            }

            // Update the transitions
            self.transitions = new_transitions;
        }
    }
}

impl<InputSymbol: Ord+Clone, OutputSymbol, DfaType, Ndfa: StateMachine<InputSymbol, OutputSymbol>, Builder: DfaBuilder<InputSymbol, OutputSymbol, DfaType>>
    DfaCompiler<InputSymbol, OutputSymbol, DfaType, Ndfa, Builder> {
    ///
    /// Builds a DFA using an NDFA and a builder
    ///
    pub fn build(ndfa: Ndfa, builder: Builder) -> DfaType {
        let compiler = DfaCompiler::new(ndfa, builder);
        compiler.compile()
    }

    ///
    /// Creates a new DFA compiler using a particular builder and NDFA
    ///
    pub fn new(ndfa: Ndfa, builder: Builder) -> Self {
        DfaCompiler { ndfa: ndfa, builder: builder, phantom: (PhantomData, PhantomData, PhantomData) }
    }

    ///
    /// Compiles the NDFA into a DFA
    ///
    pub fn compile(self) -> DfaType {
        // We assume that input symbols are non-overlapping, which is not automatically the case for symbol ranges

        // Work out the state mapping for each input symbol
        let mut states       = vec![];
        let mut known_states = HashMap::new();
        let mut to_process   = vec![];

        // All state machines have state 0 as their starting state
        let state_zero = DfaState::create(vec![0]);

        states.push(DfaTransitions { state_id: 0, transitions: vec![] });
        known_states.insert(state_zero.clone(), 0);
        to_process.push(state_zero);

        while let Some(state) = to_process.pop() {
            // Create a new transitions object for this state
            let mut transitions = vec![];

            for source_state in &state.source_states {
                let source_transitions = self.ndfa.get_transitions_for_state(*source_state);

                for (symbol, state) in source_transitions {
                    transitions.push((symbol, DfaState::create(vec![state])));
                }
            }

            // Merge it so that we only have one transition per symbol
            let mut dfa_transitions = DfaTransitions { state_id: states.len() as StateId, transitions: transitions};
            dfa_transitions.merge_states();

            // Process any generated states that are not already in the DFA
            for &(_, ref maybe_new_state) in &dfa_transitions.transitions {
                if !known_states.contains_key(maybe_new_state) {
                    to_process.push(maybe_new_state.clone());
                }
            }

            // Store the new state
            known_states.insert(state.clone(), dfa_transitions.state_id);
            states.push(dfa_transitions);
        }

        // Build the DFA
        let mut builder = self.builder;

        for dfa_state in states {
            builder.start_state();

            for (symbol, target_state) in dfa_state.transitions {
                builder.transition(symbol, known_states[&target_state]);
            }
        }

        // TODO: output symbols

        // Generate the final DFA
        builder.build()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::regular_pattern::*;
    use super::super::state_machine::*;
    use super::super::symbol_range_dfa::*;

    #[test]
    fn can_create_compiler() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::new(ndfa, builder);
    }

    #[test]
    fn can_build_dfa() {
        let ndfa     = "abc".into_pattern().to_ndfa("success");
        let builder  = SymbolRangeDfaBuilder::new();

        DfaCompiler::build(ndfa, builder);
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package finding.", why),
    });
}

#[derive(Serialize, Deserialize)]
struct Package {
    name: String,
    version: String,
    crc32: String,
    url: String,
    dependencies: Vec<Package>
}

#[derive(Serialize, Deserialize)]
struct PackageList {
    packages: Vec<Package>,
    last_updated: Date
}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, &str> {
    let mut list = custom_try!(File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = reader.read_to_string();
    let package_list: PackageList = custom_try!(serde_json::from_str(buffer));

    let filtered = package_list.packages.into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err("Package not found"),
        _ => Ok(filtered)
    }
}

<commit_msg>Added update package functionality<commit_after>use std::error::Error;
use std::fs::File;
use std::io::{BufReader, BufRead};
use std::path::Path;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during package finding.", why),
    });
}

#[derive(Serialize, Deserialize)]
struct Package {
    name: String,
    version: String,
    crc32: String,
    url: String,
    dependencies: Vec<Package>
}

#[derive(Serialize, Deserialize)]
struct PackageList {
    packages: Vec<Package>,
    last_updated: Date
}

pub fn update_package(url: &str, path: &Path) -> bool {
    download::download_file(url + "packages.json", path);
}

pub fn find_package(name: &str, path:&Path) -> Result<Vec<Package>, &str> {
    let mut list = custom_try!(File::open(path));
    let mut reader = BufReader::new(list);
    let mut buffer = reader.read_to_string();
    let package_list: PackageList = custom_try!(serde_json::from_str(buffer));

    let filtered = package_list.packages.into_iter()
                    .filter(|x| !x.name.contains(name))
                    .collect::<Vec<_>>();

    match filtered.len() {
        0 => Err("Package not found"),
        _ => Ok(filtered)
    }
}

<|endoftext|>


<commit_before>// Copyright 2014 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.

use rustc::dep_graph::{DepGraph, DepKind};
use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::svh::Svh;
use rustc::ich::Fingerprint;
use rustc::middle::cstore::EncodedMetadataHashes;
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::util::common::time;
use rustc::util::nodemap::DefIdMap;
use rustc_data_structures::fx::FxHashMap;
use rustc_serialize::Encodable as RustcEncodable;
use rustc_serialize::opaque::Encoder;
use std::io::{self, Cursor, Write};
use std::fs::{self, File};
use std::path::PathBuf;

use super::data::*;
use super::fs::*;
use super::dirty_clean;
use super::file_format;
use super::work_product;

use super::load::load_prev_metadata_hashes;

pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                metadata_hashes: &EncodedMetadataHashes,
                                svh: Svh) {
    debug!("save_dep_graph()");
    let _ignore = tcx.dep_graph.in_ignore();
    let sess = tcx.sess;
    if sess.opts.incremental.is_none() {
        return;
    }

    // We load the previous metadata hashes now before overwriting the file
    // (if we need them for testing).
    let prev_metadata_hashes = if tcx.sess.opts.debugging_opts.query_dep_graph {
        load_prev_metadata_hashes(tcx)
    } else {
        DefIdMap()
    };

    let mut current_metadata_hashes = FxHashMap();

    if sess.opts.debugging_opts.incremental_cc ||
       sess.opts.debugging_opts.query_dep_graph {
        save_in(sess,
                metadata_hash_export_path(sess),
                |e| encode_metadata_hashes(tcx,
                                           svh,
                                           metadata_hashes,
                                           &mut current_metadata_hashes,
                                           e));
    }

    time(sess.time_passes(), "persist query result cache", || {
        save_in(sess,
                query_cache_path(sess),
                |e| encode_query_cache(tcx, e));
    });

    if tcx.sess.opts.debugging_opts.incremental_queries {
        time(sess.time_passes(), "persist dep-graph", || {
            save_in(sess,
                    dep_graph_path(sess),
                    |e| encode_dep_graph(tcx, e));
        });
    }

    dirty_clean::check_dirty_clean_annotations(tcx);
    dirty_clean::check_dirty_clean_metadata(tcx,
                                            &prev_metadata_hashes,
                                            &current_metadata_hashes);
}

pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
    if sess.opts.incremental.is_none() {
        return;
    }

    debug!("save_work_products()");
    let _ignore = dep_graph.in_ignore();
    let path = work_products_path(sess);
    save_in(sess, path, |e| encode_work_products(dep_graph, e));

    // We also need to clean out old work-products, as not all of them are
    // deleted during invalidation. Some object files don't change their
    // content, they are just not needed anymore.
    let new_work_products = dep_graph.work_products();
    let previous_work_products = dep_graph.previous_work_products();

    for (id, wp) in previous_work_products.iter() {
        if !new_work_products.contains_key(id) {
            work_product::delete_workproduct_files(sess, wp);
            debug_assert!(wp.saved_files.iter().all(|&(_, ref file_name)| {
                !in_incr_comp_dir_sess(sess, file_name).exists()
            }));
        }
    }

    // Check that we did not delete one of the current work-products:
    debug_assert!({
        new_work_products.iter()
                         .flat_map(|(_, wp)| wp.saved_files
                                               .iter()
                                               .map(|&(_, ref name)| name))
                         .map(|name| in_incr_comp_dir_sess(sess, name))
                         .all(|path| path.exists())
    });
}

fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
    where F: FnOnce(&mut Encoder) -> io::Result<()>
{
    debug!("save: storing data in {}", path_buf.display());

    // delete the old dep-graph, if any
    // Note: It's important that we actually delete the old file and not just
    // truncate and overwrite it, since it might be a shared hard-link, the
    // underlying data of which we don't want to modify
    if path_buf.exists() {
        match fs::remove_file(&path_buf) {
            Ok(()) => {
                debug!("save: remove old file");
            }
            Err(err) => {
                sess.err(&format!("unable to delete old dep-graph at `{}`: {}",
                                  path_buf.display(),
                                  err));
                return;
            }
        }
    }

    // generate the data in a memory buffer
    let mut wr = Cursor::new(Vec::new());
    file_format::write_file_header(&mut wr).unwrap();
    match encode(&mut Encoder::new(&mut wr)) {
        Ok(()) => {}
        Err(err) => {
            sess.err(&format!("could not encode dep-graph to `{}`: {}",
                              path_buf.display(),
                              err));
            return;
        }
    }

    // write the data out
    let data = wr.into_inner();
    match File::create(&path_buf).and_then(|mut file| file.write_all(&data)) {
        Ok(_) => {
            debug!("save: data written to disk successfully");
        }
        Err(err) => {
            sess.err(&format!("failed to write dep-graph to `{}`: {}",
                              path_buf.display(),
                              err));
            return;
        }
    }
}

fn encode_dep_graph(tcx: TyCtxt,
                    encoder: &mut Encoder)
                    -> io::Result<()> {
    // First encode the commandline arguments hash
    tcx.sess.opts.dep_tracking_hash().encode(encoder)?;

    // Encode the graph data.
    let serialized_graph = tcx.dep_graph.serialize();

    if tcx.sess.opts.debugging_opts.incremental_info {
        #[derive(Clone)]
        struct Stat {
            kind: DepKind,
            node_counter: u64,
            edge_counter: u64,
        }

        let total_node_count = serialized_graph.nodes.len();
        let total_edge_count = serialized_graph.edge_list_data.len();
        let (total_edge_reads, total_duplicate_edge_reads) =
            tcx.dep_graph.edge_deduplication_data();

        let mut counts: FxHashMap<_, Stat> = FxHashMap();

        for (i, &(node, _)) in serialized_graph.nodes.iter_enumerated() {
            let stat = counts.entry(node.kind).or_insert(Stat {
                kind: node.kind,
                node_counter: 0,
                edge_counter: 0,
            });

            stat.node_counter += 1;
            let (edge_start, edge_end) = serialized_graph.edge_list_indices[i];
            stat.edge_counter += (edge_end - edge_start) as u64;
        }

        let mut counts: Vec<_> = counts.values().cloned().collect();
        counts.sort_by_key(|s| -(s.node_counter as i64));

        let percentage_of_all_nodes: Vec<f64> = counts.iter().map(|s| {
            (100.0 * (s.node_counter as f64)) / (total_node_count as f64)
        }).collect();

        let average_edges_per_kind: Vec<f64> = counts.iter().map(|s| {
            (s.edge_counter as f64) / (s.node_counter as f64)
        }).collect();

        println!("[incremental]");
        println!("[incremental] DepGraph Statistics");

        const SEPARATOR: &str = "[incremental] --------------------------------\
                                 ----------------------------------------------\
                                 ------------";

        println!("{}", SEPARATOR);
        println!("[incremental]");
        println!("[incremental] Total Node Count: {}", total_node_count);
        println!("[incremental] Total Edge Count: {}", total_edge_count);
        println!("[incremental] Total Edge Reads: {}", total_edge_reads);
        println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
        println!("[incremental]");
        println!("[incremental]  {:<36}| {:<17}| {:<12}| {:<17}|",
                 "Node Kind",
                 "Node Frequency",
                 "Node Count",
                 "Avg. Edge Count");
        println!("[incremental] -------------------------------------\
                  |------------------\
                  |-------------\
                  |------------------|");

        for (i, stat) in counts.iter().enumerate() {
            println!("[incremental]  {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
                format!("{:?}", stat.kind),
                percentage_of_all_nodes[i],
                stat.node_counter,
                average_edges_per_kind[i]);
        }

        println!("{}", SEPARATOR);
        println!("[incremental]");
    }

    serialized_graph.encode(encoder)?;

    Ok(())
}

fn encode_metadata_hashes(tcx: TyCtxt,
                          svh: Svh,
                          metadata_hashes: &EncodedMetadataHashes,
                          current_metadata_hashes: &mut FxHashMap<DefId, Fingerprint>,
                          encoder: &mut Encoder)
                          -> io::Result<()> {
    assert_eq!(metadata_hashes.hashes.len(),
        metadata_hashes.hashes.iter().map(|x| (x.def_index, ())).collect::<FxHashMap<_,_>>().len());

    let mut serialized_hashes = SerializedMetadataHashes {
        entry_hashes: metadata_hashes.hashes.to_vec(),
        index_map: FxHashMap()
    };

    if tcx.sess.opts.debugging_opts.query_dep_graph {
        for serialized_hash in &serialized_hashes.entry_hashes {
            let def_id = DefId::local(DefIndex::from_u32(serialized_hash.def_index));

            // Store entry in the index_map
            let def_path_hash = tcx.def_path_hash(def_id);
            serialized_hashes.index_map.insert(def_id.index.as_u32(), def_path_hash);

            // Record hash in current_metadata_hashes
            current_metadata_hashes.insert(def_id, serialized_hash.hash);
        }

        debug!("save: stored index_map (len={}) for serialized hashes",
               serialized_hashes.index_map.len());
    }

    // Encode everything.
    svh.encode(encoder)?;
    serialized_hashes.encode(encoder)?;

    Ok(())
}

fn encode_work_products(dep_graph: &DepGraph,
                        encoder: &mut Encoder) -> io::Result<()> {
    let work_products: Vec<_> = dep_graph
        .work_products()
        .iter()
        .map(|(id, work_product)| {
            SerializedWorkProduct {
                id: id.clone(),
                work_product: work_product.clone(),
            }
        })
        .collect();

    work_products.encode(encoder)
}

fn encode_query_cache(tcx: TyCtxt,
                      encoder: &mut Encoder)
                      -> io::Result<()> {
    tcx.serialize_query_result_cache(encoder)
}
<commit_msg>Remove some trailing whitespace.<commit_after>// Copyright 2014 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.

use rustc::dep_graph::{DepGraph, DepKind};
use rustc::hir::def_id::{DefId, DefIndex};
use rustc::hir::svh::Svh;
use rustc::ich::Fingerprint;
use rustc::middle::cstore::EncodedMetadataHashes;
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::util::common::time;
use rustc::util::nodemap::DefIdMap;
use rustc_data_structures::fx::FxHashMap;
use rustc_serialize::Encodable as RustcEncodable;
use rustc_serialize::opaque::Encoder;
use std::io::{self, Cursor, Write};
use std::fs::{self, File};
use std::path::PathBuf;

use super::data::*;
use super::fs::*;
use super::dirty_clean;
use super::file_format;
use super::work_product;

use super::load::load_prev_metadata_hashes;

pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                metadata_hashes: &EncodedMetadataHashes,
                                svh: Svh) {
    debug!("save_dep_graph()");
    let _ignore = tcx.dep_graph.in_ignore();
    let sess = tcx.sess;
    if sess.opts.incremental.is_none() {
        return;
    }

    // We load the previous metadata hashes now before overwriting the file
    // (if we need them for testing).
    let prev_metadata_hashes = if tcx.sess.opts.debugging_opts.query_dep_graph {
        load_prev_metadata_hashes(tcx)
    } else {
        DefIdMap()
    };

    let mut current_metadata_hashes = FxHashMap();

    if sess.opts.debugging_opts.incremental_cc ||
       sess.opts.debugging_opts.query_dep_graph {
        save_in(sess,
                metadata_hash_export_path(sess),
                |e| encode_metadata_hashes(tcx,
                                           svh,
                                           metadata_hashes,
                                           &mut current_metadata_hashes,
                                           e));
    }

    time(sess.time_passes(), "persist query result cache", || {
        save_in(sess,
                query_cache_path(sess),
                |e| encode_query_cache(tcx, e));
    });

    if tcx.sess.opts.debugging_opts.incremental_queries {
        time(sess.time_passes(), "persist dep-graph", || {
            save_in(sess,
                    dep_graph_path(sess),
                    |e| encode_dep_graph(tcx, e));
        });
    }

    dirty_clean::check_dirty_clean_annotations(tcx);
    dirty_clean::check_dirty_clean_metadata(tcx,
                                            &prev_metadata_hashes,
                                            &current_metadata_hashes);
}

pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
    if sess.opts.incremental.is_none() {
        return;
    }

    debug!("save_work_products()");
    let _ignore = dep_graph.in_ignore();
    let path = work_products_path(sess);
    save_in(sess, path, |e| encode_work_products(dep_graph, e));

    // We also need to clean out old work-products, as not all of them are
    // deleted during invalidation. Some object files don't change their
    // content, they are just not needed anymore.
    let new_work_products = dep_graph.work_products();
    let previous_work_products = dep_graph.previous_work_products();

    for (id, wp) in previous_work_products.iter() {
        if !new_work_products.contains_key(id) {
            work_product::delete_workproduct_files(sess, wp);
            debug_assert!(wp.saved_files.iter().all(|&(_, ref file_name)| {
                !in_incr_comp_dir_sess(sess, file_name).exists()
            }));
        }
    }

    // Check that we did not delete one of the current work-products:
    debug_assert!({
        new_work_products.iter()
                         .flat_map(|(_, wp)| wp.saved_files
                                               .iter()
                                               .map(|&(_, ref name)| name))
                         .map(|name| in_incr_comp_dir_sess(sess, name))
                         .all(|path| path.exists())
    });
}

fn save_in<F>(sess: &Session, path_buf: PathBuf, encode: F)
    where F: FnOnce(&mut Encoder) -> io::Result<()>
{
    debug!("save: storing data in {}", path_buf.display());

    // delete the old dep-graph, if any
    // Note: It's important that we actually delete the old file and not just
    // truncate and overwrite it, since it might be a shared hard-link, the
    // underlying data of which we don't want to modify
    if path_buf.exists() {
        match fs::remove_file(&path_buf) {
            Ok(()) => {
                debug!("save: remove old file");
            }
            Err(err) => {
                sess.err(&format!("unable to delete old dep-graph at `{}`: {}",
                                  path_buf.display(),
                                  err));
                return;
            }
        }
    }

    // generate the data in a memory buffer
    let mut wr = Cursor::new(Vec::new());
    file_format::write_file_header(&mut wr).unwrap();
    match encode(&mut Encoder::new(&mut wr)) {
        Ok(()) => {}
        Err(err) => {
            sess.err(&format!("could not encode dep-graph to `{}`: {}",
                              path_buf.display(),
                              err));
            return;
        }
    }

    // write the data out
    let data = wr.into_inner();
    match File::create(&path_buf).and_then(|mut file| file.write_all(&data)) {
        Ok(_) => {
            debug!("save: data written to disk successfully");
        }
        Err(err) => {
            sess.err(&format!("failed to write dep-graph to `{}`: {}",
                              path_buf.display(),
                              err));
            return;
        }
    }
}

fn encode_dep_graph(tcx: TyCtxt,
                    encoder: &mut Encoder)
                    -> io::Result<()> {
    // First encode the commandline arguments hash
    tcx.sess.opts.dep_tracking_hash().encode(encoder)?;

    // Encode the graph data.
    let serialized_graph = tcx.dep_graph.serialize();

    if tcx.sess.opts.debugging_opts.incremental_info {
        #[derive(Clone)]
        struct Stat {
            kind: DepKind,
            node_counter: u64,
            edge_counter: u64,
        }

        let total_node_count = serialized_graph.nodes.len();
        let total_edge_count = serialized_graph.edge_list_data.len();
        let (total_edge_reads, total_duplicate_edge_reads) =
            tcx.dep_graph.edge_deduplication_data();

        let mut counts: FxHashMap<_, Stat> = FxHashMap();

        for (i, &(node, _)) in serialized_graph.nodes.iter_enumerated() {
            let stat = counts.entry(node.kind).or_insert(Stat {
                kind: node.kind,
                node_counter: 0,
                edge_counter: 0,
            });

            stat.node_counter += 1;
            let (edge_start, edge_end) = serialized_graph.edge_list_indices[i];
            stat.edge_counter += (edge_end - edge_start) as u64;
        }

        let mut counts: Vec<_> = counts.values().cloned().collect();
        counts.sort_by_key(|s| -(s.node_counter as i64));

        let percentage_of_all_nodes: Vec<f64> = counts.iter().map(|s| {
            (100.0 * (s.node_counter as f64)) / (total_node_count as f64)
        }).collect();

        let average_edges_per_kind: Vec<f64> = counts.iter().map(|s| {
            (s.edge_counter as f64) / (s.node_counter as f64)
        }).collect();

        println!("[incremental]");
        println!("[incremental] DepGraph Statistics");

        const SEPARATOR: &str = "[incremental] --------------------------------\
                                 ----------------------------------------------\
                                 ------------";

        println!("{}", SEPARATOR);
        println!("[incremental]");
        println!("[incremental] Total Node Count: {}", total_node_count);
        println!("[incremental] Total Edge Count: {}", total_edge_count);
        println!("[incremental] Total Edge Reads: {}", total_edge_reads);
        println!("[incremental] Total Duplicate Edge Reads: {}", total_duplicate_edge_reads);
        println!("[incremental]");
        println!("[incremental]  {:<36}| {:<17}| {:<12}| {:<17}|",
                 "Node Kind",
                 "Node Frequency",
                 "Node Count",
                 "Avg. Edge Count");
        println!("[incremental] -------------------------------------\
                  |------------------\
                  |-------------\
                  |------------------|");

        for (i, stat) in counts.iter().enumerate() {
            println!("[incremental]  {:<36}|{:>16.1}% |{:>12} |{:>17.1} |",
                format!("{:?}", stat.kind),
                percentage_of_all_nodes[i],
                stat.node_counter,
                average_edges_per_kind[i]);
        }

        println!("{}", SEPARATOR);
        println!("[incremental]");
    }

    serialized_graph.encode(encoder)?;

    Ok(())
}

fn encode_metadata_hashes(tcx: TyCtxt,
                          svh: Svh,
                          metadata_hashes: &EncodedMetadataHashes,
                          current_metadata_hashes: &mut FxHashMap<DefId, Fingerprint>,
                          encoder: &mut Encoder)
                          -> io::Result<()> {
    assert_eq!(metadata_hashes.hashes.len(),
        metadata_hashes.hashes.iter().map(|x| (x.def_index, ())).collect::<FxHashMap<_,_>>().len());

    let mut serialized_hashes = SerializedMetadataHashes {
        entry_hashes: metadata_hashes.hashes.to_vec(),
        index_map: FxHashMap()
    };

    if tcx.sess.opts.debugging_opts.query_dep_graph {
        for serialized_hash in &serialized_hashes.entry_hashes {
            let def_id = DefId::local(DefIndex::from_u32(serialized_hash.def_index));

            // Store entry in the index_map
            let def_path_hash = tcx.def_path_hash(def_id);
            serialized_hashes.index_map.insert(def_id.index.as_u32(), def_path_hash);

            // Record hash in current_metadata_hashes
            current_metadata_hashes.insert(def_id, serialized_hash.hash);
        }

        debug!("save: stored index_map (len={}) for serialized hashes",
               serialized_hashes.index_map.len());
    }

    // Encode everything.
    svh.encode(encoder)?;
    serialized_hashes.encode(encoder)?;

    Ok(())
}

fn encode_work_products(dep_graph: &DepGraph,
                        encoder: &mut Encoder) -> io::Result<()> {
    let work_products: Vec<_> = dep_graph
        .work_products()
        .iter()
        .map(|(id, work_product)| {
            SerializedWorkProduct {
                id: id.clone(),
                work_product: work_product.clone(),
            }
        })
        .collect();

    work_products.encode(encoder)
}

fn encode_query_cache(tcx: TyCtxt,
                      encoder: &mut Encoder)
                      -> io::Result<()> {
    tcx.serialize_query_result_cache(encoder)
}
<|endoftext|>


<commit_before>//! Provides a simple SAH split based BVH2 that stores types implementing the Boundable trait

use std::sync::Arc;

use geometry::Boundable;
use linalg::Ray;

pub struct BVH<T> {
    /// Maximum amount of geometry we're willing to put in a leaf
    max_geom: usize,
    /// Reference to the vec containing the unordered objects in the BVH
    objects: Arc<Vec<T>>,
    // Should this be a vec of references? or of indices?
    // doing ordered_geom: Vec<&T> seems to be a lifetime annotation nightmare
}

impl<T: Boundable> BVH<T> {
    pub fn new(max_geom: usize, objects: Arc<Vec<T>>) -> BVH<T> {
        BVH { max_geom: max_geom, objects: objects }
    }
    /// Traverse the BVH and call the function passed on the objects in the leaf nodes
    /// of the BVH, returning the value returned by the function after traversal
    /// completes.
    /// TODO: I've tried to base this interface on that of `Iterator::map` however they don't seem
    /// to take `f` as a mutable parameter?
    pub fn intersect<'a, F, R>(&'a self, ray: &mut Ray, f: F) -> Option<R>
            where F: Fn(&mut Ray, &'a T) -> Option<R> {
        let mut result = None;
		for o in &*self.objects {
			result = f(ray, o).or(result);
		}
        result
    }
}

<commit_msg>Not sure how to write ordered_geom w/o exploding lifetime annotations<commit_after>//! Provides a simple SAH split based BVH2 that stores types implementing the Boundable trait

use std::sync::Arc;

use geometry::Boundable;
use linalg::Ray;

pub struct BVH<T> {
    /// Maximum amount of geometry we're willing to put in a leaf
    max_geom: usize,
    /// Reference to the vec containing the unordered objects in the BVH
    objects: Arc<Vec<T>>,
    // Should this be a vec of references? or of indices?
    // doing ordered_geom: Vec<&T> seems to be a lifetime annotation nightmare
    // I'm not sure how to express that the refered to objects live as long as
    // `objects`, it seems like adding a lifetime parameter requires polluting
    // everything with lifetime annotations that I think should be unecessary
    // ordered_geom: Vec<&'a T>,
}

impl<T: Boundable> BVH<T> {
    pub fn new(max_geom: usize, objects: Arc<Vec<T>>) -> BVH<T> {
        BVH { max_geom: max_geom, objects: objects }
    }
    /// Traverse the BVH and call the function passed on the objects in the leaf nodes
    /// of the BVH, returning the value returned by the function after traversal
    /// completes.
    /// TODO: I've tried to base this interface on that of `Iterator::map` however they don't seem
    /// to take `f` as a mutable parameter?
    pub fn intersect<'a, F, R>(&'a self, ray: &mut Ray, f: F) -> Option<R>
            where F: Fn(&mut Ray, &'a T) -> Option<R> {
        let mut result = None;
		for o in &*self.objects {
			result = f(ray, o).or(result);
		}
        result
    }
}

<|endoftext|>


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

use uuid::Uuid;

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

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

pub struct CellFormat {
    pub fieldname: String,
    pub fieldtype: CellType
}

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

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

/*
trait Formattable {
    fn own_format(&mut self) {
        self.format = RecFormat::new(self.format.cols);
    }
}
*/

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

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

/*
impl Formattable for Rec {
}
*/

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

impl Table {
    pub fn new(format: Arc<RwLock<RecFormat>>) -> Table {
        return Table {
            format: format
        };
    }
    pub fn new(format: Arc<RwLock<RecFormat>>, name: String) -> Table {
        return Table {
            name: name,
            format: format
        };
    }
}
<commit_msg>Remove duplicate constructor<commit_after>use std::sync::{Arc, RwLock};
use std::option::Option;
use std::clone::Clone;

use uuid::Uuid;

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

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

pub struct CellFormat {
    pub fieldname: String,
    pub fieldtype: CellType
}

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

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

/*
trait Formattable {
    fn own_format(&mut self) {
        self.format = RecFormat::new(self.format.cols);
    }
}
*/

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

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

/*
impl Formattable for Rec {
}
*/

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

impl Table {
    pub fn new(format: Arc<RwLock<RecFormat>>) -> Table {
        return Table {
            format: format
        };
    }
}
<|endoftext|>


<commit_before>extern crate schannel;

use std::io;
use std::fmt;
use std::error;
use std::sync::Arc;
use self::schannel::cert_store::{PfxImportOptions, Memory, CertStore, CertAdd};
use self::schannel::cert_context::CertContext;
use self::schannel::schannel_cred::{Direction, SchannelCred, Protocol};
use self::schannel::tls_stream;

fn convert_protocols(protocols: &[::Protocol]) -> Vec<Protocol> {
    protocols
        .iter()
        .map(|p| match *p {
            ::Protocol::Sslv3 => Protocol::Ssl3,
            ::Protocol::Tlsv10 => Protocol::Tls10,
            ::Protocol::Tlsv11 => Protocol::Tls11,
            ::Protocol::Tlsv12 => Protocol::Tls12,
            ::Protocol::__NonExhaustive => unreachable!(),
        })
        .collect()
}

pub struct Error(io::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Error(error)
    }
}

pub struct Pkcs12 {
    cert: CertContext,
}

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let mut store = try!(PfxImportOptions::new().password(pass).import(buf));
        let mut identity = None;

        for cert in store.certs() {
            if cert.private_key()
                .silent(true)
                .compare_key(true)
                .acquire()
                .is_ok()
            {
                identity = Some(cert);
            }
        }

        let identity = match identity {
            Some(identity) => identity,
            None => {
                return Err(
                    io::Error::new(
                        io::ErrorKind::InvalidInput,
                        "No identity found in PKCS #12 archive",
                    ).into(),
                );
            }
        };

        Ok(Pkcs12 { cert: identity })
    }
}

pub struct Certificate(CertContext);

impl Certificate {
    pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = try!(CertContext::new(buf));
        Ok(Certificate(cert))
    }
}

pub struct MidHandshakeTlsStream<S>(tls_stream::MidHandshakeTlsStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
where
    S: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S>
where
    S: io::Read + io::Write,
{
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }

    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<tls_stream::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: tls_stream::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            tls_stream::HandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
            tls_stream::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<io::Error> for HandshakeError<S> {
    fn from(e: io::Error) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

pub struct TlsConnectorBuilder(TlsConnector);

impl TlsConnectorBuilder {
    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        self.0.cert = Some(pkcs12.cert);
        Ok(())
    }

    pub fn add_root_certificate(&mut self, cert: Certificate) -> Result<(), Error> {
        try!(self.0.roots.add_cert(&cert.0, CertAdd::ReplaceExisting));
        Ok(())
    }

    pub fn supported_protocols(&mut self, protocols: &[::Protocol]) -> Result<(), Error> {
        self.0.protocols = convert_protocols(protocols);
        Ok(())
    }

    pub fn build(self) -> Result<TlsConnector, Error> {
        Ok(self.0)
    }
}

#[derive(Clone)]
pub struct TlsConnector {
    cert: Option<CertContext>,
    roots: CertStore,
    protocols: Vec<Protocol>,
    callback: Option<Arc<Fn(tls_stream::CertValidationResult) -> io::Result<()> + Sync + Send>>,
}

impl TlsConnector {
    pub fn builder() -> Result<TlsConnectorBuilder, Error> {
        Ok(TlsConnectorBuilder(TlsConnector {
            cert: None,
            roots: try!(Memory::new()).into_store(),
            protocols: vec![Protocol::Tls10, Protocol::Tls11, Protocol::Tls12],
            callback: None,
        }))
    }

    pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        self._connect(Some(domain), stream)
    }

    pub fn connect_no_domain<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        self._connect(None, stream)
    }

    fn _connect<S>(
        &self,
        domain: Option<&str>,
        stream: S,
    ) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut builder = SchannelCred::builder();
        builder.enabled_protocols(&self.protocols);
        if let Some(cert) = self.cert.as_ref() {
            builder.cert(cert.clone());
        }
        let cred = try!(builder.acquire(Direction::Outbound));
        let mut builder = tls_stream::Builder::new();
        if let Some(domain) = domain {
            builder.domain(domain);
        }
        if let Some(ref callback) = self.callback {
            let callback = callback.clone();
            builder.verify_callback(move |r| callback(r));
        }
        builder.cert_store(self.roots.clone());
        match builder.connect(cred, stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsAcceptorBuilder(TlsAcceptor);

impl TlsAcceptorBuilder {
    pub fn supported_protocols(&mut self, protocols: &[::Protocol]) -> Result<(), Error> {
        self.0.protocols = convert_protocols(protocols);
        Ok(())
    }

    pub fn build(self) -> Result<TlsAcceptor, Error> {
        Ok(self.0)
    }
}

#[derive(Clone)]
pub struct TlsAcceptor {
    cert: CertContext,
    protocols: Vec<Protocol>,
}

impl TlsAcceptor {
    pub fn builder(pkcs12: Pkcs12) -> Result<TlsAcceptorBuilder, Error> {
        Ok(TlsAcceptorBuilder(TlsAcceptor {
            cert: pkcs12.cert,
            protocols: vec![Protocol::Tls10, Protocol::Tls11, Protocol::Tls12],
        }))
    }

    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut builder = SchannelCred::builder();
        builder.enabled_protocols(&self.protocols);
        builder.cert(self.cert.clone());
        // FIXME we're probably missing the certificate chain?
        let cred = try!(builder.acquire(Direction::Inbound));
        match tls_stream::Builder::new().accept(cred, stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsStream<S>(tls_stream::TlsStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.get_buf().len())
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        try!(self.0.shutdown());
        Ok(())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// SChannel-specific extensions to `TlsConnectorBuilder`.
pub trait TlsConnectorBuilderExt {
    /// Sets a callback function which decides if the server's certificate chain
    /// is to be trusted.
    fn verify_callback<F>(&mut self, callback: F)
    where
        F: Fn(tls_stream::CertValidationResult) -> io::Result<()> + 'static + Send + Sync;
}

impl TlsConnectorBuilderExt for ::TlsConnectorBuilder {
    fn verify_callback<F>(&mut self, callback: F)
    where
        F: Fn(tls_stream::CertValidationResult) -> io::Result<()> + 'static + Send + Sync,
    {
        (self.0).0.callback = Some(Arc::new(callback));
    }
}

/// SChannel-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the SChannel `TlsStream`.
    fn raw_stream(&self) -> &tls_stream::TlsStream<S>;

    /// Returns a mutable reference to the SChannel `TlsStream`.
    fn raw_stream_mut(&mut self) -> &mut tls_stream::TlsStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &tls_stream::TlsStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut tls_stream::TlsStream<S> {
        &mut (self.0).0
    }
}

/// SChannel-specific extensions to `Error`
pub trait ErrorExt {
    /// Extract the underlying SChannel error for inspection.
    fn schannel_error(&self) -> &io::Error;
}

impl ErrorExt for ::Error {
    fn schannel_error(&self) -> &io::Error {
        &(self.0).0
    }
}

/// SChannel-specific extensions to `Certificate`.
pub trait CertificateExt {
    /// builds a native_Tls `Certificate` from an schannel `CertContext`
    fn from_cert_context(CertContext) -> ::Certificate;
}

impl CertificateExt for ::Certificate {
    fn from_cert_context(cert: CertContext) -> ::Certificate {
        ::Certificate(Certificate(cert))
    }
}
<commit_msg>filter supplied certs by whether they're certs<commit_after>extern crate schannel;

use std::io;
use std::fmt;
use std::error;
use std::sync::Arc;
use self::schannel::cert_store::{PfxImportOptions, Memory, CertStore, CertAdd};
use self::schannel::cert_context::CertContext;
use self::schannel::schannel_cred::{Direction, SchannelCred, Protocol};
use self::schannel::tls_stream;

fn convert_protocols(protocols: &[::Protocol]) -> Vec<Protocol> {
    protocols
        .iter()
        .map(|p| match *p {
            ::Protocol::Sslv3 => Protocol::Ssl3,
            ::Protocol::Tlsv10 => Protocol::Tls10,
            ::Protocol::Tlsv11 => Protocol::Tls11,
            ::Protocol::Tlsv12 => Protocol::Tls12,
            ::Protocol::__NonExhaustive => unreachable!(),
        })
        .collect()
}

pub struct Error(io::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Error(error)
    }
}

pub struct Pkcs12 {
    cert: CertContext,
}

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let mut store = try!(PfxImportOptions::new().password(pass).import(buf));
        let mut identity = None;

        for cert in store.certs() {
            if cert.private_key()
                .silent(true)
                .compare_key(true)
                .acquire()
                .is_ok()
            {
                identity = Some(cert);
            }
        }

        let identity = match identity {
            Some(identity) => identity,
            None => {
                return Err(
                    io::Error::new(
                        io::ErrorKind::InvalidInput,
                        "No identity found in PKCS #12 archive",
                    ).into(),
                );
            }
        };

        Ok(Pkcs12 { cert: identity })
    }
}

pub struct Certificate(CertContext);

impl Certificate {
    pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
        let cert = try!(CertContext::new(buf));
        Ok(Certificate(cert))
    }
}

pub struct MidHandshakeTlsStream<S>(tls_stream::MidHandshakeTlsStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
where
    S: fmt::Debug,
{
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S>
where
    S: io::Read + io::Write,
{
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }

    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<tls_stream::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: tls_stream::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            tls_stream::HandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
            tls_stream::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<io::Error> for HandshakeError<S> {
    fn from(e: io::Error) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

pub struct TlsConnectorBuilder(TlsConnector);

impl TlsConnectorBuilder {
    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        self.0.cert = Some(pkcs12.cert);
        Ok(())
    }

    pub fn add_root_certificate(&mut self, cert: Certificate) -> Result<(), Error> {
        try!(self.0.roots.add_cert(&cert.0, CertAdd::ReplaceExisting));
        Ok(())
    }

    pub fn supported_protocols(&mut self, protocols: &[::Protocol]) -> Result<(), Error> {
        self.0.protocols = convert_protocols(protocols);
        Ok(())
    }

    pub fn build(self) -> Result<TlsConnector, Error> {
        Ok(self.0)
    }
}

#[derive(Clone)]
pub struct TlsConnector {
    cert: Option<CertContext>,
    roots: CertStore,
    protocols: Vec<Protocol>,
    callback: Option<Arc<Fn(tls_stream::CertValidationResult) -> io::Result<()> + Sync + Send>>,
}

impl TlsConnector {
    pub fn builder() -> Result<TlsConnectorBuilder, Error> {
        Ok(TlsConnectorBuilder(TlsConnector {
            cert: None,
            roots: try!(Memory::new()).into_store(),
            protocols: vec![Protocol::Tls10, Protocol::Tls11, Protocol::Tls12],
            callback: None,
        }))
    }

    pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        self._connect(Some(domain), stream)
    }

    pub fn connect_no_domain<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        self._connect(None, stream)
    }

    fn _connect<S>(
        &self,
        domain: Option<&str>,
        stream: S,
    ) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut builder = SchannelCred::builder();
        builder.enabled_protocols(&self.protocols);
        if let Some(cert) = self.cert.as_ref() {
            if let Some(usage) = cert.key_usage() {
                if usage.contains("Digital Signature") {
                    builder.cert(cert.clone());
                }
            }
        }
        let cred = try!(builder.acquire(Direction::Outbound));
        let mut builder = tls_stream::Builder::new();
        if let Some(domain) = domain {
            builder.domain(domain);
        }
        if let Some(ref callback) = self.callback {
            let callback = callback.clone();
            builder.verify_callback(move |r| callback(r));
        }
        builder.cert_store(self.roots.clone());
        match builder.connect(cred, stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsAcceptorBuilder(TlsAcceptor);

impl TlsAcceptorBuilder {
    pub fn supported_protocols(&mut self, protocols: &[::Protocol]) -> Result<(), Error> {
        self.0.protocols = convert_protocols(protocols);
        Ok(())
    }

    pub fn build(self) -> Result<TlsAcceptor, Error> {
        Ok(self.0)
    }
}

#[derive(Clone)]
pub struct TlsAcceptor {
    cert: CertContext,
    protocols: Vec<Protocol>,
}

impl TlsAcceptor {
    pub fn builder(pkcs12: Pkcs12) -> Result<TlsAcceptorBuilder, Error> {
        Ok(TlsAcceptorBuilder(TlsAcceptor {
            cert: pkcs12.cert,
            protocols: vec![Protocol::Tls10, Protocol::Tls11, Protocol::Tls12],
        }))
    }

    pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
    where
        S: io::Read + io::Write,
    {
        let mut builder = SchannelCred::builder();
        builder.enabled_protocols(&self.protocols);
        builder.cert(self.cert.clone());
        // FIXME we're probably missing the certificate chain?
        let cred = try!(builder.acquire(Direction::Inbound));
        match tls_stream::Builder::new().accept(cred, stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsStream<S>(tls_stream::TlsStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.get_buf().len())
    }

    pub fn shutdown(&mut self) -> io::Result<()> {
        try!(self.0.shutdown());
        Ok(())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// SChannel-specific extensions to `TlsConnectorBuilder`.
pub trait TlsConnectorBuilderExt {
    /// Sets a callback function which decides if the server's certificate chain
    /// is to be trusted.
    fn verify_callback<F>(&mut self, callback: F)
    where
        F: Fn(tls_stream::CertValidationResult) -> io::Result<()> + 'static + Send + Sync;
}

impl TlsConnectorBuilderExt for ::TlsConnectorBuilder {
    fn verify_callback<F>(&mut self, callback: F)
    where
        F: Fn(tls_stream::CertValidationResult) -> io::Result<()> + 'static + Send + Sync,
    {
        (self.0).0.callback = Some(Arc::new(callback));
    }
}

/// SChannel-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the SChannel `TlsStream`.
    fn raw_stream(&self) -> &tls_stream::TlsStream<S>;

    /// Returns a mutable reference to the SChannel `TlsStream`.
    fn raw_stream_mut(&mut self) -> &mut tls_stream::TlsStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &tls_stream::TlsStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut tls_stream::TlsStream<S> {
        &mut (self.0).0
    }
}

/// SChannel-specific extensions to `Error`
pub trait ErrorExt {
    /// Extract the underlying SChannel error for inspection.
    fn schannel_error(&self) -> &io::Error;
}

impl ErrorExt for ::Error {
    fn schannel_error(&self) -> &io::Error {
        &(self.0).0
    }
}

/// SChannel-specific extensions to `Certificate`.
pub trait CertificateExt {
    /// builds a native_Tls `Certificate` from an schannel `CertContext`
    fn from_cert_context(CertContext) -> ::Certificate;
}

impl CertificateExt for ::Certificate {
    fn from_cert_context(cert: CertContext) -> ::Certificate {
        ::Certificate(Certificate(cert))
    }
}
<|endoftext|>


<commit_before>use clap::{App, AppSettings, Arg, SubCommand};
use error::Error;
use glob::glob;
use std::path::Path;
use std::process::exit;
use std::{env, fs, u64};
use tree_sitter::Language;
use tree_sitter_cli::{
    config, error, generate, highlight, loader, logger, parse, query, test, test_highlight, wasm,
    web_ui,
};

const BUILD_VERSION: &'static str = env!("CARGO_PKG_VERSION");
const BUILD_SHA: Option<&'static str> = option_env!("BUILD_SHA");

fn main() {
    if let Err(e) = run() {
        if !e.message().is_empty() {
            println!("");
            eprintln!("{}", e.message());
        }
        exit(1);
    }
}

fn run() -> error::Result<()> {
    let version = if let Some(build_sha) = BUILD_SHA {
        format!("{} ({})", BUILD_VERSION, build_sha)
    } else {
        BUILD_VERSION.to_string()
    };

    let matches = App::new("tree-sitter")
        .version(version.as_str())
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .author("Max Brunsfeld <maxbrunsfeld@gmail.com>")
        .about("Generates and tests parsers")
        .subcommand(SubCommand::with_name("init-config").about("Generate a default config file"))
        .subcommand(
            SubCommand::with_name("generate")
                .about("Generate a parser")
                .arg(Arg::with_name("grammar-path").index(1))
                .arg(Arg::with_name("log").long("log"))
                .arg(Arg::with_name("prev-abi").long("prev-abi"))
                .arg(
                    Arg::with_name("report-states-for-rule")
                        .long("report-states-for-rule")
                        .value_name("rule-name")
                        .takes_value(true),
                )
                .arg(Arg::with_name("no-minimize").long("no-minimize")),
        )
        .subcommand(
            SubCommand::with_name("parse")
                .about("Parse files")
                .arg(
                    Arg::with_name("path")
                        .index(1)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("debug").long("debug").short("d"))
                .arg(Arg::with_name("debug-graph").long("debug-graph").short("D"))
                .arg(Arg::with_name("quiet").long("quiet").short("q"))
                .arg(Arg::with_name("time").long("time").short("t"))
                .arg(Arg::with_name("allow-cancellation").long("cancel"))
                .arg(Arg::with_name("files-").long("cancel"))
                .arg(Arg::with_name("timeout").long("timeout").takes_value(true))
                .arg(
                    Arg::with_name("edits")
                        .long("edit")
                        .short("edit")
                        .takes_value(true)
                        .multiple(true)
                        .number_of_values(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("query")
                .about("Search files using a syntax tree query")
                .arg(Arg::with_name("query-path").index(1).required(true))
                .arg(
                    Arg::with_name("path")
                        .index(2)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("captures").long("captures").short("c")),
        )
        .subcommand(
            SubCommand::with_name("test")
                .about("Run a parser's tests")
                .arg(
                    Arg::with_name("filter")
                        .long("filter")
                        .short("f")
                        .takes_value(true),
                )
                .arg(Arg::with_name("debug").long("debug").short("d"))
                .arg(Arg::with_name("debug-graph").long("debug-graph").short("D")),
        )
        .subcommand(
            SubCommand::with_name("highlight")
                .about("Highlight a file")
                .arg(
                    Arg::with_name("path")
                        .index(1)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("html").long("html").short("h"))
                .arg(Arg::with_name("time").long("time").short("t"))
                .arg(Arg::with_name("q").short("q")),
        )
        .subcommand(
            SubCommand::with_name("build-wasm")
                .about("Compile a parser to WASM")
                .arg(
                    Arg::with_name("docker")
                        .long("docker")
                        .help("Run emscripten via docker even if it is installed locally"),
                )
                .arg(Arg::with_name("path").index(1).multiple(true)),
        )
        .subcommand(
            SubCommand::with_name("web-ui").about("Test a parser interactively in the browser"),
        )
        .subcommand(
            SubCommand::with_name("dump-languages")
                .about("Print info about all known language parsers"),
        )
        .get_matches();

    let home_dir = dirs::home_dir().expect("Failed to read home directory");
    let current_dir = env::current_dir().unwrap();
    let config = config::Config::load(&home_dir);
    let mut loader = loader::Loader::new(config.binary_directory.clone());

    if matches.subcommand_matches("init-config").is_some() {
        let config = config::Config::new(&home_dir);
        config.save(&home_dir)?;
    } else if let Some(matches) = matches.subcommand_matches("generate") {
        let grammar_path = matches.value_of("grammar-path");
        let report_symbol_name = matches.value_of("report-states-for-rule").or_else(|| {
            if matches.is_present("report-states") {
                Some("")
            } else {
                None
            }
        });
        if matches.is_present("log") {
            logger::init();
        }
        let prev_abi = matches.is_present("prev-abi");
        generate::generate_parser_in_directory(
            &current_dir,
            grammar_path,
            !prev_abi,
            report_symbol_name,
        )?;
    } else if let Some(matches) = matches.subcommand_matches("test") {
        let debug = matches.is_present("debug");
        let debug_graph = matches.is_present("debug-graph");
        let filter = matches.value_of("filter");
        let languages = loader.languages_at_path(&current_dir)?;
        let language = languages
            .first()
            .ok_or_else(|| "No language found".to_string())?;
        let test_dir = current_dir.join("test");

        // Run the corpus tests. Look for them at two paths: `test/corpus` and `corpus`.
        let mut test_corpus_dir = test_dir.join("corpus");
        if !test_corpus_dir.is_dir() {
            test_corpus_dir = current_dir.join("corpus");
        }
        if test_corpus_dir.is_dir() {
            test::run_tests_at_path(*language, &test_corpus_dir, debug, debug_graph, filter)?;
        }

        // Check that all of the queries are valid.
        test::check_queries_at_path(*language, &current_dir.join("queries"))?;

        // Run the syntax highlighting tests.
        let test_highlight_dir = test_dir.join("highlight");
        if test_highlight_dir.is_dir() {
            test_highlight::test_highlights(&loader, &test_highlight_dir)?;
        }
    } else if let Some(matches) = matches.subcommand_matches("parse") {
        let debug = matches.is_present("debug");
        let debug_graph = matches.is_present("debug-graph");
        let quiet = matches.is_present("quiet");
        let time = matches.is_present("time");
        let edits = matches
            .values_of("edits")
            .map_or(Vec::new(), |e| e.collect());
        let allow_cancellation = matches.is_present("allow-cancellation");
        let timeout = matches
            .value_of("timeout")
            .map_or(0, |t| u64::from_str_radix(t, 10).unwrap());
        let paths = collect_paths(matches.values_of("path").unwrap())?;
        let max_path_length = paths.iter().map(|p| p.chars().count()).max().unwrap();
        let mut has_error = false;
        loader.find_all_languages(&config.parser_directories)?;
        for path in paths {
            let path = Path::new(&path);
            let language =
                select_language(&mut loader, path, &current_dir, matches.value_of("scope"))?;
            has_error |= parse::parse_file_at_path(
                language,
                path,
                &edits,
                max_path_length,
                quiet,
                time,
                timeout,
                debug,
                debug_graph,
                allow_cancellation,
            )?;
        }
        if has_error {
            return Error::err(String::new());
        }
    } else if let Some(matches) = matches.subcommand_matches("query") {
        let ordered_captures = matches.values_of("captures").is_some();
        let paths = matches
            .values_of("path")
            .unwrap()
            .into_iter()
            .map(Path::new)
            .collect::<Vec<&Path>>();
        loader.find_all_languages(&config.parser_directories)?;
        let language = select_language(
            &mut loader,
            paths[0],
            &current_dir,
            matches.value_of("scope"),
        )?;
        let query_path = Path::new(matches.value_of("query-path").unwrap());
        query::query_files_at_paths(language, paths, query_path, ordered_captures)?;
    } else if let Some(matches) = matches.subcommand_matches("highlight") {
        loader.configure_highlights(&config.theme.highlight_names);
        loader.find_all_languages(&config.parser_directories)?;

        let time = matches.is_present("time");
        let paths = matches.values_of("path").unwrap().into_iter();
        let html_mode = matches.is_present("html");
        if html_mode {
            println!("{}", highlight::HTML_HEADER);
        }

        let language_config;
        if let Some(scope) = matches.value_of("scope") {
            language_config = loader.language_configuration_for_scope(scope)?;
            if language_config.is_none() {
                return Error::err(format!("Unknown scope '{}'", scope));
            }
        } else {
            language_config = None;
        }

        for path in paths {
            let path = Path::new(path);
            let (language, language_config) = match language_config {
                Some(v) => v,
                None => match loader.language_configuration_for_file_name(path)? {
                    Some(v) => v,
                    None => {
                        eprintln!("No language found for path {:?}", path);
                        continue;
                    }
                },
            };

            let source = fs::read(path)?;

            if let Some(highlight_config) = language_config.highlight_config(language)? {
                if html_mode {
                    highlight::html(&loader, &config.theme, &source, highlight_config, time)?;
                } else {
                    highlight::ansi(&loader, &config.theme, &source, highlight_config, time)?;
                }
            } else {
                return Error::err(format!("No syntax highlighting query found"));
            }
        }
    } else if let Some(matches) = matches.subcommand_matches("build-wasm") {
        let grammar_path = current_dir.join(matches.value_of("path").unwrap_or(""));
        wasm::compile_language_to_wasm(&grammar_path, matches.is_present("docker"))?;
    } else if matches.subcommand_matches("web-ui").is_some() {
        web_ui::serve(&current_dir);
    } else if matches.subcommand_matches("dump-languages").is_some() {
        loader.find_all_languages(&config.parser_directories)?;
        for (configuration, language_path) in loader.get_all_language_configurations() {
            println!(
                concat!(
                    "scope: {}\n",
                    "parser: {:?}\n",
                    "highlights: {:?}\n",
                    "file_types: {:?}\n",
                    "content_regex: {:?}\n",
                    "injection_regex: {:?}\n",
                ),
                configuration.scope.as_ref().unwrap_or(&String::new()),
                language_path,
                configuration.highlights_filenames,
                configuration.file_types,
                configuration.content_regex,
                configuration.injection_regex,
            );
        }
    }

    Ok(())
}

fn collect_paths<'a>(paths: impl Iterator<Item = &'a str>) -> error::Result<Vec<String>> {
    let mut result = Vec::new();

    let mut incorporate_path = |path: &str, positive| {
        if positive {
            result.push(path.to_string());
        } else {
            if let Some(index) = result.iter().position(|p| p == path) {
                result.remove(index);
            }
        }
    };

    for mut path in paths {
        let mut positive = true;
        if path.starts_with("!") {
            positive = false;
            path = path.trim_start_matches("!");
        }

        if Path::new(path).exists() {
            incorporate_path(path, positive);
        } else {
            for path in glob(path)? {
                if let Some(path) = path?.to_str() {
                    incorporate_path(path, positive);
                }
            }
        }
    }
    Ok(result)
}

fn select_language(
    loader: &mut loader::Loader,
    path: &Path,
    current_dir: &Path,
    scope: Option<&str>,
) -> Result<Language, Error> {
    if let Some(scope) = scope {
        if let Some(config) =
            loader
                .language_configuration_for_scope(scope)
                .map_err(Error::wrap(|| {
                    format!("Failed to load language for scope '{}'", scope)
                }))?
        {
            Ok(config.0)
        } else {
            return Error::err(format!("Unknown scope '{}'", scope));
        }
    } else if let Some((lang, _)) =
        loader
            .language_configuration_for_file_name(path)
            .map_err(Error::wrap(|| {
                format!(
                    "Failed to load language for file name {:?}",
                    path.file_name().unwrap()
                )
            }))?
    {
        Ok(lang)
    } else if let Some(lang) = loader
        .languages_at_path(&current_dir)
        .map_err(Error::wrap(|| {
            "Failed to load language in current directory"
        }))?
        .first()
        .cloned()
    {
        Ok(lang)
    } else {
        eprintln!("No language found");
        Error::err("No language found".to_string())
    }
}
<commit_msg>Remove accidentally-commited garbage line in arg parsing config<commit_after>use clap::{App, AppSettings, Arg, SubCommand};
use error::Error;
use glob::glob;
use std::path::Path;
use std::process::exit;
use std::{env, fs, u64};
use tree_sitter::Language;
use tree_sitter_cli::{
    config, error, generate, highlight, loader, logger, parse, query, test, test_highlight, wasm,
    web_ui,
};

const BUILD_VERSION: &'static str = env!("CARGO_PKG_VERSION");
const BUILD_SHA: Option<&'static str> = option_env!("BUILD_SHA");

fn main() {
    if let Err(e) = run() {
        if !e.message().is_empty() {
            println!("");
            eprintln!("{}", e.message());
        }
        exit(1);
    }
}

fn run() -> error::Result<()> {
    let version = if let Some(build_sha) = BUILD_SHA {
        format!("{} ({})", BUILD_VERSION, build_sha)
    } else {
        BUILD_VERSION.to_string()
    };

    let matches = App::new("tree-sitter")
        .version(version.as_str())
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .author("Max Brunsfeld <maxbrunsfeld@gmail.com>")
        .about("Generates and tests parsers")
        .subcommand(SubCommand::with_name("init-config").about("Generate a default config file"))
        .subcommand(
            SubCommand::with_name("generate")
                .about("Generate a parser")
                .arg(Arg::with_name("grammar-path").index(1))
                .arg(Arg::with_name("log").long("log"))
                .arg(Arg::with_name("prev-abi").long("prev-abi"))
                .arg(
                    Arg::with_name("report-states-for-rule")
                        .long("report-states-for-rule")
                        .value_name("rule-name")
                        .takes_value(true),
                )
                .arg(Arg::with_name("no-minimize").long("no-minimize")),
        )
        .subcommand(
            SubCommand::with_name("parse")
                .about("Parse files")
                .arg(
                    Arg::with_name("path")
                        .index(1)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("debug").long("debug").short("d"))
                .arg(Arg::with_name("debug-graph").long("debug-graph").short("D"))
                .arg(Arg::with_name("quiet").long("quiet").short("q"))
                .arg(Arg::with_name("time").long("time").short("t"))
                .arg(Arg::with_name("allow-cancellation").long("cancel"))
                .arg(Arg::with_name("timeout").long("timeout").takes_value(true))
                .arg(
                    Arg::with_name("edits")
                        .long("edit")
                        .short("edit")
                        .takes_value(true)
                        .multiple(true)
                        .number_of_values(1),
                ),
        )
        .subcommand(
            SubCommand::with_name("query")
                .about("Search files using a syntax tree query")
                .arg(Arg::with_name("query-path").index(1).required(true))
                .arg(
                    Arg::with_name("path")
                        .index(2)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("captures").long("captures").short("c")),
        )
        .subcommand(
            SubCommand::with_name("test")
                .about("Run a parser's tests")
                .arg(
                    Arg::with_name("filter")
                        .long("filter")
                        .short("f")
                        .takes_value(true),
                )
                .arg(Arg::with_name("debug").long("debug").short("d"))
                .arg(Arg::with_name("debug-graph").long("debug-graph").short("D")),
        )
        .subcommand(
            SubCommand::with_name("highlight")
                .about("Highlight a file")
                .arg(
                    Arg::with_name("path")
                        .index(1)
                        .multiple(true)
                        .required(true),
                )
                .arg(Arg::with_name("scope").long("scope").takes_value(true))
                .arg(Arg::with_name("html").long("html").short("h"))
                .arg(Arg::with_name("time").long("time").short("t"))
                .arg(Arg::with_name("q").short("q")),
        )
        .subcommand(
            SubCommand::with_name("build-wasm")
                .about("Compile a parser to WASM")
                .arg(
                    Arg::with_name("docker")
                        .long("docker")
                        .help("Run emscripten via docker even if it is installed locally"),
                )
                .arg(Arg::with_name("path").index(1).multiple(true)),
        )
        .subcommand(
            SubCommand::with_name("web-ui").about("Test a parser interactively in the browser"),
        )
        .subcommand(
            SubCommand::with_name("dump-languages")
                .about("Print info about all known language parsers"),
        )
        .get_matches();

    let home_dir = dirs::home_dir().expect("Failed to read home directory");
    let current_dir = env::current_dir().unwrap();
    let config = config::Config::load(&home_dir);
    let mut loader = loader::Loader::new(config.binary_directory.clone());

    if matches.subcommand_matches("init-config").is_some() {
        let config = config::Config::new(&home_dir);
        config.save(&home_dir)?;
    } else if let Some(matches) = matches.subcommand_matches("generate") {
        let grammar_path = matches.value_of("grammar-path");
        let report_symbol_name = matches.value_of("report-states-for-rule").or_else(|| {
            if matches.is_present("report-states") {
                Some("")
            } else {
                None
            }
        });
        if matches.is_present("log") {
            logger::init();
        }
        let prev_abi = matches.is_present("prev-abi");
        generate::generate_parser_in_directory(
            &current_dir,
            grammar_path,
            !prev_abi,
            report_symbol_name,
        )?;
    } else if let Some(matches) = matches.subcommand_matches("test") {
        let debug = matches.is_present("debug");
        let debug_graph = matches.is_present("debug-graph");
        let filter = matches.value_of("filter");
        let languages = loader.languages_at_path(&current_dir)?;
        let language = languages
            .first()
            .ok_or_else(|| "No language found".to_string())?;
        let test_dir = current_dir.join("test");

        // Run the corpus tests. Look for them at two paths: `test/corpus` and `corpus`.
        let mut test_corpus_dir = test_dir.join("corpus");
        if !test_corpus_dir.is_dir() {
            test_corpus_dir = current_dir.join("corpus");
        }
        if test_corpus_dir.is_dir() {
            test::run_tests_at_path(*language, &test_corpus_dir, debug, debug_graph, filter)?;
        }

        // Check that all of the queries are valid.
        test::check_queries_at_path(*language, &current_dir.join("queries"))?;

        // Run the syntax highlighting tests.
        let test_highlight_dir = test_dir.join("highlight");
        if test_highlight_dir.is_dir() {
            test_highlight::test_highlights(&loader, &test_highlight_dir)?;
        }
    } else if let Some(matches) = matches.subcommand_matches("parse") {
        let debug = matches.is_present("debug");
        let debug_graph = matches.is_present("debug-graph");
        let quiet = matches.is_present("quiet");
        let time = matches.is_present("time");
        let edits = matches
            .values_of("edits")
            .map_or(Vec::new(), |e| e.collect());
        let allow_cancellation = matches.is_present("allow-cancellation");
        let timeout = matches
            .value_of("timeout")
            .map_or(0, |t| u64::from_str_radix(t, 10).unwrap());
        let paths = collect_paths(matches.values_of("path").unwrap())?;
        let max_path_length = paths.iter().map(|p| p.chars().count()).max().unwrap();
        let mut has_error = false;
        loader.find_all_languages(&config.parser_directories)?;
        for path in paths {
            let path = Path::new(&path);
            let language =
                select_language(&mut loader, path, &current_dir, matches.value_of("scope"))?;
            has_error |= parse::parse_file_at_path(
                language,
                path,
                &edits,
                max_path_length,
                quiet,
                time,
                timeout,
                debug,
                debug_graph,
                allow_cancellation,
            )?;
        }
        if has_error {
            return Error::err(String::new());
        }
    } else if let Some(matches) = matches.subcommand_matches("query") {
        let ordered_captures = matches.values_of("captures").is_some();
        let paths = matches
            .values_of("path")
            .unwrap()
            .into_iter()
            .map(Path::new)
            .collect::<Vec<&Path>>();
        loader.find_all_languages(&config.parser_directories)?;
        let language = select_language(
            &mut loader,
            paths[0],
            &current_dir,
            matches.value_of("scope"),
        )?;
        let query_path = Path::new(matches.value_of("query-path").unwrap());
        query::query_files_at_paths(language, paths, query_path, ordered_captures)?;
    } else if let Some(matches) = matches.subcommand_matches("highlight") {
        loader.configure_highlights(&config.theme.highlight_names);
        loader.find_all_languages(&config.parser_directories)?;

        let time = matches.is_present("time");
        let paths = matches.values_of("path").unwrap().into_iter();
        let html_mode = matches.is_present("html");
        if html_mode {
            println!("{}", highlight::HTML_HEADER);
        }

        let language_config;
        if let Some(scope) = matches.value_of("scope") {
            language_config = loader.language_configuration_for_scope(scope)?;
            if language_config.is_none() {
                return Error::err(format!("Unknown scope '{}'", scope));
            }
        } else {
            language_config = None;
        }

        for path in paths {
            let path = Path::new(path);
            let (language, language_config) = match language_config {
                Some(v) => v,
                None => match loader.language_configuration_for_file_name(path)? {
                    Some(v) => v,
                    None => {
                        eprintln!("No language found for path {:?}", path);
                        continue;
                    }
                },
            };

            let source = fs::read(path)?;

            if let Some(highlight_config) = language_config.highlight_config(language)? {
                if html_mode {
                    highlight::html(&loader, &config.theme, &source, highlight_config, time)?;
                } else {
                    highlight::ansi(&loader, &config.theme, &source, highlight_config, time)?;
                }
            } else {
                return Error::err(format!("No syntax highlighting query found"));
            }
        }
    } else if let Some(matches) = matches.subcommand_matches("build-wasm") {
        let grammar_path = current_dir.join(matches.value_of("path").unwrap_or(""));
        wasm::compile_language_to_wasm(&grammar_path, matches.is_present("docker"))?;
    } else if matches.subcommand_matches("web-ui").is_some() {
        web_ui::serve(&current_dir);
    } else if matches.subcommand_matches("dump-languages").is_some() {
        loader.find_all_languages(&config.parser_directories)?;
        for (configuration, language_path) in loader.get_all_language_configurations() {
            println!(
                concat!(
                    "scope: {}\n",
                    "parser: {:?}\n",
                    "highlights: {:?}\n",
                    "file_types: {:?}\n",
                    "content_regex: {:?}\n",
                    "injection_regex: {:?}\n",
                ),
                configuration.scope.as_ref().unwrap_or(&String::new()),
                language_path,
                configuration.highlights_filenames,
                configuration.file_types,
                configuration.content_regex,
                configuration.injection_regex,
            );
        }
    }

    Ok(())
}

fn collect_paths<'a>(paths: impl Iterator<Item = &'a str>) -> error::Result<Vec<String>> {
    let mut result = Vec::new();

    let mut incorporate_path = |path: &str, positive| {
        if positive {
            result.push(path.to_string());
        } else {
            if let Some(index) = result.iter().position(|p| p == path) {
                result.remove(index);
            }
        }
    };

    for mut path in paths {
        let mut positive = true;
        if path.starts_with("!") {
            positive = false;
            path = path.trim_start_matches("!");
        }

        if Path::new(path).exists() {
            incorporate_path(path, positive);
        } else {
            for path in glob(path)? {
                if let Some(path) = path?.to_str() {
                    incorporate_path(path, positive);
                }
            }
        }
    }
    Ok(result)
}

fn select_language(
    loader: &mut loader::Loader,
    path: &Path,
    current_dir: &Path,
    scope: Option<&str>,
) -> Result<Language, Error> {
    if let Some(scope) = scope {
        if let Some(config) =
            loader
                .language_configuration_for_scope(scope)
                .map_err(Error::wrap(|| {
                    format!("Failed to load language for scope '{}'", scope)
                }))?
        {
            Ok(config.0)
        } else {
            return Error::err(format!("Unknown scope '{}'", scope));
        }
    } else if let Some((lang, _)) =
        loader
            .language_configuration_for_file_name(path)
            .map_err(Error::wrap(|| {
                format!(
                    "Failed to load language for file name {:?}",
                    path.file_name().unwrap()
                )
            }))?
    {
        Ok(lang)
    } else if let Some(lang) = loader
        .languages_at_path(&current_dir)
        .map_err(Error::wrap(|| {
            "Failed to load language in current directory"
        }))?
        .first()
        .cloned()
    {
        Ok(lang)
    } else {
        eprintln!("No language found");
        Error::err("No language found".to_string())
    }
}
<|endoftext|>