<commit_before>#![feature(asm)]

use std::{fmt, slice, str};
use std::ops::Deref;

enum RequestType {
    BasicInformation              = 0x00000000,
    VersionInformation            = 0x00000001,
    StructuredExtendedInformation = 0x00000007,
    ExtendedFunctionInformation   = 0x80000000,
    BrandString1                  = 0x80000002,
    BrandString2                  = 0x80000003,
    BrandString3                  = 0x80000004,
    PhysicalAddressSize           = 0x80000008,
}

fn cpuid(code: RequestType) -> (u32, u32, u32, u32) {
    let res1;
    let res2;
    let res3;
    let res4;

    unsafe {
        asm!("cpuid"
             : // output operands
             "={eax}"(res1),
             "={ebx}"(res2),
             "={ecx}"(res3),
             "={edx}"(res4)
             : // input operands
             "{eax}"(code as u32),
             "{ecx}"(0 as u32)
             : // clobbers
             : // options
        );
    }

    (res1, res2, res3, res4)
}

// This matches the Intel Architecture guide, with bits 31 -> 0.
// The bit positions are inclusive.
fn bits_of(val: u32, start_bit: u8, end_bit: u8) -> u32 {
    let mut silly = 0;

    for _ in start_bit..end_bit+1 {
        silly <<= 1;
        silly |= 1;
    }

    (val >> start_bit) & silly
}

macro_rules! bit {
    ($reg:ident, $idx:expr, $name:ident) => {
        pub fn $name(self) -> bool {
            ((self.$reg >> $idx) & 1) != 0
        }
    }
}

/// Exposes the processor feature flags.
///
/// Each method corresponds to a single capability. Method names match
/// the feature mnemonic listed in the Intel Instruction Set
/// Reference.
#[derive(Copy, Clone)]
pub struct FeatureInformation {
    ecx: u32,
    edx: u32,
}

impl FeatureInformation {
    bit!(ecx,  0, sse3);
    bit!(ecx,  1, pclmulqdq);
    bit!(ecx,  2, dtes64);
    bit!(ecx,  3, monitor);
    bit!(ecx,  4, ds_cpl);
    bit!(ecx,  5, vmx);
    bit!(ecx,  6, smx);
    bit!(ecx,  7, eist);
    bit!(ecx,  8, tm2);
    bit!(ecx,  9, ssse3);
    bit!(ecx, 10, cnxt_id);
    bit!(ecx, 11, sdbg);
    bit!(ecx, 12, fma);
    bit!(ecx, 13, cmpxchg16b);
    bit!(ecx, 14, xtpr_update_control);
    bit!(ecx, 15, pdcm);
    // 16 - reserved
    bit!(ecx, 17, pcid);
    bit!(ecx, 18, dca);
    bit!(ecx, 19, sse4_1);
    bit!(ecx, 20, sse4_2);
    bit!(ecx, 21, x2apic);
    bit!(ecx, 22, movbe);
    bit!(ecx, 23, popcnt);
    bit!(ecx, 24, tsc_deadline);
    bit!(ecx, 25, aesni);
    bit!(ecx, 26, xsave);
    bit!(ecx, 27, osxsave);
    bit!(ecx, 28, avx);
    bit!(ecx, 29, f16c);
    bit!(ecx, 30, rdrand);
    // 31 - unused

    bit!(edx,  0, fpu);
    bit!(edx,  1, vme);
    bit!(edx,  2, de);
    bit!(edx,  3, pse);
    bit!(edx,  4, tsc);
    bit!(edx,  5, msr);
    bit!(edx,  6, pae);
    bit!(edx,  7, mce);
    bit!(edx,  8, cx8);
    bit!(edx,  9, apic);
    // reserved
    bit!(edx, 11, sep);
    bit!(edx, 12, mtrr);
    bit!(edx, 13, pge);
    bit!(edx, 14, mca);
    bit!(edx, 15, cmov);
    bit!(edx, 16, pat);
    bit!(edx, 17, pse_36);
    bit!(edx, 18, psn);
    bit!(edx, 19, clfsh);
    // reserved
    bit!(edx, 21, ds);
    bit!(edx, 22, acpi);
    bit!(edx, 23, mmx);
    bit!(edx, 24, fxsr);
    bit!(edx, 25, sse);
    bit!(edx, 26, sse2);
    bit!(edx, 27, ss);
    bit!(edx, 28, htt);
    bit!(edx, 29, tm);
    // reserved
    bit!(edx, 31, pbe);
}

macro_rules! dump {
    ($me:expr, $f: expr, $name: ident) => {
        try!(writeln!($f, "{}: {}", stringify!($name), $me.$name()));
    }
}

impl fmt::Debug for FeatureInformation {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        dump!(self, f, sse3);
        dump!(self, f, pclmulqdq);
        dump!(self, f, dtes64);
        dump!(self, f, monitor);
        dump!(self, f, ds_cpl);
        dump!(self, f, vmx);
        dump!(self, f, smx);
        dump!(self, f, eist);
        dump!(self, f, tm2);
        dump!(self, f, ssse3);
        dump!(self, f, cnxt_id);
        dump!(self, f, sdbg);
        dump!(self, f, fma);
        dump!(self, f, cmpxchg16b);
        dump!(self, f, xtpr_update_control);
        dump!(self, f, pdcm);
        dump!(self, f, pcid);
        dump!(self, f, dca);
        dump!(self, f, sse4_1);
        dump!(self, f, sse4_2);
        dump!(self, f, x2apic);
        dump!(self, f, movbe);
        dump!(self, f, popcnt);
        dump!(self, f, tsc_deadline);
        dump!(self, f, aesni);
        dump!(self, f, xsave);
        dump!(self, f, osxsave);
        dump!(self, f, avx);
        dump!(self, f, f16c);
        dump!(self, f, rdrand);
        dump!(self, f, fpu);
        dump!(self, f, vme);
        dump!(self, f, de);
        dump!(self, f, pse);
        dump!(self, f, tsc);
        dump!(self, f, msr);
        dump!(self, f, pae);
        dump!(self, f, mce);
        dump!(self, f, cx8);
        dump!(self, f, apic);
        dump!(self, f, sep);
        dump!(self, f, mtrr);
        dump!(self, f, pge);
        dump!(self, f, mca);
        dump!(self, f, cmov);
        dump!(self, f, pat);
        dump!(self, f, pse_36);
        dump!(self, f, psn);
        dump!(self, f, clfsh);
        dump!(self, f, ds);
        dump!(self, f, acpi);
        dump!(self, f, mmx);
        dump!(self, f, fxsr);
        dump!(self, f, sse);
        dump!(self, f, sse2);
        dump!(self, f, ss);
        dump!(self, f, htt);
        dump!(self, f, tm);
        dump!(self, f, pbe);
        Ok(())
    }
}

pub fn feature_information() -> FeatureInformation {
    let (_, _, c, d) = cpuid(RequestType::VersionInformation);
    FeatureInformation { ecx: c, edx: d }
}

fn as_bytes(v: &u32) -> &[u8] {
    let start = v as *const u32 as *const u8;
    // TODO: use u32::BYTES
    unsafe { slice::from_raw_parts(start, 4) }
}

// 3 calls of 4 registers of 4 bytes
const BRAND_STRING_LENGTH: usize = 3 * 4 * 4;

/// The brand of the processor.
pub struct BrandString {
    bytes: [u8; BRAND_STRING_LENGTH],
}

impl BrandString {
    fn new() -> BrandString {
        BrandString { bytes: [0; BRAND_STRING_LENGTH] }
    }
}

impl Deref for BrandString {
    type Target = str;

    fn deref(&self) -> &str {
        let nul_terminator = self.bytes.iter().position(|&b| b == 0).unwrap_or(0);
        let usable_bytes = &self.bytes[..nul_terminator];
        unsafe { str::from_utf8_unchecked(usable_bytes) }
    }
}

impl fmt::Display for BrandString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self as &str).fmt(f)
    }
}

pub fn brand_string() -> BrandString {
    // Should check supported (EAX Return Value of 0x80000000 ≥ 0x80000004)

    fn append_bytes(a: RequestType, bytes: &mut [u8]) {
        let (a, b, c, d) = cpuid(a);

        let result_bytes =
            as_bytes(&a).iter()
            .chain(as_bytes(&b).iter())
            .chain(as_bytes(&c).iter())
            .chain(as_bytes(&d).iter());

        for (output, input) in bytes.iter_mut().zip(result_bytes) {
            *output = *input
        }
    }

    let mut brand_string = BrandString::new();
    append_bytes(RequestType::BrandString1, &mut brand_string.bytes[0..]);
    append_bytes(RequestType::BrandString2, &mut brand_string.bytes[16..]);
    append_bytes(RequestType::BrandString3, &mut brand_string.bytes[32..]);
    brand_string
}

#[derive(Copy,Clone)]
pub struct StructuredExtendedInformation {
    ebx: u32,
    ecx: u32,
}

impl StructuredExtendedInformation {
    bit!(ebx,  0, fsgsbase);
    bit!(ebx,  1, ia32_tsc_adjust_msr);
    // 2 - reserved
    bit!(ebx,  3, bmi1);
    bit!(ebx,  4, hle);
    bit!(ebx,  5, avx2);
    // 6 - reserved
    bit!(ebx,  7, smep);
    bit!(ebx,  8, bmi2);
    bit!(ebx,  9, enhanced_rep_movsb_stosb);
    bit!(ebx, 10, invpcid);
    bit!(ebx, 11, rtm);
    bit!(ebx, 12, pqm);
    bit!(ebx, 13, deprecates_fpu_cs_ds);
    // 14 - reserved
    bit!(ebx, 15, pqe);
    // 16 - reserved
    // 17 - reserved
    bit!(ebx, 18, rdseed);
    bit!(ebx, 19, adx);
    bit!(ebx, 20, smap);
    // 21 - reserved
    // 22 - reserved
    // 23 - reserved
    // 24 - reserved
    bit!(ebx, 25, intel_processor_trace);
    // 26 - reserved
    // 27 - reserved
    // 28 - reserved
    // 29 - reserved
    // 30 - reserved
    // 31 - reserved

    bit!(ecx,  0, prefetchwt1);
}

impl fmt::Debug for StructuredExtendedInformation {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        dump!(self, f, fsgsbase);
        dump!(self, f, ia32_tsc_adjust_msr);
        dump!(self, f, bmi1);
        dump!(self, f, hle);
        dump!(self, f, avx2);
        dump!(self, f, smep);
        dump!(self, f, bmi2);
        dump!(self, f, enhanced_rep_movsb_stosb);
        dump!(self, f, invpcid);
        dump!(self, f, rtm);
        dump!(self, f, pqm);
        dump!(self, f, deprecates_fpu_cs_ds);
        dump!(self, f, pqe);
        dump!(self, f, rdseed);
        dump!(self, f, adx);
        dump!(self, f, smap);
        dump!(self, f, intel_processor_trace);
        dump!(self, f, prefetchwt1);
        Ok(())
    }
}

pub fn structured_extended_information() -> StructuredExtendedInformation {
    let (_, b, c, _) = cpuid(RequestType::StructuredExtendedInformation);
    StructuredExtendedInformation { ebx: b, ecx: c }
}

#[derive(Copy,Clone,Debug)]
pub struct PhysicalAddressSize(u32);

impl PhysicalAddressSize {
    pub fn physical_address_bits(self) -> u32 {
        bits_of(self.0, 0, 7)
    }

    pub fn linear_address_bits(self) -> u32 {
        bits_of(self.0, 8, 15)
    }
}

pub fn physical_address_size() -> PhysicalAddressSize {
    let (a, _, _, _) = cpuid(RequestType::PhysicalAddressSize);
    PhysicalAddressSize(a)
}

#[test]
fn basic_genuine_intel() {
    let (_, b, c, d) = cpuid(RequestType::BasicInformation);

    assert_eq!(b"Genu", as_bytes(&b));
    assert_eq!(b"ntel", as_bytes(&c));
    assert_eq!(b"ineI", as_bytes(&d));
}

#[test]
fn brand_string_contains_intel() {
    assert!(brand_string().contains("Intel(R)"))
}
<commit_msg>Fix comments<commit_after>#![feature(asm)]

use std::{fmt, slice, str};
use std::ops::Deref;

enum RequestType {
    BasicInformation              = 0x00000000,
    VersionInformation            = 0x00000001,
    StructuredExtendedInformation = 0x00000007,
    ExtendedFunctionInformation   = 0x80000000,
    BrandString1                  = 0x80000002,
    BrandString2                  = 0x80000003,
    BrandString3                  = 0x80000004,
    PhysicalAddressSize           = 0x80000008,
}

fn cpuid(code: RequestType) -> (u32, u32, u32, u32) {
    let res1;
    let res2;
    let res3;
    let res4;

    unsafe {
        asm!("cpuid"
             : // output operands
             "={eax}"(res1),
             "={ebx}"(res2),
             "={ecx}"(res3),
             "={edx}"(res4)
             : // input operands
             "{eax}"(code as u32),
             "{ecx}"(0 as u32)
             : // clobbers
             : // options
        );
    }

    (res1, res2, res3, res4)
}

// This matches the Intel Architecture guide, with bits 31 -> 0.
// The bit positions are inclusive.
fn bits_of(val: u32, start_bit: u8, end_bit: u8) -> u32 {
    let mut silly = 0;

    for _ in start_bit..end_bit+1 {
        silly <<= 1;
        silly |= 1;
    }

    (val >> start_bit) & silly
}

macro_rules! bit {
    ($reg:ident, $idx:expr, $name:ident) => {
        pub fn $name(self) -> bool {
            ((self.$reg >> $idx) & 1) != 0
        }
    }
}

/// Exposes the processor feature flags.
///
/// Each method corresponds to a single capability. Method names match
/// the feature mnemonic listed in the Intel Instruction Set
/// Reference.
#[derive(Copy, Clone)]
pub struct FeatureInformation {
    ecx: u32,
    edx: u32,
}

impl FeatureInformation {
    bit!(ecx,  0, sse3);
    bit!(ecx,  1, pclmulqdq);
    bit!(ecx,  2, dtes64);
    bit!(ecx,  3, monitor);
    bit!(ecx,  4, ds_cpl);
    bit!(ecx,  5, vmx);
    bit!(ecx,  6, smx);
    bit!(ecx,  7, eist);
    bit!(ecx,  8, tm2);
    bit!(ecx,  9, ssse3);
    bit!(ecx, 10, cnxt_id);
    bit!(ecx, 11, sdbg);
    bit!(ecx, 12, fma);
    bit!(ecx, 13, cmpxchg16b);
    bit!(ecx, 14, xtpr_update_control);
    bit!(ecx, 15, pdcm);
    // 16 - reserved
    bit!(ecx, 17, pcid);
    bit!(ecx, 18, dca);
    bit!(ecx, 19, sse4_1);
    bit!(ecx, 20, sse4_2);
    bit!(ecx, 21, x2apic);
    bit!(ecx, 22, movbe);
    bit!(ecx, 23, popcnt);
    bit!(ecx, 24, tsc_deadline);
    bit!(ecx, 25, aesni);
    bit!(ecx, 26, xsave);
    bit!(ecx, 27, osxsave);
    bit!(ecx, 28, avx);
    bit!(ecx, 29, f16c);
    bit!(ecx, 30, rdrand);
    // 31 - unused

    bit!(edx,  0, fpu);
    bit!(edx,  1, vme);
    bit!(edx,  2, de);
    bit!(edx,  3, pse);
    bit!(edx,  4, tsc);
    bit!(edx,  5, msr);
    bit!(edx,  6, pae);
    bit!(edx,  7, mce);
    bit!(edx,  8, cx8);
    bit!(edx,  9, apic);
    // 10 - reserved
    bit!(edx, 11, sep);
    bit!(edx, 12, mtrr);
    bit!(edx, 13, pge);
    bit!(edx, 14, mca);
    bit!(edx, 15, cmov);
    bit!(edx, 16, pat);
    bit!(edx, 17, pse_36);
    bit!(edx, 18, psn);
    bit!(edx, 19, clfsh);
    // 20 - reserved
    bit!(edx, 21, ds);
    bit!(edx, 22, acpi);
    bit!(edx, 23, mmx);
    bit!(edx, 24, fxsr);
    bit!(edx, 25, sse);
    bit!(edx, 26, sse2);
    bit!(edx, 27, ss);
    bit!(edx, 28, htt);
    bit!(edx, 29, tm);
    // 30 -reserved
    bit!(edx, 31, pbe);
}

macro_rules! dump {
    ($me:expr, $f: expr, $name: ident) => {
        try!(writeln!($f, "{}: {}", stringify!($name), $me.$name()));
    }
}

impl fmt::Debug for FeatureInformation {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        dump!(self, f, sse3);
        dump!(self, f, pclmulqdq);
        dump!(self, f, dtes64);
        dump!(self, f, monitor);
        dump!(self, f, ds_cpl);
        dump!(self, f, vmx);
        dump!(self, f, smx);
        dump!(self, f, eist);
        dump!(self, f, tm2);
        dump!(self, f, ssse3);
        dump!(self, f, cnxt_id);
        dump!(self, f, sdbg);
        dump!(self, f, fma);
        dump!(self, f, cmpxchg16b);
        dump!(self, f, xtpr_update_control);
        dump!(self, f, pdcm);
        dump!(self, f, pcid);
        dump!(self, f, dca);
        dump!(self, f, sse4_1);
        dump!(self, f, sse4_2);
        dump!(self, f, x2apic);
        dump!(self, f, movbe);
        dump!(self, f, popcnt);
        dump!(self, f, tsc_deadline);
        dump!(self, f, aesni);
        dump!(self, f, xsave);
        dump!(self, f, osxsave);
        dump!(self, f, avx);
        dump!(self, f, f16c);
        dump!(self, f, rdrand);
        dump!(self, f, fpu);
        dump!(self, f, vme);
        dump!(self, f, de);
        dump!(self, f, pse);
        dump!(self, f, tsc);
        dump!(self, f, msr);
        dump!(self, f, pae);
        dump!(self, f, mce);
        dump!(self, f, cx8);
        dump!(self, f, apic);
        dump!(self, f, sep);
        dump!(self, f, mtrr);
        dump!(self, f, pge);
        dump!(self, f, mca);
        dump!(self, f, cmov);
        dump!(self, f, pat);
        dump!(self, f, pse_36);
        dump!(self, f, psn);
        dump!(self, f, clfsh);
        dump!(self, f, ds);
        dump!(self, f, acpi);
        dump!(self, f, mmx);
        dump!(self, f, fxsr);
        dump!(self, f, sse);
        dump!(self, f, sse2);
        dump!(self, f, ss);
        dump!(self, f, htt);
        dump!(self, f, tm);
        dump!(self, f, pbe);
        Ok(())
    }
}

pub fn feature_information() -> FeatureInformation {
    let (_, _, c, d) = cpuid(RequestType::VersionInformation);
    FeatureInformation { ecx: c, edx: d }
}

fn as_bytes(v: &u32) -> &[u8] {
    let start = v as *const u32 as *const u8;
    // TODO: use u32::BYTES
    unsafe { slice::from_raw_parts(start, 4) }
}

// 3 calls of 4 registers of 4 bytes
const BRAND_STRING_LENGTH: usize = 3 * 4 * 4;

/// The brand of the processor.
pub struct BrandString {
    bytes: [u8; BRAND_STRING_LENGTH],
}

impl BrandString {
    fn new() -> BrandString {
        BrandString { bytes: [0; BRAND_STRING_LENGTH] }
    }
}

impl Deref for BrandString {
    type Target = str;

    fn deref(&self) -> &str {
        let nul_terminator = self.bytes.iter().position(|&b| b == 0).unwrap_or(0);
        let usable_bytes = &self.bytes[..nul_terminator];
        unsafe { str::from_utf8_unchecked(usable_bytes) }
    }
}

impl fmt::Display for BrandString {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self as &str).fmt(f)
    }
}

pub fn brand_string() -> BrandString {
    // Should check supported (EAX Return Value of 0x80000000 ≥ 0x80000004)

    fn append_bytes(a: RequestType, bytes: &mut [u8]) {
        let (a, b, c, d) = cpuid(a);

        let result_bytes =
            as_bytes(&a).iter()
            .chain(as_bytes(&b).iter())
            .chain(as_bytes(&c).iter())
            .chain(as_bytes(&d).iter());

        for (output, input) in bytes.iter_mut().zip(result_bytes) {
            *output = *input
        }
    }

    let mut brand_string = BrandString::new();
    append_bytes(RequestType::BrandString1, &mut brand_string.bytes[0..]);
    append_bytes(RequestType::BrandString2, &mut brand_string.bytes[16..]);
    append_bytes(RequestType::BrandString3, &mut brand_string.bytes[32..]);
    brand_string
}

#[derive(Copy,Clone)]
pub struct StructuredExtendedInformation {
    ebx: u32,
    ecx: u32,
}

impl StructuredExtendedInformation {
    bit!(ebx,  0, fsgsbase);
    bit!(ebx,  1, ia32_tsc_adjust_msr);
    // 2 - reserved
    bit!(ebx,  3, bmi1);
    bit!(ebx,  4, hle);
    bit!(ebx,  5, avx2);
    // 6 - reserved
    bit!(ebx,  7, smep);
    bit!(ebx,  8, bmi2);
    bit!(ebx,  9, enhanced_rep_movsb_stosb);
    bit!(ebx, 10, invpcid);
    bit!(ebx, 11, rtm);
    bit!(ebx, 12, pqm);
    bit!(ebx, 13, deprecates_fpu_cs_ds);
    // 14 - reserved
    bit!(ebx, 15, pqe);
    // 16 - reserved
    // 17 - reserved
    bit!(ebx, 18, rdseed);
    bit!(ebx, 19, adx);
    bit!(ebx, 20, smap);
    // 21 - reserved
    // 22 - reserved
    // 23 - reserved
    // 24 - reserved
    bit!(ebx, 25, intel_processor_trace);
    // 26 - reserved
    // 27 - reserved
    // 28 - reserved
    // 29 - reserved
    // 30 - reserved
    // 31 - reserved

    bit!(ecx,  0, prefetchwt1);
}

impl fmt::Debug for StructuredExtendedInformation {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        dump!(self, f, fsgsbase);
        dump!(self, f, ia32_tsc_adjust_msr);
        dump!(self, f, bmi1);
        dump!(self, f, hle);
        dump!(self, f, avx2);
        dump!(self, f, smep);
        dump!(self, f, bmi2);
        dump!(self, f, enhanced_rep_movsb_stosb);
        dump!(self, f, invpcid);
        dump!(self, f, rtm);
        dump!(self, f, pqm);
        dump!(self, f, deprecates_fpu_cs_ds);
        dump!(self, f, pqe);
        dump!(self, f, rdseed);
        dump!(self, f, adx);
        dump!(self, f, smap);
        dump!(self, f, intel_processor_trace);
        dump!(self, f, prefetchwt1);
        Ok(())
    }
}

pub fn structured_extended_information() -> StructuredExtendedInformation {
    let (_, b, c, _) = cpuid(RequestType::StructuredExtendedInformation);
    StructuredExtendedInformation { ebx: b, ecx: c }
}

#[derive(Copy,Clone,Debug)]
pub struct PhysicalAddressSize(u32);

impl PhysicalAddressSize {
    pub fn physical_address_bits(self) -> u32 {
        bits_of(self.0, 0, 7)
    }

    pub fn linear_address_bits(self) -> u32 {
        bits_of(self.0, 8, 15)
    }
}

pub fn physical_address_size() -> PhysicalAddressSize {
    let (a, _, _, _) = cpuid(RequestType::PhysicalAddressSize);
    PhysicalAddressSize(a)
}

#[test]
fn basic_genuine_intel() {
    let (_, b, c, d) = cpuid(RequestType::BasicInformation);

    assert_eq!(b"Genu", as_bytes(&b));
    assert_eq!(b"ntel", as_bytes(&c));
    assert_eq!(b"ineI", as_bytes(&d));
}

#[test]
fn brand_string_contains_intel() {
    assert!(brand_string().contains("Intel(R)"))
}
<|endoftext|>


<commit_before>
//! **petgraph** is a graph data structure library.
//!
//! - [`Graph`](./graph/struct.Graph.html) which is an adjacency list graph with
//! arbitrary associated data.
//!
//! - [`StableGraph`](./stable_graph/struct.StableGraph.html) is similar
//! to `Graph`, but it keeps indices stable across removals.
//!
//! - [`GraphMap`](./graphmap/struct.GraphMap.html) is an adjacency list graph
//! which is backed by a hash table and the node identifiers are the keys
//! into the table.
//!
//! Optional crate feature flags: `"serde-1"`, see the Readme for more information.
//!
#![doc(html_root_url = "https://docs.rs/petgraph/0.4/")]

extern crate fixedbitset;
#[cfg(feature = "graphmap")]
extern crate ordermap;

#[cfg(feature = "serde-1")]
extern crate serde;
#[cfg(feature = "serde-1")]
#[macro_use]
extern crate serde_derive;

#[cfg(all(feature = "serde-1", test))]
extern crate itertools;

#[doc(no_inline)]
pub use graph::Graph;

pub use Direction::{Outgoing, Incoming};

#[macro_use]
mod macros;
mod scored;

// these modules define trait-implementing macros
#[macro_use]
pub mod visit;
#[macro_use]
pub mod data;

pub mod algo;
#[cfg(feature = "generate")]
pub mod generate;
#[cfg(feature = "graphmap")]
pub mod graphmap;
mod graph_impl;
pub mod dot;
pub mod unionfind;
mod dijkstra;
pub mod csr;
mod iter_format;
mod isomorphism;
mod traits_graph;
mod util;
#[cfg(feature = "quickcheck")]
mod quickcheck;
#[cfg(feature = "serde-1")]
mod serde_utils;

pub mod prelude;

/// `Graph<N, E, Ty, Ix>` is a graph datastructure using an adjacency list representation.
pub mod graph {
    pub use graph_impl::{
        Edge,
        EdgeIndex,
        EdgeIndices,
        EdgeReference,
        EdgeReferences,
        EdgeWeightsMut,
        Edges,
        Externals,
        Frozen,
        Graph,
        Neighbors,
        Node,
        NodeIndex,
        NodeIndices,
        NodeWeightsMut,
        WalkNeighbors,
        GraphIndex,
        IndexType,
        edge_index,
        node_index,
        DefaultIx,
        DiGraph,
        UnGraph,
    };
}

#[cfg(feature = "stable_graph")]
pub use graph_impl::stable_graph;

macro_rules! copyclone {
    ($name:ident) => {
        impl Clone for $name {
            #[inline]
            fn clone(&self) -> Self { *self }
        }
    }
}

// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction.
#[derive(Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[repr(usize)]
pub enum Direction {
    /// An `Outgoing` edge is an outward edge *from* the current node.
    Outgoing = 0,
    /// An `Incoming` edge is an inbound edge *to* the current node.
    Incoming = 1
}

copyclone!(Direction);

impl Direction {
    /// Return the opposite `Direction`.
    #[inline]
    pub fn opposite(&self) -> Direction {
        match *self {
            Outgoing => Incoming,
            Incoming => Outgoing,
        }
    }

    /// Return `0` for `Outgoing` and `1` for `Incoming`.
    #[inline]
    pub fn index(&self) -> usize {
        (*self as usize) & 0x1
    }
}

#[doc(hidden)]
pub use Direction as EdgeDirection;

/// Marker type for a directed graph.
#[derive(Copy, Debug)]
pub enum Directed { }
copyclone!(Directed);

/// Marker type for an undirected graph.
#[derive(Copy, Debug)]
pub enum Undirected { }
copyclone!(Undirected);

/// A graph's edge type determines whether is has directed edges or not.
pub trait EdgeType {
    fn is_directed() -> bool;
}

impl EdgeType for Directed {
    #[inline]
    fn is_directed() -> bool { true }
}

impl EdgeType for Undirected {
    #[inline]
    fn is_directed() -> bool { false }
}

/// Convert an element like `(i, j)` or `(i, j, w)` into
/// a triple of source, target, edge weight.
///
/// For `Graph::from_edges` and `GraphMap::from_edges`.
pub trait IntoWeightedEdge<E> {
    type NodeId;
    fn into_weighted_edge(self) -> (Self::NodeId, Self::NodeId, E);
}

impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix)
    where E: Default
{
    type NodeId = Ix;

    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (s, t) = self;
        (s, t, E::default())
    }
}

impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix, E)
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        self
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for (Ix, Ix, &'a E)
    where E: Clone
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (a, b, c) = self;
        (a, b, c.clone())
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix)
    where Ix: Copy, E: Default
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (s, t) = *self;
        (s, t, E::default())
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix, E)
    where Ix: Copy, E: Clone
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        self.clone()
    }
}
<commit_msg>DOC: Fix crate feature mention ("flag" is redundant)<commit_after>
//! **petgraph** is a graph data structure library.
//!
//! - [`Graph`](./graph/struct.Graph.html) which is an adjacency list graph with
//! arbitrary associated data.
//!
//! - [`StableGraph`](./stable_graph/struct.StableGraph.html) is similar
//! to `Graph`, but it keeps indices stable across removals.
//!
//! - [`GraphMap`](./graphmap/struct.GraphMap.html) is an adjacency list graph
//! which is backed by a hash table and the node identifiers are the keys
//! into the table.
//!
//! Optional crate feature: `"serde-1"`, see the Readme for more information.
//!
#![doc(html_root_url = "https://docs.rs/petgraph/0.4/")]

extern crate fixedbitset;
#[cfg(feature = "graphmap")]
extern crate ordermap;

#[cfg(feature = "serde-1")]
extern crate serde;
#[cfg(feature = "serde-1")]
#[macro_use]
extern crate serde_derive;

#[cfg(all(feature = "serde-1", test))]
extern crate itertools;

#[doc(no_inline)]
pub use graph::Graph;

pub use Direction::{Outgoing, Incoming};

#[macro_use]
mod macros;
mod scored;

// these modules define trait-implementing macros
#[macro_use]
pub mod visit;
#[macro_use]
pub mod data;

pub mod algo;
#[cfg(feature = "generate")]
pub mod generate;
#[cfg(feature = "graphmap")]
pub mod graphmap;
mod graph_impl;
pub mod dot;
pub mod unionfind;
mod dijkstra;
pub mod csr;
mod iter_format;
mod isomorphism;
mod traits_graph;
mod util;
#[cfg(feature = "quickcheck")]
mod quickcheck;
#[cfg(feature = "serde-1")]
mod serde_utils;

pub mod prelude;

/// `Graph<N, E, Ty, Ix>` is a graph datastructure using an adjacency list representation.
pub mod graph {
    pub use graph_impl::{
        Edge,
        EdgeIndex,
        EdgeIndices,
        EdgeReference,
        EdgeReferences,
        EdgeWeightsMut,
        Edges,
        Externals,
        Frozen,
        Graph,
        Neighbors,
        Node,
        NodeIndex,
        NodeIndices,
        NodeWeightsMut,
        WalkNeighbors,
        GraphIndex,
        IndexType,
        edge_index,
        node_index,
        DefaultIx,
        DiGraph,
        UnGraph,
    };
}

#[cfg(feature = "stable_graph")]
pub use graph_impl::stable_graph;

macro_rules! copyclone {
    ($name:ident) => {
        impl Clone for $name {
            #[inline]
            fn clone(&self) -> Self { *self }
        }
    }
}

// Index into the NodeIndex and EdgeIndex arrays
/// Edge direction.
#[derive(Copy, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)]
#[repr(usize)]
pub enum Direction {
    /// An `Outgoing` edge is an outward edge *from* the current node.
    Outgoing = 0,
    /// An `Incoming` edge is an inbound edge *to* the current node.
    Incoming = 1
}

copyclone!(Direction);

impl Direction {
    /// Return the opposite `Direction`.
    #[inline]
    pub fn opposite(&self) -> Direction {
        match *self {
            Outgoing => Incoming,
            Incoming => Outgoing,
        }
    }

    /// Return `0` for `Outgoing` and `1` for `Incoming`.
    #[inline]
    pub fn index(&self) -> usize {
        (*self as usize) & 0x1
    }
}

#[doc(hidden)]
pub use Direction as EdgeDirection;

/// Marker type for a directed graph.
#[derive(Copy, Debug)]
pub enum Directed { }
copyclone!(Directed);

/// Marker type for an undirected graph.
#[derive(Copy, Debug)]
pub enum Undirected { }
copyclone!(Undirected);

/// A graph's edge type determines whether is has directed edges or not.
pub trait EdgeType {
    fn is_directed() -> bool;
}

impl EdgeType for Directed {
    #[inline]
    fn is_directed() -> bool { true }
}

impl EdgeType for Undirected {
    #[inline]
    fn is_directed() -> bool { false }
}

/// Convert an element like `(i, j)` or `(i, j, w)` into
/// a triple of source, target, edge weight.
///
/// For `Graph::from_edges` and `GraphMap::from_edges`.
pub trait IntoWeightedEdge<E> {
    type NodeId;
    fn into_weighted_edge(self) -> (Self::NodeId, Self::NodeId, E);
}

impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix)
    where E: Default
{
    type NodeId = Ix;

    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (s, t) = self;
        (s, t, E::default())
    }
}

impl<Ix, E> IntoWeightedEdge<E> for (Ix, Ix, E)
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        self
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for (Ix, Ix, &'a E)
    where E: Clone
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (a, b, c) = self;
        (a, b, c.clone())
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix)
    where Ix: Copy, E: Default
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        let (s, t) = *self;
        (s, t, E::default())
    }
}

impl<'a, Ix, E> IntoWeightedEdge<E> for &'a (Ix, Ix, E)
    where Ix: Copy, E: Clone
{
    type NodeId = Ix;
    fn into_weighted_edge(self) -> (Ix, Ix, E) {
        self.clone()
    }
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A GLFW window back-end for the Piston game engine.

extern crate glfw;
extern crate collections;
extern crate gl;
extern crate event;
extern crate shader_version;
extern crate input;

// External crates.
use collections::RingBuf;
use glfw::Context;
use input::{
    keyboard,
    mouse,
};
use event::{
    Window,
    WindowSettings,
};
use shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct GlfwWindow {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: WindowSettings,
    event_queue: RingBuf<input::InputEvent>,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
}

impl GlfwWindow {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GlfwWindow {
        win.set_all_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        GlfwWindow {
            window: win,
            events: events,
            glfw: glfw,
            settings: WindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                samples: 0, //unknown
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> GlfwWindow {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        let (major, minor) = opengl.get_major_minor();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(major as u32, minor as u32));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
        glfw.window_hint(glfw::Samples(settings.samples as u32));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| window.get_proc_address(s));

        GlfwWindow {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if self.settings.exit_on_esc => {
                    self.window.set_should_close(true);
                }
                glfw::CharEvent(ch) => {
                    self.event_queue.push(input::Text(ch.to_string()));
                }
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push(
                        input::Press(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push(
                        input::Release(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push(
                        input::Press(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push(
                        input::Release(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push(input::Move(input::MouseCursor(x, y)));
                    match self.last_mouse_pos {
                        Some((lx, ly)) => {
                            self.event_queue.push(
                                input::Move(input::MouseRelative(x - lx, y - ly))
                            )
                        }
                        None => {}
                    };
                    self.last_mouse_pos = Some((x, y));
                }
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push(input::Move(input::MouseScroll(x, y)));
                }
                glfw::SizeEvent(w, h) => {
                    self.event_queue.push(input::Resize(w as u32, h as u32));
                }
                glfw::FocusEvent(focus) => {
                    self.event_queue.push(input::Focus(focus));
                }
                _ => {}
            }
        }
    }
}

impl Window for GlfwWindow {
    fn get_settings<'a>(&'a self) -> &'a WindowSettings {
        &self.settings
    }

    fn get_draw_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_framebuffer_size();
        (w as u32, h as u32)
    }

    fn get_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_size();
        (w as u32, h as u32)
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn close(&mut self) {
        self.window.set_should_close(true);
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        if enabled {
            self.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            self.window.set_cursor_mode(glfw::CursorNormal);
            self.last_mouse_pos = None;
        }
    }

    fn poll_event(&mut self) -> Option<input::InputEvent> {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front()
        } else {
            None
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}
<commit_msg>Upgraded to latest piston-event<commit_after>#![deny(missing_docs)]

//! A GLFW window back-end for the Piston game engine.

extern crate glfw;
extern crate collections;
extern crate gl;
extern crate event;
extern crate shader_version;
extern crate input;

// External crates.
use collections::RingBuf;
use glfw::Context;
use input::{
    keyboard,
    mouse,
    InputEvent,
};
use event::{
    Window,
    WindowSettings,
};
use event::window::{
    PollEvent,
    SwapBuffers,
};
use shader_version::opengl::OpenGL;

/// Contains stuff for game window.
pub struct GlfwWindow {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: WindowSettings,
    event_queue: RingBuf<input::InputEvent>,
    // Used to compute relative mouse movement.
    last_mouse_pos: Option<(f64, f64)>,
}

impl GlfwWindow {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GlfwWindow {
        win.set_all_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        GlfwWindow {
            window: win,
            events: events,
            glfw: glfw,
            settings: WindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                samples: 0, //unknown
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(opengl: OpenGL, settings: WindowSettings) -> GlfwWindow {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        let (major, minor) = opengl.get_major_minor();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(major as u32, minor as u32));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
        glfw.window_hint(glfw::Samples(settings.samples as u32));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| window.get_proc_address(s));

        GlfwWindow {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::new(),
            last_mouse_pos: None,
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                if self.settings.exit_on_esc => {
                    self.window.set_should_close(true);
                }
                glfw::CharEvent(ch) => {
                    self.event_queue.push(input::Text(ch.to_string()));
                }
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push(
                        input::Press(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push(
                        input::Release(input::Keyboard(glfw_map_key(key)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push(
                        input::Press(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push(
                        input::Release(input::Mouse(glfw_map_mouse(button)))
                    );
                }
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push(input::Move(input::MouseCursor(x, y)));
                    match self.last_mouse_pos {
                        Some((lx, ly)) => {
                            self.event_queue.push(
                                input::Move(input::MouseRelative(x - lx, y - ly))
                            )
                        }
                        None => {}
                    };
                    self.last_mouse_pos = Some((x, y));
                }
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push(input::Move(input::MouseScroll(x, y)));
                }
                glfw::SizeEvent(w, h) => {
                    self.event_queue.push(input::Resize(w as u32, h as u32));
                }
                glfw::FocusEvent(focus) => {
                    self.event_queue.push(input::Focus(focus));
                }
                _ => {}
            }
        }
    }
}

impl PollEvent<InputEvent> for GlfwWindow {
    fn poll_event(&mut self) -> Option<input::InputEvent> {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front()
        } else {
            None
        }
    }
}

impl SwapBuffers for GlfwWindow {
    fn swap_buffers(&mut self) {
        use glfw::Context;

        self.window.swap_buffers();
    }
}

impl Window for GlfwWindow {
    fn get_settings<'a>(&'a self) -> &'a WindowSettings {
        &self.settings
    }

    fn get_draw_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_framebuffer_size();
        (w as u32, h as u32)
    }

    fn get_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_size();
        (w as u32, h as u32)
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn close(&mut self) {
        self.window.set_should_close(true);
    }

    fn capture_cursor(&mut self, enabled: bool) {
        if enabled {
            self.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            self.window.set_cursor_mode(glfw::CursorNormal);
            self.last_mouse_pos = None;
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}
<|endoftext|>


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

//! Library for retrieving and interacting with the [crates.io index].
//!
//! [crates.io index]: https://github.com/rust-lang/crates.io-index
//!
//! ## Examples
//!
//! ```rust
//! extern crate crates_index;
//!
//! let index = crates_index::Index::new("_index");
//! if !index.exists() {
//!    index.retrieve().expect("Could not fetch crates.io index");
//! }
//! for crate_ in index.crates() {
//!    let latest_version = crate_.latest_version();
//!    println!("crate name: {}", latest_version.name());
//!    println!("crate version: {}", latest_version.version());
//! }
//! ```

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::{BufRead, BufReader};
use std::iter;
use std::path::{Path, PathBuf};

#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate glob;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;

error_chain! {
    foreign_links {
        Git(git2::Error);
    }
}

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(Deserialize, Clone, Debug)]
pub struct Version {
    name: String,
    vers: String,
    deps: Vec<Dependency>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(Deserialize, Clone, Debug)]
pub struct Dependency {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>,
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        match self.target {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    pub fn kind(&self) -> Option<&str> {
        match self.kind {
            Some(ref s) => Some(s),
            None => None,
        }
    }
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::new(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new<P: AsRef<Path>>(path: P) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;
        let path = path.as_ref();

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

/// Wrapper around managing the crates.io-index git repository
#[derive(Debug, Clone, PartialEq)]
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new<P: Into<PathBuf>>(path: P) -> Index {
        Index { path: path.into() }
    }

    /// Determines if a crates.io repository exists at `self.path`
    pub fn exists(&self) -> bool {
        git2::Repository::discover(&self.path)
            .map(|repository| {
                repository
                    .find_remote("origin")
                    .map(|remote| remote.url() == Some(INDEX_GIT_URL))
                    .unwrap_or(false)
            })
            .unwrap_or(false)
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve(&self) -> Result<()> {
        let _ = git2::Repository::clone(INDEX_GIT_URL, &self.path)?;
        Ok(())
    }

    /// Assumes the index already exists at `self.path`, and updates it
    pub fn update(&self) -> Result<()> {
        debug_assert!(self.exists());
        let repo = git2::Repository::discover(&self.path)?;
        let mut origin_remote = repo.find_remote("origin")?;
        origin_remote.fetch(&["master"], None, None)?;
        let oid = repo.refname_to_id("refs/remotes/origin/master")?;
        let object = repo.find_object(oid, None).unwrap();
        repo.reset(&object, git2::ResetType::Hard, None)?;
        Ok(())
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve_or_update(&self) -> Result<()> {
        if self.exists() {
            self.update()
        } else {
            self.retrieve()
        }
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| {
                      path.file_name()
                          .and_then(OsStr::to_str)
                          .map(|file_name| file_name.eq_ignore_ascii_case(crate_name))
                          .unwrap_or(false)
                  })
            .map(|p| Crate::new(&p))
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone()) // TODO: remove this clone
    }

    /// Get the index directory.
    pub fn path(&self) -> &Path {
        &self.path
    }
}

/// A single crate that contains many published versions
#[derive(Debug)]
pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn new<P: AsRef<Path>>(index_path: P) -> Crate {
        let index_path = index_path.as_ref();
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = serde_json::from_str(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate { versions: versions }
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }

    pub fn name(&self) -> &str {
        self.latest_version().name()
    }
}

#[cfg(test)]
mod test {
    use super::Index;
    extern crate tempdir;
    use self::tempdir::TempDir;

    #[test]
    fn test_dependencies() {
        let tmp_dir = TempDir::new("test1").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve().expect("could not fetch crates io index");
        let crate_ = index.crates().nth(0).expect("could not find a crate in the index");
        let _ = format!("supports debug {:?}", crate_);
        let version = crate_.latest_version();
        let _ = version.deps;
    }

    #[test]
    fn test_retrieve_or_update() {
        let tmp_dir = TempDir::new("test2").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
    }

    #[test]
    fn test_exists() {
        let tmp_dir = TempDir::new("test3").unwrap();

        let index = Index::new(tmp_dir.path());
        assert!(!index.exists());
        index.retrieve().unwrap();
        assert!(index.exists());
    }
}
<commit_msg>Add the method `Dependency::crate_name()`.<commit_after>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Library for retrieving and interacting with the [crates.io index].
//!
//! [crates.io index]: https://github.com/rust-lang/crates.io-index
//!
//! ## Examples
//!
//! ```rust
//! extern crate crates_index;
//!
//! let index = crates_index::Index::new("_index");
//! if !index.exists() {
//!    index.retrieve().expect("Could not fetch crates.io index");
//! }
//! for crate_ in index.crates() {
//!    let latest_version = crate_.latest_version();
//!    println!("crate name: {}", latest_version.name());
//!    println!("crate version: {}", latest_version.version());
//! }
//! ```

use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::{BufRead, BufReader};
use std::iter;
use std::path::{Path, PathBuf};

#[macro_use]
extern crate error_chain;
extern crate git2;
extern crate glob;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;

error_chain! {
    foreign_links {
        Git(git2::Error);
    }
}

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(Deserialize, Clone, Debug)]
pub struct Version {
    name: String,
    vers: String,
    deps: Vec<Dependency>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(Deserialize, Clone, Debug)]
pub struct Dependency {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>,
    package: Option<String>,
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        match self.target {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    pub fn kind(&self) -> Option<&str> {
        match self.kind {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    pub fn package(&self) -> Option<&str> {
        match self.package {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    /// Returns the name of the crate providing the dependency.
    /// This is equivalent to `name()` unless `self.package()`
    /// is not `None`, in which case it's equal to `self.package()`.
    ///
    /// Basically, you can define a dependency in your `Cargo.toml`
    /// like this:
    ///
    /// ```toml
    /// serde_lib = {version = "1", package = "serde"}
    /// ```
    ///
    /// ...which means that it uses the crate `serde` but imports
    /// it under the name `serde_lib`.
    pub fn crate_name(&self) -> &str {
        match self.package {
            Some(ref s) => s,
            None => self.name(),
        }
    }
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::new(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new<P: AsRef<Path>>(path: P) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;
        let path = path.as_ref();

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

/// Wrapper around managing the crates.io-index git repository
#[derive(Debug, Clone, PartialEq)]
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new<P: Into<PathBuf>>(path: P) -> Index {
        Index { path: path.into() }
    }

    /// Determines if a crates.io repository exists at `self.path`
    pub fn exists(&self) -> bool {
        git2::Repository::discover(&self.path)
            .map(|repository| {
                repository
                    .find_remote("origin")
                    .map(|remote| remote.url() == Some(INDEX_GIT_URL))
                    .unwrap_or(false)
            })
            .unwrap_or(false)
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve(&self) -> Result<()> {
        let _ = git2::Repository::clone(INDEX_GIT_URL, &self.path)?;
        Ok(())
    }

    /// Assumes the index already exists at `self.path`, and updates it
    pub fn update(&self) -> Result<()> {
        debug_assert!(self.exists());
        let repo = git2::Repository::discover(&self.path)?;
        let mut origin_remote = repo.find_remote("origin")?;
        origin_remote.fetch(&["master"], None, None)?;
        let oid = repo.refname_to_id("refs/remotes/origin/master")?;
        let object = repo.find_object(oid, None).unwrap();
        repo.reset(&object, git2::ResetType::Hard, None)?;
        Ok(())
    }

    /// Downloads the index to the path specified from the constructor
    pub fn retrieve_or_update(&self) -> Result<()> {
        if self.exists() {
            self.update()
        } else {
            self.retrieve()
        }
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| {
                      path.file_name()
                          .and_then(OsStr::to_str)
                          .map(|file_name| file_name.eq_ignore_ascii_case(crate_name))
                          .unwrap_or(false)
                  })
            .map(|p| Crate::new(&p))
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone()) // TODO: remove this clone
    }

    /// Get the index directory.
    pub fn path(&self) -> &Path {
        &self.path
    }
}

/// A single crate that contains many published versions
#[derive(Debug)]
pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn new<P: AsRef<Path>>(index_path: P) -> Crate {
        let index_path = index_path.as_ref();
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = serde_json::from_str(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate { versions: versions }
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }

    pub fn name(&self) -> &str {
        self.latest_version().name()
    }
}

#[cfg(test)]
mod test {
    use super::Index;
    extern crate tempdir;
    use self::tempdir::TempDir;

    #[test]
    fn test_dependencies() {
        let tmp_dir = TempDir::new("test1").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        // let crate_ = index.crates().nth(0).expect("could not find a crate in the index");
        let crate_ = index.crate_("sval").expect("Could not find the crate libnotify in the index");
        let _ = format!("supports debug {:?}", crate_);

        let version = crate_.versions().iter().find(|v| v.version() == "0.0.1")
            .expect("Version 0.0.1 of sval does not exist?");
        let dep_with_package_name = version.dependencies().iter().find(|d| d.name() == "serde_lib")
            .expect("sval does not have expected dependency?");
        assert_ne!(dep_with_package_name.name(), dep_with_package_name.package().unwrap());
        assert_eq!(dep_with_package_name.crate_name(), dep_with_package_name.package().unwrap());
    }

    #[test]
    fn test_retrieve_or_update() {
        let tmp_dir = TempDir::new("test2").unwrap();

        let index = Index::new(tmp_dir.path());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
        index.retrieve_or_update().expect("could not fetch crates io index");
        assert!(index.exists());
    }

    #[test]
    fn test_exists() {
        let tmp_dir = TempDir::new("test3").unwrap();

        let index = Index::new(tmp_dir.path());
        assert!(!index.exists());
        index.retrieve().unwrap();
        assert!(index.exists());
    }
}
<|endoftext|>