<commit_before>use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::hash_map::Entry::*;
use std::hash::{Hash, Hasher};
use std::iter;
use std::str::CharIndices;
use std::ops;
use itertools::{GroupBy, Itertools};
use coalesce::Coalesce;

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Debug, Eq, Ord, RustcEncodable, RustcDecodable)]
pub struct Document {
    id: String,
    content: String,
}

impl Document {
    /// Construct a new Document from an id and content.
    /// Both two arguments can be anything that can be turned into a String.
    pub fn new<S, T>(id: S, content: T) -> Document
        where S: Into<String>,
              T: Into<String>
    {
        Document { id: id.into(), content: content.into(), }
    }

    pub fn id(&self) -> &str {
        &self.id
    }

    pub fn content(&self) -> &str {
        &self.content
    }
}

impl Hash for Document {
    // Documents are unique only upon their id
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.id.hash(state);
    }
}

impl PartialEq for Document {
    // Documents are unique only upon their id
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

impl PartialOrd for Document {
    fn partial_cmp(&self, other: &Document) -> Option<::std::cmp::Ordering> {
        self.id.partial_cmp(&other.id)
    }
}

/// A SearchResult is the representation of a Document returned for a specific set of search
/// terms. It is unique upon the document and the vec of highlight indices. It also contains a
/// search score for use in ranking against the other search results
#[derive(Clone, Debug, RustcEncodable)]
pub struct SearchResult<'a> {
    doc: &'a Document,
    highlights: Vec<(usize, usize)>,
    score: f32,
}

impl<'a> SearchResult<'a> {
    fn new(doc: &'a Document, mut highlights: Vec<(usize, usize)>) -> SearchResult<'a> {
        SearchResult {
            score: highlights.iter()
                .map(|&(begin, end)| end - begin)
                .sum::<usize>() as f32 / (doc.content.len() as f32).sqrt(),
            doc: doc,
            highlights: { highlights.sort(); highlights },
        }
    }

    /// Returns the document
    pub fn doc(&self) -> &Document {
        &self.doc
    }

    /// Returns the highlighted indices.
    ///
    /// Each `(usize, usize)` indicates the start and end of a term in the document's content
    /// that should be highlighted.
    pub fn highlights(&self) -> &Vec<(usize, usize)> {
        &self.highlights
    }

    /// Returns the search result's score.
    ///
    /// Score is computed by the product of the summed length of the matching terms and the inverse
    /// square root of the length of the document. Taking the square root of the document's length
    /// helps to combat bias toward short content.
    pub fn score(&self) -> f32 {
        self.score
    }

    pub fn highlight(&self, before: &str, after: &str) -> String {
        let mut begin_idx = 0;
        let mut parts = String::new();
        for &(begin, end) in &self.highlights {
            parts.push_str(&self.doc.content[begin_idx..begin]);
            parts.push_str(before);
            parts.push_str(&self.doc.content[begin..end]);
            parts.push_str(after);
            begin_idx = end;
        }
        parts.push_str(&self.doc.content[begin_idx..]);
        parts
    }
}

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to sets of Documents.
#[derive(Debug)]
pub struct InvertedIndex {
    index: BTreeMap<String, BTreeMap<String, Vec<(usize, usize)>>>,
    docs: BTreeMap<String, Document>,
}

impl InvertedIndex {
    pub fn new() -> InvertedIndex {
        InvertedIndex {
            index: BTreeMap::new(),
            docs: BTreeMap::new(),
        }
    }

    /// A basic implementation of index, splits the document's content into whitespace-separated
    /// words, and inserts each word-document pair into the map.
    pub fn index(&mut self, doc: Document) {
        let analyzed  = analyze_doc(doc.content());
        let previous_version = self.docs.insert(doc.id.clone(), doc.clone());
        if let Some(previous_version) = previous_version {
            let previous_analyzed = analyze_doc(previous_version.content());
            for (ngram, _) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&doc.id);
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        for (ngram, highlighted) in analyzed {
            let mut highlights = self.index.entry(ngram)
                .or_insert_with(BTreeMap::new)
                .entry(doc.id.clone())
                .or_insert_with(Vec::new);
            let coalesce_idx = highlights.binary_search(&highlighted).err().unwrap();
            highlights.coalesce(coalesce_idx, highlighted);
        }
    }

    /// A basic search implementation that splits the query's content into whitespace-separated
    /// words, looks up the set of Documents for each word, and then concatenates the sets.
    pub fn search(&self, query: &str) -> Vec<SearchResult> {
        let unique_terms: HashSet<_> = query.split_whitespace().map(str::to_lowercase).collect();
        let map: HashMap<String, Vec<(usize, usize)>> = unique_terms.into_iter()
            .flat_map(|word| self.index.get(&word))
            .flat_map(BTreeMap::iter)
            .fold(HashMap::new(), |mut map, (doc_id, highlights)| {
                match map.entry(doc_id.clone()) {
                    Vacant(entry) => { entry.insert(highlights.clone()); },
                    Occupied(mut entry) => {
                        let entry: &mut Vec<(usize, usize)> = entry.get_mut();
                        for highlight in highlights {
                            let coalesce_idx = entry.binary_search(highlight).err().unwrap();
                            entry.coalesce(coalesce_idx, highlight.clone());
                        }
                    }
                }
                map
            });
        let mut results: Vec<_> = map.into_iter()
            .map(|(doc_id, index_map)| SearchResult::new(&self.docs[&doc_id], index_map.into_iter().collect()))
            .collect();
        results.sort_by(|result1, result2| result2.score.partial_cmp(&result1.score).unwrap());
        results
    }
}

fn analyze_doc(doc: &str) ->
    iter::FlatMap<
        iter::Filter<
            GroupBy<bool, CharIndices, fn(&(usize, char)) -> bool>,
            fn(&(bool, Vec<(usize, char)>)) -> bool>,
        iter::Map<ops::Range<usize>, Ngrams>,
        fn((bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams>>
{
    doc.char_indices()
        .group_by(is_whitespace as fn(&(usize, char)) -> bool)
        .filter(not_whitespace as fn(&(bool, Vec<(usize, char)>)) -> bool)
        .flat_map(ngrams)
}

fn ngrams((_, chars): (bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams> {
    (1..chars.len() + 1).map(Ngrams::new(chars))
}

fn not_whitespace(&(is_whitespace, _): &(bool, Vec<(usize, char)>)) -> bool {
    !is_whitespace
}

fn is_whitespace(&(_, c): &(usize, char)) -> bool {
    c.is_whitespace()
}

struct Ngrams {
    chars: Vec<(usize, char)>
}

impl Ngrams {
    fn new(chars: Vec<(usize, char)>) -> Ngrams {
        Ngrams { chars: chars }
    }
}

impl Fn<(usize,)> for Ngrams {
    extern "rust-call" fn call(&self, (to,): (usize,)) -> (String, (usize, usize)) {
        let word = self.chars[..to].iter().flat_map(|&(_, c)| c.to_lowercase()).collect();
        let start = self.chars[0].0;
        let (last_idx, last_char) = self.chars[to - 1];
        let finish = last_idx + last_char.len_utf8();
        (word, (start, finish))
    }
}

impl FnMut<(usize,)> for Ngrams {
    extern "rust-call" fn call_mut(&mut self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

impl FnOnce<(usize,)> for Ngrams {
    type Output = (String, (usize, usize));
    extern "rust-call" fn call_once(self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::BTreeMap;

    #[test]
    fn test_ngrams() {
        let mut index = InvertedIndex::new();
        let doc1 = Document::new("1", "learn to program in rust today");
        let doc2 = Document::new("2", "what did you today do");
        index.index(doc1.clone());
        index.index(doc2.clone());
        let search_results = index.search("to");
        let expected: BTreeMap<_, _> = [
            (doc1.clone(), vec![(6, 8), (25, 27)]),
            (doc2, vec![(13, 15)]),
        ].iter().cloned().collect();
        assert_eq!(search_results.len(), expected.len());
        for search_result in &search_results {
            assert_eq!(&search_result.highlights, &expected[search_result.doc])
        }
        assert_eq!("learn to program in rust \
                   today",
                   search_results.iter()
                        .find(|search_result| search_result.doc == &doc1)
                        .unwrap()
                        .highlight("", ""));

    }

    #[test]
    fn test_highlight() {
        let mut index = InvertedIndex::new();
        let doc1 = Document::new("2", "Won\u{2019}t this split the ecosystem? Will everyone use?");
        index.index(doc1.clone());
        let expected =  "Won\u{2019}t this split the *e*cosystem? Will *e*veryone use?";
        let search_results = index.search("e");
        assert_eq!(1, search_results.len());
        assert_eq!(search_results[0].highlight("*", "*"), expected);
    }

    #[test]
    fn test_unicode() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "嗨, 您好");
        index.index(doc.clone());
        let to_search = "您";
        let search_results = index.search(to_search);
        let &SearchResult { ref doc, ref highlights, .. } = search_results.iter().next().unwrap();
        let (begin, end) = highlights[0];
        assert_eq!(&doc.content()[begin..end], to_search);
    }

    #[test]
    fn test_update_doc() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "abc åäö");
        index.index(doc);
        let doc = Document::new("0", "different");
        index.index(doc);
        let search_results = index.search("å");
        assert!(search_results.is_empty());
        assert_eq!(index.docs.len(), 1);
    }

    #[test]
    fn test_ranking() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "beat");
        index.index(doc.clone());
        let doc2 = Document::new("1", "beast");
        index.index(doc2);
        let search_results = index.search("be");
        assert_eq!(index.docs.len(), 2);
        // "beat" should be first, since it's a closer match
        assert_eq!(search_results[0].doc, &doc);
    }

    #[test]
    fn test_duplicate_term() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "beat");
        index.index(doc.clone());
        let search_results = index.search("be be");
        assert_eq!(search_results.len(), 1);
    }

    #[test]
    fn test_duplicate_term2() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "beat");
        index.index(doc.clone());
        let search_results = index.search("be b");
        assert_eq!(search_results.len(), 1);
        assert_eq!(search_results[0].highlights, vec![(0, 2)]);
    }

    #[test]
    fn test_lowercase_search() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "BeAt");
        index.index(doc.clone());
        let search_results = index.search("bE");
        assert_eq!(search_results.len(), 1);
        assert_eq!(search_results[0].highlights, vec![(0, 2)]);
    }

    #[test]
    fn test_lowercase_index() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "BeAt");
        index.index(doc.clone());
        let search_results = index.search("be");
        assert_eq!(search_results.len(), 1);
        assert_eq!(search_results[0].highlights, vec![(0, 2)]);
    }
}
<commit_msg>Run rustfmt<commit_after>use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::hash_map::Entry::*;
use std::hash::{Hash, Hasher};
use std::iter;
use std::str::CharIndices;
use std::ops;
use itertools::{GroupBy, Itertools};
use coalesce::Coalesce;

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Debug, Eq, Ord, RustcEncodable, RustcDecodable)]
pub struct Document {
    id: String,
    content: String,
}

impl Document {
    /// Construct a new Document from an id and content.
    /// Both two arguments can be anything that can be turned into a String.
    pub fn new<S, T>(id: S, content: T) -> Document
        where S: Into<String>,
              T: Into<String>
    {
        Document { id: id.into(), content: content.into() }
    }

    pub fn id(&self) -> &str {
        &self.id
    }

    pub fn content(&self) -> &str {
        &self.content
    }
}

impl Hash for Document {
    // Documents are unique only upon their id
    fn hash<H>(&self, state: &mut H)
        where H: Hasher
    {
        self.id.hash(state);
    }
}

impl PartialEq for Document {
    // Documents are unique only upon their id
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

impl PartialOrd for Document {
    fn partial_cmp(&self, other: &Document) -> Option<::std::cmp::Ordering> {
        self.id.partial_cmp(&other.id)
    }
}

/// A SearchResult is the representation of a Document returned for a specific set of search
/// terms. It is unique upon the document and the vec of highlight indices. It also contains a
/// search score for use in ranking against the other search results
#[derive(Clone, Debug, RustcEncodable)]
pub struct SearchResult<'a> {
    doc: &'a Document,
    highlights: Vec<(usize, usize)>,
    score: f32,
}

impl<'a> SearchResult<'a> {
    fn new(doc: &'a Document, mut highlights: Vec<(usize, usize)>) -> SearchResult<'a> {
        SearchResult {
            score: highlights.iter()
                .map(|&(begin, end)| end - begin)
                .sum::<usize>() as f32 /
                   (doc.content.len() as f32).sqrt(),
            doc: doc,
            highlights: {
                highlights.sort();
                highlights
            },
        }
    }

    /// Returns the document
    pub fn doc(&self) -> &Document {
        &self.doc
    }

    /// Returns the highlighted indices.
    ///
    /// Each `(usize, usize)` indicates the start and end of a term in the document's content
    /// that should be highlighted.
    pub fn highlights(&self) -> &Vec<(usize, usize)> {
        &self.highlights
    }

    /// Returns the search result's score.
    ///
    /// Score is computed by the product of the summed length of the matching terms and the inverse
    /// square root of the length of the document. Taking the square root of the document's length
    /// helps to combat bias toward short content.
    pub fn score(&self) -> f32 {
        self.score
    }

    pub fn highlight(&self, before: &str, after: &str) -> String {
        let mut begin_idx = 0;
        let mut parts = String::new();
        for &(begin, end) in &self.highlights {
            parts.push_str(&self.doc.content[begin_idx..begin]);
            parts.push_str(before);
            parts.push_str(&self.doc.content[begin..end]);
            parts.push_str(after);
            begin_idx = end;
        }
        parts.push_str(&self.doc.content[begin_idx..]);
        parts
    }
}

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to sets of Documents.
#[derive(Debug)]
pub struct InvertedIndex {
    index: BTreeMap<String, BTreeMap<String, Vec<(usize, usize)>>>,
    docs: BTreeMap<String, Document>,
}

impl InvertedIndex {
    pub fn new() -> InvertedIndex {
        InvertedIndex { index: BTreeMap::new(), docs: BTreeMap::new() }
    }

    /// A basic implementation of index, splits the document's content into whitespace-separated
    /// words, and inserts each word-document pair into the map.
    pub fn index(&mut self, doc: Document) {
        let analyzed = analyze_doc(doc.content());
        let previous_version = self.docs.insert(doc.id.clone(), doc.clone());
        if let Some(previous_version) = previous_version {
            let previous_analyzed = analyze_doc(previous_version.content());
            for (ngram, _) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&doc.id);
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        for (ngram, highlighted) in analyzed {
            let mut highlights = self.index
                                     .entry(ngram)
                                     .or_insert_with(BTreeMap::new)
                                     .entry(doc.id.clone())
                                     .or_insert_with(Vec::new);
            let coalesce_idx = highlights.binary_search(&highlighted).err().unwrap();
            highlights.coalesce(coalesce_idx, highlighted);
        }
    }

    /// A basic search implementation that splits the query's content into whitespace-separated
    /// words, looks up the set of Documents for each word, and then concatenates the sets.
    pub fn search(&self, query: &str) -> Vec<SearchResult> {
        let unique_terms: HashSet<_> = query.split_whitespace().map(str::to_lowercase).collect();
        let map: HashMap<String, Vec<(usize, usize)>> = unique_terms.into_iter()
            .flat_map(|word| self.index.get(&word))
            .flat_map(BTreeMap::iter)
            .fold(HashMap::new(), |mut map, (doc_id, highlights)| {
                match map.entry(doc_id.clone()) {
                    Vacant(entry) => { entry.insert(highlights.clone()); },
                    Occupied(mut entry) => {
                        let entry: &mut Vec<(usize, usize)> = entry.get_mut();
                        for highlight in highlights {
                            let coalesce_idx = entry.binary_search(highlight).err().unwrap();
                            entry.coalesce(coalesce_idx, highlight.clone());
                        }
                    }
                }
                map
            });
        let mut results: Vec<_> = map.into_iter()
                                     .map(|(doc_id, index_map)| {
                                         SearchResult::new(&self.docs[&doc_id],
                                                           index_map.into_iter().collect())
                                     })
                                     .collect();
        results.sort_by(|result1, result2| result2.score.partial_cmp(&result1.score).unwrap());
        results
    }
}

#[rustfmt_skip]
fn analyze_doc(doc: &str) ->
    iter::FlatMap<
        iter::Filter<
            GroupBy<bool, CharIndices, fn(&(usize, char)) -> bool>,
            fn(&(bool, Vec<(usize, char)>)) -> bool>,
        iter::Map<ops::Range<usize>, Ngrams>,
        fn((bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams>>
{
    doc.char_indices()
        .group_by(is_whitespace as fn(&(usize, char)) -> bool)
        .filter(not_whitespace as fn(&(bool, Vec<(usize, char)>)) -> bool)
        .flat_map(ngrams)
}

fn ngrams((_, chars): (bool, Vec<(usize, char)>)) -> iter::Map<ops::Range<usize>, Ngrams> {
    (1..chars.len() + 1).map(Ngrams::new(chars))
}

fn not_whitespace(&(is_whitespace, _): &(bool, Vec<(usize, char)>)) -> bool {
    !is_whitespace
}

fn is_whitespace(&(_, c): &(usize, char)) -> bool {
    c.is_whitespace()
}

struct Ngrams {
    chars: Vec<(usize, char)>,
}

impl Ngrams {
    fn new(chars: Vec<(usize, char)>) -> Ngrams {
        Ngrams { chars: chars }
    }
}

impl Fn<(usize,)> for Ngrams {
    extern "rust-call" fn call(&self, (to,): (usize,)) -> (String, (usize, usize)) {
        let word = self.chars[..to].iter().flat_map(|&(_, c)| c.to_lowercase()).collect();
        let start = self.chars[0].0;
        let (last_idx, last_char) = self.chars[to - 1];
        let finish = last_idx + last_char.len_utf8();
        (word, (start, finish))
    }
}

impl FnMut<(usize,)> for Ngrams {
    extern "rust-call" fn call_mut(&mut self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

impl FnOnce<(usize,)> for Ngrams {
    type Output = (String, (usize, usize));
    extern "rust-call" fn call_once(self, to: (usize,)) -> (String, (usize, usize)) {
        self.call(to)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::BTreeMap;

    #[test]
    fn test_ngrams() {
        let mut index = InvertedIndex::new();
        let doc1 = Document::new("1", "learn to program in rust today");
        let doc2 = Document::new("2", "what did you today do");
        index.index(doc1.clone());
        index.index(doc2.clone());
        let search_results = index.search("to");
        let expected: BTreeMap<_, _> = [(doc1.clone(), vec![(6, 8), (25, 27)]),
                                        (doc2, vec![(13, 15)])]
                                           .iter()
                                           .cloned()
                                           .collect();
        assert_eq!(search_results.len(), expected.len());
        for search_result in &search_results {
            assert_eq!(&search_result.highlights, &expected[search_result.doc])
        }
        assert_eq!("learn to program in rust today",
                   search_results.iter()
                                 .find(|search_result| search_result.doc == &doc1)
                                 .unwrap()
                                 .highlight("", ""));

    }

    #[test]
    fn test_highlight() {
        let mut index = InvertedIndex::new();
        let doc1 = Document::new("2", "Won\u{2019}t this split the ecosystem? Will everyone use?");
        index.index(doc1.clone());
        let expected = "Won\u{2019}t this split the *e*cosystem? Will *e*veryone use?";
        let search_results = index.search("e");
        assert_eq!(1, search_results.len());
        assert_eq!(search_results[0].highlight("*", "*"), expected);
    }

    #[test]
    fn test_unicode() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "嗨, 您好");
        index.index(doc.clone());
        let to_search = "您";
        let search_results = index.search(to_search);
        let &SearchResult { ref doc, ref highlights, .. } = search_results.iter().next().unwrap();
        let (begin, end) = highlights[0];
        assert_eq!(&doc.content()[begin..end], to_search);
    }

    #[test]
    fn test_update_doc() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "abc åäö");
        index.index(doc);
        let doc = Document::new("0", "different");
        index.index(doc);
        let search_results = index.search("å");
        assert!(search_results.is_empty());
        assert_eq!(index.docs.len(), 1);
    }

    #[test]
    fn test_ranking() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "beat");
        index.index(doc.clone());
        let doc2 = Document::new("1", "beast");
        index.index(doc2);
        let search_results = index.search("be");
        assert_eq!(index.docs.len(), 2);
        // "beat" should be first, since it's a closer match
        assert_eq!(search_results[0].doc, &doc);
    }

    #[test]
    fn test_duplicate_term() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "beat");
        index.index(doc.clone());
        let search_results = index.search("be be");
        assert_eq!(search_results.len(), 1);
    }

    #[test]
    fn test_duplicate_term2() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "beat");
        index.index(doc.clone());
        let search_results = index.search("be b");
        assert_eq!(search_results.len(), 1);
        assert_eq!(search_results[0].highlights, vec![(0, 2)]);
    }

    #[test]
    fn test_lowercase_search() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "BeAt");
        index.index(doc.clone());
        let search_results = index.search("bE");
        assert_eq!(search_results.len(), 1);
        assert_eq!(search_results[0].highlights, vec![(0, 2)]);
    }

    #[test]
    fn test_lowercase_index() {
        let mut index = InvertedIndex::new();
        let doc = Document::new("0", "BeAt");
        index.index(doc.clone());
        let search_results = index.search("be");
        assert_eq!(search_results.len(), 1);
        assert_eq!(search_results[0].highlights, vec![(0, 2)]);
    }
}
<|endoftext|>


<commit_before>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::min;
use score::Score;
use sorted_result_set::SortedResultSet;
use std::ascii::AsciiExt;

#[derive(Debug)]
pub struct Search<'s> {
    pub config: &'s Configuration,
    current: usize,
    pub query: String,
    pub selection: Option<String>,
    pub result: Vec<String>,
    choice_stack: Vec<Vec<&'s String>>,
    done: bool,
}

impl<'s> Search<'s> {
    pub fn blank(config: &'s Configuration) -> Search<'s> {
        let query = config.initial_search.clone();

        let mut choice_stack: Vec<Vec<&'s String>> = Vec::new();
        let mut result = Vec::new();
        let mut first_stack_frame = Vec::new();

        for choice in config.choices.iter().take(config.visible_limit) {
            result.push(choice.clone());
        }

        for choice in config.choices.iter() {
            first_stack_frame.push(choice);
        }

        choice_stack.push(first_stack_frame);

        Search::new(config, query, choice_stack, result, 0, false)
    }

    pub fn is_done(&self) -> bool {
        self.done
    }

    pub fn done(self) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, self.current, true)
    }

    fn new(config: &'s Configuration, query: String, choice_stack: Vec<Vec<&'s String>>, result: Vec<String>, index: usize, done: bool) -> Search<'s> {
        let selection = Search::select(&result, index);

        Search { config: config,
                 current: index,
                 query: query,
                 selection: selection,
                 result: result,
                 choice_stack: choice_stack,
                 done: done}
    }

    fn new_for_index(self, index: usize) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, index, self.done)
    }

    pub fn iter_matches<F: FnMut(&'s String, f32)>(query: &str, choices: &Vec<&'s String>, mut f: F) {
        let lower_query = query.to_ascii_lowercase();

        for choice in choices.iter() {
            let lower_choice = choice.to_ascii_lowercase();

            match Score::score(&lower_choice, &lower_query) {
                0.0     => continue,
                quality => f(choice, quality),
            };
        }
    }

    fn select(result: &Vec<String>, index: usize) -> Option<String> {
        match result.get(index) {
            Some(t) => Some(t.clone()),
            None => None,
        }
    }

    pub fn down(self) -> Search<'s> {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    pub fn up(self) -> Search<'s> {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(mut self, input: &str) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        let mut results = SortedResultSet::new(self.config.visible_limit);
        let mut filtered_choices: Vec<&String> = Vec::new();
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.last().unwrap(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                               filtered_choices.push(match_str)
                                             });

        self.choice_stack.push(filtered_choices);
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    pub fn backspace(mut self) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.pop();
        &self.choice_stack.pop();

        let mut results = SortedResultSet::new(self.config.visible_limit);
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.last().unwrap(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                             });
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.actual_limit() {
            0
        } else {
            next_index
        }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 {
            self.actual_limit() - 1
        } else {
            self.current - 1
        }
    }

    fn actual_limit(&self) -> usize {
        min(self.config.visible_limit, self.num_matches())
    }

    pub fn num_matches(&self) -> usize {
        self.choice_stack.last().unwrap().len()
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use configuration::Configuration;
    use super::*;
    use self::test::Bencher;
    use sorted_result_set::SortedResultSet;

    fn one_two_three() -> Vec<String> {
        vec!["one".to_string(),
             "two".to_string(),
             "three".to_string()]
    }

    // Move me later
    #[test]
    fn it_pushes_to_the_stack_when_appending() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("t");

        assert_eq!(search.choice_stack.len(), 2);
    }

    #[test]
    fn it_pop_from_the_stack_when_backspacing() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("t").backspace();

        assert_eq!(search.choice_stack.len(), 1);
    }

    #[test]
    fn it_selects_the_first_choice_by_default() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn it_selets_the_second_when_down_is_called() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_end_of_list() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_top_of_list() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.up().up().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_visible_limit() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, Some(2));
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").down().selection, Some("three".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results_twice() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").append_to_search("w").selection, Some("two".to_string()));
    }

    #[test]
    fn it_handles_not_matching_anything() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("x").selection, None);
    }

    #[test]
    fn up_match_nothing_after_filtering_all_out() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.up().selection, None);
    }

    #[test]
    fn down_match_nothing_after_filtering_all_out() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.down().selection, None);
    }

    #[test]
    fn backspaces_over_characters() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.query, "e");
        assert_eq!(search.backspace().query, "");
    }

    #[test]
    fn resets_the_index_when_removing_char_from_search() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.down().backspace().current, 0);
    }

    #[test]
    fn resets_the_index_when_adding_char_to_seach() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).down();

        assert_eq!(search.append_to_search("o").current, 0);
    }

    #[test]
    fn previous_results_appear_after_backspace() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("t");

        assert_eq!(search.backspace().num_matches(), 3);
    }

    #[test]
    fn initial_search_is_not_done() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert!(!search.is_done());
    }

    #[test]
    fn done_search_is_done() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).done();

        assert!(search.is_done());
    }

    #[test]
    fn done_search_has_selection() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).done();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_bottom_of_choices() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("n").down();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_top_of_choices() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("n").up();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn search_is_case_insensitive() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 2);
    }

    #[test]
    fn uses_configs_visible_limit_as_result_size() {
        let input = input_times(30);

        let mut bar = Vec::new();
        for f in input.iter() {
            bar.push((*f).clone());
        }

        let config = Configuration::from_inputs(bar, None, Some(20));
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 20);
    }

    fn input_times(n: usize) ->Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for thing in one_two_three().iter().cycle().take(n) {
            result.push(thing.clone());
        }
        result
    }

    //84114 ns/iter (+/- 33515)
    #[bench]
    fn filter_speed(b: &mut Bencher) {
        let initial_elements = input_times(1000);
        let query = "t";
        let mut f = Vec::new();
        for g in initial_elements.iter() {
            f.push(g);
        }

        b.iter(||{
            let mut results = SortedResultSet::new(20);
            Search::iter_matches(query, &f,
                                    |choice, quality| results.push(choice, quality));
            results
        });
    }
}
<commit_msg>Remove tests that check against choices_stack size<commit_after>use configuration::Configuration;
use std::slice::SliceExt;
use std::cmp::min;
use score::Score;
use sorted_result_set::SortedResultSet;
use std::ascii::AsciiExt;

#[derive(Debug)]
pub struct Search<'s> {
    pub config: &'s Configuration,
    current: usize,
    pub query: String,
    pub selection: Option<String>,
    pub result: Vec<String>,
    choice_stack: Vec<Vec<&'s String>>,
    done: bool,
}

impl<'s> Search<'s> {
    pub fn blank(config: &'s Configuration) -> Search<'s> {
        let query = config.initial_search.clone();

        let mut choice_stack: Vec<Vec<&'s String>> = Vec::new();
        let mut result = Vec::new();
        let mut first_stack_frame = Vec::new();

        for choice in config.choices.iter().take(config.visible_limit) {
            result.push(choice.clone());
        }

        for choice in config.choices.iter() {
            first_stack_frame.push(choice);
        }

        choice_stack.push(first_stack_frame);

        Search::new(config, query, choice_stack, result, 0, false)
    }

    pub fn is_done(&self) -> bool {
        self.done
    }

    pub fn done(self) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, self.current, true)
    }

    fn new(config: &'s Configuration, query: String, choice_stack: Vec<Vec<&'s String>>, result: Vec<String>, index: usize, done: bool) -> Search<'s> {
        let selection = Search::select(&result, index);

        Search { config: config,
                 current: index,
                 query: query,
                 selection: selection,
                 result: result,
                 choice_stack: choice_stack,
                 done: done}
    }

    fn new_for_index(self, index: usize) -> Search<'s> {
        Search::new(self.config, self.query, self.choice_stack, self.result, index, self.done)
    }

    pub fn iter_matches<F: FnMut(&'s String, f32)>(query: &str, choices: &Vec<&'s String>, mut f: F) {
        let lower_query = query.to_ascii_lowercase();

        for choice in choices.iter() {
            let lower_choice = choice.to_ascii_lowercase();

            match Score::score(&lower_choice, &lower_query) {
                0.0     => continue,
                quality => f(choice, quality),
            };
        }
    }

    fn select(result: &Vec<String>, index: usize) -> Option<String> {
        match result.get(index) {
            Some(t) => Some(t.clone()),
            None => None,
        }
    }

    pub fn down(self) -> Search<'s> {
        let next_index = self.next_index();
        self.new_for_index(next_index)
    }

    pub fn up(self) -> Search<'s> {
        let next_index = self.prev_index();
        self.new_for_index(next_index)
    }

    pub fn append_to_search(mut self, input: &str) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.push_str(input.as_slice());

        let mut results = SortedResultSet::new(self.config.visible_limit);
        let mut filtered_choices: Vec<&String> = Vec::new();
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.last().unwrap(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                               filtered_choices.push(match_str)
                                             });

        self.choice_stack.push(filtered_choices);
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    pub fn backspace(mut self) -> Search<'s> {
        let mut new_query = self.query.clone();
        new_query.pop();
        &self.choice_stack.pop();

        let mut results = SortedResultSet::new(self.config.visible_limit);
        Search::iter_matches(new_query.as_slice(), &self.choice_stack.last().unwrap(),
                        |match_str, quality| {
                                               results.push(match_str, quality);
                                             });
        Search::new(self.config, new_query, self.choice_stack, results.as_sorted_vec(), 0, self.done)
    }

    fn next_index(&self) -> usize {
        let next_index = self.current + 1;

        if next_index >= self.actual_limit() {
            0
        } else {
            next_index
        }
    }

    fn prev_index(&self) -> usize {
        if self.current == 0 {
            self.actual_limit() - 1
        } else {
            self.current - 1
        }
    }

    fn actual_limit(&self) -> usize {
        min(self.config.visible_limit, self.num_matches())
    }

    pub fn num_matches(&self) -> usize {
        self.choice_stack.last().unwrap().len()
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use configuration::Configuration;
    use super::*;
    use self::test::Bencher;
    use sorted_result_set::SortedResultSet;

    fn one_two_three() -> Vec<String> {
        vec!["one".to_string(),
             "two".to_string(),
             "three".to_string()]
    }

    #[test]
    fn it_selects_the_first_choice_by_default() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn it_selets_the_second_when_down_is_called() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_end_of_list() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_top_of_list() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.up().up().selection, Some("two".to_string()));
    }

    #[test]
    fn it_loop_around_when_reaching_visible_limit() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, Some(2));
        let search = Search::blank(&config);

        assert_eq!(search.down().down().down().selection, Some("two".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").down().selection, Some("three".to_string()));
    }

    #[test]
    fn it_moves_down_the_filtered_search_results_twice() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("t").append_to_search("w").selection, Some("two".to_string()));
    }

    #[test]
    fn it_handles_not_matching_anything() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert_eq!(search.append_to_search("x").selection, None);
    }

    #[test]
    fn up_match_nothing_after_filtering_all_out() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.up().selection, None);
    }

    #[test]
    fn down_match_nothing_after_filtering_all_out() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("x");

        assert_eq!(search.down().selection, None);
    }

    #[test]
    fn backspaces_over_characters() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.query, "e");
        assert_eq!(search.backspace().query, "");
    }

    #[test]
    fn resets_the_index_when_removing_char_from_search() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("e");

        assert_eq!(search.down().backspace().current, 0);
    }

    #[test]
    fn resets_the_index_when_adding_char_to_seach() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).down();

        assert_eq!(search.append_to_search("o").current, 0);
    }

    #[test]
    fn previous_results_appear_after_backspace() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("t");

        assert_eq!(search.backspace().num_matches(), 3);
    }

    #[test]
    fn initial_search_is_not_done() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config);

        assert!(!search.is_done());
    }

    #[test]
    fn done_search_is_done() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).done();

        assert!(search.is_done());
    }

    #[test]
    fn done_search_has_selection() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).done();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_bottom_of_choices() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("n").down();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn loop_around_when_reaching_top_of_choices() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("n").up();

        assert_eq!(search.selection, Some("one".to_string()));
    }

    #[test]
    fn search_is_case_insensitive() {
        let input = one_two_three();
        let config = Configuration::from_inputs(input, None, None);
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 2);
    }

    #[test]
    fn uses_configs_visible_limit_as_result_size() {
        let input = input_times(30);

        let mut bar = Vec::new();
        for f in input.iter() {
            bar.push((*f).clone());
        }

        let config = Configuration::from_inputs(bar, None, Some(20));
        let search = Search::blank(&config).append_to_search("T");

        assert_eq!(search.num_matches(), 20);
    }

    fn input_times(n: usize) ->Vec<String> {
        let mut result: Vec<String> = Vec::new();
        for thing in one_two_three().iter().cycle().take(n) {
            result.push(thing.clone());
        }
        result
    }

    //84114 ns/iter (+/- 33515)
    #[bench]
    fn filter_speed(b: &mut Bencher) {
        let initial_elements = input_times(1000);
        let query = "t";
        let mut f = Vec::new();
        for g in initial_elements.iter() {
            f.push(g);
        }

        b.iter(||{
            let mut results = SortedResultSet::new(20);
            Search::iter_matches(query, &f,
                                    |choice, quality| results.push(choice, quality));
            results
        });
    }
}
<|endoftext|>


<commit_before>//! The server module defines the codec used for parsing stats in capella.

use std::io;
use std::cell::RefCell;
use std::error::Error;
use std::net::SocketAddr;
use std::rc::Rc;
use std::time::Duration;

use futures::{Future, Stream, Sink};

use tokio_core::net::{UdpCodec, UdpSocket};
use tokio_core::reactor::Core;

use tokio_timer::Timer;

use cache::CapellaCache;

use parse::{self, Metric};

/// StatsCodec defines the UDP parser used to accept packets and returns a new
/// statistic or an error.
pub struct StatsCodec;

impl UdpCodec for StatsCodec {
    type In = (SocketAddr, Vec<Metric>);
    type Out = SocketAddr;

    fn decode(&mut self, addr: &SocketAddr, buf: &[u8]) -> io::Result<Self::In> {
        let mut metrics = Vec::new();

        // See if we got multiple metrics.
        if buf.contains(&b'\n') {
            // Based on the behavior of split, we need to filter out zero-length chunks.
            for m in buf.split(|c| *c == b'\n').filter(|chunk| chunk.len() > 0) {
                let metric = parse::parse_metric(m)?;
                metrics.push(metric);
            }
            return Ok((*addr, metrics));
        }

        // We only got one metric sent.
        let metric = parse::parse_metric(buf)?;
        metrics.push(metric);

        Ok((*addr, metrics))
    }

    // Since stat collecting is fire and forget, we don't need to write data
    // back to the client.
    fn encode(&mut self, addr: Self::Out, _: &mut Vec<u8>) -> SocketAddr {
        addr
    }
}

// TODO: This will need to allow for configuration.
pub fn start_udp_server() {
    let cache = Rc::new(RefCell::new(CapellaCache::default()));
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let addr: SocketAddr = "127.0.0.1:8125".parse().unwrap();
    let s = UdpSocket::bind(&addr, &handle).unwrap();

    let (sink, stream) = s.framed(StatsCodec).split();

    // This sets up the purge timer utilizing the event loop.
    let t = Timer::default().interval(Duration::new(5, 0));
    let future_t = t.for_each(|()| {
        cache.borrow_mut().purge_metrics();
        Ok(())
    }).map_err(|e| {
        io::Error::new(io::ErrorKind::Other, e.description())
    });

    // This is the event loop stream in which all values are parsed.
    // TODO: Investigate why I can't figure out how to chain functions to catch the error case.
    use error::CapellaResult;
    let events = stream.then(|res| {
        let v = res.unwrap_or(("0.0.0.0:8125".parse().unwrap(), vec![]));
        if v.1.len() == 0 {
            cache.borrow_mut().bad_metric_increase();
        }

        println!("{:?}", v.1);
        for m in &v.1 {
            cache.borrow_mut().add_metric(m);
        }

        let r: CapellaResult<SocketAddr> = Ok(v.0);
        r
    });
    let f = sink.send_all(events).join(future_t);

    drop(core.run(f));
}
<commit_msg>use a for each future instead of sending through the sink<commit_after>//! The server module defines the codec used for parsing stats in capella.

use std::io;
use std::cell::RefCell;
use std::error::Error;
use std::net::SocketAddr;
use std::rc::Rc;
use std::time::Duration;

use futures::{Future, Stream};

use tokio_core::net::{UdpCodec, UdpSocket};
use tokio_core::reactor::Core;

use tokio_timer::Timer;

use cache::CapellaCache;

use parse::{self, Metric};

/// StatsCodec defines the UDP parser used to accept packets and returns a new
/// statistic or an error.
pub struct StatsCodec;

impl UdpCodec for StatsCodec {
    type In = (SocketAddr, Vec<Metric>);
    type Out = SocketAddr;

    fn decode(&mut self, addr: &SocketAddr, buf: &[u8]) -> io::Result<Self::In> {
        let mut metrics = Vec::new();

        // See if we got multiple metrics.
        if buf.contains(&b'\n') {
            // Based on the behavior of split, we need to filter out zero-length chunks.
            for m in buf.split(|c| *c == b'\n').filter(|chunk| chunk.len() > 0) {
                let metric = parse::parse_metric(m)?;
                metrics.push(metric);
            }
            return Ok((*addr, metrics));
        }

        // We only got one metric sent.
        let metric = parse::parse_metric(buf)?;
        metrics.push(metric);

        Ok((*addr, metrics))
    }

    // Since stat collecting is fire and forget, we don't need to write data
    // back to the client.
    fn encode(&mut self, addr: Self::Out, _: &mut Vec<u8>) -> SocketAddr {
        addr
    }
}

// TODO: This will need to allow for configuration.
pub fn start_udp_server() {
    let cache = Rc::new(RefCell::new(CapellaCache::default()));
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let addr: SocketAddr = "127.0.0.1:8125".parse().unwrap();
    let s = UdpSocket::bind(&addr, &handle).unwrap();

    let (_, stream) = s.framed(StatsCodec).split();

    // This sets up the purge timer utilizing the event loop.
    let t = Timer::default().interval(Duration::new(5, 0));
    let future_t = t.for_each(|()| {
        cache.borrow_mut().purge_metrics();
        Ok(())
    }).map_err(|e| {
        io::Error::new(io::ErrorKind::Other, e.description())
    });

    // This is the event loop stream in which all values are parsed.
    let events = stream.for_each(|(_, metrics)| {
        if metrics.len() == 0 {
            cache.borrow_mut().bad_metric_increase();
        }

        for m in &metrics {
            cache.borrow_mut().add_metric(m);
        }

        Ok(())
    }).map_err(|e| {
        io::Error::new(io::ErrorKind::Other, e.description())
    });
    let f = events.join(future_t);

    drop(core.run(f));
}
<|endoftext|>


<commit_before>use std::{
    io::{self, ErrorKind},
    net::{IpAddr, SocketAddr},
    pin::Pin,
    sync::Arc,
    task::{Context, Poll},
};

use futures::{future, ready};
use kcp::{Error as KcpError, KcpResult};
use log::trace;
use tokio::{
    io::{AsyncRead, AsyncWrite, ReadBuf},
    net::UdpSocket,
};

use crate::{config::KcpConfig, session::KcpSession, skcp::KcpSocket};

pub struct KcpStream {
    session: Arc<KcpSession>,
    recv_buffer: Vec<u8>,
    recv_buffer_pos: usize,
    recv_buffer_cap: usize,
}

impl Drop for KcpStream {
    fn drop(&mut self) {
        self.session.close();
    }
}

impl KcpStream {
    /// Create a `KcpStream` connecting to `addr`
    pub async fn connect(config: &KcpConfig, addr: SocketAddr) -> KcpResult<KcpStream> {
        let udp = match addr.ip() {
            IpAddr::V4(..) => UdpSocket::bind("0.0.0.0:0").await?,
            IpAddr::V6(..) => UdpSocket::bind("[::]:0").await?,
        };

        KcpStream::connect_with_socket(config, udp, addr).await
    }

    /// Create a `KcpStream` with an existed `UdpSocket` connecting to `addr`
    pub async fn connect_with_socket(config: &KcpConfig, udp: UdpSocket, addr: SocketAddr) -> KcpResult<KcpStream> {
        let udp = Arc::new(udp);
        let conv = rand::random();
        let socket = KcpSocket::new(config, conv, udp, addr, config.stream)?;

        let session = KcpSession::new_shared(socket, config.session_expire, None);

        Ok(KcpStream::with_session(session))
    }

    pub(crate) fn with_session(session: Arc<KcpSession>) -> KcpStream {
        KcpStream {
            session,
            recv_buffer: Vec::new(),
            recv_buffer_pos: 0,
            recv_buffer_cap: 0,
        }
    }

    /// `send` data in `buf`
    pub fn poll_send(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<KcpResult<usize>> {
        // Mutex doesn't have poll_lock, spinning on it.
        let mut kcp = self.session.kcp_socket().lock();
        let result = ready!(kcp.poll_send(cx, buf));
        self.session.notify();
        result.into()
    }

    /// `send` data in `buf`
    pub async fn send(&mut self, buf: &[u8]) -> KcpResult<usize> {
        future::poll_fn(|cx| self.poll_send(cx, buf)).await
    }

    /// `recv` data into `buf`
    pub fn poll_recv(&mut self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<KcpResult<usize>> {
        loop {
            // Consumes all data in buffer
            if self.recv_buffer_pos < self.recv_buffer_cap {
                let remaining = self.recv_buffer_cap - self.recv_buffer_pos;
                let copy_length = remaining.min(buf.len());

                (&mut buf[..copy_length])
                    .copy_from_slice(&self.recv_buffer[self.recv_buffer_pos..self.recv_buffer_pos + copy_length]);
                self.recv_buffer_pos += copy_length;
                return Ok(copy_length).into();
            }

            // Mutex doesn't have poll_lock, spinning on it.
            let mut kcp = self.session.kcp_socket().lock();

            // Try to read from KCP
            // 1. Read directly with user provided `buf`
            let peek_size = kcp.peek_size().unwrap_or(0);

            // 1.1. User's provided buffer is larger than available buffer's size
            if peek_size > 0 && peek_size <= buf.len() {
                match ready!(kcp.poll_recv(cx, buf)) {
                    Ok(n) => {
                        trace!("[CLIENT] recv directly {} bytes", n);
                        return Ok(n).into();
                    }
                    Err(KcpError::UserBufTooSmall) => {}
                    Err(err) => return Err(err).into(),
                }
            }

            // 2. User `buf` too small, read to recv_buffer
            let required_size = peek_size;
            if self.recv_buffer.len() < required_size {
                self.recv_buffer.resize(required_size, 0);
            }

            match ready!(kcp.poll_recv(cx, &mut self.recv_buffer)) {
                Ok(0) => return Ok(0).into(),
                Ok(n) => {
                    trace!("[CLIENT] recv buffered {} bytes", n);
                    self.recv_buffer_pos = 0;
                    self.recv_buffer_cap = n;
                }
                Err(err) => return Err(err).into(),
            }
        }
    }

    /// `recv` data into `buf`
    pub async fn recv(&mut self, buf: &mut [u8]) -> KcpResult<usize> {
        future::poll_fn(|cx| self.poll_recv(cx, buf)).await
    }
}

impl AsyncRead for KcpStream {
    fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
        match ready!(self.poll_recv(cx, buf.initialize_unfilled())) {
            Ok(n) => {
                buf.advance(n);
                Ok(()).into()
            }
            Err(KcpError::IoError(err)) => Err(err).into(),
            Err(err) => Err(io::Error::new(ErrorKind::Other, err)).into(),
        }
    }
}

impl AsyncWrite for KcpStream {
    fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        match ready!(self.poll_send(cx, buf)) {
            Ok(n) => Ok(n).into(),
            Err(KcpError::IoError(err)) => Err(err).into(),
            Err(err) => Err(io::Error::new(ErrorKind::Other, err)).into(),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        // Mutex doesn't have poll_lock, spinning on it.
        let mut kcp = self.session.kcp_socket().lock();
        match kcp.flush() {
            Ok(..) => {
                self.session.notify();
                Ok(()).into()
            }
            Err(KcpError::IoError(err)) => Err(err).into(),
            Err(err) => Err(io::Error::new(ErrorKind::Other, err)).into(),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        Ok(()).into()
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for KcpStream {
    fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd {
        let kcp_socket = self.session.kcp_socket().lock();
        kcp_socket.udp_socket().as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawSocket for KcpStream {
    fn as_raw_socket(&self) -> std::os::windows::prelude::RawSocket {
        let kcp_socket = self.session.kcp_socket().lock();
        kcp_socket.udp_socket().as_raw_socket()
    }
}
<commit_msg>fix: remove unnecessary borrow<commit_after>use std::{
    io::{self, ErrorKind},
    net::{IpAddr, SocketAddr},
    pin::Pin,
    sync::Arc,
    task::{Context, Poll},
};

use futures::{future, ready};
use kcp::{Error as KcpError, KcpResult};
use log::trace;
use tokio::{
    io::{AsyncRead, AsyncWrite, ReadBuf},
    net::UdpSocket,
};

use crate::{config::KcpConfig, session::KcpSession, skcp::KcpSocket};

pub struct KcpStream {
    session: Arc<KcpSession>,
    recv_buffer: Vec<u8>,
    recv_buffer_pos: usize,
    recv_buffer_cap: usize,
}

impl Drop for KcpStream {
    fn drop(&mut self) {
        self.session.close();
    }
}

impl KcpStream {
    /// Create a `KcpStream` connecting to `addr`
    pub async fn connect(config: &KcpConfig, addr: SocketAddr) -> KcpResult<KcpStream> {
        let udp = match addr.ip() {
            IpAddr::V4(..) => UdpSocket::bind("0.0.0.0:0").await?,
            IpAddr::V6(..) => UdpSocket::bind("[::]:0").await?,
        };

        KcpStream::connect_with_socket(config, udp, addr).await
    }

    /// Create a `KcpStream` with an existed `UdpSocket` connecting to `addr`
    pub async fn connect_with_socket(config: &KcpConfig, udp: UdpSocket, addr: SocketAddr) -> KcpResult<KcpStream> {
        let udp = Arc::new(udp);
        let conv = rand::random();
        let socket = KcpSocket::new(config, conv, udp, addr, config.stream)?;

        let session = KcpSession::new_shared(socket, config.session_expire, None);

        Ok(KcpStream::with_session(session))
    }

    pub(crate) fn with_session(session: Arc<KcpSession>) -> KcpStream {
        KcpStream {
            session,
            recv_buffer: Vec::new(),
            recv_buffer_pos: 0,
            recv_buffer_cap: 0,
        }
    }

    /// `send` data in `buf`
    pub fn poll_send(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<KcpResult<usize>> {
        // Mutex doesn't have poll_lock, spinning on it.
        let mut kcp = self.session.kcp_socket().lock();
        let result = ready!(kcp.poll_send(cx, buf));
        self.session.notify();
        result.into()
    }

    /// `send` data in `buf`
    pub async fn send(&mut self, buf: &[u8]) -> KcpResult<usize> {
        future::poll_fn(|cx| self.poll_send(cx, buf)).await
    }

    /// `recv` data into `buf`
    pub fn poll_recv(&mut self, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<KcpResult<usize>> {
        loop {
            // Consumes all data in buffer
            if self.recv_buffer_pos < self.recv_buffer_cap {
                let remaining = self.recv_buffer_cap - self.recv_buffer_pos;
                let copy_length = remaining.min(buf.len());

                buf[..copy_length]
                    .copy_from_slice(&self.recv_buffer[self.recv_buffer_pos..self.recv_buffer_pos + copy_length]);
                self.recv_buffer_pos += copy_length;
                return Ok(copy_length).into();
            }

            // Mutex doesn't have poll_lock, spinning on it.
            let mut kcp = self.session.kcp_socket().lock();

            // Try to read from KCP
            // 1. Read directly with user provided `buf`
            let peek_size = kcp.peek_size().unwrap_or(0);

            // 1.1. User's provided buffer is larger than available buffer's size
            if peek_size > 0 && peek_size <= buf.len() {
                match ready!(kcp.poll_recv(cx, buf)) {
                    Ok(n) => {
                        trace!("[CLIENT] recv directly {} bytes", n);
                        return Ok(n).into();
                    }
                    Err(KcpError::UserBufTooSmall) => {}
                    Err(err) => return Err(err).into(),
                }
            }

            // 2. User `buf` too small, read to recv_buffer
            let required_size = peek_size;
            if self.recv_buffer.len() < required_size {
                self.recv_buffer.resize(required_size, 0);
            }

            match ready!(kcp.poll_recv(cx, &mut self.recv_buffer)) {
                Ok(0) => return Ok(0).into(),
                Ok(n) => {
                    trace!("[CLIENT] recv buffered {} bytes", n);
                    self.recv_buffer_pos = 0;
                    self.recv_buffer_cap = n;
                }
                Err(err) => return Err(err).into(),
            }
        }
    }

    /// `recv` data into `buf`
    pub async fn recv(&mut self, buf: &mut [u8]) -> KcpResult<usize> {
        future::poll_fn(|cx| self.poll_recv(cx, buf)).await
    }
}

impl AsyncRead for KcpStream {
    fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
        match ready!(self.poll_recv(cx, buf.initialize_unfilled())) {
            Ok(n) => {
                buf.advance(n);
                Ok(()).into()
            }
            Err(KcpError::IoError(err)) => Err(err).into(),
            Err(err) => Err(io::Error::new(ErrorKind::Other, err)).into(),
        }
    }
}

impl AsyncWrite for KcpStream {
    fn poll_write(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
        match ready!(self.poll_send(cx, buf)) {
            Ok(n) => Ok(n).into(),
            Err(KcpError::IoError(err)) => Err(err).into(),
            Err(err) => Err(io::Error::new(ErrorKind::Other, err)).into(),
        }
    }

    fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        // Mutex doesn't have poll_lock, spinning on it.
        let mut kcp = self.session.kcp_socket().lock();
        match kcp.flush() {
            Ok(..) => {
                self.session.notify();
                Ok(()).into()
            }
            Err(KcpError::IoError(err)) => Err(err).into(),
            Err(err) => Err(io::Error::new(ErrorKind::Other, err)).into(),
        }
    }

    fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
        Ok(()).into()
    }
}

#[cfg(unix)]
impl std::os::unix::io::AsRawFd for KcpStream {
    fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd {
        let kcp_socket = self.session.kcp_socket().lock();
        kcp_socket.udp_socket().as_raw_fd()
    }
}

#[cfg(windows)]
impl std::os::windows::io::AsRawSocket for KcpStream {
    fn as_raw_socket(&self) -> std::os::windows::prelude::RawSocket {
        let kcp_socket = self.session.kcp_socket().lock();
        kcp_socket.udp_socket().as_raw_socket()
    }
}
<|endoftext|>


<commit_before><commit_msg>Use IPv4 or IPv6 depending on the peer's address.<commit_after><|endoftext|>


<commit_before>pub use chan_signal::Signal;
pub use chan::{Sender, Receiver};

/// A type implementing the Runner trait has the job of performing some arbitrary
/// work while waiting for a signal indication shutdown. Upon receiving that
/// defined shutdown Signal, the Runner must exit in a finite period of time.
pub trait Runner {
    /// Error type for the Runner.
    type Error;

    /// The run function is called when a user wants to perform work.
    fn run(self, signals: Receiver<Signal>) -> Result<(), Self::Error>;

    /// The setup function is called when a user wants to get ready to work.
    ///
    /// This function should only complete once the type is ready to be run,
    /// and must complete in finite period of time.
    fn setup(&mut self) -> Result<(), Self::Error>;
}

/// A Thread represents are running unit of work. It can be signaled and waited on.
pub trait Thread {
    /// Error type for the Thread.
    type Error;

    /// This function will block until the running Thread has finished its setup and
    /// is ready to run.
    fn ready(&self) -> Result<(), Self::Error>;
    /// This function will wait until the Thread has exited, returning a success or
    /// failure.
    fn wait(&self) -> Result<(), Self::Error>;
    /// This function will signal the running Thread with the specified signal.
    ///
    /// This is a non-blocking function.
    fn signal(&self, signal: Signal);
}

#[cfg(test)]
mod tests {
    use std::thread;
    use std::sync::mpsc;
    use chan;
    use std::error::Error;
    use std::fmt;
    use {Signal, Thread, Runner, Receiver, Sender};

    struct Test {
        data: usize,
    }

    #[derive(Debug, Eq, PartialEq, Clone)]
    struct TestError;

    impl fmt::Display for TestError {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            write!(fmt, "a testing error")
        }
    }
    impl Error for TestError {
        fn description(&self) -> &str {
            "a testing error"
        }
    }

    impl Runner for Test {
        type Error = TestError;

        fn setup(&mut self) -> Result<(), TestError> {
            self.data = 27;
            Ok(())
        }

        fn run(mut self, _signals: Receiver<Signal>) -> Result<(), TestError> {
            self.data += 73;
            Ok(())
        }
    }

    struct TestThread {
        runner: mpsc::Receiver<bool>,
        signals: Sender<Signal>,
    }

    impl TestThread {
        fn new(runner: Test) -> TestThread {
            let (sn, rc) = mpsc::channel();
            let (send_runner, recv_runner) = mpsc::channel::<Test>();
            // Marid sender/receiver
            let (signals, sig_recv) = chan::async();
            thread::spawn(move || {
                let mut runner = recv_runner.recv().unwrap();
                match runner.setup() {
                    Ok(_) => sn.send(true),
                    Err(_) => sn.send(false),
                }.unwrap();

                match runner.run(sig_recv) {
                    Ok(_) => sn.send(true),
                    Err(_) => sn.send(false),
                }.unwrap();
            });

            send_runner.send(runner).unwrap();

            TestThread{
                runner: rc,
                signals: signals,
            }
        }
    }

    impl Thread for TestThread {
        type Error = TestError;

        fn ready(&self) -> Result<(), Self::Error> {
            if self.runner.recv().unwrap() {
                Ok(())
            } else {
                Err(TestError)
            }
        }

        fn wait(&self) -> Result<(), Self::Error> {
            match self.runner.recv() {
                Ok(_) => Ok(()),
                Err(_) => Err(TestError),
            }
        }

        fn signal(&self, signal: Signal) {
            self.signals.send(signal);
        }
    }

    #[test]
    fn test_runner_and_thread() {
        let runner = Test { data: 0 };
        let thread = TestThread::new(runner);
        assert!(thread.ready().is_ok());
        assert!(thread.wait().is_ok());
    }

    #[test]
    fn test_signal() {
    }
}
<commit_msg>Test signal sending<commit_after>pub use chan_signal::Signal;
pub use chan::{Sender, Receiver};

/// A type implementing the Runner trait has the job of performing some arbitrary
/// work while waiting for a signal indication shutdown. Upon receiving that
/// defined shutdown Signal, the Runner must exit in a finite period of time.
pub trait Runner {
    /// Error type for the Runner.
    type Error;

    /// The run function is called when a user wants to perform work.
    fn run(self, signals: Receiver<Signal>) -> Result<(), Self::Error>;

    /// The setup function is called when a user wants to get ready to work.
    ///
    /// This function should only complete once the type is ready to be run,
    /// and must complete in finite period of time.
    fn setup(&mut self) -> Result<(), Self::Error>;
}

/// A Thread represents are running unit of work. It can be signaled and waited on.
pub trait Thread {
    /// Error type for the Thread.
    type Error;

    /// This function will block until the running Thread has finished its setup and
    /// is ready to run.
    fn ready(&self) -> Result<(), Self::Error>;
    /// This function will wait until the Thread has exited, returning a success or
    /// failure.
    fn wait(&self) -> Result<(), Self::Error>;
    /// This function will signal the running Thread with the specified signal.
    ///
    /// This is a non-blocking function.
    fn signal(&self, signal: Signal);
}

#[cfg(test)]
mod tests {
    use std::thread;
    use std::sync::mpsc;
    use chan;
    use std::error::Error;
    use std::fmt;
    use {Signal, Thread, Runner, Receiver, Sender};

    struct Test {
        data: usize,
    }

    #[derive(Debug, Eq, PartialEq, Clone)]
    struct TestError;

    impl fmt::Display for TestError {
        fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
            write!(fmt, "a testing error")
        }
    }
    impl Error for TestError {
        fn description(&self) -> &str {
            "a testing error"
        }
    }

    impl Runner for Test {
        type Error = TestError;

        fn setup(&mut self) -> Result<(), TestError> {
            self.data = 27;
            Ok(())
        }

        fn run(mut self, signals: Receiver<Signal>) -> Result<(), TestError> {
            self.data += 73;
            let sig = signals.recv().unwrap();
            if sig == Signal::INT {
                Ok(())
            } else {
                Err(TestError)
            }
        }
    }

    struct TestThread {
        runner: mpsc::Receiver<bool>,
        signals: Sender<Signal>,
    }

    impl TestThread {
        fn new(runner: Test) -> TestThread {
            let (sn, rc) = mpsc::channel();
            let (send_runner, recv_runner) = mpsc::channel::<Test>();
            // Marid sender/receiver
            let (signals, sig_recv) = chan::async();
            thread::spawn(move || {
                let mut runner = recv_runner.recv().unwrap();
                match runner.setup() {
                    Ok(_) => sn.send(true),
                    Err(_) => sn.send(false),
                }.unwrap();

                match runner.run(sig_recv) {
                    Ok(_) => sn.send(true),
                    Err(_) => sn.send(false),
                }.unwrap();
            });

            send_runner.send(runner).unwrap();

            TestThread{
                runner: rc,
                signals: signals,
            }
        }
    }

    impl Thread for TestThread {
        type Error = TestError;

        fn ready(&self) -> Result<(), Self::Error> {
            if self.runner.recv().unwrap() {
                Ok(())
            } else {
                Err(TestError)
            }
        }

        fn wait(&self) -> Result<(), Self::Error> {
            match self.runner.recv() {
                Ok(b) => if b { Ok(()) } else { Err(TestError) },
                Err(_) => Err(TestError),
            }
        }

        fn signal(&self, signal: Signal) {
            self.signals.send(signal);
        }
    }

    #[test]
    fn test_runner_and_thread() {
        let runner = Test { data: 0 };
        let thread = TestThread::new(runner);
        assert!(thread.ready().is_ok());
        thread.signal(Signal::INT);
        assert!(thread.wait().is_ok());
    }

    #[test]
    fn test_signal() {
        let runner = Test { data: 0 };
        let thread = TestThread::new(runner);
        assert!(thread.ready().is_ok());
        thread.signal(Signal::HUP);
        assert!(thread.wait().is_err());
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate std;

use super::liblua;
use super::Index;
use super::Lua;
use super::Pushable;
use super::Readable;

macro_rules! integer_impl(
    ($t:ident) => (
        impl Pushable for $t {
            fn push_to_lua(&self, lua: &Lua) {
                unsafe { liblua::lua_pushinteger(lua.lua, *self as liblua::lua_Integer) }
            }
        }
        impl Readable for $t {
            fn read_from_lua(lua: &Lua, index: i32) -> Option<$t> {
                unsafe {
                    let success: libc::c_int = std::mem::uninitialized();
                    let val = liblua::lua_tointegerx(lua.lua, index, std::mem::transmute(&success));
                    match success {
                        0 => None,
                        _ => Some(val as $t)
                    }
                }
            }
        }
        impl Index for $t {
        }
    );
)

integer_impl!(int)
integer_impl!(i8)
integer_impl!(i16)
integer_impl!(i32)
//integer_impl!(i64)   // data loss

macro_rules! unsigned_impl(
    ($t:ident) => (
        impl Pushable for $t {
            fn push_to_lua(&self, lua: &Lua) {
                unsafe { liblua::lua_pushunsigned(lua.lua, *self as liblua::lua_Unsigned) }
            }
        }
        impl Readable for $t {
            fn read_from_lua(lua: &Lua, index: i32) -> Option<$t> {
                unsafe {
                    let success: libc::c_int = std::mem::uninitialized();
                    let val = liblua::lua_tounsignedx(lua.lua, index, std::mem::transmute(&success));
                    match success {
                        0 => None,
                        _ => Some(val as $t)
                    }
                }
            }
        }
        impl Index for $t {
        }
    );
)

unsigned_impl!(uint)
unsigned_impl!(u8)
unsigned_impl!(u16)
unsigned_impl!(u32)
//unsigned_impl!(u64)   // data loss

macro_rules! numeric_impl(
    ($t:ident) => (
        impl Pushable for $t {
            fn push_to_lua(&self, lua: &Lua) {
                unsafe { liblua::lua_pushnumber(lua.lua, *self as f64) }
            }
        }
        impl Readable for $t {
            fn read_from_lua(lua: &Lua, index: i32) -> Option<$t> {
                unsafe {
                    let success: libc::c_int = std::mem::uninitialized();
                    let val = liblua::lua_tonumberx(lua.lua, index, std::mem::transmute(&success));
                    match success {
                        0 => None,
                        _ => Some(val as $t)
                    }
                }
            }
        }
        impl Index for $t {
        }
    );
)

numeric_impl!(f32)
numeric_impl!(f64)

impl Pushable for std::string::String {
    fn push_to_lua(&self, lua: &Lua) {
        unsafe { liblua::lua_pushstring(lua.lua, self.to_c_str().unwrap()) }
    }
}

impl Readable for String {
    fn read_from_lua(lua: &Lua, index: i32) -> Option<std::string::String> {
        unsafe {
            let size: libc::size_t = std::mem::uninitialized();
            let cStr = liblua::lua_tolstring(lua.lua, index, std::mem::transmute(&size));
            if cStr.is_null() {
                return None;
            }

            // I can't manage to make this compile properly, so we just transmute into a static slice
            let slice = std::slice::raw::buf_as_slice(cStr as *u8, size as uint, |buf| { let b:&'static [u8] = std::mem::transmute(buf); b });
            String::from_utf8(Vec::from_slice(slice)).ok()
        }
    }
}

impl Index for String {
}

impl Pushable for ~str {
    fn push_to_lua(&self, lua: &Lua) {
        String::from_str(*self).push_to_lua(lua)
    }
}

impl Pushable for &'static str {
    fn push_to_lua(&self, lua: &Lua) {
        String::from_str(*self).push_to_lua(lua)
    }
}

impl Index for &'static str {

}

impl Readable for ~str {
    fn read_from_lua(lua: &Lua, index: i32) -> Option<~str> {
        unimplemented!()
    }
}

impl Readable for &'static str {
    fn read_from_lua(lua: &Lua, index: i32) -> Option<&'static str> {
        unimplemented!()
    }
}

impl Index for ~str {
}

#[cfg(test)]
mod tests {
    #[test]
    fn readwrite_ints() {
        let mut lua = super::super::Lua::new();

        lua.set("a", 2).unwrap();
        let x: int = lua.get("a").unwrap();
        assert_eq!(x, 2);
    }
}
<commit_msg>Updated to latest rustc<commit_after>extern crate libc;
extern crate std;

use super::liblua;
use super::Index;
use super::Lua;
use super::Pushable;
use super::Readable;

macro_rules! integer_impl(
    ($t:ident) => (
        impl Pushable for $t {
            fn push_to_lua(&self, lua: &Lua) {
                unsafe { liblua::lua_pushinteger(lua.lua, *self as liblua::lua_Integer) }
            }
        }
        impl Readable for $t {
            fn read_from_lua(lua: &Lua, index: i32) -> Option<$t> {
                unsafe {
                    let success: libc::c_int = std::mem::uninitialized();
                    let val = liblua::lua_tointegerx(lua.lua, index, std::mem::transmute(&success));
                    match success {
                        0 => None,
                        _ => Some(val as $t)
                    }
                }
            }
        }
        impl Index for $t {
        }
    );
)

integer_impl!(int)
integer_impl!(i8)
integer_impl!(i16)
integer_impl!(i32)
//integer_impl!(i64)   // data loss

macro_rules! unsigned_impl(
    ($t:ident) => (
        impl Pushable for $t {
            fn push_to_lua(&self, lua: &Lua) {
                unsafe { liblua::lua_pushunsigned(lua.lua, *self as liblua::lua_Unsigned) }
            }
        }
        impl Readable for $t {
            fn read_from_lua(lua: &Lua, index: i32) -> Option<$t> {
                unsafe {
                    let success: libc::c_int = std::mem::uninitialized();
                    let val = liblua::lua_tounsignedx(lua.lua, index, std::mem::transmute(&success));
                    match success {
                        0 => None,
                        _ => Some(val as $t)
                    }
                }
            }
        }
        impl Index for $t {
        }
    );
)

unsigned_impl!(uint)
unsigned_impl!(u8)
unsigned_impl!(u16)
unsigned_impl!(u32)
//unsigned_impl!(u64)   // data loss

macro_rules! numeric_impl(
    ($t:ident) => (
        impl Pushable for $t {
            fn push_to_lua(&self, lua: &Lua) {
                unsafe { liblua::lua_pushnumber(lua.lua, *self as f64) }
            }
        }
        impl Readable for $t {
            fn read_from_lua(lua: &Lua, index: i32) -> Option<$t> {
                unsafe {
                    let success: libc::c_int = std::mem::uninitialized();
                    let val = liblua::lua_tonumberx(lua.lua, index, std::mem::transmute(&success));
                    match success {
                        0 => None,
                        _ => Some(val as $t)
                    }
                }
            }
        }
        impl Index for $t {
        }
    );
)

numeric_impl!(f32)
numeric_impl!(f64)

impl Pushable for std::string::String {
    fn push_to_lua(&self, lua: &Lua) {
        unsafe { liblua::lua_pushstring(lua.lua, self.to_c_str().unwrap()) }
    }
}

impl Readable for String {
    fn read_from_lua(lua: &Lua, index: i32) -> Option<std::string::String> {
        unsafe {
            let size: libc::size_t = std::mem::uninitialized();
            let cStr = liblua::lua_tolstring(lua.lua, index, std::mem::transmute(&size));
            if cStr.is_null() {
                return None;
            }

            // I can't manage to make this compile properly, so we just transmute into a static slice
            let slice = std::slice::raw::buf_as_slice(cStr as *u8, size as uint, |buf| { let b:&'static [u8] = std::mem::transmute(buf); b });
            String::from_utf8(Vec::from_slice(slice)).ok()
        }
    }
}

impl Index for String {
}

impl<'a> Pushable for &'a str {
    fn push_to_lua(&self, lua: &Lua) {
        unsafe {
            liblua::lua_pushstring(lua.lua, self.to_c_str().unwrap())
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn readwrite_ints() {
        let mut lua = super::super::Lua::new();

        lua.set("a", 2).unwrap();
        let x: int = lua.get("a").unwrap();
        assert_eq!(x, 2);
    }
}
<|endoftext|>


<commit_before>use super::Numeric;
use std::ops::{Add, Sub, Mul, Div, Rem};

#[cfg(features = "parallel")]
use super::parallel::*;

pub trait Vector<N>: Sized where N: Numeric {
    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

#[cfg(not(simd))]
/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector3<N>> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

#[cfg(not(simd))]
/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector2<N>> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}
<commit_msg>Derive additional traits on vectors<commit_after>use super::Numeric;
use std::ops::{Add, Sub, Mul, Div, Rem};

#[cfg(features = "parallel")]
use super::parallel::*;

pub trait Vector<N>: Sized
where N: Numeric {

    #[cfg(features = "unstable")]
    fn is_perpendicular_to<M>(self, v_prime: Self) -> bool
    where Self: Mul<Self, Output=M>
        , M: PartialEq
    {
        (self * v_prime) == M::zero()
    }
}

/// A 3D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector3<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              , pub z: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v3_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector3<N>> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: Self) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        , z: e!(self.z $op rhs.z)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector3<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector3<N>;
            fn $fun(self, rhs: N) -> Vector3<N> {
                Vector3 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        , z: e!(self.z $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector3<N>> for Vector3<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v3_ops!{
    Add, add, +
    Sub, sub, -
    Div, div, /
    Rem, rem, %
}

impl<N> Mul<N> for Vector3<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector3 { x: self.x * rhs
                , y: self.y * rhs
                , z: self.z * rhs
                }
    }

}

impl<N> Mul<Vector3<N>> for Vector3<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) +
        (self.y * rhs.y) +
        (self.z * rhs.z)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector3<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}

/// A 2D vector of any numeric type.
///
/// This is the non-SIMD version.
#[cfg(not(simd))]
#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Debug, Default)]
#[repr(C)]
pub struct Vector2<N>
where N: Numeric
    , N: Copy { pub x: N
              , pub y: N
              }

macro_rules! e { ($e:expr) => { $e } }

macro_rules! impl_v2_ops {
    ($($name:ident, $fun:ident, $op:tt)*) => {$(
        // implement the operation for vector & vector
        impl<N> $name<Vector2<N>> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: Self) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs.x)
                        , y: e!(self.y $op rhs.y)
                        }
            }
        }
        // implement the operation for vector & scalar
        impl<N> $name<N> for Vector2<N>
        where N: Numeric + $name<Output=N>
            , N: Copy
        {
            type Output = Vector2<N>;
            fn $fun(self, rhs: N) -> Vector2<N> {
                Vector2 { x: e!(self.x $op rhs)
                        , y: e!(self.y $op rhs)
                        }
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<N> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
            , N: Copy
        {
            type Output = Self;
            fn $fun(self, rhs: N) -> Output {
                e!(self.simdalize() $op N::splat(rhs))
            }
        }

        #[cfg(features = "parallel")]
        impl<N> $name<Vector2<N>> for Vector2<N>
        where Self: Simdalize<Elem = N>
            , N: Numeric + $name<Output = N>
        {
            type Output = Self;
            fn $fun(self, rhs: Self) -> Output {
                e!(self.simdalize() $op rhs.simdalize())
            }
        }
    )*};
}

impl_v2_ops! { Add, add, +
               Sub, sub, -
               Div, div, /
               Rem, rem, %
             }

impl<N> Mul<N> for Vector2<N>
where N: Numeric + Mul<Output = N>
    , N: Copy
{
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Vector2 { x: self.x * rhs
                , y: self.y * rhs
                }
    }
}

impl<N> Mul<Vector2<N>> for Vector2<N>
where N: Numeric
    , N: Mul<Output = N> + Add<Output = N>
    , N: Copy
{
    type Output = N;
    fn mul(self, rhs: Self) -> N {
        (self.x * rhs.x) + (self.y * rhs.y)
    }
}

#[cfg(features = "parallel")]
impl<N> Mul<N> for Vector2<N>
where Self: Simdalize<Elem = N>
    , N: Numeric + Mul<Output = N>
{
    type Output = Self;
    fn mul(self, rhs: N) -> Output { self.simdalize() * N::splat(rhs) }
}
<|endoftext|>