<commit_before>
//! This library implements string similarity metrics. Currently includes
//! Hamming, Levenshtein, Jaro, and Jaro-Winkler.

#![feature(test, core, collections)]

extern crate test;

use std::cmp::{max, min};
use std::collections::Bitv;

#[derive(Debug, PartialEq)]
pub enum StrSimError {
    DifferentLengthArgs
}

pub type HammingResult = Result<usize, StrSimError>;

#[doc = "
Calculates the number of positions in the two strings where the characters
differ. Returns an error if the strings have different lengths.
"]
pub fn hamming(a: &str, b: &str) -> HammingResult {
    if a.len() != b.len() {
        Err(StrSimError::DifferentLengthArgs)
    } else {
        Ok(a.chars()
            .zip(b.chars())
            .filter(|&(a_char, b_char)| a_char != b_char)
            .count())
    }
}

#[doc = "
Calculates the Jaro similarity between two strings. The returned value
is between 0.0 and 1.0 (where 1.0 means the strings are equal).
"]
pub fn jaro(a: &str, b: &str) -> f64 {
    if a == b { return 1.0; }
    if a.len() == 0 || b.len() == 0 { return 0.0; }

    let search_range = max(0, (max(a.len(), b.len()) / 2) - 1);

    let mut b_consumed = Bitv::from_elem(b.len(), false);
    let mut matches = 0.0;

    let mut transpositions = 0.0;
    let mut b_match_index = 0;

    for (i, a_char) in a.chars().enumerate() {
        let min_bound =
            // prevent integer wrapping
            if i > search_range {
                max(0, i - search_range)
            } else {
                0
            };
        let max_bound = min(b.len() - 1, i + search_range);

        for j in min_bound..max_bound + 1 {
            let b_char = b.char_at(j);
            if a_char == b_char && !b_consumed[j] {
                b_consumed.set(j, true);
                matches += 1.0;

                if j < b_match_index {
                    transpositions += 1.0;
                }
                b_match_index = j;

                break;
            }
        }
    }

    if matches == 0.0 {
        0.0
    } else {
        (1.0 / 3.0) * ((matches / a.len() as f64) +
                       (matches / b.len() as f64) +
                       ((matches - transpositions) / matches))
    }
}

#[doc = "
Similar to Jaro but gives a boost to strings that have a common prefix.
"]
pub fn jaro_winkler(a: &str, b: &str) -> f64 {
    let jaro_distance = jaro(a, b);

    // Don't limit the length of the common prefix
    let prefix_length = a.chars()
                         .zip(b.chars())
                         .take_while(|&(a_char, b_char)| a_char == b_char)
                         .count();

    let jaro_winkler_distance =
        jaro_distance + (0.1 * prefix_length as f64 * (1.0 - jaro_distance));

    if jaro_winkler_distance <= 1.0 {
        jaro_winkler_distance
    } else {
        1.0
    }
}

#[doc = "
Calculates the minimum number of insertions, deletions, and substitutions
required to change one string into the other.
"]
pub fn levenshtein(a: &str, b: &str) -> usize {
    if a == b { return 0; }
    else if a.len() == 0 { return b.len(); }
    else if b.len() == 0 { return a.len(); }

    let mut prev_distances: Vec<usize> = Vec::with_capacity(b.len() + 1);
    let mut curr_distances: Vec<usize> = Vec::with_capacity(b.len() + 1);

    for i in 0..(b.len() + 1) {
        prev_distances.push(i);
        curr_distances.push(0);
    }

    for (i, a_char) in a.chars().enumerate() {
        curr_distances[0] = i + 1;

        for (j, b_char) in b.chars().enumerate() {
            let cost = if a_char == b_char { 0 } else { 1 };
            curr_distances[j + 1] = min(curr_distances[j] + 1,
                                        min(prev_distances[j + 1] + 1,
                                            prev_distances[j] + cost));
        }

        prev_distances.clone_from(&curr_distances);
    }

    curr_distances[b.len()]
}

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

    #[test]
    fn hamming_empty() {
        match hamming("", "") {
            Ok(distance) => { assert_eq!(0, distance); },
            Err(why) => { panic!("{:?}", why); }
        }
    }

    #[test]
    fn hamming_same() {
        match hamming("hamming", "hamming") {
            Ok(distance) => { assert_eq!(0, distance); },
            Err(why) => { panic!("{:?}", why); }
        }
    }

    #[test]
    fn hamming_diff() {
        match hamming("hamming", "hammers") {
            Ok(distance) => { assert_eq!(3, distance); },
            Err(why) => { panic!("{:?}", why); }
        }
    }

    #[test]
    fn hamming_unequal_length() {
        match hamming("ham", "hamming") {
            Ok(_) => { panic!(); },
            Err(why) => { assert_eq!(why, StrSimError::DifferentLengthArgs); }
        }
    }

    #[test]
    fn hamming_names() {
        match hamming("Friedrich Nietzs", "Jean-Paul Sartre") {
            Ok(distance) => { assert_eq!(14, distance); },
            Err(why) => { panic!("{:?}", why); }
        }
    }

    #[test]
    fn jaro_both_empty() {
       assert_eq!(1.0, jaro("", ""));
    }

    #[test]
    fn jaro_first_empty() {
        assert_eq!(0.0, jaro("", "jaro"));
    }

    #[test]
    fn jaro_second_empty() {
        assert_eq!(0.0, jaro("distance", ""));
    }

    #[test]
    fn jaro_same() {
        assert_eq!(1.0, jaro("jaro", "jaro"));
    }

    #[test]
    fn jaro_diff_short() {
        assert!((0.767 - jaro("dixon", "dicksonx")).abs() < 0.001);
    }

    #[test]
    fn jaro_diff_no_transposition() {
        assert!((0.822 - jaro("dwayne", "duane")).abs() < 0.001);
    }

    #[test]
    fn jaro_diff_with_transposition() {
        assert!((0.944 - jaro("martha", "marhta")).abs() < 0.001);
    }

    #[test]
    fn jaro_names() {
        assert!((0.392 - jaro("Friedrich Nietzsche",
                              "Jean-Paul Sartre")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_both_empty() {
        assert_eq!(1.0, jaro_winkler("", ""));
    }

    #[test]
    fn jaro_winkler_first_empty() {
        assert_eq!(0.0, jaro_winkler("", "jaro-winkler"));
    }

    #[test]
    fn jaro_winkler_second_empty() {
        assert_eq!(0.0, jaro_winkler("distance", ""));
    }

    #[test]
    fn jaro_winkler_same() {
        assert_eq!(1.0, jaro_winkler("Jaro-Winkler", "Jaro-Winkler"));
    }

    #[test]
    fn jaro_winkler_diff_short() {
        assert!((0.813 - jaro_winkler("dixon", "dicksonx")).abs() < 0.001);
        assert!((0.813 - jaro_winkler("dicksonx", "dixon")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_diff_no_transposition() {
        assert!((0.840 - jaro_winkler("dwayne", "duane")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_diff_with_transposition() {
        assert!((0.961 - jaro_winkler("martha", "marhta")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_names() {
        assert!((0.562 - jaro_winkler("Friedrich Nietzsche",
                                      "Fran-Paul Sartre")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_long_prefix() {
        assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() <
                0.001);
    }

    #[test]
    fn jaro_winkler_more_names() {
        assert!((0.868 - jaro_winkler("Thorkel", "Thorgier")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_length_of_one() {
        assert!((0.738 - jaro_winkler("Dinsdale", "D")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_very_long_prefix() {
        assert!((1.0 - jaro_winkler("thequickbrownfoxjumpedoverx",
                                    "thequickbrownfoxjumpedovery")).abs() <
                0.001);
    }

    #[test]
    fn levenshtein_empty() {
        assert_eq!(0, levenshtein("", ""));
    }

    #[test]
    fn levenshtein_same() {
        assert_eq!(0, levenshtein("levenshtein", "levenshtein"));
    }

    #[test]
    fn levenshtein_diff_short() {
        assert_eq!(3, levenshtein("kitten", "sitting"));
    }

    #[test]
    fn levenshtein_diff_with_space() {
        assert_eq!(5, levenshtein("hello, world", "bye, world"));
    }

    #[test]
    fn levenshtein_diff_longer() {
        let a = "The quick brown fox jumped over the angry dog.";
        let b = "Lorem ipsum dolor sit amet, dicta latine an eam.";
        assert_eq!(37, levenshtein(a, b));
    }

    #[test]
    fn levenshtein_first_empty() {
        assert_eq!(7, levenshtein("", "sitting"));
    }

    #[test]
    fn levenshtein_second_empty() {
        assert_eq!(6, levenshtein("kitten", ""));
    }

    #[bench]
    fn bench_hamming(b: &mut Bencher) {
        b.iter(|| hamming("Friedrich Nietzs", "Jean-Paul Sartre"));
    }

    #[bench]
    fn bench_levenshtein(b: &mut Bencher) {
        b.iter(|| levenshtein("Friedrich Nietzsche", "Jean-Paul Sartre"));
    }

    #[bench]
    fn bench_jaro(b: &mut Bencher) {
        b.iter(|| jaro("Friedrich Nietzsche", "Jean-Paul Sartre"));
    }
}
<commit_msg>Add doc-tests<commit_after>
//! This library implements string similarity metrics. Currently includes
//! Hamming, Levenshtein, Jaro, and Jaro-Winkler.

#![feature(test, core, collections)]

extern crate test;

use std::cmp::{max, min};
use std::collections::Bitv;

#[derive(Debug, PartialEq)]
pub enum StrSimError {
    DifferentLengthArgs
}

pub type HammingResult = Result<usize, StrSimError>;

/// Calculates the number of positions in the two strings where the characters
/// differ. Returns an error if the strings have different lengths.
///
/// ```
/// use strsim::hamming;
///
/// match hamming("hamming", "hammers") {
///     Ok(distance) => assert_eq!(3, distance),
///     Err(why) => panic!("{:?}", why)
/// }
/// ```
pub fn hamming(a: &str, b: &str) -> HammingResult {
    if a.len() != b.len() {
        Err(StrSimError::DifferentLengthArgs)
    } else {
        Ok(a.chars()
            .zip(b.chars())
            .filter(|&(a_char, b_char)| a_char != b_char)
            .count())
    }
}

/// Calculates the Jaro similarity between two strings. The returned value
/// is between 0.0 and 1.0 (higher value means more similar).
///
/// ```
/// use strsim::jaro;
/// use std::num::Float;
///
/// assert!((0.392 - jaro("Friedrich Nietzsche", "Jean-Paul Sartre")).abs() <
///         0.001);
/// ```
pub fn jaro(a: &str, b: &str) -> f64 {
    if a == b { return 1.0; }
    if a.len() == 0 || b.len() == 0 { return 0.0; }

    let search_range = max(0, (max(a.len(), b.len()) / 2) - 1);

    let mut b_consumed = Bitv::from_elem(b.len(), false);
    let mut matches = 0.0;

    let mut transpositions = 0.0;
    let mut b_match_index = 0;

    for (i, a_char) in a.chars().enumerate() {
        let min_bound =
            // prevent integer wrapping
            if i > search_range {
                max(0, i - search_range)
            } else {
                0
            };
        let max_bound = min(b.len() - 1, i + search_range);

        for j in min_bound..max_bound + 1 {
            let b_char = b.char_at(j);
            if a_char == b_char && !b_consumed[j] {
                b_consumed.set(j, true);
                matches += 1.0;

                if j < b_match_index {
                    transpositions += 1.0;
                }
                b_match_index = j;

                break;
            }
        }
    }

    if matches == 0.0 {
        0.0
    } else {
        (1.0 / 3.0) * ((matches / a.len() as f64) +
                       (matches / b.len() as f64) +
                       ((matches - transpositions) / matches))
    }
}

/// Like Jaro but gives a boost to strings that have a common prefix.
///
/// ```
/// use strsim::jaro_winkler;
/// use std::num::Float;
///
/// assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() <
///         0.001);
/// ```
pub fn jaro_winkler(a: &str, b: &str) -> f64 {
    let jaro_distance = jaro(a, b);

    // Don't limit the length of the common prefix
    let prefix_length = a.chars()
                         .zip(b.chars())
                         .take_while(|&(a_char, b_char)| a_char == b_char)
                         .count();

    let jaro_winkler_distance =
        jaro_distance + (0.1 * prefix_length as f64 * (1.0 - jaro_distance));

    if jaro_winkler_distance <= 1.0 {
        jaro_winkler_distance
    } else {
        1.0
    }
}

/// Calculates the minimum number of insertions, deletions, and substitutions
/// required to change one string into the other.
///
/// ```
/// use strsim::levenshtein;
///
/// assert_eq!(3, levenshtein("kitten", "sitting"));
/// ```
pub fn levenshtein(a: &str, b: &str) -> usize {
    if a == b { return 0; }
    else if a.len() == 0 { return b.len(); }
    else if b.len() == 0 { return a.len(); }

    let mut prev_distances: Vec<usize> = Vec::with_capacity(b.len() + 1);
    let mut curr_distances: Vec<usize> = Vec::with_capacity(b.len() + 1);

    for i in 0..(b.len() + 1) {
        prev_distances.push(i);
        curr_distances.push(0);
    }

    for (i, a_char) in a.chars().enumerate() {
        curr_distances[0] = i + 1;

        for (j, b_char) in b.chars().enumerate() {
            let cost = if a_char == b_char { 0 } else { 1 };
            curr_distances[j + 1] = min(curr_distances[j] + 1,
                                        min(prev_distances[j + 1] + 1,
                                            prev_distances[j] + cost));
        }

        prev_distances.clone_from(&curr_distances);
    }

    curr_distances[b.len()]
}

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

    #[test]
    fn hamming_empty() {
        match hamming("", "") {
            Ok(distance) => { assert_eq!(0, distance); },
            Err(why) => { panic!("{:?}", why); }
        }
    }

    #[test]
    fn hamming_same() {
        match hamming("hamming", "hamming") {
            Ok(distance) => { assert_eq!(0, distance); },
            Err(why) => { panic!("{:?}", why); }
        }
    }

    #[test]
    fn hamming_diff() {
        match hamming("hamming", "hammers") {
            Ok(distance) => { assert_eq!(3, distance); },
            Err(why) => { panic!("{:?}", why); }
        }
    }

    #[test]
    fn hamming_unequal_length() {
        match hamming("ham", "hamming") {
            Ok(_) => { panic!(); },
            Err(why) => { assert_eq!(why, StrSimError::DifferentLengthArgs); }
        }
    }

    #[test]
    fn hamming_names() {
        match hamming("Friedrich Nietzs", "Jean-Paul Sartre") {
            Ok(distance) => { assert_eq!(14, distance); },
            Err(why) => { panic!("{:?}", why); }
        }
    }

    #[test]
    fn jaro_both_empty() {
       assert_eq!(1.0, jaro("", ""));
    }

    #[test]
    fn jaro_first_empty() {
        assert_eq!(0.0, jaro("", "jaro"));
    }

    #[test]
    fn jaro_second_empty() {
        assert_eq!(0.0, jaro("distance", ""));
    }

    #[test]
    fn jaro_same() {
        assert_eq!(1.0, jaro("jaro", "jaro"));
    }

    #[test]
    fn jaro_diff_short() {
        assert!((0.767 - jaro("dixon", "dicksonx")).abs() < 0.001);
    }

    #[test]
    fn jaro_diff_no_transposition() {
        assert!((0.822 - jaro("dwayne", "duane")).abs() < 0.001);
    }

    #[test]
    fn jaro_diff_with_transposition() {
        assert!((0.944 - jaro("martha", "marhta")).abs() < 0.001);
    }

    #[test]
    fn jaro_names() {
        assert!((0.392 - jaro("Friedrich Nietzsche",
                              "Jean-Paul Sartre")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_both_empty() {
        assert_eq!(1.0, jaro_winkler("", ""));
    }

    #[test]
    fn jaro_winkler_first_empty() {
        assert_eq!(0.0, jaro_winkler("", "jaro-winkler"));
    }

    #[test]
    fn jaro_winkler_second_empty() {
        assert_eq!(0.0, jaro_winkler("distance", ""));
    }

    #[test]
    fn jaro_winkler_same() {
        assert_eq!(1.0, jaro_winkler("Jaro-Winkler", "Jaro-Winkler"));
    }

    #[test]
    fn jaro_winkler_diff_short() {
        assert!((0.813 - jaro_winkler("dixon", "dicksonx")).abs() < 0.001);
        assert!((0.813 - jaro_winkler("dicksonx", "dixon")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_diff_no_transposition() {
        assert!((0.840 - jaro_winkler("dwayne", "duane")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_diff_with_transposition() {
        assert!((0.961 - jaro_winkler("martha", "marhta")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_names() {
        assert!((0.562 - jaro_winkler("Friedrich Nietzsche",
                                      "Fran-Paul Sartre")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_long_prefix() {
        assert!((0.911 - jaro_winkler("cheeseburger", "cheese fries")).abs() <
                0.001);
    }

    #[test]
    fn jaro_winkler_more_names() {
        assert!((0.868 - jaro_winkler("Thorkel", "Thorgier")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_length_of_one() {
        assert!((0.738 - jaro_winkler("Dinsdale", "D")).abs() < 0.001);
    }

    #[test]
    fn jaro_winkler_very_long_prefix() {
        assert!((1.0 - jaro_winkler("thequickbrownfoxjumpedoverx",
                                    "thequickbrownfoxjumpedovery")).abs() <
                0.001);
    }

    #[test]
    fn levenshtein_empty() {
        assert_eq!(0, levenshtein("", ""));
    }

    #[test]
    fn levenshtein_same() {
        assert_eq!(0, levenshtein("levenshtein", "levenshtein"));
    }

    #[test]
    fn levenshtein_diff_short() {
        assert_eq!(3, levenshtein("kitten", "sitting"));
    }

    #[test]
    fn levenshtein_diff_with_space() {
        assert_eq!(5, levenshtein("hello, world", "bye, world"));
    }

    #[test]
    fn levenshtein_diff_longer() {
        let a = "The quick brown fox jumped over the angry dog.";
        let b = "Lorem ipsum dolor sit amet, dicta latine an eam.";
        assert_eq!(37, levenshtein(a, b));
    }

    #[test]
    fn levenshtein_first_empty() {
        assert_eq!(7, levenshtein("", "sitting"));
    }

    #[test]
    fn levenshtein_second_empty() {
        assert_eq!(6, levenshtein("kitten", ""));
    }

    #[bench]
    fn bench_hamming(b: &mut Bencher) {
        b.iter(|| hamming("Friedrich Nietzs", "Jean-Paul Sartre"));
    }

    #[bench]
    fn bench_levenshtein(b: &mut Bencher) {
        b.iter(|| levenshtein("Friedrich Nietzsche", "Jean-Paul Sartre"));
    }

    #[bench]
    fn bench_jaro(b: &mut Bencher) {
        b.iter(|| jaro("Friedrich Nietzsche", "Jean-Paul Sartre"));
    }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

pub mod tool;
pub mod environment;

pub use tool::*;
pub use environment::*;
<commit_msg>Start working on some docs<commit_after>//!
//! This is a base library for a simple software architecture designed to make it easy to create large
//! applications by combining small tools. The idea is nothing new: it's a core idea behind UNIX, component
//! libraries like COM+ and more recently microservices. This version is based around Rust and JSON, and it's
//! intended to strip the idea down to its bare essentials.
//!
//! When we learn to program, we're trained on small example programs because those are easy to write and
//! assess. Useful software, however, tends to be much larger and trying to apply the skills obtained through
//! writing smaller pieces of software has a tendency to result in a bit of a mess. A big issue is that the
//! high degree of coupling found in large pieces of software makes it difficult to change design descisions
//! made early on. This library provides a really very simple structure that can be used to build large
//! programs out of small parts.
//!
//! There are three parts to this architecture:
//!
//! ## Tools
//!
//! Tools are small programs that perform a single task. They take input (in the form of a JSON object) and
//! generate an output (also in the form of a JSON object). They can be invoked with no initialisation. In
//! general, they run immediately, perform their task on their input and return immediately.
//!
//! This design makes it easy to compose tools: feed the input of one into another. The input and output of
//! a tool is easy to understand and can be used to invoke it within the same process, within a different
//! process or even over the network. Tools are an excellent target for tests: for many tools, a test
//! requires no code: just the input JSON and the expected output JSON.
//!
//! Keeping tools to simple single purpose use cases means that any given tool should remain comparatively
//! simple. Making them composable makes it so that larger tools and applications can be built from smaller
//! ones. Having it so that they only talk in terms of concrete data means that it's easy to substitute one
//! tool for another even at runtime.
//!
//! ## The environment
//!
//! In order to invoke a tool, we need to be able to find it. This is what the environment is for: it takes
//! the name of a tool and returns an implementation.
//!
//! Using the environment to find tools make it easy to substitute one tool for another and reduces the effort
//! required to adapt a system to new circumstances.
//!
//! When tools are created, they are given a 'birth environment', where they can find other tools that they
//! may wish to invoke. This provides for static behaviour. Sometimes a tool may want more dynamic behaviour -
//! for instance to call another tool named in its input. To allow for this, tools are provided with their
//! environment when they are invoked.
//!
//! ## The automation layer
//!
//! Tools usually don't provide much of a feedback loop: they run, perform a single task, and then they stop.
//! To create an actual application, an 'automation layer' is used. This chains tools together and deals with
//! feedback. For a web app, this might be the HTML and Javascript that runs in the browser. For other apps,
//! this could be written in Rust or it could be written using a scripting language.
//!
//! With the right collection of tools, this layer can be kept comparatively simple - making it possible to
//! quickly create large applications.
//!

extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

pub mod tool;
pub mod environment;

pub use tool::*;
pub use environment::*;
<|endoftext|>


<commit_before>//! # Leaky Bucket Rate-Limiting (as a meter) in Rust
//! This crate implements
//! the
//! [generic cell rate algorithm](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm) (GCRA)
//! for rate-limiting and scheduling in Rust.
//!
//! ## Interface
//!
//! This crate implements two "serious" rate-limiting/traffic-shaping
//! algorithms:
//! [GCRA](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm)
//! and a [Leaky
//! Bucket](https://en.wikipedia.org/wiki/Leaky_bucket#As_a_meter). An
//! "unserious" implementation is provided also, the
//! [`Allower`](example_algorithms/struct.Allower.html), which returns
//! "Yes" to all rate-limiting queries.
//!
//! The Generic Cell Rate Algorithm can be used by creating a builder
//! from the [`GCRA`](algorithms/gcra/struct.GCRA.html) struct:
//!
//! ``` rust
//! use std::time::Duration;
//! use ratelimit_meter::{Decider, GCRA};
//!
//! let mut lim = GCRA::for_capacity(50).unwrap() // Allow 50 units of work
//!     .per(Duration::from_secs(1)) // We calculate per-second (this is the default).
//!     .cell_weight(1).unwrap() // Each cell is one unit of work "heavy".
//!     .build(); // Construct a GCRA decider.
//! assert_eq!(Ok(()), lim.check());
//! ```
//!
//! The rate-limiter interface is intentionally geared towards only
//! providing callers with the information they need to make decisions
//! about what to do with each cell. Whenever possible, additional
//! information about why a cell should be denied - the `GCRA`
//! implementation will return a `time::Instant` alongside the decision to
//! allow callers to e.g. provide better error messages to users.
//!
//! Due to this, the `ratelimit_meter` crate does not provide any facility
//! to wait until a cell would be allowed - if you require this, you
//! should use the `Instant` returned with negative decisions and wait
//! in your own, e.g. event loop.
//!
//! ## Rate-limiting Algorithms
//!
//! ### Design and implementation of GCRA
//!
//! The GCRA limits the rate of cells by determining when the "next"
//! cell is expected to arrive; any cells that arrive before that time
//! are classified as non-conforming; the methods for checking cells
//! also return an expected arrival time for these cells, so that
//! callers can choose to wait (adding jitter), or reject the cell.
//!
//! Since using the GCRA results in a much smoother usage pattern, it
//! appears to be very useful for "outgoing" traffic behaviors,
//! e.g. throttling API call rates, or emails sent to a person in a
//! period of time.
//!
//! Unlike token or leaky bucket algorithms, the GCRA assumes that all
//! units of work are of the same "weight", and so allows some
//! optimizations which result in much more concise and fast code (it
//! does not even use multiplication or division in the "hot" path).
//!
//! See [the documentation of the GCRA type](algorithms/gcra/struct.GCRA.html) for
//! more details on its implementation and on trade-offs that apply to
//! it.
//!
//! ### Design and implementation of the leaky bucket
//!
//! In contrast to the GCRA, the leaky bucket algorithm does not place
//! any constraints on the next cell's arrival time: Whenever there is
//! capacity left in the bucket, it can be used. This means that the
//! distribution of "yes" decisions from heavy usage on the leaky
//! bucket rate-limiter will be clustered together. On average, the
//! cell rates of both the GCRA and the leaky bucket will be the same,
//! but in terms of observable behavior, the leaky bucket will appear
//! to allow requests at a more predictable rate.
//!
//! This kind of behavior is usually what people of online APIs expect
//! these days, which makes the leaky bucket a very popular technique
//! for rate-limiting on these kinds of services.
//!
//! The leaky bucket algorithm implemented in this crate is fairly
//! standard: It only updates the bucket fill gauge when a cell is
//! checked, and supports checking "batches" of cells in a single call
//! with no problems.
//!
//! ## Thread-safe operation
//!
//! The implementations in this crate use compare-and-set to keep
//! state, and are safe to share across threads..
//!
//! Example:
//!
//! ```
//! use std::thread;
//! use std::time::Duration;
//! use ratelimit_meter::{Decider, GCRA};
//!
//! let mut lim = GCRA::for_capacity(50).unwrap() // Allow 50 units of work
//!     .per(Duration::from_secs(1)) // We calculate per-second (this is the default).
//!     .cell_weight(1).unwrap() // Each cell is one unit of work "heavy".
//!     .build(); // Construct a GCRA decider.
//! let mut thread_lim = lim.clone();
//! thread::spawn(move || { assert_eq!(Ok(()), thread_lim.check());});
//! assert_eq!(Ok(()), lim.check());
//! ```

pub mod algorithms;
pub mod example_algorithms;
mod implementation;
mod thread_safety;

extern crate failure;
#[macro_use]
extern crate failure_derive;

use std::time::{Duration, Instant};

use implementation::*;

pub use self::algorithms::GCRA;
pub use self::algorithms::LeakyBucket;

/// Provides additional information about non-conforming cells, most
/// importantly the earliest time until the next cell could be
/// considered conforming.
///
/// Since this does not account for effects like thundering herds,
/// users should always add random jitter to the times given.
#[derive(Fail, Debug, PartialEq)]
#[fail(display = "rate-limited, wait at least {:?}", min_time)]
pub struct NonConformance {
    t0: Instant,
    min_time: Duration,
}

impl NonConformance {
    pub(crate) fn new(t0: Instant, min_time: Duration) -> NonConformance {
        NonConformance { t0, min_time }
    }
}

impl NonConformance {
    /// Returns the earliest time at which a decision could be
    /// conforming (excluding conforming decisions made by the Decider
    /// that are made in the meantime).
    pub fn earliest_possible(&self) -> Instant {
        self.t0 + self.min_time
    }

    /// Returns the minimum amount of time from the time that the
    /// decision was made (relative to the `at` argument in a
    /// `Decider`'s `check_at` method) that must pass before a
    /// decision can be conforming. Since Durations can not be
    /// negative, a zero duration is returned if `from` is already
    /// after that duration.
    pub fn wait_time_from(&self, from: Instant) -> Duration {
        if from == self.t0 {
            self.min_time
        } else if from < self.t0 + self.min_time {
            (self.t0 + self.min_time).duration_since(from)
        } else {
            Duration::new(0, 0)
        }
    }

    /// Returns the minimum amount of time (down to 0) that needs to
    /// pass from the current instant for the Decider to consider a
    /// cell conforming again.
    pub fn wait_time(&self) -> Duration {
        self.wait_time_from(Instant::now())
    }
}

/// Gives additional information about the negative outcome of a batch
/// cell decision.
///
/// Since batch queries can be made for batch sizes bigger than a
/// Decider could accomodate, there are now two possible negative
/// outcomes:
///
///   * `BatchNonConforming` - the query is valid but the Decider can
///     not accomodate them.
///
///   * `InsufficientCapacity` - the Decider can never accomodate the
///     cells queried for.
#[derive(Fail, Debug, PartialEq)]
pub enum NegativeMultiDecision {
    /// A batch of cells (the first argument) is non-conforming and
    /// can not be let through at this time. The second argument gives
    /// information about when that batch of cells might be let
    /// through again (not accounting for thundering herds and other,
    /// simultaneous decisions).
    #[fail(display = "{} cells: {}", _0, _1)]
    BatchNonConforming(u32, NonConformance),

    /// The number of cells tested (the first argument) is larger than
    /// the bucket's capacity, which means the decision can never have
    /// a conforming result.
    #[fail(display = "bucket does not have enough capacity to accomodate {} cells", _0)]
    InsufficientCapacity(u32),
}

/// The main decision trait. It allows checking a single cell against
/// the rate-limiter, either at the current time instant, or at a
/// given instant in time, updating the `Decider`'s internal state if
/// the cell is conforming.
pub trait Decider: DeciderImpl {
    /// Tests is a single cell can be accommodated at the given time
    /// stamp. If it can be, `check` updates the `Decider` to account
    /// for the conforming cell and returns `Ok(())`.
    ///
    /// If the cell is non-conforming (i.e., it can't be accomodated
    /// at this time stamp), `check_at` returns `Err` with information
    /// about the earliest time at which a cell could be considered
    /// conforming (see [`NonConformance`](struct.NonConformance.html)).
    fn check_at(&mut self, at: Instant) -> Result<(), NonConformance> {
        self.test_and_update(at)
    }

    /// Tests if a single cell can be accommodated at
    /// `Instant::now()`. See [`check_at`](#method.check_at).
    fn check(&mut self) -> Result<(), NonConformance> {
        self.test_and_update(Instant::now())
    }
}

/// The "batch" decision trait, allowing a Decider to make a decision
/// about multiple cells at once.
pub trait MultiDecider: MultiDeciderImpl {
    /// Tests if `n` cells can be accommodated at the given time
    /// stamp. If (and only if) all cells in the batch can be
    /// accomodated, the `MultiDecider` updates the internal state to
    /// account for all cells and returns `Ok(())`.
    ///
    /// If the entire batch of cells would not be conforming but the
    /// `MultiDecider` has the capacity to accomodate the cells at any
    /// point in time, `check_n_at` returns error
    /// [`NegativeMultiDecision::BatchNonConforming`](enum.NegativeMultiDecision.html#variant.BatchNonConforming),
    /// holding the number of cells and
    /// [`NonConformance`](struct.NonConformance.html) information.
    ///
    /// If `n` exceeds the bucket capacity, `check_n_at` returns
    /// [`NegativeMultiDecision::InsufficientCapacity`](enum.NegativeMultiDecision.html#variant.InsufficientCapacity),
    /// indicating that a batch of this many cells can never succeed.
    fn check_n_at(&mut self, n: u32, at: Instant) -> Result<(), NegativeMultiDecision> {
        self.test_n_and_update(n, at)
    }

    /// Tests if `n` cells can be accommodated at the current time
    /// (`Instant::now()`), using [`check_n_at`](#method.check_n_at)
    fn check_n(&mut self, n: u32) -> Result<(), NegativeMultiDecision> {
        self.test_n_and_update(n, Instant::now())
    }
}

#[test]
fn test_wait_time_from() {
    let now = Instant::now();
    let nc = NonConformance::new(now, Duration::from_secs(20));
    assert_eq!(nc.wait_time_from(now), Duration::from_secs(20));
    assert_eq!(
        nc.wait_time_from(now + Duration::from_secs(5)),
        Duration::from_secs(15)
    );
}
<commit_msg>Rustfmt for 1.26.1<commit_after>//! # Leaky Bucket Rate-Limiting (as a meter) in Rust
//! This crate implements
//! the
//! [generic cell rate algorithm](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm) (GCRA)
//! for rate-limiting and scheduling in Rust.
//!
//! ## Interface
//!
//! This crate implements two "serious" rate-limiting/traffic-shaping
//! algorithms:
//! [GCRA](https://en.wikipedia.org/wiki/Generic_cell_rate_algorithm)
//! and a [Leaky
//! Bucket](https://en.wikipedia.org/wiki/Leaky_bucket#As_a_meter). An
//! "unserious" implementation is provided also, the
//! [`Allower`](example_algorithms/struct.Allower.html), which returns
//! "Yes" to all rate-limiting queries.
//!
//! The Generic Cell Rate Algorithm can be used by creating a builder
//! from the [`GCRA`](algorithms/gcra/struct.GCRA.html) struct:
//!
//! ``` rust
//! use std::time::Duration;
//! use ratelimit_meter::{Decider, GCRA};
//!
//! let mut lim = GCRA::for_capacity(50).unwrap() // Allow 50 units of work
//!     .per(Duration::from_secs(1)) // We calculate per-second (this is the default).
//!     .cell_weight(1).unwrap() // Each cell is one unit of work "heavy".
//!     .build(); // Construct a GCRA decider.
//! assert_eq!(Ok(()), lim.check());
//! ```
//!
//! The rate-limiter interface is intentionally geared towards only
//! providing callers with the information they need to make decisions
//! about what to do with each cell. Whenever possible, additional
//! information about why a cell should be denied - the `GCRA`
//! implementation will return a `time::Instant` alongside the decision to
//! allow callers to e.g. provide better error messages to users.
//!
//! Due to this, the `ratelimit_meter` crate does not provide any facility
//! to wait until a cell would be allowed - if you require this, you
//! should use the `Instant` returned with negative decisions and wait
//! in your own, e.g. event loop.
//!
//! ## Rate-limiting Algorithms
//!
//! ### Design and implementation of GCRA
//!
//! The GCRA limits the rate of cells by determining when the "next"
//! cell is expected to arrive; any cells that arrive before that time
//! are classified as non-conforming; the methods for checking cells
//! also return an expected arrival time for these cells, so that
//! callers can choose to wait (adding jitter), or reject the cell.
//!
//! Since using the GCRA results in a much smoother usage pattern, it
//! appears to be very useful for "outgoing" traffic behaviors,
//! e.g. throttling API call rates, or emails sent to a person in a
//! period of time.
//!
//! Unlike token or leaky bucket algorithms, the GCRA assumes that all
//! units of work are of the same "weight", and so allows some
//! optimizations which result in much more concise and fast code (it
//! does not even use multiplication or division in the "hot" path).
//!
//! See [the documentation of the GCRA type](algorithms/gcra/struct.GCRA.html) for
//! more details on its implementation and on trade-offs that apply to
//! it.
//!
//! ### Design and implementation of the leaky bucket
//!
//! In contrast to the GCRA, the leaky bucket algorithm does not place
//! any constraints on the next cell's arrival time: Whenever there is
//! capacity left in the bucket, it can be used. This means that the
//! distribution of "yes" decisions from heavy usage on the leaky
//! bucket rate-limiter will be clustered together. On average, the
//! cell rates of both the GCRA and the leaky bucket will be the same,
//! but in terms of observable behavior, the leaky bucket will appear
//! to allow requests at a more predictable rate.
//!
//! This kind of behavior is usually what people of online APIs expect
//! these days, which makes the leaky bucket a very popular technique
//! for rate-limiting on these kinds of services.
//!
//! The leaky bucket algorithm implemented in this crate is fairly
//! standard: It only updates the bucket fill gauge when a cell is
//! checked, and supports checking "batches" of cells in a single call
//! with no problems.
//!
//! ## Thread-safe operation
//!
//! The implementations in this crate use compare-and-set to keep
//! state, and are safe to share across threads..
//!
//! Example:
//!
//! ```
//! use std::thread;
//! use std::time::Duration;
//! use ratelimit_meter::{Decider, GCRA};
//!
//! let mut lim = GCRA::for_capacity(50).unwrap() // Allow 50 units of work
//!     .per(Duration::from_secs(1)) // We calculate per-second (this is the default).
//!     .cell_weight(1).unwrap() // Each cell is one unit of work "heavy".
//!     .build(); // Construct a GCRA decider.
//! let mut thread_lim = lim.clone();
//! thread::spawn(move || { assert_eq!(Ok(()), thread_lim.check());});
//! assert_eq!(Ok(()), lim.check());
//! ```

pub mod algorithms;
pub mod example_algorithms;
mod implementation;
mod thread_safety;

extern crate failure;
#[macro_use]
extern crate failure_derive;

use std::time::{Duration, Instant};

use implementation::*;

pub use self::algorithms::LeakyBucket;
pub use self::algorithms::GCRA;

/// Provides additional information about non-conforming cells, most
/// importantly the earliest time until the next cell could be
/// considered conforming.
///
/// Since this does not account for effects like thundering herds,
/// users should always add random jitter to the times given.
#[derive(Fail, Debug, PartialEq)]
#[fail(display = "rate-limited, wait at least {:?}", min_time)]
pub struct NonConformance {
    t0: Instant,
    min_time: Duration,
}

impl NonConformance {
    pub(crate) fn new(t0: Instant, min_time: Duration) -> NonConformance {
        NonConformance { t0, min_time }
    }
}

impl NonConformance {
    /// Returns the earliest time at which a decision could be
    /// conforming (excluding conforming decisions made by the Decider
    /// that are made in the meantime).
    pub fn earliest_possible(&self) -> Instant {
        self.t0 + self.min_time
    }

    /// Returns the minimum amount of time from the time that the
    /// decision was made (relative to the `at` argument in a
    /// `Decider`'s `check_at` method) that must pass before a
    /// decision can be conforming. Since Durations can not be
    /// negative, a zero duration is returned if `from` is already
    /// after that duration.
    pub fn wait_time_from(&self, from: Instant) -> Duration {
        if from == self.t0 {
            self.min_time
        } else if from < self.t0 + self.min_time {
            (self.t0 + self.min_time).duration_since(from)
        } else {
            Duration::new(0, 0)
        }
    }

    /// Returns the minimum amount of time (down to 0) that needs to
    /// pass from the current instant for the Decider to consider a
    /// cell conforming again.
    pub fn wait_time(&self) -> Duration {
        self.wait_time_from(Instant::now())
    }
}

/// Gives additional information about the negative outcome of a batch
/// cell decision.
///
/// Since batch queries can be made for batch sizes bigger than a
/// Decider could accomodate, there are now two possible negative
/// outcomes:
///
///   * `BatchNonConforming` - the query is valid but the Decider can
///     not accomodate them.
///
///   * `InsufficientCapacity` - the Decider can never accomodate the
///     cells queried for.
#[derive(Fail, Debug, PartialEq)]
pub enum NegativeMultiDecision {
    /// A batch of cells (the first argument) is non-conforming and
    /// can not be let through at this time. The second argument gives
    /// information about when that batch of cells might be let
    /// through again (not accounting for thundering herds and other,
    /// simultaneous decisions).
    #[fail(display = "{} cells: {}", _0, _1)]
    BatchNonConforming(u32, NonConformance),

    /// The number of cells tested (the first argument) is larger than
    /// the bucket's capacity, which means the decision can never have
    /// a conforming result.
    #[fail(display = "bucket does not have enough capacity to accomodate {} cells", _0)]
    InsufficientCapacity(u32),
}

/// The main decision trait. It allows checking a single cell against
/// the rate-limiter, either at the current time instant, or at a
/// given instant in time, updating the `Decider`'s internal state if
/// the cell is conforming.
pub trait Decider: DeciderImpl {
    /// Tests is a single cell can be accommodated at the given time
    /// stamp. If it can be, `check` updates the `Decider` to account
    /// for the conforming cell and returns `Ok(())`.
    ///
    /// If the cell is non-conforming (i.e., it can't be accomodated
    /// at this time stamp), `check_at` returns `Err` with information
    /// about the earliest time at which a cell could be considered
    /// conforming (see [`NonConformance`](struct.NonConformance.html)).
    fn check_at(&mut self, at: Instant) -> Result<(), NonConformance> {
        self.test_and_update(at)
    }

    /// Tests if a single cell can be accommodated at
    /// `Instant::now()`. See [`check_at`](#method.check_at).
    fn check(&mut self) -> Result<(), NonConformance> {
        self.test_and_update(Instant::now())
    }
}

/// The "batch" decision trait, allowing a Decider to make a decision
/// about multiple cells at once.
pub trait MultiDecider: MultiDeciderImpl {
    /// Tests if `n` cells can be accommodated at the given time
    /// stamp. If (and only if) all cells in the batch can be
    /// accomodated, the `MultiDecider` updates the internal state to
    /// account for all cells and returns `Ok(())`.
    ///
    /// If the entire batch of cells would not be conforming but the
    /// `MultiDecider` has the capacity to accomodate the cells at any
    /// point in time, `check_n_at` returns error
    /// [`NegativeMultiDecision::BatchNonConforming`](enum.NegativeMultiDecision.html#variant.BatchNonConforming),
    /// holding the number of cells and
    /// [`NonConformance`](struct.NonConformance.html) information.
    ///
    /// If `n` exceeds the bucket capacity, `check_n_at` returns
    /// [`NegativeMultiDecision::InsufficientCapacity`](enum.NegativeMultiDecision.html#variant.InsufficientCapacity),
    /// indicating that a batch of this many cells can never succeed.
    fn check_n_at(&mut self, n: u32, at: Instant) -> Result<(), NegativeMultiDecision> {
        self.test_n_and_update(n, at)
    }

    /// Tests if `n` cells can be accommodated at the current time
    /// (`Instant::now()`), using [`check_n_at`](#method.check_n_at)
    fn check_n(&mut self, n: u32) -> Result<(), NegativeMultiDecision> {
        self.test_n_and_update(n, Instant::now())
    }
}

#[test]
fn test_wait_time_from() {
    let now = Instant::now();
    let nc = NonConformance::new(now, Duration::from_secs(20));
    assert_eq!(nc.wait_time_from(now), Duration::from_secs(20));
    assert_eq!(
        nc.wait_time_from(now + Duration::from_secs(5)),
        Duration::from_secs(15)
    );
}
<|endoftext|>


<commit_before>/// Implementation of Stochastic universal sampling
/// https://en.wikipedia.org/wiki/Stochastic_universal_sampling
/// Runtime: O(n)
/// Memory Usage: O(n) or O(1) (in place variant)

extern crate rand;

use self::rand::{thread_rng, Rng};

pub struct RandomChoice;

impl RandomChoice {
    /// Chooses n samples by their weights. The greater their weights the more likely they get chosen.
    ///
    /// @invariant sum of weights must not overflow.
    /// @param samples The to be selected samples
    /// @param weights Weights that get chosen by their weight/probability. One weight can be greater 1.
    /// @param n Number of randomly chosen samples by weight.
    /// @return randomly selected samples by their weights
    pub fn random_choice<'a, T>(samples: &'a [T], weights: &[f64], n: usize) -> Vec<&'a T> {
        if weights.len() == 0 || n == 0 { return Vec::new(); }

        let sum:f64 = weights.iter().fold(0.0, |acc, &i| acc + i);
        let spoke_gap: f64 = sum / n as f64;

        // next_f64() ∈ [0.0, 1.0)
        let spin = thread_rng().next_f64() * spoke_gap;

        let mut i: usize = 0;
        let mut accumulated_weights = weights[0];
        let mut choices: Vec<&T> = Vec::with_capacity(n);
        let mut current_spoke: f64 = spin;

        for _ in 0 .. n {
            while accumulated_weights < current_spoke {
                i += 1;
                accumulated_weights += weights[i];
            }
            choices.push(&samples[i]);
            current_spoke += spoke_gap;
        }

        choices
    }

    pub fn random_choice_in_place<T: Clone>(samples: &mut [T], weights: &[f64]) {
        if weights.len() < 2 { return; }

        let sum:f64 = weights.iter().fold(0.0, |acc, &i| acc + i);
        let n: usize = weights.len();
        let spoke_gap: f64 = sum / n as f64;

        // next_f64() ∈ [0.0, 1.0)
        let spin = thread_rng().next_f64() * spoke_gap;

        let mut j: usize = 0;
        let mut accumulated_weights = weights[0];
        let mut current_spoke: f64 = spin;

        for i in 0 .. n {
            while accumulated_weights < current_spoke {
                j += 1;
                accumulated_weights += weights[j];
            }
            samples[i] = samples[j].clone();
            current_spoke += spoke_gap;
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_random_choice() {
        let test_vec: Vec<f64> = vec![3.1, 1.2, 1.3, 2.0];
        //let sum:f64 = test_vec.iter().fold(0.0, |acc, &i| acc + i);

        //assert_eq!(6.0, sum);

        let choices = super::RandomChoice::random_choice(&test_vec, &test_vec, 4 as usize);

        for choice in choices {
            print!("{}, ", choice);
        }
    }

    #[test]
    fn test_random_choice_in_place() {
        let mut samples = vec!["hi", "this", "is", "a", "test!"];
        let weights: Vec<f64> = vec![1.0, 1.0, 1.0, 1.0, 1.0];

        super::RandomChoice::random_choice_in_place(&mut samples, &weights);

        for sample in samples {
            print!("{}, ", sample);
        }
    }

    #[test]
    fn test_random_choice_in_place_2() {
        struct Foo {j: i32, };
        let test1 = Foo {j: 1};
        let test2 = Foo {j: 2};
        let test3 = Foo {j: 3};
        let mut samples: Vec<&Foo> = Vec::new();

        samples.push(&test1);
        samples.push(&test2);
        samples.push(&test3);

        let weights: Vec<f64> = vec![1.0, 1.0, 1.0];

        super::RandomChoice::random_choice_in_place(&mut samples, &weights);

        for sample in samples {
            print!("foo{}, ", sample.j);
        }
    }
}<commit_msg>comment added<commit_after>/// Implementation of Stochastic universal sampling
/// https://en.wikipedia.org/wiki/Stochastic_universal_sampling
/// Runtime: O(n)
/// Memory Usage: O(n) or O(1) (in place variant)

extern crate rand;

use self::rand::{thread_rng, Rng};

pub struct RandomChoice;

impl RandomChoice {
    /// Chooses n samples by their weights. The greater their weights the more likely they get chosen.
    ///
    /// @invariant sum of weights must not overflow.
    /// @param samples The to be selected samples
    /// @param weights Weights that get chosen by their weight/probability. One weight can be greater 1.
    /// @param n Number of randomly chosen samples by weight.
    /// @return randomly selected samples by their weights
    pub fn random_choice<'a, T>(samples: &'a [T], weights: &[f64], n: usize) -> Vec<&'a T> {
        if weights.len() == 0 || n == 0 { return Vec::new(); }

        let sum:f64 = weights.iter().fold(0.0, |acc, &i| acc + i);
        let spoke_gap: f64 = sum / n as f64;

        // next_f64() ∈ [0.0, 1.0)
        let spin = thread_rng().next_f64() * spoke_gap;

        let mut i: usize = 0;
        let mut accumulated_weights = weights[0];
        let mut choices: Vec<&T> = Vec::with_capacity(n);
        let mut current_spoke: f64 = spin;

        for _ in 0 .. n {
            while accumulated_weights < current_spoke {
                i += 1;
                accumulated_weights += weights[i];
            }
            choices.push(&samples[i]);
            current_spoke += spoke_gap;
        }

        choices
    }

    /// Chooses n samples by their weights. The greater their weights the more likely they get chosen.
    /// The result gets saved directly in the samples argument.
    /// @invariant sum of weights must not overflow.
    /// @param samples The to be selected samples
    /// @param weights Weights that get chosen by their weight/probability. One weight can be greater 1.
    pub fn random_choice_in_place<T: Clone>(samples: &mut [T], weights: &[f64]) {
        if weights.len() < 2 { return; }

        let sum:f64 = weights.iter().fold(0.0, |acc, &i| acc + i);
        let n: usize = weights.len();
        let spoke_gap: f64 = sum / n as f64;

        // next_f64() ∈ [0.0, 1.0)
        let spin = thread_rng().next_f64() * spoke_gap;

        let mut j: usize = 0;
        let mut accumulated_weights = weights[0];
        let mut current_spoke: f64 = spin;

        for i in 0 .. n {
            while accumulated_weights < current_spoke {
                j += 1;
                accumulated_weights += weights[j];
            }
            samples[i] = samples[j].clone();
            current_spoke += spoke_gap;
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_random_choice() {
        let test_vec: Vec<f64> = vec![3.1, 1.2, 1.3, 2.0];
        //let sum:f64 = test_vec.iter().fold(0.0, |acc, &i| acc + i);

        //assert_eq!(6.0, sum);

        let choices = super::RandomChoice::random_choice(&test_vec, &test_vec, 4 as usize);

        for choice in choices {
            print!("{}, ", choice);
        }
    }

    #[test]
    fn test_random_choice_in_place() {
        let mut samples = vec!["hi", "this", "is", "a", "test!"];
        let weights: Vec<f64> = vec![1.0, 1.0, 1.0, 1.0, 1.0];

        super::RandomChoice::random_choice_in_place(&mut samples, &weights);

        for sample in samples {
            print!("{}, ", sample);
        }
    }

    #[test]
    fn test_random_choice_in_place_2() {
        struct Foo {j: i32, };
        let test1 = Foo {j: 1};
        let test2 = Foo {j: 2};
        let test3 = Foo {j: 3};
        let mut samples: Vec<&Foo> = Vec::new();

        samples.push(&test1);
        samples.push(&test2);
        samples.push(&test3);

        let weights: Vec<f64> = vec![1.0, 1.0, 1.0];

        super::RandomChoice::random_choice_in_place(&mut samples, &weights);

        for sample in samples {
            print!("foo{}, ", sample.j);
        }
    }
}<|endoftext|>


<commit_before>extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::iter::IteratorExt;
use std::io;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Ok(Some(element)) = builder.push_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    pub categories: Vec<Category>,
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(|e| e.content_str());
        let link = element.get_child("link", None).map(|e| e.content_str());
        let description = element.get_child("description", None).map(|e| e.content_str());

        let categories = element.get_children("category", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category", None, &[("domain", None, d)]),
            None => Element::new("category", None, &[]),
        };
        category.text(&self.value);
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<commit_msg>Alphabetize imports<commit_after>extern crate xml;

use std::ascii::AsciiExt;
use std::default::Default;
use std::io;
use std::iter::IteratorExt;
use xml::{Element, ElementBuilder, Parser, Xml};

trait ElementUtils {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str);
    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>);
}

impl ElementUtils for Element {
    fn tag_with_text(&mut self, child_name: &'static str, child_body: &str) {
        self.tag(elem_with_text(child_name, child_body));
    }

    fn tag_with_text_opt(&mut self, child_name: &'static str, child_body: &Option<String>) {
        if let Some(ref c) = *child_body {
            self.tag_with_text(child_name, &c);
        }
    }
}

fn elem_with_text(tag_name: &'static str, chars: &str) -> Element {
    let mut elem = Element::new(tag_name, None, &[]);
    elem.text(chars);
    elem
}

trait ViaXml {
    fn to_xml(&self) -> Element;
    fn from_xml(element: Element) -> Result<Self, &'static str>;
}

/// RSS
///
/// "At the top level, a RSS document is a \<rss\> element, with a mandatory attribute called
/// version, that specifies the version of RSS that the document conforms to. If it conforms to
/// this specification, the version attribute must be 2.0."
///
/// [RSS 2.0 Specification § RSS]
/// (http://cyber.law.harvard.edu/rss/rss.html#whatIsRss)
#[derive(Default)]
pub struct Rss(pub Channel);

impl ViaXml for Rss {
    fn to_xml(&self) -> Element {
        let mut rss = Element::new("rss", None, &[("version", None, "2.0")]);

        let &Rss(ref channel) = self;
        rss.tag(channel.to_xml());

        rss
    }

    fn from_xml(rss_elem: Element) -> Result<Self, &'static str> {
        if rss_elem.name.to_ascii_lowercase() != "rss" {
            panic!("Expected <rss>, found <{}>", rss_elem.name);
        }

        let channel_elem = match rss_elem.get_child("channel", None) {
            Some(elem) => elem,
            None => return Err("No <channel> element found in <rss>"),
        };

        let channel = try!(ViaXml::from_xml(channel_elem.clone()));

        Ok(Rss(channel))
    }
}

impl Rss {
    pub fn to_string(&self) -> String {
        let mut ret = format!("{}", Xml::PINode("xml version='1.0' encoding='UTF-8'".to_string()));
        ret.push_str(&format!("{}", self.to_xml()));
        ret
    }

    pub fn from_read(reader: &mut io::Read) -> Result<Self, &'static str> {
        let mut rss_string = String::new();

        match reader.read_to_string(&mut rss_string) {
            Ok(..) => (),
            Err(..) => return Err("Error reading string from reader"),
        }

        let mut parser = Parser::new();
        parser.feed_str(&rss_string);

        let mut builder = ElementBuilder::new();

        for event in parser {
            if let Ok(Some(element)) = builder.push_event(event) {
                return ViaXml::from_xml(element);
            }
        }

        Err("RSS read error")
    }
}

/// Channel
///
/// "Subordinate to the \<rss\> element is a single \<channel\> element, which contains information
/// about the channel (metadata) and its contents."
///
/// [RSS 2.0 Specification § Channel]
/// (http://cyber.law.harvard.edu/rss/rss.html#requiredChannelElements)
///
/// ## Examples
///
/// ```
/// use rss::Channel;
/// use std::default::Default;
///
/// let channel = Channel {
///     title: "My Blog".to_string(),
///     link: "http://myblog.com".to_string(),
///     description: "Where I write stuff".to_string(),
///     items: vec![],
///     ..Default::default()
/// };
/// ```
#[derive(Default)]
pub struct Channel {
    pub title: String,
    pub link: String,
    pub description: String,
    pub items: Vec<Item>,
    pub language: Option<String>,
    pub copyright: Option<String>,
    pub managing_editor: Option<String>,
    pub web_master: Option<String>,
    pub pub_date: Option<String>,
    pub last_build_date: Option<String>,
    pub categories: Vec<Category>,
    pub generator: Option<String>,
    pub docs: Option<String>,
    // pub cloud:
    // pub ttl:
    pub image: Option<String>,
    pub rating: Option<String>,
    // pub text_input:
    pub skip_hours: Option<String>,
    pub skip_days: Option<String>,
}

impl ViaXml for Channel {
    fn to_xml(&self) -> Element {
        let mut channel = Element::new("channel", None, &[]);

        channel.tag_with_text("title", &self.title);
        channel.tag_with_text("link", &self.link);
        channel.tag_with_text("description", &self.description);

        for item in &self.items {
            channel.tag(item.to_xml());
        }

        channel.tag_with_text_opt("language", &self.language);
        channel.tag_with_text_opt("copyright", &self.copyright);
        channel.tag_with_text_opt("managingEditor", &self.managing_editor);
        channel.tag_with_text_opt("webMaster", &self.web_master);
        channel.tag_with_text_opt("pubDate", &self.pub_date);
        channel.tag_with_text_opt("lastBuildDate", &self.last_build_date);
        channel.tag_with_text_opt("generator", &self.generator);
        channel.tag_with_text_opt("docs", &self.docs);
        channel.tag_with_text_opt("image", &self.image);
        channel.tag_with_text_opt("rating", &self.rating);
        channel.tag_with_text_opt("skipHours", &self.skip_hours);
        channel.tag_with_text_opt("skipDays", &self.skip_days);

        for category in &self.categories {
            channel.tag(category.to_xml());
        }

        channel
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = match element.get_child("title", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <title> element"),
        };

        let link = match element.get_child("link", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <link> element"),
        };

        let description = match element.get_child("description", None) {
            Some(element) => element.content_str(),
            None => return Err("<channel> is missing required <description> element"),
        };

        let items = element.get_children("item", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        let categories = element.get_children("category", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Channel {
            title: title,
            link: link,
            description: description,
            items: items,
            categories: categories,
            ..Default::default()  // TODO
        })
    }
}

#[derive(Default)]
pub struct Item {
    pub title: Option<String>,
    pub link: Option<String>,
    pub description: Option<String>,
    // pub author
    pub categories: Vec<Category>,
    // pub comments
    // pub enclosure
    // pub guid
    // pub pubDate
    // pub source
}

impl ViaXml for Item {
    fn to_xml(&self) -> Element {
        let mut item = Element::new("item", None, &[]);

        item.tag_with_text_opt("title", &self.title);
        item.tag_with_text_opt("link", &self.link);
        item.tag_with_text_opt("description", &self.description);

        for category in &self.categories {
            item.tag(category.to_xml());
        }

        item
    }

    fn from_xml(element: Element) -> Result<Self, &'static str> {
        let title = element.get_child("title", None).map(|e| e.content_str());
        let link = element.get_child("link", None).map(|e| e.content_str());
        let description = element.get_child("description", None).map(|e| e.content_str());

        let categories = element.get_children("category", None)
            .into_iter()
            .map(|e| ViaXml::from_xml(e.clone()).unwrap())
            .collect();

        Ok(Item {
            title: title,
            link: link,
            description: description,
            categories: categories,
        })
    }
}

/// Category
///
/// [RSS 2.0 Specification § Category]
/// (http://cyber.law.harvard.edu/rss/rss.html#ltcategorygtSubelementOfLtitemgt)
#[derive(Default)]
pub struct Category {
    pub domain: Option<String>,
    pub value: String,
}

impl ViaXml for Category {
    fn to_xml(&self) -> Element {
        let mut category = match self.domain {
            Some(ref d) => Element::new("category", None, &[("domain", None, d)]),
            None => Element::new("category", None, &[]),
        };
        category.text(&self.value);
        category
    }

    fn from_xml(elem: Element) -> Result<Self, &'static str> {
        let domain = elem.get_attribute("domain", None).map(|s| s.to_string());
        let value = elem.content_str();

        Ok(Category {
            domain: domain,
            value: value,
        })
    }
}

#[cfg(test)]
mod test {
    use std::default::Default;
    use std::fs::File;
    use super::{Rss, Item, Channel};

    #[test]
    fn test_basic_to_string() {
        let item = Item {
            title: Some("My first post!".to_string()),
            link: Some("http://myblog.com/post1".to_string()),
            description: Some("This is my first post".to_string()),
            ..Default::default()
        };

        let channel = Channel {
            title: "My Blog".to_string(),
            link: "http://myblog.com".to_string(),
            description: "Where I write stuff".to_string(),
            items: vec![item],
            ..Default::default()
        };

        let rss = Rss(channel);
        assert_eq!(rss.to_string(), "<?xml version=\'1.0\' encoding=\'UTF-8\'?><rss version=\'2.0\'><channel><title>My Blog</title><link>http://myblog.com</link><description>Where I write stuff</description><item><title>My first post!</title><link>http://myblog.com/post1</link><description>This is my first post</description></item></channel></rss>");
    }

    #[test]
    fn test_from_file() {
        let mut file = File::open("test-data/pinboard.xml").unwrap();
        let rss = Rss::from_read(&mut file).unwrap();
        assert!(rss.to_string().len() > 0);
    }

    #[test]
    #[should_panic]
    fn test_from_read_no_channels() {
        let mut rss_bytes = "<rss></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_from_read_one_channel_no_properties() {
        let mut rss_bytes = "<rss><channel></channel></rss>".as_bytes();
        let Rss(_) = Rss::from_read(&mut rss_bytes).unwrap();
    }

    #[test]
    fn test_from_read_one_channel() {
        let mut rss_bytes = "<rss><channel><title>Hello world!</title><description></description><link></link></channel></rss>".as_bytes();
        let Rss(channel) = Rss::from_read(&mut rss_bytes).unwrap();
        assert_eq!("Hello world!", channel.title);
    }
}
<|endoftext|>


<commit_before>//! Provides the abstraction of a bit field, which allows for bit-level update and retrieval
//! operations.

#![no_std]

#[cfg(test)]
mod tests;

use core::ops::Range;

/// A generic trait which provides methods for extracting and setting specific bits or ranges of
/// bits.
pub trait BitField {

    /// Returns the length, eg number of bits, in this bit field.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// assert_eq!(u32::bit_length(), 32);
    /// assert_eq!(u64::bit_length(), 64);
    /// ```
    fn bit_length() -> u8;

    /// Obtains the bit at the index `bit`; note that index 0 is the least significant bit, while
    /// index `length() - 1` is the most significant bit.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// let value: u32 = 0b110101;
    ///
    /// assert_eq!(value.get_bit(1), false);
    /// assert_eq!(value.get_bit(2), true);
    /// ```
    ///
    /// ## Panics
    ///
    /// This method will panic if the bit index is out of bounds of the bit field.
    fn get_bit(&self, bit: u8) -> bool;

    /// Obtains the range of bits specified by `range`; note that index 0 is the least significant
    /// bit, while index `length() - 1` is the most significant bit.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// let value: u32 = 0b110101;
    ///
    /// assert_eq!(value.get_bits(0..3), 0b101);
    /// assert_eq!(value.get_bits(2..6), 0b1101);
    /// ```
    ///
    /// ## Panics
    ///
    /// This method will panic if the start or end indexes of the range are out of bounds of the
    /// bit field.
    fn get_bits(&self, range: Range<u8>) -> Self;

    /// Sets the bit at the index `bit` to the value `value` (where true means a value of '1' and
    /// false means a value of '0'); note that index 0 is the least significant bit, while index
    /// `length() - 1` is the most significant bit.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// let mut value = 0u32;
    ///
    /// value.set_bit(1, true);
    /// assert_eq!(value, 2u32);
    ///
    /// value.set_bit(3, true);
    /// assert_eq!(value, 10u32);
    ///
    /// value.set_bit(1, false);
    /// assert_eq!(value, 8u32);
    /// ```
    ///
    /// ## Panics
    ///
    /// This method will panic if the bit index is out of the bounds of the bit field.
    fn set_bit(&mut self, bit: u8, value: bool) -> &mut Self;

    /// Sets the range of bits defined by the range `range` to the lower bits of `value`; to be
    /// specific, if the range is N bits long, the N lower bits of `value` will be used; if any of
    /// the other bits in `value` are set to 1, this function will panic.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// let mut value = 0u32;
    ///
    /// value.set_bits(0..2, 0b11);
    /// assert_eq!(value, 0b11);
    ///
    /// value.set_bits(0..4, 0b1010);
    /// assert_eq!(value, 0b1010);
    /// ```
    ///
    /// ## Panics
    ///
    /// This method will panic if the range is out of bounds of the bit field, or if there are `1`s
    /// not in the lower N bits of `value`.
    fn set_bits(&mut self, range: Range<u8>, value: Self) -> &mut Self;
}

pub trait BitArray<T: BitField> {
    fn bit_length(&self) -> usize;

    fn get_bit(&self, bit: usize) -> bool;

    fn get_bits(&self, range: Range<usize>) -> T;

    fn set_bit(&mut self, bit: usize, value: bool);

    fn set_bits(&mut self, range: Range<usize>, value: T);
}

/// An internal macro used for implementing BitField on the standard integral types.
macro_rules! bitfield_numeric_impl {
    ($($t:ty)*) => ($(
        impl BitField for $t {
            fn bit_length() -> u8 {
                ::core::mem::size_of::<Self>() as u8 * 8
            }

            fn get_bit(&self, bit: u8) -> bool {
                assert!(bit < Self::bit_length());

                (*self & (1 << bit)) != 0
            }

            fn get_bits(&self, range: Range<u8>) -> Self {
                assert!(range.start < Self::bit_length());
                assert!(range.end <= Self::bit_length());
                assert!(range.start < range.end);

                // shift away high bits
                let bits = *self << (Self::bit_length() - range.end) >> (Self::bit_length() - range.end);

                // shift away low bits
                bits >> range.start
            }

            fn set_bit(&mut self, bit: u8, value: bool) -> &mut Self {
                assert!(bit < Self::bit_length());

                if value {
                    *self |= 1 << bit;
                } else {
                    *self &= !(1 << bit);
                }

                self
            }

            fn set_bits(&mut self, range: Range<u8>, value: Self) -> &mut Self {
                assert!(range.start < Self::bit_length());
                assert!(range.end <= Self::bit_length());
                assert!(range.start < range.end);
                assert!(value << (Self::bit_length() - (range.end - range.start)) >>
                        (Self::bit_length() - (range.end - range.start)) == value,
                        "value does not fit into bit range");

                let bitmask: Self = !(!0 << (Self::bit_length() - range.end) >>
                                    (Self::bit_length() - range.end) >>
                                    range.start << range.start);

                // set bits
                *self = (*self & bitmask) | (value << range.start);

                self
            }
        }
    )*)
}

bitfield_numeric_impl! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }

impl<T: BitField> BitArray<T> for [T] {
    fn bit_length(&self) -> usize {
        self.len() * (T::bit_length() as usize)
    }

    fn get_bit(&self, bit: usize) -> bool {
        let slice_index = bit / T::bit_length() as usize;
        let bit_index = (bit % T::bit_length() as usize) as u8;
        self[slice_index].get_bit(bit_index)
    }

    fn get_bits(&self, range: Range<usize>) -> T {
        assert!(range.len() <= T::bit_length() as usize);

        let slice_start = range.start/T::bit_length() as usize;
        let slice_end = range.end / T::bit_length() as usize;
        let bit_start = (range.start % T::bit_length() as usize) as u8;
        let bit_end = (range.end % T::bit_length() as usize) as u8;
        let len = range.len() as u8;

        if slice_start == slice_end {
            self[slice_start].get_bits(bit_start..bit_end)
        } else if bit_end == 0 {
            self[slice_start].get_bits(bit_start..T::bit_length())
        } else {
            let mut ret = self[slice_start].get_bits(bit_start..T::bit_length());
            ret.set_bits((T::bit_length() - bit_start)..len, self[slice_end].get_bits(0..bit_end));
            ret
        }
    }

    fn set_bit(&mut self, bit: usize, value: bool) {
        let slice_index = bit / T::bit_length() as usize;
        let bit_index = (bit % T::bit_length() as usize) as u8;
        self[slice_index].set_bit(bit_index, value);
    }

    fn set_bits(&mut self, range: Range<usize>, value: T) {
        assert!(range.len() <= T::bit_length() as usize);

        let slice_start = range.start/T::bit_length() as usize;
        let slice_end = range.end / T::bit_length() as usize;
        let bit_start = (range.start % T::bit_length() as usize) as u8;
        let bit_end = (range.end % T::bit_length() as usize) as u8;

        if slice_start == slice_end {
            self[slice_start].set_bits(bit_start..bit_end, value);
        } else if bit_end == 0 {
            self[slice_start].set_bits(bit_start..T::bit_length(), value);
        } else {
            self[slice_start].set_bits(bit_start..T::bit_length(), value.get_bits(0..T::bit_length()-bit_start));
            self[slice_end].set_bits(0..bit_end, value.get_bits(T::bit_length()-bit_start..T::bit_length()));
        }
    }

}

<commit_msg>Added assertion to make it more readable that an BitField will mostly span two fields of an [T: BitField]<commit_after>//! Provides the abstraction of a bit field, which allows for bit-level update and retrieval
//! operations.

#![no_std]

#[cfg(test)]
mod tests;

use core::ops::Range;

/// A generic trait which provides methods for extracting and setting specific bits or ranges of
/// bits.
pub trait BitField {

    /// Returns the length, eg number of bits, in this bit field.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// assert_eq!(u32::bit_length(), 32);
    /// assert_eq!(u64::bit_length(), 64);
    /// ```
    fn bit_length() -> u8;

    /// Obtains the bit at the index `bit`; note that index 0 is the least significant bit, while
    /// index `length() - 1` is the most significant bit.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// let value: u32 = 0b110101;
    ///
    /// assert_eq!(value.get_bit(1), false);
    /// assert_eq!(value.get_bit(2), true);
    /// ```
    ///
    /// ## Panics
    ///
    /// This method will panic if the bit index is out of bounds of the bit field.
    fn get_bit(&self, bit: u8) -> bool;

    /// Obtains the range of bits specified by `range`; note that index 0 is the least significant
    /// bit, while index `length() - 1` is the most significant bit.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// let value: u32 = 0b110101;
    ///
    /// assert_eq!(value.get_bits(0..3), 0b101);
    /// assert_eq!(value.get_bits(2..6), 0b1101);
    /// ```
    ///
    /// ## Panics
    ///
    /// This method will panic if the start or end indexes of the range are out of bounds of the
    /// bit field.
    fn get_bits(&self, range: Range<u8>) -> Self;

    /// Sets the bit at the index `bit` to the value `value` (where true means a value of '1' and
    /// false means a value of '0'); note that index 0 is the least significant bit, while index
    /// `length() - 1` is the most significant bit.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// let mut value = 0u32;
    ///
    /// value.set_bit(1, true);
    /// assert_eq!(value, 2u32);
    ///
    /// value.set_bit(3, true);
    /// assert_eq!(value, 10u32);
    ///
    /// value.set_bit(1, false);
    /// assert_eq!(value, 8u32);
    /// ```
    ///
    /// ## Panics
    ///
    /// This method will panic if the bit index is out of the bounds of the bit field.
    fn set_bit(&mut self, bit: u8, value: bool) -> &mut Self;

    /// Sets the range of bits defined by the range `range` to the lower bits of `value`; to be
    /// specific, if the range is N bits long, the N lower bits of `value` will be used; if any of
    /// the other bits in `value` are set to 1, this function will panic.
    ///
    /// ```rust
    /// use bit_field::BitField;
    ///
    /// let mut value = 0u32;
    ///
    /// value.set_bits(0..2, 0b11);
    /// assert_eq!(value, 0b11);
    ///
    /// value.set_bits(0..4, 0b1010);
    /// assert_eq!(value, 0b1010);
    /// ```
    ///
    /// ## Panics
    ///
    /// This method will panic if the range is out of bounds of the bit field, or if there are `1`s
    /// not in the lower N bits of `value`.
    fn set_bits(&mut self, range: Range<u8>, value: Self) -> &mut Self;
}

pub trait BitArray<T: BitField> {
    fn bit_length(&self) -> usize;

    fn get_bit(&self, bit: usize) -> bool;

    fn get_bits(&self, range: Range<usize>) -> T;

    fn set_bit(&mut self, bit: usize, value: bool);

    fn set_bits(&mut self, range: Range<usize>, value: T);
}

/// An internal macro used for implementing BitField on the standard integral types.
macro_rules! bitfield_numeric_impl {
    ($($t:ty)*) => ($(
        impl BitField for $t {
            fn bit_length() -> u8 {
                ::core::mem::size_of::<Self>() as u8 * 8
            }

            fn get_bit(&self, bit: u8) -> bool {
                assert!(bit < Self::bit_length());

                (*self & (1 << bit)) != 0
            }

            fn get_bits(&self, range: Range<u8>) -> Self {
                assert!(range.start < Self::bit_length());
                assert!(range.end <= Self::bit_length());
                assert!(range.start < range.end);

                // shift away high bits
                let bits = *self << (Self::bit_length() - range.end) >> (Self::bit_length() - range.end);

                // shift away low bits
                bits >> range.start
            }

            fn set_bit(&mut self, bit: u8, value: bool) -> &mut Self {
                assert!(bit < Self::bit_length());

                if value {
                    *self |= 1 << bit;
                } else {
                    *self &= !(1 << bit);
                }

                self
            }

            fn set_bits(&mut self, range: Range<u8>, value: Self) -> &mut Self {
                assert!(range.start < Self::bit_length());
                assert!(range.end <= Self::bit_length());
                assert!(range.start < range.end);
                assert!(value << (Self::bit_length() - (range.end - range.start)) >>
                        (Self::bit_length() - (range.end - range.start)) == value,
                        "value does not fit into bit range");

                let bitmask: Self = !(!0 << (Self::bit_length() - range.end) >>
                                    (Self::bit_length() - range.end) >>
                                    range.start << range.start);

                // set bits
                *self = (*self & bitmask) | (value << range.start);

                self
            }
        }
    )*)
}

bitfield_numeric_impl! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }

impl<T: BitField> BitArray<T> for [T] {
    fn bit_length(&self) -> usize {
        self.len() * (T::bit_length() as usize)
    }

    fn get_bit(&self, bit: usize) -> bool {
        let slice_index = bit / T::bit_length() as usize;
        let bit_index = (bit % T::bit_length() as usize) as u8;
        self[slice_index].get_bit(bit_index)
    }

    fn get_bits(&self, range: Range<usize>) -> T {
        assert!(range.len() <= T::bit_length() as usize);

        let slice_start = range.start/T::bit_length() as usize;
        let slice_end = range.end / T::bit_length() as usize;
        let bit_start = (range.start % T::bit_length() as usize) as u8;
        let bit_end = (range.end % T::bit_length() as usize) as u8;
        let len = range.len() as u8;

        assert!(slice_end - slice_start<= 1);

        if slice_start == slice_end {
            self[slice_start].get_bits(bit_start..bit_end)
        } else if bit_end == 0 {
            self[slice_start].get_bits(bit_start..T::bit_length())
        } else {
            let mut ret = self[slice_start].get_bits(bit_start..T::bit_length());
            ret.set_bits((T::bit_length() - bit_start)..len, self[slice_end].get_bits(0..bit_end));
            ret
        }
    }

    fn set_bit(&mut self, bit: usize, value: bool) {
        let slice_index = bit / T::bit_length() as usize;
        let bit_index = (bit % T::bit_length() as usize) as u8;
        self[slice_index].set_bit(bit_index, value);
    }

    fn set_bits(&mut self, range: Range<usize>, value: T) {
        assert!(range.len() <= T::bit_length() as usize);

        let slice_start = range.start/T::bit_length() as usize;
        let slice_end = range.end / T::bit_length() as usize;
        let bit_start = (range.start % T::bit_length() as usize) as u8;
        let bit_end = (range.end % T::bit_length() as usize) as u8;

        assert!(slice_end - slice_start<= 1);

        if slice_start == slice_end {
            self[slice_start].set_bits(bit_start..bit_end, value);
        } else if bit_end == 0 {
            self[slice_start].set_bits(bit_start..T::bit_length(), value);
        } else {
            self[slice_start].set_bits(bit_start..T::bit_length(), value.get_bits(0..T::bit_length()-bit_start));
            self[slice_end].set_bits(0..bit_end, value.get_bits(T::bit_length()-bit_start..T::bit_length()));
        }
    }

}

<|endoftext|>


<commit_before>//! nanosleep for rust
//!
//!
//! # Goals
//! * provide nanosleep for linux and macos
//!
//! # Future work
//! * other OS support?
//!
//! # Usage
//!
//! Include the module and call ```shuteye::sleep(Duration::new(seconds, nanoseconds))```
//!
//! # Example
//!
//! Sleep for 1 uS
//!
//! ```
//! use shuteye::sleep;
//! use std::time::Duration;
//!
//! // call sleep
//! sleep(Duration::new(0, 1000));

#![deny(warnings)]

extern crate libc;

use std::ptr;
use std::time::Duration;

/// sleep for a relative time
///
/// # Example
/// ```rust
/// use std::time::Duration;
/// use shuteye::sleep;
///
/// // simple sleep for 1s duration
/// sleep(Duration::new(1, 0));
///
/// // remain captures remaining time
/// match sleep(Duration::new(1, 0)) {
///     Some(remain) => {
///         // woke early - some sleep time remains
///     }
///     None => {
///         // woke on-time or late - no sleep time remains
///     }
/// }
/// ```
pub fn sleep(duration: Duration) -> Option<Duration> {
    let ts = duration_to_timespec(duration);
    let mut remain = libc::timespec {
        tv_sec: 0,
        tv_nsec: 0,
    };

    #[cfg(target_os = "linux")] clock_nanosleep(libc::CLOCK_MONOTONIC, 0, &ts, Some(&mut remain));

    #[cfg(target_os = "macos")] nanosleep(&ts, Some(&mut remain));

    if remain.tv_nsec == 0 && remain.tv_sec == 0 {
        return None;
    }
    Some(timespec_to_duration(remain))
}

fn duration_to_timespec(duration: Duration) -> libc::timespec {
    libc::timespec {
        tv_sec: duration.as_secs() as libc::time_t,
        tv_nsec: duration.subsec_nanos() as libc::c_long,
    }
}

fn timespec_to_duration(timespec: libc::timespec) -> Duration {
    Duration::new(timespec.tv_sec as u64, timespec.tv_nsec as u32)
}

#[cfg(target_os = "linux")]
fn clock_nanosleep(
    clk_id: libc::clockid_t,
    flags: libc::c_int,
    req: &libc::timespec,
    remain: Option<&mut libc::timespec>,
) -> i32 {
    match remain {
        Some(p) => unsafe { libc::clock_nanosleep(clk_id, flags, req as *const _, p as *mut _) },
        _ => unsafe { libc::clock_nanosleep(clk_id, flags, req as *const _, ptr::null_mut()) },
    }
}

#[cfg(target_os = "macos")]
fn nanosleep(req: &libc::timespec, remain: Option<&mut libc::timespec>) -> i32 {
    match remain {
        Some(p) => unsafe { libc::nanosleep(req as *const _, p as *mut _) },
        _ => unsafe { libc::nanosleep(req as *const _, ptr::null_mut()) },
    }
}
<commit_msg>fix: cast_lossless warning (#21)<commit_after>//! nanosleep for rust
//!
//!
//! # Goals
//! * provide nanosleep for linux and macos
//!
//! # Future work
//! * other OS support?
//!
//! # Usage
//!
//! Include the module and call ```shuteye::sleep(Duration::new(seconds, nanoseconds))```
//!
//! # Example
//!
//! Sleep for 1 uS
//!
//! ```
//! use shuteye::sleep;
//! use std::time::Duration;
//!
//! // call sleep
//! sleep(Duration::new(0, 1000));

#![deny(warnings)]

extern crate libc;

use std::ptr;
use std::time::Duration;

/// sleep for a relative time
///
/// # Example
/// ```rust
/// use std::time::Duration;
/// use shuteye::sleep;
///
/// // simple sleep for 1s duration
/// sleep(Duration::new(1, 0));
///
/// // remain captures remaining time
/// match sleep(Duration::new(1, 0)) {
///     Some(remain) => {
///         // woke early - some sleep time remains
///     }
///     None => {
///         // woke on-time or late - no sleep time remains
///     }
/// }
/// ```
pub fn sleep(duration: Duration) -> Option<Duration> {
    let ts = duration_to_timespec(duration);
    let mut remain = libc::timespec {
        tv_sec: 0,
        tv_nsec: 0,
    };

    #[cfg(target_os = "linux")] clock_nanosleep(libc::CLOCK_MONOTONIC, 0, &ts, Some(&mut remain));

    #[cfg(target_os = "macos")] nanosleep(&ts, Some(&mut remain));

    if remain.tv_nsec == 0 && remain.tv_sec == 0 {
        return None;
    }
    Some(timespec_to_duration(remain))
}

fn duration_to_timespec(duration: Duration) -> libc::timespec {
    libc::timespec {
        tv_sec: duration.as_secs() as libc::time_t,
        tv_nsec: i64::from(duration.subsec_nanos()) as libc::c_long,
    }
}

fn timespec_to_duration(timespec: libc::timespec) -> Duration {
    Duration::new(timespec.tv_sec as u64, timespec.tv_nsec as u32)
}

#[cfg(target_os = "linux")]
fn clock_nanosleep(
    clk_id: libc::clockid_t,
    flags: libc::c_int,
    req: &libc::timespec,
    remain: Option<&mut libc::timespec>,
) -> i32 {
    match remain {
        Some(p) => unsafe { libc::clock_nanosleep(clk_id, flags, req as *const _, p as *mut _) },
        _ => unsafe { libc::clock_nanosleep(clk_id, flags, req as *const _, ptr::null_mut()) },
    }
}

#[cfg(target_os = "macos")]
fn nanosleep(req: &libc::timespec, remain: Option<&mut libc::timespec>) -> i32 {
    match remain {
        Some(p) => unsafe { libc::nanosleep(req as *const _, p as *mut _) },
        _ => unsafe { libc::nanosleep(req as *const _, ptr::null_mut()) },
    }
}
<|endoftext|>