<commit_before>use std::ascii::AsciiExt;

struct Score;

impl Score {
    pub fn score(choice: &str, query: &str) -> f32 {
        let choice_length = choice.len() as f32;
        let query_length = query.len() as f32;
        let lower_choice = choice.to_ascii_lowercase();
        let lower_query = query.to_ascii_lowercase();

        if choice_length == 0.0 || query_length > choice_length  {
            return 0.0
        }
        if query_length == 0.0  {
            return 1.0
        }

        let possible_match_length = compute_match_length(lower_choice.as_slice(), lower_query.as_slice());
         match possible_match_length {
             Some(match_length) => return normalize_score(query_length, match_length, choice_length),
             None => return 0.0,
         };
    }
}

fn normalize_score(query_length: f32, match_length: uint, choice_length: f32) -> f32 {
    (query_length / match_length as f32) / choice_length
}

fn compute_match_length(choice: &str, query: &str) -> Option<uint> {
    let query_chars = query.chars().collect::<Vec<char>>();
    let first_char = query_chars[0];

    let match_beginnings = find_char_in_choice(first_char, choice);

    let mut shortest_match: Option<uint> = None;

    for beginning in match_beginnings.iter() {
        let possible_match_length = find_match_length(choice, &query_chars, *beginning);
        match (possible_match_length, shortest_match) {
            (_, None) => shortest_match = possible_match_length,
            (Some(match_length), Some(shortest)) if match_length < shortest => shortest_match = possible_match_length,
            _ => continue,
        };
    }
    return shortest_match;
}

fn find_char_in_choice(first_char: char, choice: &str) -> Vec<uint> {
    let mut found: Vec<uint> = Vec::new();
    for  (idx, character) in choice.chars().enumerate() {
        if character == first_char {
            found.push(idx);
        }
    }

    return found;
}

fn find_match_length(choice: &str, query_chars: &Vec<char>, beginning: uint) -> Option<uint> {
    let mut last_index = beginning;
    for query_char in query_chars.iter() {
       let found = find_first_after(choice, *query_char, last_index);
       match found {
           Some(n) => last_index = n,
           None => return None,
       };
    }
    return Some(last_index - beginning + 1);
}

fn find_first_after(choice: &str, query: char, beginning: uint) -> Option<uint> {
    for (idx, character) in choice.chars().enumerate().skip(beginning) {
        if character == query {
            return Some(idx);
        }
    }
    None
}

#[cfg(test)]

#[test]
fn scores_zero_when_the_choice_is_emtpy() {
    assert_eq!(Score::score("", "a"), 0.0);
}

#[test]
fn scores_one_when_the_query_is_empty() {
    assert_eq!(Score::score("a", ""), 1.0);
}

#[test]
fn scores_zero_if_query_is_longer_than_the_choice() {
    assert_eq!(Score::score("a", "aaaaa"), 0.0);
}

#[test]
fn scores_zero_if_query_does_not_match_at_all() {
    assert_eq!(Score::score("a", "b"), 0.0);
}

#[test]
fn scores_greater_than_zero_if_query_matches_choice() {
    assert!(Score::score("a", "a") > 0.0);
    assert!(Score::score("ab", "a") > 0.0);
    assert!(Score::score("ba", "a") > 0.0);
    assert!(Score::score("bab", "a") > 0.0);
    assert!(Score::score("babababab", "aaaa") > 0.0);
}

#[test]
fn case_insensitive_matching() {
    assert!(Score::score("a", "A") == 1.0);
    assert!(Score::score("A", "a") == 1.0);
}

#[test]
fn normalizes_score_based_on_length() {
    assert_eq!(Score::score("a", "a") , 1.0);
    assert_eq!(Score::score("ab", "ab") , 0.5);
    assert_eq!(Score::score("a long string", "a long string") , 1.0 / "a long string".len() as f32);
    assert_eq!(Score::score("spec/search_spec.rb", "sear"), 1.0 / "spec/search_spec.rb".len() as f32)
}

#[test]
fn matches_punctuation() {
    assert!(Score::score("/! symbols $^", "/!$^") > 0.0);
}

#[test]
fn repeated_character_does_not_match() {
    assert_eq!(Score::score("a", "aa") , 0.0);
}

#[test]
fn scores_higher_for_better_matches() {
      assert!(Score::score("selecta.gemspec", "asp") > Score::score("algorithm4_spec.rb", "asp"));
      assert!(Score::score("README.md", "em") > Score::score("benchmark.rb", "em"));
      assert!(Score::score("search.rb", "sear") > Score::score("spec/search_spec.rb", "sear"));
}

#[test]
fn scores_shorter_matches_higher() {
      assert!(Score::score("fbb", "fbb") > Score::score("foo bar baz", "fbb"));
      assert!(Score::score("foo", "foo") > Score::score("longer foo", "foo"));
      assert!(Score::score("foo", "foo") > Score::score("foo longer", "foo"));
      assert!(Score::score("1/2/3/4", "1/2/3") > Score::score("1/9/2/3/4", "1/2/3"));
}

#[test]
fn scores_the_tighter_of_two_matches_regardless_of_order() {
      let beginning = "121padding2";
      let end = "1padding212";
      assert_eq!(Score::score(beginning, "12"), Score::score(end, "12"));
}

<commit_msg>Refactorings<commit_after>use std::ascii::AsciiExt;

struct Score;

impl Score {
    pub fn score(choice: &str, query: &str) -> f32 {
        let choice_length = choice.len() as f32;
        let query_length = query.len() as f32;
        let lower_choice = choice.to_ascii_lowercase();
        let lower_query = query.to_ascii_lowercase();

        if query_length == 0.0  { return 1.0 }

        let possible_match_length = compute_match_length(lower_choice.as_slice(), lower_query.as_slice());
         match possible_match_length {
             Some(match_length) => return normalize(query_length, match_length, choice_length),
             None => return 0.0,
         };
    }
}

fn normalize(query_length: f32, match_length: uint, choice_length: f32) -> f32 {
    (query_length / match_length as f32) / choice_length
}

fn compute_match_length(choice: &str, query: &str) -> Option<uint> {
    let query_chars = query.chars().collect::<Vec<char>>();
    let first_char = query_chars[0];

    let match_beginnings = find_positions(first , choice);

    let mut shortest_match: Option<uint> = None;

    for beginning in match_beginnings.iter() {
        let possible_match_length = find_match_length(choice, rest, *beginning);

        match (shortest_match, possible_match_length) {
            (Some(shortest), Some(length)) if shortest > length => shortest_match = possible_match_length,
            (None, Some(length)) => shortest_match = possible_match_length,
            (_, _) => continue,
        };
    }
    return shortest_match;
}

fn find_positions(first_char: char, choice: &str) -> Vec<uint> {
    let mut found: Vec<uint> = Vec::new();
    for  (idx, character) in choice.chars().enumerate() {
        if character == first_char {
            found.push(idx);
        }
    }

    return found;
}

fn find_match_length(choice: &str, query_chars: &Vec<char>, beginning: uint) -> Option<uint> {
    let mut last_index = beginning;
    for query_char in query_chars.iter() {
       let found = find_first_after(choice, *query_char, last_index);
       match found {
           Some(n) => last_index = n,
           None => return None,
       };
    }
    return Some(last_index - beginning + 1);
}

fn find_first_after(choice: &str, query: char, beginning: uint) -> Option<uint> {
    for (idx, character) in choice.chars().enumerate().skip(beginning) {
        if character == query {
            return Some(idx);
        }
    }
    None
}

#[cfg(test)]

#[test]
fn scores_zero_when_the_choice_is_emtpy() {
    assert_eq!(Score::score("", "a"), 0.0);
}

#[test]
fn scores_one_when_the_query_is_empty() {
    assert_eq!(Score::score("a", ""), 1.0);
}

#[test]
fn scores_zero_if_query_is_longer_than_the_choice() {
    assert_eq!(Score::score("a", "aaaaa"), 0.0);
}

#[test]
fn scores_zero_if_query_does_not_match_at_all() {
    assert_eq!(Score::score("a", "b"), 0.0);
}

#[test]
fn scores_greater_than_zero_if_query_matches_choice() {
    assert!(Score::score("a", "a") > 0.0);
    assert!(Score::score("ab", "a") > 0.0);
    assert!(Score::score("ba", "a") > 0.0);
    assert!(Score::score("bab", "a") > 0.0);
    assert!(Score::score("babababab", "aaaa") > 0.0);
}

#[test]
fn case_insensitive_matching() {
    assert!(Score::score("a", "A") == 1.0);
    assert!(Score::score("A", "a") == 1.0);
}

#[test]
fn normalizes_score_based_on_length() {
    assert_eq!(Score::score("a", "a") , 1.0);
    assert_eq!(Score::score("ab", "ab") , 0.5);
    assert_eq!(Score::score("a long string", "a long string") , 1.0 / "a long string".len() as f32);
    assert_eq!(Score::score("spec/search_spec.rb", "sear"), 1.0 / "spec/search_spec.rb".len() as f32)
}

#[test]
fn matches_punctuation() {
    assert!(Score::score("/! symbols $^", "/!$^") > 0.0);
}

#[test]
fn repeated_character_does_not_match() {
    assert_eq!(Score::score("a", "aa") , 0.0);
}

#[test]
fn scores_higher_for_better_matches() {
      assert!(Score::score("selecta.gemspec", "asp") > Score::score("algorithm4_spec.rb", "asp"));
      assert!(Score::score("README.md", "em") > Score::score("benchmark.rb", "em"));
      assert!(Score::score("search.rb", "sear") > Score::score("spec/search_spec.rb", "sear"));
}

#[test]
fn scores_shorter_matches_higher() {
      assert!(Score::score("fbb", "fbb") > Score::score("foo bar baz", "fbb"));
      assert!(Score::score("foo", "foo") > Score::score("longer foo", "foo"));
      assert!(Score::score("foo", "foo") > Score::score("foo longer", "foo"));
      assert!(Score::score("1/2/3/4", "1/2/3") > Score::score("1/9/2/3/4", "1/2/3"));
}

#[test]
fn scores_the_tighter_of_two_matches_regardless_of_order() {
      let beginning = "121padding2";
      let end = "1padding212";
      assert_eq!(Score::score(beginning, "12"), Score::score(end, "12"));
}

#[test]
fn tighter_matches_score_higher() {
    assert!(Score::score("long 12 long", "12") > Score::score("1 long 2", "12"));
}

<|endoftext|>


<commit_before>use std::str::StrExt;
use std::ascii::AsciiExt;

pub fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }

    if choice.len() == 0 {
        return 0.0;
    }

    //let lower_choice = choice.into_ascii_lowercase();
    let lower_choice = choice.to_ascii_lowercase();
    let lower_query = query.to_ascii_lowercase();
    let lower_choice_len = lower_choice.len() as f64;

    //println!("{} in {}", lower_query, lower_choice);
    let match_length = compute_match_length(lower_choice, lower_query.chars().collect());

    if match_length == 0 {
        return 0.0;
    }

    //println!("{} / {}", lower_query.len(), match_length);
    let score = lower_query.len() as f64 / match_length as f64;

    //println!("{} / {}", score, lower_choice_len);
    score / lower_choice_len
}

/// Find the length of the shortest substring matching the given characters.
fn compute_match_length(haystack: String, needles: Vec<char>) -> usize {
    let first_char = needles[0];
    let rest = needles.slice_from(1);
    let mut min_index = 0;

    let first_indexes = find_char_in_string(haystack.as_slice(), first_char);

    for first_index in first_indexes.iter() {
        //println!("first_index = {}", first_index);
        let last_index = find_end_of_match(haystack.as_slice(), rest, *first_index);

        match last_index {
            Some(index) => {
                let new_index = index - *first_index + 1;
                //println!("last_index = {}, new_index = {}, min_index = {}", index, new_index, min_index);
                if min_index == 0 || new_index < min_index {
                    min_index = new_index;
                }
            },
            None => {}
        }
    }

    //println!("min_index = {}", min_index);
    min_index
}

/// Find all occurrences of the character in the string, returning their indexes.
fn find_char_in_string(haystack: &str, needle: char) -> Vec<usize> {
    let mut index: usize = 0;
    let mut indexes = Vec::new();
    let mut h = haystack.as_slice();

    //println!("{}", "find_char_in_string");
    loop {
        index = match find_from_offset(h, needle, index) {
            Some(i) => {
                indexes.push(i);
                i + 1
            },
            None => { break; },
        };
    }

    indexes
}

/// Find each of the characters in the string, moving strictly left to right.
fn find_end_of_match(haystack: &str, needles: &[char], first_index: usize) -> Option<usize> {
    //println!("at this point haystack = {}", haystack);
    let mut last_index = first_index;
    //println!("{}", "find_end_of_match");
    for needle in needles.iter() {
        last_index = match find_from_offset(haystack, *needle, last_index + 1) {
            Some(i) => i,
            None => { return None; },
        };
    }

    Some(last_index)
}

/// Implements Ruby's `#index` method
fn find_from_offset(haystack: &str, needle: char, offset: usize) -> Option<usize> {
    let h = haystack.slice_from(offset);
    //println!("from_from_offset: h = {}, needle = {}, offset = {}", h, needle, offset);

    let index = h.find(needle);

    match index {
        Some(i) => Some(i + offset),
        None => { return None; },
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use test::Bencher;

    #[test]
    fn test_scores_zero_when_choice_is_empty() {
        assert!(score("", "a") == 0.0);

    }

    #[test]
    fn test_scores_one_when_query_is_empty() {
        assert!(score("a", "") == 1.0);
    }

    #[test]
    fn test_scores_zero_when_the_query_longer_than_choice() {
        assert!(score("short", "longer") == 0.0);
    }

    #[test]
    fn test_scores_zero_when_query_does_not_match_at_all() {
        assert!(score("a", "b") == 0.0);
    }

    #[test]
    fn test_scores_zero_when_only_prefix_of_query_matches() {
        assert!(score("ab", "ac") == 0.0);
    }

    #[test]
    fn test_scores_greater_than_zero_when_matches() {
        let given_choices: Vec<&str> = vec!("a", "ab", "ba", "bab");

        for choice in given_choices.iter() {
            assert!(score(*choice, "a") > 0.0);
        }

        assert!(score("babababab", "aaaa") > 0.0);
    }

    #[test]
    fn test_scores_1_normalized_to_length_when_the_query_equals_choice() {
        assert!(score("a", "a") == 1.0);
        assert!(score("ab", "ab") == 0.5);
        assert!(score("a long string", "a long string") ==
                1.0 / "a long string".len() as f64);
        assert!(score("spec/search_spec.rb", "sear") ==
                1.0 / "spec/search_spec.rb".len() as f64);
    }

    #[test]
    fn test_matches_punctuation() {
        assert!(score("/! symbols $^", "/!$^") > 0.0);
    }

    #[test]
    fn test_is_case_insensitive() {
        assert!(score("a", "A") == 1.0);
        assert!(score("A", "a") == 1.0);
    }

    #[test]
    fn test_does_not_match_when_same_letter_is_repeated_in_choice() {
        assert!(score("a", "aa") == 0.0);
    }

    #[test]
    fn test_scores_higher_for_better_matches() {
        assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
        assert!(score("README.md", "em") > score("benchmark.rb", "em"));
        assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));
    }

    #[test]
    fn test_scores_shorter_matches_higher() {
        assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
        assert!(score("foo", "foo") > score("longer foo", "foo"));
        assert!(score("foo", "foo") > score("foo longer", "foo"));
        assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));
    }

    #[test]
    fn test_sometimes_score_longer_strings_higher_if_better_match() {
        assert!(score("long 12 long", "12") > score("1 long 2", "12"));
    }

    #[test]
    fn test_scores_higher_of_two_matches_regardless_of_order() {
        let tight = "12";
        let loose = "1padding2";
        let expect1 = tight.to_string() + loose;
        let expect2 = loose.to_string() + tight;

        assert!(score(expect1.as_slice(), "12") == 1.0 / expect1.len() as f64);
        assert!(score(expect2.as_slice(), "12") == 1.0 / expect2.len() as f64);

    }

    #[bench]
    fn non_matching(b: &mut Bencher) {
        b.iter(|| {
            let _ = score("xxxxxxxxxxxxxxxxx", "yyyyyyyyyyyyyyy");
        });
    }

    #[bench]
    fn match_exactly(b: &mut Bencher) {
        b.iter(|| {
            let _ = score("xxxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxxxx");
        });
    }
}
<commit_msg>get some<commit_after>use std::str::StrExt;
use std::ascii::AsciiExt;

pub fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }

    if choice.len() == 0 {
        return 0.0;
    }

    let lower_choice = choice.to_ascii_lowercase();
    let lower_query = query.to_ascii_lowercase();
    let lower_choice_len = lower_choice.len() as f64;

    let match_length = compute_match_length(lower_choice.as_slice(), lower_query.chars().collect());

    if match_length == 0 {
        return 0.0;
    }

    let score = lower_query.len() as f64 / match_length as f64;

    score / lower_choice_len
}

/// Find the length of the shortest substring matching the given characters.
fn compute_match_length(haystack: &str, needles: Vec<char>) -> usize {
    let first_char = needles[0];
    let rest = needles.slice_from(1);
    let mut min_index = 0;

    let first_indexes = find_char_in_string(haystack, first_char);

    for first_index in first_indexes.iter() {
        let last_index = find_end_of_match(haystack, rest, *first_index);

        match last_index {
            Some(index) => {
                let new_index = index - *first_index + 1;
                if min_index == 0 || new_index < min_index {
                    min_index = new_index;
                }
            },
            None => {}
        }
    }

    min_index
}

/// Find all occurrences of the character in the string, returning their indexes.
fn find_char_in_string(haystack: &str, needle: char) -> Vec<usize> {
    let mut index: usize = 0;
    let mut indexes = Vec::new();

    loop {
        index = match find_from_offset(haystack, needle, index) {
            Some(i) => {
                indexes.push(i);
                i + 1
            },
            None => { break; },
        };
    }

    indexes
}

/// Find each of the characters in the string, moving strictly left to right.
fn find_end_of_match(haystack: &str, needles: &[char], first_index: usize) -> Option<usize> {
    let mut last_index = first_index;
    for needle in needles.iter() {
        last_index = match find_from_offset(haystack, *needle, last_index + 1) {
            Some(i) => i,
            None => { return None; },
        };
    }

    Some(last_index)
}

/// Implements Ruby's `#index` method
fn find_from_offset(haystack: &str, needle: char, offset: usize) -> Option<usize> {
    let h = haystack.slice_from(offset);

    let index = h.find(needle);

    match index {
        Some(i) => Some(i + offset),
        None => { return None; },
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use test::Bencher;

    #[test]
    fn test_scores_zero_when_choice_is_empty() {
        assert!(score("", "a") == 0.0);

    }

    #[test]
    fn test_scores_one_when_query_is_empty() {
        assert!(score("a", "") == 1.0);
    }

    #[test]
    fn test_scores_zero_when_the_query_longer_than_choice() {
        assert!(score("short", "longer") == 0.0);
    }

    #[test]
    fn test_scores_zero_when_query_does_not_match_at_all() {
        assert!(score("a", "b") == 0.0);
    }

    #[test]
    fn test_scores_zero_when_only_prefix_of_query_matches() {
        assert!(score("ab", "ac") == 0.0);
    }

    #[test]
    fn test_scores_greater_than_zero_when_matches() {
        let given_choices: Vec<&str> = vec!("a", "ab", "ba", "bab");

        for choice in given_choices.iter() {
            assert!(score(*choice, "a") > 0.0);
        }

        assert!(score("babababab", "aaaa") > 0.0);
    }

    #[test]
    fn test_scores_1_normalized_to_length_when_the_query_equals_choice() {
        assert!(score("a", "a") == 1.0);
        assert!(score("ab", "ab") == 0.5);
        assert!(score("a long string", "a long string") ==
                1.0 / "a long string".len() as f64);
        assert!(score("spec/search_spec.rb", "sear") ==
                1.0 / "spec/search_spec.rb".len() as f64);
    }

    #[test]
    fn test_matches_punctuation() {
        assert!(score("/! symbols $^", "/!$^") > 0.0);
    }

    #[test]
    fn test_is_case_insensitive() {
        assert!(score("a", "A") == 1.0);
        assert!(score("A", "a") == 1.0);
    }

    #[test]
    fn test_does_not_match_when_same_letter_is_repeated_in_choice() {
        assert!(score("a", "aa") == 0.0);
    }

    #[test]
    fn test_scores_higher_for_better_matches() {
        assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
        assert!(score("README.md", "em") > score("benchmark.rb", "em"));
        assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));
    }

    #[test]
    fn test_scores_shorter_matches_higher() {
        assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
        assert!(score("foo", "foo") > score("longer foo", "foo"));
        assert!(score("foo", "foo") > score("foo longer", "foo"));
        assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));
    }

    #[test]
    fn test_sometimes_score_longer_strings_higher_if_better_match() {
        assert!(score("long 12 long", "12") > score("1 long 2", "12"));
    }

    #[test]
    fn test_scores_higher_of_two_matches_regardless_of_order() {
        let tight = "12";
        let loose = "1padding2";
        let expect1 = tight.to_string() + loose;
        let expect2 = loose.to_string() + tight;

        assert!(score(expect1.as_slice(), "12") == 1.0 / expect1.len() as f64);
        assert!(score(expect2.as_slice(), "12") == 1.0 / expect2.len() as f64);

    }

    #[bench]
    fn non_matching(b: &mut Bencher) {
        b.iter(|| {
            let _ = score("xxxxxxxxxxxxxxxxx", "yyyyyyyyyyyyyyy");
        });
    }

    #[bench]
    fn match_exactly(b: &mut Bencher) {
        b.iter(|| {
            let _ = score("xxxxxxxxxxxxxxxxx", "xxxxxxxxxxxxxxxxx");
        });
    }
}
<|endoftext|>


<commit_before>use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use std::cmp::Ordering;
use syntax::ast::{Item, ItemKind, LitKind, MetaItemKind, Mod};
use syntax::ast::{NestedMetaItemKind, ViewPath_, Visibility};
use syntax::codemap::Span;
use syntax::parse::token::keywords;
use syntax::print::pprust::path_to_string;

// Warn unsorted declarations by default (since denying is a poor choice for styling lints)
declare_lint!(UNSORTED_DECLARATIONS, Warn,
              "Warn when the declarations of crates or modules are not in alphabetical order");

pub struct Sorty;

impl LintPass for Sorty {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNSORTED_DECLARATIONS)
    }
}

impl EarlyLintPass for Sorty {
    // walking through all the modules is enough for our purpose
    fn check_mod(&mut self, cx: &EarlyContext, module: &Mod, _span: Span, _id: u32) {
        // TODO: lint should stop ignoring the comments near the declarations
        let session_codemap = cx.sess.codemap();    // required only for checking inline mods
        let mut extern_crates = Vec::new();
        let mut uses = Vec::new();
        let mut mods = Vec::new();

        for item in &module.items {
            // I've made use of `format!` most of the time, because we have a mixture of
            // `String` & `InternedString`
            let item_name = format!("{}", item.ident.name.as_str());
            let item_span = item.span;
            match item.node.clone() {
                ItemKind::ExternCrate(optional_name) if item_name != "std" => {
                    // We've put the declaration here because, we have to sort crate declarations
                    // with respect to the renamed version (instead of the old one).
                    // Since we also don't have `pub` (indicated by the `false` below),
                    // we could just append the declaration to the attributes.
                    let mut item_attrs = get_item_attrs(&item, false);
                    item_attrs = match optional_name {    // for `extern crate foo as bar`
                        Some(old_name) => format!("{}extern crate {} as", item_attrs, old_name),
                        None => format!("{}extern crate", item_attrs),
                    };

                    extern_crates.push((item_name, item_attrs, item_span, false));
                }

                ItemKind::Mod(module) => {
                    let mod_invoked_file = session_codemap.span_to_filename(item.span);
                    let mod_declared_file = session_codemap.span_to_filename(module.inner);
                    if mod_declared_file != mod_invoked_file {          // ignores inline modules
                        let item_attrs = get_item_attrs(&item, true);
                        mods.push((item_name, item_attrs, item_span, false));
                    }
                }

                ItemKind::Use(spanned) => {
                    let item_attrs = get_item_attrs(&item, true);
                    match spanned.node {
                        ViewPath_::ViewPathSimple(ref ident, ref path) => {
                            let path_str = path_to_string(&path);
                            let name = ident.name.as_str();

                            let renamed = {     // `use foo as bar`
                                let split = path_str.split(":").collect::<Vec<_>>();
                                match split[split.len() - 1] == &*name {
                                    true => path_str.clone(),
                                    false => format!("{} as {}", &path_str, &name),
                                }
                            };

                            uses.push((renamed, item_attrs, item_span, false));
                        }

                        ViewPath_::ViewPathList(ref path, ref list) => {
                            let old_list = list.iter().map(|&list_item| {
                                if list_item.node.name.name == keywords::SelfValue.name() {
                                    "self".to_owned()   // this must be `self`
                                } else {
                                    let name = list_item.node.name.name.as_str();
                                    match list_item.node.rename {
                                        Some(new_name) => format!("{} as {}", name, new_name),
                                        None => (&*name).to_owned(),
                                    }
                                }
                            }).collect::<Vec<_>>();

                            let mut new_list = old_list.clone();
                            new_list.sort_by(|a, b| {
                                match (&**a, &**b) {    // `self` should be first in a list of use items
                                    ("self", _) => Ordering::Less,
                                    (_, "self") => Ordering::Greater,
                                    _ => a.cmp(b),
                                }
                            });

                            let mut warn = false;
                            let use_list = format!("{}::{{{}}}", path_to_string(&path), new_list.join(", "));
                            for (old_stuff, new_stuff) in old_list.iter().zip(new_list.iter()) {
                                // check whether the use list is sorted
                                if old_stuff != new_stuff {
                                    warn = true;
                                    break
                                }
                            }

                            uses.push((use_list, item_attrs, path.span, warn));
                        }

                        ViewPath_::ViewPathGlob(ref path) => {
                            let path_str = path_to_string(&path) + "::*";
                            // we don't have any use statements like `use std::prelude::*`
                            // since it's done only by rustc, we can safely neglect those here
                            if !path_str.starts_with("std::") {
                                uses.push((path_str, item_attrs, item_span, false));
                            }
                        }
                    }
                }
                _ => (),
            }
        }

        // we don't include the crate declaration here, because we've already appended it with the
        // attributes
        check_sort(&extern_crates, cx, "crate declarations", "");
        check_sort(&mods, cx, "module declarations (other than inline modules)", "mod");
        check_sort(&uses, cx, "use statements", "use");

        // for collecting, formatting & filtering the attributes (and checking the visibility)
        fn get_item_attrs(item: &Item, pub_check: bool) -> String {
            let mut attr_vec = item.attrs
                                   .iter()
                                   .filter_map(|attr| {
                                       let meta_item = attr.node.value.node.clone();
                                       let meta_string = get_meta_as_string(&meta_item);
                                       match meta_string.starts_with("doc = ") {
                                           true => None,
                                           false => Some(format!("#[{}]", meta_string)),
                                       }
                                   }).collect::<Vec<_>>();

            attr_vec.sort_by(|a, b| {
                match (&**a, &**b) {    // put `macro_use` first for later checking
                    ("#[macro_use]", _) => Ordering::Less,
                    (_, "#[macro_use]") => Ordering::Greater,
                    _ => a.cmp(b),
                }
            });

            let attr_string = attr_vec.join("\n");
            match item.vis {
                Visibility::Public if pub_check => match attr_string.is_empty() {
                    true => "pub ".to_owned(),
                    false => attr_string + "\npub ",    // `pub` for mods and uses
                },
                _ => match attr_string.is_empty() {
                    true => attr_string,
                    false => attr_string + "\n",
                },
            }
        }

        fn format_literal(lit: &LitKind) -> String {
            match lit {
                &LitKind::Str(ref inner_str, _) => format!("{}", inner_str),
                _ => panic!("unexpected literal for meta item!"),
            }
        }

        // collect the information from meta items into Strings
        fn get_meta_as_string(meta_item: &MetaItemKind) -> String {
            match *meta_item {
                MetaItemKind::Word(ref string) => format!("{}", string),
                MetaItemKind::List(ref string, ref meta_items) => {
                    let stuff = meta_items.iter().map(|meta_item| match meta_item.node {
                        NestedMetaItemKind::MetaItem(ref meta) => get_meta_as_string(&meta.node),
                        NestedMetaItemKind::Literal(ref value) => format_literal(&value.node),
                    }).collect::<Vec<_>>();

                    format!("{}({})", string, stuff.join(", "))
                },
                MetaItemKind::NameValue(ref string, ref literal) => {
                    let value = format_literal(&literal.node);
                    format!("{} = \"{}\"", string, value)
                },
            }
        }

        // checks the sorting of all the declarations and raises warnings whenever necessary
        // takes a slice of tuples with name, related attributes, spans and whether to warn for
        // unordered use lists
        fn check_sort(old_list: &[(String, String, Span, bool)], cx: &EarlyContext,
                      kind: &str, syntax: &str) {

            // prepend given characters to the names for "biased" sorting
            fn str_for_biased_sort(string: &str, choice: bool, prepend_char: &str) -> String {
                match choice {
                    true => prepend_char.to_owned() + string,
                    false => string.to_owned(),
                }
            }

            let mut new_list = old_list.iter()
                                       .map(|&(ref name, ref attrs, _span, warn)| {
                                           (name.clone(), attrs.clone(), warn)
                                       }).collect::<Vec<_>>();

            new_list.sort_by(|&(ref str_a, ref attr_a, _), &(ref str_b, ref attr_b, _)| {
                // move the `pub` statements below
                // (with `~` since it's on the farther side of ASCII)
                let mut new_str_a = str_for_biased_sort(&str_a, attr_a.ends_with("pub "), "~");
                let mut new_str_b = str_for_biased_sort(&str_b, attr_b.ends_with("pub "), "~");
                // move the #[macro_use] stuff above
                // (with `!` since it's on the lower extreme of ASCII)
                new_str_a = str_for_biased_sort(&new_str_a,
                                                attr_a.starts_with("#[macro_use]"), "!");
                new_str_b = str_for_biased_sort(&new_str_b,
                                                attr_b.starts_with("#[macro_use]"), "!");
                new_str_a.cmp(&new_str_b)
            });

            for (i, (&(ref old_name, _, span_start, _warn),
                     &(ref new_name, _, warn))) in old_list.iter()
                                                           .zip(new_list.iter())
                                                           .enumerate() {
                if (old_name != new_name) || warn {
                    // print all the declarations proceeding the first unsorted one
                    let suggestion_list = new_list[i..new_list.len()]
                                          .iter()
                                          .map(|&(ref name, ref attrs, _)| {
                                              format!("{}{} {};", attrs, syntax, name)
                                          }).collect::<Vec<_>>();

                    // increase the span to include more lines
                    let mut final_span = span_start;
                    let (_, _, old_span, _) = old_list[old_list.len() - 1];
                    final_span.hi = old_span.hi;

                    let message = format!("{} should be in alphabetical order!", kind);
                    let suggestion = format!("Try this...\n\n{}\n", suggestion_list.join("\n"));
                    cx.span_lint_help(UNSORTED_DECLARATIONS, final_span, &message, &suggestion);
                    break
                }
            }
        }
    }
}
<commit_msg>Rustup to 1.14.0<commit_after>use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use std::cmp::Ordering;
use syntax::ast::{Item, ItemKind, LitKind, MetaItemKind, Mod, NodeId};
use syntax::ast::{NestedMetaItemKind, ViewPath_, Visibility};
use syntax::codemap::Span;
use syntax::parse::token::keywords;
use syntax::print::pprust::path_to_string;

// Warn unsorted declarations by default (since denying is a poor choice for styling lints)
declare_lint!(UNSORTED_DECLARATIONS, Warn,
              "Warn when the declarations of crates or modules are not in alphabetical order");

pub struct Sorty;

impl LintPass for Sorty {
    fn get_lints(&self) -> LintArray {
        lint_array!(UNSORTED_DECLARATIONS)
    }
}

impl EarlyLintPass for Sorty {
    // walking through all the modules is enough for our purpose
    fn check_mod(&mut self, cx: &EarlyContext, module: &Mod, _span: Span, _id: NodeId) {
        // TODO: lint should stop ignoring the comments near the declarations
        let session_codemap = cx.sess.codemap();    // required only for checking inline mods
        let mut extern_crates = Vec::new();
        let mut uses = Vec::new();
        let mut mods = Vec::new();

        for item in &module.items {
            // I've made use of `format!` most of the time, because we have a mixture of
            // `String` & `InternedString`
            let item_name = format!("{}", item.ident.name.as_str());
            let item_span = item.span;
            match item.node.clone() {
                ItemKind::ExternCrate(optional_name) if item_name != "std" => {
                    // We've put the declaration here because, we have to sort crate declarations
                    // with respect to the renamed version (instead of the old one).
                    // Since we also don't have `pub` (indicated by the `false` below),
                    // we could just append the declaration to the attributes.
                    let mut item_attrs = get_item_attrs(&item, false);
                    item_attrs = match optional_name {    // for `extern crate foo as bar`
                        Some(old_name) => format!("{}extern crate {} as", item_attrs, old_name),
                        None => format!("{}extern crate", item_attrs),
                    };

                    extern_crates.push((item_name, item_attrs, item_span, false));
                }

                ItemKind::Mod(module) => {
                    let mod_invoked_file = session_codemap.span_to_filename(item.span);
                    let mod_declared_file = session_codemap.span_to_filename(module.inner);
                    if mod_declared_file != mod_invoked_file {          // ignores inline modules
                        let item_attrs = get_item_attrs(&item, true);
                        mods.push((item_name, item_attrs, item_span, false));
                    }
                }

                ItemKind::Use(spanned) => {
                    let item_attrs = get_item_attrs(&item, true);
                    match spanned.node {
                        ViewPath_::ViewPathSimple(ref ident, ref path) => {
                            let path_str = path_to_string(&path);
                            let name = ident.name.as_str();

                            let renamed = {     // `use foo as bar`
                                let split = path_str.split(":").collect::<Vec<_>>();
                                match split[split.len() - 1] == &*name {
                                    true => path_str.clone(),
                                    false => format!("{} as {}", &path_str, &name),
                                }
                            };

                            uses.push((renamed, item_attrs, item_span, false));
                        }

                        ViewPath_::ViewPathList(ref path, ref list) => {
                            let old_list = list.iter().map(|&list_item| {
                                if list_item.node.name.name == keywords::SelfValue.name() {
                                    "self".to_owned()   // this must be `self`
                                } else {
                                    let name = list_item.node.name.name.as_str();
                                    match list_item.node.rename {
                                        Some(new_name) => format!("{} as {}", name, new_name),
                                        None => (&*name).to_owned(),
                                    }
                                }
                            }).collect::<Vec<_>>();

                            let mut new_list = old_list.clone();
                            new_list.sort_by(|a, b| {
                                match (&**a, &**b) {    // `self` should be first in a list of use items
                                    ("self", _) => Ordering::Less,
                                    (_, "self") => Ordering::Greater,
                                    _ => a.cmp(b),
                                }
                            });

                            let mut warn = false;
                            let use_list = format!("{}::{{{}}}", path_to_string(&path), new_list.join(", "));
                            for (old_stuff, new_stuff) in old_list.iter().zip(new_list.iter()) {
                                // check whether the use list is sorted
                                if old_stuff != new_stuff {
                                    warn = true;
                                    break
                                }
                            }

                            uses.push((use_list, item_attrs, path.span, warn));
                        }

                        ViewPath_::ViewPathGlob(ref path) => {
                            let path_str = path_to_string(&path) + "::*";
                            // we don't have any use statements like `use std::prelude::*`
                            // since it's done only by rustc, we can safely neglect those here
                            if !path_str.starts_with("std::") {
                                uses.push((path_str, item_attrs, item_span, false));
                            }
                        }
                    }
                }
                _ => (),
            }
        }

        // we don't include the crate declaration here, because we've already appended it with the
        // attributes
        check_sort(&extern_crates, cx, "crate declarations", "");
        check_sort(&mods, cx, "module declarations (other than inline modules)", "mod");
        check_sort(&uses, cx, "use statements", "use");

        // for collecting, formatting & filtering the attributes (and checking the visibility)
        fn get_item_attrs(item: &Item, pub_check: bool) -> String {
            let mut attr_vec = item.attrs
                                   .iter()
                                   .filter_map(|attr| {
                                       let meta_item = attr.node.value.node.clone();
                                       let meta_string = get_meta_as_string(&meta_item);
                                       match meta_string.starts_with("doc = ") {
                                           true => None,
                                           false => Some(format!("#[{}]", meta_string)),
                                       }
                                   }).collect::<Vec<_>>();

            attr_vec.sort_by(|a, b| {
                match (&**a, &**b) {    // put `macro_use` first for later checking
                    ("#[macro_use]", _) => Ordering::Less,
                    (_, "#[macro_use]") => Ordering::Greater,
                    _ => a.cmp(b),
                }
            });

            let attr_string = attr_vec.join("\n");
            match item.vis {
                Visibility::Public if pub_check => match attr_string.is_empty() {
                    true => "pub ".to_owned(),
                    false => attr_string + "\npub ",    // `pub` for mods and uses
                },
                _ => match attr_string.is_empty() {
                    true => attr_string,
                    false => attr_string + "\n",
                },
            }
        }

        fn format_literal(lit: &LitKind) -> String {
            match lit {
                &LitKind::Str(ref inner_str, _) => format!("{}", inner_str),
                _ => panic!("unexpected literal for meta item!"),
            }
        }

        // collect the information from meta items into Strings
        fn get_meta_as_string(meta_item: &MetaItemKind) -> String {
            match *meta_item {
                MetaItemKind::Word(ref string) => format!("{}", string),
                MetaItemKind::List(ref string, ref meta_items) => {
                    let stuff = meta_items.iter().map(|meta_item| match meta_item.node {
                        NestedMetaItemKind::MetaItem(ref meta) => get_meta_as_string(&meta.node),
                        NestedMetaItemKind::Literal(ref value) => format_literal(&value.node),
                    }).collect::<Vec<_>>();

                    format!("{}({})", string, stuff.join(", "))
                },
                MetaItemKind::NameValue(ref string, ref literal) => {
                    let value = format_literal(&literal.node);
                    format!("{} = \"{}\"", string, value)
                },
            }
        }

        // checks the sorting of all the declarations and raises warnings whenever necessary
        // takes a slice of tuples with name, related attributes, spans and whether to warn for
        // unordered use lists
        fn check_sort(old_list: &[(String, String, Span, bool)], cx: &EarlyContext,
                      kind: &str, syntax: &str) {

            // prepend given characters to the names for "biased" sorting
            fn str_for_biased_sort(string: &str, choice: bool, prepend_char: &str) -> String {
                match choice {
                    true => prepend_char.to_owned() + string,
                    false => string.to_owned(),
                }
            }

            let mut new_list = old_list.iter()
                                       .map(|&(ref name, ref attrs, _span, warn)| {
                                           (name.clone(), attrs.clone(), warn)
                                       }).collect::<Vec<_>>();

            new_list.sort_by(|&(ref str_a, ref attr_a, _), &(ref str_b, ref attr_b, _)| {
                // move the `pub` statements below
                // (with `~` since it's on the farther side of ASCII)
                let mut new_str_a = str_for_biased_sort(&str_a, attr_a.ends_with("pub "), "~");
                let mut new_str_b = str_for_biased_sort(&str_b, attr_b.ends_with("pub "), "~");
                // move the #[macro_use] stuff above
                // (with `!` since it's on the lower extreme of ASCII)
                new_str_a = str_for_biased_sort(&new_str_a,
                                                attr_a.starts_with("#[macro_use]"), "!");
                new_str_b = str_for_biased_sort(&new_str_b,
                                                attr_b.starts_with("#[macro_use]"), "!");
                new_str_a.cmp(&new_str_b)
            });

            for (i, (&(ref old_name, _, span_start, _warn),
                     &(ref new_name, _, warn))) in old_list.iter()
                                                           .zip(new_list.iter())
                                                           .enumerate() {
                if (old_name != new_name) || warn {
                    // print all the declarations proceeding the first unsorted one
                    let suggestion_list = new_list[i..new_list.len()]
                                          .iter()
                                          .map(|&(ref name, ref attrs, _)| {
                                              format!("{}{} {};", attrs, syntax, name)
                                          }).collect::<Vec<_>>();

                    // increase the span to include more lines
                    let mut final_span = span_start;
                    let (_, _, old_span, _) = old_list[old_list.len() - 1];
                    final_span.hi = old_span.hi;

                    let message = format!("{} should be in alphabetical order!", kind);
                    let suggestion = format!("Try this...\n\n{}\n", suggestion_list.join("\n"));
                    cx.span_lint_help(UNSORTED_DECLARATIONS, final_span, &message, &suggestion);
                    break
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use std::collections::{Deque, DList};
use spinlock::Spinlock;

pub struct Sound {
	data: [u8,.. 0x30],
	buffer: Option<Arc<Spinlock<DList<u8>>>>,
}

impl Sound {
	pub fn new() -> Sound {
		Sound { data: [0,.. 0x30], buffer: None }
	}

	pub fn rb(&self, a: u16) -> u8 {
		self.data[a as uint - 0xFF10]
	}

	pub fn wb(&mut self, a: u16, v: u8) {
		self.data[a as uint - 0xFF10] = v;
	}

	pub fn attach_buffer(&mut self, buffer: Arc<Spinlock<DList<u8>>>)
	{
		self.buffer = Some(buffer);
	}

	pub fn cycle(&mut self, cycles: uint)
	{
		let mut data = match self.buffer
		{
			None => return,
			Some(ref buffer) => buffer.lock(),
		};

		if data.len() > 10000 { return; }

		for _ in range(0, cycles)
		{
			data.push_back(0);
		}
	}
}
<commit_msg>push_back -> push<commit_after>use std::sync::Arc;
use std::collections::DList;
use spinlock::Spinlock;

pub struct Sound {
	data: [u8,.. 0x30],
	buffer: Option<Arc<Spinlock<DList<u8>>>>,
}

impl Sound {
	pub fn new() -> Sound {
		Sound { data: [0,.. 0x30], buffer: None }
	}

	pub fn rb(&self, a: u16) -> u8 {
		self.data[a as uint - 0xFF10]
	}

	pub fn wb(&mut self, a: u16, v: u8) {
		self.data[a as uint - 0xFF10] = v;
	}

	pub fn attach_buffer(&mut self, buffer: Arc<Spinlock<DList<u8>>>)
	{
		self.buffer = Some(buffer);
	}

	pub fn cycle(&mut self, cycles: uint)
	{
		let mut data = match self.buffer
		{
			None => return,
			Some(ref buffer) => buffer.lock(),
		};

		if data.len() > 10000 { return; }

		for _ in range(0, cycles)
		{
			data.push(0);
		}
	}
}
<|endoftext|>


<commit_before>use std::fmt;
use UndoCmd;

/// `UndoStack` maintains a stack of `UndoCmd`s that can be undone and redone by using methods
/// on the `UndoStack`.
///
/// `UndoStack` will notice when it's state changes to either dirty or clean, and the user can
/// set methods that should be called for either state change. This is useful for example if
/// you want to automatically enable or disable undo or redo buttons based on there are any
/// more actions that can be undone or redone.
pub struct UndoStack<'a> {
    // All commands on the stack.
    stack: Vec<Box<UndoCmd + 'a>>,
    // Current position in the stack.
    idx: usize,
    // Max amount of commands allowed on the stack.
    limit: Option<usize>,
    // Called when the state changes from dirty to clean.
    on_clean: Box<FnMut() + 'a>,
    // Called when the state changes from clean to dirty.
    on_dirty: Box<FnMut() + 'a>,
}

impl<'a> UndoStack<'a> {
    /// Creates a new `UndoStack`.
    #[inline]
    pub fn new() -> Self {
        UndoStack {
            stack: Vec::new(),
            idx: 0,
            limit: None,
            on_clean: Box::new(|| {}),
            on_dirty: Box::new(|| {}),
        }
    }

    /// Creates a new `UndoStack` with the specified capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        UndoStack {
            stack: Vec::with_capacity(capacity),
            idx: 0,
            limit: None,
            on_clean: Box::new(|| {}),
            on_dirty: Box::new(|| {}),
        }
    }

    /// Returns the capacity of the `UndoStack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.stack.capacity()
    }

    /// Reserves capacity for at least `additional` more commands to be inserted in the given stack.
    /// The stack may reserve more space to avoid frequent reallocations.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.stack.reserve(additional);
    }

    /// Shrinks the capacity of the `UndoStack` as much as possible.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.stack.shrink_to_fit();
    }

    /// Sets the limit on how many `UndoCmd`s can be stored in the stack. If this limit is reached
    /// it will start popping of commands at the bottom of the stack when pushing new commands
    /// on to the stack. No limit is set by default which means it may grow indefinitely.
    ///
    /// # Panics
    /// Panics if the given limit is zero.
    ///
    /// # Examples
    /// ```
    /// # use undo::{UndoCmd, UndoStack};
    /// # #[derive(Clone, Copy)]
    /// # struct PopCmd {
    /// #   vec: *mut Vec<i32>,
    /// #   e: Option<i32>,
    /// # }
    /// # impl UndoCmd for PopCmd {
    /// #   fn redo(&mut self) {
    /// #       self.e = unsafe {
    /// #           let ref mut vec = *self.vec;
    /// #           vec.pop()
    /// #       }
    /// #   }
    /// #   fn undo(&mut self) {
    /// #       unsafe {
    /// #           let ref mut vec = *self.vec;
    /// #           vec.push(self.e.unwrap());
    /// #       }
    /// #   }
    /// # }
    /// let mut vec = vec![1, 2, 3];
    /// let mut stack = UndoStack::new()
    ///     .limit(2);
    ///
    /// let cmd = PopCmd { vec: &mut vec, e: None };
    /// stack.push(cmd);
    /// stack.push(cmd);
    /// stack.push(cmd); // Pops off the first cmd.
    ///
    /// assert!(vec.is_empty());
    ///
    /// stack.undo();
    /// stack.undo();
    /// stack.undo(); // Does nothing.
    ///
    /// assert_eq!(vec, vec![1, 2]);
    /// ```
    #[inline]
    pub fn limit(mut self, limit: usize) -> Self {
        assert_ne!(limit, 0);

        if limit < self.idx {
            let x = self.idx - limit;
            self.stack.drain(..x);
            self.idx = limit;
            debug_assert_eq!(self.stack.len(), limit);
        }
        self.limit = Some(limit);
        self
    }

    /// Sets what should happen if the state changes from dirty to clean.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// Note: An empty stack is clean, so the first push will not trigger this method.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_clean(|| x += 1);
    /// ```
    #[inline]
    pub fn on_clean<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_clean = Box::new(f);
        self
    }

    /// Sets what should happen if the state changes from clean to dirty.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_dirty(|| x += 1);
    /// ```
    #[inline]
    pub fn on_dirty<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_dirty = Box::new(f);
        self
    }

    /// Returns `true` if the state of the stack is clean, `false` otherwise.
    #[inline]
    pub fn is_clean(&self) -> bool {
        self.idx == self.stack.len()
    }

    /// Returns `true` if the state of the stack is dirty, `false` otherwise.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        !self.is_clean()
    }

    /// Pushes a `UndoCmd` to the top of the `UndoStack` and executes its [`redo`] method.
    /// This pops off all `UndoCmd`s that is above the active command from the `UndoStack`.
    ///
    /// If `cmd`s id is equal to the current top command, the two commands are merged.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn push<T>(&mut self, mut cmd: T)
        where T: UndoCmd + 'a,
    {
        let is_dirty = self.is_dirty();
        let idx = self.idx;
        // Pop off all elements after idx from stack.
        self.stack.truncate(idx);
        cmd.redo();

        // Check if we should merge cmd with the top command on stack.
        let id = cmd.id();
        if idx > 0 && id.is_some() && id == unsafe { self.stack.get_unchecked(idx - 1).id() } {

            // MergeCmd is the result of the merging.
            struct MergeCmd<'a> {
                cmd1: Box<UndoCmd + 'a>,
                cmd2: Box<UndoCmd + 'a>,
            }

            impl<'a> UndoCmd for MergeCmd<'a> {
                #[inline]
                fn redo(&mut self) {
                    self.cmd1.redo();
                    self.cmd2.redo();
                }

                #[inline]
                fn undo(&mut self) {
                    self.cmd2.undo();
                    self.cmd1.undo();
                }

                #[inline]
                fn id(&self) -> Option<u64> {
                    self.cmd1.id()
                }
            }

            // Merge the command with the one on the top of the stack.
            let cmd = MergeCmd {
                cmd1: unsafe {
                    // Unchecked pop.
                    self.stack.set_len(idx - 1);
                    ::std::ptr::read(self.stack.get_unchecked(self.stack.len()))
                },
                cmd2: Box::new(cmd),
            };
            self.stack.push(Box::new(cmd));
        } else {
            match self.limit.map(|limit| idx == limit) {
                Some(false) | None => self.idx += 1,
                Some(true) => { self.stack.remove(0); },
            }
            self.stack.push(Box::new(cmd));
        }

        // State is always clean after a push, check if it was dirty before.
        if is_dirty {
            let ref mut f = self.on_clean;
            f();
        }
    }

    /// Calls the [`redo`] method for the active `UndoCmd` and sets the next `UndoCmd` as the new
    /// active one.
    ///
    /// Calling this method when there are no more commands to redo does nothing.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn redo(&mut self) {
        if self.idx < self.stack.len() {
            let is_dirty = self.is_dirty();
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.idx);
                cmd.redo();
            }
            self.idx += 1;
            // Check if stack went from dirty to clean.
            if is_dirty && self.is_clean() {
                let ref mut f = self.on_clean;
                f();
            }
        }
    }

    /// Calls the [`undo`] method for the active `UndoCmd` and sets the previous `UndoCmd` as the
    /// new active one.
    ///
    /// Calling this method when there are no more commands to undo does nothing.
    ///
    /// [`undo`]: trait.UndoCmd.html#tymethod.undo
    pub fn undo(&mut self) {
        if self.idx > 0 {
            let is_clean = self.is_clean();
            self.idx -= 1;
            debug_assert!(self.idx < self.stack.len());
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.idx);
                cmd.undo();
            }
            // Check if stack went from clean to dirty.
            if is_clean && self.is_dirty() {
                let ref mut f = self.on_dirty;
                f();
            }
        }
    }
}

impl<'a> Default for UndoStack<'a> {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl<'a> fmt::Debug for UndoStack<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("UndoStack")
            .field("stack", &self.stack)
            .field("idx", &self.idx)
            .finish()
    }
}

#[cfg(test)]
mod test {
    use {UndoStack, UndoCmd};

    #[derive(Clone, Copy)]
    struct PopCmd {
        vec: *mut Vec<i32>,
        e: Option<i32>,
    }

    impl UndoCmd for PopCmd {
        fn redo(&mut self) {
            self.e = unsafe {
                let ref mut vec = *self.vec;
                vec.pop()
            }
        }

        fn undo(&mut self) {
            unsafe {
                let ref mut vec = *self.vec;
                vec.push(self.e.unwrap());
            }
        }
    }

    #[test]
    fn pop() {
        use std::cell::Cell;

        let x = Cell::new(0);
        let mut vec = vec![1, 2, 3];
        let mut undo_stack = UndoStack::new()
            .on_clean(|| x.set(0))
            .on_dirty(|| x.set(1));

        let cmd = PopCmd { vec: &mut vec, e: None };
        for _ in 0..3 {
            undo_stack.push(cmd);
        }
        assert_eq!(x.get(), 0);
        assert!(vec.is_empty());

        for _ in 0..3 {
            undo_stack.undo();
        }
        assert_eq!(x.get(), 1);
        assert_eq!(vec, vec![1, 2, 3]);

        undo_stack.push(cmd);
        assert_eq!(x.get(), 0);
        assert_eq!(vec, vec![1, 2]);

        undo_stack.undo();
        assert_eq!(x.get(), 1);
        assert_eq!(vec, vec![1, 2, 3]);

        undo_stack.redo();
        assert_eq!(x.get(), 0);
        assert_eq!(vec, vec![1, 2]);
    }

    #[test]
    fn limit() {
        let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let mut undo_stack = UndoStack::new();

        let cmd = PopCmd { vec: &mut vec, e: None };

        for _ in 0..6 {
            undo_stack.push(cmd);
        }
        assert_eq!(vec, vec![1, 2, 3, 4]);

        undo_stack = undo_stack.limit(3);
        assert_eq!(undo_stack.stack.len(), 3);

        for _ in 0..6 {
            undo_stack.undo();
        }
        assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7]);

        for _ in 0..6 {
            undo_stack.redo();
        }
        assert_eq!(vec, vec![1, 2, 3, 4]);
    }
}
<commit_msg>Remove ~25% of stack when limit is reached<commit_after>use std::fmt;
use UndoCmd;

/// `UndoStack` maintains a stack of `UndoCmd`s that can be undone and redone by using methods
/// on the `UndoStack`.
///
/// `UndoStack` will notice when it's state changes to either dirty or clean, and the user can
/// set methods that should be called for either state change. This is useful for example if
/// you want to automatically enable or disable undo or redo buttons based on there are any
/// more actions that can be undone or redone.
pub struct UndoStack<'a> {
    // All commands on the stack.
    stack: Vec<Box<UndoCmd + 'a>>,
    // Current position in the stack.
    idx: usize,
    // Max amount of commands allowed on the stack.
    limit: Option<usize>,
    // Called when the state changes from dirty to clean.
    on_clean: Box<FnMut() + 'a>,
    // Called when the state changes from clean to dirty.
    on_dirty: Box<FnMut() + 'a>,
}

impl<'a> UndoStack<'a> {
    /// Creates a new `UndoStack`.
    #[inline]
    pub fn new() -> Self {
        UndoStack {
            stack: Vec::new(),
            idx: 0,
            limit: None,
            on_clean: Box::new(|| {}),
            on_dirty: Box::new(|| {}),
        }
    }

    /// Creates a new `UndoStack` with the specified capacity.
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        UndoStack {
            stack: Vec::with_capacity(capacity),
            idx: 0,
            limit: None,
            on_clean: Box::new(|| {}),
            on_dirty: Box::new(|| {}),
        }
    }

    /// Returns the capacity of the `UndoStack`.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.stack.capacity()
    }

    /// Reserves capacity for at least `additional` more commands to be inserted in the given stack.
    /// The stack may reserve more space to avoid frequent reallocations.
    ///
    /// # Panics
    /// Panics if the new capacity overflows usize.
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.stack.reserve(additional);
    }

    /// Shrinks the capacity of the `UndoStack` as much as possible.
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.stack.shrink_to_fit();
    }

    /// Sets the limit on how many `UndoCmd`s can be stored in the stack. If this limit is reached
    /// it will start popping of commands at the bottom of the stack when pushing new commands
    /// on to the stack. No limit is set by default which means it may grow indefinitely.
    ///
    /// The stack will never grow above the limit, but it may remove multiple commands at a
    /// time to increase performance.
    ///
    /// # Panics
    /// Panics if the given limit is zero.
    ///
    /// # Examples
    /// ```
    /// # use undo::{UndoCmd, UndoStack};
    /// # #[derive(Clone, Copy)]
    /// # struct PopCmd {
    /// #   vec: *mut Vec<i32>,
    /// #   e: Option<i32>,
    /// # }
    /// # impl UndoCmd for PopCmd {
    /// #   fn redo(&mut self) {
    /// #       self.e = unsafe {
    /// #           let ref mut vec = *self.vec;
    /// #           vec.pop()
    /// #       }
    /// #   }
    /// #   fn undo(&mut self) {
    /// #       unsafe {
    /// #           let ref mut vec = *self.vec;
    /// #           vec.push(self.e.unwrap());
    /// #       }
    /// #   }
    /// # }
    /// let mut vec = vec![1, 2, 3];
    /// let mut stack = UndoStack::new()
    ///     .limit(2);
    ///
    /// let cmd = PopCmd { vec: &mut vec, e: None };
    /// stack.push(cmd);
    /// stack.push(cmd);
    /// stack.push(cmd); // Pops off the first cmd.
    ///
    /// assert!(vec.is_empty());
    ///
    /// stack.undo();
    /// stack.undo();
    /// stack.undo(); // Does nothing.
    ///
    /// assert_eq!(vec, vec![1, 2]);
    /// ```
    #[inline]
    pub fn limit(mut self, limit: usize) -> Self {
        assert_ne!(limit, 0);

        if limit < self.idx {
            let x = self.idx - limit;
            self.stack.drain(..x);
            self.idx = limit;
            debug_assert_eq!(self.idx, self.stack.len());
        }
        self.limit = Some(limit);
        self
    }

    /// Sets what should happen if the state changes from dirty to clean.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// Note: An empty stack is clean, so the first push will not trigger this method.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_clean(|| x += 1);
    /// ```
    #[inline]
    pub fn on_clean<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_clean = Box::new(f);
        self
    }

    /// Sets what should happen if the state changes from clean to dirty.
    /// By default the `UndoStack` does nothing when the state changes.
    ///
    /// # Examples
    /// ```
    /// # #![allow(unused_variables)]
    /// # use undo::UndoStack;
    /// let mut x = 0;
    /// let stack = UndoStack::new()
    ///     .on_dirty(|| x += 1);
    /// ```
    #[inline]
    pub fn on_dirty<F>(mut self, f: F) -> Self
        where F: FnMut() + 'a,
    {
        self.on_dirty = Box::new(f);
        self
    }

    /// Returns `true` if the state of the stack is clean, `false` otherwise.
    #[inline]
    pub fn is_clean(&self) -> bool {
        self.idx == self.stack.len()
    }

    /// Returns `true` if the state of the stack is dirty, `false` otherwise.
    #[inline]
    pub fn is_dirty(&self) -> bool {
        !self.is_clean()
    }

    /// Pushes a `UndoCmd` to the top of the `UndoStack` and executes its [`redo`] method.
    /// This pops off all `UndoCmd`s that is above the active command from the `UndoStack`.
    ///
    /// If `cmd`s id is equal to the current top command, the two commands are merged.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn push<T>(&mut self, mut cmd: T)
        where T: UndoCmd + 'a,
    {
        let is_dirty = self.is_dirty();
        let idx = self.idx;
        // Pop off all elements after idx from stack.
        self.stack.truncate(idx);
        cmd.redo();

        // Check if we should merge cmd with the top command on stack.
        let id = cmd.id();
        if idx != 0 && id.is_some() && id == unsafe { self.stack.get_unchecked(idx - 1).id() } {

            // MergeCmd is the result of the merging.
            struct MergeCmd<'a> {
                cmd1: Box<UndoCmd + 'a>,
                cmd2: Box<UndoCmd + 'a>,
            }

            impl<'a> UndoCmd for MergeCmd<'a> {
                #[inline]
                fn redo(&mut self) {
                    self.cmd1.redo();
                    self.cmd2.redo();
                }

                #[inline]
                fn undo(&mut self) {
                    self.cmd2.undo();
                    self.cmd1.undo();
                }

                #[inline]
                fn id(&self) -> Option<u64> {
                    self.cmd1.id()
                }
            }

            // Merge the command with the one on the top of the stack.
            let cmd = MergeCmd {
                cmd1: unsafe {
                    // Unchecked pop.
                    self.stack.set_len(idx - 1);
                    ::std::ptr::read(self.stack.get_unchecked(self.stack.len()))
                },
                cmd2: Box::new(cmd),
            };
            self.stack.push(Box::new(cmd));
        } else {
            match self.limit {
                Some(limit) if idx == limit => {
                    // Remove ~25% of the stack at once.
                    let x = idx / 4 + 1;
                    self.stack.drain(..x);
                    self.idx -= x - 1;
                },
                _ => self.idx += 1,
            }
            self.stack.push(Box::new(cmd));
        }

        debug_assert_eq!(self.idx, self.stack.len());
        // State is always clean after a push, check if it was dirty before.
        if is_dirty {
            let ref mut f = self.on_clean;
            f();
        }
    }

    /// Calls the [`redo`] method for the active `UndoCmd` and sets the next `UndoCmd` as the new
    /// active one.
    ///
    /// Calling this method when there are no more commands to redo does nothing.
    ///
    /// [`redo`]: trait.UndoCmd.html#tymethod.redo
    pub fn redo(&mut self) {
        if self.idx < self.stack.len() {
            let is_dirty = self.is_dirty();
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.idx);
                cmd.redo();
            }
            self.idx += 1;
            // Check if stack went from dirty to clean.
            if is_dirty && self.is_clean() {
                let ref mut f = self.on_clean;
                f();
            }
        }
    }

    /// Calls the [`undo`] method for the active `UndoCmd` and sets the previous `UndoCmd` as the
    /// new active one.
    ///
    /// Calling this method when there are no more commands to undo does nothing.
    ///
    /// [`undo`]: trait.UndoCmd.html#tymethod.undo
    pub fn undo(&mut self) {
        if self.idx > 0 {
            let is_clean = self.is_clean();
            self.idx -= 1;
            debug_assert!(self.idx < self.stack.len());
            unsafe {
                let cmd = self.stack.get_unchecked_mut(self.idx);
                cmd.undo();
            }
            // Check if stack went from clean to dirty.
            if is_clean && self.is_dirty() {
                let ref mut f = self.on_dirty;
                f();
            }
        }
    }
}

impl<'a> Default for UndoStack<'a> {
    #[inline]
    fn default() -> Self {
        Self::new()
    }
}

impl<'a> fmt::Debug for UndoStack<'a> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("UndoStack")
            .field("stack", &self.stack)
            .field("idx", &self.idx)
            .finish()
    }
}

#[cfg(test)]
mod test {
    use {UndoStack, UndoCmd};

    #[derive(Clone, Copy)]
    struct PopCmd {
        vec: *mut Vec<i32>,
        e: Option<i32>,
    }

    impl UndoCmd for PopCmd {
        fn redo(&mut self) {
            self.e = unsafe {
                let ref mut vec = *self.vec;
                vec.pop()
            }
        }

        fn undo(&mut self) {
            unsafe {
                let ref mut vec = *self.vec;
                vec.push(self.e.unwrap());
            }
        }
    }

    #[test]
    fn pop() {
        use std::cell::Cell;

        let x = Cell::new(0);
        let mut vec = vec![1, 2, 3];
        let mut stack = UndoStack::new()
            .on_clean(|| x.set(0))
            .on_dirty(|| x.set(1));

        let cmd = PopCmd { vec: &mut vec, e: None };
        for _ in 0..3 {
            stack.push(cmd);
        }
        assert_eq!(x.get(), 0);
        assert!(vec.is_empty());

        for _ in 0..3 {
            stack.undo();
        }
        assert_eq!(x.get(), 1);
        assert_eq!(vec, vec![1, 2, 3]);

        stack.push(cmd);
        assert_eq!(x.get(), 0);
        assert_eq!(vec, vec![1, 2]);

        stack.undo();
        assert_eq!(x.get(), 1);
        assert_eq!(vec, vec![1, 2, 3]);

        stack.redo();
        assert_eq!(x.get(), 0);
        assert_eq!(vec, vec![1, 2]);
    }

    #[test]
    fn limit() {
        let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let mut stack = UndoStack::new();

        let cmd = PopCmd { vec: &mut vec, e: None };

        for _ in 0..6 {
            stack.push(cmd);
        }
        assert_eq!(vec, vec![1, 2, 3, 4]);

        stack = stack.limit(3);
        assert_eq!(stack.stack.len(), 3);

        for _ in 0..6 {
            stack.undo();
        }
        assert_eq!(vec, vec![1, 2, 3, 4, 5, 6, 7]);

        for _ in 0..6 {
            stack.redo();
        }
        assert_eq!(vec, vec![1, 2, 3, 4]);
    }
}
<|endoftext|>


<commit_before>use super::model::*;

/// The websocket protocol version expected.
const VERSION: u64 = 3;

/// Known state composed from received events.
#[derive(Debug, Clone)]
pub struct State {
	user: CurrentUser,
	settings: UserSettings,
	server_settings: Vec<UserServerSettings>,
	session_id: String,
	private_channels: Vec<PrivateChannel>,
	servers: Vec<LiveServer>,
}

impl State {
	/// Create a new state from an initial `ReadyEvent`.
	pub fn new(ready: ReadyEvent) -> State {
		if ready.version != VERSION {
			warn!("Got protocol version {} instead of {}", ready.version, VERSION);
		}
		State {
			user: ready.user,
			settings: ready.user_settings,
			server_settings: ready.user_server_settings,
			session_id: ready.session_id,
			private_channels: ready.private_channels,
			servers: ready.servers,
		}
	}

	/// Update the state according to the changes described in the given event.
	pub fn update(&mut self, event: &Event) {
		match *event {
			Event::Ready(ref ready) => *self = State::new(ready.clone()),
			Event::GatewayChanged(_, ref ready) => *self = State::new(ready.clone()),
			Event::UserUpdate(ref user) => self.user = user.clone(),
			Event::UserSettingsUpdate {
				ref enable_tts_command, ref inline_attachment_media,
				ref inline_embed_media, ref locale,
				ref message_display_compact, ref muted_channels,
				ref render_embeds, ref show_current_game,
				ref theme, ref convert_emoticons,
			} => {
				opt_modify(&mut self.settings.enable_tts_command, enable_tts_command);
				opt_modify(&mut self.settings.inline_attachment_media, inline_attachment_media);
				opt_modify(&mut self.settings.inline_embed_media, inline_embed_media);
				opt_modify(&mut self.settings.locale, locale);
				opt_modify(&mut self.settings.message_display_compact, message_display_compact);
				opt_modify(&mut self.settings.muted_channels, muted_channels);
				opt_modify(&mut self.settings.render_embeds, render_embeds);
				opt_modify(&mut self.settings.show_current_game, show_current_game);
				opt_modify(&mut self.settings.theme, theme);
				opt_modify(&mut self.settings.convert_emoticons, convert_emoticons);
			}
			Event::UserServerSettingsUpdate(ref settings) => {
				self.server_settings.iter_mut().find(|s| s.server_id == settings.server_id).map(|srv| {
					srv.clone_from(settings);
				});
			}
			Event::VoiceStateUpdate(ref server, ref state) => {
				self.servers.iter_mut().find(|s| s.id == *server).map(|srv| {
					if !state.channel_id.is_some() {
						// Remove the user from the voice state list
						srv.voice_states.retain(|v| v.user_id != state.user_id);
					} else {
						// Update or add to the voice state list
						match srv.voice_states.iter_mut().find(|u| u.user_id == state.user_id) {
							Some(srv_state) => { srv_state.clone_from(state); return }
							None => {}
						}
						srv.voice_states.push(state.clone());
					}
				});
			}
			Event::PresenceUpdate { ref server_id, ref presence, ref user, roles: _ } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					// If the user was modified, update the member list
					if let &Some(ref user) = user {
						srv.members.iter_mut().find(|u| u.user.id == user.id).map(|member| {
							member.user.clone_from(&user);
						});
					}
					if presence.status == OnlineStatus::Offline {
						// Remove the user from the presence list
						srv.presences.retain(|u| u.user_id != presence.user_id);
					} else {
						// Update or add to the presence list
						match srv.presences.iter_mut().find(|u| u.user_id == presence.user_id) {
							Some(srv_presence) => { srv_presence.clone_from(presence); return }
							None => {}
						}
						srv.presences.push(presence.clone());
					}
				});
			}
			Event::ServerCreate(ref server) => self.servers.push(server.clone()),
			Event::ServerUpdate(ref server) => {
				self.servers.iter_mut().find(|s| s.id == server.id).map(|srv| {
					srv.name.clone_from(&server.name);
					srv.afk_timeout = server.afk_timeout;
					srv.afk_channel_id.clone_from(&server.afk_channel_id);
					srv.icon.clone_from(&server.icon);
					srv.roles.clone_from(&server.roles);
					srv.region.clone_from(&server.region);
					// embed_enabled and embed_channel_id skipped
					srv.owner_id.clone_from(&server.owner_id);
					srv.verification_level = server.verification_level;
				});
			}
			Event::ServerDelete(ref server) => self.servers.retain(|s| s.id != server.id),
			Event::ServerMemberAdd { ref server_id, ref joined_at, ref roles, ref user } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.member_count += 1;
					srv.members.push(Member {
						user: user.clone(),
						roles: roles.clone(),
						joined_at: joined_at.clone(),
						mute: false,
						deaf: false,
					})
				});
			}
			Event::ServerMemberUpdate { ref server_id, ref roles, ref user } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.members.iter_mut().find(|m| m.user.id == user.id).map(|member| {
						member.user.clone_from(user);
						member.roles.clone_from(roles);
					})
				});
			}
			Event::ServerMemberRemove(ref server_id, ref user) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.member_count -= 1;
					srv.members.retain(|m| m.user.id != user.id);
				});
			}
			Event::ServerRoleCreate(ref server_id, ref role) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.push(role.clone());
				});
			}
			Event::ServerRoleUpdate(ref server_id, ref role) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.iter_mut().find(|r| r.id == role.id).map(|srv_role| {
						srv_role.clone_from(role);
					});
				});
			}
			Event::ServerRoleDelete(ref server_id, ref role_id) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.retain(|r| r.id != *role_id);
				});
			}
			Event::ChannelCreate(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.push(channel.clone());
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.push(channel.clone());
					});
				}
			},
			Event::ChannelUpdate(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.iter_mut().find(|c| c.id == channel.id).map(|chan| {
						chan.clone_from(channel);
					});
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.iter_mut().find(|c| c.id == channel.id).map(|chan| {
							chan.clone_from(channel);
						})
					});
				}
			},
			Event::ChannelDelete(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.retain(|c| c.id != channel.id);
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.retain(|c| c.id != channel.id);
					});
				}
			},
			_ => {}
		}
	}

	/// Get information about the logged-in user.
	#[inline]
	pub fn user(&self) -> &CurrentUser { &self.user }

	/// Get the logged-in user's client settings.
	#[inline]
	pub fn settings(&self) -> &UserSettings { &self.settings }

	/// Get the websocket session ID.
	#[inline]
	pub fn session_id(&self) -> &str { &self.session_id }

	/// Get the list of private channels with other users.
	#[inline]
	pub fn private_channels(&self) -> &[PrivateChannel] { &self.private_channels }

	/// Get the list of servers this user has access to.
	#[inline]
	pub fn servers(&self) -> &[LiveServer] { &self.servers }

	/// Look up a private or public channel by its ID.
	pub fn find_channel(&self, id: &ChannelId) -> Option<ChannelRef> {
		for server in &self.servers {
			for channel in &server.channels {
				if channel.id == *id {
					return Some(ChannelRef::Public(server, channel))
				}
			}
		}
		for channel in &self.private_channels {
			if channel.id == *id {
				return Some(ChannelRef::Private(channel))
			}
		}
		None
	}
}

/// A reference to a private or public channel
#[derive(Debug, Clone, Copy)]
pub enum ChannelRef<'a> {
	/// A private channel
	Private(&'a PrivateChannel),
	/// A public channel and its server
	Public(&'a LiveServer, &'a PublicChannel),
}

#[inline]
fn opt_modify<T: Clone>(dest: &mut T, src: &Option<T>) {
	if let Some(val) = src.as_ref() {
		dest.clone_from(val);
	}
}
<commit_msg>Expose per-server settings in State<commit_after>use super::model::*;

/// The websocket protocol version expected.
const VERSION: u64 = 3;

/// Known state composed from received events.
#[derive(Debug, Clone)]
pub struct State {
	user: CurrentUser,
	settings: UserSettings,
	server_settings: Vec<UserServerSettings>,
	session_id: String,
	private_channels: Vec<PrivateChannel>,
	servers: Vec<LiveServer>,
}

impl State {
	/// Create a new state from an initial `ReadyEvent`.
	pub fn new(ready: ReadyEvent) -> State {
		if ready.version != VERSION {
			warn!("Got protocol version {} instead of {}", ready.version, VERSION);
		}
		State {
			user: ready.user,
			settings: ready.user_settings,
			server_settings: ready.user_server_settings,
			session_id: ready.session_id,
			private_channels: ready.private_channels,
			servers: ready.servers,
		}
	}

	/// Update the state according to the changes described in the given event.
	pub fn update(&mut self, event: &Event) {
		match *event {
			Event::Ready(ref ready) => *self = State::new(ready.clone()),
			Event::GatewayChanged(_, ref ready) => *self = State::new(ready.clone()),
			Event::UserUpdate(ref user) => self.user = user.clone(),
			Event::UserSettingsUpdate {
				ref enable_tts_command, ref inline_attachment_media,
				ref inline_embed_media, ref locale,
				ref message_display_compact, ref muted_channels,
				ref render_embeds, ref show_current_game,
				ref theme, ref convert_emoticons,
			} => {
				opt_modify(&mut self.settings.enable_tts_command, enable_tts_command);
				opt_modify(&mut self.settings.inline_attachment_media, inline_attachment_media);
				opt_modify(&mut self.settings.inline_embed_media, inline_embed_media);
				opt_modify(&mut self.settings.locale, locale);
				opt_modify(&mut self.settings.message_display_compact, message_display_compact);
				opt_modify(&mut self.settings.muted_channels, muted_channels);
				opt_modify(&mut self.settings.render_embeds, render_embeds);
				opt_modify(&mut self.settings.show_current_game, show_current_game);
				opt_modify(&mut self.settings.theme, theme);
				opt_modify(&mut self.settings.convert_emoticons, convert_emoticons);
			}
			Event::UserServerSettingsUpdate(ref settings) => {
				self.server_settings.iter_mut().find(|s| s.server_id == settings.server_id).map(|srv| {
					srv.clone_from(settings);
				});
			}
			Event::VoiceStateUpdate(ref server, ref state) => {
				self.servers.iter_mut().find(|s| s.id == *server).map(|srv| {
					if !state.channel_id.is_some() {
						// Remove the user from the voice state list
						srv.voice_states.retain(|v| v.user_id != state.user_id);
					} else {
						// Update or add to the voice state list
						match srv.voice_states.iter_mut().find(|u| u.user_id == state.user_id) {
							Some(srv_state) => { srv_state.clone_from(state); return }
							None => {}
						}
						srv.voice_states.push(state.clone());
					}
				});
			}
			Event::PresenceUpdate { ref server_id, ref presence, ref user, roles: _ } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					// If the user was modified, update the member list
					if let &Some(ref user) = user {
						srv.members.iter_mut().find(|u| u.user.id == user.id).map(|member| {
							member.user.clone_from(&user);
						});
					}
					if presence.status == OnlineStatus::Offline {
						// Remove the user from the presence list
						srv.presences.retain(|u| u.user_id != presence.user_id);
					} else {
						// Update or add to the presence list
						match srv.presences.iter_mut().find(|u| u.user_id == presence.user_id) {
							Some(srv_presence) => { srv_presence.clone_from(presence); return }
							None => {}
						}
						srv.presences.push(presence.clone());
					}
				});
			}
			Event::ServerCreate(ref server) => self.servers.push(server.clone()),
			Event::ServerUpdate(ref server) => {
				self.servers.iter_mut().find(|s| s.id == server.id).map(|srv| {
					srv.name.clone_from(&server.name);
					srv.afk_timeout = server.afk_timeout;
					srv.afk_channel_id.clone_from(&server.afk_channel_id);
					srv.icon.clone_from(&server.icon);
					srv.roles.clone_from(&server.roles);
					srv.region.clone_from(&server.region);
					// embed_enabled and embed_channel_id skipped
					srv.owner_id.clone_from(&server.owner_id);
					srv.verification_level = server.verification_level;
				});
			}
			Event::ServerDelete(ref server) => self.servers.retain(|s| s.id != server.id),
			Event::ServerMemberAdd { ref server_id, ref joined_at, ref roles, ref user } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.member_count += 1;
					srv.members.push(Member {
						user: user.clone(),
						roles: roles.clone(),
						joined_at: joined_at.clone(),
						mute: false,
						deaf: false,
					})
				});
			}
			Event::ServerMemberUpdate { ref server_id, ref roles, ref user } => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.members.iter_mut().find(|m| m.user.id == user.id).map(|member| {
						member.user.clone_from(user);
						member.roles.clone_from(roles);
					})
				});
			}
			Event::ServerMemberRemove(ref server_id, ref user) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.member_count -= 1;
					srv.members.retain(|m| m.user.id != user.id);
				});
			}
			Event::ServerRoleCreate(ref server_id, ref role) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.push(role.clone());
				});
			}
			Event::ServerRoleUpdate(ref server_id, ref role) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.iter_mut().find(|r| r.id == role.id).map(|srv_role| {
						srv_role.clone_from(role);
					});
				});
			}
			Event::ServerRoleDelete(ref server_id, ref role_id) => {
				self.servers.iter_mut().find(|s| s.id == *server_id).map(|srv| {
					srv.roles.retain(|r| r.id != *role_id);
				});
			}
			Event::ChannelCreate(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.push(channel.clone());
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.push(channel.clone());
					});
				}
			},
			Event::ChannelUpdate(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.iter_mut().find(|c| c.id == channel.id).map(|chan| {
						chan.clone_from(channel);
					});
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.iter_mut().find(|c| c.id == channel.id).map(|chan| {
							chan.clone_from(channel);
						})
					});
				}
			},
			Event::ChannelDelete(ref channel) => match *channel {
				Channel::Private(ref channel) => {
					self.private_channels.retain(|c| c.id != channel.id);
				}
				Channel::Public(ref channel) => {
					self.servers.iter_mut().find(|s| s.id == channel.server_id).map(|srv| {
						srv.channels.retain(|c| c.id != channel.id);
					});
				}
			},
			_ => {}
		}
	}

	/// Get information about the logged-in user.
	#[inline]
	pub fn user(&self) -> &CurrentUser { &self.user }

	/// Get the logged-in user's client settings.
	#[inline]
	pub fn settings(&self) -> &UserSettings { &self.settings }

	/// Get the logged-in user's per-server notification settings.
	#[inline]
	pub fn server_settings(&self) -> &[UserServerSettings] { &self.server_settings }

	/// Get the websocket session ID.
	#[inline]
	pub fn session_id(&self) -> &str { &self.session_id }

	/// Get the list of private channels with other users.
	#[inline]
	pub fn private_channels(&self) -> &[PrivateChannel] { &self.private_channels }

	/// Get the list of servers this user has access to.
	#[inline]
	pub fn servers(&self) -> &[LiveServer] { &self.servers }

	/// Look up a private or public channel by its ID.
	pub fn find_channel(&self, id: &ChannelId) -> Option<ChannelRef> {
		for server in &self.servers {
			for channel in &server.channels {
				if channel.id == *id {
					return Some(ChannelRef::Public(server, channel))
				}
			}
		}
		for channel in &self.private_channels {
			if channel.id == *id {
				return Some(ChannelRef::Private(channel))
			}
		}
		None
	}
}

/// A reference to a private or public channel
#[derive(Debug, Clone, Copy)]
pub enum ChannelRef<'a> {
	/// A private channel
	Private(&'a PrivateChannel),
	/// A public channel and its server
	Public(&'a LiveServer, &'a PublicChannel),
}

#[inline]
fn opt_modify<T: Clone>(dest: &mut T, src: &Option<T>) {
	if let Some(val) = src.as_ref() {
		dest.clone_from(val);
	}
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::rc::Rc;

use actix_http::error::{Error, ErrorInternalServerError};
use actix_http::Extensions;
use futures::{Async, Future, IntoFuture, Poll};

use crate::extract::FromRequest;
use crate::service::ServiceFromRequest;

/// Application state factory
pub(crate) trait StateFactory {
    fn construct(&self) -> Box<StateFactoryResult>;
}

pub(crate) trait StateFactoryResult {
    fn poll_result(&mut self, extensions: &mut Extensions) -> Poll<(), ()>;
}

/// Application state
pub struct State<T>(Rc<T>);

impl<T> State<T> {
    pub(crate) fn new(state: T) -> State<T> {
        State(Rc::new(state))
    }

    /// Get referecnce to inner state type.
    pub fn get_ref(&self) -> &T {
        self.0.as_ref()
    }
}

impl<T> Deref for State<T> {
    type Target = T;

    fn deref(&self) -> &T {
        self.0.as_ref()
    }
}

impl<T> Clone for State<T> {
    fn clone(&self) -> State<T> {
        State(self.0.clone())
    }
}

impl<T: 'static, P> FromRequest<P> for State<T> {
    type Error = Error;
    type Future = Result<Self, Error>;
    type Config = ();

    #[inline]
    fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
        if let Some(st) = req.app_extensions().get::<State<T>>() {
            Ok(st.clone())
        } else {
            Err(ErrorInternalServerError(
                "State is not configured, to configure use App::state()",
            ))
        }
    }
}

impl<T: 'static> StateFactory for State<T> {
    fn construct(&self) -> Box<StateFactoryResult> {
        Box::new(StateFut { st: self.clone() })
    }
}

struct StateFut<T> {
    st: State<T>,
}

impl<T: 'static> StateFactoryResult for StateFut<T> {
    fn poll_result(&mut self, extensions: &mut Extensions) -> Poll<(), ()> {
        extensions.insert(self.st.clone());
        Ok(Async::Ready(()))
    }
}

impl<F, Out> StateFactory for F
where
    F: Fn() -> Out + 'static,
    Out: IntoFuture + 'static,
    Out::Error: std::fmt::Debug,
{
    fn construct(&self) -> Box<StateFactoryResult> {
        Box::new(StateFactoryFut {
            fut: (*self)().into_future(),
        })
    }
}

struct StateFactoryFut<T, F>
where
    F: Future<Item = T>,
    F::Error: std::fmt::Debug,
{
    fut: F,
}

impl<T: 'static, F> StateFactoryResult for StateFactoryFut<T, F>
where
    F: Future<Item = T>,
    F::Error: std::fmt::Debug,
{
    fn poll_result(&mut self, extensions: &mut Extensions) -> Poll<(), ()> {
        match self.fut.poll() {
            Ok(Async::Ready(s)) => {
                extensions.insert(State::new(s));
                Ok(Async::Ready(()))
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(e) => {
                log::error!("Can not construct application state: {:?}", e);
                Err(())
            }
        }
    }
}
<commit_msg>make State type Send compatible<commit_after>use std::ops::Deref;
use std::sync::Arc;

use actix_http::error::{Error, ErrorInternalServerError};
use actix_http::Extensions;
use futures::{Async, Future, IntoFuture, Poll};

use crate::extract::FromRequest;
use crate::service::ServiceFromRequest;

/// Application state factory
pub(crate) trait StateFactory {
    fn construct(&self) -> Box<StateFactoryResult>;
}

pub(crate) trait StateFactoryResult {
    fn poll_result(&mut self, extensions: &mut Extensions) -> Poll<(), ()>;
}

/// Application state
pub struct State<T>(Arc<T>);

impl<T> State<T> {
    pub(crate) fn new(state: T) -> State<T> {
        State(Arc::new(state))
    }

    /// Get referecnce to inner state type.
    pub fn get_ref(&self) -> &T {
        self.0.as_ref()
    }
}

impl<T> Deref for State<T> {
    type Target = T;

    fn deref(&self) -> &T {
        self.0.as_ref()
    }
}

impl<T> Clone for State<T> {
    fn clone(&self) -> State<T> {
        State(self.0.clone())
    }
}

impl<T: 'static, P> FromRequest<P> for State<T> {
    type Error = Error;
    type Future = Result<Self, Error>;
    type Config = ();

    #[inline]
    fn from_request(req: &mut ServiceFromRequest<P>) -> Self::Future {
        if let Some(st) = req.app_extensions().get::<State<T>>() {
            Ok(st.clone())
        } else {
            Err(ErrorInternalServerError(
                "State is not configured, to configure use App::state()",
            ))
        }
    }
}

impl<T: 'static> StateFactory for State<T> {
    fn construct(&self) -> Box<StateFactoryResult> {
        Box::new(StateFut { st: self.clone() })
    }
}

struct StateFut<T> {
    st: State<T>,
}

impl<T: 'static> StateFactoryResult for StateFut<T> {
    fn poll_result(&mut self, extensions: &mut Extensions) -> Poll<(), ()> {
        extensions.insert(self.st.clone());
        Ok(Async::Ready(()))
    }
}

impl<F, Out> StateFactory for F
where
    F: Fn() -> Out + 'static,
    Out: IntoFuture + 'static,
    Out::Error: std::fmt::Debug,
{
    fn construct(&self) -> Box<StateFactoryResult> {
        Box::new(StateFactoryFut {
            fut: (*self)().into_future(),
        })
    }
}

struct StateFactoryFut<T, F>
where
    F: Future<Item = T>,
    F::Error: std::fmt::Debug,
{
    fut: F,
}

impl<T: 'static, F> StateFactoryResult for StateFactoryFut<T, F>
where
    F: Future<Item = T>,
    F::Error: std::fmt::Debug,
{
    fn poll_result(&mut self, extensions: &mut Extensions) -> Poll<(), ()> {
        match self.fut.poll() {
            Ok(Async::Ready(s)) => {
                extensions.insert(State::new(s));
                Ok(Async::Ready(()))
            }
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(e) => {
                log::error!("Can not construct application state: {:?}", e);
                Err(())
            }
        }
    }
}
<|endoftext|>