<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v[mut read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8, ..4] = [0u8, ..4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8, ..8] = [0u8, ..8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL;
        static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8, ..0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(&mut v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>rollup merge of #19832: japaric/no-nocopy<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v[mut read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8, ..4] = [0u8, ..4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8, ..8] = [0u8, ..8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL;
        static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8, ..0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(&mut v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|endoftext|>


<commit_before>use matching::fragment;
use matching::fragment::Fragment;
use std::path::PathBuf;
use std::collections::hash_map::HashMap;

#[derive(PartialEq)]
pub struct Entry {
    pub path: PathBuf,
    pub index: HashMap<char, Vec<usize>>,
}

impl Entry {
    /// Compares the query string to the entry,
    /// and returns a score between 0 and 1.
    pub fn similarity(&self, query: &str) -> f32 {
        // Exact matches produce a perfect score.
        if query == self.path.to_string_lossy() {
            return 1.0;
        }

        // Pre-calculate the path length as we'll be using it frequently.
        let path_length = self.path.to_string_lossy().chars().count();

        // We track fragment/substring matches, which have a greater weight than
        // a simple sum of individual character occurrences in the entry path.
        let mut match_fragments: Vec<Fragment> = Vec::new();

        // This counter is used to track characters in the query that aren't in
        // the entry's path, which has discrete weighting in the final score.
        let mut non_existent_char_count = 0;

        // Look for the query's character in the path's index, bumping
        // the character score up for each occurrence in the path.
        for query_char in query.chars() {
            match self.index.get(&query_char) {
                Some(occurrences) => {
                    // Initially, we'll assume that none of the occurrences
                    // of this character have been tracked as fragments.
                    let mut unaccounted_occurrences = occurrences.clone();

                    // Extend any existing fragment matches that also
                    // have this char at the end of their existing match.
                    for fragment in match_fragments.iter_mut() {
                        // Get the index at which this character would have to
                        // occur to extend this particular fragment over it.
                        let target_index = fragment.next_index();

                        if occurrences.contains(&target_index) {
                            // Since this character match is covered by this
                            // fragment, remove it from the unaccounted set.
                            match unaccounted_occurrences.iter().position(|&o| o == target_index) {
                                Some(position) => {
                                    unaccounted_occurrences.remove(position);
                                },
                                None => (),
                            }

                            // Bump the fragment's length to cover this char.
                            fragment.increase_length();
                        }
                    }

                    // Create fragment matches for any unaccounted occurrences.
                    for occurrence_index in unaccounted_occurrences.iter() {
                        match_fragments.push(fragment::new(*occurrence_index));
                    }

                },
                None => {
                    // Characters in the query string that
                    // aren't in the path reduce the score;
                    // track these so we can consider them later.
                    non_existent_char_count += 1;
                },
            }
        }

        // Determine the percentage of characters in the query string that
        // are in the entry, using the non-existent count we've calculated.
        let non_existence_penalty =
            // Guard against a potential arithmetic overflow here.
            if non_existent_char_count >= path_length {
                return 0.0f32
            } else {
                (path_length - non_existent_char_count) as f32 / path_length as f32
            };

        // Calculate an exponentially-scaled score based on fragment lengths.
        let fragment_score = match_fragments.iter().fold(0, |acc, ref fragment| {
            acc + fragment.length.pow(2)
        });

        // Calculate and return the similarity value. The path_length division
        // is used to offset the increased fragment score probability for
        // larger entry paths.
        fragment_score as f32 * non_existence_penalty / path_length as f32
    }
}

fn index_path(path: &str) -> HashMap<char, Vec<usize>> {
    let mut index: HashMap<char, Vec<usize>> = HashMap::new();
    for (char_index, path_char) in path.chars().enumerate() {
        if index.contains_key(&path_char) {
            match index.get_mut(&path_char) {
               Some(occurrences) => occurrences.push(char_index),
               None => ()
            }
        } else {
           index.insert(path_char, vec![char_index]);
        }
    }

    index
}

pub fn new(path: String) -> Entry {
    Entry{
        // Build the index before we transfer ownership of path.
        index: index_path(&path),
        path: PathBuf::from(path),
    }
}

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

    #[test]
    fn similarity_correctly_scores_perfect_matches() {
        let entry = new("src/hound.rs".to_string());
        assert_eq!(entry.similarity("src/hound.rs"), 1.0);
    }

    #[test]
    fn similarity_correctly_scores_completely_different_terms() {
        let entry = new("src".to_string());
        assert_eq!(entry.similarity("lib"), 0.0);
    }

    #[test]
    fn similarity_scores_based_on_term_length() {
        let long_entry = new("hound library".to_string());
        let differing_length_score = long_entry.similarity("houn");

        // Don't use a perfect match, since those product a perfect score.
        let short_entry = new("hound".to_string());
        let same_length_score = short_entry.similarity("houn");

        assert!(same_length_score > differing_length_score);
    }

    #[test]
    fn similarity_score_increases_for_consecutive_matches() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let properly_ordered_score = entry.similarity(" houn");

        let improperly_ordered_score = entry.similarity("nuoh");
        assert!(properly_ordered_score > improperly_ordered_score);
    }

    #[test]
    fn similarity_score_decreases_for_non_matching_characters() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let non_matching_score = entry.similarity("houns");

        let subset_score = entry.similarity("houn");
        assert!(subset_score > non_matching_score);
    }

    #[test]
    fn similarity_score_is_zero_for_larger_query_with_no_matching_characters() {
        let entry = new("amp".to_string());
        assert_eq!(entry.similarity("hound"), 0.0f32);
    }
}
<commit_msg>We don't use character scores anymore; update comment.<commit_after>use matching::fragment;
use matching::fragment::Fragment;
use std::path::PathBuf;
use std::collections::hash_map::HashMap;

#[derive(PartialEq)]
pub struct Entry {
    pub path: PathBuf,
    pub index: HashMap<char, Vec<usize>>,
}

impl Entry {
    /// Compares the query string to the entry,
    /// and returns a score between 0 and 1.
    pub fn similarity(&self, query: &str) -> f32 {
        // Exact matches produce a perfect score.
        if query == self.path.to_string_lossy() {
            return 1.0;
        }

        // Pre-calculate the path length as we'll be using it frequently.
        let path_length = self.path.to_string_lossy().chars().count();

        // We track fragment/substring matches, which have a greater weight than
        // a simple sum of individual character occurrences in the entry path.
        let mut match_fragments: Vec<Fragment> = Vec::new();

        // This counter is used to track characters in the query that aren't in
        // the entry's path, which has discrete weighting in the final score.
        let mut non_existent_char_count = 0;

        // Look for the query's character in the path's index.
        for query_char in query.chars() {
            match self.index.get(&query_char) {
                Some(occurrences) => {
                    // Initially, we'll assume that none of the occurrences
                    // of this character have been tracked as fragments.
                    let mut unaccounted_occurrences = occurrences.clone();

                    // Extend any existing fragment matches that also
                    // have this char at the end of their existing match.
                    for fragment in match_fragments.iter_mut() {
                        // Get the index at which this character would have to
                        // occur to extend this particular fragment over it.
                        let target_index = fragment.next_index();

                        if occurrences.contains(&target_index) {
                            // Since this character match is covered by this
                            // fragment, remove it from the unaccounted set.
                            match unaccounted_occurrences.iter().position(|&o| o == target_index) {
                                Some(position) => {
                                    unaccounted_occurrences.remove(position);
                                },
                                None => (),
                            }

                            // Bump the fragment's length to cover this char.
                            fragment.increase_length();
                        }
                    }

                    // Create fragment matches for any unaccounted occurrences.
                    for occurrence_index in unaccounted_occurrences.iter() {
                        match_fragments.push(fragment::new(*occurrence_index));
                    }

                },
                None => {
                    // Characters in the query string that
                    // aren't in the path reduce the score;
                    // track these so we can consider them later.
                    non_existent_char_count += 1;
                },
            }
        }

        // Determine the percentage of characters in the query string that
        // are in the entry, using the non-existent count we've calculated.
        let non_existence_penalty =
            // Guard against a potential arithmetic overflow here.
            if non_existent_char_count >= path_length {
                return 0.0f32
            } else {
                (path_length - non_existent_char_count) as f32 / path_length as f32
            };

        // Calculate an exponentially-scaled score based on fragment lengths.
        let fragment_score = match_fragments.iter().fold(0, |acc, ref fragment| {
            acc + fragment.length.pow(2)
        });

        // Calculate and return the similarity value. The path_length division
        // is used to offset the increased fragment score probability for
        // larger entry paths.
        fragment_score as f32 * non_existence_penalty / path_length as f32
    }
}

fn index_path(path: &str) -> HashMap<char, Vec<usize>> {
    let mut index: HashMap<char, Vec<usize>> = HashMap::new();
    for (char_index, path_char) in path.chars().enumerate() {
        if index.contains_key(&path_char) {
            match index.get_mut(&path_char) {
               Some(occurrences) => occurrences.push(char_index),
               None => ()
            }
        } else {
           index.insert(path_char, vec![char_index]);
        }
    }

    index
}

pub fn new(path: String) -> Entry {
    Entry{
        // Build the index before we transfer ownership of path.
        index: index_path(&path),
        path: PathBuf::from(path),
    }
}

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

    #[test]
    fn similarity_correctly_scores_perfect_matches() {
        let entry = new("src/hound.rs".to_string());
        assert_eq!(entry.similarity("src/hound.rs"), 1.0);
    }

    #[test]
    fn similarity_correctly_scores_completely_different_terms() {
        let entry = new("src".to_string());
        assert_eq!(entry.similarity("lib"), 0.0);
    }

    #[test]
    fn similarity_scores_based_on_term_length() {
        let long_entry = new("hound library".to_string());
        let differing_length_score = long_entry.similarity("houn");

        // Don't use a perfect match, since those product a perfect score.
        let short_entry = new("hound".to_string());
        let same_length_score = short_entry.similarity("houn");

        assert!(same_length_score > differing_length_score);
    }

    #[test]
    fn similarity_score_increases_for_consecutive_matches() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let properly_ordered_score = entry.similarity(" houn");

        let improperly_ordered_score = entry.similarity("nuoh");
        assert!(properly_ordered_score > improperly_ordered_score);
    }

    #[test]
    fn similarity_score_decreases_for_non_matching_characters() {
        let entry = new("hound".to_string());

        // Don't use a perfect match, since those product a perfect score.
        let non_matching_score = entry.similarity("houns");

        let subset_score = entry.similarity("houn");
        assert!(subset_score > non_matching_score);
    }

    #[test]
    fn similarity_score_is_zero_for_larger_query_with_no_matching_characters() {
        let entry = new("amp".to_string());
        assert_eq!(entry.similarity("hound"), 0.0f32);
    }
}
<|endoftext|>


<commit_before>use futures::{
    future::{select, Either},
    Future, FutureExt,
};
use hyper::server::conn::Http;
use tokio::{
    runtime::{Builder, Runtime},
    signal::ctrl_c,
    task::{JoinHandle, LocalSet},
};

use crate::{
    base::{Router, Server},
    config::{Config, TlsAcceptor},
    how::Result,
    stat::stat_print,
};

pub struct State {
    tls: Option<TlsAcceptor>,
    config: Config,
    runtime: Runtime,
    router: Router,
    http: Http,
}

pub static mut STATE: Option<State> = None;

pub type GlobalState = &'static State;

impl State {
    pub fn new(config: Config) -> Result<Self> {
        let tls = config.load_cert()?;
        let mut http = Http::new();
        http.keep_alive(config.keep_alive);
        let router = Router::new(&config);
        let runtime = Builder::new().threaded_scheduler().thread_name("tok").enable_all().build()?;

        Ok(Self {
            config,
            runtime,
            router,
            tls,
            http,
        })
    }
    pub fn into_global(self) -> GlobalState {
        unsafe {
            STATE = Some(self);
            assert_eq!(STATE.as_ref().unwrap().config, Self::global().config);
            STATE.as_ref().unwrap()
        }
    }
    pub fn global() -> GlobalState {
        unsafe { STATE.as_ref().expect("Global State is None") }
    }

    pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        self.runtime.spawn(future)
    }
    pub fn config(&self) -> &Config {
        &self.config
    }
    pub fn tls(&self) -> &Option<TlsAcceptor> {
        &self.tls
    }
    pub fn http(&self) -> &Http {
        &self.http
    }
    pub fn router(&self) -> &Router {
        &self.router
    }
}

pub fn run(config: Config) -> Result<()> {
    stat_print(&config.addr, config.cert.is_some(), config.routes.values());

    let state = State::new(config)?.into_global();
    let mut rt = Builder::new().basic_scheduler().enable_all().build()?;
    let local = LocalSet::new();

    local.block_on(&mut rt, async move {
        let http = Server::run(state);
        let ctrlc = ctrl_c();

        match select(http.boxed(), ctrlc.boxed()).await {
            Either::Left((http, _)) => {
                error!("http listen failed: {:?}", http);
            }
            Either::Right((ctrlc, _)) => {
                warn!("ctrlc catched: {:?}, will exit", ctrlc);
            }
        }

        Ok(())
    })
}
<commit_msg>set core_threads for Runtime<commit_after>use futures::{
    future::{select, Either},
    Future, FutureExt,
};
use hyper::server::conn::Http;
use tokio::{
    runtime::{Builder, Runtime},
    signal::ctrl_c,
    task::{JoinHandle, LocalSet},
};

use crate::{
    base::{Router, Server},
    config::{Config, TlsAcceptor},
    how::Result,
    stat::stat_print,
};

pub struct State {
    tls: Option<TlsAcceptor>,
    config: Config,
    runtime: Runtime,
    router: Router,
    http: Http,
}

pub static mut STATE: Option<State> = None;

pub type GlobalState = &'static State;

impl State {
    pub fn new(config: Config) -> Result<Self> {
        let tls = config.load_cert()?;
        let mut http = Http::new();
        http.keep_alive(config.keep_alive);
        let router = Router::new(&config);
        let runtime = Builder::new()
            .threaded_scheduler()
            .core_threads(num_cpus::get() * 2 + 1)
            .thread_name("tok")
            .enable_all()
            .build()?;

        Ok(Self {
            config,
            runtime,
            router,
            tls,
            http,
        })
    }
    pub fn into_global(self) -> GlobalState {
        unsafe {
            STATE = Some(self);
            assert_eq!(STATE.as_ref().unwrap().config, Self::global().config);
            STATE.as_ref().unwrap()
        }
    }
    pub fn global() -> GlobalState {
        unsafe { STATE.as_ref().expect("Global State is None") }
    }

    pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
    where
        F: Future + Send + 'static,
        F::Output: Send + 'static,
    {
        self.runtime.spawn(future)
    }
    pub fn config(&self) -> &Config {
        &self.config
    }
    pub fn tls(&self) -> &Option<TlsAcceptor> {
        &self.tls
    }
    pub fn http(&self) -> &Http {
        &self.http
    }
    pub fn router(&self) -> &Router {
        &self.router
    }
}

pub fn run(config: Config) -> Result<()> {
    stat_print(&config.addr, config.cert.is_some(), config.routes.values());

    let state = State::new(config)?.into_global();
    let mut rt = Builder::new().basic_scheduler().enable_all().build()?;
    let local = LocalSet::new();

    local.block_on(&mut rt, async move {
        let http = Server::run(state);
        let ctrlc = ctrl_c();

        match select(http.boxed(), ctrlc.boxed()).await {
            Either::Left((http, _)) => {
                error!("http listen failed: {:?}", http);
            }
            Either::Right((ctrlc, _)) => {
                warn!("ctrlc catched: {:?}, will exit", ctrlc);
            }
        }

        Ok(())
    })
}
<|endoftext|>


<commit_before>// Copyright 2015 Drew Short <drew@sothr.com>.
//
// Licensed under the MIT license<LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

// Pull in the image processing crate
extern crate image;

use std::path::Path;
use self::image::{
    GenericImage,
    Pixel,
    FilterType
};
use self::image::imageops;

pub struct PreparedImage<'a> {
    orig_path: &'a str,
    image: image::ImageBuffer<image::Luma<u8>,Vec<u8>>
}

pub fn prepare_image(path: &Path, size: u32) -> PreparedImage {
    let image_path = path.to_str().unwrap();
    let image = image::open(path).unwrap();
    let small_image = image.resize_exact(size, size, image::FilterType::Lanczos3);
    let grey_image = small_image.to_luma();
    PreparedImage { orig_path: &*image_path, image: grey_image }
}

/*
 * Calculate the number of bits different between two hashes
 */
pub fn calculate_hamming_distance(hash1: u64, hash2: u64) -> u64 {
    // The binary xor of the two hashes should give us a number representing
    // the differences between the two hashes. All that's left is to count
    // the number of 1's in the difference to determine the hamming distance
    let bin_diff = hash1 ^ hash2;
    let bin_diff_str = format!("{:b}", bin_diff);
    let mut hamming = 0u64;
    for bit in bin_diff_str.chars() {
        match bit {
            '1' => hamming+=1,
            _ => continue
        }
    }
    hamming
}

/**
 * Calculate the ahash of an image provided at the indicated path.
 *
 * # Arguments
 *
 * * 'path' - The path to the image file to create a hash from.
 *
 * Returns a u64 representing the value of the hash
 */
pub fn get_ahash(prepared_image: PreparedImage) -> u64 {
    let img = prepared_image.image;
    let (width, height) = img.dimensions();

    // calculating the average pixel value
    let mut total = 0u64;
    for pixel in img.pixels() {
        let channels = pixel.channels();
        //println!("Pixel is: {}", channels[0]);
        total += channels[0] as u64;
    }
    let mean = total / (width*height) as u64;
    //println!("Mean for {} is {}", prepared_image.orig_path, mean);

    // Calculating a hash based on the mean
    let mut hash = 0u64;
    for pixel in img.pixels() {
        let channels = pixel.channels();
        let pixel_sum = channels[0] as u64;
        if pixel_sum >= mean {
            hash |= 1;
            //println!("Pixel {} is >= {} therefore {:b}", pixel_sum, mean, hash);
        } else {
            hash |= 0;
            //println!("Pixel {} is < {} therefore {:b}", pixel_sum, mean, hash);
        }
        hash <<= 1;
    }
    //println!("Hash for {} is {}", prepared_image.orig_path, hash);

    return hash;
}
<commit_msg>Working on the dhash and phash implementations for the library.<commit_after>// Copyright 2015 Drew Short <drew@sothr.com>.
//
// Licensed under the MIT license<LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms.

// Pull in the image processing crate
extern crate image;

use std::path::Path;
use self::image::{
    GenericImage,
    Pixel,
    FilterType
};
use self::image::imageops;

pub struct PreparedImage<'a> {
    orig_path: &'a str,
    image: image::ImageBuffer<image::Luma<u8>,Vec<u8>>
}

pub fn prepare_image(path: &Path, size: u32) -> PreparedImage {
    let image_path = path.to_str().unwrap();
    let image = image::open(path).unwrap();
    let small_image = image.resize_exact(size, size, image::FilterType::Lanczos3);
    let grey_image = small_image.to_luma();
    PreparedImage { orig_path: &*image_path, image: grey_image }
}

/*
 * Calculate the number of bits different between two hashes
 */
pub fn calculate_hamming_distance(hash1: u64, hash2: u64) -> u64 {
    // The binary xor of the two hashes should give us a number representing
    // the differences between the two hashes. All that's left is to count
    // the number of 1's in the difference to determine the hamming distance
    let bin_diff = hash1 ^ hash2;
    let bin_diff_str = format!("{:b}", bin_diff);
    let mut hamming = 0u64;
    for bit in bin_diff_str.chars() {
        match bit {
            '1' => hamming+=1,
            _ => continue
        }
    }
    hamming
}

/**
 * Calculate the ahash of the provided prepared image.
 *
 * # Arguments
 *
 * * 'prepared_image' - The already prepared image for perceptual processing.
 *
 * Returns a u64 representing the value of the hash
 */
pub fn get_ahash(prepared_image: PreparedImage) -> u64 {
    let img = prepared_image.image;
    let (width, height) = img.dimensions();

    // calculating the average pixel value
    let mut total = 0u64;
    for pixel in img.pixels() {
        let channels = pixel.channels();
        //println!("Pixel is: {}", channels[0]);
        total += channels[0] as u64;
    }
    let mean = total / (width*height) as u64;
    //println!("Mean for {} is {}", prepared_image.orig_path, mean);

    // Calculating a hash based on the mean
    let mut hash = 0u64;
    for pixel in img.pixels() {
        let channels = pixel.channels();
        let pixel_sum = channels[0] as u64;
        if pixel_sum >= mean {
            hash |= 1;
            //println!("Pixel {} is >= {} therefore {:b}", pixel_sum, mean, hash);
        } else {
            hash |= 0;
            //println!("Pixel {} is < {} therefore {:b}", pixel_sum, mean, hash);
        }
        hash <<= 1;
    }
    //println!("Hash for {} is {}", prepared_image.orig_path, hash);

    return hash;
}

/**
 * Calculate the dhash of the provided prepared image
 *
 * # Arguments
 *
 * * 'prepared_image' - The already prepared image for perceptual processing
 *
 * # Return
 *
 * Returns a u64 representing the value of the hash
 */
pub fn get_dhash(prepared_image: PreparedImage) -> u64 {

}

/**
 * Calculate the phash of the provided prepared image
 *
 * # Arguments
 *
 * * 'prepared_image' - The already prepared image for perceptual processing
 *
 * # Return
 *
 * Returns a u64 representing the value of the hash
 */
pub fn get_phash(prepared_image: PreparedImage) -> u64 {

}
<|endoftext|>


<commit_before>use std::str;
use std::str::FromStr;
use nom::*;
use nom::IResult::*;
use nom::Err::*;
use nock::Noun;

/// Match at least two spaces or one newline.
pub fn gap(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let mut spaces = 0;
    let mut idx = 0;
    for item in input.iter() {
        if *item == '\t' as u8 {
            // Physical tabs are banned.
            // XXX: Should have own ErrorKind tag.
            return Error(Position(ErrorKind::MultiSpace, input));
        }

        if *item == '\n' as u8 {
            spaces += 2;
        } else if is_space(*item) {
            spaces += 1;
        }

        if !is_space(*item) && *item != '\r' as u8 && *item != '\n' as u8 {
            break;
        }

        idx += 1;
    }

    if spaces < 2 {
        return Error(Position(ErrorKind::MultiSpace, input));
    } else {
        return Done(&input[idx..], &input[0..idx]);
    }
}

// TODO: Handle separator dots
named!(atom<Noun>,
  map_res!(
    map_res!(
      digit,
      str::from_utf8
    ),
    FromStr::from_str
  )
);

named!(pqr<(Noun, Noun, Noun)>,
    alt!(
        chain!(
            p: preceded!(gap, atom) ~
            q: preceded!(gap, atom) ~
            r: preceded!(gap, atom),
            || { (p, q, r) })
        | delimited!(
            tag!("("),
            chain!(
                p: atom ~
                multispace ~
                q: atom ~
                multispace ~
                r: atom,
                || { (p, q, r) }),
            tag!(")"))
    )
);

named!(wtcl<Noun>,
   chain!(
       tag!("?:")
     ~ a: pqr
     , || { let (p, q, r) = a.clone(); n![6, p, q, r] }
    )
);

named!(hoon<Noun>,
    alt!(
        atom
      | wtcl
    )
);

#[cfg(test)]
mod test {
    use nom::IResult;
    use nock::Noun;
    use super::{gap, atom, pqr, wtcl};

    #[test]
    fn test_parse_hoon() {
        assert_eq!(atom(&b"1234"[..]),
                   IResult::Done(&b""[..], Noun::Atom(1234)));

        assert!(gap(&b"  "[..]).is_done());
        assert!(gap(&b"    "[..]).is_done());
        assert!(gap(&b"\n"[..]).is_done());
        assert!(gap(&b"\n  "[..]).is_done());
        assert!(gap(&b"  \n  "[..]).is_done());
        assert!(!gap(&b" "[..]).is_done());

        assert_eq!(pqr(&b"(1 2 3)"[..]),
                   IResult::Done(&b""[..], (Noun::Atom(1), Noun::Atom(2), Noun::Atom(3))));
        assert_eq!(pqr(&b"\n1\n2\n3"[..]),
                   IResult::Done(&b""[..], (Noun::Atom(1), Noun::Atom(2), Noun::Atom(3))));
        assert_eq!(pqr(&b"  1  2  3"[..]),
                   IResult::Done(&b""[..], (Noun::Atom(1), Noun::Atom(2), Noun::Atom(3))));

        assert_eq!(wtcl(&b"?:(1 2 3)"[..]),
                   IResult::Done(&b""[..], n![6, 1, 2, 3]));
        assert_eq!(wtcl(&b"?:(1   2\n3)"[..]),
                   IResult::Done(&b""[..], n![6, 1, 2, 3]));
        assert_eq!(wtcl(&b"?:  1\n  2\n3"[..]),
                   IResult::Done(&b""[..], n![6, 1, 2, 3]));
    }
}
<commit_msg>Failing decrement test in parser<commit_after>use std::str;
use std::str::FromStr;
use nom::*;
use nom::IResult::*;
use nom::Err::*;
use nock::Noun;

/// Match at least two spaces or one newline.
pub fn gap(input: &[u8]) -> IResult<&[u8], &[u8]> {
    let mut spaces = 0;
    let mut idx = 0;
    for item in input.iter() {
        if *item == '\t' as u8 {
            // Physical tabs are banned.
            // XXX: Should have own ErrorKind tag.
            return Error(Position(ErrorKind::MultiSpace, input));
        }

        if *item == '\n' as u8 {
            spaces += 2;
        } else if is_space(*item) {
            spaces += 1;
        }

        if !is_space(*item) && *item != '\r' as u8 && *item != '\n' as u8 {
            break;
        }

        idx += 1;
    }

    if spaces < 2 {
        return Error(Position(ErrorKind::MultiSpace, input));
    } else {
        return Done(&input[idx..], &input[0..idx]);
    }
}

// TODO: Handle separator dots
named!(atom<Noun>,
  map_res!(
    map_res!(
      digit,
      str::from_utf8
    ),
    FromStr::from_str
  )
);

named!(pqr<(Noun, Noun, Noun)>,
    alt!(
        chain!(
            p: preceded!(gap, atom) ~
            q: preceded!(gap, atom) ~
            r: preceded!(gap, atom),
            || { (p, q, r) })
        | delimited!(
            tag!("("),
            chain!(
                p: atom ~
                multispace ~
                q: atom ~
                multispace ~
                r: atom,
                || { (p, q, r) }),
            tag!(")"))
    )
);

named!(wtcl<Noun>,
   chain!(
       tag!("?:")
     ~ a: pqr
     , || { let (p, q, r) = a.clone(); n![6, p, q, r] }
    )
);

named!(hoon<Noun>,
    alt!(
        atom
      | wtcl
    )
);

#[cfg(test)]
mod test {
    use std::rc::Rc;
    use nom::IResult;
    use nock::Noun;
    use super::{gap, atom, pqr, wtcl, hoon};

    #[test]
    fn test_parse_atom() {
        assert_eq!(atom(&b"1234"[..]),
                   IResult::Done(&b""[..], Noun::Atom(1234)));
    }

    #[test]
    fn test_parse_gap() {
        assert!(gap(&b"  "[..]).is_done());
        assert!(gap(&b"    "[..]).is_done());
        assert!(gap(&b"\n"[..]).is_done());
        assert!(gap(&b"\n  "[..]).is_done());
        assert!(gap(&b"  \n  "[..]).is_done());
        assert!(!gap(&b" "[..]).is_done());
    }

    #[test]
    fn test_parse_hoon() {
        assert_eq!(pqr(&b"(1 2 3)"[..]),
                   IResult::Done(&b""[..], (Noun::Atom(1), Noun::Atom(2), Noun::Atom(3))));
        assert_eq!(pqr(&b"\n1\n2\n3"[..]),
                   IResult::Done(&b""[..], (Noun::Atom(1), Noun::Atom(2), Noun::Atom(3))));
        assert_eq!(pqr(&b"  1  2  3"[..]),
                   IResult::Done(&b""[..], (Noun::Atom(1), Noun::Atom(2), Noun::Atom(3))));

        assert_eq!(wtcl(&b"?:(1 2 3)"[..]),
                   IResult::Done(&b""[..], n![6, 1, 2, 3]));
        assert_eq!(wtcl(&b"?:(1   2\n3)"[..]),
                   IResult::Done(&b""[..], n![6, 1, 2, 3]));
        assert_eq!(wtcl(&b"?:  1\n  2\n3"[..]),
                   IResult::Done(&b""[..], n![6, 1, 2, 3]));
    }

    #[test]
    fn test_decrement() {
        // Simple test case that needs quite a bit of machinery up and
        // running.
        let code = b"\
            =>  a=.                     ::  line 1
            =+  b=0                     ::  line 2
            |-                          ::  line 3
            ?:  =(a +(b))               ::  line 4
              b                         ::  line 5
            $(b +(b))                   ::  line 6";
        if let IResult::Done(_, noun) = hoon(&code[..]) {
            assert_eq!(n![42, noun].nock(),
                Ok(Rc::new(Noun::Atom(41))));
        } else {
            panic!("Failed to parse decrement code");
        }
    }
}
<|endoftext|>


<commit_before>use std::boxed::Box;
use std::borrow::BorrowMut;
use std::borrow::Borrow;
use std::option::Option;
use std::string::String;
use std::vec::Vec;

pub struct ASTNode<'a> {
    vals: Vec<&'a str>,
    index: usize,
    pub left: Box<Option<ASTNode<'a>>>,
    pub right: Box<Option<ASTNode<'a>>>,
}

impl<'a> ASTNode<'a> {

    pub fn new(vals: Vec<&'a str>) -> ASTNode<'a> {
        ASTNode { vals: vals, index: 0, left: Box::new(Option::None), right: Box::new(Option::None) }
    }

    pub fn current_val(&self) -> &'a str {
        self.vals[self.index]
    }

    pub fn next_val(&mut self) -> Option<&'a str> {
        if self.index == usize::max_value() {
            return Option::None;
        }
        let v = self.vals.get(self.index + 1);
        if v.is_some() {
            self.index += 1;
            return Option::Some(*(v.unwrap()));
        }
        Option::None
    }

    pub fn prev_val(&mut self) -> Option<&'a str> {
        if self.index == 0 {
            return Option::None;
        }
        let v = self.vals.get(self.index - 1);
        if v.is_some() {
            self.index -= 1;
            return Option::Some(*(v.unwrap()));
        }
        Option::None
    }
}

pub fn parse_query<'a>(query_string: &'a str) -> ASTNode<'a> {
    let mut c = query_string.chars();
    let index = c.position(|c| c == ' ').unwrap();
    let v = &query_string[0..index];
    ASTNode::new(vec![v])
}
<commit_msg>parser start<commit_after>use std::boxed::Box;
use std::borrow::BorrowMut;
use std::borrow::Borrow;
use std::option::Option;
use std::string::String;
use std::vec::Vec;

pub struct ASTNode<'a> {
    vals: Vec<&'a str>,
    index: usize,
    pub left: Box<Option<ASTNode<'a>>>,
    pub right: Box<Option<ASTNode<'a>>>,
}

impl<'a> ASTNode<'a> {

    pub fn new(vals: Vec<&'a str>) -> ASTNode<'a> {
        ASTNode { vals: vals, index: 0, left: Box::new(Option::None), right: Box::new(Option::None) }
    }

    pub fn current_val(&self) -> &'a str {
        self.vals[self.index]
    }

    pub fn next_val(&mut self) -> Option<&'a str> {
        if self.index == usize::max_value() {
            return Option::None;
        }
        let v = self.vals.get(self.index + 1);
        if v.is_some() {
            self.index += 1;
            return Option::Some(*(v.unwrap()));
        }
        Option::None
    }

    pub fn prev_val(&mut self) -> Option<&'a str> {
        if self.index == 0 {
            return Option::None;
        }
        let v = self.vals.get(self.index - 1);
        if v.is_some() {
            self.index -= 1;
            return Option::Some(*(v.unwrap()));
        }
        Option::None
    }
}

pub fn parse_query<'a>(query_string: &'a str) -> ASTNode<'a> {
    let mut c = query_string.chars().peekable();
    let mut last_index = 0;
    let mut head = Option::None;
    while c.peek().is_some() {
        let index = c.position(|c| c == ' ').unwrap();
        let v = &query_string[last_index..index];
        let node = ASTNode::new(vec![v]);
        last_index = index + 2;
        if head.is_none() {
            head = Option::Some(node);
        }
        else {
            head.unwrap().left = Box::new(Option::Some(node));
        }
    }
    head.unwrap()
}
<|endoftext|>


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

use chrono::NaiveDateTime;
use diesel::prelude::*;

use crate::util::errors::{cargo_err, AppResult};

use crate::models::{Crate, Dependency, User, VersionOwnerAction};
use crate::schema::*;
use crate::views::{EncodableAuditAction, EncodableVersion, EncodableVersionLinks};

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug, Queryable, Deserialize, Serialize)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: NaiveDateTime,
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: serde_json::Value,
    pub yanked: bool,
    pub license: Option<String>,
    pub crate_size: Option<i32>,
    pub published_by: Option<i32>,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: serde_json::Value,
    license: Option<String>,
    crate_size: Option<i32>,
    published_by: i32,
}

/// The highest version (semver order) and the most recently updated version.
/// Typically used for a single crate.
#[derive(Debug, Clone)]
pub struct TopVersions {
    pub highest: semver::Version,
    pub newest: semver::Version,
}

/// A default semver value, "0.0.0", for use in TopVersions
fn default_semver_version() -> semver::Version {
    semver::Version {
        major: 0,
        minor: 0,
        patch: 0,
        pre: vec![],
        build: vec![],
    }
}

impl Version {
    pub fn encodable(
        self,
        crate_name: &str,
        published_by: Option<User>,
        audit_actions: Vec<(VersionOwnerAction, User)>,
    ) -> EncodableVersion {
        let Version {
            id,
            num,
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            crate_size,
            ..
        } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            readme_path: format!("/api/v1/crates/{}/{}/readme", crate_name, num),
            num: num.clone(),
            id,
            krate: crate_name.to_string(),
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            links: EncodableVersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
            crate_size,
            published_by: published_by.map(User::encodable_public),
            audit_actions: audit_actions
                .into_iter()
                .map(|(audit_action, user)| EncodableAuditAction {
                    action: audit_action.action.into(),
                    user: User::encodable_public(user),
                    time: audit_action.time,
                })
                .collect(),
        }
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    /// Return both the newest (most recently updated) and the
    /// highest version (in semver order) for a collection of date/version pairs.
    pub fn top<T>(pairs: T) -> TopVersions
    where
        T: Clone + IntoIterator<Item = (NaiveDateTime, semver::Version)>,
    {
        TopVersions {
            newest: pairs
                .clone()
                .into_iter()
                .max()
                .unwrap_or((
                    NaiveDateTime::from_timestamp(0, 0),
                    default_semver_version(),
                ))
                .1,
            highest: pairs
                .into_iter()
                .map(|(_, v)| v)
                .max()
                .unwrap_or_else(default_semver_version),
        }
    }

    pub fn record_readme_rendering(version_id_: i32, conn: &PgConnection) -> QueryResult<usize> {
        use crate::schema::readme_renderings::dsl::*;
        use diesel::dsl::now;

        diesel::insert_into(readme_renderings)
            .values(version_id.eq(version_id_))
            .on_conflict(version_id)
            .do_update()
            .set(rendered_at.eq(now))
            .execute(conn)
    }

    /// Gets the User who ran `cargo publish` for this version, if recorded.
    /// Not for use when you have a group of versions you need the publishers for.
    pub fn published_by(&self, conn: &PgConnection) -> Option<User> {
        match self.published_by {
            Some(pb) => users::table.find(pb).first(conn).ok(),
            None => None,
        }
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
        crate_size: i32,
        published_by: i32,
    ) -> AppResult<Self> {
        let features = serde_json::to_value(features)?;

        let mut new_version = NewVersion {
            crate_id,
            num: num.to_string(),
            features,
            license,
            crate_size: Some(crate_size),
            published_by,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(
        &self,
        conn: &PgConnection,
        authors: &[String],
        published_by_email: &str,
    ) -> AppResult<Version> {
        use crate::schema::version_authors::{name, version_id};
        use crate::schema::versions::dsl::*;
        use diesel::dsl::exists;
        use diesel::{insert_into, select};

        conn.transaction(|| {
            let already_uploaded = versions
                .filter(crate_id.eq(self.crate_id))
                .filter(num.eq(&self.num));
            if select(exists(already_uploaded)).get_result(conn)? {
                return Err(cargo_err(&format_args!(
                    "crate version `{}` is already \
                     uploaded",
                    self.num
                )));
            }

            let version: Version = insert_into(versions).values(self).get_result(conn)?;

            insert_into(versions_published_by::table)
                .values((
                    versions_published_by::version_id.eq(version.id),
                    versions_published_by::email.eq(published_by_email),
                ))
                .execute(conn)?;

            let new_authors = authors
                .iter()
                .map(|s| (version_id.eq(version.id), name.eq(s)))
                .collect::<Vec<_>>();

            insert_into(version_authors::table)
                .values(&new_authors)
                .execute(conn)?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> AppResult<()> {
        if let Some(ref license) = self.license {
            for part in license.split('/') {
                license_exprs::validate_license_expr(part).map_err(|e| {
                    cargo_err(&format_args!(
                        "{}; see http://opensource.org/licenses \
                         for options, and http://spdx.org/licenses/ \
                         for their identifiers",
                        e
                    ))
                })?;
            }
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}
<commit_msg>models/version: Derive `Eq` for `TopVersions` struct<commit_after>use std::collections::HashMap;

use chrono::NaiveDateTime;
use diesel::prelude::*;

use crate::util::errors::{cargo_err, AppResult};

use crate::models::{Crate, Dependency, User, VersionOwnerAction};
use crate::schema::*;
use crate::views::{EncodableAuditAction, EncodableVersion, EncodableVersionLinks};

// Queryable has a custom implementation below
#[derive(Clone, Identifiable, Associations, Debug, Queryable, Deserialize, Serialize)]
#[belongs_to(Crate)]
pub struct Version {
    pub id: i32,
    pub crate_id: i32,
    pub num: semver::Version,
    pub updated_at: NaiveDateTime,
    pub created_at: NaiveDateTime,
    pub downloads: i32,
    pub features: serde_json::Value,
    pub yanked: bool,
    pub license: Option<String>,
    pub crate_size: Option<i32>,
    pub published_by: Option<i32>,
}

#[derive(Insertable, Debug)]
#[table_name = "versions"]
pub struct NewVersion {
    crate_id: i32,
    num: String,
    features: serde_json::Value,
    license: Option<String>,
    crate_size: Option<i32>,
    published_by: i32,
}

/// The highest version (semver order) and the most recently updated version.
/// Typically used for a single crate.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TopVersions {
    pub highest: semver::Version,
    pub newest: semver::Version,
}

/// A default semver value, "0.0.0", for use in TopVersions
fn default_semver_version() -> semver::Version {
    semver::Version {
        major: 0,
        minor: 0,
        patch: 0,
        pre: vec![],
        build: vec![],
    }
}

impl Version {
    pub fn encodable(
        self,
        crate_name: &str,
        published_by: Option<User>,
        audit_actions: Vec<(VersionOwnerAction, User)>,
    ) -> EncodableVersion {
        let Version {
            id,
            num,
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            crate_size,
            ..
        } = self;
        let num = num.to_string();
        EncodableVersion {
            dl_path: format!("/api/v1/crates/{}/{}/download", crate_name, num),
            readme_path: format!("/api/v1/crates/{}/{}/readme", crate_name, num),
            num: num.clone(),
            id,
            krate: crate_name.to_string(),
            updated_at,
            created_at,
            downloads,
            features,
            yanked,
            license,
            links: EncodableVersionLinks {
                dependencies: format!("/api/v1/crates/{}/{}/dependencies", crate_name, num),
                version_downloads: format!("/api/v1/crates/{}/{}/downloads", crate_name, num),
                authors: format!("/api/v1/crates/{}/{}/authors", crate_name, num),
            },
            crate_size,
            published_by: published_by.map(User::encodable_public),
            audit_actions: audit_actions
                .into_iter()
                .map(|(audit_action, user)| EncodableAuditAction {
                    action: audit_action.action.into(),
                    user: User::encodable_public(user),
                    time: audit_action.time,
                })
                .collect(),
        }
    }

    /// Returns (dependency, crate dependency name)
    pub fn dependencies(&self, conn: &PgConnection) -> QueryResult<Vec<(Dependency, String)>> {
        Dependency::belonging_to(self)
            .inner_join(crates::table)
            .select((dependencies::all_columns, crates::name))
            .order((dependencies::optional, crates::name))
            .load(conn)
    }

    /// Return both the newest (most recently updated) and the
    /// highest version (in semver order) for a collection of date/version pairs.
    pub fn top<T>(pairs: T) -> TopVersions
    where
        T: Clone + IntoIterator<Item = (NaiveDateTime, semver::Version)>,
    {
        TopVersions {
            newest: pairs
                .clone()
                .into_iter()
                .max()
                .unwrap_or((
                    NaiveDateTime::from_timestamp(0, 0),
                    default_semver_version(),
                ))
                .1,
            highest: pairs
                .into_iter()
                .map(|(_, v)| v)
                .max()
                .unwrap_or_else(default_semver_version),
        }
    }

    pub fn record_readme_rendering(version_id_: i32, conn: &PgConnection) -> QueryResult<usize> {
        use crate::schema::readme_renderings::dsl::*;
        use diesel::dsl::now;

        diesel::insert_into(readme_renderings)
            .values(version_id.eq(version_id_))
            .on_conflict(version_id)
            .do_update()
            .set(rendered_at.eq(now))
            .execute(conn)
    }

    /// Gets the User who ran `cargo publish` for this version, if recorded.
    /// Not for use when you have a group of versions you need the publishers for.
    pub fn published_by(&self, conn: &PgConnection) -> Option<User> {
        match self.published_by {
            Some(pb) => users::table.find(pb).first(conn).ok(),
            None => None,
        }
    }
}

impl NewVersion {
    pub fn new(
        crate_id: i32,
        num: &semver::Version,
        features: &HashMap<String, Vec<String>>,
        license: Option<String>,
        license_file: Option<&str>,
        crate_size: i32,
        published_by: i32,
    ) -> AppResult<Self> {
        let features = serde_json::to_value(features)?;

        let mut new_version = NewVersion {
            crate_id,
            num: num.to_string(),
            features,
            license,
            crate_size: Some(crate_size),
            published_by,
        };

        new_version.validate_license(license_file)?;

        Ok(new_version)
    }

    pub fn save(
        &self,
        conn: &PgConnection,
        authors: &[String],
        published_by_email: &str,
    ) -> AppResult<Version> {
        use crate::schema::version_authors::{name, version_id};
        use crate::schema::versions::dsl::*;
        use diesel::dsl::exists;
        use diesel::{insert_into, select};

        conn.transaction(|| {
            let already_uploaded = versions
                .filter(crate_id.eq(self.crate_id))
                .filter(num.eq(&self.num));
            if select(exists(already_uploaded)).get_result(conn)? {
                return Err(cargo_err(&format_args!(
                    "crate version `{}` is already \
                     uploaded",
                    self.num
                )));
            }

            let version: Version = insert_into(versions).values(self).get_result(conn)?;

            insert_into(versions_published_by::table)
                .values((
                    versions_published_by::version_id.eq(version.id),
                    versions_published_by::email.eq(published_by_email),
                ))
                .execute(conn)?;

            let new_authors = authors
                .iter()
                .map(|s| (version_id.eq(version.id), name.eq(s)))
                .collect::<Vec<_>>();

            insert_into(version_authors::table)
                .values(&new_authors)
                .execute(conn)?;
            Ok(version)
        })
    }

    fn validate_license(&mut self, license_file: Option<&str>) -> AppResult<()> {
        if let Some(ref license) = self.license {
            for part in license.split('/') {
                license_exprs::validate_license_expr(part).map_err(|e| {
                    cargo_err(&format_args!(
                        "{}; see http://opensource.org/licenses \
                         for options, and http://spdx.org/licenses/ \
                         for their identifiers",
                        e
                    ))
                })?;
            }
        } else if license_file.is_some() {
            // If no license is given, but a license file is given, flag this
            // crate as having a nonstandard license. Note that we don't
            // actually do anything else with license_file currently.
            self.license = Some(String::from("non-standard"));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![allow(non_camel_case_types)]

use libc::*;

pub type xmpp_handler = Option<extern "C" fn(*const xmpp_conn_t, *const xmpp_stanza_t, *const c_void)>;
pub type xmpp_conn_handler = Option<extern "C" fn(*const xmpp_conn_t, c_int, c_int, *const xmpp_stream_error_t, *const c_void)>;
pub type xmpp_timed_handler = Option<extern "C" fn(*const xmpp_conn_t, *const xmpp_stanza_t, *const c_void)>;
pub type xmpp_log_handler = Option<extern "C" fn(*const c_void, c_int, *const c_char, *const c_char, *const c_char)>;
pub type xmpp_open_handler = Option<extern "C" fn(*const xmpp_conn_t)>;

pub type hash_free_func = Option<extern "C" fn(*const xmpp_ctx_t, *mut c_void)>;

#[repr(C)]
pub struct xmpp_conn_t {
  _ref: c_uint,
  ctx: *mut xmpp_ctx_t,
  _type: c_int,

  state: c_int,
  timeout_stamp: uint64_t,
  error: c_int,
  stream_error: *mut xmpp_stream_error_t,
  sock: c_int,
  tls: *mut c_void,

  tls_support: c_int,
  tls_disabled: c_int,
  tls_failed: c_int,
  sasl_support: c_int,
  secured: c_int,

  bind_required: c_int,
  session_required: c_int,

  lang: *mut c_char,
  domain: *mut c_char,
  connectdomain: *mut c_char,
  connectport: *mut c_char,
  jid: *mut c_char,
  pass: *mut c_char,
  bound_jid: *mut c_char,
  stream_id: *mut c_char,

  blocking_seed: c_int,
  send_queue_max: c_int,
  send_queue_len: c_int,
  send_queue_head: *mut c_void,
  send_queue_tail: *mut c_void,

  reset_parser: c_int,
  parser: *mut c_void,
  connect_timeout: c_uint,
  open_handler: xmpp_open_handler,
  authenticated: c_int,

  conn_handler: xmpp_conn_handler,
  userdata: *mut c_void,

  timed_handlers: *mut c_void,
  id_handlers: *mut hash_t,
  handlers: *mut c_void
}

#[repr(C)]
pub struct xmpp_stanza_t {
  _ref: c_int,
  ctx: *mut xmpp_ctx_t,
  _type: c_int,
  prev: *mut xmpp_stanza_t,
  next: *mut xmpp_stanza_t,
  children: *mut xmpp_stanza_t,
  parent: *mut xmpp_stanza_t,
  data: *mut c_char,
  attributes: *mut hash_t
}

#[repr(C)]
pub struct xmpp_ctx_t {
  mem: *const xmpp_mem_t,
  log: *const xmpp_log_t,
  loop_status: c_int,
  connlist: *mut xmpp_connlist_t
}

#[repr(C)]
pub struct xmpp_connlist_t {
  conn: *mut xmpp_conn_t,
  next: *mut xmpp_connlist_t
}

#[repr(C)]
pub struct xmpp_mem_t {
  alloc: Option<extern "C" fn(size_t, *mut u8) -> *mut u8>,
  free: Option<extern "C" fn(*mut u8, *const u8)>,
  realloc: Option<extern "C" fn(*mut u8, size_t, *const u8) -> *mut u8>,
  userdata: *mut c_void
}

#[repr(C)]
pub struct xmpp_log_t {
  handler: xmpp_log_handler,
  userdata: *mut c_void
}

#[repr(C)]
pub struct xmpp_stream_error_t {
  _type: c_int, //xmpp_error_type_t
  text: *mut c_char,
  stanza: *mut xmpp_stanza_t
}

#[repr(C)]
pub struct hashentry_t {
  next: *mut hashentry_t,
  key: *mut c_char,
  values: *mut c_void
}

#[repr(C)]
pub struct hash_t {
  _ref: c_uint,
  ctx: *mut xmpp_ctx_t,
  free: hash_free_func,
  length: c_int,
  num_keys: c_int,
  entries: *mut *mut hashentry_t
}

#[repr(C)]
pub enum xmpp_log_level_t {
  XMPP_LEVEL_DEBUG,
  XMPP_LEVEL_INFO,
  XMPP_LEVEL_WARN,
  XMPP_LEVEL_ERROR
}

#[repr(C)]
pub enum xmpp_conn_type_t {
  XMPP_UNKNOWN,
  XMPP_CLIENT,
  XMPP_COMPONENT
}

#[repr(C)]
pub enum xmpp_conn_event_t {
  XMPP_CONN_CONNECT,
  XMPP_CONN_DISCONNECT,
  XMPP_CONN_FAIL
}

#[repr(C)]
pub enum xmpp_error_type_t {
  XMPP_SE_BAD_FORMAT,
  XMPP_SE_BAD_NS_PREFIX,
  XMPP_SE_CONFLICT,
  XMPP_SE_CONN_TIMEOUT,
  XMPP_SE_HOST_GONE,
  XMPP_SE_HOST_UNKNOWN,
  XMPP_SE_IMPROPER_ADDR,
  XMPP_SE_INTERNAL_SERVER_ERROR,
  XMPP_SE_INVALID_FROM,
  XMPP_SE_INVALID_ID,
  XMPP_SE_INVALID_NS,
  XMPP_SE_INVALID_XML,
  XMPP_SE_NOT_AUTHORIZED,
  XMPP_SE_POLICY_VIOLATION,
  XMPP_SE_REMOTE_CONN_FAILED,
  XMPP_SE_RESOURCE_CONSTRAINT,
  XMPP_SE_RESTRICTED_XML,
  XMPP_SE_SEE_OTHER_HOST,
  XMPP_SE_SYSTEM_SHUTDOWN,
  XMPP_SE_UNDEFINED_CONDITION,
  XMPP_SE_UNSUPPORTED_ENCODING,
  XMPP_SE_UNSUPPORTED_STANZA_TYPE,
  XMPP_SE_UNSUPPORTED_VERSION,
  XMPP_SE_XML_NOT_WELL_FORMED
}

#[link(name="strophe")]
extern {
  // connection management
  pub fn xmpp_conn_new(ctx: *const xmpp_ctx_t) -> *mut xmpp_conn_t;
  pub fn xmpp_conn_close(ctx: *const xmpp_ctx_t) -> *mut xmpp_conn_t;
  pub fn xmpp_conn_release(conn: *const xmpp_conn_t) -> c_int;
  pub fn xmpp_conn_get_jid(conn: *const xmpp_conn_t) -> *const c_char;
  pub fn xmpp_conn_get_bound_jid(conn: *const xmpp_conn_t) -> *const c_char;
  pub fn xmpp_conn_set_jid(conn: *const xmpp_conn_t, jid: *const c_char);
  pub fn xmpp_conn_get_pass(conn: *const xmpp_conn_t) -> *const c_char;
  pub fn xmpp_conn_set_pass(conn: *const xmpp_conn_t, pass: *const c_char);
  pub fn xmpp_conn_get_context(conn: *const xmpp_conn_t) -> *mut xmpp_ctx_t;
  pub fn xmpp_connect_client(conn: *const xmpp_conn_t, altdomain: *const c_char, altport: c_ushort, callback: xmpp_conn_handler, userdata: *const u8) -> c_int;
  pub fn xmpp_disconnect(conn: *const xmpp_conn_t);
  pub fn xmpp_send(conn: *const xmpp_conn_t, stanza: *const xmpp_stanza_t);

  // context objects
  pub fn xmpp_get_default_logger(level: c_int) -> *mut xmpp_log_t;
  pub fn xmpp_ctx_new(mem: *const xmpp_mem_t, log: *const xmpp_log_t) -> *mut xmpp_ctx_t;
  pub fn xmpp_ctx_free(ctx: *const xmpp_ctx_t);

  // initialization, shutdown and versioning
  pub fn xmpp_initialize();
  pub fn xmpp_shutdown();
  pub fn xmpp_version_check(major: c_int, minor: c_int) -> c_int;

  // event loop
  pub fn xmpp_run_once(ctx: *mut xmpp_ctx_t, timeout: c_ulong);
  pub fn xmpp_run(ctx: *mut xmpp_ctx_t);
  pub fn xmpp_stop(ctx: *mut xmpp_ctx_t);

  // stanza and timed event handlers
  pub fn xmpp_timed_handler_delete(conn: *const xmpp_conn_t, handler: xmpp_timed_handler);
  pub fn xmpp_id_handler_delete(conn: *const xmpp_conn_t, handler: xmpp_handler, id: *const c_char);
  pub fn xmpp_handler_delete(conn: *const xmpp_conn_t, handler: xmpp_handler);
  pub fn xmpp_timed_handler_add(conn: *const xmpp_conn_t, handler: xmpp_timed_handler, period: c_ulong, userdata: *const c_void);
  pub fn xmpp_id_handler_add(conn: *const xmpp_conn_t, handler: xmpp_handler, id: *const c_char, userdata: *const c_void);
  pub fn xmpp_handler_add(conn: *const xmpp_conn_t, handler: xmpp_handler, ns: *const c_char, name: *const c_char, _type: *const c_char, userdata: *const c_void);

  // stanza creation and manipulation
  pub fn xmpp_stanza_new(ctx: *mut xmpp_ctx_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_clone(stanza: *const xmpp_stanza_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_copy(stanza: *const xmpp_stanza_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_release(stanza: *const xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_is_text(stanza: *const xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_is_tag(stanza: *const xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_to_text(stanza: *mut xmpp_stanza_t, buf: *const *const c_char, sizelen: *const size_t) -> c_int;
  pub fn xmpp_stanza_set_name(stanza: *mut xmpp_stanza_t, name: *const c_char) -> c_int;
  pub fn xmpp_stanza_get_name(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_attribute_count(stanza: *const xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_get_attributes(stanza: *const xmpp_stanza_t, attr: *const *const c_char, attrlen: c_int) -> c_int;
  pub fn xmpp_stanza_set_attribute(stanza: *const xmpp_stanza_t, key: *const c_char, value: *const c_char) -> c_int;
  pub fn xmpp_stanza_set_ns(stanza: *const xmpp_stanza_t, ns: *const c_char) -> c_int;
  pub fn xmpp_stanza_add_child(stanza: *mut xmpp_stanza_t, child: *mut xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_set_text(stanza: *mut xmpp_stanza_t, text: *const c_char) -> c_int;
  pub fn xmpp_stanza_set_text_with_size(stanza: *mut xmpp_stanza_t, text: *const c_char, size: size_t) -> c_int;
  pub fn xmpp_stanza_get_id(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_ns(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_type(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_child_by_name(stanza: *const xmpp_stanza_t, name: *const c_char) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_get_child_by_ns(stanza: *const xmpp_stanza_t, ns: *const c_char) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_get_children(stanza: *const xmpp_stanza_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_get_next(stanza: *const xmpp_stanza_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_get_text(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_text_ptr(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_set_id(stanza: *const xmpp_stanza_t, id: *const c_char) -> c_int;
  pub fn xmpp_stanza_set_type(stanza: *const xmpp_stanza_t, _type: *const c_char) -> c_int;
  pub fn xmpp_stanza_get_attribute(stanza: *const xmpp_stanza_t, name: *const c_char) -> *mut c_char;
}

<commit_msg>add missing globals<commit_after>#![allow(non_camel_case_types)]

use libc::*;

pub type xmpp_handler = Option<extern "C" fn(*const xmpp_conn_t, *const xmpp_stanza_t, *const c_void)>;
pub type xmpp_conn_handler = Option<extern "C" fn(*const xmpp_conn_t, c_int, c_int, *const xmpp_stream_error_t, *const c_void)>;
pub type xmpp_timed_handler = Option<extern "C" fn(*const xmpp_conn_t, *const xmpp_stanza_t, *const c_void)>;
pub type xmpp_log_handler = Option<extern "C" fn(*const c_void, c_int, *const c_char, *const c_char, *const c_char)>;
pub type xmpp_open_handler = Option<extern "C" fn(*const xmpp_conn_t)>;

pub type hash_free_func = Option<extern "C" fn(*const xmpp_ctx_t, *mut c_void)>;

#[repr(C)]
pub struct xmpp_conn_t {
  _ref: c_uint,
  ctx: *mut xmpp_ctx_t,
  _type: c_int,

  state: c_int,
  timeout_stamp: uint64_t,
  error: c_int,
  stream_error: *mut xmpp_stream_error_t,
  sock: c_int,
  tls: *mut c_void,

  tls_support: c_int,
  tls_disabled: c_int,
  tls_failed: c_int,
  sasl_support: c_int,
  secured: c_int,

  bind_required: c_int,
  session_required: c_int,

  lang: *mut c_char,
  domain: *mut c_char,
  connectdomain: *mut c_char,
  connectport: *mut c_char,
  jid: *mut c_char,
  pass: *mut c_char,
  bound_jid: *mut c_char,
  stream_id: *mut c_char,

  blocking_seed: c_int,
  send_queue_max: c_int,
  send_queue_len: c_int,
  send_queue_head: *mut c_void,
  send_queue_tail: *mut c_void,

  reset_parser: c_int,
  parser: *mut c_void,
  connect_timeout: c_uint,
  open_handler: xmpp_open_handler,
  authenticated: c_int,

  conn_handler: xmpp_conn_handler,
  userdata: *mut c_void,

  timed_handlers: *mut c_void,
  id_handlers: *mut hash_t,
  handlers: *mut c_void
}

#[repr(C)]
pub struct xmpp_stanza_t {
  _ref: c_int,
  ctx: *mut xmpp_ctx_t,
  _type: c_int,
  prev: *mut xmpp_stanza_t,
  next: *mut xmpp_stanza_t,
  children: *mut xmpp_stanza_t,
  parent: *mut xmpp_stanza_t,
  data: *mut c_char,
  attributes: *mut hash_t
}

#[repr(C)]
pub struct xmpp_ctx_t {
  mem: *const xmpp_mem_t,
  log: *const xmpp_log_t,
  loop_status: c_int,
  connlist: *mut xmpp_connlist_t
}

#[repr(C)]
pub struct xmpp_connlist_t {
  conn: *mut xmpp_conn_t,
  next: *mut xmpp_connlist_t
}

#[repr(C)]
pub struct xmpp_mem_t {
  alloc: Option<extern "C" fn(size_t, *mut u8) -> *mut u8>,
  free: Option<extern "C" fn(*mut u8, *const u8)>,
  realloc: Option<extern "C" fn(*mut u8, size_t, *const u8) -> *mut u8>,
  userdata: *mut c_void
}

#[repr(C)]
pub struct xmpp_log_t {
  handler: xmpp_log_handler,
  userdata: *mut c_void
}

#[repr(C)]
pub struct xmpp_stream_error_t {
  _type: c_int, //xmpp_error_type_t
  text: *mut c_char,
  stanza: *mut xmpp_stanza_t
}

#[repr(C)]
pub struct hashentry_t {
  next: *mut hashentry_t,
  key: *mut c_char,
  values: *mut c_void
}

#[repr(C)]
pub struct hash_t {
  _ref: c_uint,
  ctx: *mut xmpp_ctx_t,
  free: hash_free_func,
  length: c_int,
  num_keys: c_int,
  entries: *mut *mut hashentry_t
}

#[repr(C)]
pub enum xmpp_log_level_t {
  XMPP_LEVEL_DEBUG,
  XMPP_LEVEL_INFO,
  XMPP_LEVEL_WARN,
  XMPP_LEVEL_ERROR
}

#[repr(C)]
pub enum xmpp_conn_type_t {
  XMPP_UNKNOWN,
  XMPP_CLIENT,
  XMPP_COMPONENT
}

#[repr(C)]
pub enum xmpp_conn_event_t {
  XMPP_CONN_CONNECT,
  XMPP_CONN_DISCONNECT,
  XMPP_CONN_FAIL
}

#[repr(C)]
pub enum xmpp_error_type_t {
  XMPP_SE_BAD_FORMAT,
  XMPP_SE_BAD_NS_PREFIX,
  XMPP_SE_CONFLICT,
  XMPP_SE_CONN_TIMEOUT,
  XMPP_SE_HOST_GONE,
  XMPP_SE_HOST_UNKNOWN,
  XMPP_SE_IMPROPER_ADDR,
  XMPP_SE_INTERNAL_SERVER_ERROR,
  XMPP_SE_INVALID_FROM,
  XMPP_SE_INVALID_ID,
  XMPP_SE_INVALID_NS,
  XMPP_SE_INVALID_XML,
  XMPP_SE_NOT_AUTHORIZED,
  XMPP_SE_POLICY_VIOLATION,
  XMPP_SE_REMOTE_CONN_FAILED,
  XMPP_SE_RESOURCE_CONSTRAINT,
  XMPP_SE_RESTRICTED_XML,
  XMPP_SE_SEE_OTHER_HOST,
  XMPP_SE_SYSTEM_SHUTDOWN,
  XMPP_SE_UNDEFINED_CONDITION,
  XMPP_SE_UNSUPPORTED_ENCODING,
  XMPP_SE_UNSUPPORTED_STANZA_TYPE,
  XMPP_SE_UNSUPPORTED_VERSION,
  XMPP_SE_XML_NOT_WELL_FORMED
}

pub const XMPP_NS_CLIENT: &'static str = "jabber:client";
pub const XMPP_NS_COMPONENT: &'static str = "jabber:component:accept";
pub const XMPP_NS_STREAMS: &'static str = "http://etherx.jabber.org/streams";
pub const XMPP_NS_STREAMS_IETF: &'static str = "urn:ietf:params:xml:ns:xmpp-streams";
pub const XMPP_NS_TLS: &'static str = "urn:ietf:params:xml:ns:xmpp-tls";
pub const XMPP_NS_SASL: &'static str = "urn:ietf:params:xml:ns:xmpp-sasl";
pub const XMPP_NS_BIND: &'static str = "urn:ietf:params:xml:ns:xmpp-bind";
pub const XMPP_NS_SESSION: &'static str = "urn:ietf:params:xml:ns:xmpp-session";
pub const XMPP_NS_AUTH: &'static str = "jabber:iq:auth";
pub const XMPP_NS_DISCO_INFO: &'static str = "http://jabber.org/protocol/disco#info";
pub const XMPP_NS_DISCO_ITEMS: &'static str = "http://jabber.org/protocol/disco#items";
pub const XMPP_NS_ROSTER: &'static str = "jabber:iq:roster";

pub const XMPP_EOK:    c_int = 0;
pub const XMPP_EMEM:   c_int = -1;
pub const XMPP_EINVOP: c_int = -2;
pub const XMPP_EINT:   c_int = -3;

#[link(name="strophe")]
extern {
  // connection management
  pub fn xmpp_conn_new(ctx: *const xmpp_ctx_t) -> *mut xmpp_conn_t;
  pub fn xmpp_conn_close(ctx: *const xmpp_ctx_t) -> *mut xmpp_conn_t;
  pub fn xmpp_conn_release(conn: *const xmpp_conn_t) -> c_int;
  pub fn xmpp_conn_get_jid(conn: *const xmpp_conn_t) -> *const c_char;
  pub fn xmpp_conn_get_bound_jid(conn: *const xmpp_conn_t) -> *const c_char;
  pub fn xmpp_conn_set_jid(conn: *const xmpp_conn_t, jid: *const c_char);
  pub fn xmpp_conn_get_pass(conn: *const xmpp_conn_t) -> *const c_char;
  pub fn xmpp_conn_set_pass(conn: *const xmpp_conn_t, pass: *const c_char);
  pub fn xmpp_conn_get_context(conn: *const xmpp_conn_t) -> *mut xmpp_ctx_t;
  pub fn xmpp_connect_client(conn: *const xmpp_conn_t, altdomain: *const c_char, altport: c_ushort, callback: xmpp_conn_handler, userdata: *const u8) -> c_int;
  pub fn xmpp_disconnect(conn: *const xmpp_conn_t);
  pub fn xmpp_send(conn: *const xmpp_conn_t, stanza: *const xmpp_stanza_t);

  // context objects
  pub fn xmpp_get_default_logger(level: c_int) -> *mut xmpp_log_t;
  pub fn xmpp_ctx_new(mem: *const xmpp_mem_t, log: *const xmpp_log_t) -> *mut xmpp_ctx_t;
  pub fn xmpp_ctx_free(ctx: *const xmpp_ctx_t);

  // initialization, shutdown and versioning
  pub fn xmpp_initialize();
  pub fn xmpp_shutdown();
  pub fn xmpp_version_check(major: c_int, minor: c_int) -> c_int;

  // event loop
  pub fn xmpp_run_once(ctx: *mut xmpp_ctx_t, timeout: c_ulong);
  pub fn xmpp_run(ctx: *mut xmpp_ctx_t);
  pub fn xmpp_stop(ctx: *mut xmpp_ctx_t);

  // stanza and timed event handlers
  pub fn xmpp_timed_handler_delete(conn: *const xmpp_conn_t, handler: xmpp_timed_handler);
  pub fn xmpp_id_handler_delete(conn: *const xmpp_conn_t, handler: xmpp_handler, id: *const c_char);
  pub fn xmpp_handler_delete(conn: *const xmpp_conn_t, handler: xmpp_handler);
  pub fn xmpp_timed_handler_add(conn: *const xmpp_conn_t, handler: xmpp_timed_handler, period: c_ulong, userdata: *const c_void);
  pub fn xmpp_id_handler_add(conn: *const xmpp_conn_t, handler: xmpp_handler, id: *const c_char, userdata: *const c_void);
  pub fn xmpp_handler_add(conn: *const xmpp_conn_t, handler: xmpp_handler, ns: *const c_char, name: *const c_char, _type: *const c_char, userdata: *const c_void);

  // stanza creation and manipulation
  pub fn xmpp_stanza_new(ctx: *mut xmpp_ctx_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_clone(stanza: *const xmpp_stanza_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_copy(stanza: *const xmpp_stanza_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_release(stanza: *const xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_is_text(stanza: *const xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_is_tag(stanza: *const xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_to_text(stanza: *mut xmpp_stanza_t, buf: *const *const c_char, sizelen: *const size_t) -> c_int;
  pub fn xmpp_stanza_set_name(stanza: *mut xmpp_stanza_t, name: *const c_char) -> c_int;
  pub fn xmpp_stanza_get_name(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_attribute_count(stanza: *const xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_get_attributes(stanza: *const xmpp_stanza_t, attr: *const *const c_char, attrlen: c_int) -> c_int;
  pub fn xmpp_stanza_set_attribute(stanza: *const xmpp_stanza_t, key: *const c_char, value: *const c_char) -> c_int;
  pub fn xmpp_stanza_set_ns(stanza: *const xmpp_stanza_t, ns: *const c_char) -> c_int;
  pub fn xmpp_stanza_add_child(stanza: *mut xmpp_stanza_t, child: *mut xmpp_stanza_t) -> c_int;
  pub fn xmpp_stanza_set_text(stanza: *mut xmpp_stanza_t, text: *const c_char) -> c_int;
  pub fn xmpp_stanza_set_text_with_size(stanza: *mut xmpp_stanza_t, text: *const c_char, size: size_t) -> c_int;
  pub fn xmpp_stanza_get_id(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_ns(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_type(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_child_by_name(stanza: *const xmpp_stanza_t, name: *const c_char) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_get_child_by_ns(stanza: *const xmpp_stanza_t, ns: *const c_char) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_get_children(stanza: *const xmpp_stanza_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_get_next(stanza: *const xmpp_stanza_t) -> *mut xmpp_stanza_t;
  pub fn xmpp_stanza_get_text(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_get_text_ptr(stanza: *const xmpp_stanza_t) -> *mut c_char;
  pub fn xmpp_stanza_set_id(stanza: *const xmpp_stanza_t, id: *const c_char) -> c_int;
  pub fn xmpp_stanza_set_type(stanza: *const xmpp_stanza_t, _type: *const c_char) -> c_int;
  pub fn xmpp_stanza_get_attribute(stanza: *const xmpp_stanza_t, name: *const c_char) -> *mut c_char;
}

<|endoftext|>