<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.slice_from_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::Sync;
    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;

    unsafe impl Sync for *const 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 thread::Thread;

    #[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);

            Thread::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();
                Thread::yield_now();
                let mut v = [0u8; 1000];

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

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>std: Second pass stabilization of sync<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.slice_from_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, ATOMIC_BOOL_INIT, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = ATOMIC_BOOL_INIT;
        static GETRANDOM_AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        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::Sync;
    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;

    unsafe impl Sync for *const 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 thread::Thread;

    #[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);

            Thread::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();
                Thread::yield_now();
                let mut v = [0u8; 1000];

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

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


<commit_before>/// Implements all outgoing status packets

use std::io::Write;
use std::mem::transmute;

use super::super::super::deque_buffer::DequeBuffer;
use super::super::super::game_connection::GameConnection; //It's super super super effective!
use super::super::{ PacketHeader, ID_STATUS_STC_RESPONSE };

/// A packet sent from the server to
pub struct StatusResponsePacket;

impl StatusResponsePacket {

    /// Gets this StatusResponsePacket's ID
    pub fn get_id(&self) -> u32 {

        ID_STATUS_STC_RESPONSE

    }

    /// Gets the JSON response
    fn get_json_response(&self) -> String {
"{
    \"version\": {
        \"name\": \"1.8.8\",
        \"protocol\": 47
    },
    \"players\": {
        \"max\": 100,
        \"online\": 5
    },
    \"description\": {
        \"text\": \"Hello world\"
    }
}".to_string()
    }

    /// Creates a new Packet
    pub fn new() -> StatusResponsePacket {

        StatusResponsePacket

    }

    /// Encodes and sends this StatusResponsePacket
    pub fn send(&self, connection: &mut GameConnection) {
        info!("Sending a server status response packet!");

        let mut data_buffer = DequeBuffer::new();

        data_buffer.write_unsigned_varint_32(self.get_id());

        data_buffer.write_utf8_string(self.get_json_response());

        let mut length_buffer = DequeBuffer::with_capacity(data_buffer.remaining());

        length_buffer.write_unsigned_varint_32(data_buffer.remaining() as u32); //TODO: Try to get this as write_unsigned_varint_32_front

        let buffer = &(length_buffer.data.iter().chain(data_buffer.data.iter()).collect::<Vec<&u8>>())[..];

        let _buffer: &[u8] = unsafe { transmute(buffer) };

        info!("{} + {} = {}", length_buffer.remaining(), data_buffer.remaining(), _buffer.len());

        info!("Flush? {:?}", connection.stream.flush());

        let result = connection.stream.write(_buffer);

        if (result.is_ok()) {
            info!("Flush? {:?}", connection.stream.flush());
        }

        info!("Wrote a {:?}", result);

    }

}<commit_msg>SLP sends, but need to do some research because the read buffer is not expanding as it should. This might take a few days<commit_after>/// Implements all outgoing status packets

use std::io::Write;
use std::mem::transmute;

use super::super::super::deque_buffer::DequeBuffer;
use super::super::super::game_connection::GameConnection; //It's super super super effective!
use super::super::{ PacketHeader, ID_STATUS_STC_RESPONSE };

/// A packet sent from the server to
pub struct StatusResponsePacket;

impl StatusResponsePacket {

    /// Gets this StatusResponsePacket's ID
    pub fn get_id(&self) -> u32 {

        ID_STATUS_STC_RESPONSE

    }

    /// Gets the JSON response
    fn get_json_response(&self) -> String {
"{
    \"version\": {
        \"name\": \"1.8.8\",
        \"protocol\": 47
    },
    \"players\": {
        \"max\": 100,
        \"online\": 5
    },
    \"description\": {
        \"text\": \"Hello world\"
    }
}".to_string()
    }

    /// Creates a new Packet
    pub fn new() -> StatusResponsePacket {

        StatusResponsePacket

    }

    /// Encodes and sends this StatusResponsePacket
    pub fn send(&self, connection: &mut GameConnection) {
        info!("Sending a server status response packet!");

        let mut data_buffer = DequeBuffer::new();

        data_buffer.write_unsigned_varint_32(self.get_id());

        data_buffer.write_utf8_string(self.get_json_response());

        let mut length_buffer = DequeBuffer::new();

        length_buffer.write_unsigned_varint_32(data_buffer.remaining() as u32); //TODO: Try to get this as write_unsigned_varint_32_front

        let buffer = &(length_buffer.data.iter().chain(data_buffer.data.iter()).collect::<Vec<&u8>>())[..];

        debug!("Oh {:?}!", buffer);

        let _buffer: &[u8] = unsafe { transmute(buffer) };

        info!("{} + {} = {}", length_buffer.remaining(), data_buffer.remaining(), _buffer.len());

        info!("Flush? {:?}", connection.stream.flush());

        let result = connection.stream.write(_buffer);

        if (result.is_ok()) {
            info!("Flush? {:?}", connection.stream.flush());
        }

        info!("Wrote a {:?}", result);

    }

}<|endoftext|>


<commit_before>/*
 * This file is part of Twig (ported to Rust).
 *
 * For the copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * The patterns used by the lexer to tokenize the templates.
 *
 * Written as regular expressions (perl-style).
 *
 * @author Colin Kiegel <kiegel@gmx.de>
 */

use regex::Regex;
use regex::Error as regexError;

use environment::Environment;
use lexer::options::Options;

use std::rc::Rc;

//const REGEX_NAME            : &'static str = r"/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A";
//const REGEX_NUMBER          : &'static str = r"/[0-9]+(?:\.[0-9]+)?/A";
//const REGEX_STRING          : &'static str = r"/\"([^#\"\\]*(?:\\.[^#\"\\]*)*)\"|\'([^\'\\]*(?:\\.[^\'\\]*)*)\'/As"; // TODO check if it should be ' instead of \'
//const REGEX_DQ_STRING_DELIM : &'static str = r"/\"/A";
//const REGEX_DQ_STRING_PART  : &'static str = r"/[^#\"\\]*(?:(?:\\.|#(?!\\{))[^#\"\\]*)*/As";

#[derive(Debug)]
#[derive(PartialEq)]
pub struct RegexPatterns {
    var: Regex,
    block: Regex,
    raw_data: Regex,
    operator: Regex,
    comment: Regex,
    block_raw: Regex,
    block_line: Regex,
    tokens_start: Regex,
    interpolation_start: Regex,
    interpolation_end: Regex,
}

macro_rules! quote {
    ($string:expr) => ({
        use regex;
        regex::quote(&$string)
    });
}

macro_rules! regex_concat {
    ($modifier:expr, $pattern:expr) => ({
        //format!("/{}/{}", $pattern, $modifier)
        &("/".to_string() + &$pattern + "/" + &$modifier)
    });
}

macro_rules! try_new_regex {
    ($regex:expr) => ({
        try!(Regex::new(&$regex))
    });
}

#[allow(dead_code)]
#[allow(unused_variables)]
impl RegexPatterns {
    pub fn new(env: Rc<Environment>, opt: Rc<Options>) -> Result<RegexPatterns, regexError> {
        let ws = quote!(opt.whitespace_trim);
        let b0 = quote!(opt.tag_block.0);
        let b1 = quote!(opt.tag_block.1);
        let v0 = quote!(opt.tag_variable.0);
        let v1 = quote!(opt.tag_variable.1);
        let c0 = quote!(opt.tag_comment.0);
        let c1 = quote!(opt.tag_comment.1);
        let i0 = quote!(opt.interpolation.0);
        let i1 = quote!(opt.interpolation.1);

        Ok(RegexPatterns {
            var: try_new_regex!(format!(r"/\s*{ws}{v1}\s*|\s*{v1}/A",
                        ws = ws,
                        v1 = v1)),
                // PHP: '/\s*'.$whitespace_trim.$tag_variable[1].'\s*|\s*'.$tag_variable[1].'/A'

            block: try_new_regex!(format!(r"/\s*(?:{ws}{b1}\s*|\s*{b1})\n?/A",
                        ws = ws,
                        b1 = b1)),
                // PHP: '/\s*(?:'.$whitespace_trim.$tag_block[1].'\s*|\s*'.$tag_block[1].')\n?/A'

            raw_data: try_new_regex!(format!(r"/({b0}{ws}|{b0})\s*(?:end%s)\s*(?:{ws}{b1}\s*|\s*{b1})/s",
                        ws = ws,
                        b0 = b0,
                        b1 = b1)),
                // PHP: '/('.$tag_block[0].$whitespace_trim.'|'.$tag_block[0].')\s*(?:end%s)\s*(?:'.$whitespace_trim.$tag_block[1].'\s*|\s*'.$tag_block[1].')/s'

            operator: try_new_regex!(&RegexPatterns::get_operator_regex(env)),
                // PHP: $this.getOperatorRegex(),

            comment: try_new_regex!(format!(r"/(?:{ws}{c1}\s*|{c1})\n?/s",
                        ws = ws,
                        c1 = c1)),
                // PHP: '/(?:'.$whitespace_trim.$tag_comment[1].'\s*|'.$tag_comment[1].')\n?/s'

            block_raw: try_new_regex!(format!(r"/\s*(raw|verbatim)\s*(?:{ws}{b1}\s*|\s*{b1})/As",
                        ws = ws,
                        b1 = b1)),
                // PHP: '/\s*(raw|verbatim)\s*(?:'.$whitespace_trim.$tag_block[1].'\s*|\s*'.$tag_block[1].')/As'

            block_line: try_new_regex!(format!(r"/\s*line\s+(\d+)\s*{b1}/As",
                        b1 = b0)),
                // PHP: '/\s*line\s+(\d+)\s*'.$tag_block[1].'/As'

            tokens_start: try_new_regex!(format!(r"/({v0}|{b0}|{c0})({ws})?/s",
                        ws = ws,
                        b0 = b0,
                        v0 = v0,
                        c0 = c0)),
                // PHP: '/('.$tag_variable[0].'|'.$tag_block[0].'|'.$tag_comment[0].')('.$whitespace_trim.')?/s'

            interpolation_start: try_new_regex!(format!(r"/{i0}\s*/A",
                        i0 = i0)),
                // PHP: '/'.$interpolation[0].'\s*/A'

            interpolation_end: try_new_regex!(format!(r"/\s*{i1}/A",
                        i1 = i1)),
                // PHP: '/\s*'.$interpolation[1].'/A'
        })
    }

    fn get_operator_regex(env: Rc<Environment>) -> String {

        //$operators = array_merge(
            //array('='),
            // TODO array_keys($this->env->getUnaryOperators()),
            // TODO array_keys($this->env->getBinaryOperators())
        //);

        //$operators = array_combine($operators, array_map('strlen', $operators));
        //arsort($operators);

        //$regex = array();
        //foreach ($operators as $operator => $length) {
            // an operator that ends with a character must be followed by
            // a whitespace or a parenthesis
            //if (ctype_alpha($operator[$length - 1])) {
            //    $r = preg_quote($operator, '/').'(?=[\s()])';
            //} else {
            //    $r = preg_quote($operator, '/');
            //}

            // an operator with a space can be any amount of whitespaces
            //$r = preg_replace('/\s+/', '\s+', $r);

            //$regex[] = $r;
        //}

        //return '/'.implode('|', $regex).'/A';
        "".to_string()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use environment::Environment;
    use lexer::options::Options;
    use std::rc::Rc;
    use regex::Regex;

    #[test]
    pub fn from_default_options() {
        let env = Rc::new(Environment{..Default::default()});
        let opt = Rc::new(Options{..Default::default()});
        let rp_o = RegexPatterns::new(env, opt).unwrap();
        let rp_x = RegexPatterns {
            var: Regex::new(r"/\s*-\}\}\s*|\s*\}\}/A").unwrap(),
            block: Regex::new(r"/\s*(?:-%\}\s*|\s*%\})\n?/A").unwrap(),
            raw_data: Regex::new(r"/(\{%-|\{%)\s*(?:end%s)\s*(?:-%\}\s*|\s*%\})/s").unwrap(),
            operator: Regex::new(r"").unwrap(),
            comment: Regex::new(r"/(?:-\#\}\s*|\#\})\n?/s").unwrap(),
            block_raw: Regex::new(r"/\s*(raw|verbatim)\s*(?:-%\}\s*|\s*%\})/As").unwrap(),
            block_line: Regex::new(r"/\s*line\s+(\d+)\s*\{%/As").unwrap(),
            tokens_start: Regex::new(r"/(\{\{|\{%|\{\#)(-)?/s").unwrap(),
            interpolation_start: Regex::new(r"/\#\{\s*/A").unwrap(),
            interpolation_end: Regex::new(r"/\s*\}/A").unwrap(),
        };

        println!(".var");
        assert_eq!(rp_o.var, rp_x.var);
        println!(".block");
        assert_eq!(rp_o.block, rp_x.block);
        println!(".raw_data");
        assert_eq!(rp_o.raw_data, rp_x.raw_data);
        println!(".operator");
        assert_eq!(rp_o.operator, rp_x.operator);
        println!(".comment");
        assert_eq!(rp_o.comment, rp_x.comment);
        println!(".block_raw");
        assert_eq!(rp_o.block_raw, rp_x.block_raw);
        println!(".block_line");
        assert_eq!(rp_o.block_line, rp_x.block_line);
        println!(".tokens_start");
        assert_eq!(rp_o.tokens_start, rp_x.tokens_start);
        println!(".interpolation_start");
        assert_eq!(rp_o.interpolation_start, rp_x.interpolation_start);
        println!(".interpolation_end");
        assert_eq!(rp_o.interpolation_end, rp_x.interpolation_end);
    }
}
<commit_msg>fixed lexer regex patterns<commit_after>/*
 * This file is part of Twig (ported to Rust).
 *
 * For the copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/**
 * The patterns used by the lexer to tokenize the templates.
 *
 * Written as regular expressions (perl-style).
 *
 * @author Colin Kiegel <kiegel@gmx.de>
 */

use regex::Regex;
use regex::Error as regexError;

use environment::Environment;
use lexer::options::Options;

use std::rc::Rc;

//const REGEX_NAME            : &'static str = r"\A[a-zA-Z_\x7f-\xff][a-zA-Z\d_\x7f-\xff]*";
//const REGEX_NUMBER          : &'static str = r"\A\d+(?:\.\d+)?";
//const REGEX_STRING          : &'static str = r"\A\"([^#\"\\]*(?:\\[.\n][^#\"\\]*)*)\"|'([^'\\]*(?:\\[.\n][^'\\]*)*)'";
//const REGEX_DQ_STRING_DELIM : &'static str = r"\A\"";
//const REGEX_DQ_STRING_PART  : &'static str = r"\A[^#\"\\]*(?:(?:\\[.\n]|#(?!\\{))[^#\"\\]*)*";

#[derive(Debug)]
#[derive(PartialEq)]
pub struct RegexPatterns {
    pub var: Regex,
    pub block: Regex,
    pub raw_data: Regex,
    pub operator: Regex,
    pub comment: Regex,
    pub block_raw: Regex,
    pub block_line: Regex,
    pub tokens_start: Regex,
    pub interpolation_start: Regex,
    pub interpolation_end: Regex,
}

macro_rules! quote {
    ($string:expr) => ({
        use regex;
        regex::quote(&$string)
    });
}

macro_rules! regex_concat {
    ($modifier:expr, $pattern:expr) => ({
        //format!("/{}/{}", $pattern, $modifier)
        &("/".to_string() + &$pattern + "/" + &$modifier)
    });
}

macro_rules! try_new_regex {
    ($regex:expr) => ({
        try!(Regex::new(&$regex))
    });
}

#[allow(dead_code)]
#[allow(unused_variables)]
impl RegexPatterns {
    pub fn new(env: Rc<Environment>, opt: Rc<Options>) -> Result<RegexPatterns, regexError> {
        let ws = quote!(opt.whitespace_trim);
        let b0 = quote!(opt.tag_block.0);
        let b1 = quote!(opt.tag_block.1);
        let v0 = quote!(opt.tag_variable.0);
        let v1 = quote!(opt.tag_variable.1);
        let c0 = quote!(opt.tag_comment.0);
        let c1 = quote!(opt.tag_comment.1);
        let i0 = quote!(opt.interpolation.0);
        let i1 = quote!(opt.interpolation.1);

        Ok(RegexPatterns {
            var: try_new_regex!(format!(
                r"\A\s*{ws}{v1}\s*|\s*{v1}", ws = ws, v1 = v1)),
                // orig: '/\s*'.$whitespace_trim.$tag_variable[1].'\s*|\s*'.$tag_variable[1].'/A'

            block: try_new_regex!(format!(
                r"\A\s*(?:{ws}{b1}\s*|\s*{b1})\n?", ws = ws, b1 = b1)),
                // orig: '/\s*(?:'.$whitespace_trim.$tag_block[1].'\s*|\s*'.$tag_block[1].')\n?/A'

            raw_data: try_new_regex!(format!(
                r"({b0}{ws}|{b0})\s*(?:end%s)\s*(?:{ws}{b1}\s*|\s*{b1})", ws = ws, b0 = b0, b1 = b1)),
                // orig: '/('.$tag_block[0].$whitespace_trim.'|'.$tag_block[0].')\s*(?:end%s)\s*(?:'.$whitespace_trim.$tag_block[1].'\s*|\s*'.$tag_block[1].')/s'

            operator: try_new_regex!(&RegexPatterns::get_operator_regex(env)),

            comment: try_new_regex!(format!(
                r"(?:{ws}{c1}\s*|{c1})\n?", ws = ws, c1 = c1)),
                // orig: '/(?:'.$whitespace_trim.$tag_comment[1].'\s*|'.$tag_comment[1].')\n?/s'

            block_raw: try_new_regex!(format!(
                r"\A\s*(raw|verbatim)\s*(?:{ws}{b1}\s*|\s*{b1})", ws = ws, b1 = b1)),
                // orig: '/\s*(raw|verbatim)\s*(?:'.$whitespace_trim.$tag_block[1].'\s*|\s*'.$tag_block[1].')/As'

            block_line: try_new_regex!(format!(
                r"\A\s*line\s+(\d+)\s*{b1}", b1 = b1)),
                // orig: '/\s*line\s+(\d+)\s*'.$tag_block[1].'/As'

            tokens_start: try_new_regex!(format!(
                r"({v0}|{b0}|{c0})({ws})?", ws = ws, b0 = b0, v0 = v0, c0 = c0)),
                // orig: '/('.$tag_variable[0].'|'.$tag_block[0].'|'.$tag_comment[0].')('.$whitespace_trim.')?/s'

            interpolation_start: try_new_regex!(format!(
                r"\A{i0}\s*", i0 = i0)),
                // orig: '/'.$interpolation[0].'\s*/A'

            interpolation_end: try_new_regex!(format!(
                r"\A\s*{i1}", i1 = i1)),
                // orig: '/\s*'.$interpolation[1].'/A'
        })
    }

    fn get_operator_regex(env: Rc<Environment>) -> String {

        //$operators = array_merge(
            //array('='),
            // TODO array_keys($this->env->getUnaryOperators()),
            // TODO array_keys($this->env->getBinaryOperators())
        //);

        //$operators = array_combine($operators, array_map('strlen', $operators));
        //arsort($operators);

        //$regex = array();
        //foreach ($operators as $operator => $length) {
            // an operator that ends with a character must be followed by
            // a whitespace or a parenthesis
            //if (ctype_alpha($operator[$length - 1])) {
            //    $r = preg_quote($operator, '/').'(?=[\s()])';
            //} else {
            //    $r = preg_quote($operator, '/');
            //}

            // an operator with a space can be any amount of whitespaces
            //$r = preg_replace('/\s+/', '\s+', $r);

            //$regex[] = $r;
        //}

        //return '/'.implode('|', $regex).'/A';
        "".to_string()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use environment::Environment;
    use lexer::options::Options;
    use std::rc::Rc;
    use regex::Regex;

    #[test]
    pub fn from_default_options() {
        let env = Rc::new(Environment{..Default::default()});
        let opt = Rc::new(Options{..Default::default()});
        let rp_o = RegexPatterns::new(env, opt).unwrap();
        let rp_x = RegexPatterns {
            var: Regex::new(r"\A\s*-\}\}\s*|\s*\}\}").unwrap(),
            block: Regex::new(r"\A\s*(?:-%\}\s*|\s*%\})\n?").unwrap(),
            raw_data: Regex::new(r"(\{%-|\{%)\s*(?:end%s)\s*(?:-%\}\s*|\s*%\})").unwrap(),
            operator: Regex::new(r"").unwrap(),
            comment: Regex::new(r"(?:-\#\}\s*|\#\})\n?").unwrap(),
            block_raw: Regex::new(r"\A\s*(raw|verbatim)\s*(?:-%\}\s*|\s*%\})").unwrap(),
            block_line: Regex::new(r"\A\s*line\s+(\d+)\s*%\}").unwrap(),
            tokens_start: Regex::new(r"(\{\{|\{%|\{\#)(-)?").unwrap(),
            interpolation_start: Regex::new(r"\A\#\{\s*").unwrap(),
            interpolation_end: Regex::new(r"\A\s*\}").unwrap(),
        };

        println!(".var");
        assert_eq!(rp_o.var, rp_x.var);
        println!(".block");
        assert_eq!(rp_o.block, rp_x.block);
        println!(".raw_data");
        assert_eq!(rp_o.raw_data, rp_x.raw_data);
        println!(".operator");
        assert_eq!(rp_o.operator, rp_x.operator);
        println!(".comment");
        assert_eq!(rp_o.comment, rp_x.comment);
        println!(".block_raw");
        assert_eq!(rp_o.block_raw, rp_x.block_raw);
        println!(".block_line");
        assert_eq!(rp_o.block_line, rp_x.block_line);
        println!(".tokens_start");
        assert_eq!(rp_o.tokens_start, rp_x.tokens_start);
        println!(".interpolation_start");
        assert_eq!(rp_o.interpolation_start, rp_x.interpolation_start);
        println!(".interpolation_end");
        assert_eq!(rp_o.interpolation_end, rp_x.interpolation_end);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cmp::{min, max};
use std::num::SignedInt;

#[derive(PartialEq, Eq, Show, Copy, Clone)]
pub struct Interval {
  lb: int,
  ub: int
}

impl Interval
{
  pub fn new(lb: int, ub: int) -> Interval {
    Interval { lb: lb, ub: ub }
  }

  pub fn empty() -> Interval {
    Interval::new(1, 0)
  }

  pub fn singleton(x: int) -> Interval {
    Interval::new(x, x)
  }

  pub fn is_singleton(self) -> bool {
    self.lb == self.ub
  }

  pub fn size(self) -> uint {
    if self.is_empty() { 0 }
    else { (self.ub - self.lb + 1).abs() as uint }
  }

  pub fn is_empty(self) -> bool {
    self.lb > self.ub
  }

  pub fn has_member(self, x: int) -> bool {
    x >= self.lb && x <= self.ub
  }

  pub fn is_subset_of(self, i: Interval) -> bool {
    if self.is_empty() { true }
    else {
      self.lb >= i.lb && self.ub <= i.ub
    }
  }

  pub fn intersection(self, i: Interval) -> Interval {
    Interval::new(
      max(self.lb, i.lb),
      min(self.ub, i.ub)
    )
  }

  pub fn hull(self, i: Interval) -> Interval {
    if self.is_empty() { i }
    else if i.is_empty() { self }
    else {
      Interval::new(
        min(self.lb, i.lb),
        max(self.ub, i.ub)
      )
    }
  }

  fn disjoint(self, i: Interval) -> bool {
    self.lb > i.ub || i.lb > self.ub
  }
}

pub trait ToInterval {
  fn to_interval(self) -> Interval;
}

impl ToInterval for Interval {
  fn to_interval(self) -> Interval { self }
}

impl ToInterval for (int, int) {
  fn to_interval(self) -> Interval {
    let (a, b) = self;
    Interval::new(a, b)
  }
}

impl ToInterval for () {
  fn to_interval(self) -> Interval {
    Interval::empty()
  }
}

impl ToInterval for int {
  fn to_interval(self) -> Interval {
    Interval::singleton(self)
  }
}

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

  const empty: Interval = Interval {lb: 1, ub: 0};
  const invalid: Interval = Interval {lb: 10, ub: -10};
  const zero: Interval = Interval {lb: 0, ub: 0};
  const one: Interval = Interval {lb: 1, ub: 1};

  const i1_2: Interval = Interval {lb: 1, ub: 2};
  const i0_10: Interval = Interval {lb: 0, ub: 10};
  const i0_15: Interval = Interval {lb: 0, ub: 15};
  const im5_10: Interval = Interval {lb: -5, ub: 10};
  const i5_10: Interval = Interval {lb: 5, ub: 10};
  const i0_5: Interval = Interval {lb: 0, ub: 5};
  const i0_4: Interval = Interval {lb: 0, ub: 4};
  const im5_5: Interval = Interval {lb: -5, ub: 5};
  const i20_30: Interval = Interval {lb: 20, ub: 30};
  const im30_m20: Interval = Interval {lb: -30, ub: -20};

  #[test]
  fn to_interval_id_test() {
    let id = i1_2.clone().to_interval();
    assert!(i1_2 == id);
    assert!(i1_2 == Interval::new(1, 2));
  }

  #[test]
  fn size_test() {
    assert!(zero.size() == 1);
    assert!(one.size() == 1);
    assert!(empty.size() == 0);
    assert!(invalid.size() == 0);

    assert!(i1_2.size() == 2);
    assert!(i0_10.size() == 11);
    assert!(im30_m20.size() == 11);
  }

  #[test]
  fn member_test() {
    assert!(i1_2.has_member(1));
    assert!(i1_2.has_member(2));
    assert!(!i1_2.has_member(0));
    assert!(!i1_2.has_member(3));

    assert!(zero.has_member(0));
    assert!(!zero.has_member(1));

    assert!(!empty.has_member(0));
    assert!(!empty.has_member(1));
    assert!(!empty.has_member(5));
    assert!(!empty.has_member(-5));

    assert!(!invalid.has_member(0));
    assert!(!invalid.has_member(-11));
    assert!(!invalid.has_member(11));
  }

  #[test]
  fn is_subset_of_test() {
    let cases = vec![
      (zero, zero,          true),
      (i1_2, i1_2,          true),
      (empty, empty,        true),
      (invalid, invalid,    true)
    ];

    // For each cases (x, y, res)
    // * x and y are the values
    // * res is a tuple (r, sym) where
    //    * r is true if x is a subset of y
    //    * sym is true if y is a subset of x
    let sym_cases = vec![
      // ||
      // |-|
      (empty, zero,         (true, false)),
      (invalid, zero,       (true, false)),
      (empty, invalid,      (true, true)),
      // ||
      //|--|
      (empty, i1_2,         (true, false)),
      (invalid, i1_2,       (true, false)),
      //  |--|
      // |----|
      (i1_2, i0_10,         (true, false)),
      // |--|
      //     |--|
      (i0_4, i5_10,         (false, false)),
      // |--|
      //    |--|
      (i0_5, i5_10,         (false, false)),
      // |---|
      //   |---|
      (im5_5, i0_10,        (false, false)),
      // |--|
      //         |--|
      (i0_10, i20_30,       (false, false)),
      // |--|
      // |---|
      (i0_10, i0_15,        (true, false)),
      // |---|
      //  |--|
      (im5_10, i0_10,       (false, true))
    ];

    for (x,y,r) in cases.into_iter() {
      assert!(x.is_subset_of(y) == r, "{} is subset of {} is not equal to {}", x, y, r);
    }

    for (x,y,(r1,r2)) in sym_cases.into_iter() {
      assert!(x.is_subset_of(y) == r1, "{} is subset of {} is not equal to {}", x, y, r1);
      assert!(y.is_subset_of(x) == r2, "{} is subset of {} is not equal to {}", y, x, r2);
    }
  }
}<commit_msg>Fix equality that cannot be derived and add tests.<commit_after>// Copyright 2015 Pierre Talbot (IRCAM)

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::cmp::{min, max};
use std::num::SignedInt;

#[derive(Eq, Show, Copy, Clone)]
pub struct Interval {
  lb: int,
  ub: int
}

impl PartialEq<Interval> for Interval
{
  fn eq(&self, other: &Interval) -> bool {
    if self.is_empty() && other.is_empty() { true }
    else { self.lb == other.lb && self.ub == other.ub }
  }
}

impl Interval
{
  pub fn new(lb: int, ub: int) -> Interval {
    Interval { lb: lb, ub: ub }
  }

  pub fn empty() -> Interval {
    Interval::new(1, 0)
  }

  pub fn singleton(x: int) -> Interval {
    Interval::new(x, x)
  }

  pub fn is_singleton(self) -> bool {
    self.lb == self.ub
  }

  pub fn size(self) -> uint {
    if self.is_empty() { 0 }
    else { (self.ub - self.lb + 1).abs() as uint }
  }

  pub fn is_empty(self) -> bool {
    self.lb > self.ub
  }

  pub fn has_member(self, x: int) -> bool {
    x >= self.lb && x <= self.ub
  }

  pub fn is_subset_of(self, i: Interval) -> bool {
    if self.is_empty() { true }
    else {
      self.lb >= i.lb && self.ub <= i.ub
    }
  }

  pub fn intersection(self, i: Interval) -> Interval {
    Interval::new(
      max(self.lb, i.lb),
      min(self.ub, i.ub)
    )
  }

  pub fn hull(self, i: Interval) -> Interval {
    if self.is_empty() { i }
    else if i.is_empty() { self }
    else {
      Interval::new(
        min(self.lb, i.lb),
        max(self.ub, i.ub)
      )
    }
  }

  fn disjoint(self, i: Interval) -> bool {
    self.lb > i.ub || i.lb > self.ub
  }
}

pub trait ToInterval {
  fn to_interval(self) -> Interval;
}

impl ToInterval for Interval {
  fn to_interval(self) -> Interval { self }
}

impl ToInterval for (int, int) {
  fn to_interval(self) -> Interval {
    let (a, b) = self;
    Interval::new(a, b)
  }
}

impl ToInterval for () {
  fn to_interval(self) -> Interval {
    Interval::empty()
  }
}

impl ToInterval for int {
  fn to_interval(self) -> Interval {
    Interval::singleton(self)
  }
}

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

  const empty: Interval = Interval {lb: 1, ub: 0};
  const invalid: Interval = Interval {lb: 10, ub: -10};
  const zero: Interval = Interval {lb: 0, ub: 0};
  const one: Interval = Interval {lb: 1, ub: 1};

  const i1_2: Interval = Interval {lb: 1, ub: 2};
  const i0_10: Interval = Interval {lb: 0, ub: 10};
  const i0_15: Interval = Interval {lb: 0, ub: 15};
  const im5_10: Interval = Interval {lb: -5, ub: 10};
  const i5_10: Interval = Interval {lb: 5, ub: 10};
  const i0_5: Interval = Interval {lb: 0, ub: 5};
  const i0_4: Interval = Interval {lb: 0, ub: 4};
  const im5_5: Interval = Interval {lb: -5, ub: 5};
  const i20_30: Interval = Interval {lb: 20, ub: 30};
  const im30_m20: Interval = Interval {lb: -30, ub: -20};

  #[test]
  fn to_interval_id_test() {
    let id = i1_2.clone().to_interval();
    assert!(i1_2 == id);
    assert!(i1_2 == Interval::new(1, 2));
  }

  #[test]
  fn equality_test() {
    assert!(empty == empty);
    assert!(empty == invalid);
    assert!(invalid == empty);
    assert!(i1_2 == i1_2);
  }

  #[test]
  fn size_test() {
    assert!(zero.size() == 1);
    assert!(one.size() == 1);
    assert!(empty.size() == 0);
    assert!(invalid.size() == 0);

    assert!(i1_2.size() == 2);
    assert!(i0_10.size() == 11);
    assert!(im30_m20.size() == 11);
  }

  #[test]
  fn member_test() {
    assert!(i1_2.has_member(1));
    assert!(i1_2.has_member(2));
    assert!(!i1_2.has_member(0));
    assert!(!i1_2.has_member(3));

    assert!(zero.has_member(0));
    assert!(!zero.has_member(1));

    assert!(!empty.has_member(0));
    assert!(!empty.has_member(1));
    assert!(!empty.has_member(5));
    assert!(!empty.has_member(-5));

    assert!(!invalid.has_member(0));
    assert!(!invalid.has_member(-11));
    assert!(!invalid.has_member(11));
  }

  #[test]
  fn is_subset_of_test() {
    let cases = vec![
      (zero, zero,          true),
      (i1_2, i1_2,          true),
      (empty, empty,        true),
      (invalid, invalid,    true)
    ];

    // For each cases (x, y, res)
    // * x and y are the values
    // * res is a tuple (r, sym) where
    //    * r is true if x is a subset of y
    //    * sym is true if y is a subset of x
    let sym_cases = vec![
      // ||
      // |-|
      (empty, zero,         (true, false)),
      (invalid, zero,       (true, false)),
      (empty, invalid,      (true, true)),
      // ||
      //|--|
      (empty, i1_2,         (true, false)),
      (invalid, i1_2,       (true, false)),
      //  |--|
      // |----|
      (i1_2, i0_10,         (true, false)),
      // |--|
      //     |--|
      (i0_4, i5_10,         (false, false)),
      // |--|
      //    |--|
      (i0_5, i5_10,         (false, false)),
      // |---|
      //   |---|
      (im5_5, i0_10,        (false, false)),
      // |--|
      //         |--|
      (i0_10, i20_30,       (false, false)),
      // |--|
      // |---|
      (i0_10, i0_15,        (true, false)),
      // |---|
      //  |--|
      (im5_10, i0_10,       (false, true))
    ];

    for (x,y,r) in cases.into_iter() {
      assert!(x.is_subset_of(y) == r, "{} is subset of {} is not equal to {}", x, y, r);
    }

    for (x,y,(r1,r2)) in sym_cases.into_iter() {
      assert!(x.is_subset_of(y) == r1, "{} is subset of {} is not equal to {}", x, y, r1);
      assert!(y.is_subset_of(x) == r2, "{} is subset of {} is not equal to {}", y, x, r2);
    }
  }
}<|endoftext|>


<commit_before>use crate::exceptions::{CalculateError, IOError};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use std::fs;
use std::fs::DirEntry;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Measurement {
    pub command: String,
    pub mean: f64,
    pub stddev: f64,
    pub median: f64,
    pub user: f64,
    pub system: f64,
    pub min: f64,
    pub max: f64,
    pub times: Vec<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Measurements {
    pub results: Vec<Measurement>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Data {
    pub threshold: f64,
    pub difference: f64,
    pub baseline: f64,
    pub dev: f64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Calculation {
    pub metric: String,
    pub regression: bool,
    pub data: Data,
}

#[derive(Debug, Clone, PartialEq)]
pub struct MeasurementGroup {
    pub version: String,
    pub run: String,
    pub measurement: Measurement,
}

fn calculate(metric: &str, dev: &Measurement, baseline: &Measurement) -> Vec<Calculation> {
    let median_threshold = 1.05; // 5% regression threshold
    let median_difference = dev.median / baseline.median;

    let stddev_threshold = 1.05; // 5% regression threshold
    let stddev_difference = dev.stddev / baseline.stddev;

    vec![
        Calculation {
            metric: ["median", metric].join("_"),
            regression: median_difference > median_threshold,
            data: Data {
                threshold: median_threshold,
                difference: median_difference,
                baseline: baseline.median,
                dev: dev.median,
            }
        },
        Calculation {
            metric: ["stddev", metric].join("_"),
            regression: stddev_difference > stddev_threshold,
            data: Data {
                threshold: stddev_threshold,
                difference: stddev_difference,
                baseline: baseline.stddev,
                dev: dev.stddev,
            }
        },
    ]
}

// given a directory, read all files in the directory and return each
// filename with the deserialized json contents of that file
fn measurements_from_files(
    results_directory: &Path,
) -> Result<Vec<(PathBuf, Measurements)>, CalculateError> {
    fs::read_dir(results_directory)
        .or_else(|e| Err(IOError::ReadErr(results_directory.to_path_buf(), Some(e))))
        .or_else(|e| Err(CalculateError::CalculateIOError(e)))?
        .into_iter()
        .map(|entry| {
            let ent: DirEntry = entry.or_else(|e| Err(IOError::ReadErr(results_directory.to_path_buf(), Some(e))))
                .or_else(|e| Err(CalculateError::CalculateIOError(e)))?;

            Ok(ent.path())
        })
        .collect::<Result<Vec<PathBuf>, CalculateError>>()?
        .iter()
        .filter(|path| {
            path
                .extension()
                .and_then(|ext| ext.to_str())
                .map_or(false, |ext| ext.ends_with("json"))
        })
        .map(|path| {
            fs::read_to_string(path)
                .or_else(|e| Err(IOError::BadFileContentsErr(path.clone(), Some(e))))
                .or_else(|e| Err(CalculateError::CalculateIOError(e)))
                .and_then(|contents| {
                    serde_json::from_str::<Measurements>(&contents)
                        .or_else(|e| Err(CalculateError::BadJSONErr(path.clone(), Some(e))))
                })
                .map(|m| (path.clone(), m))
        })
        .collect()
}

// given a list of filename-measurement pairs, detect any regressions by grouping
// measurements together by filename
fn calculate_regressions(
    measurements: &[(PathBuf, Measurement)],
) -> Result<Vec<Calculation>, CalculateError> {
    let mut measurement_groups: Vec<MeasurementGroup> = measurements
        .iter()
        .map(|(p, m)| {
            p.file_name()
                .ok_or_else(|| IOError::MissingFilenameErr(p.to_path_buf()))
                .and_then(|name| {
                    name.to_str()
                        .ok_or_else(|| IOError::FilenameNotUnicodeErr(p.to_path_buf()))
                })
                .map(|name| {
                    let parts: Vec<&str> = name.split("_").collect();
                    MeasurementGroup {
                        version: parts[0].to_owned(),
                        run: parts[1..].join("_"),
                        measurement: m.clone(),
                    }
                })
        })
        .collect::<Result<Vec<MeasurementGroup>, IOError>>()
        .or_else(|e| Err(CalculateError::CalculateIOError(e)))?;

    measurement_groups.sort_by(|x, y| (&x.run, &x.version).cmp(&(&y.run, &y.version)));

    // locking up mutation
    let sorted_measurement_groups = measurement_groups;

    let calculations: Vec<Calculation> = sorted_measurement_groups
        .iter()
        .group_by(|x| x.run.clone())
        .into_iter()
        .map(|(_, g)| {
            let mut groups: Vec<&MeasurementGroup> = g.collect();
            groups.sort_by(|x, y| x.version.cmp(&y.version));

            match groups.len() {
                2 => {
                    let dev = &groups[1];
                    let baseline = &groups[0];

                    if dev.version == "dev" && baseline.version == "baseline" {
                        Ok(calculate(&dev.run, &dev.measurement, &baseline.measurement))
                    } else {
                        Err(CalculateError::BadBranchNameErr(baseline.version.clone(), dev.version.clone()))
                    }
                },
                i => {
                    let gs: Vec<MeasurementGroup> = groups.into_iter().map(|x| x.clone()).collect();
                    Err(CalculateError::BadGroupSizeErr(i, gs))
                },
            }
        })
        .collect::<Result<Vec<Vec<Calculation>>, CalculateError>>()?
        .concat();

    Ok(calculations)
}

pub fn regressions(results_directory: &PathBuf) -> Result<Vec<Calculation>, CalculateError> {
    measurements_from_files(Path::new(&results_directory)).and_then(|v| match v[..] {
        // exit early with an Err if there are no results to process
        [] => {
            Err(CalculateError::NoResultsErr(results_directory.clone()))
        },

        _ => {
            // we expect two runs for each project-metric pairing: one for each branch, baseline
            // and dev. An odd result count is unexpected.
            if v.len() % 2 == 1 {
                Err(CalculateError::OddResultsCountErr(v.len(), results_directory.clone()))
            } else {
                // otherwise, we can do our comparisons
                let measurements = v
                    .into_iter()
                    // the way we're running these, the files will each contain exactly one measurement, hence `results[0]`
                    .map(|(p, ms)| (p, ms.results[0].clone()))
                    .collect::<Vec<(PathBuf, Measurement)>>();

                calculate_regressions(&measurements)
            }
        },
    })
}
<commit_msg>more reference improvements<commit_after>use crate::exceptions::{CalculateError, IOError};
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use std::fs;
use std::fs::DirEntry;

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Measurement {
    pub command: String,
    pub mean: f64,
    pub stddev: f64,
    pub median: f64,
    pub user: f64,
    pub system: f64,
    pub min: f64,
    pub max: f64,
    pub times: Vec<f64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct Measurements {
    pub results: Vec<Measurement>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Data {
    pub threshold: f64,
    pub difference: f64,
    pub baseline: f64,
    pub dev: f64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Calculation {
    pub metric: String,
    pub regression: bool,
    pub data: Data,
}

#[derive(Debug, Clone, PartialEq)]
pub struct MeasurementGroup {
    pub version: String,
    pub run: String,
    pub measurement: Measurement,
}

fn calculate(metric: &str, dev: &Measurement, baseline: &Measurement) -> Vec<Calculation> {
    let median_threshold = 1.05; // 5% regression threshold
    let median_difference = dev.median / baseline.median;

    let stddev_threshold = 1.05; // 5% regression threshold
    let stddev_difference = dev.stddev / baseline.stddev;

    vec![
        Calculation {
            metric: ["median", metric].join("_"),
            regression: median_difference > median_threshold,
            data: Data {
                threshold: median_threshold,
                difference: median_difference,
                baseline: baseline.median,
                dev: dev.median,
            }
        },
        Calculation {
            metric: ["stddev", metric].join("_"),
            regression: stddev_difference > stddev_threshold,
            data: Data {
                threshold: stddev_threshold,
                difference: stddev_difference,
                baseline: baseline.stddev,
                dev: dev.stddev,
            }
        },
    ]
}

// given a directory, read all files in the directory and return each
// filename with the deserialized json contents of that file
fn measurements_from_files(
    results_directory: &Path,
) -> Result<Vec<(PathBuf, Measurements)>, CalculateError> {
    fs::read_dir(results_directory)
        .or_else(|e| Err(IOError::ReadErr(results_directory.to_path_buf(), Some(e))))
        .or_else(|e| Err(CalculateError::CalculateIOError(e)))?
        .into_iter()
        .map(|entry| {
            let ent: DirEntry = entry.or_else(|e| Err(IOError::ReadErr(results_directory.to_path_buf(), Some(e))))
                .or_else(|e| Err(CalculateError::CalculateIOError(e)))?;

            Ok(ent.path())
        })
        .collect::<Result<Vec<PathBuf>, CalculateError>>()?
        .iter()
        .filter(|path| {
            path
                .extension()
                .and_then(|ext| ext.to_str())
                .map_or(false, |ext| ext.ends_with("json"))
        })
        .map(|path| {
            fs::read_to_string(path)
                .or_else(|e| Err(IOError::BadFileContentsErr(path.clone(), Some(e))))
                .or_else(|e| Err(CalculateError::CalculateIOError(e)))
                .and_then(|contents| {
                    serde_json::from_str::<Measurements>(&contents)
                        .or_else(|e| Err(CalculateError::BadJSONErr(path.clone(), Some(e))))
                })
                .map(|m| (path.clone(), m))
        })
        .collect()
}

// given a list of filename-measurement pairs, detect any regressions by grouping
// measurements together by filename
fn calculate_regressions(
    measurements: &[(&PathBuf, &Measurement)],
) -> Result<Vec<Calculation>, CalculateError> {
    let mut measurement_groups: Vec<MeasurementGroup> = measurements
        .iter()
        .map(|(p, m)| {
            p.file_name()
                .ok_or_else(|| IOError::MissingFilenameErr(p.to_path_buf()))
                .and_then(|name| {
                    name.to_str()
                        .ok_or_else(|| IOError::FilenameNotUnicodeErr(p.to_path_buf()))
                })
                .map(|name| {
                    let parts: Vec<&str> = name.split("_").collect();
                    MeasurementGroup {
                        version: parts[0].to_owned(),
                        run: parts[1..].join("_"),
                        measurement: (*m).clone(),
                    }
                })
        })
        .collect::<Result<Vec<MeasurementGroup>, IOError>>()
        .or_else(|e| Err(CalculateError::CalculateIOError(e)))?;

    measurement_groups.sort_by(|x, y| (&x.run, &x.version).cmp(&(&y.run, &y.version)));

    // locking up mutation
    let sorted_measurement_groups = measurement_groups;

    let calculations: Vec<Calculation> = sorted_measurement_groups
        .iter()
        .group_by(|x| x.run.clone())
        .into_iter()
        .map(|(_, g)| {
            let mut groups: Vec<&MeasurementGroup> = g.collect();
            groups.sort_by(|x, y| x.version.cmp(&y.version));

            match groups.len() {
                2 => {
                    let dev = &groups[1];
                    let baseline = &groups[0];

                    if dev.version == "dev" && baseline.version == "baseline" {
                        Ok(calculate(&dev.run, &dev.measurement, &baseline.measurement))
                    } else {
                        Err(CalculateError::BadBranchNameErr(baseline.version.clone(), dev.version.clone()))
                    }
                },
                i => {
                    let gs: Vec<MeasurementGroup> = groups.into_iter().map(|x| x.clone()).collect();
                    Err(CalculateError::BadGroupSizeErr(i, gs))
                },
            }
        })
        .collect::<Result<Vec<Vec<Calculation>>, CalculateError>>()?
        .concat();

    Ok(calculations)
}

pub fn regressions(results_directory: &PathBuf) -> Result<Vec<Calculation>, CalculateError> {
    measurements_from_files(Path::new(&results_directory)).and_then(|v| {
        // exit early with an Err if there are no results to process
        if v.len() <= 0 {
            Err(CalculateError::NoResultsErr(results_directory.clone()))
        // we expect two runs for each project-metric pairing: one for each branch, baseline
        // and dev. An odd result count is unexpected.
        } else if v.len() % 2 == 1 {
            Err(CalculateError::OddResultsCountErr(v.len(), results_directory.clone()))
        } else {
            // otherwise, we can do our comparisons
            let measurements = v
                .iter()
                // the way we're running these, the files will each contain exactly one measurement, hence `results[0]`
                .map(|(p, ms)| (p, &ms.results[0]))
                .collect::<Vec<(&PathBuf, &Measurement)>>();

            calculate_regressions(&measurements[..])
        }
    })
}
<|endoftext|>


<commit_before>use abra::store::memory::MemoryIndexStore;

use system::index::Index;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_get_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let indices = system.indices.read().unwrap();

    // Check index exists
    get_index_or_404!(indices, *index_name);

    // TODO
    return Ok(json_response(status::Ok, "{}"));
}

pub fn view_put_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Load data from body
    // let data = json_from_request_body!(req);

    // Create index
    let mut indices_dir = system.get_indices_dir();
    indices_dir.push(index_name);
    indices_dir.set_extension("rsi");
    let index = Index::new(index_name.clone().to_owned(), MemoryIndexStore::new());
    let index_ref = indices.insert(index);
    indices.aliases.insert(index_name.clone().to_owned(), index_ref);

    // TODO: load settings

    system.log.info("[api] created index", b!("index" => *index_name));

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_delete_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Make sure the index exists
    get_index_or_404!(indices, *index_name);

    // Remove index from array
    let index_ref = match indices.aliases.get(*index_name) {
        Some(index_ref) => Some(*index_ref),
        None => None
    };

    if let Some(ref index_ref) = index_ref {
        indices.remove(index_ref);
    }

    // Delete file
    let mut indices_dir = system.get_indices_dir();
    indices_dir.push(index_name);
    indices_dir.set_extension("rsi");
    // fs::remove_file(&index_path).unwrap();

    system.log.info("[api] deleted index", b!("index" => *index_name));

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_post_refresh_index(req: &mut Request) -> IronResult<Response> {
    // let ref system = get_system!(req);
    // let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    // TODO
    // let mut indices = system.indices.write().unwrap();

    // TODO: {"_shards":{"total":10,"successful":5,"failed":0}}
    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}
<commit_msg>Create a couple of default analyzers<commit_after>use abra::analysis::AnalyzerSpec;
use abra::analysis::tokenizers::TokenizerSpec;
use abra::analysis::filters::FilterSpec;
use abra::analysis::ngram_generator::Edge;
use abra::store::memory::MemoryIndexStore;

use system::index::Index;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_get_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let indices = system.indices.read().unwrap();

    // Check index exists
    get_index_or_404!(indices, *index_name);

    // TODO
    return Ok(json_response(status::Ok, "{}"));
}

pub fn view_put_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Load data from body
    // let data = json_from_request_body!(req);

    // Create index
    let mut indices_dir = system.get_indices_dir();
    indices_dir.push(index_name);
    indices_dir.set_extension("rsi");
    let mut index = Index::new(index_name.clone().to_owned(), MemoryIndexStore::new());

    // Insert standard and edgengram analyzers
    // TODO: Load these from index settings
    index.analyzers.insert("standard".to_string(), AnalyzerSpec {
        tokenizer: TokenizerSpec::Standard,
        filters: vec![
            FilterSpec::Lowercase,
            FilterSpec::ASCIIFolding,
        ]
    });
    index.analyzers.insert("edgengram_analyzer".to_string(), AnalyzerSpec {
        tokenizer: TokenizerSpec::Standard,
        filters: vec![
            FilterSpec::Lowercase,
            FilterSpec::ASCIIFolding,
            FilterSpec::NGram {
                min_size: 2,
                max_size: 15,
                edge: Edge::Left
            },
        ]
    });

    // TODO: load settings

    let index_ref = indices.insert(index);
    indices.aliases.insert(index_name.clone().to_owned(), index_ref);

    system.log.info("[api] created index", b!("index" => *index_name));

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_delete_index(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Make sure the index exists
    get_index_or_404!(indices, *index_name);

    // Remove index from array
    let index_ref = match indices.aliases.get(*index_name) {
        Some(index_ref) => Some(*index_ref),
        None => None
    };

    if let Some(ref index_ref) = index_ref {
        indices.remove(index_ref);
    }

    // Delete file
    let mut indices_dir = system.get_indices_dir();
    indices_dir.push(index_name);
    indices_dir.set_extension("rsi");
    // fs::remove_file(&index_path).unwrap();

    system.log.info("[api] deleted index", b!("index" => *index_name));

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}

pub fn view_post_refresh_index(req: &mut Request) -> IronResult<Response> {
    // let ref system = get_system!(req);
    // let ref index_name = read_path_parameter!(req, "index").unwrap_or("");

    // Lock index array
    // TODO
    // let mut indices = system.indices.write().unwrap();

    // TODO: {"_shards":{"total":10,"successful":5,"failed":0}}
    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}
<|endoftext|>