<commit_before>//! Eudex is a Soundex-esque phonetic reduction/hashing algorithm, providing locality sensitive
//! "hashes" of words, based on the spelling and pronunciation.

#![cfg_attr(test, feature(test))]
#[cfg(test)]
extern crate test;

/// The sound table.
///
/// The first bit each describes a certain property of the phone:
///
/// | Position | Modifier | Property     | Phones                   |
/// |----------|----------|--------------|--------------------------|
/// | 1        | 1        | Discriminant | (for tagging duplicates) |
/// | 2        | 2        | Fricative    | fvsjxzhct                |
/// | 3        | 4        | Nasal        | mn                       |
/// | 4        | 8        | Plosive      | pbtdcgqk                 |
/// | 5        | 16       | Dental       | tdnzs                    |
/// | 6        | 32       | Liquid       | lr                       |
/// | 7        | 64       | Labial       | bfpv                     |
/// | 8        | 128      | Confident¹   | lrxzq                    |
///
/// ¹hard to misspell.
const PHONES: [u64; LETTERS as usize] = [
    0, // a
    0b01001000, // b
    0b00001010, // c
    0b00011000, // d
    0, // e
    0b01000010, // f
    0b00001000, // g
    0b00000010, // h
    0, // i
    0b00000011, // j
    0b00001001, // k
    0b10100000, // l
    0b00000100, // m
    0b00010100, // n
    0, // o
    0b01001001, // p
    0b10101000, // q
    0b10100001, // r
    0b00010010, // s
    0b00011011, // t
    0, // u
    0b01000011, // v
    0b00000000, // w
    0b10000010, // x
    0, // y
    0b10010010, // z
];
/// Number of letters in our phone map.
const LETTERS: u8 =  26;

/// Phonetically hash this string.
///
/// This hashing function is based upon a phonetic reduction algorithm, and is locality sensitive.
///
/// This will map the string a Soundex-esque value, although to similar sounding strings will not
/// necessarily be mapped to the same, but will map to nearby values (nearby in this case means the
/// XOR having a low Hamming weight).
///
/// This is two orders of magnitude faster than Soundex, and several orders of magnitude faster
/// than Levenshtein distance, making it feasible to run on large sets of strings in very short
/// time.
///
/// A word containing too many non-duplicate consonants will overflow and possibly cause
/// unspecified behavior, although observations shows that it affect the end result relatively
/// little.
///
/// Each byte in the string will be mapped to a value from a table, such that similarly sounding
/// characters have many overlapping bits. This way you ensure that strings sounding alike will be
/// mapped nearby each other. Vowels and duplicates will be skipped.
///
/// The first byte, however, is skipped and left in the most significant place, making it most
/// influential to the hash.
///
/// Case has no effect.
pub fn hash(s: &str) -> u64 {
    let mut bytes = s.bytes();
    let first_byte = bytes.next().map_or(0, |x| {
        let phone = phone(x);
        if phone == 0 { x as u64 } else { phone }
    });
    let mut res = 0;

    for i in bytes {
        let x = phone(i);
        if x != 0 && res & 255 != x {
            res <<= 8;
            res |= x;
        }
    }

    res | (first_byte << 56)
}

/// Get the "sound" of this character.
///
/// This is designed such that similar sounding characters will have a low XOR. Vowels or skipgrams
/// will return 0.
#[inline(always)]
fn phone(b: u8) -> u64 {
    let entry = (b | 32).wrapping_sub(b'a');
    if entry < LETTERS {
        PHONES[entry as usize]
    } else { 0 }
}

/// Calculate the Eudex distance between two words.
///
/// This metric will only measure the bitwise distance between two strings, which is a XOR-like
/// metric, making it unfit for certain purposes.  Generally speaking, the lower this is, the more
/// similar are the two words, although each byte carries different weight (the first one carries
/// the most, and the following's weights are simply half the weight of the previous byte).
///
/// # Example
///
/// ```rust
/// let distance = eudex::distance("write", "right").count_ones();
/// // Hamming weight of the Eudex distance gives a "smoother" word metric.
///
/// assert_eq!(distance, 10);
/// ```
pub fn distance(a: &str, b: &str) -> u64 {
    hash(a) ^ hash(b)
}

/// Check if two sentences sound "similar".
pub fn similar(a: &str, b: &str) -> bool {
    distance(a, b) < 670000
}

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

    #[test]
    fn test_exact() {
        assert_eq!(hash("lal"), hash("lel"));
        assert_eq!(hash("rupert"), hash("ropert"));
        assert_eq!(hash("rrr"), hash("rraaaa"));
        assert_eq!(hash("random"), hash("rondom"));
        assert_eq!(hash("java"), hash("jiva"));
        assert_eq!(hash("JAva"), hash("jAva"));
        assert_eq!(hash("triggered"), hash("TRIGGERED"));
        assert_eq!(hash("comp-uter"), hash("computer"));
        assert_eq!(hash("comp@u#te?r"), hash("computer"));
        assert_eq!(hash("c0mp^tər"), hash("computer"));
    }

    #[test]
    fn test_mismatch() {
        assert!(hash("reddit") != hash("eddit"));
        assert!(hash("lol") != hash("lulz"));
        assert!(hash("ijava") != hash("java"));
        assert!(hash("jesus") != hash("iesus"));
        assert!(hash("aesus") != hash("iesus"));
    }

    #[test]
    fn test_distance() {
        assert!(distance("lizzard", "wizzard") > distance("rick", "rolled"));
        assert!(distance("bannana", "panana") >= distance("apple", "abple"));
        //assert!(distance("franco", "sranco") < distance("unicode", "ASCII"));
        assert!(distance("trump", "drumpf") < distance("gangam", "style"));
        assert!(distance("right", "write").count_zeros() > distance("write", "abdominohysterotomy").count_zeros());
    }

    #[test]
    fn test_reflexivity() {
        assert_eq!(distance("a", "b"), distance("b", "a"));
        assert_eq!(distance("youtube", "facebook"), distance("facebook", "youtube"));
        assert_eq!(distance("Rust", "Go"), distance("Go", "Rust"));
        assert_eq!(distance("rick", "rolled"), distance("rolled", "rick"));
    }

    #[test]
    fn test_similar() {
        // Similar.
        assert!(similar("yay", "yuy"));
        assert!(distance("crack", "crakk").count_ones() < 10);
        assert!(similar("what", "wat"));
        assert!(similar("jesus", "jeuses"));
        assert!(similar("", ""));
        assert!(similar("jumpo", "jumbo"));
        assert!(similar("lol", "lulz"));
        assert!(similar("goth", "god"));
        assert!(similar("maier", "meyer"));
        assert!(similar("schmid", "schmidt"));

        // Not similar.
        assert!(!similar("youtube", "reddit"));
        assert!(!similar("yet", "vet"));
        assert!(!similar("hacker", "4chan"));
        assert!(!similar("awesome", "me"));
        assert!(!similar("prisco", "vkisco"));
        assert!(!similar("no", "go"));
        assert!(!similar("horse", "norse"));
        assert!(!similar("nice", "mice"));
    }

    #[bench]
    fn bench_dict(b: &mut Bencher) {
        use std::fs;
        use std::io::{BufRead, BufReader};

        b.iter(|| {
            let dict = fs::File::open("/usr/share/dict/american-english").unwrap_or_else(|_| {
                fs::File::open("/usr/share/dict/words").unwrap()
            });
            let mut vec = Vec::new();

            for i in BufReader::new(dict).lines() {
                vec.push(hash(&i.unwrap()));
            }

            vec
        });
    }
}
<commit_msg>Make Eudex sensitive to vowels.<commit_after>//! Eudex is a Soundex-esque phonetic reduction/hashing algorithm, providing locality sensitive
//! "hashes" of words, based on the spelling and pronunciation.

#![cfg_attr(test, feature(test))]
#[cfg(test)]
extern crate test;

/// The sound table.
///
/// The first bit each describes a certain property of the phone:
///
/// | Position | Modifier | Property     | Phones                   |
/// |----------|---------:|--------------|:------------------------:|
/// | 1        | 1        | Discriminant | (for tagging duplicates) |
/// | 2        | 2        | Nasal        | mn                       |
/// | 3        | 4        | Fricative    | fvsjxzhct                |
/// | 4        | 8        | Plosive      | pbtdcgqk                 |
/// | 5        | 16       | Dental       | tdnzs                    |
/// | 6        | 32       | Liquid       | lr                       |
/// | 7        | 64       | Labial       | bfpv                     |
/// | 8        | 128      | Confident¹   | lrxzq                    |
///
/// ¹hard to misspell.
///
/// Vowels are, to maxize the XOR distance, represented by 0 and 1 (open and closed, respectively).
const PHONES: [u64; LETTERS as usize] = [
    0, // a
    0b01001000, // b
    0b00001100, // c
    0b00011000, // d
    0, // e
    0b01000100, // f
    0b00001000, // g
    0b00000100, // h
    1, // i
    0b00000101, // j
    0b00001001, // k
    0b10100000, // l
    0b00000010, // m
    0b00010010, // n
    0, // o
    0b01001001, // p
    0b10101000, // q
    0b10100001, // r
    0b00010100, // s
    0b00011101, // t
    1, // u
    0b01000101, // v
    0b00000000, // w
    0b10000100, // x
    1, // y
    0b10010100, // z
];

/// An _injective_ phone table.
///
/// The first bit (MSD) is set if it is a vowel. If so, the second bit represent, if it is closed
/// or not, and the third is set, if it is a front vowel. The rest of the digits are used as
/// discriminants.
///
/// If it is a consonant, the rest of the bits are simply a right truncated version of the
/// [`PHONES`](./const.PHONES.hmtl) table, with the LSD used as discriminant.
const INJECTIVE_PHONES: [u64; LETTERS as usize] = [
    0b11100000, // a
    0b00100100, // b
    0b00000110, // c
    0b00001100, // d
    0b11100001, // e
    0b00100010, // f
    0b00000100, // g
    0b00000010, // h
    0b11000000, // i
    0b00000011, // j
    0b00000101, // k
    0b01010000, // l
    0b00000001, // m
    0b00001001, // n
    0b10100000, // o
    0b00100101, // p
    0b01010100, // q
    0b01010001, // r
    0b00001010, // s
    0b00001110, // t
    0b11000001, // u
    0b00100011, // v
    0b00000000, // w
    0b01000010, // x
    0b11100010, // y
    0b01001010, // z
];

/// Number of letters in our phone map.
const LETTERS: u8 =  26;

/// Phonetically hash this string.
///
/// This hashing function is based upon a phonetic reduction algorithm, and is locality sensitive.
///
/// This will map the string a Soundex-esque value, although to similar sounding strings will not
/// necessarily be mapped to the same, but will map to nearby values (nearby in this case means the
/// XOR having a low Hamming weight).
///
/// This is two orders of magnitude faster than Soundex, and several orders of magnitude faster
/// than Levenshtein distance, making it feasible to run on large sets of strings in very short
/// time.
///
/// Each byte in the string will be mapped to a value from a table, such that similarly sounding
/// characters have many overlapping bits. This way you ensure that strings sounding alike will be
/// mapped nearby each other. Vowels and duplicates will be skipped.
///
/// The first byte, however, is skipped and left in the most significant place, making it most
/// influential to the hash.
///
/// Case has no effect.
pub fn hash(s: &str) -> u64 {
    let mut bytes = s.bytes();
    let first_byte = bytes.next().map_or(0, |b| {
        let entry = (b | 32).wrapping_sub(b'a');
        if entry < LETTERS {
            INJECTIVE_PHONES[entry as usize]
        } else { 0 }
    });
    let mut res = 0;

    for b in bytes {
        let x = {
            let entry = (b | 32).wrapping_sub(b'a');
            if entry < LETTERS {
                PHONES[entry as usize]
            } else { 0 }
        };

        // Collapse consecutive vowels and similar sounding consonants into one.
        if res & 254 != x & 254 {
            res <<= 8;
            res |= x;
        }
    }

    res | (first_byte << 56)
}

/// Calculate the Eudex distance between two words.
///
/// This metric will only measure the bitwise distance between two strings, which is a XOR-like
/// metric, making it unfit for certain purposes.  Generally speaking, the lower this is, the more
/// similar are the two words, although each byte carries different weight (the first one carries
/// the most, and the following's weights are simply half the weight of the previous byte).
///
/// # Example
///
/// ```rust
/// let distance = eudex::distance("write", "right").count_ones();
/// // Hamming weight of the Eudex distance gives a "smoother" word metric.
///
/// assert_eq!(distance, 15);
/// ```
pub fn distance(a: &str, b: &str) -> u64 {
    hash(a) ^ hash(b)
}

/// Check if two sentences sound "similar".
pub fn similar(a: &str, b: &str) -> bool {
    distance(a, b) < 670000
}

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

    #[test]
    fn test_exact() {
        assert_eq!(hash("JAva"), hash("jAva"));
        assert_eq!(hash("co!mputer"), hash("computer"));
        //assert_eq!(hash("comp-uter"), hash("computer"));
        //assert_eq!(hash("comp@u#te?r"), hash("computer"));
        assert_eq!(hash("java"), hash("jiva"));
        assert_eq!(hash("lal"), hash("lel"));
        assert_eq!(hash("rindom"), hash("ryndom"));
        assert_eq!(hash("riiiindom"), hash("ryyyyyndom"));
        assert_eq!(hash("riyiyiiindom"), hash("ryyyyyndom"));
        assert_eq!(hash("triggered"), hash("TRIGGERED"));
        assert_eq!(hash("repert"), hash("ropert"));
    }

    #[test]
    fn test_mismatch() {
        assert!(hash("reddit") != hash("eddit"));
        assert!(hash("lol") != hash("lulz"));
        assert!(hash("ijava") != hash("java"));
        assert!(hash("jesus") != hash("iesus"));
        assert!(hash("aesus") != hash("iesus"));
        assert!(hash("iesus") != hash("yesus"));
        //assert!(hash("ripert") != hash("ropert"));
        //assert!(hash("rupirt") != hash("ropyrt"));
        assert!(hash("rrr") != hash("rraaaa"));
    }

    #[test]
    fn test_distance() {
        assert!(distance("lizzard", "wizzard") > distance("rick", "rolled"));
        assert!(distance("bannana", "panana") >= distance("apple", "abple"));
        //assert!(distance("franco", "sranco") < distance("unicode", "ASCII"));
        assert!(distance("trump", "drumpf") < distance("gangam", "style"));
        assert!(distance("right", "write").count_zeros() > distance("write", "abdominohysterotomy").count_zeros());
    }

    #[test]
    fn test_reflexivity() {
        assert_eq!(distance("a", "b"), distance("b", "a"));
        assert_eq!(distance("youtube", "facebook"), distance("facebook", "youtube"));
        assert_eq!(distance("Rust", "Go"), distance("Go", "Rust"));
        assert_eq!(distance("rick", "rolled"), distance("rolled", "rick"));
    }

    #[test]
    fn test_similar() {
        // Similar.
        assert!(similar("yay", "yuy"));
        assert!(distance("crack", "crakk").count_ones() < 10);
        assert!(similar("what", "wat"));
        assert!(similar("jesus", "jeuses"));
        assert!(similar("", ""));
        assert!(similar("jumpo", "jumbo"));
        assert!(similar("lol", "lulz"));
        assert!(similar("goth", "god"));
        assert!(similar("maier", "meyer"));
        //assert!(similar("schmid", "schmidt"));

        // Not similar.
        assert!(!similar("youtube", "reddit"));
        assert!(!similar("yet", "vet"));
        assert!(!similar("hacker", "4chan"));
        assert!(!similar("awesome", "me"));
        assert!(!similar("prisco", "vkisco"));
        assert!(!similar("no", "go"));
        assert!(!similar("horse", "norse"));
        assert!(!similar("nice", "mice"));
    }

    #[bench]
    fn bench_dict(b: &mut Bencher) {
        use std::fs;
        use std::io::{BufRead, BufReader};

        b.iter(|| {
            let dict = fs::File::open("/usr/share/dict/american-english").unwrap_or_else(|_| {
                fs::File::open("/usr/share/dict/words").unwrap()
            });
            let mut vec = Vec::new();

            for i in BufReader::new(dict).lines() {
                vec.push(hash(&i.unwrap()));
            }

            vec
        });
    }
}
<|endoftext|>


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

//! A set of [cryptographic hash
//! functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function) provided by the operating
//! system, when available.
//!
//! The purpose of this crate is to provide access to hash algorithms with as few dependencies as
//! possible. This means that when possible, the library uses the hashing functions that are
//! provided by the given operating system's bundled cryptographic libraries.
//!
//! # Supported Implementations
//!
//! By operating system:
//!
//! * Windows: `CryptoAPI`
//! * Mac OS X: `CommonCrypto`
//! * Linux/BSD/etc.: `OpenSSL`
//!
//! # Supported Algorithms
//!
//! * MD5
//! * SHA1
//! * SHA256
//! * SHA512

#![warn(missing_docs)]

#[cfg(any(target_os = "macos", target_os = "ios"))]
extern crate commoncrypto;
extern crate hex;
#[cfg(not(any(
    target_os = "macos",
    target_os = "ios",
    target_os = "windows"
)))]
extern crate openssl;
#[cfg(target_os = "windows")]
extern crate winapi;

use std::io::Write;

#[cfg(any(target_os = "macos", target_os = "ios"))]
#[path = "imp/commoncrypto.rs"]
mod imp;
#[cfg(target_os = "windows")]
#[path = "imp/cryptoapi.rs"]
mod imp;
#[cfg(not(any(
    target_os = "macos",
    target_os = "ios",
    target_os = "windows"
)))]
#[path = "imp/openssl.rs"]
mod imp;

mod test;

pub use imp::Hasher;

/// Available cryptographic hash functions.
#[derive(Clone, Debug)]
pub enum Algorithm {
    /// Popular message digest algorithm, only available for backwards compatibility purposes.
    MD5,
    /// SHA-1 algorithm from NIST FIPS, only available for backwards compatibility purposes.
    SHA1,
    /// SHA-2 family algorithm (256 bits).
    SHA256,
    /// SHA-2 family algorithm (512 bits).
    SHA512,
}

/// Helper function for `Hasher` which generates a cryptographic digest from the given
/// data and algorithm.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, digest};
///
/// let data = b"crypto-hash";
/// let result = digest(Algorithm::SHA256, data);
/// let expected =
///     b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'"
///     .to_vec();
/// assert_eq!(expected, result)
/// ```
pub fn digest(algorithm: Algorithm, data: &[u8]) -> Vec<u8> {
    let mut hasher = imp::Hasher::new(&algorithm);
    hasher.write_all(data).expect("Could not write hash data");
    hasher.finish()
}

/// Helper function for `Hasher` which generates a cryptographic digest serialized in
/// hexadecimal from the given data and algorithm.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, hex_digest};
///
/// let data = b"crypto-hash";
/// let result = hex_digest(Algorithm::SHA256, data);
/// let expected = "fd1afb6022cd4d47c890961c533928eacfe8219f1b2524f7fb2a61847ddf8c27";
/// assert_eq!(expected, result)
/// ```
pub fn hex_digest(algorithm: Algorithm, data: &[u8]) -> String {
    hex::encode(digest(algorithm, data))
}
<commit_msg>Rustfmt<commit_after>// Copyright (c) 2015, 2016, 2017 Mark Lee
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! A set of [cryptographic hash
//! functions](https://en.wikipedia.org/wiki/Cryptographic_hash_function) provided by the operating
//! system, when available.
//!
//! The purpose of this crate is to provide access to hash algorithms with as few dependencies as
//! possible. This means that when possible, the library uses the hashing functions that are
//! provided by the given operating system's bundled cryptographic libraries.
//!
//! # Supported Implementations
//!
//! By operating system:
//!
//! * Windows: `CryptoAPI`
//! * Mac OS X: `CommonCrypto`
//! * Linux/BSD/etc.: `OpenSSL`
//!
//! # Supported Algorithms
//!
//! * MD5
//! * SHA1
//! * SHA256
//! * SHA512

#![warn(missing_docs)]

#[cfg(any(target_os = "macos", target_os = "ios"))]
extern crate commoncrypto;
extern crate hex;
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
extern crate openssl;
#[cfg(target_os = "windows")]
extern crate winapi;

use std::io::Write;

#[cfg(any(target_os = "macos", target_os = "ios"))]
#[path = "imp/commoncrypto.rs"]
mod imp;
#[cfg(target_os = "windows")]
#[path = "imp/cryptoapi.rs"]
mod imp;
#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "windows")))]
#[path = "imp/openssl.rs"]
mod imp;

mod test;

pub use imp::Hasher;

/// Available cryptographic hash functions.
#[derive(Clone, Debug)]
pub enum Algorithm {
    /// Popular message digest algorithm, only available for backwards compatibility purposes.
    MD5,
    /// SHA-1 algorithm from NIST FIPS, only available for backwards compatibility purposes.
    SHA1,
    /// SHA-2 family algorithm (256 bits).
    SHA256,
    /// SHA-2 family algorithm (512 bits).
    SHA512,
}

/// Helper function for `Hasher` which generates a cryptographic digest from the given
/// data and algorithm.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, digest};
///
/// let data = b"crypto-hash";
/// let result = digest(Algorithm::SHA256, data);
/// let expected =
///     b"\xfd\x1a\xfb`\"\xcdMG\xc8\x90\x96\x1cS9(\xea\xcf\xe8!\x9f\x1b%$\xf7\xfb*a\x84}\xdf\x8c'"
///     .to_vec();
/// assert_eq!(expected, result)
/// ```
pub fn digest(algorithm: Algorithm, data: &[u8]) -> Vec<u8> {
    let mut hasher = imp::Hasher::new(&algorithm);
    hasher.write_all(data).expect("Could not write hash data");
    hasher.finish()
}

/// Helper function for `Hasher` which generates a cryptographic digest serialized in
/// hexadecimal from the given data and algorithm.
///
/// # Examples
///
/// ```rust
/// use crypto_hash::{Algorithm, hex_digest};
///
/// let data = b"crypto-hash";
/// let result = hex_digest(Algorithm::SHA256, data);
/// let expected = "fd1afb6022cd4d47c890961c533928eacfe8219f1b2524f7fb2a61847ddf8c27";
/// assert_eq!(expected, result)
/// ```
pub fn hex_digest(algorithm: Algorithm, data: &[u8]) -> String {
    hex::encode(digest(algorithm, data))
}
<|endoftext|>


<commit_before>extern crate time;
extern crate rand;

static EPOCH:f64 = 946702800.0;
static TIMESTAMP_SHIFT:usize = 23;
static RANDOM_MAX_VALUE:u32 = 4194303;

#[derive(Copy, Debug)]
pub struct Id {
    pub timestamp: f64,
    pub random_bits: u32,
}

pub fn new() -> u64 {
    let now = time_as_float(time::get_time());
    let timestamp = ((now - EPOCH) * 1000.0) as u64;
    let random_bits = rand::random::<u32>() % RANDOM_MAX_VALUE;

    (timestamp << TIMESTAMP_SHIFT) | (random_bits as u64)
}

pub fn parse(id:u64) -> Id {
    let random_bits = (id as u32) & RANDOM_MAX_VALUE;
    let mut timestamp = (id >> TIMESTAMP_SHIFT) as f64;
    timestamp /= 1000.0;
    timestamp += EPOCH;

    Id { timestamp: timestamp, random_bits: random_bits }
}

fn time_as_float(spec:time::Timespec) -> f64 {
    let mut nsec = spec.nsec as f64;
    while nsec > 1.0 {
        nsec /= 10.0;
    }

    (spec.sec as f64) + nsec
}

#[test]
fn test_time_as_float() {
    let input = time::Timespec { sec: 12, nsec: 34};
    let output = time_as_float(input);

    assert_eq!(output, 12.34);
}
<commit_msg>add missing Clone trait<commit_after>extern crate time;
extern crate rand;

static EPOCH:f64 = 946702800.0;
static TIMESTAMP_SHIFT:usize = 23;
static RANDOM_MAX_VALUE:u32 = 4194303;

#[derive(Clone, Copy, Debug)]
pub struct Id {
    pub timestamp: f64,
    pub random_bits: u32,
}

pub fn new() -> u64 {
    let now = time_as_float(time::get_time());
    let timestamp = ((now - EPOCH) * 1000.0) as u64;
    let random_bits = rand::random::<u32>() % RANDOM_MAX_VALUE;

    (timestamp << TIMESTAMP_SHIFT) | (random_bits as u64)
}

pub fn parse(id:u64) -> Id {
    let random_bits = (id as u32) & RANDOM_MAX_VALUE;
    let mut timestamp = (id >> TIMESTAMP_SHIFT) as f64;
    timestamp /= 1000.0;
    timestamp += EPOCH;

    Id { timestamp: timestamp, random_bits: random_bits }
}

fn time_as_float(spec:time::Timespec) -> f64 {
    let mut nsec = spec.nsec as f64;
    while nsec > 1.0 {
        nsec /= 10.0;
    }

    (spec.sec as f64) + nsec
}

#[test]
fn test_time_as_float() {
    let input = time::Timespec { sec: 12, nsec: 34};
    let output = time_as_float(input);

    assert_eq!(output, 12.34);
}
<|endoftext|>


<commit_before>// use std::io;
// use std::str::FromStr;
use std::num::ParseFloatError;

pub type Coordinate = (f32, f32, f32);
pub type XYZLine = (String, Coordinate);
pub type Snapshot = (String, Vec<XYZLine>);

pub fn parse_coord(x: &str, y: &str, z: &str) -> Result<Coordinate, ParseFloatError> {
    let vec_x = match x.parse::<f32>() {
        Ok(value) => value,
        Err(err) => return Err(err)
    };
    let vec_y = match y.parse::<f32>() {
        Ok(value) => value,
        Err(err) => return Err(err)
    };
    let vec_z = match z.parse::<f32>() {
        Ok(value) => value,
        Err(err) => return Err(err)
    };

    Ok((vec_x, vec_y, vec_z))
}

// fn read_xyz_line<R: io::BufRead>(reader: &mut R) -> Option<XYZLine> {
//     let mut buffer = String::new();
//     try!(reader.read_line(&mut buffer));
//     let splited: Vec<&str> = buffer.split_whitespace().collect();
//     if splited.len() == 4 {
//         Some(
//             (String::from(splited[0]),
//             parse_coord(splited[1], splited[2], splited[3]))
//             )
//     } else {
//         None
//     }
// }

// fn collect_xyz<R: io::BufRead>(reader: &mut R, num: i32) -> Vec<XYZLine> {
//     let mut vec = Vec::new();
//     for _ in 0..num {
//         match read_xyz_line(reader) {
//             Some(x) => vec.push(x),
//             _ => ()
//         };
//     }
//     vec
// }

// pub fn read_snapshot<R: io::BufRead>(mut reader: &mut R) -> Snapshot {
//     let mut buffer = String::new();
//     try!(reader.read_line(&mut buffer));
//     let num = i32::from_str(&buffer).unwrap(); // TODO try
//     reader.read_line(&mut buffer); // TODO try
//     (buffer.clone(), collect_xyz(reader, num))
// }

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Use try! macro instead of match<commit_after>// use std::io;
// use std::str::FromStr;
use std::num::ParseFloatError;

pub type Coordinate = (f32, f32, f32);
pub type XYZLine = (String, Coordinate);
pub type Snapshot = (String, Vec<XYZLine>);

pub fn parse_coord(x: &str, y: &str, z: &str) -> Result<Coordinate, ParseFloatError> {
    let vec_x = try!(x.parse::<f32>());
    let vec_y = try!(y.parse::<f32>());
    let vec_z = try!(z.parse::<f32>());

    Ok((vec_x, vec_y, vec_z))
}

// fn read_xyz_line<R: io::BufRead>(reader: &mut R) -> Option<XYZLine> {
//     let mut buffer = String::new();
//     try!(reader.read_line(&mut buffer));
//     let splited: Vec<&str> = buffer.split_whitespace().collect();
//     if splited.len() == 4 {
//         Some(
//             (String::from(splited[0]),
//             parse_coord(splited[1], splited[2], splited[3]))
//             )
//     } else {
//         None
//     }
// }

// fn collect_xyz<R: io::BufRead>(reader: &mut R, num: i32) -> Vec<XYZLine> {
//     let mut vec = Vec::new();
//     for _ in 0..num {
//         match read_xyz_line(reader) {
//             Some(x) => vec.push(x),
//             _ => ()
//         };
//     }
//     vec
// }

// pub fn read_snapshot<R: io::BufRead>(mut reader: &mut R) -> Snapshot {
//     let mut buffer = String::new();
//     try!(reader.read_line(&mut buffer));
//     let num = i32::from_str(&buffer).unwrap(); // TODO try
//     reader.read_line(&mut buffer); // TODO try
//     (buffer.clone(), collect_xyz(reader, num))
// }

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::ffi::CString;
use std::ffi::CStr;
use std::string::String;

mod ext_readline {
    use libc::c_char;

    extern "C" {
        pub fn add_history(line: *const c_char);
        pub fn readline(p: *const c_char) -> *const c_char;
    }
}

pub fn add_history(line: &str) {
    unsafe {
        ext_readline::add_history(CString::new(line).unwrap().as_ptr());
    }
}

pub fn readline(prompt: &str) -> Option<String> {
    let cprmt = CString::new(prompt).unwrap().as_ptr();
    unsafe {
        let ret = ext_readline::readline(cprmt);
        if ret.is_null() {  // user pressed Ctrl-D
            None
        }
        else {
            let slice = CStr::from_ptr(ret);

            let bytes = slice.to_bytes();

            Some(String::from_utf8_lossy(bytes).into_owned())
        }
    }
}
<commit_msg>add docs<commit_after>//! A Simple wrapper for libreadline or libedit
//!
//! Exports two functions:
//!
//!   - `add_history`
//!   - `readline`
//!

extern crate libc;

use std::ffi::CString;
use std::ffi::CStr;
use std::string::String;

mod ext_readline {
    use libc::c_char;

    extern "C" {
        pub fn add_history(line: *const c_char);
        pub fn readline(p: *const c_char) -> *const c_char;
    }
}

/// Update the internal history of input lines
///
/// Call this after a successful `readline()` call to add that line to the
/// history.
pub fn add_history(line: &str) {
    unsafe {
        ext_readline::add_history(CString::new(line).unwrap().as_ptr());
    }
}

/// Invoke the external `readline()`.
///
/// Returns an `Option<String>` representing whether a `String` was returned
/// or NULL. `None` indicates the user has signal end of input.
pub fn readline(prompt: &str) -> Option<String> {
    let cprmt = CString::new(prompt).unwrap().as_ptr();
    unsafe {
        let ret = ext_readline::readline(cprmt);
        if ret.is_null() {  // user pressed Ctrl-D
            None
        }
        else {
            let slice = CStr::from_ptr(ret);

            let bytes = slice.to_bytes();

            Some(String::from_utf8_lossy(bytes).into_owned())
        }
    }
}
<|endoftext|>


<commit_before>extern crate futures;
extern crate rand;
#[macro_use]
extern crate tokio_core;

pub use kcp::KCP;

mod kcp;

use std::io;
use std::net::{SocketAddr, Shutdown};

use futures::Async;
use tokio_core::io::IoFuture;
use tokio_core::net::UdpSocket;
use tokio_core::reactor::{Handle, PollEvented};

use std::io::Write;
use std::sync::{Arc, Mutex};

struct KcpTunnel {
    socket: UdpSocket,
    addr: SocketAddr,
}

impl Write for KcpTunnel {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = self.socket.send_to(buf, &self.addr).unwrap();
        if n == buf.len() {
            Ok(n)
        } else {
            Err(io::Error::new(io::ErrorKind::WouldBlock, "failed to send"))
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

pub struct KcpStream {
    io: PollEvented<u8>,
    addr: SocketAddr,
}

pub struct KcpStreamNew {
    inner: IoFuture<KcpStream>,
}

enum KcpStreamConnect {
    Waiting(KcpStream),
    Empty,
}

impl KcpStream {
    pub fn connect(addr: &SocketAddr, handle: &Handle) -> KcpStreamNew {
        unimplemented!()
    }

    fn new(socket: UdpSocket, addr: &SocketAddr, handle: &Handle) -> IoFuture<KcpStream> {
        let conv = rand::random::<u32>();
        let tunnel = Arc::new(Mutex::new(KcpTunnel {
            socket: socket,
            addr: *addr,
        }));

        unimplemented!()
    }

    pub fn connect_stream(// stream: net::TcpStream,
                          addr: &SocketAddr,
                          handle: &Handle)
                          -> IoFuture<KcpStream> {
        unimplemented!()
    }

    pub fn poll_read(&self) -> Async<()> {
        unimplemented!()
    }

    pub fn poll_write(&self) -> Async<()> {
        unimplemented!()
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        unimplemented!()
    }

    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        unimplemented!()
    }

    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
        unimplemented!()
    }

    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
        unimplemented!()
    }

    pub fn nodelay(&self) -> io::Result<bool> {
        unimplemented!()
    }

    pub fn set_keepalive_ms(&self, keepalive: Option<u32>) -> io::Result<()> {
        unimplemented!()
    }

    pub fn keepalive_ms(&self) -> io::Result<Option<u32>> {
        unimplemented!()
    }

    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
        unimplemented!()
    }

    pub fn ttl(&self) -> io::Result<u32> {
        unimplemented!()
    }
}
<commit_msg>Update<commit_after>extern crate futures;
extern crate rand;
#[macro_use]
extern crate tokio_core;

pub use kcp::KCP;

mod kcp;

use std::io;
use std::net::{SocketAddr, Shutdown};
use std::str;

use futures::{Future, failed, Async};
use tokio_core::io::IoFuture;
use tokio_core::net::UdpSocket;
use tokio_core::reactor::{Handle, PollEvented};

use std::io::Write;

struct KcpTunnel {
    socket: UdpSocket,
    addr: SocketAddr,
}

impl Write for KcpTunnel {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = self.socket.send_to(buf, &self.addr).unwrap();
        if n == buf.len() {
            Ok(n)
        } else {
            Err(io::Error::new(io::ErrorKind::WouldBlock, "failed to send"))
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

pub struct KcpStream {
    io: UdpSocket,
    kcp: KCP,
}

pub struct KcpStreamNew {
    inner: IoFuture<KcpStream>,
}

enum KcpStreamConnect {
    Waiting(KcpStream),
    Empty,
}

impl KcpStream {
    pub fn connect(addr: &SocketAddr, handle: &Handle) -> KcpStreamNew {
        let any = str::FromStr::from_str("0.0.0.0:0").unwrap();
        let future = match UdpSocket::bind(&any, handle) {
            Ok(udp) => KcpStream::new(udp, addr, handle),
            Err(e) => failed(e).boxed(),
        };
        KcpStreamNew { inner: future }
    }

    fn new(socket: UdpSocket, addr: &SocketAddr, handle: &Handle) -> IoFuture<KcpStream> {
        let conv = rand::random::<u32>();
        let kcp = KCP::new(conv);
        KcpStreamConnect::Waiting(KcpStream {
                io: socket,
                kcp: kcp,
            })
            .boxed()
    }

    pub fn connect_stream(// stream: net::TcpStream,
                          addr: &SocketAddr,
                          handle: &Handle)
                          -> IoFuture<KcpStream> {
        unimplemented!()
    }

    pub fn poll_read(&self) -> Async<()> {
        unimplemented!()
    }

    pub fn poll_write(&self) -> Async<()> {
        unimplemented!()
    }

    pub fn local_addr(&self) -> io::Result<SocketAddr> {
        unimplemented!()
    }

    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        unimplemented!()
    }

    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
        unimplemented!()
    }

    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
        unimplemented!()
    }

    pub fn nodelay(&self) -> io::Result<bool> {
        unimplemented!()
    }

    pub fn set_keepalive_ms(&self, keepalive: Option<u32>) -> io::Result<()> {
        unimplemented!()
    }

    pub fn keepalive_ms(&self) -> io::Result<Option<u32>> {
        unimplemented!()
    }

    pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
        unimplemented!()
    }

    pub fn ttl(&self) -> io::Result<u32> {
        unimplemented!()
    }
}

impl Future for KcpStreamConnect {
    type Item = KcpStream;
    type Error = io::Error;

    fn poll(&mut self) -> futures::Poll<KcpStream, io::Error> {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_usize());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_usize());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

use std::fmt::{Display,Formatter,Result};
use std::ops::{Add,Sub,Mul,Div};

/// byte size for 1 byte
pub static B: usize = 1;
/// bytes size for 1 kilobyte
pub static KB: usize = 1000;
/// bytes size for 1 megabyte
pub static MB: usize = 1000000;
/// bytes size for 1 gigabyte
pub static GB: usize = 1000000000;
/// bytes size for 1 terabyte
pub static TB: usize = 1000000000000;
/// bytes size for 1 petabyte
pub static PB: usize = 1000000000000000;

/// bytes size for 1 kibibyte
pub static KIB: usize = 1024;
/// bytes size for 1 mebibyte
pub static MIB: usize = 1048576;
/// bytes size for 1 gibibyte
pub static GIB: usize = 1073741824;
/// bytes size for 1 tebibyte
pub static TIB: usize = 1099511627776;
/// bytes size for 1 pebibyte
pub static PIB: usize = 1125899906842624;

static UNITS:    &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB:  f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
/// Byte size representation
pub struct ByteSize {
  size: usize
}

impl ByteSize {
  #[inline(always)]
  pub fn b(size: usize) -> ByteSize {
    ByteSize {size: size}
  }

  #[inline(always)]
  pub fn kb(size: usize) -> ByteSize {
    ByteSize {size: size * KB}
  }

  #[inline(always)]
  pub fn kib(size: usize) -> ByteSize {
   ByteSize {size: size * KIB}
  }

  #[inline(always)]
  pub fn mb(size: usize) -> ByteSize {
    ByteSize {size: size * MB}
  }

  #[inline(always)]
  pub fn mib(size: usize) -> ByteSize {
    ByteSize {size: size * MIB}
  }

  #[inline(always)]
  pub fn gb(size: usize) -> ByteSize {
    ByteSize {size: size * GB}
  }

  #[inline(always)]
  pub fn gib(size: usize) -> ByteSize {
    ByteSize {size: size * GIB}
  }

  #[inline(always)]
  pub fn tb(size: usize) -> ByteSize {
    ByteSize {size: size * TB}
  }

  #[inline(always)]
  pub fn tib(size: usize) -> ByteSize {
    ByteSize {size: size * TIB}
  }

  #[inline(always)]
  pub fn pb(size: usize) -> ByteSize {
    ByteSize {size: size * PB}
  }

  #[inline(always)]
  pub fn pib(size: usize) -> ByteSize {
    ByteSize {size: size * PIB}
  }

  #[inline(always)]
  pub fn as_usize(&self) -> usize {
    self.size
  }

  pub fn to_string(&self, si: bool) -> String {

    let unit = if si { KIB } else { KB };
    let unit_base =  if si { LN_KIB } else { LN_KB };
    let unit_prefix = if si { UNITS_SI.as_bytes() } else { UNITS.as_bytes() };
    let unit_suffix = if si { "iB" } else { "B" };

    if self.size < unit {
      format!("{} B", self.size)

    } else {
      let exp = match ((self.size as f64).ln() / unit_base) as usize {
        e if e == 0 => 1,
        e => e
      };

      format!("{} {}{}", (self.size / unit.pow(exp as u32)),
        unit_prefix[exp - 1] as char, unit_suffix)
    }
  }
}

impl Display for ByteSize {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", self.to_string(false))
  }
}

impl Add<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size + rhs)}
  }
}

impl Add<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size + rhs.size)}
  }
}

impl Sub<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size - rhs)}
  }
}

impl Sub<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size - rhs.size)}
  }
}

impl Mul<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn mul(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size * rhs)}
  }
}

impl Div<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn div(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size / rhs)}
  }
}

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

  #[test]
  fn test_arithmetic() {
    let x = ByteSize::mb(1);
    let y = ByteSize::kb(100);

    assert_eq!(
      (x + y).as_usize(),
      1100000
    );
    assert_eq!(
      (x + (100*1000)).as_usize(),
      1100000
    );

    assert_eq!(
      (x - y).as_usize(),
      900000
    );
    assert_eq!(
      (x - (100*1000)).as_usize(),
      900000
    );
  }

  #[test]
  fn test_comparison() {
    assert!(ByteSize::mb(1) == ByteSize::kb(1000));
    assert!(ByteSize::mib(1) == ByteSize::kib(1024));
    assert!(ByteSize::mb(1) != ByteSize::kib(1024));
    assert!(ByteSize::mb(1) < ByteSize::kib(1024));
    assert!(ByteSize::b(0) < ByteSize::tib(1));
  }

  fn assert_display(expected: &str, b: ByteSize) {
    assert_eq!(expected, format!("{}", b));
  }

  #[test]
  fn test_display() {
    assert_display("215 B", ByteSize::b(215));
    assert_display("1 KB", ByteSize::kb(1));
    assert_display("301 KB", ByteSize::kb(301));
    assert_display("419 MB", ByteSize::mb(419));
    assert_display("518 GB", ByteSize::gb(518));
    assert_display("815 TB", ByteSize::tb(815));
    assert_display("609 PB", ByteSize::pb(609));
  }

  fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
    assert_eq!(expected.to_string(), b.to_string(si));
  }

  #[test]
  fn test_to_string() {
    assert_to_string("215 B", ByteSize::b(215), true);
    assert_to_string("215 B", ByteSize::b(215), false);

    assert_to_string("1 kiB", ByteSize::kib(1), true);
    assert_to_string("1 KB", ByteSize::kib(1), false);

    assert_to_string("293 kiB", ByteSize::kb(301), true);
    assert_to_string("301 KB", ByteSize::kb(301), false);

    assert_to_string("1 MiB", ByteSize::mib(1), true);
    assert_to_string("1048 KB", ByteSize::mib(1), false);

    assert_to_string("399 MiB", ByteSize::mb(419), true);
    assert_to_string("419 MB", ByteSize::mb(419), false);

    assert_to_string("482 GiB", ByteSize::gb(518), true);
    assert_to_string("518 GB", ByteSize::gb(518), false);

    assert_to_string("741 TiB", ByteSize::tb(815), true);
    assert_to_string("815 TB", ByteSize::tb(815), false);

    assert_to_string("540 PiB", ByteSize::pb(609), true);
    assert_to_string("609 PB", ByteSize::pb(609), false);
  }
}
<commit_msg>Implement Default trait<commit_after>//! ByteSize is an utility that easily makes bytes size representation
//! and helps its arithmetic operations.
//!
//! ## Example
//!
//! ```ignore
//! extern crate bytesize;
//!
//! use bytesize::ByteSize;
//!
//! fn byte_arithmetic_operator() {
//!   let x = ByteSize::mb(1);
//!   let y = ByteSize::kb(100);
//!
//!   let plus = x + y;
//!   print!("{} bytes", plus.as_usize());
//!
//!   let minus = ByteSize::tb(100) - ByteSize::gb(4);
//!   print!("{} bytes", minus.as_usize());
//! }
//! ```
//!
//! It also provides its human readable string as follows:
//!
//! ```ignore
//!  assert_eq!("482 GiB".to_string(), ByteSize::gb(518).to_string(true));
//!  assert_eq!("518 GB".to_string(), ByteSize::gb(518).to_string(false));
//! ```

use std::fmt::{Display,Formatter,Result};
use std::ops::{Add,Sub,Mul,Div};

/// byte size for 1 byte
pub static B: usize = 1;
/// bytes size for 1 kilobyte
pub static KB: usize = 1000;
/// bytes size for 1 megabyte
pub static MB: usize = 1000000;
/// bytes size for 1 gigabyte
pub static GB: usize = 1000000000;
/// bytes size for 1 terabyte
pub static TB: usize = 1000000000000;
/// bytes size for 1 petabyte
pub static PB: usize = 1000000000000000;

/// bytes size for 1 kibibyte
pub static KIB: usize = 1024;
/// bytes size for 1 mebibyte
pub static MIB: usize = 1048576;
/// bytes size for 1 gibibyte
pub static GIB: usize = 1073741824;
/// bytes size for 1 tebibyte
pub static TIB: usize = 1099511627776;
/// bytes size for 1 pebibyte
pub static PIB: usize = 1125899906842624;

static UNITS:    &'static str = "KMGTPE";
static UNITS_SI: &'static str = "kMGTPE";
static LN_KB:  f64 = 6.931471806; // ln 1024
static LN_KIB: f64 = 6.907755279; // ln 1000

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Default)]
/// Byte size representation
pub struct ByteSize {
  size: usize
}

impl ByteSize {
  #[inline(always)]
  pub fn b(size: usize) -> ByteSize {
    ByteSize {size: size}
  }

  #[inline(always)]
  pub fn kb(size: usize) -> ByteSize {
    ByteSize {size: size * KB}
  }

  #[inline(always)]
  pub fn kib(size: usize) -> ByteSize {
   ByteSize {size: size * KIB}
  }

  #[inline(always)]
  pub fn mb(size: usize) -> ByteSize {
    ByteSize {size: size * MB}
  }

  #[inline(always)]
  pub fn mib(size: usize) -> ByteSize {
    ByteSize {size: size * MIB}
  }

  #[inline(always)]
  pub fn gb(size: usize) -> ByteSize {
    ByteSize {size: size * GB}
  }

  #[inline(always)]
  pub fn gib(size: usize) -> ByteSize {
    ByteSize {size: size * GIB}
  }

  #[inline(always)]
  pub fn tb(size: usize) -> ByteSize {
    ByteSize {size: size * TB}
  }

  #[inline(always)]
  pub fn tib(size: usize) -> ByteSize {
    ByteSize {size: size * TIB}
  }

  #[inline(always)]
  pub fn pb(size: usize) -> ByteSize {
    ByteSize {size: size * PB}
  }

  #[inline(always)]
  pub fn pib(size: usize) -> ByteSize {
    ByteSize {size: size * PIB}
  }

  #[inline(always)]
  pub fn as_usize(&self) -> usize {
    self.size
  }

  pub fn to_string(&self, si: bool) -> String {

    let unit = if si { KIB } else { KB };
    let unit_base =  if si { LN_KIB } else { LN_KB };
    let unit_prefix = if si { UNITS_SI.as_bytes() } else { UNITS.as_bytes() };
    let unit_suffix = if si { "iB" } else { "B" };

    if self.size < unit {
      format!("{} B", self.size)

    } else {
      let exp = match ((self.size as f64).ln() / unit_base) as usize {
        e if e == 0 => 1,
        e => e
      };

      format!("{} {}{}", (self.size / unit.pow(exp as u32)),
        unit_prefix[exp - 1] as char, unit_suffix)
    }
  }
}

impl Display for ByteSize {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}", self.to_string(false))
  }
}

impl Add<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size + rhs)}
  }
}

impl Add<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn add(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size + rhs.size)}
  }
}

impl Sub<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size - rhs)}
  }
}

impl Sub<ByteSize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn sub(self, rhs: ByteSize) -> ByteSize {
    ByteSize {size: (self.size - rhs.size)}
  }
}

impl Mul<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn mul(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size * rhs)}
  }
}

impl Div<usize> for ByteSize {
  type Output = ByteSize;

  #[inline(always)]
  fn div(self, rhs: usize) -> ByteSize {
    ByteSize {size: (self.size / rhs)}
  }
}

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

  #[test]
  fn test_arithmetic() {
    let x = ByteSize::mb(1);
    let y = ByteSize::kb(100);

    assert_eq!(
      (x + y).as_usize(),
      1100000
    );
    assert_eq!(
      (x + (100*1000)).as_usize(),
      1100000
    );

    assert_eq!(
      (x - y).as_usize(),
      900000
    );
    assert_eq!(
      (x - (100*1000)).as_usize(),
      900000
    );
  }

  #[test]
  fn test_comparison() {
    assert!(ByteSize::mb(1) == ByteSize::kb(1000));
    assert!(ByteSize::mib(1) == ByteSize::kib(1024));
    assert!(ByteSize::mb(1) != ByteSize::kib(1024));
    assert!(ByteSize::mb(1) < ByteSize::kib(1024));
    assert!(ByteSize::b(0) < ByteSize::tib(1));
  }

  fn assert_display(expected: &str, b: ByteSize) {
    assert_eq!(expected, format!("{}", b));
  }

  #[test]
  fn test_display() {
    assert_display("215 B", ByteSize::b(215));
    assert_display("1 KB", ByteSize::kb(1));
    assert_display("301 KB", ByteSize::kb(301));
    assert_display("419 MB", ByteSize::mb(419));
    assert_display("518 GB", ByteSize::gb(518));
    assert_display("815 TB", ByteSize::tb(815));
    assert_display("609 PB", ByteSize::pb(609));
  }

  fn assert_to_string(expected: &str, b: ByteSize, si: bool) {
    assert_eq!(expected.to_string(), b.to_string(si));
  }

  #[test]
  fn test_to_string() {
    assert_to_string("215 B", ByteSize::b(215), true);
    assert_to_string("215 B", ByteSize::b(215), false);

    assert_to_string("1 kiB", ByteSize::kib(1), true);
    assert_to_string("1 KB", ByteSize::kib(1), false);

    assert_to_string("293 kiB", ByteSize::kb(301), true);
    assert_to_string("301 KB", ByteSize::kb(301), false);

    assert_to_string("1 MiB", ByteSize::mib(1), true);
    assert_to_string("1048 KB", ByteSize::mib(1), false);

    assert_to_string("399 MiB", ByteSize::mb(419), true);
    assert_to_string("419 MB", ByteSize::mb(419), false);

    assert_to_string("482 GiB", ByteSize::gb(518), true);
    assert_to_string("518 GB", ByteSize::gb(518), false);

    assert_to_string("741 TiB", ByteSize::tb(815), true);
    assert_to_string("815 TB", ByteSize::tb(815), false);

    assert_to_string("540 PiB", ByteSize::pb(609), true);
    assert_to_string("609 PB", ByteSize::pb(609), false);
  }

  #[test]
  fn test_default() {
    assert_eq!(ByteSize::b(0), ByteSize::default());
  }
}
<|endoftext|>


<commit_before>//! Clustering algorithms.
//!
//! This crate provides generic implementations of clustering
//! algorithms, allowing them to work with any back-end "point
//! database" that implements the required operations, e.g. one might
//! be happy with using the naive collection `BruteScan` from this
//! crate, or go all out and implement a specialised R*-tree for
//! optimised performance.
//!
//! # Installation
//!
//! Add the following to your `Cargo.toml` file:
//!
//! ```toml
//! [dependencies]
//! cogset = "0.1"
//! ```

mod dbscan;
pub use dbscan::Dbscan;

mod point;
pub use point::{Point, RegionQuery, Points, ListPoints, BruteScan, BruteScanNeighbours, Euclid};
<commit_msg>Source link.<commit_after>//! Clustering algorithms.
//!
//! This crate provides generic implementations of clustering
//! algorithms, allowing them to work with any back-end "point
//! database" that implements the required operations, e.g. one might
//! be happy with using the naive collection `BruteScan` from this
//! crate, or go all out and implement a specialised R*-tree for
//! optimised performance.
//!
//! [Source](https://github.com/huonw/cogset).
//!
//! # Installation
//!
//! Add the following to your `Cargo.toml` file:
//!
//! ```toml
//! [dependencies]
//! cogset = "0.1"
//! ```

mod dbscan;
pub use dbscan::Dbscan;

mod point;
pub use point::{Point, RegionQuery, Points, ListPoints, BruteScan, BruteScanNeighbours, Euclid};
<|endoftext|>


<commit_before>#![feature(old_io,net,core,io)]
extern crate time;

mod ntp;

use std::net::{UdpSocket, lookup_host, SocketAddr};
use time::Timespec;

const NTP_PORT: u16 = 123;
const UDP_LOCAL: &'static str = "0.0.0.0:35000";

/// `receive_network_timestamp` retrieves the current from the Internet using
/// the NTP protocol.
///
/// # Arguments
///
/// * `host` - The NTP server (i.e. sundial.columbia.edu).
pub fn receive_network_timestamp(host: &str) -> Result<Timespec, std::io::Error> {
    let host = try!(lookup_host(host)).next().unwrap();
    let addr = SocketAddr::new(try!(host).ip(), NTP_PORT);
    let header = ntp::NTPHeader::new();
    let message = header.encode();

    let socket = try!(UdpSocket::bind(UDP_LOCAL));

    try!(socket.send_to(message.as_slice(), &addr));

    let mut buf = [0u8; 1000];

    // TODO: Rust doesn't support timeouts yet
    let (amt, _) = try!(socket.recv_from(buf.as_mut_slice()));

    drop(socket);

    let header = ntp::NTPHeader::decode(amt, &buf);

    Ok(header.transmit_timestamp.as_timespec())
}

#[test]
fn receive_timestamp() {
    const NTP_SERVER: &'static str = "sundial.columbia.edu";

    receive_network_timestamp(NTP_SERVER).unwrap();
}
<commit_msg>improve external function name<commit_after>#![feature(old_io,net,core,io)]
extern crate time;

mod ntp;

use std::net::{UdpSocket, lookup_host, SocketAddr};
use time::Timespec;

const NTP_PORT: u16 = 123;
const UDP_LOCAL: &'static str = "0.0.0.0:35000";

/// `retrieve_ntp_timestamp` retrieves the current time from a NTP server.
///
/// # Arguments
///
/// * `host` - The NTP server (i.e. sundial.columbia.edu).
pub fn retrieve_ntp_timestamp(host: &str) -> Result<Timespec, std::io::Error> {
    let host = try!(lookup_host(host)).next().unwrap();
    let addr = SocketAddr::new(try!(host).ip(), NTP_PORT);
    let header = ntp::NTPHeader::new();
    let message = header.encode();

    let socket = try!(UdpSocket::bind(UDP_LOCAL));

    try!(socket.send_to(message.as_slice(), &addr));

    let mut buf = [0u8; 1000];

    // TODO: Rust doesn't support timeouts yet
    let (amt, _) = try!(socket.recv_from(buf.as_mut_slice()));

    drop(socket);

    let header = ntp::NTPHeader::decode(amt, &buf);

    Ok(header.transmit_timestamp.as_timespec())
}

#[test]
fn receive_timestamp() {
    const NTP_SERVER: &'static str = "sundial.columbia.edu";

    retrieve_ntp_timestamp(NTP_SERVER).unwrap();
}
<|endoftext|>


<commit_before>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let _server = ServerBuilder::new(Arc::new(io)).start_http(&"127.0.0.1:3030".parse().unwrap());
//! }
//! ```

#![warn(missing_docs)]

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

pub mod request_response;
mod cors;
mod handler;
mod hosts_validator;
#[cfg(test)]
mod tests;

use std::sync::{Arc, Mutex};
use std::net::SocketAddr;
use std::thread;
use hyper::server;
use jsonrpc::IoHandler;

pub use hyper::header::AccessControlAllowOrigin;
pub use handler::{PanicHandler, ServerHandler};
pub use hosts_validator::is_host_header_valid;

/// Result of starting the Server.
pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error.
#[derive(Debug)]
pub enum RpcServerError {
	/// IO Error
	IoError(std::io::Error),
	/// Other Error (hyper)
	Other(hyper::error::Error),
}

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}

/// Specifies if domains should be validated.
pub enum DomainsValidation<T> {
	/// Allow only domains on the list.
	AllowOnly(Vec<T>),
	/// Disable domains validation completely.
	Disabled,
}

impl<T> Into<Option<Vec<T>>> for DomainsValidation<T> {
	fn into(self) -> Option<Vec<T>> {
		use DomainsValidation::*;
		match self {
			AllowOnly(list) => Some(list),
			Disabled => None,
		}
	}
}

impl<T> From<Option<Vec<T>>> for DomainsValidation<T> {
	fn from(other: Option<Vec<T>>) -> Self {
		match other {
			Some(list) => DomainsValidation::AllowOnly(list),
			None => DomainsValidation::Disabled,
		}
	}
}

/// Convenient JSON-RPC HTTP Server builder.
pub struct ServerBuilder {
	jsonrpc_handler: Arc<IoHandler>,
	cors_domains: Option<Vec<AccessControlAllowOrigin>>,
	allowed_hosts: Option<Vec<String>>,
	panic_handler: Option<Box<Fn() -> () + Send>>,
}

impl ServerBuilder {
	/// Creates new `ServerBuilder` with specified `IoHandler`.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn new(jsonrpc_handler: Arc<IoHandler>) -> Self {
		ServerBuilder {
			jsonrpc_handler: jsonrpc_handler,
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Sets handler invoked in case of server panic.
	pub fn panic_handler<F>(mut self, handler: F) -> Self where F : Fn() -> () + Send + 'static {
		self.panic_handler = Some(Box::new(handler));
		self
	}

	/// Configures a list of allowed CORS origins.
	pub fn cors(mut self, cors_domains: DomainsValidation<AccessControlAllowOrigin>) -> Self {
		self.cors_domains = cors_domains.into();
		self
	}

	/// Allow connections only with `Host` header set to binding address.
	pub fn allow_only_bind_host(mut self) -> Self {
		self.allowed_hosts = Some(Vec::new());
		self
	}

	/// Specify a list of valid `Host` headers. Binding address is allowed automatically.
	pub fn allowed_hosts(mut self, allowed_hosts: DomainsValidation<String>) -> Self {
		self.allowed_hosts = allowed_hosts.into();
		self
	}

	/// Start this JSON-RPC HTTP server trying to bind to specified `SocketAddr`.
	pub fn start_http(self, addr: &SocketAddr) -> ServerResult {
		let panic_for_server = Arc::new(Mutex::new(self.panic_handler));
		let jsonrpc_handler = self.jsonrpc_handler;
		let cors_domains = self.cors_domains;
		let hosts = Arc::new(Mutex::new(self.allowed_hosts));
		let hosts_setter = hosts.clone();

		let (l, srv) = try!(try!(hyper::Server::http(addr)).handle(move |_| {
			let handler = PanicHandler { handler: panic_for_server.clone() };
			let hosts = hosts.lock().unwrap().clone();
			ServerHandler::new(jsonrpc_handler.clone(), cors_domains.clone(), hosts, handler)
		}));

		// Add current host to allowed headers.
		// NOTE: we need to use `l.addr()` instead of `addr`
		// it might be different!
		{
			let mut hosts = hosts_setter.lock().unwrap();
			if let Some(ref mut hosts) = *hosts {
				let address = format!("{}", l.addr());
				hosts.push(address.clone());
				hosts.push(address.replace("127.0.0.1", "localhost"));
			}
		}

		thread::spawn(move || {
			srv.run();
		});

		Ok(Server {
			server: Some(l),
		})
	}
}

/// jsonrpc http server instance
pub struct Server {
	server: Option<server::Listening>,
}

impl Server {
	/// Returns address of this server
	pub fn addr(&self) -> &SocketAddr {
		self.server.as_ref().unwrap().addr()
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close()
	}
}
<commit_msg>Fixing to_string<commit_after>//! jsonrpc http server.
//!
//! ```no_run
//! extern crate jsonrpc_core;
//! extern crate jsonrpc_http_server;
//!
//! use std::sync::Arc;
//! use jsonrpc_core::*;
//! use jsonrpc_http_server::*;
//!
//! struct SayHello;
//! impl MethodCommand for SayHello {
//! 	fn execute(&self, _params: Params) -> Result<Value, Error> {
//! 		Ok(Value::String("hello".to_string()))
//! 	}
//! }
//!
//! fn main() {
//! 	let io = IoHandler::new();
//! 	io.add_method("say_hello", SayHello);
//! 	let _server = ServerBuilder::new(Arc::new(io)).start_http(&"127.0.0.1:3030".parse().unwrap());
//! }
//! ```

#![warn(missing_docs)]

extern crate hyper;
extern crate unicase;
extern crate jsonrpc_core as jsonrpc;

pub mod request_response;
mod cors;
mod handler;
mod hosts_validator;
#[cfg(test)]
mod tests;

use std::sync::{Arc, Mutex};
use std::net::SocketAddr;
use std::thread;
use hyper::server;
use jsonrpc::IoHandler;

pub use hyper::header::AccessControlAllowOrigin;
pub use handler::{PanicHandler, ServerHandler};
pub use hosts_validator::is_host_header_valid;

/// Result of starting the Server.
pub type ServerResult = Result<Server, RpcServerError>;

/// RPC Server startup error.
#[derive(Debug)]
pub enum RpcServerError {
	/// IO Error
	IoError(std::io::Error),
	/// Other Error (hyper)
	Other(hyper::error::Error),
}

impl From<hyper::error::Error> for RpcServerError {
	fn from(err: hyper::error::Error) -> Self {
		match err {
			hyper::error::Error::Io(e) => RpcServerError::IoError(e),
			e => RpcServerError::Other(e)
		}
	}
}

/// Specifies if domains should be validated.
pub enum DomainsValidation<T> {
	/// Allow only domains on the list.
	AllowOnly(Vec<T>),
	/// Disable domains validation completely.
	Disabled,
}

impl<T> Into<Option<Vec<T>>> for DomainsValidation<T> {
	fn into(self) -> Option<Vec<T>> {
		use DomainsValidation::*;
		match self {
			AllowOnly(list) => Some(list),
			Disabled => None,
		}
	}
}

impl<T> From<Option<Vec<T>>> for DomainsValidation<T> {
	fn from(other: Option<Vec<T>>) -> Self {
		match other {
			Some(list) => DomainsValidation::AllowOnly(list),
			None => DomainsValidation::Disabled,
		}
	}
}

/// Convenient JSON-RPC HTTP Server builder.
pub struct ServerBuilder {
	jsonrpc_handler: Arc<IoHandler>,
	cors_domains: Option<Vec<AccessControlAllowOrigin>>,
	allowed_hosts: Option<Vec<String>>,
	panic_handler: Option<Box<Fn() -> () + Send>>,
}

impl ServerBuilder {
	/// Creates new `ServerBuilder` with specified `IoHandler`.
	///
	/// By default:
	/// 1. Server is not sending any CORS headers.
	/// 2. Server is validating `Host` header.
	pub fn new(jsonrpc_handler: Arc<IoHandler>) -> Self {
		ServerBuilder {
			jsonrpc_handler: jsonrpc_handler,
			cors_domains: None,
			allowed_hosts: None,
			panic_handler: None,
		}
	}

	/// Sets handler invoked in case of server panic.
	pub fn panic_handler<F>(mut self, handler: F) -> Self where F : Fn() -> () + Send + 'static {
		self.panic_handler = Some(Box::new(handler));
		self
	}

	/// Configures a list of allowed CORS origins.
	pub fn cors(mut self, cors_domains: DomainsValidation<AccessControlAllowOrigin>) -> Self {
		self.cors_domains = cors_domains.into();
		self
	}

	/// Allow connections only with `Host` header set to binding address.
	pub fn allow_only_bind_host(mut self) -> Self {
		self.allowed_hosts = Some(Vec::new());
		self
	}

	/// Specify a list of valid `Host` headers. Binding address is allowed automatically.
	pub fn allowed_hosts(mut self, allowed_hosts: DomainsValidation<String>) -> Self {
		self.allowed_hosts = allowed_hosts.into();
		self
	}

	/// Start this JSON-RPC HTTP server trying to bind to specified `SocketAddr`.
	pub fn start_http(self, addr: &SocketAddr) -> ServerResult {
		let panic_for_server = Arc::new(Mutex::new(self.panic_handler));
		let jsonrpc_handler = self.jsonrpc_handler;
		let cors_domains = self.cors_domains;
		let hosts = Arc::new(Mutex::new(self.allowed_hosts));
		let hosts_setter = hosts.clone();

		let (l, srv) = try!(try!(hyper::Server::http(addr)).handle(move |_| {
			let handler = PanicHandler { handler: panic_for_server.clone() };
			let hosts = hosts.lock().unwrap().clone();
			ServerHandler::new(jsonrpc_handler.clone(), cors_domains.clone(), hosts, handler)
		}));

		// Add current host to allowed headers.
		// NOTE: we need to use `l.addr()` instead of `addr`
		// it might be different!
		{
			let mut hosts = hosts_setter.lock().unwrap();
			if let Some(ref mut hosts) = *hosts {
				let address = l.addr().to_string();
				hosts.push(address.clone());
				hosts.push(address.replace("127.0.0.1", "localhost"));
			}
		}

		thread::spawn(move || {
			srv.run();
		});

		Ok(Server {
			server: Some(l),
		})
	}
}

/// jsonrpc http server instance
pub struct Server {
	server: Option<server::Listening>,
}

impl Server {
	/// Returns address of this server
	pub fn addr(&self) -> &SocketAddr {
		self.server.as_ref().unwrap().addr()
	}
}

impl Drop for Server {
	fn drop(&mut self) {
		self.server.take().unwrap().close()
	}
}
<|endoftext|>


<commit_before>#![feature(core)]
#![feature(collections)]

extern crate curl;
extern crate url;
extern crate "rustc-serialize" as rustc_serialize;
extern crate regex;

use std::collections::BTreeMap;
use curl::http;
use url::form_urlencoded;
use rustc_serialize::json::{self, ToJson};
use self::Parameters::*;

pub mod config;

/// Optional parameters for Pushover API messages
#[derive(PartialEq, Clone)]
pub enum Parameters {
    /// A numeric priority from -2 (lowest priority) to 2 (emergency priority)
    /// (Default: 0)
    Priority(i8),
    /// A title for the push notification
    Title(String),
    /// A string identifying the device to send the notification to
    Device(String),
    /// The notification sound to play (out of the Pushover-supported sounds)
    Sound(String),
    /// A supplementary URL to send with the notification
    URL(String),
    /// A title to give the supplementary URL
    URLTitle(String),
    /// Gist the full message body and link it as a supplementary URL with
    /// title "Full Output (GitHub Gist)". This option supersedes the URL and
    /// URLTitle options if those are also provided.
    Gist,
    /// Enable debugging output
    Debug
}

#[derive(RustcDecodable)]
struct MessagesJson {
    status: isize,
    errors: Vec<String>
}

#[derive(RustcEncodable)]
struct GistPost {
    files: BTreeMap<String, json::Json>
}

#[derive(RustcDecodable)]
struct GistResponse {
    html_url: String
}

fn api_error(response_body: &str) -> Result<(), Vec<String>> {
    let response: MessagesJson = json::decode(response_body).unwrap();

    if response.status != 1 {
        return Err(response.errors);
    }

    Err(vec![format!("general API error")])
}

/// Post a message body with a given title to GitHub Gist and return the Gist's
/// URL.
pub fn gist(message: &str, title: String) -> Result<String, (u32, String)> {
    let mut content = BTreeMap::new();
    content.insert("content".to_string(), message.to_json());
    let mut gist_file = BTreeMap::new();
    gist_file.insert(title, content.to_json());
    let gist = GistPost {
        files: gist_file
    };

    if let Ok(json) = json::encode(&gist) {
        let mut handle = http::handle();
        let upload = handle
                        .post("https://api.github.com/gists", json.as_slice())
                        .header("Content-Type", "application/json")
                        .header("User-Agent", "po");
        if let Ok(res) = upload.exec() {
            if res.get_code() == 201 || res.get_code() == 200 {
                let body = std::str::from_utf8(res.get_body()).unwrap();
                let response: GistResponse = json::decode(body).unwrap();
                return Ok(response.html_url);
            }
        }
    }

    Err((0, format!("Generic: Couldn't post to Gist.")))
}
/// Pushes a message using the Pushover API, with the specified API token,
/// user key, message body, and array of optional Parameters.
pub fn push(token: &str, user: &str, message: &str,
                       parameters: &[Parameters]) -> Result<(), Vec<String>> {
    // Keep these here for now to satisfy the borrow checker:
    let msg = if message.len() > 1024 {
        message[0..1024].as_slice()
    }
    else {
        message
    };
    let mut title = "po".to_string();
    let mut debug = false;

    let mut notification = vec![
        ("token".to_string(), token.to_string()),
        ("user".to_string(), user.to_string()),
        ("message".to_string(), msg.to_string())];

    // Copy the parameters collection into a vector we own; slightly inefficent
    // but much more convenient for the caller.
    let mut para = Vec::new();
    para.push_all(parameters);

    for parameter in para.into_iter() {
        match parameter {
            Priority(p)  => notification.push(("priority".to_string(), p.to_string())),
            Title(t)     => {
                notification.push(("title".to_string(), t.clone()));
                title = t;
            },
            Device(d)    => notification.push(("device".to_string(), d)),
            Sound(s)     => notification.push(("sound".to_string(), s)),
            URL(u)       => notification.push(("url".to_string(), u)),
            URLTitle(ut) => notification.push(("url_title".to_string(), ut)),
            Gist         => {
                if let Ok(gist_url) = gist(message, title.clone()) {
                    notification.push(("url".to_string(), gist_url));
                    notification.push(("url_title".to_string(),
                        "Full Output (GitHub Gist)".to_string()));
                }
            },
            Debug        => debug = true
        }
    }

    let body = form_urlencoded::serialize_owned(notification.as_slice());
    if debug {
        println!("push body:\n{}", body);
    }
    let mut handle = http::handle();
    let message = handle
                    .post("https://api.pushover.net/1/messages.json", body.as_slice())
                    .header("Content-Type", "application/x-www-form-urlencoded");
    match message.exec() {
        Ok(res) => {
            match res.get_code() {
                200 => Ok(()),
                400...499 => api_error(std::str::from_utf8(res.get_body()).unwrap()),
                n => Err(vec![format!("API error {}", n)])
            }
        },
        Err(code) => Err(vec![format!("curl error {}", code)])
    }
}

pub fn send_with_url(token: &str, user: &str, message: &str, priority: i8,
            title: Option<&str>, device: Option<&str>,
            sound: Option<&str>, url: Option<&str>,
            url_title: Option<&str>) -> Result<(), Vec<String>> {
    let mut parameters: Vec<Parameters> = vec![Parameters::Priority(priority)];

    if let Some(t) = title {
        parameters.push(Parameters::Title(t.to_string()));
    }
    if let Some(d) = device {
        parameters.push(Parameters::Device(d.to_string()));
    }
    if let Some(s) = sound {
        parameters.push(Parameters::Sound(s.to_string()));
    }
    if let Some(u) = url {
        parameters.push(Parameters::URL(u.to_string()));
    }
    if let Some(ut) = url_title {
        parameters.push(Parameters::URLTitle(ut.to_string()));
    }
    push(token, user, message, parameters.as_slice())
}

pub fn send(token: &str, user: &str, message: &str, priority: i8,
            title: Option<&str>, device: Option<&str>,
            sound: Option<&str>) -> Result<(), Vec<String>> {
    send_with_url(token, user, message, priority, title, device, sound, None, None)
}

pub fn send_gist(token: &str, user: &str, message: &str, priority: i8,
                 title: Option<&str>, device: Option<&str>,
                 sound: Option<&str>) -> Result<(), Vec<String>> {
    let mut parameters: Vec<Parameters> = vec![Parameters::Priority(priority)];

    if let Some(t) = title {
        parameters.push(Parameters::Title(t.to_string()));
    }
    if let Some(d) = device {
        parameters.push(Parameters::Device(d.to_string()));
    }
    if let Some(s) = sound {
        parameters.push(Parameters::Sound(s.to_string()));
    }
    parameters.push(Parameters::Gist);
    push(token, user, message, parameters.as_slice())
}

/// Send a basic push notification with just an API token, user key, and
/// message body.
pub fn send_basic(token: &str, user: &str,
                  message: &str) -> Result<(), Vec<String>> {
    return push(token, user, message, vec![].as_slice());
}
<commit_msg>Another documentation bump<commit_after>//! A library for sending push notifications using the Pushover API.
//! Repository and command-line client documentation is
//! [here](https://github.com/unjordy/po).
#![feature(core)]
#![feature(collections)]

extern crate curl;
extern crate url;
extern crate "rustc-serialize" as rustc_serialize;
extern crate regex;

use std::collections::BTreeMap;
use curl::http;
use url::form_urlencoded;
use rustc_serialize::json::{self, ToJson};
use self::Parameters::*;

pub mod config;

/// Optional parameters for Pushover API messages
#[derive(PartialEq, Clone)]
pub enum Parameters {
    /// A numeric priority from -2 (lowest priority) to 2 (emergency priority)
    /// (Default: 0)
    Priority(i8),
    /// A title for the push notification
    Title(String),
    /// A string identifying the device to send the notification to
    Device(String),
    /// The notification sound to play (out of the Pushover-supported sounds)
    Sound(String),
    /// A supplementary URL to send with the notification
    URL(String),
    /// A title to give the supplementary URL
    URLTitle(String),
    /// Gist the full message body and link it as a supplementary URL with
    /// title "Full Output (GitHub Gist)". This option supersedes the URL and
    /// URLTitle options if those are also provided.
    Gist,
    /// Enable debugging output
    Debug
}

#[derive(RustcDecodable)]
struct MessagesJson {
    status: isize,
    errors: Vec<String>
}

#[derive(RustcEncodable)]
struct GistPost {
    files: BTreeMap<String, json::Json>
}

#[derive(RustcDecodable)]
struct GistResponse {
    html_url: String
}

fn api_error(response_body: &str) -> Result<(), Vec<String>> {
    let response: MessagesJson = json::decode(response_body).unwrap();

    if response.status != 1 {
        return Err(response.errors);
    }

    Err(vec![format!("general API error")])
}

/// Post a message body with a given title to GitHub Gist and return the Gist's
/// URL.
pub fn gist(message: &str, title: String) -> Result<String, (u32, String)> {
    let mut content = BTreeMap::new();
    content.insert("content".to_string(), message.to_json());
    let mut gist_file = BTreeMap::new();
    gist_file.insert(title, content.to_json());
    let gist = GistPost {
        files: gist_file
    };

    if let Ok(json) = json::encode(&gist) {
        let mut handle = http::handle();
        let upload = handle
                        .post("https://api.github.com/gists", json.as_slice())
                        .header("Content-Type", "application/json")
                        .header("User-Agent", "po");
        if let Ok(res) = upload.exec() {
            if res.get_code() == 201 || res.get_code() == 200 {
                let body = std::str::from_utf8(res.get_body()).unwrap();
                let response: GistResponse = json::decode(body).unwrap();
                return Ok(response.html_url);
            }
        }
    }

    Err((0, format!("Generic: Couldn't post to Gist.")))
}
/// Pushes a message using the Pushover API, with the specified API token,
/// user key, message body, and array of optional Parameters.
pub fn push(token: &str, user: &str, message: &str,
                       parameters: &[Parameters]) -> Result<(), Vec<String>> {
    // Keep these here for now to satisfy the borrow checker:
    let msg = if message.len() > 1024 {
        message[0..1024].as_slice()
    }
    else {
        message
    };
    let mut title = "po".to_string();
    let mut debug = false;

    let mut notification = vec![
        ("token".to_string(), token.to_string()),
        ("user".to_string(), user.to_string()),
        ("message".to_string(), msg.to_string())];

    // Copy the parameters collection into a vector we own; slightly inefficent
    // but much more convenient for the caller.
    let mut para = Vec::new();
    para.push_all(parameters);

    for parameter in para.into_iter() {
        match parameter {
            Priority(p)  => notification.push(("priority".to_string(), p.to_string())),
            Title(t)     => {
                notification.push(("title".to_string(), t.clone()));
                title = t;
            },
            Device(d)    => notification.push(("device".to_string(), d)),
            Sound(s)     => notification.push(("sound".to_string(), s)),
            URL(u)       => notification.push(("url".to_string(), u)),
            URLTitle(ut) => notification.push(("url_title".to_string(), ut)),
            Gist         => {
                if let Ok(gist_url) = gist(message, title.clone()) {
                    notification.push(("url".to_string(), gist_url));
                    notification.push(("url_title".to_string(),
                        "Full Output (GitHub Gist)".to_string()));
                }
            },
            Debug        => debug = true
        }
    }

    let body = form_urlencoded::serialize_owned(notification.as_slice());
    if debug {
        println!("push body:\n{}", body);
    }
    let mut handle = http::handle();
    let message = handle
                    .post("https://api.pushover.net/1/messages.json", body.as_slice())
                    .header("Content-Type", "application/x-www-form-urlencoded");
    match message.exec() {
        Ok(res) => {
            match res.get_code() {
                200 => Ok(()),
                400...499 => api_error(std::str::from_utf8(res.get_body()).unwrap()),
                n => Err(vec![format!("API error {}", n)])
            }
        },
        Err(code) => Err(vec![format!("curl error {}", code)])
    }
}

pub fn send_with_url(token: &str, user: &str, message: &str, priority: i8,
            title: Option<&str>, device: Option<&str>,
            sound: Option<&str>, url: Option<&str>,
            url_title: Option<&str>) -> Result<(), Vec<String>> {
    let mut parameters: Vec<Parameters> = vec![Parameters::Priority(priority)];

    if let Some(t) = title {
        parameters.push(Parameters::Title(t.to_string()));
    }
    if let Some(d) = device {
        parameters.push(Parameters::Device(d.to_string()));
    }
    if let Some(s) = sound {
        parameters.push(Parameters::Sound(s.to_string()));
    }
    if let Some(u) = url {
        parameters.push(Parameters::URL(u.to_string()));
    }
    if let Some(ut) = url_title {
        parameters.push(Parameters::URLTitle(ut.to_string()));
    }
    push(token, user, message, parameters.as_slice())
}

pub fn send(token: &str, user: &str, message: &str, priority: i8,
            title: Option<&str>, device: Option<&str>,
            sound: Option<&str>) -> Result<(), Vec<String>> {
    send_with_url(token, user, message, priority, title, device, sound, None, None)
}

pub fn send_gist(token: &str, user: &str, message: &str, priority: i8,
                 title: Option<&str>, device: Option<&str>,
                 sound: Option<&str>) -> Result<(), Vec<String>> {
    let mut parameters: Vec<Parameters> = vec![Parameters::Priority(priority)];

    if let Some(t) = title {
        parameters.push(Parameters::Title(t.to_string()));
    }
    if let Some(d) = device {
        parameters.push(Parameters::Device(d.to_string()));
    }
    if let Some(s) = sound {
        parameters.push(Parameters::Sound(s.to_string()));
    }
    parameters.push(Parameters::Gist);
    push(token, user, message, parameters.as_slice())
}

/// Send a basic push notification with just an API token, user key, and
/// message body.
pub fn send_basic(token: &str, user: &str,
                  message: &str) -> Result<(), Vec<String>> {
    return push(token, user, message, vec![].as_slice());
}
<|endoftext|>


<commit_before>extern crate iron;

extern crate r2d2;
extern crate r2d2_postgres;
extern crate postgres;

use iron::prelude::*;
use iron::{typemap, BeforeMiddleware};

use std::sync::Arc;
use std::default::Default;
use postgres::{SslMode};
use r2d2_postgres::PostgresConnectionManager;

pub struct PostgresMiddleware {
  pub pool: Arc<r2d2::Pool<r2d2_postgres::PostgresConnectionManager, r2d2::LoggingErrorHandler>>,
}

struct Value(Arc<r2d2::Pool<r2d2_postgres::PostgresConnectionManager, r2d2::LoggingErrorHandler>>);

impl typemap::Key for PostgresMiddleware { type Value = Value; }

impl PostgresMiddleware {
  pub fn new(pg_connection_str: &str) -> PostgresMiddleware {
    let config = Default::default();
    let manager = PostgresConnectionManager::new(pg_connection_str, SslMode::None);
    let error_handler = r2d2::LoggingErrorHandler;
    let pool = Arc::new(r2d2::Pool::new(config, manager, error_handler).unwrap());
    PostgresMiddleware {
      pool: pool,
    }
  }
}

impl BeforeMiddleware for PostgresMiddleware {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<PostgresMiddleware>(Value(self.pool.clone()));
        Ok(())
    }
}

pub trait PostgresReqExt {
  fn db_conn(&self) -> r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager,
    r2d2::LoggingErrorHandler>;
}

impl PostgresReqExt for Request {
  fn db_conn(&self) -> r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager,
    r2d2::LoggingErrorHandler> {
    let poll_value = self.extensions.get::<PostgresMiddleware>().unwrap();
    let &Value(ref poll) = poll_value;

    return poll.get().unwrap();
  }
}
<commit_msg>(fix) compilation for latest iron<commit_after>extern crate iron;

extern crate r2d2;
extern crate r2d2_postgres;
extern crate postgres;

use iron::prelude::*;
use iron::{typemap, BeforeMiddleware};

use std::sync::Arc;
use std::default::Default;
use postgres::{SslMode};
use r2d2_postgres::PostgresConnectionManager;

pub struct PostgresMiddleware {
  pub pool: Arc<r2d2::Pool<r2d2_postgres::PostgresConnectionManager, r2d2::LoggingErrorHandler>>,
}

struct Value(Arc<r2d2::Pool<r2d2_postgres::PostgresConnectionManager, r2d2::LoggingErrorHandler>>);

impl typemap::Key for PostgresMiddleware { type Value = Value; }

impl PostgresMiddleware {
  pub fn new(pg_connection_str: &str) -> PostgresMiddleware {
    let config = Default::default();
    let manager = PostgresConnectionManager::new(pg_connection_str, SslMode::None);
    let error_handler = r2d2::LoggingErrorHandler;
    let pool = Arc::new(r2d2::Pool::new(config, manager, error_handler).unwrap());
    PostgresMiddleware {
      pool: pool,
    }
  }
}

impl BeforeMiddleware for PostgresMiddleware {
    fn before(&self, req: &mut Request) -> IronResult<()> {
        req.extensions.insert::<PostgresMiddleware>(Value(self.pool.clone()));
        Ok(())
    }
}

pub trait PostgresReqExt {
  fn db_conn(&self) -> r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager,
    r2d2::LoggingErrorHandler>;
}

impl<'a> PostgresReqExt for Request<'a> {
  fn db_conn(&self) -> r2d2::PooledConnection<r2d2_postgres::PostgresConnectionManager,
    r2d2::LoggingErrorHandler> {
    let poll_value = self.extensions.get::<PostgresMiddleware>().unwrap();
    let &Value(ref poll) = poll_value;

    return poll.get().unwrap();
  }
}
<|endoftext|>