<commit_before>//! Register pressure tracking.
//!
//! SSA-based register allocation depends on a spilling phase that "lowers register pressure
//! sufficiently". This module defines the data structures needed to measure register pressure
//! accurately enough to guarantee that the coloring phase will not run out of registers.
//!
//! Ideally, measuring register pressure amounts to simply counting the number of live registers at
//! any given program point. This simplistic method has two problems:
//!
//! 1. Registers are not interchangeable. Most ISAs have separate integer and floating-point
//!    register banks, so we need to at least count the number of live registers in each register
//!    bank separately.
//!
//! 2. Some ISAs have complicated register aliasing properties. In particular, the 32-bit ARM
//!    ISA has a floating-point register bank where two 32-bit registers alias one 64-bit register.
//!    This makes it difficult to accurately measure register pressure.
//!
//! This module deals with the problems via *register banks* and *top-level register classes*.
//! Register classes in different register banks are completely independent, so we can count
//! registers in one bank without worrying about the other bank at all.
//!
//! All register classes have a unique top-level register class, and we will count registers for
//! each top-level register class individually. However, a register bank can have multiple
//! top-level register classes that interfere with each other, so all top-level counts need to
//! be considered when determining how many more registers can be allocated.
//!
//! Currently, the only register bank with multiple top-level registers is the `arm32`
//! floating-point register bank which has `S`, `D`, and `Q` top-level classes.

// Remove once we're using the pressure tracker.
#![allow(dead_code)]

use isa::registers::{RegInfo, MAX_TOPRCS, RegClass, RegClassMask};
use regalloc::AllocatableSet;
use std::cmp::min;
use std::iter::ExactSizeIterator;

/// Information per top-level register class.
///
/// Everything but the count is static information computed from the constructor arguments.
#[derive(Default)]
struct TopRC {
    // Number of registers currently used from this register class.
    count: u32,

    // Max number of registers that can be allocated.
    limit: u32,

    // Register units per register.
    width: u8,

    // The first aliasing top-level RC.
    first_toprc: u8,

    // The number of aliasing top-level RCs.
    num_toprcs: u8,
}

pub struct Pressure {
    // Bit mask of top-level register classes that are aliased by other top-level register classes.
    // Unaliased register classes can use a simpler interference algorithm.
    aliased: RegClassMask,

    // Current register counts per top-level register class.
    toprc: [TopRC; MAX_TOPRCS],
}

impl Pressure {
    /// Create a new register pressure tracker.
    pub fn new(reginfo: &RegInfo, usable: &AllocatableSet) -> Pressure {
        let mut p = Pressure {
            aliased: 0,
            toprc: Default::default(),
        };

        // Get the layout of aliasing top-level register classes from the register banks.
        for bank in reginfo.banks {
            let first = bank.first_toprc;
            let num = bank.num_toprcs;
            for rc in &mut p.toprc[first..first + num] {
                rc.first_toprc = first as u8;
                rc.num_toprcs = num as u8;
            }

            // Flag the top-level register classes with aliases.
            if num > 1 {
                p.aliased |= ((1 << num) - 1) << first;
            }
        }

        // Compute per-class limits from `usable`.
        for (toprc, rc) in p.toprc
                .iter_mut()
                .take_while(|t| t.num_toprcs > 0)
                .zip(reginfo.classes) {
            toprc.limit = usable.iter(rc).len() as u32;
            toprc.width = rc.width;
        }

        p
    }

    /// Check for an available register in the register class `rc`.
    ///
    /// If it is possible to allocate one more register from `rc`'s top-level register class,
    /// returns 0.
    ///
    /// If not, returns a bit-mask of top-level register classes that are interfering. Register
    /// pressure should be eased in one of the returned top-level register classes before calling
    /// `can_take()` to check again.
    pub fn check_avail(&self, rc: RegClass) -> RegClassMask {
        let entry = &self.toprc[rc.toprc as usize];
        let mask = 1 << rc.toprc;
        if self.aliased & mask == 0 {
            // This is a simple unaliased top-level register class.
            if entry.count < entry.limit { 0 } else { mask }
        } else {
            // This is the more complicated case. The top-level register class has aliases.
            self.check_avail_aliased(entry)
        }
    }

    /// Check for an available register in a top-level register class that may have aliases.
    ///
    /// This is the out-of-line slow path for `check_avail()`.
    fn check_avail_aliased(&self, entry: &TopRC) -> RegClassMask {
        let first = entry.first_toprc as usize;
        let num = entry.num_toprcs as usize;
        let width = entry.width as u32;
        let ulimit = entry.limit * width;

        // Count up the number of available register units.
        let mut units = 0;
        for (rc, rci) in self.toprc[first..first + num].iter().zip(first..) {
            let rcw = rc.width as u32;
            // If `rc.width` is smaller than `width`, each register in `rc` could potentially block
            // one of ours. This is assuming that none of the smaller registers are straddling the
            // bigger ones.
            //
            // If `rc.width` is larger than `width`, we are also assuming that the registers are
            // aligned and `rc.width` is a multiple of `width`.
            let u = if rcw < width {
                // We can't take more than the total number of register units in the class.
                // This matters for arm32 S-registers which can only ever lock out 16 D-registers.
                min(rc.count * width, rc.limit * rcw)
            } else {
                rc.count * rcw
            };

            // If this top-level RC on its own is responsible for exceeding our limit, return it
            // early to guarantee that registers here are spilled before spilling other registers
            // unnecessarily.
            if u >= ulimit {
                return 1 << rci;
            }

            units += u;
        }

        // We've counted up the worst-case number of register units claimed by all aliasing
        // classes. Compare to the unit limit in this class.
        if units < ulimit {
            0
        } else {
            // Registers need to be spilled from any one of the aliasing classes.
            ((1 << num) - 1) << first
        }
    }

    /// Take a register from `rc`.
    ///
    /// This assumes that `can_take(rc)` already returned 0.
    pub fn take(&mut self, rc: RegClass) {
        self.toprc[rc.toprc as usize].count += 1
    }

    /// Free a register in `rc`.
    pub fn free(&mut self, rc: RegClass) {
        self.toprc[rc.toprc as usize].count -= 1
    }

    /// Reset all counts to 0.
    pub fn reset(&mut self) {
        for e in self.toprc.iter_mut() {
            e.count = 0;
        }
    }
}

#[cfg(test)]
mod tests {
    use isa::{TargetIsa, RegClass};
    use regalloc::AllocatableSet;
    use std::borrow::Borrow;
    use super::Pressure;

    // Make an arm32 `TargetIsa`, if possible.
    fn arm32() -> Option<Box<TargetIsa>> {
        use settings;
        use isa;

        let shared_builder = settings::builder();
        let shared_flags = settings::Flags::new(&shared_builder);

        isa::lookup("arm32").map(|b| b.finish(shared_flags))
    }

    // Get a register class by name.
    fn rc_by_name(isa: &TargetIsa, name: &str) -> RegClass {
        isa.register_info()
            .classes
            .iter()
            .find(|rc| rc.name == name)
            .expect("Can't find named register class.")
    }

    #[test]
    fn basic_counting() {
        let isa = arm32().expect("This test requires arm32 support");
        let isa = isa.borrow();
        let gpr = rc_by_name(isa, "GPR");
        let s = rc_by_name(isa, "S");
        let reginfo = isa.register_info();
        let regs = AllocatableSet::new();

        let mut pressure = Pressure::new(&reginfo, &regs);
        let mut count = 0;
        while pressure.check_avail(gpr) == 0 {
            pressure.take(gpr);
            count += 1;
        }
        assert_eq!(count, 16);
        assert_eq!(pressure.check_avail(gpr), 1 << gpr.toprc);
        assert_eq!(pressure.check_avail(s), 0);
        pressure.free(gpr);
        assert_eq!(pressure.check_avail(gpr), 0);
        pressure.take(gpr);
        assert_eq!(pressure.check_avail(gpr), 1 << gpr.toprc);
        assert_eq!(pressure.check_avail(s), 0);
        pressure.reset();
        assert_eq!(pressure.check_avail(gpr), 0);
        assert_eq!(pressure.check_avail(s), 0);
    }

    #[test]
    fn arm_float_bank() {
        let isa = arm32().expect("This test requires arm32 support");
        let isa = isa.borrow();
        let s = rc_by_name(isa, "S");
        let d = rc_by_name(isa, "D");
        let q = rc_by_name(isa, "Q");
        let reginfo = isa.register_info();
        let regs = AllocatableSet::new();

        let mut pressure = Pressure::new(&reginfo, &regs);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // Allocating a single S-register should not affect availability.
        pressure.take(s);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        pressure.take(d);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        pressure.take(q);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // Take a total of 16 S-regs.
        for _ in 1..16 {
            pressure.take(s);
        }
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // We've taken 16 S, 1 D, and 1 Q. There should be 6 more Qs.
        for _ in 0..6 {
            assert_eq!(pressure.check_avail(d), 0);
            assert_eq!(pressure.check_avail(q), 0);
            pressure.take(q);
        }

        // We've taken 16 S, 1 D, and 7 Qs.
        assert!(pressure.check_avail(s) != 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert!(pressure.check_avail(q) != 0);
    }
}
<commit_msg>Track transient register counts in Pressure.<commit_after>//! Register pressure tracking.
//!
//! SSA-based register allocation depends on a spilling phase that "lowers register pressure
//! sufficiently". This module defines the data structures needed to measure register pressure
//! accurately enough to guarantee that the coloring phase will not run out of registers.
//!
//! Ideally, measuring register pressure amounts to simply counting the number of live registers at
//! any given program point. This simplistic method has two problems:
//!
//! 1. Registers are not interchangeable. Most ISAs have separate integer and floating-point
//!    register banks, so we need to at least count the number of live registers in each register
//!    bank separately.
//!
//! 2. Some ISAs have complicated register aliasing properties. In particular, the 32-bit ARM
//!    ISA has a floating-point register bank where two 32-bit registers alias one 64-bit register.
//!    This makes it difficult to accurately measure register pressure.
//!
//! This module deals with the problems via *register banks* and *top-level register classes*.
//! Register classes in different register banks are completely independent, so we can count
//! registers in one bank without worrying about the other bank at all.
//!
//! All register classes have a unique top-level register class, and we will count registers for
//! each top-level register class individually. However, a register bank can have multiple
//! top-level register classes that interfere with each other, so all top-level counts need to
//! be considered when determining how many more registers can be allocated.
//!
//! Currently, the only register bank with multiple top-level registers is the `arm32`
//! floating-point register bank which has `S`, `D`, and `Q` top-level classes.
//!
//! # Base and transient counts
//!
//! We maintain two separate register counts per top-level register class: base counts and
//! transient counts. The base counts are adjusted with the `take` and `free` functions. The
//! transient counts are adjusted with `take_transient` and `free_transient`.

// Remove once we're using the pressure tracker.
#![allow(dead_code)]

use isa::registers::{RegInfo, MAX_TOPRCS, RegClass, RegClassMask};
use regalloc::AllocatableSet;
use std::cmp::min;
use std::iter::ExactSizeIterator;

/// Information per top-level register class.
///
/// Everything but the counts is static information computed from the constructor arguments.
#[derive(Default)]
struct TopRC {
    // Number of registers currently used from this register class.
    base_count: u32,
    transient_count: u32,

    // Max number of registers that can be allocated.
    limit: u32,

    // Register units per register.
    width: u8,

    // The first aliasing top-level RC.
    first_toprc: u8,

    // The number of aliasing top-level RCs.
    num_toprcs: u8,
}

impl TopRC {
    fn total_count(&self) -> u32 {
        self.base_count + self.transient_count
    }
}

pub struct Pressure {
    // Bit mask of top-level register classes that are aliased by other top-level register classes.
    // Unaliased register classes can use a simpler interference algorithm.
    aliased: RegClassMask,

    // Current register counts per top-level register class.
    toprc: [TopRC; MAX_TOPRCS],
}

impl Pressure {
    /// Create a new register pressure tracker.
    pub fn new(reginfo: &RegInfo, usable: &AllocatableSet) -> Pressure {
        let mut p = Pressure {
            aliased: 0,
            toprc: Default::default(),
        };

        // Get the layout of aliasing top-level register classes from the register banks.
        for bank in reginfo.banks {
            let first = bank.first_toprc;
            let num = bank.num_toprcs;
            for rc in &mut p.toprc[first..first + num] {
                rc.first_toprc = first as u8;
                rc.num_toprcs = num as u8;
            }

            // Flag the top-level register classes with aliases.
            if num > 1 {
                p.aliased |= ((1 << num) - 1) << first;
            }
        }

        // Compute per-class limits from `usable`.
        for (toprc, rc) in p.toprc
                .iter_mut()
                .take_while(|t| t.num_toprcs > 0)
                .zip(reginfo.classes) {
            toprc.limit = usable.iter(rc).len() as u32;
            toprc.width = rc.width;
        }

        p
    }

    /// Check for an available register in the register class `rc`.
    ///
    /// If it is possible to allocate one more register from `rc`'s top-level register class,
    /// returns 0.
    ///
    /// If not, returns a bit-mask of top-level register classes that are interfering. Register
    /// pressure should be eased in one of the returned top-level register classes before calling
    /// `can_take()` to check again.
    fn check_avail(&self, rc: RegClass) -> RegClassMask {
        let entry = &self.toprc[rc.toprc as usize];
        let mask = 1 << rc.toprc;
        if self.aliased & mask == 0 {
            // This is a simple unaliased top-level register class.
            if entry.total_count() < entry.limit {
                0
            } else {
                mask
            }
        } else {
            // This is the more complicated case. The top-level register class has aliases.
            self.check_avail_aliased(entry)
        }
    }

    /// Check for an available register in a top-level register class that may have aliases.
    ///
    /// This is the out-of-line slow path for `check_avail()`.
    fn check_avail_aliased(&self, entry: &TopRC) -> RegClassMask {
        let first = entry.first_toprc as usize;
        let num = entry.num_toprcs as usize;
        let width = entry.width as u32;
        let ulimit = entry.limit * width;

        // Count up the number of available register units.
        let mut units = 0;
        for (rc, rci) in self.toprc[first..first + num].iter().zip(first..) {
            let rcw = rc.width as u32;
            // If `rc.width` is smaller than `width`, each register in `rc` could potentially block
            // one of ours. This is assuming that none of the smaller registers are straddling the
            // bigger ones.
            //
            // If `rc.width` is larger than `width`, we are also assuming that the registers are
            // aligned and `rc.width` is a multiple of `width`.
            let u = if rcw < width {
                // We can't take more than the total number of register units in the class.
                // This matters for arm32 S-registers which can only ever lock out 16 D-registers.
                min(rc.total_count() * width, rc.limit * rcw)
            } else {
                rc.total_count() * rcw
            };

            // If this top-level RC on its own is responsible for exceeding our limit, return it
            // early to guarantee that registers here are spilled before spilling other registers
            // unnecessarily.
            if u >= ulimit {
                return 1 << rci;
            }

            units += u;
        }

        // We've counted up the worst-case number of register units claimed by all aliasing
        // classes. Compare to the unit limit in this class.
        if units < ulimit {
            0
        } else {
            // Registers need to be spilled from any one of the aliasing classes.
            ((1 << num) - 1) << first
        }
    }

    /// Take a register from `rc`.
    ///
    /// This does not check if there are enough registers available.
    pub fn take(&mut self, rc: RegClass) {
        self.toprc[rc.toprc as usize].base_count += 1
    }

    /// Free a register in `rc`.
    pub fn free(&mut self, rc: RegClass) {
        self.toprc[rc.toprc as usize].base_count -= 1
    }

    /// Reset all counts to 0, both base and transient.
    pub fn reset(&mut self) {
        for e in self.toprc.iter_mut() {
            e.base_count = 0;
            e.transient_count = 0;
        }
    }

    /// Try to increment a transient counter.
    ///
    /// This will fail if there are not enough registers available.
    pub fn take_transient(&mut self, rc: RegClass) -> Result<(), RegClassMask> {
        let mask = self.check_avail(rc);
        if mask == 0 {
            self.toprc[rc.toprc as usize].transient_count += 1;
            Ok(())
        } else {
            Err(mask)
        }
    }

    /// Reset all transient counts to 0.
    pub fn reset_transient(&mut self) {
        for e in self.toprc.iter_mut() {
            e.transient_count = 0;
        }
    }
}

#[cfg(test)]
mod tests {
    use isa::{TargetIsa, RegClass};
    use regalloc::AllocatableSet;
    use std::borrow::Borrow;
    use super::Pressure;

    // Make an arm32 `TargetIsa`, if possible.
    fn arm32() -> Option<Box<TargetIsa>> {
        use settings;
        use isa;

        let shared_builder = settings::builder();
        let shared_flags = settings::Flags::new(&shared_builder);

        isa::lookup("arm32").map(|b| b.finish(shared_flags))
    }

    // Get a register class by name.
    fn rc_by_name(isa: &TargetIsa, name: &str) -> RegClass {
        isa.register_info()
            .classes
            .iter()
            .find(|rc| rc.name == name)
            .expect("Can't find named register class.")
    }

    #[test]
    fn basic_counting() {
        let isa = arm32().expect("This test requires arm32 support");
        let isa = isa.borrow();
        let gpr = rc_by_name(isa, "GPR");
        let s = rc_by_name(isa, "S");
        let reginfo = isa.register_info();
        let regs = AllocatableSet::new();

        let mut pressure = Pressure::new(&reginfo, &regs);
        let mut count = 0;
        while pressure.check_avail(gpr) == 0 {
            pressure.take(gpr);
            count += 1;
        }
        assert_eq!(count, 16);
        assert_eq!(pressure.check_avail(gpr), 1 << gpr.toprc);
        assert_eq!(pressure.check_avail(s), 0);
        pressure.free(gpr);
        assert_eq!(pressure.check_avail(gpr), 0);
        pressure.take(gpr);
        assert_eq!(pressure.check_avail(gpr), 1 << gpr.toprc);
        assert_eq!(pressure.check_avail(s), 0);
        pressure.reset();
        assert_eq!(pressure.check_avail(gpr), 0);
        assert_eq!(pressure.check_avail(s), 0);
    }

    #[test]
    fn arm_float_bank() {
        let isa = arm32().expect("This test requires arm32 support");
        let isa = isa.borrow();
        let s = rc_by_name(isa, "S");
        let d = rc_by_name(isa, "D");
        let q = rc_by_name(isa, "Q");
        let reginfo = isa.register_info();
        let regs = AllocatableSet::new();

        let mut pressure = Pressure::new(&reginfo, &regs);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // Allocating a single S-register should not affect availability.
        pressure.take(s);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        pressure.take(d);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        pressure.take(q);
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // Take a total of 16 S-regs.
        for _ in 1..16 {
            pressure.take(s);
        }
        assert_eq!(pressure.check_avail(s), 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert_eq!(pressure.check_avail(q), 0);

        // We've taken 16 S, 1 D, and 1 Q. There should be 6 more Qs.
        for _ in 0..6 {
            assert_eq!(pressure.check_avail(d), 0);
            assert_eq!(pressure.check_avail(q), 0);
            pressure.take(q);
        }

        // We've taken 16 S, 1 D, and 7 Qs.
        assert!(pressure.check_avail(s) != 0);
        assert_eq!(pressure.check_avail(d), 0);
        assert!(pressure.check_avail(q) != 0);
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::fs::File;
use std::ffi::OsString;
use std::io::Write;

use app::parser::Parser;
use shell::Shell;
use args::{ArgSettings, OptBuilder};

macro_rules! w {
    ($_self:ident, $f:ident, $to_w:expr) => {
        match $f.write_all($to_w) {
            Ok(..) => (),
            Err(..) => panic!(format!("Failed to write to file completions file")),
        }
    };
}

pub struct ComplGen<'a, 'b> where 'a: 'b {
    p: &'b Parser<'a, 'b>,
    out_dir: OsString,
}

impl<'a, 'b> ComplGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>, od: OsString) -> Self {
        ComplGen {
            p: p,
            out_dir: od,
        }
    }

    pub fn generate(&self, for_shell: Shell) {
        match for_shell {
            Shell::Bash => self.gen_bash(),
        }
    }

    fn gen_bash(&self) {
        use std::error::Error;
        let out_dir = PathBuf::from(&self.out_dir);

        let mut file = match File::create(out_dir.join("bash.sh")) {
            Err(why) => panic!("couldn't create bash completion file: {}",
                why.description()),
            Ok(file) => file,
        };
        w!(self, file, format!(
"_{name}() {{
    local i cur prev opts cmds
    COMPREPLY=()
    cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
    prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"
    cmd=\"\"
    opts=\"\"

    for i in ${{COMP_WORDS[@]}}
    do
        case \"${{i}}\" in
            {name})
                cmd=\"{name}\"
                ;;
            {subcmds}
            *)
                ;;
        esac
    done

    case \"${{cmd}}\" in
        {name})
            opts=\"{name_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {name_opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;
        {subcmd_details}
    esac
}}

complete -F _{name} {name}
",
            name=self.p.meta.bin_name.as_ref().unwrap(),
            name_opts=self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
            name_opts_details=self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
            subcmds=self.all_subcommands(),
            subcmd_details=self.subcommand_details()
        ).as_bytes());
    }

    fn all_subcommands(&self) -> String {
        let mut subcmds = String::new();
        let mut scs = get_all_subcommands(self.p);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmds = format!(
                "{}
            {name})
                cmd+=\"_{name}\"
                ;;",
                subcmds,
                name=sc.replace("-", "_"));
        }

        subcmds
    }

    fn subcommand_details(&self) -> String {
        let mut subcmd_dets = String::new();
        let mut scs = get_all_subcommand_paths(self.p, true);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmd_dets = format!(
                "{}
        {subcmd})
            opts=\"{sc_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;",
                subcmd_dets,
                subcmd=sc.replace("-", "_"),
                sc_opts=self.all_options_for_path(&*sc),
                level=sc.split("_").map(|_|1).fold(0, |acc, n| acc + n),
                opts_details=self.option_details_for_path(&*sc)
            );
        }

        subcmd_dets
    }

    fn all_options_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split("_").skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands.iter().filter(|s| s.p.meta.name == sc).next().unwrap().p;
        }
        let mut opts = p.short_list.iter().fold(String::new(), |acc, s| format!("{} -{}", acc, s));
        opts = format!("{} {}", opts, p.long_list.iter()
                                                 .fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
        opts = format!("{} {}", opts, p.positionals.values()
                                                   .fold(String::new(), |acc, p| format!("{} {}", acc, p)));
        opts = format!("{} {}", opts, p.subcommands.iter()
                                                   .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)));
        opts
    }

    fn option_details_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split("_").skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands.iter().filter(|s| s.p.meta.name == sc).next().unwrap().p;
        }
        let mut opts = String::new();
        for o in &p.opts {
            if let Some(l) = o.long {
                opts = format!("{}
                --{})
                    COMPREPLY=({})
                    return 0
                    ;;", opts, l, vals_for(o));
            }
            if let Some(s) = o.short {
                opts = format!("{}
                    -{})
                    COMPREPLY=({})
                    return 0
                    ;;", opts, s, vals_for(o));
            }
        }
        opts
    }
}

pub fn get_all_subcommands(p: &Parser) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        return vec![p.meta.name.clone()]
    }
    for sc in p.subcommands.iter().map(|ref s| s.p.meta.name.clone()) {
        subcmds.push(sc);
    }
    for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommands(&s.p)) {
        subcmds.extend(sc_v);
    }
    subcmds
}

pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        if !first {
            return vec![p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "_")]
        }
        return vec![];
    }
    for sc in p.subcommands.iter()
                           .map(|ref s| s.p.meta.bin_name.as_ref()
                                                         .unwrap()
                                                         .clone()
                                                         .replace(" ", "_")) {
        subcmds.push(sc);
    }
    for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommand_paths(&s.p, false)) {
        subcmds.extend(sc_v);
    }
    subcmds
}

fn vals_for(o: &OptBuilder) -> String {
    use args::AnyArg;
    let mut ret = String::new();
    let mut needs_quotes = true;
    if let Some(ref vals) = o.possible_vals() {
        needs_quotes = false;
        ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
    } else if let Some(ref vec) = o.val_names() {
        let mut it = vec.iter().peekable();
        while let Some((_, val)) = it.next() {
            ret = format!("{}<{}>{}", ret, val,
                if it.peek().is_some() {
                    " "
                } else {
                    ""
                });
        }
        let num = vec.len();
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else if let Some(num) = o.num_vals() {
        let mut it = (0..num).peekable();
        while let Some(_) = it.next() {
            ret = format!("{}<{}>{}", ret, o.name(),
            if it.peek().is_some() {
                " "
            } else {
                ""
            });
        }
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else {
        ret = format!("<{}>", o.name());
        if o.is_set(ArgSettings::Multiple) {
            ret = format!("{}...", ret);
        }
    }
    if needs_quotes {
        ret = format!("\"{}\"", ret);
    }
    ret
}
<commit_msg>imp(Completions): completions now include aliases to subcommands, including all subcommand options<commit_after>use std::path::PathBuf;
use std::fs::File;
use std::ffi::OsString;
use std::io::Write;

use app::parser::Parser;
use shell::Shell;
use args::{ArgSettings, OptBuilder};

macro_rules! w {
    ($_self:ident, $f:ident, $to_w:expr) => {
        match $f.write_all($to_w) {
            Ok(..) => (),
            Err(..) => panic!(format!("Failed to write to file completions file")),
        }
    };
}

pub struct ComplGen<'a, 'b> where 'a: 'b {
    p: &'b Parser<'a, 'b>,
    out_dir: OsString,
}

impl<'a, 'b> ComplGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>, od: OsString) -> Self {
        ComplGen {
            p: p,
            out_dir: od,
        }
    }

    pub fn generate(&self, for_shell: Shell) {
        match for_shell {
            Shell::Bash => self.gen_bash(),
        }
    }

    fn gen_bash(&self) {
        use std::error::Error;
        let out_dir = PathBuf::from(&self.out_dir);

        let mut file = match File::create(out_dir.join("bash.sh")) {
            Err(why) => panic!("couldn't create bash completion file: {}",
                why.description()),
            Ok(file) => file,
        };
        w!(self, file, format!(
"_{name}() {{
    local i cur prev opts cmds
    COMPREPLY=()
    cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
    prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"
    cmd=\"\"
    opts=\"\"

    for i in ${{COMP_WORDS[@]}}
    do
        case \"${{i}}\" in
            {name})
                cmd=\"{name}\"
                ;;
            {subcmds}
            *)
                ;;
        esac
    done

    case \"${{cmd}}\" in
        {name})
            opts=\"{name_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {name_opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;
        {subcmd_details}
    esac
}}

complete -F _{name} {name}
",
            name=self.p.meta.bin_name.as_ref().unwrap(),
            name_opts=self.all_options_for_path(self.p.meta.bin_name.as_ref().unwrap()),
            name_opts_details=self.option_details_for_path(self.p.meta.bin_name.as_ref().unwrap()),
            subcmds=self.all_subcommands(),
            subcmd_details=self.subcommand_details()
        ).as_bytes());
    }

    fn all_subcommands(&self) -> String {
        let mut subcmds = String::new();
        let scs = get_all_subcommands(self.p);

        for sc in &scs {
            subcmds = format!(
                "{}
            {name})
                cmd+=\"_{name}\"
                ;;",
                subcmds,
                name=sc.replace("-", "_"));
        }

        subcmds
    }

    fn subcommand_details(&self) -> String {
        let mut subcmd_dets = String::new();
        let mut scs = get_all_subcommand_paths(self.p, true);
        scs.sort();
        scs.dedup();

        for sc in &scs {
            subcmd_dets = format!(
                "{}
        {subcmd})
            opts=\"{sc_opts}\"
            if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
                COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
                return 0
            fi
            case \"${{prev}}\" in
                {opts_details}
                *)
                    COMPREPLY=()
                    ;;
            esac
            COMPREPLY=( $(compgen -W \"${{opts}}\" -- ${{cur}}) )
            return 0
            ;;",
                subcmd_dets,
                subcmd=sc.replace("-", "_"),
                sc_opts=self.all_options_for_path(&*sc),
                level=sc.split("_").map(|_|1).fold(0, |acc, n| acc + n),
                opts_details=self.option_details_for_path(&*sc)
            );
        }

        subcmd_dets
    }

    fn all_options_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split("_").skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands.iter()
                              .filter(|s| s.p.meta.name == sc
                                  || (s.p.meta.aliases.is_some() && s.p.meta.aliases.as_ref()
                                                                                .unwrap()
                                                                                .iter()
                                                                                .any(|&(n,_)| n==sc )))
                              .next()
                              .unwrap().p;
        }
        let mut opts = p.short_list.iter().fold(String::new(), |acc, s| format!("{} -{}", acc, s));
        opts = format!("{} {}", opts, p.long_list.iter()
                                                 .fold(String::new(), |acc, l| format!("{} --{}", acc, l)));
        opts = format!("{} {}", opts, p.positionals.values()
                                                   .fold(String::new(), |acc, p| format!("{} {}", acc, p)));
        opts = format!("{} {}", opts, p.subcommands.iter()
                                                   .fold(String::new(), |acc, s| format!("{} {}", acc, s.p.meta.name)));
        for sc in &p.subcommands {
            if let Some(ref aliases) = sc.p.meta.aliases {
                opts = format!("{} {}", opts, aliases.iter().map(|&(n,_)| n).fold(String::new(), |acc, a| format!("{} {}", acc, a)));
            }
        }
        opts
    }

    fn option_details_for_path(&self, path: &str) -> String {
        let mut p = self.p;
        for sc in path.split("_").skip(1) {
            debugln!("iter;sc={}", sc);
            p = &p.subcommands.iter().filter(|s| s.p.meta.name == sc || (s.p.meta.aliases.is_some() && s.p.meta.aliases.as_ref().unwrap().iter().any(|&(n,_)| n==sc ))).next().unwrap().p;
        }
        let mut opts = String::new();
        for o in &p.opts {
            if let Some(l) = o.long {
                opts = format!("{}
                --{})
                    COMPREPLY=({})
                    return 0
                    ;;", opts, l, vals_for(o));
            }
            if let Some(s) = o.short {
                opts = format!("{}
                    -{})
                    COMPREPLY=({})
                    return 0
                    ;;", opts, s, vals_for(o));
            }
        }
        opts
    }
}

pub fn get_all_subcommands(p: &Parser) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        let mut ret = vec![p.meta.name.clone()];
        if let Some(ref aliases) = p.meta.aliases {
            for &(n, _) in aliases {
                ret.push(n.to_owned());
            }
        }
        return ret;
    }
    for sc in &p.subcommands {
        if let Some(ref aliases) = sc.p.meta.aliases {
            for &(n, _) in aliases {
                subcmds.push(n.to_owned());
            }
        }
        subcmds.push(sc.p.meta.name.clone());
    }
    for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommands(&s.p)) {
        subcmds.extend(sc_v);
    }
    subcmds.sort();
    subcmds.dedup();
    subcmds
}

pub fn get_all_subcommand_paths(p: &Parser, first: bool) -> Vec<String> {
    let mut subcmds = vec![];
    if !p.has_subcommands() {
        if !first {
            let name = &*p.meta.name;
            let path = p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "_");
            let mut ret = vec![path.clone()];
            if let Some(ref aliases) = p.meta.aliases {
                for &(n, _) in aliases {
                    ret.push(path.replace(name, n));
                }
            }
            return ret;
        }
        return vec![];
    }
    for sc in &p.subcommands {
        let name = &*sc.p.meta.name;
        let path = sc.p.meta.bin_name.as_ref().unwrap().clone().replace(" ", "_");
        subcmds.push(path.clone());
        if let Some(ref aliases) = sc.p.meta.aliases {
            for &(n, _) in aliases {
                subcmds.push(path.replace(name, n));
            }
        }
    }
    for sc_v in p.subcommands.iter().map(|ref s| get_all_subcommand_paths(&s.p, false)) {
        subcmds.extend(sc_v);
    }
    subcmds
}

fn vals_for(o: &OptBuilder) -> String {
    use args::AnyArg;
    let mut ret = String::new();
    let mut needs_quotes = true;
    if let Some(ref vals) = o.possible_vals() {
        needs_quotes = false;
        ret = format!("$(compgen -W \"{}\" -- ${{cur}})", vals.join(" "));
    } else if let Some(ref vec) = o.val_names() {
        let mut it = vec.iter().peekable();
        while let Some((_, val)) = it.next() {
            ret = format!("{}<{}>{}", ret, val,
                if it.peek().is_some() {
                    " "
                } else {
                    ""
                });
        }
        let num = vec.len();
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else if let Some(num) = o.num_vals() {
        let mut it = (0..num).peekable();
        while let Some(_) = it.next() {
            ret = format!("{}<{}>{}", ret, o.name(),
            if it.peek().is_some() {
                " "
            } else {
                ""
            });
        }
        if o.is_set(ArgSettings::Multiple) && num == 1 {
            ret = format!("{}...", ret);
        }
    } else {
        ret = format!("<{}>", o.name());
        if o.is_set(ArgSettings::Multiple) {
            ret = format!("{}...", ret);
        }
    }
    if needs_quotes {
        ret = format!("\"{}\"", ret);
    }
    ret
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]
//! It module contains Rust representation of Cassandra consistency levels.
use super::{IntoBytes};
use super::types::*;
use super::FromBytes;

/// `Consistency` is an enum which represents Cassandra's consistency levels.
pub enum Consistency {
    #[allow(missing_docs)]
    Any,
    #[allow(missing_docs)]
    One,
    #[allow(missing_docs)]
    Two,
    #[allow(missing_docs)]
    Three,
    #[allow(missing_docs)]
    Quorum,
    #[allow(missing_docs)]
    All,
    #[allow(missing_docs)]
    LocalQuorum,
    #[allow(missing_docs)]
    EachQuorum,
    #[allow(missing_docs)]
    Serial,
    #[allow(missing_docs)]
    LocalSerial,
    #[allow(missing_docs)]
    LocalOne
}

impl IntoBytes for Consistency {
    fn into_cbytes(&self) -> Vec<u8> {
        return match self {
            &Consistency::Any => to_short(0x0000),
            &Consistency::One => to_short(0x0001),
            &Consistency::Two => to_short(0x0002),
            &Consistency::Three => to_short(0x0003),
            &Consistency::Quorum => to_short(0x0004),
            &Consistency::All => to_short(0x0005),
            &Consistency::LocalQuorum => to_short(0x0006),
            &Consistency::EachQuorum => to_short(0x0007),
            &Consistency::Serial => to_short(0x0008),
            &Consistency::LocalSerial => to_short(0x0009),
            &Consistency::LocalOne => to_short(0x000A)
        };
    }
}

impl FromBytes for Consistency {
    fn from_bytes(bytes: Vec<u8>) -> Consistency {
        return match from_bytes(bytes.clone()) {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => {
                error!("Unexpected Cassandra consistency: {:?}", bytes);
                panic!("Unexpected Cassandra consistency: {:?}", bytes);
            }
        };
    }
}
<commit_msg>Add some rustdocs<commit_after>#![warn(missing_docs)]
//! The module contains Rust representation of Cassandra consistency levels.
use super::{IntoBytes};
use super::types::*;
use super::FromBytes;

/// `Consistency` is an enum which represents Cassandra's consistency levels.
pub enum Consistency {
    #[allow(missing_docs)]
    Any,
    #[allow(missing_docs)]
    One,
    #[allow(missing_docs)]
    Two,
    #[allow(missing_docs)]
    Three,
    #[allow(missing_docs)]
    Quorum,
    #[allow(missing_docs)]
    All,
    #[allow(missing_docs)]
    LocalQuorum,
    #[allow(missing_docs)]
    EachQuorum,
    #[allow(missing_docs)]
    Serial,
    #[allow(missing_docs)]
    LocalSerial,
    #[allow(missing_docs)]
    LocalOne
}

impl IntoBytes for Consistency {
    fn into_cbytes(&self) -> Vec<u8> {
        return match self {
            &Consistency::Any => to_short(0x0000),
            &Consistency::One => to_short(0x0001),
            &Consistency::Two => to_short(0x0002),
            &Consistency::Three => to_short(0x0003),
            &Consistency::Quorum => to_short(0x0004),
            &Consistency::All => to_short(0x0005),
            &Consistency::LocalQuorum => to_short(0x0006),
            &Consistency::EachQuorum => to_short(0x0007),
            &Consistency::Serial => to_short(0x0008),
            &Consistency::LocalSerial => to_short(0x0009),
            &Consistency::LocalOne => to_short(0x000A)
        };
    }
}

impl FromBytes for Consistency {
    fn from_bytes(bytes: Vec<u8>) -> Consistency {
        return match from_bytes(bytes.clone()) {
            0x0000 => Consistency::Any,
            0x0001 => Consistency::One,
            0x0002 => Consistency::Two,
            0x0003 => Consistency::Three,
            0x0004 => Consistency::Quorum,
            0x0005 => Consistency::All,
            0x0006 => Consistency::LocalQuorum,
            0x0007 => Consistency::EachQuorum,
            0x0008 => Consistency::Serial,
            0x0009 => Consistency::LocalSerial,
            0x000A => Consistency::LocalOne,
            _ => {
                error!("Unexpected Cassandra consistency: {:?}", bytes);
                panic!("Unexpected Cassandra consistency: {:?}", bytes);
            }
        };
    }
}
<|endoftext|>


<commit_before>use cudnn::ffi;
use cudnn::{Tensor, Filter4d, Convolution2d};
use cudart::Memory;
use std::ptr;

pub struct Cudnn {
    handle: ffi::Handle
}

impl Drop for Cudnn {
    fn drop(&mut self) {
        unsafe { ffi::cudnnDestroy(self.handle) };
    }
}

impl Cudnn {
    pub fn new() -> Result<Cudnn, &'static str> {
        let mut handle: ffi::Handle = ptr::null_mut();
        match unsafe { ffi::cudnnCreate(&mut handle) } {
            ffi::Status::Success => Ok(Cudnn { handle : handle }),
            e => Err(e.to_str())
        }
    }

    pub fn sigmoid_forward(self,
                           src_desc: Tensor,
                           src: &Memory<f32>,
                           dst_desc: Tensor,
                           dst: &mut Memory<f32>) -> Result<(), &'static str> {
        match unsafe { ffi::cudnnActivationForward(self.handle,
                                                   ffi::ActivationDescriptor::Sigmoid,
                                                   *&[1.0f32].as_ptr() as *const ::libc::c_void,
                                                   src_desc.desc,
                                                   src.data,
                                                   *&[0.0f32].as_ptr() as *const ::libc::c_void,
                                                   dst_desc.desc,
                                                   dst.data) } {
            ffi::Status::Success => Ok(()),
            e => Err(e.to_str())
        }
    }

    pub fn get_conv_forward_algo(&self,
                                 x_desc: &Tensor,
                                 w_desc: &Filter4d,
                                 conv_desc: &Convolution2d,
                                 y_desc: &Tensor) -> Result<ffi::ConvolutionFwdAlgo, &'static str> {
        let mut res = ffi::ConvolutionFwdAlgo::ImplicitGemm;
        match unsafe { ffi::cudnnGetConvolutionForwardAlgorithm(self.handle,
                                                                x_desc.desc,
                                                                w_desc.desc,
                                                                conv_desc.desc,
                                                                y_desc.desc,
                                                                ffi::ConvolutionFwdPreference::PreferFastest,
                                                                0,
                                                                &mut res) } {
            ffi::Status::Success => Ok(res),
            e => Err(e.to_str())
        }
    }

    pub fn get_conv_forward_workspace_size(&self,
                                           x_desc: &Tensor,
                                           w_desc: &Filter4d,
                                           conv_desc: &Convolution2d,
                                           y_desc: &Tensor,
                                           algo: ffi::ConvolutionFwdAlgo) -> Result<usize, &'static str> {

        let mut res = 0usize;
        match unsafe { ffi::cudnnGetConvolutionForwardWorkspaceSize(self.handle,
                                                                    x_desc.desc,
                                                                    w_desc.desc,
                                                                    conv_desc.desc,
                                                                    y_desc.desc,
                                                                    algo,
                                                                    &mut res) } {
            ffi::Status::Success => Ok(res),
            e => Err(e.to_str())
        }
    }

    pub fn conv_forward(&self,
                        x_desc: &Tensor,
                        x: &Memory<f32>,
                        w_desc: &Filter4d,
                        w: &Memory<f32>,
                        conv_desc: &Convolution2d,
                        y_desc: &Tensor,
                        y: &Memory<f32>) -> Result<(), &'static str> {
        let alpha = 1f32;
        let beta = 0f32;
        let algo = try!(self.get_conv_forward_algo(&x_desc,
                                                   &w_desc,
                                                   &conv_desc,
                                                   &y_desc));
        let workspace_size = try!(self.get_conv_forward_workspace_size(&x_desc,
                                                                       &w_desc,
                                                                       &conv_desc,
                                                                       &y_desc,
                                                                       algo));
        let workspace = try!(Memory::<f32>::new(workspace_size / 4));
        match unsafe { ffi::cudnnConvolutionForward(self.handle,
                                                    &alpha as *const _ as *const ::libc::c_void,
                                                    x_desc.desc,
                                                    x.data,
                                                    w_desc.desc,
                                                    w.data,
                                                    conv_desc.desc,
                                                    algo,
                                                    workspace.data,
                                                    workspace_size,
                                                    &beta as *const _ as *const ::libc::c_void,
                                                    y_desc.desc,
                                                    y.data) } {
            ffi::Status::Success => Ok(()),
            e => Err(e.to_str())
        }
    }

    pub fn conv_forward_src(&self,
                            x_desc: &Tensor,
                            x: &Memory<f32>,
                            w_desc: &Filter4d,
                            w: &Memory<f32>,
                            conv_desc: &Convolution2d,
                            y_desc: &Tensor) -> Result<(), &'static str> {
        let alpha = 1f32;
        let beta = 0f32;
        let algo = try!(self.get_conv_forward_algo(&x_desc,
                                                   &w_desc,
                                                   &conv_desc,
                                                   &y_desc));
        let workspace_size = try!(self.get_conv_forward_workspace_size(&x_desc,
                                                                       &w_desc,
                                                                       &conv_desc,
                                                                       &y_desc,
                                                                       algo));
        let workspace = try!(Memory::<f32>::new(workspace_size / 4));
        match unsafe { ffi::cudnnConvolutionForward(self.handle,
                                                    &alpha as *const _ as *const ::libc::c_void,
                                                    x_desc.desc,
                                                    x.data,
                                                    w_desc.desc,
                                                    w.data,
                                                    conv_desc.desc,
                                                    algo,
                                                    workspace.data,
                                                    workspace_size,
                                                    &beta as *const _ as *const ::libc::c_void,
                                                    y_desc.desc,
                                                    x.data) } {
            ffi::Status::Success => Ok(()),
            e => Err(e.to_str())
        }
    }
}
<commit_msg>preferring saving memory<commit_after>use cudnn::ffi;
use cudnn::{Tensor, Filter4d, Convolution2d};
use cudart::Memory;
use std::ptr;

pub struct Cudnn {
    handle: ffi::Handle
}

impl Drop for Cudnn {
    fn drop(&mut self) {
        unsafe { ffi::cudnnDestroy(self.handle) };
    }
}

impl Cudnn {
    pub fn new() -> Result<Cudnn, &'static str> {
        let mut handle: ffi::Handle = ptr::null_mut();
        match unsafe { ffi::cudnnCreate(&mut handle) } {
            ffi::Status::Success => Ok(Cudnn { handle : handle }),
            e => Err(e.to_str())
        }
    }

    pub fn sigmoid_forward(self,
                           src_desc: Tensor,
                           src: &Memory<f32>,
                           dst_desc: Tensor,
                           dst: &mut Memory<f32>) -> Result<(), &'static str> {
        match unsafe { ffi::cudnnActivationForward(self.handle,
                                                   ffi::ActivationDescriptor::Sigmoid,
                                                   *&[1.0f32].as_ptr() as *const ::libc::c_void,
                                                   src_desc.desc,
                                                   src.data,
                                                   *&[0.0f32].as_ptr() as *const ::libc::c_void,
                                                   dst_desc.desc,
                                                   dst.data) } {
            ffi::Status::Success => Ok(()),
            e => Err(e.to_str())
        }
    }

    pub fn get_conv_forward_algo(&self,
                                 x_desc: &Tensor,
                                 w_desc: &Filter4d,
                                 conv_desc: &Convolution2d,
                                 y_desc: &Tensor) -> Result<ffi::ConvolutionFwdAlgo, &'static str> {
        let mut res = ffi::ConvolutionFwdAlgo::ImplicitGemm;
        match unsafe { ffi::cudnnGetConvolutionForwardAlgorithm(self.handle,
                                                                x_desc.desc,
                                                                w_desc.desc,
                                                                conv_desc.desc,
                                                                y_desc.desc,
                                                                ffi::ConvolutionFwdPreference::NoWorkspace,
                                                                0,
                                                                &mut res) } {
            ffi::Status::Success => Ok(res),
            e => Err(e.to_str())
        }
    }

    pub fn get_conv_forward_workspace_size(&self,
                                           x_desc: &Tensor,
                                           w_desc: &Filter4d,
                                           conv_desc: &Convolution2d,
                                           y_desc: &Tensor,
                                           algo: ffi::ConvolutionFwdAlgo) -> Result<usize, &'static str> {

        let mut res = 0usize;
        match unsafe { ffi::cudnnGetConvolutionForwardWorkspaceSize(self.handle,
                                                                    x_desc.desc,
                                                                    w_desc.desc,
                                                                    conv_desc.desc,
                                                                    y_desc.desc,
                                                                    algo,
                                                                    &mut res) } {
            ffi::Status::Success => Ok(res),
            e => Err(e.to_str())
        }
    }

    pub fn conv_forward(&self,
                        x_desc: &Tensor,
                        x: &Memory<f32>,
                        w_desc: &Filter4d,
                        w: &Memory<f32>,
                        conv_desc: &Convolution2d,
                        y_desc: &Tensor,
                        y: &Memory<f32>) -> Result<(), &'static str> {
        let alpha = 1f32;
        let beta = 0f32;
        let algo = try!(self.get_conv_forward_algo(&x_desc,
                                                   &w_desc,
                                                   &conv_desc,
                                                   &y_desc));
        let workspace_size = try!(self.get_conv_forward_workspace_size(&x_desc,
                                                                       &w_desc,
                                                                       &conv_desc,
                                                                       &y_desc,
                                                                       algo));
        let workspace = try!(Memory::<f32>::new(workspace_size / 4));
        match unsafe { ffi::cudnnConvolutionForward(self.handle,
                                                    &alpha as *const _ as *const ::libc::c_void,
                                                    x_desc.desc,
                                                    x.data,
                                                    w_desc.desc,
                                                    w.data,
                                                    conv_desc.desc,
                                                    algo,
                                                    workspace.data,
                                                    workspace_size,
                                                    &beta as *const _ as *const ::libc::c_void,
                                                    y_desc.desc,
                                                    y.data) } {
            ffi::Status::Success => Ok(()),
            e => Err(e.to_str())
        }
    }

    pub fn conv_forward_src(&self,
                            x_desc: &Tensor,
                            x: &Memory<f32>,
                            w_desc: &Filter4d,
                            w: &Memory<f32>,
                            conv_desc: &Convolution2d,
                            y_desc: &Tensor) -> Result<(), &'static str> {
        let alpha = 1f32;
        let beta = 0f32;
        let algo = try!(self.get_conv_forward_algo(&x_desc,
                                                   &w_desc,
                                                   &conv_desc,
                                                   &y_desc));
        let workspace_size = try!(self.get_conv_forward_workspace_size(&x_desc,
                                                                       &w_desc,
                                                                       &conv_desc,
                                                                       &y_desc,
                                                                       algo));
        let workspace = try!(Memory::<f32>::new(workspace_size / 4));
        match unsafe { ffi::cudnnConvolutionForward(self.handle,
                                                    &alpha as *const _ as *const ::libc::c_void,
                                                    x_desc.desc,
                                                    x.data,
                                                    w_desc.desc,
                                                    w.data,
                                                    conv_desc.desc,
                                                    algo,
                                                    workspace.data,
                                                    workspace_size,
                                                    &beta as *const _ as *const ::libc::c_void,
                                                    y_desc.desc,
                                                    x.data) } {
            ffi::Status::Success => Ok(()),
            e => Err(e.to_str())
        }
    }
}
<|endoftext|>


<commit_before>use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::GlContext;

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct GlutinWindow {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl GlutinWindow {
  pub fn new() -> GlutinWindow {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      window_title.with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) = gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    GlutinWindow {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for GlutinWindow {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    (RESOLUTION_X as f32, RESOLUTION_Y as f32)
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.hidpi_factor()
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }
  fn poll_events(&mut self) -> WindowStatus {
    use glutin::KeyboardInput;
    use glutin::MouseButton;
    use glutin::WindowEvent::{Resized, CloseRequested, CursorMoved, MouseInput};
    use glutin::ElementState::{Pressed, Released};
    use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };
    let window = &self.window;

    let m_rtv = &mut self.render_target_view;
    let m_dsv = &mut self.depth_stencil_view;
    let m_pos = &mut self.mouse_pos;

    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => match input {
            KeyboardInput { virtual_keycode: Some(Escape), .. } => WindowStatus::Close,
            KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
              controls.zoom_out();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
              controls.zoom_in();
              WindowStatus::Open
            }
            KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
              controls.zoom_stop();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
              controls.move_character_up();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
              controls.move_character_down();
              WindowStatus::Open
            }
            KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
              controls.stop_character_y();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
              controls.move_character_left();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
              controls.move_character_right();
              WindowStatus::Open
            }
            KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
              controls.stop_character_x();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, modifiers, .. } => {
              if modifiers.ctrl {
                controls.ctrl_pressed();
              }
              WindowStatus::Open
            }
            KeyboardInput { state: Released, modifiers, .. } => {
              if !modifiers.ctrl {
                controls.ctrl_released();
              }
              WindowStatus::Open
            }
          },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          Resized(w, h) => {
            window.resize(w, h);
            gfx_window_glutin::update_views(&window, m_rtv, m_dsv);
            WindowStatus::Open
          }
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }
}

<commit_msg>Remove broken window resizing<commit_after>use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::GlContext;

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct GlutinWindow {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl GlutinWindow {
  pub fn new() -> GlutinWindow {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      window_title
        .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_min_dimensions(RESOLUTION_X, RESOLUTION_Y)
        .with_max_dimensions(RESOLUTION_X, RESOLUTION_Y)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("Please enter a valid ID")
      };
      window_title.with_fullscreen(Some(monitor))
                  .with_dimensions(RESOLUTION_X, RESOLUTION_Y)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8)
      .with_gl(glutin::GlRequest::GlThenGles {
        opengles_version: (3, 0),
        opengl_version: (4, 1),
      });

    let (window, device, factory, rtv, dsv) = gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    GlutinWindow {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for GlutinWindow {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    (RESOLUTION_X as f32, RESOLUTION_Y as f32)
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.hidpi_factor()
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }
  fn poll_events(&mut self) -> WindowStatus {
    use glutin::KeyboardInput;
    use glutin::MouseButton;
    use glutin::WindowEvent::{CloseRequested, CursorMoved, MouseInput};
    use glutin::ElementState::{Pressed, Released};
    use glutin::VirtualKeyCode::{Escape, Z, X, W, A, S, D};

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };

    let m_pos = &mut self.mouse_pos;

    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => match input {
            KeyboardInput { virtual_keycode: Some(Escape), .. } => WindowStatus::Close,
            KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
              controls.zoom_out();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
              controls.zoom_in();
              WindowStatus::Open
            }
            KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
              controls.zoom_stop();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
              controls.move_character_up();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
              controls.move_character_down();
              WindowStatus::Open
            }
            KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
              controls.stop_character_y();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
              controls.move_character_left();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
              controls.move_character_right();
              WindowStatus::Open
            }
            KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
            KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
              controls.stop_character_x();
              WindowStatus::Open
            }
            KeyboardInput { state: Pressed, modifiers, .. } => {
              if modifiers.ctrl {
                controls.ctrl_pressed();
              }
              WindowStatus::Open
            }
            KeyboardInput { state: Released, modifiers, .. } => {
              if !modifiers.ctrl {
                controls.ctrl_released();
              }
              WindowStatus::Open
            }
          },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = position;
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }
}

<|endoftext|>


<commit_before>use std::marker;
use std::collections::HashMap;

use solicit::http::client::RequestStream;
use solicit::http::client::ClientSession;
use solicit::http::session::Client;
use solicit::http::session::SessionState;
use solicit::http::session::DefaultSessionState;
use solicit::http::session::DefaultStream;
use solicit::http::session::StreamState;
use solicit::http::session::StreamDataError;
use solicit::http::session::StreamDataChunk;
use solicit::http::session::Stream as solicit_Stream;
use solicit::http::session::StreamIter;
use solicit::http::connection::HttpConnection;
use solicit::http::connection::SendStatus;
use solicit::http::connection::EndStream;
use solicit::http::connection::DataChunk;
use solicit::http::priority::SimplePrioritizer;
use solicit::http::frame::RawFrame;
use solicit::http::StreamId;
use solicit::http::HttpScheme;
use solicit::http::HttpError;
use solicit::http::Header;
use solicit::http::StaticHeader;

use futures;
use futures::Future;
use futures::stream::Stream;

use tokio_core;
use tokio_core::TcpStream;
use tokio_core::io::TaskIo;
use tokio_core::io::TaskIoRead;
use tokio_core::io::TaskIoWrite;
use tokio_core::LoopHandle;

use error::*;
use futures_misc::*;

use solicit_async::*;

struct GrpcHttp2ClientStream2 {
    state: StreamState,
}

impl solicit_Stream for GrpcHttp2ClientStream2 {
    fn new_data_chunk(&mut self, data: &[u8]) {
    }

    fn set_headers<'n, 'v>(&mut self, headers: Vec<Header<'n, 'v>>) {
    }

    fn set_state(&mut self, state: StreamState) {
        self.state = state;
    }

    fn get_data_chunk(&mut self, buf: &mut [u8]) -> Result<StreamDataChunk, StreamDataError> {
        unimplemented!()
    }

    fn state(&self) -> StreamState {
        self.state
    }
}

struct Inner {
    host: String,
    conn: HttpConnection,
    streams: HashMap<StreamId, GrpcHttp2ClientStream2>,
    next_stream_id: StreamId,
}

impl SessionState for Inner {
    type Stream = GrpcHttp2ClientStream2;

    fn insert_outgoing(&mut self, stream: Self::Stream) -> StreamId {
        let id = self.next_stream_id;
        self.streams.insert(id, stream);
        self.next_stream_id += 2;
        id
    }

    fn insert_incoming(&mut self, stream_id: StreamId, stream: Self::Stream) -> Result<(), ()> {
        // TODO: assert parity
        // TODO: Assert that the stream IDs are monotonically increasing!
        self.streams.insert(stream_id, stream);
        Ok(())
    }

    #[inline]
    fn get_stream_ref(&self, stream_id: StreamId) -> Option<&Self::Stream> {
        self.streams.get(&stream_id)
    }

    #[inline]
    fn get_stream_mut(&mut self, stream_id: StreamId) -> Option<&mut Self::Stream> {
        self.streams.get_mut(&stream_id)
    }

    #[inline]
    fn remove_stream(&mut self, stream_id: StreamId) -> Option<Self::Stream> {
        self.streams.remove(&stream_id)
    }

    #[inline]
    fn iter(&mut self) -> StreamIter<GrpcHttp2ClientStream2> {
        // https://github.com/mlalic/solicit/pull/34
        unimplemented!()
    }

    /// Number of currently active streams
    #[inline]
    fn len(&self) -> usize {
        self.streams.len()
    }
}

struct HttpConnectionAsync<H : ResponseHandler> {
    _marker: marker::PhantomData<H>,
    inner: TaskRcMut<Inner>,
    call_tx: tokio_core::Sender<ToWriteMessage<H>>,
}

trait ResponseHandler : Send + 'static {
    fn headers(self) -> HttpFuture<Self>;
    fn body_chunk(self) -> HttpFuture<Self>;
    fn end(self) -> HttpFuture<()>;
}

struct StartRequestMessage<H : ResponseHandler> {
    headers: Vec<()>,
    body: HttpStream<Vec<u8>>,
    response_handler: H,
}

struct ReadToWriteMessage {

}

enum ToWriteMessage<H : ResponseHandler> {
    Start(StartRequestMessage<H>),
    FromRead(ReadToWriteMessage),
}

fn run_write<H : ResponseHandler>(
    write: TaskIoWrite<TcpStream>,
    inner: TaskRcMut<Inner>,
    requests: tokio_core::Receiver<ToWriteMessage<H>>)
        -> HttpFuture<()>
{
    let requests = requests.map_err(HttpError::from);
    requests.fold((), |_, _| {
        futures::finished::<_, HttpError>(())
    }).boxed()
}

struct ReadLoop {
    read: TaskIoRead<TcpStream>,
    inner: TaskRcMut<Inner>,
}

impl ReadLoop {
    fn recv_raw_frame(self) -> HttpFuture<(Self, RawFrame<'static>)> {
        let ReadLoop { read, inner } = self;
        recv_raw_frame(read)
            .map(|(read, frame)| (ReadLoop { read: read, inner: inner}, frame))
            .map_err(HttpError::from)
            .boxed()
    }

    fn read_process_frame(self) -> HttpFuture<Self> {
        self.recv_raw_frame()
            .map(|(rl, frame)| rl)
            .boxed()
    }

    fn run(self) -> HttpFuture<()> {
        let stream = stream_repeat(());

        let future = stream.fold(self, |rl, _| {
            rl.read_process_frame()
        });

        future.map(|_| ()).boxed()
    }
}

impl<H : ResponseHandler> HttpConnectionAsync<H> {
    fn new(lh: LoopHandle, conn: TcpStream) -> HttpFuture<(Self, HttpFuture<()>)> {
        let (call_tx, call_rx) = lh.channel();

        let handshake = client_handshake(conn);
        handshake.and_then(move |conn| {
            let (read, write) = TaskIo::new(conn).split();

            let inner = TaskRcMut::new(Inner {
                host: "localhost".to_owned(), // TODO
                conn: HttpConnection::new(HttpScheme::Http),
                next_stream_id: 1,
                streams: HashMap::new(),
            });

            let write_inner = inner.clone();
            let run_write = call_rx.map_err(HttpError::from).and_then(move |call_rx| run_write(write, write_inner, call_rx));
            let run_read = ReadLoop { read: read, inner: inner.clone() }.run();

            let c = HttpConnectionAsync {
                _marker: marker::PhantomData,
                inner: inner,
                call_tx: call_tx,
            };
            Ok((c, run_write.join(run_read).map(|_| ()).boxed()))
        }).boxed()
    }

    fn start_request(
        &self,
        headers: Vec<()>,
        body: HttpStream<Vec<u8>>,
        response_handler: H)
            -> HttpFuture<()>
    {
        self.call_tx.send(ToWriteMessage::Start(StartRequestMessage {
            headers: headers,
            body: body,
            response_handler: response_handler,
        }));
        futures::finished(()).boxed()
    }
}
<commit_msg>working on http client<commit_after>use std::marker;
use std::collections::HashMap;

use solicit::http::client::RequestStream;
use solicit::http::client::ClientSession;
use solicit::http::session::Client;
use solicit::http::session::SessionState;
use solicit::http::session::DefaultSessionState;
use solicit::http::session::DefaultStream;
use solicit::http::session::StreamState;
use solicit::http::session::StreamDataError;
use solicit::http::session::StreamDataChunk;
use solicit::http::session::Stream as solicit_Stream;
use solicit::http::session::StreamIter;
use solicit::http::connection::HttpConnection;
use solicit::http::connection::SendStatus;
use solicit::http::connection::EndStream;
use solicit::http::connection::DataChunk;
use solicit::http::priority::SimplePrioritizer;
use solicit::http::frame::RawFrame;
use solicit::http::StreamId;
use solicit::http::HttpScheme;
use solicit::http::HttpError;
use solicit::http::Header;
use solicit::http::StaticHeader;

use futures;
use futures::Future;
use futures::stream::Stream;

use tokio_core;
use tokio_core::TcpStream;
use tokio_core::io as tokio_io;
use tokio_core::io::TaskIo;
use tokio_core::io::TaskIoRead;
use tokio_core::io::TaskIoWrite;
use tokio_core::LoopHandle;

use error::*;
use futures_misc::*;

use solicit_async::*;

struct GrpcHttp2ClientStream2 {
    state: StreamState,
}

impl solicit_Stream for GrpcHttp2ClientStream2 {
    fn new_data_chunk(&mut self, data: &[u8]) {
    }

    fn set_headers<'n, 'v>(&mut self, headers: Vec<Header<'n, 'v>>) {
    }

    fn set_state(&mut self, state: StreamState) {
        self.state = state;
    }

    fn get_data_chunk(&mut self, buf: &mut [u8]) -> Result<StreamDataChunk, StreamDataError> {
        unimplemented!()
    }

    fn state(&self) -> StreamState {
        self.state
    }
}

struct Inner<H : ResponseHandler> {
    host: String,
    conn: HttpConnection,
    streams: HashMap<StreamId, GrpcHttp2ClientStream2>,
    next_stream_id: StreamId,
    _phantom_data: marker::PhantomData<H>,
}

impl<H : ResponseHandler> SessionState for Inner<H> {
    type Stream = GrpcHttp2ClientStream2;

    fn insert_outgoing(&mut self, stream: Self::Stream) -> StreamId {
        let id = self.next_stream_id;
        self.streams.insert(id, stream);
        self.next_stream_id += 2;
        id
    }

    fn insert_incoming(&mut self, stream_id: StreamId, stream: Self::Stream) -> Result<(), ()> {
        // TODO: assert parity
        // TODO: Assert that the stream IDs are monotonically increasing!
        self.streams.insert(stream_id, stream);
        Ok(())
    }

    #[inline]
    fn get_stream_ref(&self, stream_id: StreamId) -> Option<&Self::Stream> {
        self.streams.get(&stream_id)
    }

    #[inline]
    fn get_stream_mut(&mut self, stream_id: StreamId) -> Option<&mut Self::Stream> {
        self.streams.get_mut(&stream_id)
    }

    #[inline]
    fn remove_stream(&mut self, stream_id: StreamId) -> Option<Self::Stream> {
        self.streams.remove(&stream_id)
    }

    #[inline]
    fn iter(&mut self) -> StreamIter<GrpcHttp2ClientStream2> {
        // https://github.com/mlalic/solicit/pull/34
        unimplemented!()
    }

    /// Number of currently active streams
    #[inline]
    fn len(&self) -> usize {
        self.streams.len()
    }
}

struct HttpConnectionAsync<H : ResponseHandler> {
    inner: TaskRcMut<Inner<H>>,
    call_tx: tokio_core::Sender<ToWriteMessage<H>>,
}

trait ResponseHandler : Send + 'static {
    fn headers(self) -> HttpFuture<Self>;
    fn body_chunk(self) -> HttpFuture<Self>;
    fn end(self) -> HttpFuture<()>;
}

struct StartRequestMessage<H : ResponseHandler> {
    headers: Vec<()>,
    body: HttpStream<Vec<u8>>,
    response_handler: H,
}

struct ReadToWriteMessage {
    buf: Vec<u8>,
}

enum ToWriteMessage<H : ResponseHandler> {
    Start(StartRequestMessage<H>),
    FromRead(ReadToWriteMessage),
}

struct WriteLoop<H : ResponseHandler> {
    write: TaskIoWrite<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> WriteLoop<H> {
    fn process_from_read(self, message: ReadToWriteMessage) -> HttpFuture<Self> {
        let WriteLoop { write, inner } = self;

        tokio_io::write_all(write, message.buf)
            .map(move |(write, _)| WriteLoop { write: write, inner: inner })
            .map_err(HttpError::from)
            .boxed()
    }

    fn process_start(self, start: StartRequestMessage<H>) -> HttpFuture<Self> {
        futures::finished(self).boxed()
    }

    fn process_message(self, message: ToWriteMessage<H>) -> HttpFuture<Self> {
        match message {
            ToWriteMessage::Start(start) => self.process_start(start),
            ToWriteMessage::FromRead(from_read) => self.process_from_read(from_read),
        }
    }

    fn run(self, requests: tokio_core::Receiver<ToWriteMessage<H>>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        requests
            .fold(self, move |wl, message: ToWriteMessage<H>| {
                wl.process_message(message)
            })
            .map(|_| ())
            .boxed()
    }
}

struct ReadLoop<H : ResponseHandler> {
    read: TaskIoRead<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> ReadLoop<H> {
    fn recv_raw_frame(self) -> HttpFuture<(Self, RawFrame<'static>)> {
        let ReadLoop { read, inner } = self;
        recv_raw_frame(read)
            .map(|(read, frame)| (ReadLoop { read: read, inner: inner}, frame))
            .map_err(HttpError::from)
            .boxed()
    }

    fn read_process_frame(self) -> HttpFuture<Self> {
        self.recv_raw_frame()
            .map(|(rl, frame)| rl)
            .boxed()
    }

    fn run(self) -> HttpFuture<()> {
        let stream = stream_repeat(());

        let future = stream.fold(self, |rl, _| {
            rl.read_process_frame()
        });

        future.map(|_| ()).boxed()
    }
}

impl<H : ResponseHandler> HttpConnectionAsync<H> {
    fn new(lh: LoopHandle, conn: TcpStream) -> HttpFuture<(Self, HttpFuture<()>)> {
        let (call_tx, call_rx) = lh.channel();

        let handshake = client_handshake(conn);
        handshake.and_then(move |conn| {
            let (read, write) = TaskIo::new(conn).split();

            let inner = TaskRcMut::new(Inner {
                host: "localhost".to_owned(), // TODO
                conn: HttpConnection::new(HttpScheme::Http),
                next_stream_id: 1,
                streams: HashMap::new(),
                _phantom_data: marker::PhantomData,
            });

            let write_inner = inner.clone();
            let run_write = call_rx.map_err(HttpError::from).and_then(move |call_rx| WriteLoop { write: write, inner: write_inner }.run(call_rx));
            let run_read = ReadLoop { read: read, inner: inner.clone() }.run();

            let c = HttpConnectionAsync {
                inner: inner,
                call_tx: call_tx,
            };
            Ok((c, run_write.join(run_read).map(|_| ()).boxed()))
        }).boxed()
    }

    fn start_request(
        &self,
        headers: Vec<()>,
        body: HttpStream<Vec<u8>>,
        response_handler: H)
            -> HttpFuture<()>
    {
        self.call_tx.send(ToWriteMessage::Start(StartRequestMessage {
            headers: headers,
            body: body,
            response_handler: response_handler,
        }));
        futures::finished(()).boxed()
    }
}
<|endoftext|>