<commit_before>use ffi::sec;
use ffi::sec::{SECStatus, SECItemFFI};
use ffi::nspr::PRBool;
use result::NSSResult;
use libc::{c_void, c_int, c_uint, c_ulong};
use std::ptr;

#[allow(non_camel_case_types)]
pub type CK_MECHANISM_TYPE = c_ulong;

pub const CKM_RSA_PKCS_KEY_PAIR_GEN : CK_MECHANISM_TYPE = 0x0000_0000;
pub const CKM_RSA_PKCS      : CK_MECHANISM_TYPE = 0x0000_0001;
pub const CKM_RSA_PKCS_OAEP : CK_MECHANISM_TYPE = 0x0000_0009;

pub const CKM_SHA_1   : CK_MECHANISM_TYPE = 0x0000_0220;
pub const CKM_SHA_224 : CK_MECHANISM_TYPE = 0x0000_0255;
pub const CKM_SHA_256 : CK_MECHANISM_TYPE = 0x0000_0250;
pub const CKM_SHA_384 : CK_MECHANISM_TYPE = 0x0000_0260;
pub const CKM_SHA_512 : CK_MECHANISM_TYPE = 0x0000_0270;

pub const CKM_DES_ECB     : CK_MECHANISM_TYPE = 0x0000_0121;
pub const CKM_DES_CBC     : CK_MECHANISM_TYPE = 0x0000_0122;
pub const CKM_DES_CBC_PAD : CK_MECHANISM_TYPE = 0x0000_0125;
pub const CKM_AES_ECB     : CK_MECHANISM_TYPE = 0x0000_1081;
pub const CKM_AES_CBC     : CK_MECHANISM_TYPE = 0x0000_1082;
pub const CKM_AES_CBC_PAD : CK_MECHANISM_TYPE = 0x0000_1085;
// CK_MECHANISM_TYPE

#[allow(non_camel_case_types)]
pub type CK_ATTRIBUTE_TYPE = c_ulong;

pub const CKA_ENCRYPT : CK_ATTRIBUTE_TYPE = 0x0000_0104;
pub const CKA_DECRYPT : CK_ATTRIBUTE_TYPE = 0x0000_0105;
// CK_ATTRIBUTE_TYPE

#[allow(non_camel_case_types)]
type CK_RSA_PKCS_MGF_TYPE = c_ulong;

const CKG_MGF1_SHA1   : CK_RSA_PKCS_MGF_TYPE = 0x0000_0001;
const CKG_MGF1_SHA224 : CK_RSA_PKCS_MGF_TYPE = 0x0000_0005;
const CKG_MGF1_SHA256 : CK_RSA_PKCS_MGF_TYPE = 0x0000_0002;
const CKG_MGF1_SHA384 : CK_RSA_PKCS_MGF_TYPE = 0x0000_0003;
const CKG_MGF1_SHA512 : CK_RSA_PKCS_MGF_TYPE = 0x0000_0004;
// CK_RSA_PKCS_MGF_TYPE

#[repr(C)]
#[allow(dead_code)] // List all available options
pub enum PK11Origin
{
    OriginNULL = 0,
    OriginDerive = 1,
    OriginGenerated = 2,
    OriginFortezzaHack = 3,
    OriginUnwrap = 4,
}

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct CK_RSA_PKCS_OAEP_PARAMS
{
    hash_alg: CK_MECHANISM_TYPE,
    mgf: CK_RSA_PKCS_MGF_TYPE,
    source: c_ulong,
    data_source: *mut c_void,
    data_len: c_ulong,
}

impl CK_RSA_PKCS_OAEP_PARAMS
{
    pub fn from_algorithm(ckm: CK_MECHANISM_TYPE) -> CK_RSA_PKCS_OAEP_PARAMS
    {
        let mgf = mgf_type_from_ckm(ckm);
        CK_RSA_PKCS_OAEP_PARAMS
        {
            hash_alg: ckm,
            mgf: mgf,
            source: CKZ_DATA_SPECIFIED,
            data_source: ptr::null_mut(),
            data_len: 0,
        }
    }
}

fn mgf_type_from_ckm(ckm: CK_MECHANISM_TYPE) -> CK_RSA_PKCS_MGF_TYPE
{
    match ckm
    {
        CKM_SHA_1 => CKG_MGF1_SHA1,
        CKM_SHA_224 => CKG_MGF1_SHA224,
        CKM_SHA_256 => CKG_MGF1_SHA256,
        CKM_SHA_384 => CKG_MGF1_SHA384,
        CKM_SHA_512 => CKG_MGF1_SHA512,
        _ => panic!("Unsupported mechanism provided"),
    }
}

pub struct PK11RSAGenParams
{
    pub key_size_bits: c_int,
    pub pe: c_ulong,
}

// Opaque structures, with pointer references only
#[repr(C)] pub struct PK11SlotInfo;
#[repr(C)] pub struct PK11Context;
#[repr(C)] pub struct PK11SymKey;
#[repr(C)] pub struct SECKEYPrivateKey;
#[repr(C)] pub struct SECKEYPublicKey;
#[repr(C)] pub struct CERTSubjectPublicKeyInfo;

pub struct SlotInfo
{
    ptr: *mut PK11SlotInfo
}

impl SlotInfo
{
    pub fn get_internal() -> NSSResult<SlotInfo>
    {
        let ptr = unsafe { PK11_GetInternalKeySlot() };
        SlotInfo::from_ptr(ptr)
    }

    pub fn get_best(mechanism: CK_MECHANISM_TYPE) -> NSSResult<SlotInfo>
    {
        let ptr = unsafe { PK11_GetBestSlot(mechanism, ptr::null_mut()) };
        SlotInfo::from_ptr(ptr)
    }

    fn from_ptr(ptr: *mut PK11SlotInfo) -> NSSResult<SlotInfo>
    {
        if ptr.is_null() {
            Err(::ffi::nspr::get_error_code())
        }
        else {
            Ok(SlotInfo { ptr: ptr })
        }
    }

    pub fn get_mut(&mut self) -> *mut PK11SlotInfo
    {
        self.ptr
    }
}

impl Drop for SlotInfo
{
    fn drop(&mut self)
    {
        unsafe { PK11_FreeSlot(self.ptr) };
    }
}

macro_rules! create_wrapper(
    ($newname:ident, $ffiname:ty, $destructor:ident) => (
        pub struct $newname
        {
            ptr: *mut $ffiname
        }

        impl $newname
        {
            pub fn wrap(ptr: *mut $ffiname) -> NSSResult<$newname>
            {
                match ptr.is_null()
                {
                    true => Err(::ffi::nspr::get_error_code()),
                    false => Ok($newname { ptr: ptr }),
                }
            }

            #[allow(dead_code)]
            pub fn get(&self) -> *const $ffiname
            {
                self.ptr
            }

            #[allow(dead_code)]
            pub fn get_mut(&mut self) -> *mut $ffiname
            {
                self.ptr
            }
        }

        impl Drop for $newname
        {
            fn drop(&mut self)
            {
                unsafe { $destructor(self.ptr) }
            }
        }

    );
);

unsafe fn context_destructor(context: *mut PK11Context) { PK11_DestroyContext(context, PRBool::True); }

create_wrapper!(SymKey, PK11SymKey, PK11_FreeSymKey);
create_wrapper!(Context, PK11Context, context_destructor);
create_wrapper!(PrivateKey, SECKEYPrivateKey, SECKEY_DestroyPrivateKey);
create_wrapper!(PublicKey, SECKEYPublicKey, SECKEY_DestroyPublicKey);
create_wrapper!(PublicKeyInfo, CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo);

pub const KU_ALL : c_uint = 0xFF;
pub const CKZ_DATA_SPECIFIED : c_ulong = 0x0000_0001;

#[link(name="nss3")]
extern "C"
{
    fn PK11_GetBestSlot(typ: CK_MECHANISM_TYPE, wincx: *mut c_void) -> *mut PK11SlotInfo;
    fn PK11_GetInternalKeySlot() -> *mut PK11SlotInfo;
    fn PK11_FreeSlot(slot: *mut PK11SlotInfo);
    pub fn PK11_ImportSymKey(slot: *mut PK11SlotInfo, cipher: CK_MECHANISM_TYPE, origin: PK11Origin,
                             operation: CK_ATTRIBUTE_TYPE, key: *mut sec::SECItemFFI, wincx: *mut c_void)
        -> *mut PK11SymKey;
    fn PK11_FreeSymKey(key: *mut PK11SymKey);
    pub fn PK11_ParamFromIV(typ: CK_MECHANISM_TYPE, iv: *mut sec::SECItemFFI) -> *mut sec::SECItemFFI;
    pub fn PK11_CreateContextBySymKey(typ: CK_MECHANISM_TYPE, operation: CK_ATTRIBUTE_TYPE,
                                      symKey: *mut PK11SymKey, param: *mut sec::SECItemFFI) -> *mut PK11Context;
    fn PK11_DestroyContext(context: *mut PK11Context, freeit: PRBool);
    pub fn PK11_CipherOp(context: *mut PK11Context, buf_out: *mut u8, outlen: *mut c_int,
                         maxout: c_int, buf_in: *const u8, inlen: c_int) -> SECStatus;
    pub fn PK11_DigestFinal(context: *mut PK11Context, data: *mut u8, outlen: *mut c_uint, length: c_uint) -> SECStatus;

    pub fn SECKEY_ConvertToPublicKey(private_key: *mut SECKEYPrivateKey) -> *mut SECKEYPublicKey;
    fn SECKEY_DestroyPrivateKey(private_key: *mut SECKEYPrivateKey);
    fn SECKEY_DestroyPublicKey(private_key: *mut SECKEYPublicKey);
    pub fn SECKEY_DecodeDERSubjectPublicKeyInfo(spkider: *const SECItemFFI) -> *mut CERTSubjectPublicKeyInfo;
    fn SECKEY_DestroySubjectPublicKeyInfo(cert: *mut CERTSubjectPublicKeyInfo);
    pub fn SECKEY_ExtractPublicKey(cert_subject: *const CERTSubjectPublicKeyInfo) -> *mut SECKEYPublicKey;
    pub fn PK11_ImportDERPrivateKeyInfoAndReturnKey(slot: *mut PK11SlotInfo, derPKI: *mut SECItemFFI, nickname: *mut SECItemFFI,
                                                    publicValue: *mut SECItemFFI, isPerm: PRBool, isPrivate: PRBool, usage: c_uint,
                                                    privk: *mut *mut SECKEYPrivateKey, wincx: *mut c_void) -> SECStatus;
    pub fn PK11_PubEncrypt(key: *mut SECKEYPublicKey, mechanism: CK_MECHANISM_TYPE, param: *mut SECItemFFI, out: *mut u8,
                           out_len: *mut c_uint, max_len: c_uint, data: *const u8, data_len: c_uint, wincx: *mut c_void) -> SECStatus;
    pub fn SECKEY_PublicKeyStrength(key: *const SECKEYPublicKey) -> c_uint;
    pub fn PK11_PrivDecrypt(key: *mut SECKEYPrivateKey, mechanism: CK_MECHANISM_TYPE, param: *mut SECItemFFI,
                            out: *mut u8, out_len: *mut c_uint, max_len: c_uint, enc: *const u8, enc_len: c_uint) -> SECStatus;
    pub fn PK11_GenerateKeyPair(slot: *mut PK11SlotInfo, kind: CK_MECHANISM_TYPE, param: *mut c_void, pub_key: *mut *mut SECKEYPublicKey,
                                token: PRBool, sensitive: PRBool, wincx: *mut c_void) -> *mut SECKEYPrivateKey;
    pub fn SECKEY_EncodeDERSubjectPublicKeyInfo(pubk: *const SECKEYPublicKey) -> *mut SECItemFFI;
    pub fn PK11_ExportDERPrivateKeyInfo(privk: *mut SECKEYPrivateKey, wincx: *mut c_void) -> *mut SECItemFFI;
}
<commit_msg>Fix improper_ctypes warnings<commit_after>use ffi::sec;
use ffi::sec::{SECStatus, SECItemFFI};
use ffi::nspr::PRBool;
use result::NSSResult;
use libc::{c_void, c_int, c_uint, c_ulong};
use std::ptr;

#[allow(non_camel_case_types)]
pub type CK_MECHANISM_TYPE = c_ulong;

pub const CKM_RSA_PKCS_KEY_PAIR_GEN : CK_MECHANISM_TYPE = 0x0000_0000;
pub const CKM_RSA_PKCS      : CK_MECHANISM_TYPE = 0x0000_0001;
pub const CKM_RSA_PKCS_OAEP : CK_MECHANISM_TYPE = 0x0000_0009;

pub const CKM_SHA_1   : CK_MECHANISM_TYPE = 0x0000_0220;
pub const CKM_SHA_224 : CK_MECHANISM_TYPE = 0x0000_0255;
pub const CKM_SHA_256 : CK_MECHANISM_TYPE = 0x0000_0250;
pub const CKM_SHA_384 : CK_MECHANISM_TYPE = 0x0000_0260;
pub const CKM_SHA_512 : CK_MECHANISM_TYPE = 0x0000_0270;

pub const CKM_DES_ECB     : CK_MECHANISM_TYPE = 0x0000_0121;
pub const CKM_DES_CBC     : CK_MECHANISM_TYPE = 0x0000_0122;
pub const CKM_DES_CBC_PAD : CK_MECHANISM_TYPE = 0x0000_0125;
pub const CKM_AES_ECB     : CK_MECHANISM_TYPE = 0x0000_1081;
pub const CKM_AES_CBC     : CK_MECHANISM_TYPE = 0x0000_1082;
pub const CKM_AES_CBC_PAD : CK_MECHANISM_TYPE = 0x0000_1085;
// CK_MECHANISM_TYPE

#[allow(non_camel_case_types)]
pub type CK_ATTRIBUTE_TYPE = c_ulong;

pub const CKA_ENCRYPT : CK_ATTRIBUTE_TYPE = 0x0000_0104;
pub const CKA_DECRYPT : CK_ATTRIBUTE_TYPE = 0x0000_0105;
// CK_ATTRIBUTE_TYPE

#[allow(non_camel_case_types)]
type CK_RSA_PKCS_MGF_TYPE = c_ulong;

const CKG_MGF1_SHA1   : CK_RSA_PKCS_MGF_TYPE = 0x0000_0001;
const CKG_MGF1_SHA224 : CK_RSA_PKCS_MGF_TYPE = 0x0000_0005;
const CKG_MGF1_SHA256 : CK_RSA_PKCS_MGF_TYPE = 0x0000_0002;
const CKG_MGF1_SHA384 : CK_RSA_PKCS_MGF_TYPE = 0x0000_0003;
const CKG_MGF1_SHA512 : CK_RSA_PKCS_MGF_TYPE = 0x0000_0004;
// CK_RSA_PKCS_MGF_TYPE

#[repr(C)]
#[allow(dead_code)] // List all available options
pub enum PK11Origin
{
    OriginNULL = 0,
    OriginDerive = 1,
    OriginGenerated = 2,
    OriginFortezzaHack = 3,
    OriginUnwrap = 4,
}

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct CK_RSA_PKCS_OAEP_PARAMS
{
    hash_alg: CK_MECHANISM_TYPE,
    mgf: CK_RSA_PKCS_MGF_TYPE,
    source: c_ulong,
    data_source: *mut c_void,
    data_len: c_ulong,
}

impl CK_RSA_PKCS_OAEP_PARAMS
{
    pub fn from_algorithm(ckm: CK_MECHANISM_TYPE) -> CK_RSA_PKCS_OAEP_PARAMS
    {
        let mgf = mgf_type_from_ckm(ckm);
        CK_RSA_PKCS_OAEP_PARAMS
        {
            hash_alg: ckm,
            mgf: mgf,
            source: CKZ_DATA_SPECIFIED,
            data_source: ptr::null_mut(),
            data_len: 0,
        }
    }
}

fn mgf_type_from_ckm(ckm: CK_MECHANISM_TYPE) -> CK_RSA_PKCS_MGF_TYPE
{
    match ckm
    {
        CKM_SHA_1 => CKG_MGF1_SHA1,
        CKM_SHA_224 => CKG_MGF1_SHA224,
        CKM_SHA_256 => CKG_MGF1_SHA256,
        CKM_SHA_384 => CKG_MGF1_SHA384,
        CKM_SHA_512 => CKG_MGF1_SHA512,
        _ => panic!("Unsupported mechanism provided"),
    }
}

pub struct PK11RSAGenParams
{
    pub key_size_bits: c_int,
    pub pe: c_ulong,
}

// Opaque structures, with pointer references only
#[repr(C)] pub struct PK11SlotInfo(c_void);
#[repr(C)] pub struct PK11Context(c_void);
#[repr(C)] pub struct PK11SymKey(c_void);
#[repr(C)] pub struct SECKEYPrivateKey(c_void);
#[repr(C)] pub struct SECKEYPublicKey(c_void);
#[repr(C)] pub struct CERTSubjectPublicKeyInfo(c_void);

pub struct SlotInfo
{
    ptr: *mut PK11SlotInfo
}

impl SlotInfo
{
    pub fn get_internal() -> NSSResult<SlotInfo>
    {
        let ptr = unsafe { PK11_GetInternalKeySlot() };
        SlotInfo::from_ptr(ptr)
    }

    pub fn get_best(mechanism: CK_MECHANISM_TYPE) -> NSSResult<SlotInfo>
    {
        let ptr = unsafe { PK11_GetBestSlot(mechanism, ptr::null_mut()) };
        SlotInfo::from_ptr(ptr)
    }

    fn from_ptr(ptr: *mut PK11SlotInfo) -> NSSResult<SlotInfo>
    {
        if ptr.is_null() {
            Err(::ffi::nspr::get_error_code())
        }
        else {
            Ok(SlotInfo { ptr: ptr })
        }
    }

    pub fn get_mut(&mut self) -> *mut PK11SlotInfo
    {
        self.ptr
    }
}

impl Drop for SlotInfo
{
    fn drop(&mut self)
    {
        unsafe { PK11_FreeSlot(self.ptr) };
    }
}

macro_rules! create_wrapper(
    ($newname:ident, $ffiname:ty, $destructor:ident) => (
        pub struct $newname
        {
            ptr: *mut $ffiname
        }

        impl $newname
        {
            pub fn wrap(ptr: *mut $ffiname) -> NSSResult<$newname>
            {
                match ptr.is_null()
                {
                    true => Err(::ffi::nspr::get_error_code()),
                    false => Ok($newname { ptr: ptr }),
                }
            }

            #[allow(dead_code)]
            pub fn get(&self) -> *const $ffiname
            {
                self.ptr
            }

            #[allow(dead_code)]
            pub fn get_mut(&mut self) -> *mut $ffiname
            {
                self.ptr
            }
        }

        impl Drop for $newname
        {
            fn drop(&mut self)
            {
                unsafe { $destructor(self.ptr) }
            }
        }

    );
);

unsafe fn context_destructor(context: *mut PK11Context) { PK11_DestroyContext(context, PRBool::True); }

create_wrapper!(SymKey, PK11SymKey, PK11_FreeSymKey);
create_wrapper!(Context, PK11Context, context_destructor);
create_wrapper!(PrivateKey, SECKEYPrivateKey, SECKEY_DestroyPrivateKey);
create_wrapper!(PublicKey, SECKEYPublicKey, SECKEY_DestroyPublicKey);
create_wrapper!(PublicKeyInfo, CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo);

pub const KU_ALL : c_uint = 0xFF;
pub const CKZ_DATA_SPECIFIED : c_ulong = 0x0000_0001;

#[link(name="nss3")]
extern "C"
{
    fn PK11_GetBestSlot(typ: CK_MECHANISM_TYPE, wincx: *mut c_void) -> *mut PK11SlotInfo;
    fn PK11_GetInternalKeySlot() -> *mut PK11SlotInfo;
    fn PK11_FreeSlot(slot: *mut PK11SlotInfo);
    pub fn PK11_ImportSymKey(slot: *mut PK11SlotInfo, cipher: CK_MECHANISM_TYPE, origin: PK11Origin,
                             operation: CK_ATTRIBUTE_TYPE, key: *mut sec::SECItemFFI, wincx: *mut c_void)
        -> *mut PK11SymKey;
    fn PK11_FreeSymKey(key: *mut PK11SymKey);
    pub fn PK11_ParamFromIV(typ: CK_MECHANISM_TYPE, iv: *mut sec::SECItemFFI) -> *mut sec::SECItemFFI;
    pub fn PK11_CreateContextBySymKey(typ: CK_MECHANISM_TYPE, operation: CK_ATTRIBUTE_TYPE,
                                      symKey: *mut PK11SymKey, param: *mut sec::SECItemFFI) -> *mut PK11Context;
    fn PK11_DestroyContext(context: *mut PK11Context, freeit: PRBool);
    pub fn PK11_CipherOp(context: *mut PK11Context, buf_out: *mut u8, outlen: *mut c_int,
                         maxout: c_int, buf_in: *const u8, inlen: c_int) -> SECStatus;
    pub fn PK11_DigestFinal(context: *mut PK11Context, data: *mut u8, outlen: *mut c_uint, length: c_uint) -> SECStatus;

    pub fn SECKEY_ConvertToPublicKey(private_key: *mut SECKEYPrivateKey) -> *mut SECKEYPublicKey;
    fn SECKEY_DestroyPrivateKey(private_key: *mut SECKEYPrivateKey);
    fn SECKEY_DestroyPublicKey(private_key: *mut SECKEYPublicKey);
    pub fn SECKEY_DecodeDERSubjectPublicKeyInfo(spkider: *const SECItemFFI) -> *mut CERTSubjectPublicKeyInfo;
    fn SECKEY_DestroySubjectPublicKeyInfo(cert: *mut CERTSubjectPublicKeyInfo);
    pub fn SECKEY_ExtractPublicKey(cert_subject: *const CERTSubjectPublicKeyInfo) -> *mut SECKEYPublicKey;
    pub fn PK11_ImportDERPrivateKeyInfoAndReturnKey(slot: *mut PK11SlotInfo, derPKI: *mut SECItemFFI, nickname: *mut SECItemFFI,
                                                    publicValue: *mut SECItemFFI, isPerm: PRBool, isPrivate: PRBool, usage: c_uint,
                                                    privk: *mut *mut SECKEYPrivateKey, wincx: *mut c_void) -> SECStatus;
    pub fn PK11_PubEncrypt(key: *mut SECKEYPublicKey, mechanism: CK_MECHANISM_TYPE, param: *mut SECItemFFI, out: *mut u8,
                           out_len: *mut c_uint, max_len: c_uint, data: *const u8, data_len: c_uint, wincx: *mut c_void) -> SECStatus;
    pub fn SECKEY_PublicKeyStrength(key: *const SECKEYPublicKey) -> c_uint;
    pub fn PK11_PrivDecrypt(key: *mut SECKEYPrivateKey, mechanism: CK_MECHANISM_TYPE, param: *mut SECItemFFI,
                            out: *mut u8, out_len: *mut c_uint, max_len: c_uint, enc: *const u8, enc_len: c_uint) -> SECStatus;
    pub fn PK11_GenerateKeyPair(slot: *mut PK11SlotInfo, kind: CK_MECHANISM_TYPE, param: *mut c_void, pub_key: *mut *mut SECKEYPublicKey,
                                token: PRBool, sensitive: PRBool, wincx: *mut c_void) -> *mut SECKEYPrivateKey;
    pub fn SECKEY_EncodeDERSubjectPublicKeyInfo(pubk: *const SECKEYPublicKey) -> *mut SECItemFFI;
    pub fn PK11_ExportDERPrivateKeyInfo(privk: *mut SECKEYPrivateKey, wincx: *mut c_void) -> *mut SECItemFFI;
}
<|endoftext|>


<commit_before>use std::ops::{Index, IndexMut};
use sha1::{Sha1, Digest};
use metainfo::FileInfo;

pub struct PartialFile {
    collection: PieceCollection,
    info: FileInfo
}

impl PartialFile {
    pub fn new(info: &FileInfo) -> PartialFile {
        PartialFile {
            info: info.clone(),
            collection: PieceCollection::new(info.piece_length as usize,
                info.pieces.len() as u64)
        }
    }

    pub fn is_complete(&self) -> bool {
        for i in 0..self.info.pieces.len() {
            if !self._is_piece_complete(i) {
                return false;
            }
        }
        true
    }

    pub fn has_piece(&self, i: usize) -> bool {
        self._is_piece_complete(i)
    }

    pub fn get_piece_mut<'a>(&self, i: usize) -> &'a mut Piece {
        &mut self.collection.pieces[i]
    }

    fn _is_piece_complete(&self, i: usize) -> bool {
        let mut sha1: Sha1 = Sha1::new();
        sha1.update(&self.collection[i]);
        let ref bytes1 = sha1.digest().bytes();
        let ref bytes2 = self.info.pieces[i];
        bytes1 == bytes2.as_slice()
    }

    pub fn bit_array(&self) -> Vec<bool> {
        (0..self.info.pieces.len())
            .map(|i| self._is_piece_complete(i))
            .collect::<Vec<bool>>()
    }

    pub fn add_piece(&mut self, index: usize, offset: usize, block: Vec<u8>) -> bool {
        self.collection.add(index, offset, block)
    }
}

struct Piece {
    data: Vec<u8>,
    length: u32
}

impl Piece {
    pub fn add(&mut self: offset: u32, block: Vec<u8>) {

    }

    pub fn get_offset(
}

struct PieceCollection {
    pieces: Vec<Vec<u8>>,
    piece_size: u64
}

impl PieceCollection {
    pub fn new(pieces: usize, size: u64) -> PieceCollection {
        let mut vec = Vec::new();
        for i in 0..pieces {
            vec.push(Vec::new());
        }
        PieceCollection { pieces: vec, piece_size: size }
    }

    pub fn add(&mut self, index: usize, offset: usize, block: Vec<u8>) -> bool {
        if index >= self.pieces.len() { return false; }
        if offset + block.len() > self.piece_size as usize {
            return false;
        }

        let existing_block = &mut self.pieces[index];
        existing_block.resize(offset + block.len(), 0);
        for i in 0..block.len() {
            existing_block[offset + i as usize] = block[i];
        }
        true
    }
}

impl Index<usize> for PieceCollection {
    type Output = Vec<u8>;

    fn index<'a>(&'a self, _index: usize) -> &'a Vec<u8> {
        &self.pieces[_index]
    }
}

impl IndexMut<usize> for PieceCollection {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut Vec<u8> {
        &mut self.pieces[_index]
    }
}
<commit_msg>Use Piece type in PieceCollection<commit_after>use std::ops::{Index, IndexMut};
use sha1::{Sha1, Digest};
use metainfo::FileInfo;
use metainfo::SHA1Hash20b;

pub struct PartialFile {
    collection: PieceCollection,
    info: FileInfo
}

impl PartialFile {
    pub fn new(info: &FileInfo) -> PartialFile {
        PartialFile {
            info: info.clone(),
            collection: PieceCollection::new(info.piece_length as usize,
                info.pieces.len() as u64)
        }
    }

    pub fn is_complete(&self) -> bool {
        for i in 0..self.info.pieces.len() {
            if !self._is_piece_complete(i) {
                return false;
            }
        }
        true
    }

    pub fn has_piece(&self, i: usize) -> bool {
        self._is_piece_complete(i)
    }

    pub fn get_piece_mut<'a>(&self, i: usize) -> &'a mut Piece {
        &mut self.collection.pieces[i]
    }

    fn _is_piece_complete(&self, i: usize) -> bool {
        let mut sha1: Sha1 = Sha1::new();
        sha1.update(&self.collection[i]);
        let ref bytes1 = sha1.digest().bytes();
        let ref bytes2 = self.info.pieces[i];
        bytes1 == bytes2.as_slice()
    }

    pub fn bit_array(&self) -> Vec<bool> {
        (0..self.info.pieces.len())
            .map(|i| self._is_piece_complete(i))
            .collect::<Vec<bool>>()
    }

    pub fn add_piece(&mut self, index: usize, offset: usize, block: Vec<u8>) -> bool {
        self.collection.add(index, offset, block)
    }
}

struct Piece {
    data: Vec<u8>,
    length: u32
}

impl Piece {
    pub fn new(length: u32, hash: SHA1Hash20b) -> Piece {
        Piece {
            data: Vec::new(),
            length: length,
            hash: hash
        }
    }
    pub fn add(&mut self, offset: u32, block: &[u8]) -> bool {
        if offset > self.length || self.is_complete() {
            return false;
        }
        let existing_block = self.data;
        existing_block.resize(offset + block.len(), 0);
        for i in 0..block.len() {
            existing_block[offset + i as usize] = block[i];
        }
        true
    }

    pub fn get_offset<'a>(&'a self, offset: usize) -> Option<&'a mut &[u8]> {
        unimplemented!()
    }

    pub fn is_complete(&self) -> bool {
        let mut sha1: Sha1 = Sha1::new();
        sha1.update(&self.data);
        let ref bytes1 = sha1.digest().bytes();
        let ref bytes2 = self.hash;
        bytes1 == bytes2.as_slice()
    }
}

struct PieceCollection {
    pieces: Vec<Piece>,
    piece_size: u64
}

impl PieceCollection {
    pub fn new(pieces: &[SHA1Hash20b], size: u64) -> PieceCollection {
        let mut vec = Vec::new();
        for hash in pieces {
            vec.push(Piece::new(size, hash));
        }
        PieceCollection { pieces: vec, piece_size: size }
    }

    pub fn add(&mut self, index: usize, offset: usize, block: Vec<u8>) -> bool {
        if index >= self.pieces.len() { return false; }
        if offset + block.len() > self.piece_size as usize {
            return false;
        }

        let existing_block = &mut self.pieces[index];
        existing_block.resize(offset + block.len(), 0);
        for i in 0..block.len() {
            existing_block[offset + i as usize] = block[i];
        }
        true
    }
}

impl Index<usize> for PieceCollection {
    type Output = Piece;

    fn index<'a>(&'a self, _index: usize) -> &'a Piece {
        &self.pieces[_index]
    }
}

impl IndexMut<usize> for PieceCollection {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut Piece {
        &mut self.pieces[_index]
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use libc;
use std::{mem, ptr, io, any, marker};
#[cfg(feature="nightly")] use std::panic;
use std::ffi::{CString, CStr};
use python::{Python, PythonObject, PyDrop};
use objects::{PyObject, PyTuple, PyDict, PyString, exc};
use conversion::ToPyObject;
use ffi;
use err::{self, PyResult};

#[macro_export]
#[doc(hidden)]
macro_rules! py_method_def {
    ($name: expr, $flags: expr, $wrap: expr) => {{
        static mut method_def: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
            //ml_name: bytes!(stringify!($name), "\0"),
            ml_name: 0 as *const $crate::_detail::libc::c_char,
            ml_meth: None,
            ml_flags: $crate::_detail::ffi::METH_VARARGS | $crate::_detail::ffi::METH_KEYWORDS | $flags,
            ml_doc: 0 as *const $crate::_detail::libc::c_char
        };
        method_def.ml_name = concat!($name, "\0").as_ptr() as *const _;
        method_def.ml_meth = Some(
            ::std::mem::transmute::<$crate::_detail::ffi::PyCFunctionWithKeywords,
                                  $crate::_detail::ffi::PyCFunction>($wrap)
        );
        &mut method_def
    }}
}

/// Creates a Python callable object that invokes a Rust function.
///
/// There are two forms of this macro:
/// 1) `py_fn!(py, f(parameter_list))`
/// 2) `py_fn!(py, f(parameter_list) -> PyResult<T> { body })`
///
/// All three forms return a value of type `PyObject`.
/// This python object is a callable object that invokes
/// the Rust function when called.
///
/// When called, the arguments are converted into
/// the Rust types specified in the parameter list.
/// See `py_argparse!()` for details on argument parsing.
///
/// Form 1:
/// * `py` must be an expression of type `Python`
/// * `f` must be the name of a function that is compatible with the specified
///    parameter list, except that a single parameter of type `Python` is prepended.
///    The function must return `PyResult<T>` for some `T` that implements `ToPyObject`.
///
/// Form 2:
/// * `py` must be an identifier refers to a `Python` value.
///   The function body will also have access to a `Python` variable of this name.
/// * `f` must be an identifier.
/// * The function return type must be `PyResult<T>` for some `T` that
///   implements `ToPyObject`.
///
/// # Example
/// ```
/// #[macro_use] extern crate cpython;
/// use cpython::{Python, PyResult, PyErr, PyDict};
/// use cpython::{exc};
///
/// fn multiply(py: Python, lhs: i32, rhs: i32) -> PyResult<i32> {
///     match lhs.checked_mul(rhs) {
///         Some(val) => Ok(val),
///         None => Err(PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None))
///     }
/// }
///
/// fn main() {
///     let gil = Python::acquire_gil();
///     let py = gil.python();
///     let dict = PyDict::new(py);
///     dict.set_item(py, "multiply", py_fn!(py, multiply(lhs: i32, rhs: i32))).unwrap();
///     py.run("print(multiply(6, 7))", None, Some(&dict)).unwrap();
/// }
/// ```
#[macro_export]
macro_rules! py_fn {
    ($py:expr, $f:ident $plist:tt ) => {
        py_argparse_parse_plist! { py_fn_impl { $py, $f } $plist }
    };
    ($py:ident, $f:ident $plist:tt -> $ret:ty { $($body:tt)* } ) => {
        py_argparse_parse_plist! { py_fn_impl { $py, $f, $ret, { $($body)* } } $plist }
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! py_fn_impl {
    // Form 1: reference existing function
    { $py:expr, $f:ident [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ] } => {{
        // <DUMMY> is workaround for rust issue #26201
        unsafe extern "C" fn wrap<DUMMY>(
            _slf: *mut $crate::_detail::ffi::PyObject,
            args: *mut $crate::_detail::ffi::PyObject,
            kwargs: *mut $crate::_detail::ffi::PyObject)
        -> *mut $crate::_detail::ffi::PyObject
        {
            $crate::_detail::handle_callback(
                stringify!($f), $crate::_detail::PyObjectCallbackConverter,
                |py| {
                    py_argparse_raw!(py, Some(stringify!($f)), args, kwargs,
                        [ $( { $pname : $ptype = $detail } )* ]
                        {
                            $f(py $(, $pname )* )
                        })
                })
        }
        unsafe {
            $crate::_detail::py_fn_impl($py,
                py_method_def!(stringify!($f), 0, wrap::<()>))
        }
    }};
    // Form 2: inline function definition
    { $py:ident, $f:ident, $ret:ty, $body:block [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ] } => {{
        fn $f($py: $crate::Python $( , $pname : $ptype )* ) -> $ret $body
        py_fn_impl!($py, $f [ $( { $pname : $ptype = $detail } )* ])
    }}
}

pub unsafe fn py_fn_impl(py: Python, method_def: *mut ffi::PyMethodDef) -> PyObject {
    err::from_owned_ptr_or_panic(py, ffi::PyCFunction_New(method_def, ptr::null_mut()))
}

pub trait CallbackConverter<S> {
    type R;

    fn convert(S, Python) -> Self::R;
    fn error_value() -> Self::R;
}

pub struct PyObjectCallbackConverter;

impl <S> CallbackConverter<S> for PyObjectCallbackConverter
    where S: ToPyObject
{
    type R = *mut ffi::PyObject;

    fn convert(val: S, py: Python) -> *mut ffi::PyObject {
        val.into_py_object(py).into_object().steal_ptr()
    }

    #[inline]
    fn error_value() -> *mut ffi::PyObject {
        ptr::null_mut()
    }
}

pub struct PythonObjectCallbackConverter<T>(pub marker::PhantomData<T>);

impl <T, S> CallbackConverter<S> for PythonObjectCallbackConverter<T>
    where T: PythonObject,
          S: ToPyObject<ObjectType=T>
{
    type R = *mut ffi::PyObject;

    fn convert(val: S, py: Python) -> *mut ffi::PyObject {
        val.into_py_object(py).into_object().steal_ptr()
    }

    #[inline]
    fn error_value() -> *mut ffi::PyObject {
        ptr::null_mut()
    }
}

#[cfg(feature="nightly")]
pub unsafe fn handle_callback<F, T, C>(location: &str, _c: C, f: F) -> C::R
    where F: FnOnce(Python) -> PyResult<T>,
          F: panic::UnwindSafe,
          C: CallbackConverter<T>
{
    let guard = AbortOnDrop(location);
    let ret = panic::catch_unwind(|| {
        let py = Python::assume_gil_acquired();
        match f(py) {
            Ok(val) => {
                C::convert(val, py)
            }
            Err(e) => {
                e.restore(py);
                C::error_value()
            }
        }
    });
    let ret = match ret {
        Ok(r) => r,
        Err(ref err) => {
            handle_panic(Python::assume_gil_acquired(), err);
            C::error_value()
        }
    };
    mem::forget(guard);
    ret
}

#[cfg(feature="nightly")]
fn handle_panic(_py: Python, _panic: &any::Any) {
    let msg = cstr!("Rust panic");
    unsafe {
        ffi::PyErr_SetString(ffi::PyExc_SystemError, msg.as_ptr());
    }
}

#[cfg(not(feature="nightly"))]
pub unsafe fn handle_callback<F, T, C>(location: &str, _c: C, f: F) -> C::R
    where F: FnOnce(Python) -> PyResult<T>,
          C: CallbackConverter<T>
{
    let guard = AbortOnDrop(location);
    let py = Python::assume_gil_acquired();
    let ret = match f(py) {
        Ok(val) => {
            C::convert(val, py)
        }
        Err(e) => {
            e.restore(py);
            C::error_value()
        }
    };
    mem::forget(guard);
    ret
}

pub struct AbortOnDrop<'a>(pub &'a str);

impl <'a> Drop for AbortOnDrop<'a> {
    fn drop(&mut self) {
        use std::io::Write;
        let _ = writeln!(&mut io::stderr(), "Cannot unwind out of {}", self.0);
        unsafe { libc::abort() }
    }
}

// Tests for this file are in tests/test_function.rs

<commit_msg>Fix Markdown formatting in py_fn!'s documentation<commit_after>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use libc;
use std::{mem, ptr, io, any, marker};
#[cfg(feature="nightly")] use std::panic;
use std::ffi::{CString, CStr};
use python::{Python, PythonObject, PyDrop};
use objects::{PyObject, PyTuple, PyDict, PyString, exc};
use conversion::ToPyObject;
use ffi;
use err::{self, PyResult};

#[macro_export]
#[doc(hidden)]
macro_rules! py_method_def {
    ($name: expr, $flags: expr, $wrap: expr) => {{
        static mut method_def: $crate::_detail::ffi::PyMethodDef = $crate::_detail::ffi::PyMethodDef {
            //ml_name: bytes!(stringify!($name), "\0"),
            ml_name: 0 as *const $crate::_detail::libc::c_char,
            ml_meth: None,
            ml_flags: $crate::_detail::ffi::METH_VARARGS | $crate::_detail::ffi::METH_KEYWORDS | $flags,
            ml_doc: 0 as *const $crate::_detail::libc::c_char
        };
        method_def.ml_name = concat!($name, "\0").as_ptr() as *const _;
        method_def.ml_meth = Some(
            ::std::mem::transmute::<$crate::_detail::ffi::PyCFunctionWithKeywords,
                                  $crate::_detail::ffi::PyCFunction>($wrap)
        );
        &mut method_def
    }}
}

/// Creates a Python callable object that invokes a Rust function.
///
/// There are two forms of this macro:
///
/// 1. `py_fn!(py, f(parameter_list))`
/// 1. `py_fn!(py, f(parameter_list) -> PyResult<T> { body })`
///
/// All three forms return a value of type `PyObject`.
/// This python object is a callable object that invokes
/// the Rust function when called.
///
/// When called, the arguments are converted into
/// the Rust types specified in the parameter list.
/// See `py_argparse!()` for details on argument parsing.
///
/// Form 1:
///
/// * `py` must be an expression of type `Python`
/// * `f` must be the name of a function that is compatible with the specified
///    parameter list, except that a single parameter of type `Python` is prepended.
///    The function must return `PyResult<T>` for some `T` that implements `ToPyObject`.
///
/// Form 2:
///
/// * `py` must be an identifier refers to a `Python` value.
///   The function body will also have access to a `Python` variable of this name.
/// * `f` must be an identifier.
/// * The function return type must be `PyResult<T>` for some `T` that
///   implements `ToPyObject`.
///
/// # Example
/// ```
/// #[macro_use] extern crate cpython;
/// use cpython::{Python, PyResult, PyErr, PyDict};
/// use cpython::{exc};
///
/// fn multiply(py: Python, lhs: i32, rhs: i32) -> PyResult<i32> {
///     match lhs.checked_mul(rhs) {
///         Some(val) => Ok(val),
///         None => Err(PyErr::new_lazy_init(py.get_type::<exc::OverflowError>(), None))
///     }
/// }
///
/// fn main() {
///     let gil = Python::acquire_gil();
///     let py = gil.python();
///     let dict = PyDict::new(py);
///     dict.set_item(py, "multiply", py_fn!(py, multiply(lhs: i32, rhs: i32))).unwrap();
///     py.run("print(multiply(6, 7))", None, Some(&dict)).unwrap();
/// }
/// ```
#[macro_export]
macro_rules! py_fn {
    ($py:expr, $f:ident $plist:tt ) => {
        py_argparse_parse_plist! { py_fn_impl { $py, $f } $plist }
    };
    ($py:ident, $f:ident $plist:tt -> $ret:ty { $($body:tt)* } ) => {
        py_argparse_parse_plist! { py_fn_impl { $py, $f, $ret, { $($body)* } } $plist }
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! py_fn_impl {
    // Form 1: reference existing function
    { $py:expr, $f:ident [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ] } => {{
        // <DUMMY> is workaround for rust issue #26201
        unsafe extern "C" fn wrap<DUMMY>(
            _slf: *mut $crate::_detail::ffi::PyObject,
            args: *mut $crate::_detail::ffi::PyObject,
            kwargs: *mut $crate::_detail::ffi::PyObject)
        -> *mut $crate::_detail::ffi::PyObject
        {
            $crate::_detail::handle_callback(
                stringify!($f), $crate::_detail::PyObjectCallbackConverter,
                |py| {
                    py_argparse_raw!(py, Some(stringify!($f)), args, kwargs,
                        [ $( { $pname : $ptype = $detail } )* ]
                        {
                            $f(py $(, $pname )* )
                        })
                })
        }
        unsafe {
            $crate::_detail::py_fn_impl($py,
                py_method_def!(stringify!($f), 0, wrap::<()>))
        }
    }};
    // Form 2: inline function definition
    { $py:ident, $f:ident, $ret:ty, $body:block [ $( { $pname:ident : $ptype:ty = $detail:tt } )* ] } => {{
        fn $f($py: $crate::Python $( , $pname : $ptype )* ) -> $ret $body
        py_fn_impl!($py, $f [ $( { $pname : $ptype = $detail } )* ])
    }}
}

pub unsafe fn py_fn_impl(py: Python, method_def: *mut ffi::PyMethodDef) -> PyObject {
    err::from_owned_ptr_or_panic(py, ffi::PyCFunction_New(method_def, ptr::null_mut()))
}

pub trait CallbackConverter<S> {
    type R;

    fn convert(S, Python) -> Self::R;
    fn error_value() -> Self::R;
}

pub struct PyObjectCallbackConverter;

impl <S> CallbackConverter<S> for PyObjectCallbackConverter
    where S: ToPyObject
{
    type R = *mut ffi::PyObject;

    fn convert(val: S, py: Python) -> *mut ffi::PyObject {
        val.into_py_object(py).into_object().steal_ptr()
    }

    #[inline]
    fn error_value() -> *mut ffi::PyObject {
        ptr::null_mut()
    }
}

pub struct PythonObjectCallbackConverter<T>(pub marker::PhantomData<T>);

impl <T, S> CallbackConverter<S> for PythonObjectCallbackConverter<T>
    where T: PythonObject,
          S: ToPyObject<ObjectType=T>
{
    type R = *mut ffi::PyObject;

    fn convert(val: S, py: Python) -> *mut ffi::PyObject {
        val.into_py_object(py).into_object().steal_ptr()
    }

    #[inline]
    fn error_value() -> *mut ffi::PyObject {
        ptr::null_mut()
    }
}

#[cfg(feature="nightly")]
pub unsafe fn handle_callback<F, T, C>(location: &str, _c: C, f: F) -> C::R
    where F: FnOnce(Python) -> PyResult<T>,
          F: panic::UnwindSafe,
          C: CallbackConverter<T>
{
    let guard = AbortOnDrop(location);
    let ret = panic::catch_unwind(|| {
        let py = Python::assume_gil_acquired();
        match f(py) {
            Ok(val) => {
                C::convert(val, py)
            }
            Err(e) => {
                e.restore(py);
                C::error_value()
            }
        }
    });
    let ret = match ret {
        Ok(r) => r,
        Err(ref err) => {
            handle_panic(Python::assume_gil_acquired(), err);
            C::error_value()
        }
    };
    mem::forget(guard);
    ret
}

#[cfg(feature="nightly")]
fn handle_panic(_py: Python, _panic: &any::Any) {
    let msg = cstr!("Rust panic");
    unsafe {
        ffi::PyErr_SetString(ffi::PyExc_SystemError, msg.as_ptr());
    }
}

#[cfg(not(feature="nightly"))]
pub unsafe fn handle_callback<F, T, C>(location: &str, _c: C, f: F) -> C::R
    where F: FnOnce(Python) -> PyResult<T>,
          C: CallbackConverter<T>
{
    let guard = AbortOnDrop(location);
    let py = Python::assume_gil_acquired();
    let ret = match f(py) {
        Ok(val) => {
            C::convert(val, py)
        }
        Err(e) => {
            e.restore(py);
            C::error_value()
        }
    };
    mem::forget(guard);
    ret
}

pub struct AbortOnDrop<'a>(pub &'a str);

impl <'a> Drop for AbortOnDrop<'a> {
    fn drop(&mut self) {
        use std::io::Write;
        let _ = writeln!(&mut io::stderr(), "Cannot unwind out of {}", self.0);
        unsafe { libc::abort() }
    }
}

// Tests for this file are in tests/test_function.rs

<|endoftext|>


<commit_before>//! `GraphMap<N, E>` is an undirected graph where node values are mapping keys.

use std::hash::{Hash};
use std::collections::HashMap;
use std::iter::Cloned;
use std::collections::hash_map::{
    Keys,
};
use std::collections::hash_map::Iter as HashmapIter;
use std::slice::{
    Iter,
};
use std::fmt;
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};

use IntoWeightedEdge;

/// `GraphMap<N, E>` is an undirected graph, with generic node values `N` and edge weights `E`.
///
/// It uses an combined adjacency list and sparse adjacency matrix representation, using **O(|V|
/// + |E|)** space, and allows testing for edge existance in constant time.
///
/// The node type `N` must implement `Copy` and will be used as node identifier, duplicated
/// into several places in the data structure.
/// It must be suitable as a hash table key (implementing `Eq + Hash`).
/// The node type must also implement `Ord` so that the implementation can
/// order the pair (`a`, `b`) for an edge connecting any two nodes `a` and `b`.
///
/// `GraphMap` does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct GraphMap<N, E> {
    nodes: HashMap<N, Vec<N>>,
    edges: HashMap<(N, N), E>,
}

impl<N: Eq + Hash + fmt::Debug, E: fmt::Debug> fmt::Debug for GraphMap<N, E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.nodes.fmt(f)
    }
}

/// Use their natual order to map the node pair (a, b) to a canonical edge id.
#[inline]
fn edge_key<N: Copy + Ord>(a: N, b: N) -> (N, N) {
    if a <= b { (a, b) } else { (b, a) }
}

/// A trait group for `GraphMap`'s node identifier.
pub trait NodeTrait : Copy + Ord + Hash {}
impl<N> NodeTrait for N where N: Copy + Ord + Hash {}

impl<N, E> GraphMap<N, E>
    where N: NodeTrait
{
    /// Create a new `GraphMap`.
    pub fn new() -> Self {
        GraphMap {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    /// Create a new `GraphMap` with estimated capacity.
    pub fn with_capacity(nodes: usize, edges: usize) -> Self {
        GraphMap {
            nodes: HashMap::with_capacity(nodes),
            edges: HashMap::with_capacity(edges),
        }
    }

    /// Return the current node and edge capacity of the graph.
    pub fn capacity(&self) -> (usize, usize) {
        (self.nodes.capacity(), self.edges.capacity())
    }

    /// Create a new `GraphMap` from an iterable of edges.
    ///
    /// Node values are taken directly from the list.
    /// Edge weights `E` may either be specified in the list,
    /// or they are filled with default values.
    ///
    /// Nodes are inserted automatically to match the edges.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let gr = GraphMap::<_, ()>::from_edges(&[
    ///     (0, 1), (0, 2), (0, 3),
    ///     (1, 2), (1, 3),
    ///     (2, 3),
    /// ]);
    /// ```
    pub fn from_edges<I>(iterable: I) -> Self
        where I: IntoIterator,
              I::Item: IntoWeightedEdge<N, E>
    {
        Self::from_iter(iterable)
    }

    /// Return the number of nodes in the graph.
    pub fn node_count(&self) -> usize {
        self.nodes.len()
    }

    /// Return the number of edges in the graph.
    pub fn edge_count(&self) -> usize {
        self.edges.len()
    }

    /// Remove all nodes and edges
    pub fn clear(&mut self) {
        self.nodes.clear();
        self.edges.clear();
    }

    /// Add node `n` to the graph.
    pub fn add_node(&mut self, n: N) -> N {
        self.nodes.entry(n).or_insert_with(|| Vec::new());
        n
    }

    /// Return `true` if node `n` was removed.
    pub fn remove_node(&mut self, n: N) -> bool {
        let successors = match self.nodes.remove(&n) {
            None => return false,
            Some(sus) => sus,
        };
        for succ in successors.into_iter() {
            // remove all successor links
            self.remove_single_edge(&succ, &n);
            // Remove all edge values
            self.edges.remove(&edge_key(n, succ));
        }
        true
    }

    /// Return `true` if the node is contained in the graph.
    pub fn contains_node(&self, n: N) -> bool {
        self.nodes.contains_key(&n)
    }

    /// Add an edge connecting `a` and `b` to the graph, with associated
    /// data `weight`.
    ///
    /// Inserts nodes `a` and/or `b` if they aren't already part of the graph.
    ///
    /// Return `None` if the edge did not previously exist, otherwise,
    /// the associated data is updated and the old value is returned
    /// as `Some(old_weight)`.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    /// assert_eq!(g.node_count(), 2);
    /// assert_eq!(g.edge_count(), 1);
    /// ```
    pub fn add_edge(&mut self, a: N, b: N, weight: E) -> Option<E> {
        if let old @ Some(_) = self.edges.insert(edge_key(a, b), weight) {
            old
        } else {
            // insert in the adjacency list if it's a new edge
            self.nodes.entry(a)
                      .or_insert_with(|| Vec::with_capacity(1))
                      .push(b);
            if a != b {
                self.nodes.entry(b)
                          .or_insert_with(|| Vec::with_capacity(1))
                          .push(a);
            }
            None
        }
    }

    /// Remove successor relation from a to b
    ///
    /// Return `true` if it did exist.
    fn remove_single_edge(&mut self, a: &N, b: &N) -> bool {
        match self.nodes.get_mut(a) {
            None => false,
            Some(sus) => {
                match sus.iter().position(|elt| elt == b) {
                    Some(index) => { sus.swap_remove(index); true }
                    None => false,
                }
            }
        }
    }

    /// Remove edge from `a` to `b` from the graph and return the edge weight.
    ///
    /// Return `None` if the edge didn't exist.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    ///
    /// let edge_data = g.remove_edge(2, 1);
    /// assert_eq!(edge_data, Some(-1));
    /// assert_eq!(g.edge_count(), 0);
    /// ```
    pub fn remove_edge(&mut self, a: N, b: N) -> Option<E> {
        let exist1 = self.remove_single_edge(&a, &b);
        let exist2 = if a != b { self.remove_single_edge(&b, &a) } else { exist1 };
        let weight = self.edges.remove(&edge_key(a, b));
        debug_assert!(exist1 == exist2 && exist1 == weight.is_some());
        weight
    }

    /// Return `true` if the edge connecting `a` with `b` is contained in the graph.
    pub fn contains_edge(&self, a: N, b: N) -> bool {
        self.edges.contains_key(&edge_key(a, b))
    }

    /// Return an iterator over the nodes of the graph.
    ///
    /// Iterator element type is `N`.
    pub fn nodes(&self) -> Nodes<N> {
        Nodes{iter: self.nodes.keys().cloned()}
    }

    /// Return an iterator over the nodes that are connected with `from` by edges.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `N`.
    pub fn neighbors(&self, from: N) -> Neighbors<N> {
        Neighbors{iter:
            match self.nodes.get(&from) {
                Some(neigh) => neigh.iter(),
                None => [].iter(),
            }.cloned()
        }
    }

    /// Return an iterator over the nodes that are connected with `from` by edges,
    /// paired with the edge weight.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `(N, &E)`.
    pub fn edges(&self, from: N) -> Edges<N, E> {
        Edges {
            from: from,
            iter: self.neighbors(from),
            edges: &self.edges,
        }
    }

    /// Return a reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight(&self, a: N, b: N) -> Option<&E> {
        self.edges.get(&edge_key(a, b))
    }

    /// Return a mutable reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight_mut(&mut self, a: N, b: N) -> Option<&mut E> {
        self.edges.get_mut(&edge_key(a, b))
    }

    /// Return an iterator over all edges of the graph with their weight in arbitrary order.
    ///
    /// Iterator element type is `(N, N, &E)`
    pub fn all_edges(&self) -> AllEdges<N, E> {
        AllEdges {
            inner: self.edges.iter()
        }
    }
}

/// Create a new `GraphMap` from an iterable of edges.
impl<N, E, Item> FromIterator<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn from_iter<I>(iterable: I) -> Self
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        let mut g = Self::with_capacity(0, low);
        g.extend(iter);
        g
    }
}

/// Extend the graph from an iterable of edges.
///
/// Nodes are inserted automatically to match the edges.
impl<N, E, Item> Extend<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn extend<I>(&mut self, iterable: I)
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        self.edges.reserve(low);

        for elt in iter {
            let (source, target, weight) = elt.into_weighted_edge();
            self.add_edge(source, target, weight);
        }
    }
}

/// Utitily macro -- reinterpret passed in macro arguments as items
macro_rules! items {
    ($($item:item)*) => ($($item)*);
}

macro_rules! iterator_wrap {
    ($name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
     item: $item: ty,
     iter: $iter: ty,
     ) => (
        items! {
            pub struct $name <$($typarm),*> where $($bounds)* {
                iter: $iter,
            }
            impl<$($typarm),*> Iterator for $name <$($typarm),*>
                where $($bounds)*
            {
                type Item = $item;
                #[inline]
                fn next(&mut self) -> Option<Self::Item> {
                    self.iter.next()
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.iter.size_hint()
                }
            }
            impl<$($typarm),*> DoubleEndedIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: DoubleEndedIterator<Item=$item>,
            {
                #[inline]
                fn next_back(&mut self) -> Option<Self::Item> {
                    self.iter.next_back()
                }
            }

            impl<$($typarm),*> ExactSizeIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: ExactSizeIterator<Item=$item>,
            {
            }
        }
    );
}

iterator_wrap! {
    Nodes <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Keys<'a, N, Vec<N>>>,
}

iterator_wrap! {
    Neighbors <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Iter<'a, N>>,
}

pub struct Edges<'a, N, E: 'a> where N: 'a + NodeTrait {
    /// **Deprecated: should be private**
    pub from: N,
    /// **Deprecated: should be private**
    pub edges: &'a HashMap<(N, N), E>,
    /// **Deprecated: should be private**
    pub iter: Neighbors<'a, N>,
}

impl<'a, N, E> Iterator for Edges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, &'a E);
    fn next(&mut self) -> Option<(N, &'a E)>
    {
        match self.iter.next() {
            None => None,
            Some(b) => {
                let a = self.from;
                match self.edges.get(&edge_key(a, b)) {
                    None => unreachable!(),
                    Some(edge) => {
                        Some((b, edge))
                    }
                }
            }
        }
    }
}

pub struct AllEdges<'a, N, E: 'a> where N: 'a + NodeTrait {
    inner: HashmapIter<'a, (N, N), E>
}

impl<'a, N, E> Iterator for AllEdges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, N, &'a E);
    fn next(&mut self) -> Option<Self::Item>
    {
        match self.inner.next() {
            None => None,
            Some((&(a, b), v)) => Some((a, b, v))
        }
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> Index<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    type Output = E;
    fn index(&self, index: (N, N)) -> &E
    {
        self.edge_weight(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> IndexMut<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    fn index_mut(&mut self, index: (N, N)) -> &mut E
    {
        self.edge_weight_mut(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}
<commit_msg>Mark the fields of graphmap::Edges private<commit_after>//! `GraphMap<N, E>` is an undirected graph where node values are mapping keys.

use std::hash::{Hash};
use std::collections::HashMap;
use std::iter::Cloned;
use std::collections::hash_map::{
    Keys,
};
use std::collections::hash_map::Iter as HashmapIter;
use std::slice::{
    Iter,
};
use std::fmt;
use std::iter::FromIterator;
use std::ops::{Index, IndexMut};

use IntoWeightedEdge;

/// `GraphMap<N, E>` is an undirected graph, with generic node values `N` and edge weights `E`.
///
/// It uses an combined adjacency list and sparse adjacency matrix representation, using **O(|V|
/// + |E|)** space, and allows testing for edge existance in constant time.
///
/// The node type `N` must implement `Copy` and will be used as node identifier, duplicated
/// into several places in the data structure.
/// It must be suitable as a hash table key (implementing `Eq + Hash`).
/// The node type must also implement `Ord` so that the implementation can
/// order the pair (`a`, `b`) for an edge connecting any two nodes `a` and `b`.
///
/// `GraphMap` does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct GraphMap<N, E> {
    nodes: HashMap<N, Vec<N>>,
    edges: HashMap<(N, N), E>,
}

impl<N: Eq + Hash + fmt::Debug, E: fmt::Debug> fmt::Debug for GraphMap<N, E> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.nodes.fmt(f)
    }
}

/// Use their natual order to map the node pair (a, b) to a canonical edge id.
#[inline]
fn edge_key<N: Copy + Ord>(a: N, b: N) -> (N, N) {
    if a <= b { (a, b) } else { (b, a) }
}

/// A trait group for `GraphMap`'s node identifier.
pub trait NodeTrait : Copy + Ord + Hash {}
impl<N> NodeTrait for N where N: Copy + Ord + Hash {}

impl<N, E> GraphMap<N, E>
    where N: NodeTrait
{
    /// Create a new `GraphMap`.
    pub fn new() -> Self {
        GraphMap {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    /// Create a new `GraphMap` with estimated capacity.
    pub fn with_capacity(nodes: usize, edges: usize) -> Self {
        GraphMap {
            nodes: HashMap::with_capacity(nodes),
            edges: HashMap::with_capacity(edges),
        }
    }

    /// Return the current node and edge capacity of the graph.
    pub fn capacity(&self) -> (usize, usize) {
        (self.nodes.capacity(), self.edges.capacity())
    }

    /// Create a new `GraphMap` from an iterable of edges.
    ///
    /// Node values are taken directly from the list.
    /// Edge weights `E` may either be specified in the list,
    /// or they are filled with default values.
    ///
    /// Nodes are inserted automatically to match the edges.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let gr = GraphMap::<_, ()>::from_edges(&[
    ///     (0, 1), (0, 2), (0, 3),
    ///     (1, 2), (1, 3),
    ///     (2, 3),
    /// ]);
    /// ```
    pub fn from_edges<I>(iterable: I) -> Self
        where I: IntoIterator,
              I::Item: IntoWeightedEdge<N, E>
    {
        Self::from_iter(iterable)
    }

    /// Return the number of nodes in the graph.
    pub fn node_count(&self) -> usize {
        self.nodes.len()
    }

    /// Return the number of edges in the graph.
    pub fn edge_count(&self) -> usize {
        self.edges.len()
    }

    /// Remove all nodes and edges
    pub fn clear(&mut self) {
        self.nodes.clear();
        self.edges.clear();
    }

    /// Add node `n` to the graph.
    pub fn add_node(&mut self, n: N) -> N {
        self.nodes.entry(n).or_insert_with(|| Vec::new());
        n
    }

    /// Return `true` if node `n` was removed.
    pub fn remove_node(&mut self, n: N) -> bool {
        let successors = match self.nodes.remove(&n) {
            None => return false,
            Some(sus) => sus,
        };
        for succ in successors.into_iter() {
            // remove all successor links
            self.remove_single_edge(&succ, &n);
            // Remove all edge values
            self.edges.remove(&edge_key(n, succ));
        }
        true
    }

    /// Return `true` if the node is contained in the graph.
    pub fn contains_node(&self, n: N) -> bool {
        self.nodes.contains_key(&n)
    }

    /// Add an edge connecting `a` and `b` to the graph, with associated
    /// data `weight`.
    ///
    /// Inserts nodes `a` and/or `b` if they aren't already part of the graph.
    ///
    /// Return `None` if the edge did not previously exist, otherwise,
    /// the associated data is updated and the old value is returned
    /// as `Some(old_weight)`.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    /// assert_eq!(g.node_count(), 2);
    /// assert_eq!(g.edge_count(), 1);
    /// ```
    pub fn add_edge(&mut self, a: N, b: N, weight: E) -> Option<E> {
        if let old @ Some(_) = self.edges.insert(edge_key(a, b), weight) {
            old
        } else {
            // insert in the adjacency list if it's a new edge
            self.nodes.entry(a)
                      .or_insert_with(|| Vec::with_capacity(1))
                      .push(b);
            if a != b {
                self.nodes.entry(b)
                          .or_insert_with(|| Vec::with_capacity(1))
                          .push(a);
            }
            None
        }
    }

    /// Remove successor relation from a to b
    ///
    /// Return `true` if it did exist.
    fn remove_single_edge(&mut self, a: &N, b: &N) -> bool {
        match self.nodes.get_mut(a) {
            None => false,
            Some(sus) => {
                match sus.iter().position(|elt| elt == b) {
                    Some(index) => { sus.swap_remove(index); true }
                    None => false,
                }
            }
        }
    }

    /// Remove edge from `a` to `b` from the graph and return the edge weight.
    ///
    /// Return `None` if the edge didn't exist.
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    ///
    /// let edge_data = g.remove_edge(2, 1);
    /// assert_eq!(edge_data, Some(-1));
    /// assert_eq!(g.edge_count(), 0);
    /// ```
    pub fn remove_edge(&mut self, a: N, b: N) -> Option<E> {
        let exist1 = self.remove_single_edge(&a, &b);
        let exist2 = if a != b { self.remove_single_edge(&b, &a) } else { exist1 };
        let weight = self.edges.remove(&edge_key(a, b));
        debug_assert!(exist1 == exist2 && exist1 == weight.is_some());
        weight
    }

    /// Return `true` if the edge connecting `a` with `b` is contained in the graph.
    pub fn contains_edge(&self, a: N, b: N) -> bool {
        self.edges.contains_key(&edge_key(a, b))
    }

    /// Return an iterator over the nodes of the graph.
    ///
    /// Iterator element type is `N`.
    pub fn nodes(&self) -> Nodes<N> {
        Nodes{iter: self.nodes.keys().cloned()}
    }

    /// Return an iterator over the nodes that are connected with `from` by edges.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `N`.
    pub fn neighbors(&self, from: N) -> Neighbors<N> {
        Neighbors{iter:
            match self.nodes.get(&from) {
                Some(neigh) => neigh.iter(),
                None => [].iter(),
            }.cloned()
        }
    }

    /// Return an iterator over the nodes that are connected with `from` by edges,
    /// paired with the edge weight.
    ///
    /// If the node `from` does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is `(N, &E)`.
    pub fn edges(&self, from: N) -> Edges<N, E> {
        Edges {
            from: from,
            iter: self.neighbors(from),
            edges: &self.edges,
        }
    }

    /// Return a reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight(&self, a: N, b: N) -> Option<&E> {
        self.edges.get(&edge_key(a, b))
    }

    /// Return a mutable reference to the edge weight connecting `a` with `b`, or
    /// `None` if the edge does not exist in the graph.
    pub fn edge_weight_mut(&mut self, a: N, b: N) -> Option<&mut E> {
        self.edges.get_mut(&edge_key(a, b))
    }

    /// Return an iterator over all edges of the graph with their weight in arbitrary order.
    ///
    /// Iterator element type is `(N, N, &E)`
    pub fn all_edges(&self) -> AllEdges<N, E> {
        AllEdges {
            inner: self.edges.iter()
        }
    }
}

/// Create a new `GraphMap` from an iterable of edges.
impl<N, E, Item> FromIterator<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn from_iter<I>(iterable: I) -> Self
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        let mut g = Self::with_capacity(0, low);
        g.extend(iter);
        g
    }
}

/// Extend the graph from an iterable of edges.
///
/// Nodes are inserted automatically to match the edges.
impl<N, E, Item> Extend<Item> for GraphMap<N, E>
    where Item: IntoWeightedEdge<N, E>,
          N: NodeTrait,
{
    fn extend<I>(&mut self, iterable: I)
        where I: IntoIterator<Item=Item>,
    {
        let iter = iterable.into_iter();
        let (low, _) = iter.size_hint();
        self.edges.reserve(low);

        for elt in iter {
            let (source, target, weight) = elt.into_weighted_edge();
            self.add_edge(source, target, weight);
        }
    }
}

/// Utitily macro -- reinterpret passed in macro arguments as items
macro_rules! items {
    ($($item:item)*) => ($($item)*);
}

macro_rules! iterator_wrap {
    ($name: ident <$($typarm:tt),*> where { $($bounds: tt)* }
     item: $item: ty,
     iter: $iter: ty,
     ) => (
        items! {
            pub struct $name <$($typarm),*> where $($bounds)* {
                iter: $iter,
            }
            impl<$($typarm),*> Iterator for $name <$($typarm),*>
                where $($bounds)*
            {
                type Item = $item;
                #[inline]
                fn next(&mut self) -> Option<Self::Item> {
                    self.iter.next()
                }

                #[inline]
                fn size_hint(&self) -> (usize, Option<usize>) {
                    self.iter.size_hint()
                }
            }
            impl<$($typarm),*> DoubleEndedIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: DoubleEndedIterator<Item=$item>,
            {
                #[inline]
                fn next_back(&mut self) -> Option<Self::Item> {
                    self.iter.next_back()
                }
            }

            impl<$($typarm),*> ExactSizeIterator for $name <$($typarm),*>
                where $($bounds)*, $iter: ExactSizeIterator<Item=$item>,
            {
            }
        }
    );
}

iterator_wrap! {
    Nodes <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Keys<'a, N, Vec<N>>>,
}

iterator_wrap! {
    Neighbors <'a, N> where { N: 'a + Clone }
    item: N,
    iter: Cloned<Iter<'a, N>>,
}

pub struct Edges<'a, N, E: 'a> where N: 'a + NodeTrait {
    from: N,
    edges: &'a HashMap<(N, N), E>,
    iter: Neighbors<'a, N>,
}

impl<'a, N, E> Iterator for Edges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, &'a E);
    fn next(&mut self) -> Option<(N, &'a E)>
    {
        match self.iter.next() {
            None => None,
            Some(b) => {
                let a = self.from;
                match self.edges.get(&edge_key(a, b)) {
                    None => unreachable!(),
                    Some(edge) => {
                        Some((b, edge))
                    }
                }
            }
        }
    }
}

pub struct AllEdges<'a, N, E: 'a> where N: 'a + NodeTrait {
    inner: HashmapIter<'a, (N, N), E>
}

impl<'a, N, E> Iterator for AllEdges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, N, &'a E);
    fn next(&mut self) -> Option<Self::Item>
    {
        match self.inner.next() {
            None => None,
            Some((&(a, b), v)) => Some((a, b, v))
        }
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> Index<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    type Output = E;
    fn index(&self, index: (N, N)) -> &E
    {
        self.edge_weight(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}

/// Index `GraphMap` by node pairs to access edge weights.
impl<N, E> IndexMut<(N, N)> for GraphMap<N, E>
    where N: NodeTrait
{
    fn index_mut(&mut self, index: (N, N)) -> &mut E
    {
        self.edge_weight_mut(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}
<|endoftext|>


<commit_before>use std::io::{stdin, stdout, Write};
use hlt::parse::Decodable;
use hlt::entity::GameState;
use hlt::command::Command;
use hlt::game_map::GameMap;

#[derive(Debug)]
pub struct Game {
    pub my_id: usize,
    pub map_width: i32,
    pub map_height: i32,
}

impl Game {
    fn read_line() -> String {
        let mut buffer = String::new();
        stdin().read_line(&mut buffer).expect("Read error");
        buffer
    }

    fn read_id() -> usize {
        let line = Game::read_line();
        let parts = line.split_whitespace();
        let mut iter = parts.into_iter();
        usize::parse(&mut iter)
    }

    fn read_size() -> (i32, i32) {
        let line = Game::read_line();
        let parts = line.split_whitespace();
        let mut iter = parts.into_iter();
        let width = i32::parse(&mut iter);
        let height = i32::parse(&mut iter);
        (width, height)
    }

    pub fn new(name: &str) -> Game {
        let my_id = Game::read_id();
        let (map_width, map_height) = Game::read_size();

        println!("{}", name);

        let game = Game {
            my_id,
            map_width,
            map_height,
        };
        game.update_map();
        game
    }

    pub fn update_map(&self) -> GameMap {
        let line = Game::read_line();
        let parts = line.split_whitespace();
        let mut iter = parts.into_iter();
        let game_state = GameState::parse(&mut iter);
        GameMap::new(self, game_state)
    }

    pub fn send_command_queue(&self, commands: Vec<Command>) {
        for command in commands {
            let encoded = command.encode();
            stdout().write(encoded.as_bytes()).unwrap();
        }
        println!()
    }
}
<commit_msg>clean: Clarify the method call to ignore the first line<commit_after>use std::io::{stdin, stdout, Write};
use hlt::parse::Decodable;
use hlt::entity::GameState;
use hlt::command::Command;
use hlt::game_map::GameMap;

#[derive(Debug)]
pub struct Game {
    pub my_id: usize,
    pub map_width: i32,
    pub map_height: i32,
}

impl Game {
    fn read_line() -> String {
        let mut buffer = String::new();
        stdin().read_line(&mut buffer).expect("Read error");
        buffer
    }

    fn read_id() -> usize {
        let line = Game::read_line();
        let parts = line.split_whitespace();
        let mut iter = parts.into_iter();
        usize::parse(&mut iter)
    }

    fn read_size() -> (i32, i32) {
        let line = Game::read_line();
        let parts = line.split_whitespace();
        let mut iter = parts.into_iter();
        let width = i32::parse(&mut iter);
        let height = i32::parse(&mut iter);
        (width, height)
    }

    pub fn new(name: &str) -> Game {
        let my_id = Game::read_id();
        let (map_width, map_height) = Game::read_size();

        println!("{}", name);

        // ignore first line
        Game::read_line();

        Game {
            my_id,
            map_width,
            map_height,
        }
    }

    pub fn update_map(&self) -> GameMap {
        let line = Game::read_line();
        let parts = line.split_whitespace();
        let mut iter = parts.into_iter();
        let game_state = GameState::parse(&mut iter);
        GameMap::new(self, game_state)
    }

    pub fn send_command_queue(&self, commands: Vec<Command>) {
        for command in commands {
            let encoded = command.encode();
            stdout().write(encoded.as_bytes()).unwrap();
        }
        println!()
    }
}
<|endoftext|>


<commit_before>extern crate rand;
use rand::{thread_rng, Rng};
use std::collections::HashMap;
use std::fmt;

#[derive(Copy, Clone)]
enum Cell {
    Card(usize),
    Empty,
}

#[derive(Eq, PartialEq, Hash)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

enum Action {
    Move(Direction),
    Quit,
}

struct P15 {
    board: Vec<Cell>,
}

impl P15 {
    // todo: make the board valid right from the start.
    fn new() -> P15 {
        let mut board = (1..16).map(Cell::Card).collect::<Vec<_>>();
        board.push(Cell::Empty);

        let mut rng = thread_rng();

        rng.shuffle(board.as_mut_slice());
        while !P15::is_valid(board.clone()) {
            rng.shuffle(board.as_mut_slice());
        }

        P15 { board: board }
    }

    fn is_valid(mut board: Vec<Cell>) -> bool {
        let mut permutations = 0;

        let pos = board.iter()
            .position(|&cell| match cell {
                Cell::Empty => true,
                _ => false,
            })
            .unwrap();

        if pos != 15 {
            board.swap(pos, 15);
            permutations += 1;
        }

        for i in 1..16 {
            let pos = board.iter()
                .position(|&cell| match cell {
                    Cell::Card(val) if val == i => true,
                    _ => false,
                })
                .unwrap();

            if pos + 1 != i {
                board.swap(pos, i - 1);
                permutations += 1;
            }
        }

        permutations % 2 == 0
    }

    fn get_empty_position(&self) -> usize {
        self.board
            .iter()
            .position(|&cell| match cell {
                Cell::Empty => true,
                _ => false,
            })
            .unwrap()
    }

    fn get_moves(&self) -> HashMap<Direction, Cell> {
        let mut moves = HashMap::with_capacity(4);
        let i = self.get_empty_position();

        if i > 3 {
            moves.insert(Direction::Up, self.board[i - 4]);
        }
        if i % 4 != 0 {
            moves.insert(Direction::Left, self.board[i - 1]);
        }
        if i < 12 {
            moves.insert(Direction::Down, self.board[i + 4]);
        }
        if i % 4 != 3 {
            moves.insert(Direction::Right, self.board[i + 1]);
        }
        moves
    }

    fn play(&mut self, direction: Direction) {
        use Direction::*;
        let i = self.get_empty_position();
        match direction {
            Up => self.board.swap(i, i - 4),
            Left => self.board.swap(i, i - 1),
            Right => self.board.swap(i, i + 1),
            Down => self.board.swap(i, i + 4),
        };
    }

    fn is_complete(&self) -> bool {
        for (i, cell) in self.board.iter().enumerate() {
            match cell {
                &Cell::Card(value) if value == i + 1 => (),
                &Cell::Empty if i == 15 => (),
                _ => return false,
            };
        }
        true
    }
}

impl fmt::Display for P15 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Cell::*;
        try!(write!(f, "+----+----+----+----+\n"));
        for (i, cell) in self.board.iter().enumerate() {
            match cell {
                &Card(value) => {
                    try!(write!(f, "| {:2} ", value));
                }
                &Empty => {
                    try!(write!(f, "|    "));
                }
            };

            if i % 4 == 3 {
                try!(write!(f, "|\n"));
                try!(write!(f, "+----+----+----+----+\n"));
            }
        }
        Ok(())
    }
}

fn main() {
    let mut p15 = P15::new();
    let mut turns = 0;
    loop {
        println!("{}", p15);
        match ask_action(&p15.get_moves()) {
            Action::Move(direction) => {
                p15.play(direction);
            }
            Action::Quit => {
                println!("Bye !");
                break;
            }
        }

        turns += 1;

        if p15.is_complete() {
            println!("Well done ! You win in {} turns", turns);
            break;
        }

    }
}

fn ask_action(moves: &HashMap<Direction, Cell>) -> Action {
    use std::io::{self, Write};
    use Action::*;
    use Direction::*;
    println!("Possible moves :");

    match moves.get(&Up) {
        Some(&Cell::Card(value)) => {
            println!("\tU) {}", value);
        }
        _ => (),
    }
    match moves.get(&Left) {
        Some(&Cell::Card(value)) => {
            println!("\tL) {}", value);
        }
        _ => (),
    }
    match moves.get(&Right) {
        Some(&Cell::Card(value)) => {
            println!("\tR) {}", value);
        }
        _ => (),
    }
    match moves.get(&Down) {
        Some(&Cell::Card(value)) => {
            println!("\tD) {}", value);
        }
        _ => (),
    }
    println!("\tQ) Quit");
    print!("Choose your move : ");
    io::stdout().flush().unwrap();

    let mut action = String::new();
    io::stdin().read_line(&mut action).ok().expect("read error");
    match action.to_uppercase().trim() {
        "U" if moves.contains_key(&Up) => Move(Up),
        "L" if moves.contains_key(&Left) => Move(Left),
        "R" if moves.contains_key(&Right) => Move(Right),
        "D" if moves.contains_key(&Down) => Move(Down),
        "Q" => Quit,
        _ => {
            println!("Unknown action : {}", action);
            ask_action(moves)
        }
    }
}

<commit_msg>update 15 puzzle game<commit_after>extern crate rand;

use std::collections::HashMap;
use std::fmt;

use rand::Rng;

#[derive(Copy, Clone, PartialEq, Debug)]
enum Cell {
    Card(usize),
    Empty,
}

#[derive(Eq, PartialEq, Hash, Debug)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

enum Action {
    Move(Direction),
    Quit,
}

type Board = [Cell; 16];
const EMPTY: Board = [Cell::Empty; 16];

struct P15 {
    board: Board,
}

impl P15 {
    fn new() -> Self {
        let mut board = EMPTY;
        for (i, cell) in board.iter_mut().enumerate().skip(1) {
            *cell = Cell::Card(i);
        }

        let mut rng = rand::thread_rng();

        rng.shuffle(&mut board);
        if !Self::is_valid(board) {
            // random swap
            let i = rng.gen_range(0, 16);
            let mut j = rng.gen_range(0, 16);
            while j == i {
                j = rng.gen_range(0, 16);
            }
            board.swap(i, j);
        }

        Self { board }
    }

    fn is_valid(mut board: Board) -> bool {
        // TODO: optimize
        let mut permutations = 0;

        let pos = board.iter().position(|&cell| cell == Cell::Empty).unwrap();

        if pos != 15 {
            board.swap(pos, 15);
            permutations += 1;
        }

        for i in 1..16 {
            let pos = board
                .iter()
                .position(|&cell| match cell {
                    Cell::Card(value) if value == i => true,
                    _ => false,
                })
                .unwrap();

            if pos + 1 != i {
                board.swap(pos, i - 1);
                permutations += 1;
            }
        }

        permutations % 2 == 0
    }

    fn get_empty_position(&self) -> usize {
        self.board.iter().position(|&c| c == Cell::Empty).unwrap()
    }

    fn get_moves(&self) -> HashMap<Direction, Cell> {
        let mut moves = HashMap::new();
        let i = self.get_empty_position();

        if i > 3 {
            moves.insert(Direction::Up, self.board[i - 4]);
        }
        if i % 4 != 0 {
            moves.insert(Direction::Left, self.board[i - 1]);
        }
        if i < 12 {
            moves.insert(Direction::Down, self.board[i + 4]);
        }
        if i % 4 != 3 {
            moves.insert(Direction::Right, self.board[i + 1]);
        }
        moves
    }

    fn play(&mut self, direction: &Direction) {
        let i = self.get_empty_position();
        // This is safe because `ask_action` only returns legal moves
        match *direction {
            Direction::Up => self.board.swap(i, i - 4),
            Direction::Left => self.board.swap(i, i - 1),
            Direction::Right => self.board.swap(i, i + 1),
            Direction::Down => self.board.swap(i, i + 4),
        };
    }

    fn is_complete(&self) -> bool {
        self.board.iter().enumerate().all(|(i, &cell)| match cell {
            Cell::Card(value) => value == i + 1,
            Cell::Empty => i == 15,
        })
    }
}

impl fmt::Display for P15 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "+----+----+----+----+\n"));
        for (i, &cell) in self.board.iter().enumerate() {
            match cell {
                Cell::Card(value) => try!(write!(f, "| {:2} ", value)),
                Cell::Empty => try!(write!(f, "|    ")),
            }

            if i % 4 == 3 {
                try!(write!(f, "|\n"));
                try!(write!(f, "+----+----+----+----+\n"));
            }
        }
        Ok(())
    }
}

fn main() {
    let mut p15 = P15::new();

    for turns in 1.. {
        println!("{}", p15);
        match ask_action(&p15.get_moves()) {
            Action::Move(direction) => {
                p15.play(&direction);
            }
            Action::Quit => {
                println!("Bye !");
                break;
            }
        }

        if p15.is_complete() {
            println!("Well done ! You won in {} turns", turns);
            break;
        }
    }
}

fn ask_action(moves: &HashMap<Direction, Cell>) -> Action {
    use std::io::{self, Write};
    use Action::*;
    use Direction::*;

    println!("Possible moves:");

    if let Some(&Cell::Card(value)) = moves.get(&Up) {
        println!("\tU) {}", value);
    }
    if let Some(&Cell::Card(value)) = moves.get(&Left) {
        println!("\tL) {}", value);
    }
    if let Some(&Cell::Card(value)) = moves.get(&Right) {
        println!("\tR) {}", value);
    }
    if let Some(&Cell::Card(value)) = moves.get(&Down) {
        println!("\tD) {}", value);
    }
    println!("\tQ) Quit");
    print!("Choose your move : ");
    io::stdout().flush().unwrap();

    let mut action = String::new();
    io::stdin().read_line(&mut action).expect("read error");
    match action.to_uppercase().trim() {
        "U" if moves.contains_key(&Up) => Move(Up),
        "L" if moves.contains_key(&Left) => Move(Left),
        "R" if moves.contains_key(&Right) => Move(Right),
        "D" if moves.contains_key(&Down) => Move(Down),
        "Q" => Quit,
        _ => {
            println!("Unknown action: {}", action);
            ask_action(moves)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn board_from_ints(ints: &[usize; 16]) -> Board {
        let mut board = EMPTY;
        for (cell, &int) in board.iter_mut().zip(ints.iter()) {
            *cell = if int == 0 {
                Cell::Empty
            } else {
                Cell::Card(int)
            }
        }
        board
    }

    fn make_valid<R: Rng>(rng: &mut R, mut board: Board) -> Board {
        let i = rng.gen_range(0, 16);
        let mut j = rng.gen_range(0, 16);
        while j == i {
            j = rng.gen_range(0, 16);
        }
        board.swap(i, j);
        board
    }

    #[test]
    fn board_creation() {
        let p15 = P15::new();
        assert!(P15::is_valid(p15.board));
    }

    #[test]
    fn board_validity() {
        let mut rng = rand::weak_rng();

        fn assert_is_valid<R: Rng>(rng: &mut R, ints: &[usize; 16]) {
            let board = board_from_ints(ints);
            assert!(P15::is_valid(board));
        }

        fn assert_is_not_valid<R: Rng>(rng: &mut R, ints: &[usize; 16]) {
            let board = board_from_ints(ints);
            assert!(!P15::is_valid(board));
            assert!(P15::is_valid(make_valid(rng, board)));
        }

        assert_is_not_valid(&mut rng, &[2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]);
        assert_is_not_valid(&mut rng, &[13, 10, 11, 6, 5, 7, 4, 8, 1, 12, 14, 9, 3, 15, 2, 0]);
        assert_is_not_valid(&mut rng, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 14, 0]);
        assert_is_not_valid(&mut rng, &[2, 1, 3, 4, 5, 8, 7, 6, 9, 10, 12, 11, 15, 13, 14, 0]);
        assert_is_not_valid(&mut rng, &[4, 15, 7, 9, 3, 12, 1, 8, 5, 0, 11, 2, 13, 6, 10, 14]);

        assert_is_valid(&mut rng, &[7, 1, 3, 14, 6, 0, 4, 8, 5, 9, 13, 2, 12, 15, 11, 10]);
        assert_is_valid(&mut rng, &[7, 9, 1, 14, 6, 0, 13, 10, 8, 3, 12, 4, 15, 5, 2, 11]);
        assert_is_valid(&mut rng, &[15, 8, 9, 14, 5, 10, 1, 0, 12, 4, 3, 13, 11, 2, 7, 6]);
        assert_is_valid(&mut rng, &[1, 12, 4, 8, 10, 7, 2, 11, 6, 3, 15, 14, 9, 13, 5, 0]);
    }

    #[test]
    fn directions() {
        fn get_puzzle_moves(ints: &[usize; 16]) -> HashMap<Direction, Cell> {
            let board = board_from_ints(&ints);
            let puzzle = P15 { board };
            puzzle.get_moves()
        }

        let mut test = HashMap::new();
        test.insert(Direction::Up, Cell::Card(12));
        test.insert(Direction::Left, Cell::Card(15));
        let moves = get_puzzle_moves(&[13, 6, 8, 3, 1, 5, 2, 4, 9, 7, 10, 12, 14, 11, 15, 0]);
        assert_eq!(moves, test);

        let mut test = HashMap::new();
        test.insert(Direction::Up, Cell::Card(12));
        test.insert(Direction::Left, Cell::Card(14));
        test.insert(Direction::Right, Cell::Card(8));
        test.insert(Direction::Down, Cell::Card(15));
        let moves = get_puzzle_moves(&[7, 12, 2, 1, 14, 0, 8, 13, 3, 15, 4, 6, 11, 5, 10, 9]);
        assert_eq!(moves, test);
    }

    #[test]
    fn victory() {
        let input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0];
        let board = board_from_ints(&input);
        let puzzle = P15 { board };
        assert!(puzzle.is_complete());
    }
}
<|endoftext|>


<commit_before>//! The module implements the client side of the HTTP/2 protocol and exposes
//! an API for using it.
use std::io;

pub mod frame;
pub mod transport;
pub mod connection;
pub mod session;

/// An alias for the type that represents the ID of an HTTP/2 stream
pub type StreamId = u32;
/// An alias for the type that represents HTTP/2 haders. For now we only alias
/// the tuple of byte vectors instead of going with a full struct representation.
pub type Header = (Vec<u8>, Vec<u8>);

/// An enum representing errors that can arise when performing operations
/// involving an HTTP/2 connection.
#[derive(PartialEq)]
#[derive(Clone)]
#[derive(Debug)]
pub enum HttpError {
    IoError(io::Error),
    UnknownFrameType,
    InvalidFrame,
    UnableToConnect,
    MalformedResponse,
}

/// A convenience `Result` type that has the `HttpError` type as the error
/// type and a generic Ok result type.
pub type HttpResult<T> = Result<T, HttpError>;

/// A struct representing the full raw response received on an HTTP/2 connection.
///
/// The full body of the response is included, regardless how large it may be.
/// The headers contain both the meta-headers, as well as the actual headers.
#[derive(Clone)]
pub struct Response {
    /// The ID of the stream to which the response is associated. HTTP/1.1 does
    /// not really have an equivalent to this.
    pub stream_id: StreamId,
    /// Exposes *all* the raw response headers, including the meta-headers.
    /// (For now the only meta header allowed in HTTP/2 responses is the
    /// `:status`.)
    pub headers: Vec<Header>,
    /// The full body of the response as an uninterpreted sequence of bytes.
    pub body: Vec<u8>,
}

impl Response {
    /// Creates a new `Response` with all the components already provided.
    pub fn new(stream_id: StreamId, headers: Vec<Header>, body: Vec<u8>)
            -> Response {
        Response {
            stream_id: stream_id,
            headers: headers,
            body: body,
        }
    }

    /// Gets the response status code from the pseudo-header. If the response
    /// does not contain the response as the first pseuo-header, an error is
    /// returned as such a response is malformed.
    pub fn status_code(&self) -> HttpResult<u16> {
        // Since pseudo-headers MUST be found before any regular header fields
        // and the *only* pseudo-header defined for responses is the `:status`
        // field, the `:status` MUST be the first header; otherwise, the
        // response is malformed.
        if self.headers.len() < 1 {
            return Err(HttpError::MalformedResponse)
        }
        if &self.headers[0].0 != &b":status" {
            Err(HttpError::MalformedResponse)
        } else {
            Ok(try!(Response::parse_status_code(&self.headers[0].1)))
        }
    }

    /// A helper function that parses a given buffer as a status code and
    /// returns it as a `u16`, if it is valid.
    fn parse_status_code(buf: &[u8]) -> HttpResult<u16> {
        // "The status-code element is a three-digit integer code [...]"
        if buf.len() != 3 {
            return Err(HttpError::MalformedResponse);
        }

        // "There are five values for the first digit"
        if buf[0] < b'1' || buf[0] > b'5' {
            return Err(HttpError::MalformedResponse);
        }

        // The rest of them just have to be digits
        if buf[1] < b'0' || buf[1] > b'9' || buf[2] < b'0' || buf[2] > b'9' {
            return Err(HttpError::MalformedResponse);
        }

        // Finally, we can merge them into an integer
        Ok(100 * ((buf[0] - b'0') as u16) +
           10 * ((buf[1] - b'0') as u16) +
           1 * ((buf[2] - b'0') as u16))
    }
}

/// A struct representing a full HTTP/2 request, along with the full body, as a
/// sequence of bytes.
#[derive(Clone)]
pub struct Request {
    pub stream_id: u32,
    pub headers: Vec<Header>,
    pub body: Vec<u8>,
}

#[cfg(test)]
mod tests {
    use super::{Response, HttpError};

    /// Tests that the `Response` struct correctly parses a status code from
    /// its headers list.
    #[test]
    fn test_parse_status_code_response() {
        {
            // Only status => Ok
            let resp = Response::new(
                1,
                vec![(b":status".to_vec(), b"200".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().ok().unwrap(), 200);
        }
        {
            // Extra headers => still works
            let resp = Response::new(
                1,
                vec![(b":status".to_vec(), b"200".to_vec()),
                     (b"key".to_vec(), b"val".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().ok().unwrap(), 200);
        }
        {
            // Status is not the first header => malformed
            let resp = Response::new(
                1,
                vec![(b"key".to_vec(), b"val".to_vec()),
                     (b":status".to_vec(), b"200".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().err().unwrap(),
                       HttpError::MalformedResponse);
        }
        {
            // No headers at all => Malformed
            let resp = Response::new(1, vec![], vec![]);
            assert_eq!(resp.status_code().err().unwrap(),
                       HttpError::MalformedResponse);
        }
    }
}
<commit_msg>http: Add CompressionError variant for HttpError<commit_after>//! The module implements the client side of the HTTP/2 protocol and exposes
//! an API for using it.
use std::io;

use super::hpack::decoder::DecoderError;

pub mod frame;
pub mod transport;
pub mod connection;
pub mod session;

/// An alias for the type that represents the ID of an HTTP/2 stream
pub type StreamId = u32;
/// An alias for the type that represents HTTP/2 haders. For now we only alias
/// the tuple of byte vectors instead of going with a full struct representation.
pub type Header = (Vec<u8>, Vec<u8>);

/// An enum representing errors that can arise when performing operations
/// involving an HTTP/2 connection.
#[derive(PartialEq)]
#[derive(Clone)]
#[derive(Debug)]
pub enum HttpError {
    IoError(io::Error),
    UnknownFrameType,
    InvalidFrame,
    CompressionError(DecoderError),
    UnableToConnect,
    MalformedResponse,
}

/// A convenience `Result` type that has the `HttpError` type as the error
/// type and a generic Ok result type.
pub type HttpResult<T> = Result<T, HttpError>;

/// A struct representing the full raw response received on an HTTP/2 connection.
///
/// The full body of the response is included, regardless how large it may be.
/// The headers contain both the meta-headers, as well as the actual headers.
#[derive(Clone)]
pub struct Response {
    /// The ID of the stream to which the response is associated. HTTP/1.1 does
    /// not really have an equivalent to this.
    pub stream_id: StreamId,
    /// Exposes *all* the raw response headers, including the meta-headers.
    /// (For now the only meta header allowed in HTTP/2 responses is the
    /// `:status`.)
    pub headers: Vec<Header>,
    /// The full body of the response as an uninterpreted sequence of bytes.
    pub body: Vec<u8>,
}

impl Response {
    /// Creates a new `Response` with all the components already provided.
    pub fn new(stream_id: StreamId, headers: Vec<Header>, body: Vec<u8>)
            -> Response {
        Response {
            stream_id: stream_id,
            headers: headers,
            body: body,
        }
    }

    /// Gets the response status code from the pseudo-header. If the response
    /// does not contain the response as the first pseuo-header, an error is
    /// returned as such a response is malformed.
    pub fn status_code(&self) -> HttpResult<u16> {
        // Since pseudo-headers MUST be found before any regular header fields
        // and the *only* pseudo-header defined for responses is the `:status`
        // field, the `:status` MUST be the first header; otherwise, the
        // response is malformed.
        if self.headers.len() < 1 {
            return Err(HttpError::MalformedResponse)
        }
        if &self.headers[0].0 != &b":status" {
            Err(HttpError::MalformedResponse)
        } else {
            Ok(try!(Response::parse_status_code(&self.headers[0].1)))
        }
    }

    /// A helper function that parses a given buffer as a status code and
    /// returns it as a `u16`, if it is valid.
    fn parse_status_code(buf: &[u8]) -> HttpResult<u16> {
        // "The status-code element is a three-digit integer code [...]"
        if buf.len() != 3 {
            return Err(HttpError::MalformedResponse);
        }

        // "There are five values for the first digit"
        if buf[0] < b'1' || buf[0] > b'5' {
            return Err(HttpError::MalformedResponse);
        }

        // The rest of them just have to be digits
        if buf[1] < b'0' || buf[1] > b'9' || buf[2] < b'0' || buf[2] > b'9' {
            return Err(HttpError::MalformedResponse);
        }

        // Finally, we can merge them into an integer
        Ok(100 * ((buf[0] - b'0') as u16) +
           10 * ((buf[1] - b'0') as u16) +
           1 * ((buf[2] - b'0') as u16))
    }
}

/// A struct representing a full HTTP/2 request, along with the full body, as a
/// sequence of bytes.
#[derive(Clone)]
pub struct Request {
    pub stream_id: u32,
    pub headers: Vec<Header>,
    pub body: Vec<u8>,
}

#[cfg(test)]
mod tests {
    use super::{Response, HttpError};

    /// Tests that the `Response` struct correctly parses a status code from
    /// its headers list.
    #[test]
    fn test_parse_status_code_response() {
        {
            // Only status => Ok
            let resp = Response::new(
                1,
                vec![(b":status".to_vec(), b"200".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().ok().unwrap(), 200);
        }
        {
            // Extra headers => still works
            let resp = Response::new(
                1,
                vec![(b":status".to_vec(), b"200".to_vec()),
                     (b"key".to_vec(), b"val".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().ok().unwrap(), 200);
        }
        {
            // Status is not the first header => malformed
            let resp = Response::new(
                1,
                vec![(b"key".to_vec(), b"val".to_vec()),
                     (b":status".to_vec(), b"200".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().err().unwrap(),
                       HttpError::MalformedResponse);
        }
        {
            // No headers at all => Malformed
            let resp = Response::new(1, vec![], vec![]);
            assert_eq!(resp.status_code().err().unwrap(),
                       HttpError::MalformedResponse);
        }
    }
}
<|endoftext|>