<commit_before>use std::collections::HashSet;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::PackageIdSpec;
use core::source::Source;
use ops;
use sources::PathSource;
use util::{CargoResult, human};

pub struct DocOptions<'a, 'b: 'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a, 'b>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let mut source = try!(PathSource::for_path(manifest_path.parent().unwrap(),
                                               options.compile_opts.config));
    try!(source.update());
    let package = try!(source.root_package());

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_none() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.name()));
            } else {
                assert!(bin_names.insert(target.name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                return Err(human("Cannot document a package where a library \
                                  and a binary have the same name. Consider \
                                  renaming one or marking the target as \
                                  `doc = false`"))
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = match options.compile_opts.spec {
            Some(spec) => try!(PackageIdSpec::parse(spec)).name().to_string(),
            None => {
                match lib_names.iter().nth(0) {
                    Some(s) => s.to_string(),
                    None => return Ok(())
                }
            }
        };

        let path = package.absolute_target_dir().join("doc").join(&name)
                                                    .join("index.html");
        if fs::metadata(&path).is_ok() {
            open_docs(&path);
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) {
    // trying xdg-open
    match Command::new("xdg-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying gnome-open
    match Command::new("gnome-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying kde-open
    match Command::new("kde-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) {
    match Command::new("start").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) {
    match Command::new("open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}
<commit_msg>`cargo doc --open` should work for binary-only packages too<commit_after>use std::collections::HashSet;
use std::fs;
use std::path::Path;
use std::process::Command;

use core::PackageIdSpec;
use core::source::Source;
use ops;
use sources::PathSource;
use util::{CargoResult, human};

pub struct DocOptions<'a, 'b: 'a> {
    pub open_result: bool,
    pub compile_opts: ops::CompileOptions<'a, 'b>,
}

pub fn doc(manifest_path: &Path,
           options: &DocOptions) -> CargoResult<()> {
    let mut source = try!(PathSource::for_path(manifest_path.parent().unwrap(),
                                               options.compile_opts.config));
    try!(source.update());
    let package = try!(source.root_package());

    let mut lib_names = HashSet::new();
    let mut bin_names = HashSet::new();
    if options.compile_opts.spec.is_none() {
        for target in package.targets().iter().filter(|t| t.documented()) {
            if target.is_lib() {
                assert!(lib_names.insert(target.name()));
            } else {
                assert!(bin_names.insert(target.name()));
            }
        }
        for bin in bin_names.iter() {
            if lib_names.contains(bin) {
                return Err(human("Cannot document a package where a library \
                                  and a binary have the same name. Consider \
                                  renaming one or marking the target as \
                                  `doc = false`"))
            }
        }
    }

    try!(ops::compile(manifest_path, &options.compile_opts));

    if options.open_result {
        let name = match options.compile_opts.spec {
            Some(spec) => try!(PackageIdSpec::parse(spec)).name().to_string(),
            None => {
                match lib_names.iter().chain(bin_names.iter()).nth(0) {
                    Some(s) => s.to_string(),
                    None => return Ok(())
                }
            }
        };

        let path = package.absolute_target_dir().join("doc").join(&name)
                                                    .join("index.html");
        if fs::metadata(&path).is_ok() {
            open_docs(&path);
        }
    }

    Ok(())
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn open_docs(path: &Path) {
    // trying xdg-open
    match Command::new("xdg-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying gnome-open
    match Command::new("gnome-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };

    // trying kde-open
    match Command::new("kde-open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "windows")]
fn open_docs(path: &Path) {
    match Command::new("start").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}

#[cfg(target_os = "macos")]
fn open_docs(path: &Path) {
    match Command::new("open").arg(path).status() {
        Ok(_) => return,
        Err(_) => ()
    };
}
<|endoftext|>


<commit_before>//! A framework that can express both [gen-kill] and generic dataflow problems.
//!
//! There is another interface for dataflow in the compiler in `librustc_mir/dataflow/mod.rs`. The
//! interface in this module will eventually [replace that one][design-meeting].
//!
//! To actually use this framework, you must implement either the `Analysis` or the
//! `GenKillAnalysis` trait. If your transfer function can be expressed with only gen/kill
//! operations, prefer `GenKillAnalysis` as it will perform better. Create an `Engine` using the
//! appropriate constructor and call `iterate_to_fixpoint`. You can use a `ResultsCursor` to
//! inspect the fixpoint solution to your dataflow problem.
//!
//! ```ignore(cross-crate-imports)
//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, did: DefId) {
//!     let analysis = MyAnalysis::new();
//!
//!     // If `MyAnalysis` implements `GenKillAnalysis`.
//!     let results = Engine::new_gen_kill(tcx, body, did, analysis).iterate_to_fixpoint();
//!
//!     // If `MyAnalysis` implements `Analysis`.
//!     // let results = Engine::new_generic(tcx, body, did, analysis).iterate_to_fixpoint();
//!
//!     let mut cursor = ResultsCursor::new(body, results);
//!
//!     for (_, statement_index) in body.block_data[START_BLOCK].statements.iter_enumerated() {
//!         cursor.seek_after(Location { block: START_BLOCK, statement_index });
//!         let state = cursor.get();
//!         println!("{:?}", state);
//!     }
//! }
//! ```
//!
//! [gen-kill]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems
//! [design-meeting]https://github.com/rust-lang/compiler-team/issues/202

use std::io;

use rustc::mir::{self, BasicBlock, Location};
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_index::vec::{Idx, IndexVec};

use crate::dataflow::BottomValue;

mod cursor;
mod engine;
mod graphviz;

pub use self::cursor::{ResultsCursor, ResultsRefCursor};
pub use self::engine::Engine;

/// A dataflow analysis that has converged to fixpoint.
pub struct Results<'tcx, A>
where
    A: Analysis<'tcx>,
{
    pub analysis: A,
    entry_sets: IndexVec<BasicBlock, BitSet<A::Idx>>,
}

impl<A> Results<'tcx, A>
where
    A: Analysis<'tcx>,
{
    pub fn into_cursor(self, body: &'mir mir::Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
        ResultsCursor::new(body, self)
    }

    pub fn on_block_entry(&self, block: BasicBlock) -> &BitSet<A::Idx> {
        &self.entry_sets[block]
    }
}

/// Define the domain of a dataflow problem.
///
/// This trait specifies the lattice on which this analysis operates. For now, this must be a
/// powerset of values of type `Idx`. The elements of this lattice are represented with a `BitSet`
/// and referred to as the state vector.
///
/// This trait also defines the initial value for the dataflow state upon entry to the
/// `START_BLOCK`, as well as some names used to refer to this analysis when debugging.
pub trait AnalysisDomain<'tcx>: BottomValue {
    /// The type of the elements in the state vector.
    type Idx: Idx;

    /// A descriptive name for this analysis. Used only for debugging.
    ///
    /// This name should be brief and contain no spaces, periods or other characters that are not
    /// suitable as part of a filename.
    const NAME: &'static str;

    /// The size of the state vector.
    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize;

    /// Mutates the entry set of the `START_BLOCK` to contain the initial state for dataflow
    /// analysis.
    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>);

    /// Prints an element in the state vector for debugging.
    fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> {
        write!(w, "{:?}", idx)
    }
}

/// A dataflow problem with an arbitrarily complex transfer function.
pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
    /// Updates the current dataflow state with the effect of evaluating a statement.
    fn apply_statement_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    );

    /// Updates the current dataflow state with an effect that occurs immediately *before* the
    /// given statement.
    ///
    /// This method is useful if the consumer of the results of this analysis needs only to observe
    /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
    /// analyses should not implement this without implementing `apply_statement_effect`.
    fn apply_before_statement_effect(
        &self,
        _state: &mut BitSet<Self::Idx>,
        _statement: &mir::Statement<'tcx>,
        _location: Location,
    ) {
    }

    /// Updates the current dataflow state with the effect of evaluating a terminator.
    ///
    /// The effect of a successful return from a `Call` terminator should **not** be accounted for
    /// in this function. That should go in `apply_call_return_effect`. For example, in the
    /// `InitializedPlaces` analyses, the return place for a function call is not marked as
    /// initialized here.
    fn apply_terminator_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    );

    /// Updates the current dataflow state with an effect that occurs immediately *before* the
    /// given terminator.
    ///
    /// This method is useful if the consumer of the results of this analysis needs only to observe
    /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
    /// analyses should not implement this without implementing `apply_terminator_effect`.
    fn apply_before_terminator_effect(
        &self,
        _state: &mut BitSet<Self::Idx>,
        _terminator: &mir::Terminator<'tcx>,
        _location: Location,
    ) {
    }

    /// Updates the current dataflow state with the effect of a successful return from a `Call`
    /// terminator.
    ///
    /// This is separate from `apply_terminator_effect` to properly track state across unwind
    /// edges.
    fn apply_call_return_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    );
}

/// A gen/kill dataflow problem.
///
/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only
/// allow modification of the dataflow state via "gen" and "kill" operations. By defining transfer
/// functions for each statement in this way, the transfer function for an entire basic block can
/// be computed efficiently.
///
/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis`.
pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
    /// See `Analysis::apply_statement_effect`.
    fn statement_effect(
        &self,
        trans: &mut impl GenKill<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    );

    /// See `Analysis::apply_before_statement_effect`.
    fn before_statement_effect(
        &self,
        _trans: &mut impl GenKill<Self::Idx>,
        _statement: &mir::Statement<'tcx>,
        _location: Location,
    ) {
    }

    /// See `Analysis::apply_terminator_effect`.
    fn terminator_effect(
        &self,
        trans: &mut impl GenKill<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    );

    /// See `Analysis::apply_before_terminator_effect`.
    fn before_terminator_effect(
        &self,
        _trans: &mut impl GenKill<Self::Idx>,
        _terminator: &mir::Terminator<'tcx>,
        _location: Location,
    ) {
    }

    /// See `Analysis::apply_call_return_effect`.
    fn call_return_effect(
        &self,
        trans: &mut impl GenKill<Self::Idx>,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    );
}

impl<A> Analysis<'tcx> for A
where
    A: GenKillAnalysis<'tcx>,
{
    fn apply_statement_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        self.statement_effect(state, statement, location);
    }

    fn apply_before_statement_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        self.before_statement_effect(state, statement, location);
    }

    fn apply_terminator_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    ) {
        self.terminator_effect(state, terminator, location);
    }

    fn apply_before_terminator_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    ) {
        self.before_terminator_effect(state, terminator, location);
    }

    fn apply_call_return_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    ) {
        self.call_return_effect(state, block, func, args, return_place);
    }
}

/// The legal operations for a transfer function in a gen/kill problem.
pub trait GenKill<T>: Sized {
    /// Inserts `elem` into the `gen` set, removing it the `kill` set if present.
    fn gen(&mut self, elem: T);

    /// Inserts `elem` into the `kill` set, removing it the `gen` set if present.
    fn kill(&mut self, elem: T);

    /// Inserts the given elements into the `gen` set, removing them from the `kill` set if present.
    fn gen_all(&mut self, elems: impl IntoIterator<Item = T>) {
        for elem in elems {
            self.gen(elem);
        }
    }

    /// Inserts the given elements into the `kill` set, removing them from the `gen` set if present.
    fn kill_all(&mut self, elems: impl IntoIterator<Item = T>) {
        for elem in elems {
            self.kill(elem);
        }
    }
}

/// Stores a transfer function for a gen/kill problem.
#[derive(Clone)]
pub struct GenKillSet<T: Idx> {
    gen: HybridBitSet<T>,
    kill: HybridBitSet<T>,
}

impl<T: Idx> GenKillSet<T> {
    /// Creates a new transfer function that will leave the dataflow state unchanged.
    pub fn identity(universe: usize) -> Self {
        GenKillSet {
            gen: HybridBitSet::new_empty(universe),
            kill: HybridBitSet::new_empty(universe),
        }
    }

    /// Applies this transfer function to the given bitset.
    pub fn apply(&self, state: &mut BitSet<T>) {
        state.union(&self.gen);
        state.subtract(&self.kill);
    }
}

impl<T: Idx> GenKill<T> for GenKillSet<T> {
    fn gen(&mut self, elem: T) {
        self.gen.insert(elem);
        self.kill.remove(elem);
    }

    fn kill(&mut self, elem: T) {
        self.kill.insert(elem);
        self.gen.remove(elem);
    }
}

impl<T: Idx> GenKill<T> for BitSet<T> {
    fn gen(&mut self, elem: T) {
        self.insert(elem);
    }

    fn kill(&mut self, elem: T) {
        self.remove(elem);
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Improve docs for `GenKill` and `GenKillSet`<commit_after>//! A framework that can express both [gen-kill] and generic dataflow problems.
//!
//! There is another interface for dataflow in the compiler in `librustc_mir/dataflow/mod.rs`. The
//! interface in this module will eventually [replace that one][design-meeting].
//!
//! To actually use this framework, you must implement either the `Analysis` or the
//! `GenKillAnalysis` trait. If your transfer function can be expressed with only gen/kill
//! operations, prefer `GenKillAnalysis` as it will perform better. Create an `Engine` using the
//! appropriate constructor and call `iterate_to_fixpoint`. You can use a `ResultsCursor` to
//! inspect the fixpoint solution to your dataflow problem.
//!
//! ```ignore(cross-crate-imports)
//! fn do_my_analysis(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, did: DefId) {
//!     let analysis = MyAnalysis::new();
//!
//!     // If `MyAnalysis` implements `GenKillAnalysis`.
//!     let results = Engine::new_gen_kill(tcx, body, did, analysis).iterate_to_fixpoint();
//!
//!     // If `MyAnalysis` implements `Analysis`.
//!     // let results = Engine::new_generic(tcx, body, did, analysis).iterate_to_fixpoint();
//!
//!     let mut cursor = ResultsCursor::new(body, results);
//!
//!     for (_, statement_index) in body.block_data[START_BLOCK].statements.iter_enumerated() {
//!         cursor.seek_after(Location { block: START_BLOCK, statement_index });
//!         let state = cursor.get();
//!         println!("{:?}", state);
//!     }
//! }
//! ```
//!
//! [gen-kill]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems
//! [design-meeting]https://github.com/rust-lang/compiler-team/issues/202

use std::io;

use rustc::mir::{self, BasicBlock, Location};
use rustc_index::bit_set::{BitSet, HybridBitSet};
use rustc_index::vec::{Idx, IndexVec};

use crate::dataflow::BottomValue;

mod cursor;
mod engine;
mod graphviz;

pub use self::cursor::{ResultsCursor, ResultsRefCursor};
pub use self::engine::Engine;

/// A dataflow analysis that has converged to fixpoint.
pub struct Results<'tcx, A>
where
    A: Analysis<'tcx>,
{
    pub analysis: A,
    entry_sets: IndexVec<BasicBlock, BitSet<A::Idx>>,
}

impl<A> Results<'tcx, A>
where
    A: Analysis<'tcx>,
{
    pub fn into_cursor(self, body: &'mir mir::Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> {
        ResultsCursor::new(body, self)
    }

    pub fn on_block_entry(&self, block: BasicBlock) -> &BitSet<A::Idx> {
        &self.entry_sets[block]
    }
}

/// Define the domain of a dataflow problem.
///
/// This trait specifies the lattice on which this analysis operates. For now, this must be a
/// powerset of values of type `Idx`. The elements of this lattice are represented with a `BitSet`
/// and referred to as the state vector.
///
/// This trait also defines the initial value for the dataflow state upon entry to the
/// `START_BLOCK`, as well as some names used to refer to this analysis when debugging.
pub trait AnalysisDomain<'tcx>: BottomValue {
    /// The type of the elements in the state vector.
    type Idx: Idx;

    /// A descriptive name for this analysis. Used only for debugging.
    ///
    /// This name should be brief and contain no spaces, periods or other characters that are not
    /// suitable as part of a filename.
    const NAME: &'static str;

    /// The size of the state vector.
    fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize;

    /// Mutates the entry set of the `START_BLOCK` to contain the initial state for dataflow
    /// analysis.
    fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut BitSet<Self::Idx>);

    /// Prints an element in the state vector for debugging.
    fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> {
        write!(w, "{:?}", idx)
    }
}

/// A dataflow problem with an arbitrarily complex transfer function.
pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
    /// Updates the current dataflow state with the effect of evaluating a statement.
    fn apply_statement_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    );

    /// Updates the current dataflow state with an effect that occurs immediately *before* the
    /// given statement.
    ///
    /// This method is useful if the consumer of the results of this analysis needs only to observe
    /// *part* of the effect of a statement (e.g. for two-phase borrows). As a general rule,
    /// analyses should not implement this without implementing `apply_statement_effect`.
    fn apply_before_statement_effect(
        &self,
        _state: &mut BitSet<Self::Idx>,
        _statement: &mir::Statement<'tcx>,
        _location: Location,
    ) {
    }

    /// Updates the current dataflow state with the effect of evaluating a terminator.
    ///
    /// The effect of a successful return from a `Call` terminator should **not** be accounted for
    /// in this function. That should go in `apply_call_return_effect`. For example, in the
    /// `InitializedPlaces` analyses, the return place for a function call is not marked as
    /// initialized here.
    fn apply_terminator_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    );

    /// Updates the current dataflow state with an effect that occurs immediately *before* the
    /// given terminator.
    ///
    /// This method is useful if the consumer of the results of this analysis needs only to observe
    /// *part* of the effect of a terminator (e.g. for two-phase borrows). As a general rule,
    /// analyses should not implement this without implementing `apply_terminator_effect`.
    fn apply_before_terminator_effect(
        &self,
        _state: &mut BitSet<Self::Idx>,
        _terminator: &mir::Terminator<'tcx>,
        _location: Location,
    ) {
    }

    /// Updates the current dataflow state with the effect of a successful return from a `Call`
    /// terminator.
    ///
    /// This is separate from `apply_terminator_effect` to properly track state across unwind
    /// edges.
    fn apply_call_return_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    );
}

/// A gen/kill dataflow problem.
///
/// Each method in this trait has a corresponding one in `Analysis`. However, these methods only
/// allow modification of the dataflow state via "gen" and "kill" operations. By defining transfer
/// functions for each statement in this way, the transfer function for an entire basic block can
/// be computed efficiently.
///
/// `Analysis` is automatically implemented for all implementers of `GenKillAnalysis`.
pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
    /// See `Analysis::apply_statement_effect`.
    fn statement_effect(
        &self,
        trans: &mut impl GenKill<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    );

    /// See `Analysis::apply_before_statement_effect`.
    fn before_statement_effect(
        &self,
        _trans: &mut impl GenKill<Self::Idx>,
        _statement: &mir::Statement<'tcx>,
        _location: Location,
    ) {
    }

    /// See `Analysis::apply_terminator_effect`.
    fn terminator_effect(
        &self,
        trans: &mut impl GenKill<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    );

    /// See `Analysis::apply_before_terminator_effect`.
    fn before_terminator_effect(
        &self,
        _trans: &mut impl GenKill<Self::Idx>,
        _terminator: &mir::Terminator<'tcx>,
        _location: Location,
    ) {
    }

    /// See `Analysis::apply_call_return_effect`.
    fn call_return_effect(
        &self,
        trans: &mut impl GenKill<Self::Idx>,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    );
}

impl<A> Analysis<'tcx> for A
where
    A: GenKillAnalysis<'tcx>,
{
    fn apply_statement_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        self.statement_effect(state, statement, location);
    }

    fn apply_before_statement_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        self.before_statement_effect(state, statement, location);
    }

    fn apply_terminator_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    ) {
        self.terminator_effect(state, terminator, location);
    }

    fn apply_before_terminator_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        terminator: &mir::Terminator<'tcx>,
        location: Location,
    ) {
        self.before_terminator_effect(state, terminator, location);
    }

    fn apply_call_return_effect(
        &self,
        state: &mut BitSet<Self::Idx>,
        block: BasicBlock,
        func: &mir::Operand<'tcx>,
        args: &[mir::Operand<'tcx>],
        return_place: &mir::Place<'tcx>,
    ) {
        self.call_return_effect(state, block, func, args, return_place);
    }
}

/// The legal operations for a transfer function in a gen/kill problem.
pub trait GenKill<T> {
    /// Inserts `elem` into the state vector.
    fn gen(&mut self, elem: T);

    /// Removes `elem` from the state vector.
    fn kill(&mut self, elem: T);

    fn gen_all(&mut self, elems: impl IntoIterator<Item = T>) {
        for elem in elems {
            self.gen(elem);
        }
    }

    fn kill_all(&mut self, elems: impl IntoIterator<Item = T>) {
        for elem in elems {
            self.kill(elem);
        }
    }
}

/// Stores a transfer function for a gen/kill problem.
///
/// Calling `gen`/`kill` on a `GenKillSet` will "build up" a transfer function so that it can be
/// applied to a state vector efficiently. When there are multiple calls to `gen` and/or `kill` for
/// the same element, the most recent one takes precedence.
#[derive(Clone)]
pub struct GenKillSet<T: Idx> {
    gen: HybridBitSet<T>,
    kill: HybridBitSet<T>,
}

impl<T: Idx> GenKillSet<T> {
    /// Creates a new transfer function that will leave the dataflow state unchanged.
    pub fn identity(universe: usize) -> Self {
        GenKillSet {
            gen: HybridBitSet::new_empty(universe),
            kill: HybridBitSet::new_empty(universe),
        }
    }

    /// Applies this transfer function to the given state vector.
    pub fn apply(&self, state: &mut BitSet<T>) {
        state.union(&self.gen);
        state.subtract(&self.kill);
    }
}

impl<T: Idx> GenKill<T> for GenKillSet<T> {
    fn gen(&mut self, elem: T) {
        self.gen.insert(elem);
        self.kill.remove(elem);
    }

    fn kill(&mut self, elem: T) {
        self.kill.insert(elem);
        self.gen.remove(elem);
    }
}

impl<T: Idx> GenKill<T> for BitSet<T> {
    fn gen(&mut self, elem: T) {
        self.insert(elem);
    }

    fn kill(&mut self, elem: T) {
        self.remove(elem);
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>use super::loader::Loader;
use super::util;
use crate::error::{Error, Result};
use std::io::{self, Write};
use std::path::Path;
use std::{fs, str};
use tree_sitter_tags::TagsContext;

pub fn generate_tags(loader: &Loader, scope: Option<&str>, paths: &[String]) -> Result<()> {
    let mut lang = None;
    if let Some(scope) = scope {
        lang = loader.language_configuration_for_scope(scope)?;
        if lang.is_none() {
            return Error::err(format!("Unknown scope '{}'", scope));
        }
    }

    let mut context = TagsContext::new();
    let cancellation_flag = util::cancel_on_stdin();
    let stdout = io::stdout();
    let mut stdout = stdout.lock();

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

        if let Some(tags_config) = language_config.tags_config(language)? {
            let ident = if paths.len() > 1 {
                let path_str = format!("{:?}", path);
                writeln!(&mut stdout, "{}", &path_str[1..path_str.len() - 1])?;
                "\t"
            } else {
                ""
            };

            let source = fs::read(path)?;
            for tag in context.generate_tags(tags_config, &source, Some(&cancellation_flag))? {
                let tag = tag?;
                write!(
                    &mut stdout,
                    "{}{:<10}\t | {:<8}\t{} {} - {} `{}`",
                    ident,
                    str::from_utf8(&source[tag.name_range]).unwrap_or(""),
                    tag.syntax_type,
                    if tag.is_definition { "def" } else { "ref" },
                    tag.span.start,
                    tag.span.end,
                    str::from_utf8(&source[tag.line_range]).unwrap_or(""),
                )?;
                if let Some(docs) = tag.docs {
                    if docs.len() > 120 {
                        write!(&mut stdout, "\t{:?}...", &docs[0..120])?;
                    } else {
                        write!(&mut stdout, "\t{:?}", &docs)?;
                    }
                }
                writeln!(&mut stdout, "")?;
            }
        } else {
            eprintln!("No tags config found for path {:?}", path);
        }
    }

    Ok(())
}
<commit_msg>Fix up CLI, use new syntax_type_name<commit_after>use super::loader::Loader;
use super::util;
use crate::error::{Error, Result};
use std::io::{self, Write};
use std::path::Path;
use std::{fs, str};
use tree_sitter_tags::TagsContext;

pub fn generate_tags(loader: &Loader, scope: Option<&str>, paths: &[String]) -> Result<()> {
    let mut lang = None;
    if let Some(scope) = scope {
        lang = loader.language_configuration_for_scope(scope)?;
        if lang.is_none() {
            return Error::err(format!("Unknown scope '{}'", scope));
        }
    }

    let mut context = TagsContext::new();
    let cancellation_flag = util::cancel_on_stdin();
    let stdout = io::stdout();
    let mut stdout = stdout.lock();

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

        if let Some(tags_config) = language_config.tags_config(language)? {
            let ident = if paths.len() > 1 {
                let path_str = format!("{:?}", path);
                writeln!(&mut stdout, "{}", &path_str[1..path_str.len() - 1])?;
                "\t"
            } else {
                ""
            };

            let source = fs::read(path)?;
            for tag in context.generate_tags(tags_config, &source, Some(&cancellation_flag))? {
                let tag = tag?;
                write!(
                    &mut stdout,
                    "{}{:<10}\t | {:<8}\t{} {} - {} `{}`",
                    ident,
                    str::from_utf8(&source[tag.name_range]).unwrap_or(""),
                    &tags_config.syntax_type_name(tag.syntax_type_id),
                    if tag.is_definition { "def" } else { "ref" },
                    tag.span.start,
                    tag.span.end,
                    str::from_utf8(&source[tag.line_range]).unwrap_or(""),
                )?;
                if let Some(docs) = tag.docs {
                    if docs.len() > 120 {
                        write!(&mut stdout, "\t{:?}...", &docs[0..120])?;
                    } else {
                        write!(&mut stdout, "\t{:?}", &docs)?;
                    }
                }
                writeln!(&mut stdout, "")?;
            }
        } else {
            eprintln!("No tags config found for path {:?}", path);
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>/// Macro that allows you to quickly define a handlebars helper by passing a
/// name and a closure.
///
/// # Examples
///
/// ```rust
/// #[macro_use] extern crate handlebars;
/// #[macro_use] extern crate serde_json;
///
/// handlebars_helper!(is_above_10: |x: u64| x > 10);
///
/// # fn main() {
/// #
/// let mut handlebars = handlebars::Handlebars::new();
/// handlebars.register_helper("is-above-10", Box::new(is_above_10));
///
/// let result = handlebars
///     .render_template("{{#if (is-above-10 12)}}great!{{else}}okay{{/if}}", &json!({}))
///     .unwrap();
///  assert_eq!(&result, "great!");
/// # }
/// ```
#[macro_export]
macro_rules! handlebars_helper {
    ($struct_name:ident: |$($name:ident: $tpe:tt),*| $body:expr ) => {
        #[allow(non_camel_case_types)]
        pub struct $struct_name;

        impl $crate::HelperDef for $struct_name {
            #[allow(unused_assignments)]
            fn call_inner<'reg: 'rc, 'rc>(
                &self,
                h: &$crate::Helper<'reg, 'rc>,
                _: &'reg $crate::Handlebars,
                _: &'rc $crate::Context,
                _: &mut $crate::RenderContext<'reg>,
            ) -> Result<Option<$crate::ScopedJson<'reg, 'rc>>, $crate::RenderError> {
                let mut param_idx = 0;

                $(
                    let $name = h.param(param_idx)
                        .map(|x| x.value())
                        .ok_or_else(|| $crate::RenderError::new(&format!(
                            "`{}` helper: Couldn't read parameter {}",
                            stringify!($fn_name), stringify!($name),
                        )))
                        .and_then(|x|
                                  handlebars_helper!(@as_json_value x, $tpe)
                                  .ok_or_else(|| $crate::RenderError::new(&format!(
                                      "`{}` helper: Couldn't convert parameter {} to type `{}`. \
                                       It's {:?} as JSON. Got these params: {:?}",
                                      stringify!($fn_name), stringify!($name), stringify!($tpe),
                                      x, h.params(),
                                  )))
                        )?;
                    param_idx += 1;
                )*

                let result = $body;
                Ok(Some($crate::ScopedJson::Derived($crate::JsonValue::from(result))))
            }
        }
    };

    (@as_json_value $x:ident, object) => { $x.as_object() };
    (@as_json_value $x:ident, array) => { $x.as_array() };
    (@as_json_value $x:ident, str) => { $x.as_str() };
    (@as_json_value $x:ident, i64) => { $x.as_i64() };
    (@as_json_value $x:ident, u64) => { $x.as_u64() };
    (@as_json_value $x:ident, f64) => { $x.as_f64() };
    (@as_json_value $x:ident, bool) => { $x.as_bool() };
    (@as_json_value $x:ident, null) => { $x.as_null() };
}

/// This macro is defined if the `logging` feature is set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging"))]
#[macro_export]
macro_rules! debug {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging"))]
#[macro_export]
macro_rules! error {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging"))]
#[macro_export]
macro_rules! info {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging"))]
#[macro_export]
macro_rules! log {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging"))]
#[macro_export]
macro_rules! trace {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging"))]
#[macro_export]
macro_rules! warn {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

<commit_msg>fixup! Add compiletime feature to disable logging<commit_after>/// Macro that allows you to quickly define a handlebars helper by passing a
/// name and a closure.
///
/// # Examples
///
/// ```rust
/// #[macro_use] extern crate handlebars;
/// #[macro_use] extern crate serde_json;
///
/// handlebars_helper!(is_above_10: |x: u64| x > 10);
///
/// # fn main() {
/// #
/// let mut handlebars = handlebars::Handlebars::new();
/// handlebars.register_helper("is-above-10", Box::new(is_above_10));
///
/// let result = handlebars
///     .render_template("{{#if (is-above-10 12)}}great!{{else}}okay{{/if}}", &json!({}))
///     .unwrap();
///  assert_eq!(&result, "great!");
/// # }
/// ```
#[macro_export]
macro_rules! handlebars_helper {
    ($struct_name:ident: |$($name:ident: $tpe:tt),*| $body:expr ) => {
        #[allow(non_camel_case_types)]
        pub struct $struct_name;

        impl $crate::HelperDef for $struct_name {
            #[allow(unused_assignments)]
            fn call_inner<'reg: 'rc, 'rc>(
                &self,
                h: &$crate::Helper<'reg, 'rc>,
                _: &'reg $crate::Handlebars,
                _: &'rc $crate::Context,
                _: &mut $crate::RenderContext<'reg>,
            ) -> Result<Option<$crate::ScopedJson<'reg, 'rc>>, $crate::RenderError> {
                let mut param_idx = 0;

                $(
                    let $name = h.param(param_idx)
                        .map(|x| x.value())
                        .ok_or_else(|| $crate::RenderError::new(&format!(
                            "`{}` helper: Couldn't read parameter {}",
                            stringify!($fn_name), stringify!($name),
                        )))
                        .and_then(|x|
                                  handlebars_helper!(@as_json_value x, $tpe)
                                  .ok_or_else(|| $crate::RenderError::new(&format!(
                                      "`{}` helper: Couldn't convert parameter {} to type `{}`. \
                                       It's {:?} as JSON. Got these params: {:?}",
                                      stringify!($fn_name), stringify!($name), stringify!($tpe),
                                      x, h.params(),
                                  )))
                        )?;
                    param_idx += 1;
                )*

                let result = $body;
                Ok(Some($crate::ScopedJson::Derived($crate::JsonValue::from(result))))
            }
        }
    };

    (@as_json_value $x:ident, object) => { $x.as_object() };
    (@as_json_value $x:ident, array) => { $x.as_array() };
    (@as_json_value $x:ident, str) => { $x.as_str() };
    (@as_json_value $x:ident, i64) => { $x.as_i64() };
    (@as_json_value $x:ident, u64) => { $x.as_u64() };
    (@as_json_value $x:ident, f64) => { $x.as_f64() };
    (@as_json_value $x:ident, bool) => { $x.as_bool() };
    (@as_json_value $x:ident, null) => { $x.as_null() };
}

/// This macro is defined if the `logging` feature is set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging")]
#[macro_export]
macro_rules! debug {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging")]
#[macro_export]
macro_rules! error {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging")]
#[macro_export]
macro_rules! info {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging")]
#[macro_export]
macro_rules! log {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging")]
#[macro_export]
macro_rules! trace {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

/// This macro is defined if the `logging` feature is not set.
///
/// It ignores all logging calls inside the library.
#[cfg(feature = "logging")]
#[macro_export]
macro_rules! warn {
    (target: $target:expr, $($arg:tt)*) => { };
    ($($arg:tt)*) => { };
}

<|endoftext|>


<commit_before>use super::content::*;
use super::Object::*;
use super::{Dictionary, Document, Object, Stream};

pub fn form(boundingbox: Vec<f64>, matrix: Vec<f64>, content: Vec<u8>) -> Stream {
	let mut dict = Dictionary::new();
	dict.set("Type", Name(b"XObject".to_vec()));
	dict.set("Subtype", Name(b"Form".to_vec()));
	dict.set("BBox", Array(boundingbox.into_iter().map(Real).collect()));
	dict.set("Matrix", Array(matrix.into_iter().map(Real).collect()));
	return Stream::new(dict, content);
}

impl Document {
	pub fn insert_form_object(&mut self, page_number: u32, form_obj: Stream) {
		let pages = self.get_pages();
		let page_id = *pages.get(&page_number).expect(&format!("Page {} not exist.", page_number));

		let form_id = self.add_object(form_obj);
		let form_name = format!("M{}", form_id.0);

		let mut content = self.get_and_decode_page_content(page_id);
		// content.operations.push(Operation::new("q", vec![]));
		content.operations.push(Operation::new("Do", vec![Name(form_name.as_bytes().to_vec())]));
		// content.operations.push(Operation::new("Q", vec![]));
		let modified_contnet = content.encode().unwrap();
		self.change_page_content(page_id, modified_contnet);
		self.add_xobject(page_id, form_name, form_id);
	}
}
<commit_msg>Compress created Form xobject<commit_after>use super::content::*;
use super::Object::*;
use super::{Dictionary, Document, Object, Stream};

pub fn form(boundingbox: Vec<f64>, matrix: Vec<f64>, content: Vec<u8>) -> Stream {
	let mut dict = Dictionary::new();
	dict.set("Type", Name(b"XObject".to_vec()));
	dict.set("Subtype", Name(b"Form".to_vec()));
	dict.set("BBox", Array(boundingbox.into_iter().map(Real).collect()));
	dict.set("Matrix", Array(matrix.into_iter().map(Real).collect()));
	let mut xobject = Stream::new(dict, content);
	xobject.compress();
	xobject
}

impl Document {
	pub fn insert_form_object(&mut self, page_number: u32, form_obj: Stream) {
		let pages = self.get_pages();
		let page_id = *pages.get(&page_number).expect(&format!("Page {} not exist.", page_number));

		let form_id = self.add_object(form_obj);
		let form_name = format!("X{}", form_id.0);

		let mut content = self.get_and_decode_page_content(page_id);
		content.operations.insert(0, Operation::new("q", vec![]));
		content.operations.push(Operation::new("Q", vec![]));
		// content.operations.push(Operation::new("q", vec![]));
		content.operations.push(Operation::new("Do", vec![Name(form_name.as_bytes().to_vec())]));
		// content.operations.push(Operation::new("Q", vec![]));
		let modified_contnet = content.encode().unwrap();
		self.change_page_content(page_id, modified_contnet);
		self.add_xobject(page_id, form_name, form_id);
	}
}
<|endoftext|>


<commit_before>pub struct Memory {
  addr:[u8; 0xffff]
}

const ADDRESSABLE_MEMORY: usize = 0xFFFF;

impl Memory {
  pub fn new() -> Memory {
    Memory {
      addr: [0; ADDRESSABLE_MEMORY]
    }
  }

  pub fn store(&mut self, addr: usize, data: u8) -> Result<(), &'static str> {
    if addr > ADDRESSABLE_MEMORY {
      Err("memory address out of bounds")
    } else {
      self.addr[addr] = data;
      Ok(())
    }
  }

  pub fn load(&mut self, addr: usize) -> Result<u8, &'static str> {
    if addr > ADDRESSABLE_MEMORY {
      Err("memory address out of bounds")
    } else {
      Ok(self.addr[addr])
    }
  }
}

<commit_msg>Add memory documentation<commit_after>// NES MEMORY MAP
// http://wiki.nesdev.com/w/index.php/Sample_RAM_map
//
// Address      Size    Description
// ---------------------------------
// $0000-$07FF	$0800	2KB internal RAM
// $0800-$0FFF	$0800	Mirrors of $0000-$07FF
// $1000-$17FF	$0800
// $1800-$1FFF	$0800
// $2000-$2007	$0008	NES PPU registers
// $2008-$3FFF	$1FF8	Mirrors of $2000-2007 (repeats every 8 bytes)
// $4000-$401F	$0020	NES APU and I/O registers
// $4020-$FFFF	$BFE0	Cartridge space: PRG ROM, PRG RAM, and mapper registers (See Note)

const ADDRESSABLE_MEMORY: usize = 0xFFFF;

pub struct Memory {
  addr:[u8; ADDRESSABLE_MEMORY]
}

impl Memory {
  pub fn new() -> Memory {
    Memory {
      addr: [0; ADDRESSABLE_MEMORY]
    }
  }

  pub fn store(&mut self, addr: usize, data: u8) -> Result<(), &'static str> {
    if addr > ADDRESSABLE_MEMORY {
      Err("memory address out of bounds")
    } else {
      self.addr[addr] = data;
      Ok(())
    }
  }

  pub fn load(&mut self, addr: usize) -> Result<u8, &'static str> {
    if addr > ADDRESSABLE_MEMORY {
      Err("memory address out of bounds")
    } else {
      Ok(self.addr[addr])
    }
  }
}

<|endoftext|>


<commit_before>// Crypto challenge Set1 / Challenge 3
// Decrypt single XOR chiffre

extern crate codec;
extern crate challenge3;

#[cfg(not(test))]
fn main() {
    let args = std::os::args();

    if args.len() != 2 {
        println!("USAGE: challenge3 HEX_ENCODED_STRING");
    } else {
        let input = args[1].as_slice();
        match codec::from_hex(input) {
            Err(msg) => println!("Invalid hex string: {}", msg),
            Ok(binary) => {
                let decoded = challenge3::decode_xor(binary.as_slice());
                match std::str::from_utf8(decoded.as_slice()) {
                    Some(result) => println!("Decoded: {}", result),
                    None => println!("Failed to decode to UTF-8 string!")
                }
            }
        }
    }
}
<commit_msg>Fix Challenge3 main to new signature of decode_xor<commit_after>// Crypto challenge Set1 / Challenge 3
// Decrypt single XOR chiffre

extern crate codec;
extern crate challenge3;

#[cfg(not(test))]
fn main() {
    let args = std::os::args();

    if args.len() != 2 {
        println!("USAGE: challenge3 HEX_ENCODED_STRING");
    } else {
        let input = args[1].as_slice();
        match codec::from_hex(input) {
            Err(msg) => println!("Invalid hex string: {}", msg),
            Ok(binary) => {
                let decoded = challenge3::decode_xor(binary.as_slice());
                match decoded {
                    (plaintext, key) => {
                        match std::str::from_utf8(plaintext.as_slice()) {
                            Some(result) => println!("Decoded: {}, Key {}", result, key),
                            None => println!("Failed to decode to UTF-8 string!")
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::error::Error;
use std::fs;
use std::fmt;
use std::error;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use hyper;
use hyper_tls::HttpsConnector;
use hyper_timeout::TimeoutConnector;
use futures::{Async, Future, Poll, Stream};
use futures::future::{err, ok};
use std::time::Duration;
// use flate2::Compression;
// use flate2::write::ZlibEncoder;

use config;

const CHUNK_SIZE: usize = 1024 * 1024;

#[derive(Debug)]
enum SendError {
    Io(io::Error),
    Format(Box<Error>),
    Hyper(hyper::Error),
}

impl From<io::Error> for SendError {
    fn from(err: io::Error) -> SendError {
        SendError::Io(err)
    }
}
impl From<Box<Error>> for SendError {
    fn from(err: Box<Error>) -> SendError {
        SendError::Format(err)
    }
}
impl<'a> From<&'a str> for SendError {
    fn from(err: &str) -> SendError {
        SendError::Format(From::from(err))
    }
}
impl From<String> for SendError {
    fn from(err: String) -> SendError {
        SendError::Format(From::from(err))
    }
}
impl From<hyper::Error> for SendError {
    fn from(err: hyper::Error) -> SendError {
        SendError::Hyper(err)
    }
}

impl fmt::Display for SendError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SendError::Io(ref err) => err.fmt(f),
            SendError::Format(ref err) => err.fmt(f),
            SendError::Hyper(ref err) => err.fmt(f),
        }
    }
}

impl error::Error for SendError {
    fn description(&self) -> &str {
        match *self {
            SendError::Io(ref err) => err.description(),
            SendError::Format(ref err) => err.description(),
            SendError::Hyper(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SendError::Io(ref err) => Some(err),
            SendError::Format(ref err) => Some(err.as_ref()),
            SendError::Hyper(ref err) => Some(err),
        }
    }
}

enum HttpResult {
    Error(SendError),
    Ok((hyper::StatusCode, String)),
}

pub fn send_thread(
    token: &str,
    token_header: &str,
    url: hyper::Uri,
    todo: Arc<Mutex<VecDeque<PathBuf>>>,
    timeout: u64,
    batch_count: u64,
    batch_size: u64,
    sigint: Arc<AtomicBool>,
) {
    let mut core = ::tokio_core::reactor::Core::new().expect("Fail to start tokio reactor");
    let handle = core.handle();
    let connector = HttpsConnector::new(4, &handle).expect("Fail to start https connector");

    // Handle connection timeouts
    let mut tm = TimeoutConnector::new(connector, &handle);
    tm.set_connect_timeout(Some(Duration::from_secs(timeout)));
    tm.set_read_timeout(Some(Duration::from_secs(timeout)));
    tm.set_write_timeout(Some(Duration::from_secs(timeout)));

    // Client should be shared accross sinks
    let client = hyper::Client::configure()
        .keep_alive(true)
        .connector(tm)
        .build(&handle);

    loop {
        Payload::new(sigint.clone(), todo.clone(), batch_count, batch_size).map(|p| {
            let (tx, body) = hyper::Body::pair();

            let mut req: hyper::Request = hyper::Request::new(hyper::Post, url.clone());
            req.set_body(body);
            req.headers_mut().set_raw(String::from(token_header), token);

            info!("Req");
            let req = client
                .request(req)
                .and_then(|res| {
                    let status = res.status();
                    // TODO not read body if not debug
                    let body = res.body()
                        .fold(String::new(), |mut acc, chunk| {
                            ok::<String, hyper::Error>({
                                acc.push_str(&String::from_utf8_lossy(&chunk));
                                acc
                            })
                        })
                        .or_else(|_| ok(String::new())); // Default body as an empty string

                    ok(status)
                        .join(body)
                        .and_then(|res| ok(HttpResult::Ok(res)))
                })
                .or_else(|err| ok(HttpResult::Error(SendError::Hyper(err))));

            let pipe = p.forward(tx).and_then(|res| ok(res.0));
            core.run(req.join(pipe).then(|res| match res {
                Err(error) => {
                    crit!("unrecoverable error: {}", error);
                    err(())
                }
                Ok(res) => {
                    let payload = res.1;
                    let state = match res.0 {
                        HttpResult::Ok(result) => {
                            let status = result.0;
                            if status.is_success() {
                                Ok(payload)
                            } else {
                                Err(payload)
                            }
                        }
                        HttpResult::Error(error) => {
                            error!("{}", error);
                            Err(payload)
                        }
                    };

                    match state {
                        Err(mut payload) => {
                            // recover processing file
                            // TODO Must be done in payload
                            payload.processing.take().map(|p| payload.processed.push(p));
                            let mut todo = payload.todo.lock().unwrap();
                            for entry in payload.processed {
                                debug!("pushback sink file {}", format!("{:?}", entry.display()));
                                todo.push_front(entry);
                            }
                        }
                        Ok(payload) => {
                            info!("post success - {}", payload.sent_lines);
                            // debug!("{}", b);
                            for entry in payload.processed {
                                debug!("delete sink file {}", format!("{:?}", entry.display()));
                                match fs::remove_file(entry) {
                                    Err(err) => error!("{}", err),
                                    Ok(()) => {}
                                }
                            }
                        }
                    };
                    ok(())
                }
            }))
        });

        thread::sleep(Duration::from_millis(config::REST_TIME));
        if sigint.load(Ordering::Relaxed) {
            return;
        }
    }
}

struct Payload {
    batch_count: u64,
    batch_size: i64,
    sigint: Arc<AtomicBool>,
    todo: Arc<Mutex<VecDeque<PathBuf>>>,
    processing: Option<PathBuf>,
    processed: Vec<PathBuf>,
    reader: Option<BufReader<File>>,
    remaining: String,
    sent_lines: usize,
}

impl Payload {
    pub fn new(
        sigint: Arc<AtomicBool>,
        todo: Arc<Mutex<VecDeque<PathBuf>>>,
        batch_count: u64,
        batch_size: u64,
    ) -> Option<Payload> {
        let mut p = Payload {
            sigint: sigint,
            batch_count: batch_count,
            batch_size: batch_size as i64,
            todo: todo,
            processing: None,
            processed: Vec::new(),
            reader: None,
            remaining: String::new(),
            sent_lines: 0,
            // encoder: ZlibEncoder::new(Vec::new(), Compression::Default),
        };

        p.processing = p.get_file();

        match p.processing {
            Some(_) => Some(p),
            None => None,
        }
    }

    fn get_file(&mut self) -> Option<PathBuf> {
        let mut todo = self.todo.lock().unwrap();
        todo.pop_front()
    }

    fn load_file(&self, path: &PathBuf) -> Option<BufReader<File>> {
        debug!("load file {}", path.display());
        match File::open(path) {
            Err(err) => {
                error!("{}", err);
                None
            }
            Ok(f) => Some(BufReader::new(f)),
        }
    }
}

impl Stream for Payload {
    type Item = Result<hyper::Chunk, hyper::error::Error>;
    type Error = Box<Error>;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        // Abort on sigint
        if self.sigint.load(Ordering::Relaxed) && self.processing.is_none() {
            return Ok(Async::Ready(None));
        }

        // Get a file to process
        if self.processing.is_none() && self.batch_count > 0 && self.batch_size > 0 {
            self.processing = self.get_file();
        }

        // Load reader
        if self.reader.is_none() && self.processing.is_some() {
            let to_load = self.processing.as_ref().unwrap();
            self.batch_count = self.batch_count - 1;
            self.reader = self.load_file(to_load);
        }

        // Chunk by 1M or less
        let mut s = String::with_capacity(CHUNK_SIZE);
        let mut idx = 0;

        // Process remaining data from previous chunk
        if self.remaining.len() > 0 {
            idx = self.remaining.len();
            s.push_str(&self.remaining);
            s.clear();
        }

        // if self.processing.is_some() {
        //     Ok(Async::Ready(Some(Ok(hyper::Chunk::from(
        //         self.load_file_as_bytes(self.processing.as_ref().unwrap())
        //             .unwrap(),
        //     )))))
        // } else {
        //     Ok(Async::Ready(None))
        // }

        // send file
        let mut drained = false;
        if idx < CHUNK_SIZE && self.reader.is_some() {
            let r = self.reader.as_mut().unwrap();
            while idx < CHUNK_SIZE {
                let size = r.read_line(&mut s)?; // TODO handle chunk size overflow
                if size == 0 {
                    drained = true; // TODO continue to loop throught new file
                    break;
                }
                idx = idx + size;
                self.sent_lines = self.sent_lines + 1;
            }
        }

        if drained {
            self.reader = None;
            self.processing.take().map(|p| self.processed.push(p));
            return Ok(Async::NotReady);
        }

        self.batch_size = self.batch_size - idx as i64;

        if s.len() > 0 {
            Ok(Async::Ready(Some(Ok(hyper::Chunk::from(s)))))
        } else {
            Ok(Async::Ready(None))
        }
    }
}
<commit_msg>fix(sink): sink lock on http error<commit_after>use std::collections::VecDeque;
use std::error::Error;
use std::fs;
use std::fmt;
use std::error;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use hyper;
use hyper_tls::HttpsConnector;
use hyper_timeout::TimeoutConnector;
use futures::{Async, Future, Poll, Stream};
use futures::future::{err, ok};
use std::time::Duration;
use std::ops::Deref;
use std::ops::DerefMut;
// use flate2::Compression;
// use flate2::write::ZlibEncoder;

use config;

const CHUNK_SIZE: usize = 1024 * 1024;

#[derive(Debug)]
enum SendError {
    Io(io::Error),
    Format(Box<Error>),
    Hyper(hyper::Error),
}

impl From<io::Error> for SendError {
    fn from(err: io::Error) -> SendError {
        SendError::Io(err)
    }
}
impl From<Box<Error>> for SendError {
    fn from(err: Box<Error>) -> SendError {
        SendError::Format(err)
    }
}
impl<'a> From<&'a str> for SendError {
    fn from(err: &str) -> SendError {
        SendError::Format(From::from(err))
    }
}
impl From<String> for SendError {
    fn from(err: String) -> SendError {
        SendError::Format(From::from(err))
    }
}
impl From<hyper::Error> for SendError {
    fn from(err: hyper::Error) -> SendError {
        SendError::Hyper(err)
    }
}

impl fmt::Display for SendError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SendError::Io(ref err) => err.fmt(f),
            SendError::Format(ref err) => err.fmt(f),
            SendError::Hyper(ref err) => err.fmt(f),
        }
    }
}

impl error::Error for SendError {
    fn description(&self) -> &str {
        match *self {
            SendError::Io(ref err) => err.description(),
            SendError::Format(ref err) => err.description(),
            SendError::Hyper(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            SendError::Io(ref err) => Some(err),
            SendError::Format(ref err) => Some(err.as_ref()),
            SendError::Hyper(ref err) => Some(err),
        }
    }
}

enum HttpResult {
    Error(SendError),
    Ok((hyper::StatusCode, String)),
}

pub fn send_thread(
    token: &str,
    token_header: &str,
    url: hyper::Uri,
    todo: Arc<Mutex<VecDeque<PathBuf>>>,
    timeout: u64,
    batch_count: u64,
    batch_size: u64,
    sigint: Arc<AtomicBool>,
) {
    let mut core = ::tokio_core::reactor::Core::new().expect("Fail to start tokio reactor");
    let handle = core.handle();
    let connector = HttpsConnector::new(4, &handle).expect("Fail to start https connector");

    // Handle connection timeouts
    let mut tm = TimeoutConnector::new(connector, &handle);
    tm.set_connect_timeout(Some(Duration::from_secs(timeout)));
    tm.set_read_timeout(Some(Duration::from_secs(timeout)));
    tm.set_write_timeout(Some(Duration::from_secs(timeout)));

    // Client should be shared accross sinks
    let client = hyper::Client::configure()
        .body::<Payload>()
        .keep_alive(true)
        .connector(tm)
        .build(&handle);

    loop {
        Payload::new(sigint.clone(), todo.clone(), batch_count, batch_size).map(|p| {
            let processed = p.processed();

            let mut req: hyper::Request<Payload> = hyper::Request::new(hyper::Post, url.clone());
            req.set_body(p);
            req.headers_mut().set_raw(String::from(token_header), token);

            info!("Req");
            let req = client
                .request(req)
                .and_then(|res| {
                    let status = res.status();
                    // TODO not read body if not debug
                    let body = res.body()
                        .fold(String::new(), |mut acc, chunk| {
                            ok::<String, hyper::Error>({
                                acc.push_str(&String::from_utf8_lossy(&chunk));
                                acc
                            })
                        })
                        .or_else(|_| ok(String::new())); // Default body as an empty string

                    ok(status)
                        .join(body)
                        .and_then(|res| ok(HttpResult::Ok(res)))
                })
                .or_else(|err| ok(HttpResult::Error(SendError::Hyper(err))));

            core.run(req.then(|res: Result<HttpResult, Box<Error>>| match res {
                Err(error) => {
                    crit!("unrecoverable error: {}", error);
                    err(())
                }
                Ok(res) => {
                    let state = match res {
                        HttpResult::Ok(result) => {
                            let status = result.0;
                            if status.is_success() {
                                Ok(())
                            } else {
                                error!("HTTP error: {}", status);
                                Err(())
                            }
                        }
                        HttpResult::Error(error) => {
                            error!("HTTP error: {}", error);
                            Err(())
                        }
                    };

                    match state {
                        Err(_) => {
                            // recover processing file
                            let mut processed = processed.lock().unwrap();
                            let mut todo = todo.lock().unwrap();
                            for entry in processed.deref_mut().drain(0..) {
                                debug!("pushback sink file {}", format!("{:?}", entry.display()));
                                todo.push_front(entry);
                            }
                        }
                        Ok(_) => {
                            info!("post success");
                            // info!("post success - {}", payload.sent_lines);
                            // debug!("{}", b);
                            let processed = processed.lock().unwrap();
                            for entry in processed.deref() {
                                debug!("delete sink file {}", format!("{:?}", entry.display()));
                                match fs::remove_file(entry) {
                                    Err(err) => error!("{}", err),
                                    Ok(()) => {}
                                }
                            }
                        }
                    };
                    ok(())
                }
            }))
        });

        thread::sleep(Duration::from_millis(config::REST_TIME));
        if sigint.load(Ordering::Relaxed) {
            return;
        }
    }
}

struct Payload {
    batch_count: u64,
    batch_size: i64,
    sigint: Arc<AtomicBool>,
    todo: Arc<Mutex<VecDeque<PathBuf>>>,
    processing: Option<PathBuf>,
    processed: Arc<Mutex<Vec<PathBuf>>>,
    reader: Option<BufReader<File>>,
    remaining: String,
    sent_lines: usize,
}

impl Payload {
    pub fn new(
        sigint: Arc<AtomicBool>,
        todo: Arc<Mutex<VecDeque<PathBuf>>>,
        batch_count: u64,
        batch_size: u64,
    ) -> Option<Payload> {
        let mut p = Payload {
            sigint: sigint,
            batch_count: batch_count,
            batch_size: batch_size as i64,
            todo: todo,
            processing: None,
            processed: Arc::new(Mutex::new(Vec::new())),
            reader: None,
            remaining: String::new(),
            sent_lines: 0,
            // encoder: ZlibEncoder::new(Vec::new(), Compression::Default),
        };

        p.processing = p.get_file();

        match p.processing {
            Some(_) => Some(p),
            None => None,
        }
    }

    fn processed(&self) -> Arc<Mutex<Vec<PathBuf>>> {
        self.processed.clone()
    }

    fn get_file(&mut self) -> Option<PathBuf> {
        let mut todo = self.todo.lock().unwrap();
        let file = todo.pop_front();

        match file {
            Some(ref f) => self.processed.lock().unwrap().push(f.clone()),
            None => {}
        }

        file
    }

    fn load_file(&self, path: &PathBuf) -> Option<BufReader<File>> {
        debug!("load file {}", path.display());
        match File::open(path) {
            Err(err) => {
                error!("{}", err);
                None
            }
            Ok(f) => Some(BufReader::new(f)),
        }
    }
}

impl Stream for Payload {
    type Item = hyper::Chunk;
    type Error = hyper::Error;

    fn poll(&mut self) -> Poll<Option<hyper::Chunk>, hyper::Error> {
        // Abort on sigint
        if self.sigint.load(Ordering::Relaxed) && self.processing.is_none() {
            return Ok(Async::Ready(None));
        }

        // Get a file to process
        if self.processing.is_none() && self.batch_count > 0 && self.batch_size > 0 {
            self.processing = self.get_file();
        }

        // Load reader
        if self.reader.is_none() && self.processing.is_some() {
            let to_load = self.processing.as_ref().unwrap();
            self.batch_count = self.batch_count - 1;
            self.reader = self.load_file(to_load);
        }

        // Chunk by 1M or less
        let mut s = String::with_capacity(CHUNK_SIZE);
        let mut idx = 0;

        // Process remaining data from previous chunk
        if self.remaining.len() > 0 {
            idx = self.remaining.len();
            s.push_str(&self.remaining);
            s.clear();
        }

        // if self.processing.is_some() {
        //     Ok(Async::Ready(Some(Ok(hyper::Chunk::from(
        //         self.load_file_as_bytes(self.processing.as_ref().unwrap())
        //             .unwrap(),
        //     )))))
        // } else {
        //     Ok(Async::Ready(None))
        // }

        // send file
        let mut drained = false;
        if idx < CHUNK_SIZE && self.reader.is_some() {
            let r = self.reader.as_mut().unwrap();
            while idx < CHUNK_SIZE {
                let size = r.read_line(&mut s)?; // TODO handle chunk size overflow
                if size == 0 {
                    drained = true; // TODO continue to loop throught new file
                    break;
                }
                idx = idx + size;
                self.sent_lines = self.sent_lines + 1;
            }
        }

        if drained {
            self.reader = None;
            self.processing = None;
        }

        self.batch_size = self.batch_size - idx as i64;

        if s.len() > 0 {
            Ok(Async::Ready(Some(hyper::Chunk::from(s))))
        } else {
            Ok(Async::Ready(None))
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::fmt;
use std::ptr;
use std::iter;

use rand::{thread_rng, Rng};

// 32
const DEFAULT_LEVEL: usize = 3;

type Link<T> = Option<Box<T>>;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
struct Rawlink<T> {
    p: *mut T,
}

impl<T> Copy for Rawlink<T> {}
unsafe impl<T:Send> Send for Rawlink<T> {}
unsafe impl<T:Sync> Sync for Rawlink<T> {}

fn random_level() -> usize {
    let mut rng = thread_rng();
    let mut level = 0;
    loop {
        if rng.gen_weighted_bool(2) {
            level += 1;
            continue;
        }
        break;
    }

    level
}

#[derive(Debug)]
pub struct SkipNode<Key,E> {
    key: Key,
    it: E,
    next: Link<SkipNode<Key,E>>,
    prev: Rawlink<SkipNode<Key,E>>,
    // level 0 to DEFAULT_LEVEL
    forward: Vec<Rawlink<SkipNode<Key,E>>>,
}

impl<Key: PartialOrd, E> SkipNode<Key,E> {
    // level: 0 ~ DEFAULT_LEVEL
    fn new(key: Key, it: E, level: usize) -> SkipNode<Key,E> {
        SkipNode {
            key: key,
            it: it,
            next: None,
            prev: Rawlink::none(),
            forward: iter::repeat(Rawlink::none()).take(level).collect(),
        }
    }

    #[inline]
    fn level(&self) -> usize {
        self.forward.len()
    }

    fn to_ptr(&mut self) -> Rawlink<SkipNode<Key,E>> {
        Rawlink::some(self)
    }

    fn insert(&mut self, key: Key, it: E, level: usize) {
    }
}

pub struct SkipList<Key,E> {
    head: Link<SkipNode<Key,E>>,
    forward: Vec<Rawlink<SkipNode<Key,E>>>,
    level: usize,
    size: usize,
}

impl<Key: PartialOrd + fmt::Debug, E: fmt::Debug> SkipList<Key,E> {
    /// create new empty SkipList
    pub fn new() -> SkipList<Key, E> {
        SkipList {
            head: None,
            forward: iter::repeat(Rawlink::none()).take(DEFAULT_LEVEL).collect(),
            level: DEFAULT_LEVEL,
            size: 0,
        }
    }

    pub fn level(&self) -> usize {
        self.level
    }

    pub fn contains_key(&self, key: &Key) -> bool {
        self.find(key).is_some()
    }

    pub fn find(&self, key: &Key) -> Option<&E> {

        let level = self.level();
        let mut x = self.forward[level-1];
        for i in (0..level).rev() {
            while x.resolve().map_or(false, |n| n.forward[i].is_some()) &&
                x.resolve().map_or(false, |n| n.forward[i].resolve().unwrap().key < *key) {
                    let nx = x.resolve().map_or_else(Rawlink::none, |n| n.forward[i] );
                    x = nx;
                }
        }

        while x.resolve().map_or(false, |n| n.next.is_some()) &&
            x.resolve().map_or(false, |n| n.next.as_ref().unwrap().key < *key) {
                let nx = x.resolve_mut().map_or_else(Rawlink::none, |n| {
                    n.next.as_mut().map_or_else(Rawlink::none, |n| Rawlink::some(&mut **n))
                });
                x = nx
            }

        x.resolve().map_or(None, |n| {
            if n.key == *key {
                Some(&n.it)
            } else {
                None
            }
        })
    }

    fn adjust_head(&mut self, new_level: usize) {
        let diff = new_level - self.level;
        if diff > 0 {
            self.forward.append(&mut iter::repeat(Rawlink::none()).take(diff).collect())
        }
    }

    // Due to head node must be of same level as List,
    // inserting with decreasing order will lead to almost same bad performance as a linked list
    pub fn insert(&mut self, key: Key, it: E) {
        let mut new_level = random_level();
        if new_level > self.level { // new node will be deepest
            self.adjust_head(new_level);
            self.level = new_level;
        }
        self.size += 1;

        if self.head.is_none() {
            new_level = self.level;
            self.head = Some(Box::new(SkipNode::new(key, it, new_level)));
            let p = Rawlink::from(&mut self.head);
            for i in 0..new_level {
                self.forward[i] = p;
            }
        } else if self.head.as_ref().map_or(false, |n| n.key > key) {
            new_level = self.level;
            // insert at head
            let mut new_node = Some(Box::new(SkipNode::new(key, it, new_level)));
            let new_link = new_node.as_mut().map_or_else(Rawlink::none, |n| {
                Rawlink::some(&mut **n)
            });

            for i in 0..new_level {
                new_node.as_mut().map(|n| {
                    n.forward[i] = self.forward[i]
                });
            }

            for i in 0..new_level {
                self.forward[i] = new_link
            }

            new_node.as_mut().map(|n| n.next = self.head.take());
            self.head = new_node;
        } else {
            let mut x = self.head.as_mut().map_or_else(Rawlink::none, |n| {
                Rawlink::some(&mut **n)
            });
            // insert normally
            let mut update: Vec<Rawlink<SkipNode<Key,E>>> = self.forward[..new_level].to_vec();
            if new_level > 0 {  // need to insert skip pointers
                x = update[new_level-1];
                for i in (0..new_level).rev() {
                    while x.resolve().map_or(false, |n| n.forward[i].is_some()) &&
                        x.resolve().map_or(false, |n| n.forward[i].resolve().unwrap().key < key) {
                            let nx = x.resolve().map_or_else(Rawlink::none, |n| n.forward[i] );
                            x = nx;
                        }
                    update[i] = x.resolve_mut().map_or_else(Rawlink::none, |n| {
                        Rawlink::some(&mut *n)
                    });
                }
            }

            let mut y = x.resolve_mut().map_or_else(Rawlink::none, |n| {
                Rawlink::some(&mut *n)
            });
            // When head node level is lower than current
            if y.is_none() {
                println!("update => {:?}", update);
                y = self.head.as_mut().map_or_else(Rawlink::none, |n| {
                    Rawlink::some(&mut **n)
                });
            }
            while y.resolve().map_or(false, |n| n.next.is_some()) &&
                y.resolve().map_or(false, |n| n.next.as_ref().unwrap().key < key) {
                    let ny = y.resolve_mut().map_or_else(Rawlink::none, |n| {
                        n.next.as_mut().map_or_else(Rawlink::none, |n| Rawlink::some(&mut **n))
                    });
                    y = ny
                }
            assert!(y.is_some());
            // create node and insert
            let mut new_node = Some(Box::new(SkipNode::new(key, it, self.level)));
            let new_link = new_node.as_mut().map_or_else(Rawlink::none, |n| {
                Rawlink::some(&mut **n)
            });

            for i in 0..new_level {
                new_node.as_mut().map(|n| {
                    n.forward[i] = update[i].resolve_mut().map_or_else(Rawlink::none, |nx| {
                        nx.forward[i]
                    });
                });
                // if update is empty, then update head node's link
                update[i].resolve_mut().map_or_else(|| {
                    self.forward[i] = new_link;
                },
                    |prev| {
                    prev.forward[i] = new_link;
                });
            }

            // move in
            y.resolve_mut().map(|n| {
                new_node.as_mut().map(|new| {
                    new.next = n.next.take();
                });
                n.next = new_node;
            });
        }
    }

    pub fn remove(&mut self, key: &Key) {
        unimplemented!()
    }

    pub fn size(&self) -> usize {
        self.size
    }
}

impl<Key: PartialOrd + fmt::Display + fmt::Debug, E: fmt::Debug> fmt::Display for SkipList<Key,E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.head.is_none() {
            write!(f, "<empty skip list>")
        } else {
            write!(f, "\nlv0 ");
            let mut x = self.head.as_ref();
            while x.is_some() {
                write!(f, "{} --> ", x.as_ref().map_or_else(String::new, |n| format!("{}", n.key)));
                x = x.as_ref().map_or(None, |n| n.next.as_ref());
            }
            writeln!(f, "");
            for i in 0..self.level {
                write!(f, "lv{} ", i+1);
                let mut x = self.forward[i];
                while x.is_some() {
                    write!(f, "{} ..> ",
                           x.resolve().map_or_else(String::new, |n| format!("{}", n.key)));
                    if x.resolve().map_or(false, |n| n.level() <= i) {
                        break;
                    }
                    x = x.resolve().map_or_else(Rawlink::none, |n| n.forward[i]);
                }
                writeln!(f, "");
            }
            Ok(())
        }
    }
}

/// Rawlink is a type like Option<T> but for holding a raw mutable pointer.
impl<T> Rawlink<T> {
    /// Like `Option::None` for Rawlink.
    fn none() -> Rawlink<T> {
        Rawlink{p: ptr::null_mut()}
    }

    /// Like `Option::Some` for Rawlink
    fn some(n: &mut T) -> Rawlink<T> {
        Rawlink{p: n}
    }

    fn is_some(&self) -> bool {
        !self.is_none()
    }

    fn is_none(&self) -> bool {
        self.p.is_null()
    }

    fn take(&mut self) -> Rawlink<T> {
        mem::replace(self, Rawlink::none())
    }

    /// Convert the `Rawlink` into an immutable Option value.
    fn resolve<'a>(&self) -> Option<&'a T> {
        if self.p.is_null() {
            None
        } else {
            Some(unsafe { &*self.p })
        }
    }

    /// Convert the `Rawlink` into a mutable Option value.
    fn resolve_mut<'a>(&mut self) -> Option<&'a mut T> {
        if self.p.is_null() {
            None
        } else {
            Some(unsafe { &mut *self.p })
        }
    }
}

impl<'a, Key, E> From<&'a mut Link<SkipNode<Key, E>>> for Rawlink<SkipNode<Key, E>> {
    fn from(node: &'a mut Link<SkipNode<Key, E>>) -> Self {
        match node.as_mut() {
            None => Rawlink::none(),
            Some(ptr) => Rawlink::some(&mut **ptr),
        }
    }
}

impl<T> Clone for Rawlink<T> {
    #[inline]
    fn clone(&self) -> Rawlink<T> {
        Rawlink{p: self.p}
    }
}

#[test]
fn test_skip_list() {
    let mut list: SkipList<i32, ()> = SkipList::new();

    let mut rng = thread_rng();

    //let vals = vec![ -18130, 16865, -1813, 1686, -181, 168, -18, 16];
    for i in 0 .. 10 {
        let val = rng.gen_range(0, 2000);
        // let val = vals[i];
        println!("DEBUG {} insert => {}", i+1, val);
        list.insert(val, ());
    }

    println!("list => {}", list);
    println!("level => {}", list.level());

    list.insert(20, ());
    println!("has(20) => {}", list.contains_key(&20));
}
<commit_msg>skip_list: add remove(), unfinished<commit_after>use std::mem;
use std::fmt;
use std::ptr;
use std::iter;

use rand::{thread_rng, Rng};

// 32
const DEFAULT_LEVEL: usize = 3;

type Link<T> = Option<Box<T>>;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
struct Rawlink<T> {
    p: *mut T,
}

impl<T> Copy for Rawlink<T> {}
unsafe impl<T:Send> Send for Rawlink<T> {}
unsafe impl<T:Sync> Sync for Rawlink<T> {}

fn random_level() -> usize {
    let mut rng = thread_rng();
    let mut level = 0;
    loop {
        if rng.gen_weighted_bool(2) {
            level += 1;
            continue;
        }
        break;
    }

    level
}

#[derive(Debug)]
pub struct SkipNode<Key,E> {
    key: Key,
    it: E,
    next: Link<SkipNode<Key,E>>,
    prev: Rawlink<SkipNode<Key,E>>,
    // level 0 to DEFAULT_LEVEL
    forward: Vec<Rawlink<SkipNode<Key,E>>>,
}

impl<Key: PartialOrd, E> SkipNode<Key,E> {
    // level: 0 ~ DEFAULT_LEVEL
    fn new(key: Key, it: E, level: usize) -> SkipNode<Key,E> {
        SkipNode {
            key: key,
            it: it,
            next: None,
            prev: Rawlink::none(),
            forward: iter::repeat(Rawlink::none()).take(level).collect(),
        }
    }

    #[inline]
    fn level(&self) -> usize {
        self.forward.len()
    }

    fn to_ptr(&mut self) -> Rawlink<SkipNode<Key,E>> {
        Rawlink::some(self)
    }

    fn adjust_head(&mut self, new_level: usize) {
        let diff = new_level - self.level();
        if diff > 0 {
            self.forward.append(&mut iter::repeat(Rawlink::none()).take(diff).collect())
        }
    }

    fn insert(&mut self, key: Key, it: E, level: usize) {
    }
}

pub struct SkipList<Key,E> {
    head: Link<SkipNode<Key,E>>,
    forward: Vec<Rawlink<SkipNode<Key,E>>>,
    level: usize,
    size: usize,
}

impl<Key: PartialOrd + fmt::Debug, E: fmt::Debug> SkipList<Key,E> {
    /// create new empty SkipList
    pub fn new() -> SkipList<Key, E> {
        SkipList {
            head: None,
            forward: iter::repeat(Rawlink::none()).take(DEFAULT_LEVEL).collect(),
            level: DEFAULT_LEVEL,
            size: 0,
        }
    }

    pub fn level(&self) -> usize {
        self.level
    }

    pub fn contains_key(&self, key: &Key) -> bool {
        self.find(key).is_some()
    }

    pub fn find(&self, key: &Key) -> Option<&E> {
        let level = self.level();
        let mut x = self.forward[level-1];
        for i in (0..level).rev() {
            while x.resolve().map_or(false, |n| n.forward[i].is_some()) &&
                x.resolve().map_or(false, |n| n.forward[i].resolve().unwrap().key < *key) {
                    let nx = x.resolve().map_or_else(Rawlink::none, |n| n.forward[i] );
                    x = nx;
                }
        }

        while x.resolve().map_or(false, |n| n.next.is_some()) &&
            x.resolve().map_or(false, |n| n.next.as_ref().unwrap().key < *key) {
                let nx = x.resolve_mut().map_or_else(Rawlink::none, |n| {
                    n.next.as_mut().map_or_else(Rawlink::none, |n| Rawlink::some(&mut **n))
                });
                x = nx
            }

        x.resolve().map_or(None, |n| {
            if n.key == *key {
                Some(&n.it)
            } else {
                None
            }
        })
    }

    fn adjust_head(&mut self, new_level: usize) {
        let diff = new_level - self.level;
        if diff > 0 {
            self.forward.append(&mut iter::repeat(Rawlink::none()).take(diff).collect())
        }
    }

    // Due to head node must be of same level as List,
    // inserting with decreasing order will lead to almost same bad performance as a linked list
    pub fn insert(&mut self, key: Key, it: E) {
        let mut new_level = random_level();
        if new_level > self.level { // new node will be deepest
            self.adjust_head(new_level);
            self.level = new_level;
        }
        self.size += 1;

        if self.head.is_none() {
            new_level = self.level;
            self.head = Some(Box::new(SkipNode::new(key, it, new_level)));
            let p = Rawlink::from(&mut self.head);
            for i in 0..new_level {
                self.forward[i] = p;
            }
        } else if self.head.as_ref().map_or(false, |n| n.key > key) {
            new_level = self.level;
            // insert at head
            let mut new_node = Some(Box::new(SkipNode::new(key, it, new_level)));
            let new_link = new_node.as_mut().map_or_else(Rawlink::none, |n| {
                Rawlink::some(&mut **n)
            });

            for i in 0..new_level {
                new_node.as_mut().map(|n| {
                    n.forward[i] = self.forward[i]
                });
            }

            for i in 0..new_level {
                self.forward[i] = new_link
            }

            new_node.as_mut().map(|n| n.next = self.head.take());
            self.head = new_node;
        } else {
            let mut x = self.head.as_mut().map_or_else(Rawlink::none, |n| {
                Rawlink::some(&mut **n)
            });
            // insert normally
            let mut update: Vec<Rawlink<SkipNode<Key,E>>> = self.forward[..new_level].to_vec();
            if new_level > 0 {  // need to insert skip pointers
                x = update[new_level-1];
                for i in (0..new_level).rev() {
                    while x.resolve().map_or(false, |n| n.forward[i].is_some()) &&
                        x.resolve().map_or(false, |n| n.forward[i].resolve().unwrap().key < key) {
                            let nx = x.resolve().map_or_else(Rawlink::none, |n| n.forward[i] );
                            x = nx;
                        }
                    update[i] = x.resolve_mut().map_or_else(Rawlink::none, |n| {
                        Rawlink::some(&mut *n)
                    });
                }
            }

            let mut y = x.resolve_mut().map_or_else(Rawlink::none, |n| {
                Rawlink::some(&mut *n)
            });
            // When head node level is lower than current
            if y.is_none() {
                println!("update => {:?}", update);
                y = self.head.as_mut().map_or_else(Rawlink::none, |n| {
                    Rawlink::some(&mut **n)
                });
            }
            while y.resolve().map_or(false, |n| n.next.is_some()) &&
                y.resolve().map_or(false, |n| n.next.as_ref().unwrap().key < key) {
                    let ny = y.resolve_mut().map_or_else(Rawlink::none, |n| {
                        n.next.as_mut().map_or_else(Rawlink::none, |n| Rawlink::some(&mut **n))
                    });
                    y = ny
                }
            assert!(y.is_some());
            // create node and insert
            let mut new_node = Some(Box::new(SkipNode::new(key, it, self.level)));
            let new_link = new_node.as_mut().map_or_else(Rawlink::none, |n| {
                Rawlink::some(&mut **n)
            });

            for i in 0..new_level {
                new_node.as_mut().map(|n| {
                    n.forward[i] = update[i].resolve_mut().map_or_else(Rawlink::none, |nx| {
                        nx.forward[i]
                    });
                });
                // if update is empty, then update head node's link
                update[i].resolve_mut().map_or_else(|| {
                    self.forward[i] = new_link;
                },
                    |prev| {
                    prev.forward[i] = new_link;
                });
            }

            // move in
            y.resolve_mut().map(|n| {
                new_node.as_mut().map(|new| {
                    new.next = n.next.take();
                });
                n.next = new_node;
            });
        }
    }

    pub fn remove(&mut self, key: &Key) -> Option<E> {
        if self.head.is_none() {
            return None;
        }
        let level = self.level();
        let mut x = self.forward[level-1];
        let mut left = x;

        for i in (0..level).rev() {
            while x.resolve().map_or(false, |n| n.forward[i].is_some()) &&
                x.resolve().map_or(false, |n| n.forward[i].resolve().unwrap().key < *key) {
                    let nx = x.resolve().map_or_else(Rawlink::none, |n| n.forward[i] );
                    x = nx;
                }
        }

        while x.resolve().map_or(false, |n| n.next.is_some()) &&
            x.resolve().map_or(false, |n| n.next.as_ref().unwrap().key < *key) {
                let nx = x.resolve_mut().map_or_else(Rawlink::none, |n| {
                    n.next.as_mut().map_or_else(Rawlink::none, |n| Rawlink::some(&mut **n))
                });
                left = x;
                x = nx
            }

        if !x.resolve().map_or(false, |n| n.key == *key ) {
            None
        } else if x.p == left.p && x.is_some() {
            println!("fuck equels");
            // this means remove head
            let head = self.head.take().unwrap();
            // remove box
            let head = *head;
            let SkipNode { it, next, forward, .. } = head;
            self.head = next;
            self.forward = forward;
            self.head.as_mut().map(|n| n.adjust_head(level));
            Some(it)
        } else {
            unimplemented!()
        }
    }

    pub fn size(&self) -> usize {
        self.size
    }
}

impl<Key: PartialOrd + fmt::Display + fmt::Debug, E: fmt::Debug> fmt::Display for SkipList<Key,E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.head.is_none() {
            write!(f, "<empty skip list>")
        } else {
            write!(f, "\nlv0 ");
            let mut x = self.head.as_ref();
            while x.is_some() {
                write!(f, "{} --> ", x.as_ref().map_or_else(String::new, |n| format!("{}", n.key)));
                x = x.as_ref().map_or(None, |n| n.next.as_ref());
            }
            writeln!(f, "");
            for i in 0..self.level {
                write!(f, "lv{} ", i+1);
                let mut x = self.forward[i];
                while x.is_some() {
                    write!(f, "{} ..> ",
                           x.resolve().map_or_else(String::new, |n| format!("{}", n.key)));
                    if x.resolve().map_or(false, |n| n.level() <= i) {
                        break;
                    }
                    x = x.resolve().map_or_else(Rawlink::none, |n| n.forward[i]);
                }
                writeln!(f, "");
            }
            Ok(())
        }
    }
}

/// Rawlink is a type like Option<T> but for holding a raw mutable pointer.
impl<T> Rawlink<T> {
    /// Like `Option::None` for Rawlink.
    fn none() -> Rawlink<T> {
        Rawlink{p: ptr::null_mut()}
    }

    /// Like `Option::Some` for Rawlink
    fn some(n: &mut T) -> Rawlink<T> {
        Rawlink{p: n}
    }

    fn is_some(&self) -> bool {
        !self.is_none()
    }

    fn is_none(&self) -> bool {
        self.p.is_null()
    }

    fn take(&mut self) -> Rawlink<T> {
        mem::replace(self, Rawlink::none())
    }

    /// Convert the `Rawlink` into an immutable Option value.
    fn resolve<'a>(&self) -> Option<&'a T> {
        if self.p.is_null() {
            None
        } else {
            Some(unsafe { &*self.p })
        }
    }

    /// Convert the `Rawlink` into a mutable Option value.
    fn resolve_mut<'a>(&mut self) -> Option<&'a mut T> {
        if self.p.is_null() {
            None
        } else {
            Some(unsafe { &mut *self.p })
        }
    }
}

impl<'a, Key, E> From<&'a mut Link<SkipNode<Key, E>>> for Rawlink<SkipNode<Key, E>> {
    fn from(node: &'a mut Link<SkipNode<Key, E>>) -> Self {
        match node.as_mut() {
            None => Rawlink::none(),
            Some(ptr) => Rawlink::some(&mut **ptr),
        }
    }
}

impl<T> Clone for Rawlink<T> {
    #[inline]
    fn clone(&self) -> Rawlink<T> {
        Rawlink{p: self.p}
    }
}

#[test]
fn test_skip_list() {
    let mut list: SkipList<i32, ()> = SkipList::new();

    let mut rng = thread_rng();

    //let vals = vec![ -18130, 16865, -1813, 1686, -181, 168, -18, 16];
    for i in 0 .. 10 {
        let val = rng.gen_range(0, 2000);
        // let val = vals[i];
        println!("DEBUG {} insert => {}", i+1, val);
        list.insert(val, ());
    }

    println!("list => {}", list);
    println!("level => {}", list.level());

    list.insert(20, ());
    println!("has(20) => {}", list.contains_key(&20));
    println!("list => {}", list);

    list.remove(&20);
    println!("list => {}", list);
}
<|endoftext|>