<commit_before>#![feature(collections, unboxed_closures, core)]
extern crate itertools;
extern crate rustc_serialize;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use std::iter;
use std::ops;

use itertools::{GroupBy, Itertools};

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Eq, Debug, 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<Document> for Document {
    // Documents are unique only upon their id
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct IndexedDocument {
    pub doc: Arc<Document>,
    pub highlighted: (usize, usize),
}

/// 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
/// score and a String of the document's content post-highlighting.
#[derive(Clone, Debug, RustcEncodable)]
pub struct SearchResult {
    doc: Arc<Document>,
    highlights: Vec<(usize, usize)>,
    highlighted: String,
    score: f32,
}

impl PartialEq for SearchResult {
    // SearchResult is unique upon its document and highlights
    fn eq(&self, other: &SearchResult) -> bool {
        self.doc == other.doc && self.highlights == other.highlights
    }
}

impl Eq for SearchResult {}

impl Hash for SearchResult {
    // SearchResult is unique upon its document and highlights
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.doc.hash(state);
        self.highlights.hash(state);
    }
}

impl SearchResult {
    /// Returns the document
    pub fn doc(&self) -> &Arc<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 highlighted content.
    ///
    /// The highlighted content is the result of splicing in `<span class=highlight></span>` tags
    /// around words that should be highlighted.
    pub fn highlighted(&self) -> &String {
        &self.highlighted
    }

    /// 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
    }

    fn new_((doc, highlights): (Arc<Document>, Vec<(usize, usize)>)) -> SearchResult {
        SearchResult::new(doc, highlights)
    }

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

    fn highlighted_content(content: &str, highlights: &mut [(usize, usize)]) -> String {
        highlights.sort();
        let mut begin_idx = 0;
        let mut parts = vec![];
        for &mut (begin, end) in highlights {
            parts.push(&content[begin_idx..begin]);
            parts.push("");
            parts.push(&content[begin..end]);
            parts.push("");
            begin_idx = end;
        }
        parts.push(&content[begin_idx..]);
        parts.into_iter().join("")
    }
}

/// 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, HashSet<IndexedDocument>>,
    docs: BTreeMap<String, Arc<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 doc = Arc::new(doc);
        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, highlights) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&IndexedDocument { doc: doc.clone(), highlighted: highlights });
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        for (ngram, highlighted) in analyzed {
            self.index.entry(ngram).or_insert_with(|| HashSet::new())
                .insert(IndexedDocument { doc: doc.clone(), highlighted: 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().collect();
        let map = unique_terms.into_iter()
            .flat_map(|word| self.index.get(&word.to_lowercase()))
            .flat_map(|doc| doc)
            .cloned()
            .fold(HashMap::new(), |mut map, search_result| {
                map.entry(search_result.doc)
                    .or_insert(Vec::new())
                    .push(search_result.highlighted);
                map
            });
        let mut results: Vec<_> = map.into_iter()
            .map(SearchResult::new_)
            .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, std::str::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)
    }
}

#[test]
fn test_search1() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    index.index(doc1.clone());
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)])
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!("learn to program in rust today", expected[0].highlighted);
}

#[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 = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!("learn to program in rust today", expected[0].highlighted);

}

#[test]
fn test_search2() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("2", "what to do today");
    let doc2 = Document::new("3", "hey today");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(5, 7), (11, 13)]),
        SearchResult::new(Arc::new(doc2), vec![(4, 6)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!(expected[0].highlighted, "what to do today");
}

#[test]
fn test_unicode() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    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.clone());
    let search_results = index.search("be");
    assert_eq!(index.docs.len(), 2);
    assert_eq!(&*search_results.into_iter().next().unwrap().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);
}

<commit_msg>Fix duplicate term error. First fix wasn't correct<commit_after>#![feature(collections, unboxed_closures, core)]
extern crate itertools;
extern crate rustc_serialize;

use std::collections::{BTreeMap, HashMap, HashSet};
use std::collections::hash_map::Entry::*;
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use std::iter;
use std::ops;

use itertools::{GroupBy, Itertools};

/// A Document contains an id and content.
/// Hashing and equality are based only on the id field.
#[derive(Clone, Eq, Debug, 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<Document> for Document {
    // Documents are unique only upon their id
    fn eq(&self, other: &Document) -> bool {
        self.id == other.id
    }
}

#[derive(Clone, Eq, PartialEq, Hash, Debug)]
struct IndexedDocument {
    pub doc: Arc<Document>,
    pub highlighted: (usize, usize),
}

/// 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
/// score and a String of the document's content post-highlighting.
#[derive(Clone, Debug, RustcEncodable)]
pub struct SearchResult {
    doc: Arc<Document>,
    highlights: Vec<(usize, usize)>,
    highlighted: String,
    score: f32,
}

impl PartialEq for SearchResult {
    // SearchResult is unique upon its document and highlights
    fn eq(&self, other: &SearchResult) -> bool {
        self.doc == other.doc && self.highlights == other.highlights
    }
}

impl Eq for SearchResult {}

impl Hash for SearchResult {
    // SearchResult is unique upon its document and highlights
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.doc.hash(state);
        self.highlights.hash(state);
    }
}

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

    /// Returns the document
    pub fn doc(&self) -> &Arc<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 highlighted content.
    ///
    /// The highlighted content is the result of splicing in `<span class=highlight></span>` tags
    /// around words that should be highlighted.
    pub fn highlighted(&self) -> &String {
        &self.highlighted
    }

    /// 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
    }

    fn highlighted_content(content: &str, highlights: &mut [(usize, usize)]) -> String {
        highlights.sort();
        let mut begin_idx = 0;
        let mut parts = vec![];
        for &mut (begin, end) in highlights {
            parts.push(&content[begin_idx..begin]);
            parts.push("");
            parts.push(&content[begin..end]);
            parts.push("");
            begin_idx = end;
        }
        parts.push(&content[begin_idx..]);
        parts.into_iter().join("")
    }
}

/// 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, HashSet<IndexedDocument>>,
    docs: BTreeMap<String, Arc<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 doc = Arc::new(doc);
        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, highlights) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&IndexedDocument { doc: doc.clone(), highlighted: highlights });
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        for (ngram, highlighted) in analyzed {
            self.index.entry(ngram).or_insert_with(|| HashSet::new())
                .insert(IndexedDocument { doc: doc.clone(), highlighted: 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().collect();
        let map = unique_terms.into_iter()
            .flat_map(|word| self.index.get(&word.to_lowercase()))
            .flat_map(|doc| doc)
            .cloned()
            .fold(HashMap::new(), |mut map, IndexedDocument { doc, highlighted: (begin, end) }| {
                match map.entry(doc) {
                    Vacant(entry) => {
                        let mut indices = HashMap::new();
                        indices.insert(begin, end);
                        entry.insert(indices);
                    }
                    Occupied(mut entry) => {
                        match entry.get_mut().entry(begin) {
                            Vacant(entry) => { entry.insert(end); }
                            Occupied(mut entry) => {
                                let current = entry.get_mut();
                                *current = std::cmp::max(*current, end);
                            }
                        }
                    }
                }
                map
            });
        let mut results: Vec<_> = map.into_iter()
            .map(|(doc, index_map)| SearchResult::new(doc, 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, std::str::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)
    }
}

#[test]
fn test_search1() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("1", "learn to program in rust today");
    index.index(doc1.clone());
    let doc2 = Document::new("2", "what did you today do");
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)])
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!("learn to program in rust today", expected[0].highlighted);
}

#[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 = [
        SearchResult::new(Arc::new(doc1), vec![(6, 8), (25, 27)]),
        SearchResult::new(Arc::new(doc2), vec![(13, 15)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!("learn to program in rust today", expected[0].highlighted);

}

#[test]
fn test_search2() {
    let mut index = InvertedIndex::new();
    let doc1 = Document::new("2", "what to do today");
    let doc2 = Document::new("3", "hey today");
    index.index(doc1.clone());
    index.index(doc2.clone());
    let search_results = index.search("to");
    let expected = [
        SearchResult::new(Arc::new(doc1), vec![(5, 7), (11, 13)]),
        SearchResult::new(Arc::new(doc2), vec![(4, 6)]),
    ];
    assert_eq!(search_results, expected.iter().cloned().collect::<Vec<_>>());
    assert_eq!(expected[0].highlighted, "what to do today");
}

#[test]
fn test_unicode() {
    let mut index = InvertedIndex::new();
    let doc = Document::new("0", "abc åäö");
    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.clone());
    let search_results = index.search("be");
    assert_eq!(index.docs.len(), 2);
    assert_eq!(&*search_results.into_iter().next().unwrap().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], SearchResult::new(Arc::new(doc), vec![(0, 2)]));
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, macro_rules)]
#![crate_type = "dylib"]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap::{Span};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, DummyResult};
use rustc::plugin::Registry;

enum Severity {
    Note,
    Warning,
    Error,
    Fatal,
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    macro_rules! register_specifics {
        ($($name: expr => $sev: ident),*) => {
            {
                $(
                    reg.register_macro($name, {
                        fn f(cx: &mut ExtCtxt, sp: Span,
                             args: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
                            expand_msg($sev, cx, sp, args)
                        }
                        f
                    });
                    )*
            }
        }
    }

    register_specifics! {
        "compile_note" => Note,
        "compile_warning" => Warning,
        "compile_error" => Error,
        "compile_fatal" => Fatal
    }
}

fn expand_msg(sev: Severity,
              cx: &mut ExtCtxt, sp: Span, args: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
    // copied from syntax::ext::concat.
    let es = match base::get_exprs_from_tts(cx, sp, args) {
        Some(e) => e,
        None => return base::DummyResult::expr(sp)
    };
    let mut accumulator = String::new();
    for e in es.move_iter() {
        match e.node {
            ast::ExprLit(ref lit) => {
                match lit.node {
                    ast::LitStr(ref s, _) |
                    ast::LitFloat(ref s, _) |
                    ast::LitFloatUnsuffixed(ref s) => {
                        accumulator.push_str(s.get());
                    }
                    ast::LitChar(c) => {
                        accumulator.push_char(c);
                    }
                    ast::LitInt(i, ast::UnsignedIntLit(_)) |
                    ast::LitInt(i, ast::SignedIntLit(_, ast::Plus)) |
                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Plus)) => {
                        accumulator.push_str(format!("{}", i).as_slice());
                    }
                    ast::LitInt(i, ast::SignedIntLit(_, ast::Minus)) |
                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Minus)) => {
                        accumulator.push_str(format!("-{}", i).as_slice());
                    }
                    ast::LitNil => {}
                    ast::LitBool(b) => {
                        accumulator.push_str(format!("{}", b).as_slice());
                    }
                    ast::LitByte(..) |
                    ast::LitBinary(..) => {
                        cx.span_err(e.span, "cannot concatenate a binary literal");
                    }
                }
            }
            _ => {
                cx.span_err(e.span, "expected a literal");
            }
        }
    }

    macro_rules! emit {
        ($($sev: ident => $method: ident),*) => {
            match sev {
                $($sev => cx.$method(sp, accumulator.as_slice()),)*
            }
        }
    }
    emit! {
        Note => span_note,
        Warning => span_warn,
        Error => span_err,
        Fatal => span_fatal
    }

    DummyResult::any(sp)
}
<commit_msg>Update for rustc 6ef8392b3 2014-10-20 22:17:49 +0000<commit_after>#![feature(plugin_registrar, macro_rules)]
#![crate_type = "dylib"]

extern crate syntax;
extern crate rustc;

use syntax::ast;
use syntax::codemap::{Span};
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, DummyResult};
use rustc::plugin::Registry;

enum Severity {
    Note,
    Warning,
    Error,
    Fatal,
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    macro_rules! register_specifics {
        ($($name: expr => $sev: ident),*) => {
            {
                $(
                    reg.register_macro($name, {
                        fn f(cx: &mut ExtCtxt, sp: Span,
                             args: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
                            expand_msg($sev, cx, sp, args)
                        }
                        f
                    });
                    )*
            }
        }
    }

    register_specifics! {
        "compile_note" => Note,
        "compile_warning" => Warning,
        "compile_error" => Error,
        "compile_fatal" => Fatal
    }
}

fn expand_msg(sev: Severity,
              cx: &mut ExtCtxt, sp: Span, args: &[ast::TokenTree]) -> Box<base::MacResult+'static> {
    // copied from syntax::ext::concat.
    let es = match base::get_exprs_from_tts(cx, sp, args) {
        Some(e) => e,
        None => return base::DummyResult::expr(sp)
    };
    let mut accumulator = String::new();
    for e in es.into_iter() {
        match e.node {
            ast::ExprLit(ref lit) => {
                match lit.node {
                    ast::LitStr(ref s, _) |
                    ast::LitFloat(ref s, _) |
                    ast::LitFloatUnsuffixed(ref s) => {
                        accumulator.push_str(s.get());
                    }
                    ast::LitChar(c) => {
                        accumulator.push(c);
                    }
                    ast::LitInt(i, ast::UnsignedIntLit(_)) |
                    ast::LitInt(i, ast::SignedIntLit(_, ast::Plus)) |
                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Plus)) => {
                        accumulator.push_str(format!("{}", i).as_slice());
                    }
                    ast::LitInt(i, ast::SignedIntLit(_, ast::Minus)) |
                    ast::LitInt(i, ast::UnsuffixedIntLit(ast::Minus)) => {
                        accumulator.push_str(format!("-{}", i).as_slice());
                    }
                    ast::LitNil => {}
                    ast::LitBool(b) => {
                        accumulator.push_str(format!("{}", b).as_slice());
                    }
                    ast::LitByte(..) |
                    ast::LitBinary(..) => {
                        cx.span_err(e.span, "cannot concatenate a binary literal");
                    }
                }
            }
            _ => {
                cx.span_err(e.span, "expected a literal");
            }
        }
    }

    macro_rules! emit {
        ($($sev: ident => $method: ident),*) => {
            match sev {
                $($sev => cx.$method(sp, accumulator.as_slice()),)*
            }
        }
    }
    emit! {
        Note => span_note,
        Warning => span_warn,
        Error => span_err,
        Fatal => span_fatal
    }

    DummyResult::any(sp)
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul};
use std::iter::FromIterator;

/// Provides projections between a sphere and the map view
pub mod projection;
/// Implements a stereographic projection
pub mod stereographic;
/// Implements a simple equirectangular projection
pub mod equirectangular;
/// Layers that can be drawn on the map
pub mod layer;
/// Represents a map
pub mod map;

/// Represents a latitude, in degrees
#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
pub struct Latitude(f64);
/// Represents a longitude, in degrees
#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
pub struct Longitude(f64);

impl Latitude {
    /// Converts this latitude into an angle in radians
    pub fn to_radians(self) -> f64 {
        f64::to_radians(self.into())
    }
}
impl Longitude {
    /// Converts this longitude into an angle in radians
    pub fn to_radians(self) -> f64 {
        f64::to_radians(self.into())
    }
}
impl Into<f64> for Latitude {
    fn into(self) -> f64 {
        self.0
    }
}
impl Into<f64> for Longitude {
    fn into(self) -> f64 {
        self.0
    }
}
impl From<f64> for Latitude {
    fn from(value: f64) -> Self {
        Latitude(value)
    }
}
impl From<f64> for Longitude {
    fn from(value: f64) -> Self {
        Longitude(value)
    }
}
impl Sub for Latitude {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self {
        Self::from(self.0 - rhs.0)
    }
}
impl Sub for Longitude {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self {
        Self::from(self.0 - rhs.0)
    }
}
impl Add for Latitude {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self::from(self.0 + rhs.0)
    }
}
impl Add for Longitude {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self::from(self.0 + rhs.0)
    }
}

/// Stores a latitude and longitude
#[derive(Debug,Clone,PartialEq)]
pub struct LatLon {
    /// Latitude, degrees
    pub latitude: Latitude,
    /// Longitude, degrees
    pub longitude: Longitude,
}

impl LatLon {
    /// Returns a LatLon that is dimetrically opposite from this (on the other side of the planet)
    pub fn antipode(&self) -> LatLon {
        LatLon {
            latitude: normalize_latitude(self.latitude + Latitude(180.0)),
            longitude: normalize_longitude(self.longitude + Longitude(180.0)),
        }
    }
}

///
/// A rectangle in latitude and longitude
///
#[derive(Debug,Clone,PartialEq)]
pub struct LatLonRect {
    /// The north latitude (always >= south)
    north: Latitude,
    /// The south latitude
    south: Latitude,
    /// The east latitude (always >= west)
    east: Longitude,
    /// The west latitude
    west: Longitude,
}

impl LatLonRect {
    pub fn from_bounds(north: Latitude, south: Latitude, east: Longitude, west: Longitude) -> LatLonRect {
        LatLonRect {
            north: north,
            south: south,
            east: east,
            west: west,
        }
    }
    pub fn from_corners(northwest: &LatLon, southeast: &LatLon) -> LatLonRect {
        LatLonRect {
            north: northwest.latitude,
            south: southeast.latitude,
            east: southeast.longitude,
            west: northwest.longitude,
        }
    }
    pub fn north(&self) -> Latitude {
        self.north
    }
    pub fn south(&self) -> Latitude {
        self.south
    }
    pub fn east(&self) -> Longitude {
        self.east
    }
    pub fn west(&self) -> Longitude {
        self.west
    }
    pub fn set_north(&mut self, north: Latitude) {
        self.north = north
    }
    pub fn set_south(&mut self, south: Latitude) {
        self.south = south
    }
    pub fn set_east(&mut self, east: Longitude) {
        self.east = east
    }
    pub fn set_west(&mut self, west: Longitude) {
        self.west = west
    }
}

/// Normalizes a latitude into the range [-90, 90]
pub fn normalize_latitude(latitude: Latitude) -> Latitude {
    let radians = latitude.0.to_radians();
    let result = f64::atan(f64::sin(radians) / f64::abs(f64::cos(radians)));
    Latitude(result.to_degrees())
}
/// Normalizes a longitude into the range [-180, 180]
pub fn normalize_longitude(longitude: Longitude) -> Longitude {
    let radians = longitude.0.to_radians();
    let result = f64::atan2(f64::sin(radians), f64::cos(radians));
    Longitude(result.to_degrees())
}

/// Stores a point
#[derive(Debug,Clone,PartialEq)]
pub struct Point<N> {
    /// X coordinate
    pub x: N,
    /// Y coordinate
    pub y: N,
}

impl Point<f64> {
    /// Returns a point at (0, 0)
    pub fn origin() -> Point<f64> {
        Point { x: 0f64, y: 0f64 }
    }
}

impl<N> Add for Point<N> where N: Add<Output = N> {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Point {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}
impl<N> Sub for Point<N> where N: Sub<Output = N> {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self {
        Point {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}
impl<N> Mul<N> for Point<N> where N: Mul<N, Output = N> + Clone {
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Point {
            x: self.x * rhs.clone(),
            y: self.y * rhs,
        }
    }
}

///
/// A polygon
///
/// P is the type used to represent a point
///
pub struct Polygon<P> {
    /// The points in this quadrilateral, in clockwise order
    points: Vec<P>,
}

impl<P> Polygon<P> where P: Clone {
    pub fn new(points: &[P]) -> Polygon<P> {
        Polygon {
            points: points.iter().cloned().collect(),
        }
    }
}

impl<P> Polygon<P> {
    pub fn points<'a>(&'a self) -> &'a [P] {
        &self.points
    }
}

impl<P> FromIterator<P> for Polygon<P> {
    fn from_iter<T>(iterator: T) -> Self where T: IntoIterator<Item = P> {
        Polygon {
            points: Vec::from_iter(iterator)
        }
    }
}

#[test]
fn test_normalize_lat_identity_1() {
    assert_eq!(10.0, normalize_latitude(10.0));
}
#[test]
fn test_normalize_lat_identity_2() {
    assert_eq!(90.0, normalize_latitude(90.0));
}
#[test]
fn test_normalize_lon_identity_1() {
    assert_eq!(10.0, normalize_longitude(10.0));
}
#[test]
fn test_normalize_lon_identity_2() {
    assert_eq!(90.0, normalize_longitude(90.0));
}

#[test]
fn test_antipode_north_pole() {
    let north_pole = LatLon { latitude: 90.0, longitude: 0.0 };
    let antipode = north_pole.antipode();
    assert!(close_enough(-90.0, antipode.latitude));
}
#[test]
fn test_antipode_south_pole() {
    let south_pole = LatLon { latitude: -90.0, longitude: 0.0 };
    let antipode = south_pole.antipode();
    assert!(close_enough(90.0, antipode.latitude));
}
#[test]
fn test_antipode_zero_zero() {
    let point = LatLon { latitude: 0.0, longitude: 0.0 };
    let antipode = point.antipode();
    assert!(close_enough(0.0, antipode.latitude));
    assert!(close_enough(180.0, antipode.longitude));
}
#[test]
fn test_antipode_zero_90() {
    let point = LatLon { latitude: 0.0, longitude: 90.0 };
    let antipode = point.antipode();
    assert!(close_enough(0.0, antipode.latitude));
    assert!(close_enough(-90.0, antipode.longitude));
}

#[cfg(test)]
fn close_enough(a: f64, b: f64) -> bool {
    let result = (a - b).abs() < 0.001;
    if !result {
        println!("a = {} and b = {} are not close enough", a, b);
    }
    result
}
<commit_msg>Made Latitude an Longitude fields public<commit_after>use std::ops::{Add, Sub, Mul};
use std::iter::FromIterator;

/// Provides projections between a sphere and the map view
pub mod projection;
/// Implements a stereographic projection
pub mod stereographic;
/// Implements a simple equirectangular projection
pub mod equirectangular;
/// Layers that can be drawn on the map
pub mod layer;
/// Represents a map
pub mod map;

/// Represents a latitude, in degrees
#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
pub struct Latitude(pub f64);
/// Represents a longitude, in degrees
#[derive(Debug,Copy,Clone,PartialEq,PartialOrd)]
pub struct Longitude(pub f64);

impl Latitude {
    /// Converts this latitude into an angle in radians
    pub fn to_radians(self) -> f64 {
        f64::to_radians(self.into())
    }
}
impl Longitude {
    /// Converts this longitude into an angle in radians
    pub fn to_radians(self) -> f64 {
        f64::to_radians(self.into())
    }
}
impl Into<f64> for Latitude {
    fn into(self) -> f64 {
        self.0
    }
}
impl Into<f64> for Longitude {
    fn into(self) -> f64 {
        self.0
    }
}
impl From<f64> for Latitude {
    fn from(value: f64) -> Self {
        Latitude(value)
    }
}
impl From<f64> for Longitude {
    fn from(value: f64) -> Self {
        Longitude(value)
    }
}
impl Sub for Latitude {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self {
        Self::from(self.0 - rhs.0)
    }
}
impl Sub for Longitude {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self {
        Self::from(self.0 - rhs.0)
    }
}
impl Add for Latitude {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self::from(self.0 + rhs.0)
    }
}
impl Add for Longitude {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self::from(self.0 + rhs.0)
    }
}

/// Stores a latitude and longitude
#[derive(Debug,Clone,PartialEq)]
pub struct LatLon {
    /// Latitude, degrees
    pub latitude: Latitude,
    /// Longitude, degrees
    pub longitude: Longitude,
}

impl LatLon {
    /// Returns a LatLon that is dimetrically opposite from this (on the other side of the planet)
    pub fn antipode(&self) -> LatLon {
        LatLon {
            latitude: normalize_latitude(self.latitude + Latitude(180.0)),
            longitude: normalize_longitude(self.longitude + Longitude(180.0)),
        }
    }
}

///
/// A rectangle in latitude and longitude
///
#[derive(Debug,Clone,PartialEq)]
pub struct LatLonRect {
    /// The north latitude (always >= south)
    north: Latitude,
    /// The south latitude
    south: Latitude,
    /// The east latitude (always >= west)
    east: Longitude,
    /// The west latitude
    west: Longitude,
}

impl LatLonRect {
    pub fn from_bounds(north: Latitude, south: Latitude, east: Longitude, west: Longitude) -> LatLonRect {
        LatLonRect {
            north: north,
            south: south,
            east: east,
            west: west,
        }
    }
    pub fn from_corners(northwest: &LatLon, southeast: &LatLon) -> LatLonRect {
        LatLonRect {
            north: northwest.latitude,
            south: southeast.latitude,
            east: southeast.longitude,
            west: northwest.longitude,
        }
    }
    pub fn north(&self) -> Latitude {
        self.north
    }
    pub fn south(&self) -> Latitude {
        self.south
    }
    pub fn east(&self) -> Longitude {
        self.east
    }
    pub fn west(&self) -> Longitude {
        self.west
    }
    pub fn set_north(&mut self, north: Latitude) {
        self.north = north
    }
    pub fn set_south(&mut self, south: Latitude) {
        self.south = south
    }
    pub fn set_east(&mut self, east: Longitude) {
        self.east = east
    }
    pub fn set_west(&mut self, west: Longitude) {
        self.west = west
    }
}

/// Normalizes a latitude into the range [-90, 90]
pub fn normalize_latitude(latitude: Latitude) -> Latitude {
    let radians = latitude.0.to_radians();
    let result = f64::atan(f64::sin(radians) / f64::abs(f64::cos(radians)));
    Latitude(result.to_degrees())
}
/// Normalizes a longitude into the range [-180, 180]
pub fn normalize_longitude(longitude: Longitude) -> Longitude {
    let radians = longitude.0.to_radians();
    let result = f64::atan2(f64::sin(radians), f64::cos(radians));
    Longitude(result.to_degrees())
}

/// Stores a point
#[derive(Debug,Clone,PartialEq)]
pub struct Point<N> {
    /// X coordinate
    pub x: N,
    /// Y coordinate
    pub y: N,
}

impl Point<f64> {
    /// Returns a point at (0, 0)
    pub fn origin() -> Point<f64> {
        Point { x: 0f64, y: 0f64 }
    }
}

impl<N> Add for Point<N> where N: Add<Output = N> {
    type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Point {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}
impl<N> Sub for Point<N> where N: Sub<Output = N> {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self {
        Point {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}
impl<N> Mul<N> for Point<N> where N: Mul<N, Output = N> + Clone {
    type Output = Self;
    fn mul(self, rhs: N) -> Self {
        Point {
            x: self.x * rhs.clone(),
            y: self.y * rhs,
        }
    }
}

///
/// A polygon
///
/// P is the type used to represent a point
///
pub struct Polygon<P> {
    /// The points in this quadrilateral, in clockwise order
    points: Vec<P>,
}

impl<P> Polygon<P> where P: Clone {
    pub fn new(points: &[P]) -> Polygon<P> {
        Polygon {
            points: points.iter().cloned().collect(),
        }
    }
}

impl<P> Polygon<P> {
    pub fn points<'a>(&'a self) -> &'a [P] {
        &self.points
    }
}

impl<P> FromIterator<P> for Polygon<P> {
    fn from_iter<T>(iterator: T) -> Self where T: IntoIterator<Item = P> {
        Polygon {
            points: Vec::from_iter(iterator)
        }
    }
}

#[test]
fn test_normalize_lat_identity_1() {
    assert_eq!(10.0, normalize_latitude(10.0));
}
#[test]
fn test_normalize_lat_identity_2() {
    assert_eq!(90.0, normalize_latitude(90.0));
}
#[test]
fn test_normalize_lon_identity_1() {
    assert_eq!(10.0, normalize_longitude(10.0));
}
#[test]
fn test_normalize_lon_identity_2() {
    assert_eq!(90.0, normalize_longitude(90.0));
}

#[test]
fn test_antipode_north_pole() {
    let north_pole = LatLon { latitude: 90.0, longitude: 0.0 };
    let antipode = north_pole.antipode();
    assert!(close_enough(-90.0, antipode.latitude));
}
#[test]
fn test_antipode_south_pole() {
    let south_pole = LatLon { latitude: -90.0, longitude: 0.0 };
    let antipode = south_pole.antipode();
    assert!(close_enough(90.0, antipode.latitude));
}
#[test]
fn test_antipode_zero_zero() {
    let point = LatLon { latitude: 0.0, longitude: 0.0 };
    let antipode = point.antipode();
    assert!(close_enough(0.0, antipode.latitude));
    assert!(close_enough(180.0, antipode.longitude));
}
#[test]
fn test_antipode_zero_90() {
    let point = LatLon { latitude: 0.0, longitude: 90.0 };
    let antipode = point.antipode();
    assert!(close_enough(0.0, antipode.latitude));
    assert!(close_enough(-90.0, antipode.longitude));
}

#[cfg(test)]
fn close_enough(a: f64, b: f64) -> bool {
    let result = (a - b).abs() < 0.001;
    if !result {
        println!("a = {} and b = {} are not close enough", a, b);
    }
    result
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use bit_field::BitField;
use std::fmt::{self, Debug, Display, Formatter};
use thiserror::Error;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FieldInfo {
    pub name: &'static str,
    pub start: usize,
    pub width: usize,
    pub value: u64,
    pub decoded: Option<Decoded>,
}

impl FieldInfo {
    fn get(register: u64, name: &'static str, start: usize, end: usize) -> Self {
        let value = register.get_bits(start..end);
        Self {
            name,
            start,
            width: end - start,
            value,
            decoded: None,
        }
    }

    fn get_bit(register: u64, name: &'static str, bit: usize) -> Self {
        Self::get(register, name, bit, bit + 1)
    }

    fn with_decoded(self, decoded: Decoded) -> Self {
        Self {
            decoded: Some(decoded),
            ..self
        }
    }

    fn with_description(self, description: String) -> Self {
        self.with_decoded(Decoded {
            description: Some(description),
            fields: vec![],
        })
    }

    fn as_bit(&self) -> bool {
        assert!(self.width == 1);
        self.value == 1
    }

    /// Assuming this field has a width of exactly 1, describe it with the given function.
    ///
    /// Panics if `self.width != 1`.
    fn describe_bit<F>(self, describer: F) -> Self
    where
        F: FnOnce(bool) -> &'static str,
    {
        let bit = self.as_bit();
        let description = Some(describer(bit).to_string());
        self.with_decoded(Decoded {
            description,
            fields: vec![],
        })
    }
}

impl Display for FieldInfo {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        if self.width == 1 {
            write!(
                f,
                "{}: {}",
                self.name,
                if self.value == 1 { "true" } else { "false" }
            )
        } else {
            write!(
                f,
                "{}: {:#02$x} {1:#03$b}",
                self.name,
                self.value,
                (self.width + 3) / 4 + 2,
                self.width + 2
            )
        }
    }
}

#[derive(Debug, Error)]
pub enum DecodeError {
    #[error("Invalid ESR, res0 is {res0:#x}")]
    InvalidRes0 { res0: u64 },
    #[error("Invalid EC {ec:#x}")]
    InvalidEc { ec: u64 },
    #[error("Invalid DFSC {dfsc:#x}")]
    InvalidDfsc { dfsc: u64 },
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum SyndromeAccessSize {
    Byte = 0b00,
    Halfword = 0b01,
    Word = 0b10,
    Doubleword = 0b11,
}

impl Display for SyndromeAccessSize {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let s = match self {
            Self::Byte => "byte",
            Self::Halfword => "halfword",
            Self::Word => "word",
            Self::Doubleword => "doubleword",
        };
        write!(f, "{}", s)
    }
}

fn describe_sf(sf: bool) -> &'static str {
    if sf {
        "64-bit wide register"
    } else {
        "32-bit wide register"
    }
}

fn describe_ar(ar: bool) -> &'static str {
    if ar {
        "Acquire/release semantics"
    } else {
        "No acquire/release semantics"
    }
}

fn describe_fnv(fnv: bool) -> &'static str {
    if fnv {
        "FAR is not valid, it holds an unknown value"
    } else {
        "FAR is valid"
    }
}

fn describe_wnr(wnr: bool) -> &'static str {
    if wnr {
        "Abort caused by writing to memory"
    } else {
        "Abort caused by reading from memory"
    }
}

fn describe_dfsc(dfsc: u64) -> Result<&'static str, DecodeError> {
    let description = match dfsc {
        0b000000 => "Address size fault, level 0 of translation or translation table base register.",
        0b000001 => "Address size fault, level 1.",
        0b000010 => "Address size fault, level 2.",
        0b000011 => "Address size fault, level 3.",
        0b000100 => "Translation fault, level 0.",
        0b000101 => "Translation fault, level 1.",
        0b000110 => "Translation fault, level 2.",
        0b000111 => "Translation fault, level 3.",
        0b001001 => "Access flag fault, level 1.",
        0b001010 => "Access flag fault, level 2.",
        0b001011 => "Access flag fault, level 3.",
        0b001000 => "Access flag fault, level 0.",
        0b001100 => "Permission fault, level 0.",
        0b001101 => "Permission fault, level 1.",
        0b001110 => "Permission fault, level 2.",
        0b001111 => "Permission fault, level 3.",
        0b010000 => "Synchronous External abort, not on translation table walk or hardware update of translation table.",
        0b010001 => "Synchronous Tag Check Fault.",
        0b010011 => "Synchronous External abort on translation table walk or hardware update of translation table, level -1.",
        0b010100 => "Synchronous External abort on translation table walk or hardware update of translation table, level 0.",
        0b010101 => "Synchronous External abort on translation table walk or hardware update of translation table, level 1.",
        0b010110 => "Synchronous External abort on translation table walk or hardware update of translation table, level 2.",
        0b010111 => "Synchronous External abort on translation table walk or hardware update of translation table, level 3.",
        0b011000 => "Synchronous parity or ECC error on memory access, not on translation table walk.",
        0b011011 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level -1.",
        0b011100 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 0.",
        0b011101 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 1.",
        0b011110 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 2.",
        0b011111 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 3.",
        0b100001 => "Alignment fault.",
        0b101001 => "Address size fault, level -1.",
        0b101011 => "Translation fault, level -1.",
        0b110000 => "TLB conflict abort.",
        0b110001 => "Unsupported atomic hardware update fault.",
        0b110100 => "IMPLEMENTATION DEFINED fault (Lockdown).",
        0b110101 => "IMPLEMENTATION DEFINED fault (Unsupported Exclusive or Atomic access).",
        _ => return Err(DecodeError::InvalidDfsc { dfsc }),
    };
    Ok(description)
}

fn decode_iss_data_abort(iss: u64) -> Result<Decoded, DecodeError> {
    let isv = FieldInfo::get_bit(iss, "ISV", 24);
    let sas = FieldInfo::get(iss, "SAS", 22, 24);
    let sas_value = match sas.value {
        0b00 => SyndromeAccessSize::Byte,
        0b01 => SyndromeAccessSize::Halfword,
        0b10 => SyndromeAccessSize::Word,
        0b11 => SyndromeAccessSize::Doubleword,
        _ => unreachable!(),
    };
    let sas = sas.with_decoded(Decoded {
        description: Some(sas_value.to_string()),
        fields: vec![],
    });
    let sse = FieldInfo::get_bit(iss, "SSE", 21);
    let srt = FieldInfo::get(iss, "SRT", 16, 21);
    let sf = FieldInfo::get_bit(iss, "SF", 15).describe_bit(describe_sf);
    let ar = FieldInfo::get_bit(iss, "AR", 14).describe_bit(describe_ar);
    let vncr = FieldInfo::get_bit(iss, "VNCR", 13);
    let fnv = FieldInfo::get_bit(iss, "FnV", 10).describe_bit(describe_fnv);
    let ea = FieldInfo::get_bit(iss, "EA", 9);
    let cm = FieldInfo::get_bit(iss, "CM", 8);
    let s1ptw = FieldInfo::get_bit(iss, "S1PTW", 7);
    let wnr = FieldInfo::get_bit(iss, "WnR", 6).describe_bit(describe_wnr);
    let dfsc = FieldInfo::get(iss, "DFSC", 0, 6);
    let dfsc_description = describe_dfsc(dfsc.value)?;
    let dfsc = dfsc.with_description(dfsc_description.to_string());

    Ok(Decoded {
        description: None,
        fields: vec![
            isv, sas, sse, srt, sf, ar, vncr, fnv, ea, cm, s1ptw, wnr, dfsc,
        ],
    })
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Decoded {
    pub description: Option<String>,
    pub fields: Vec<FieldInfo>,
}

pub fn decode(esr: u64) -> Result<Decoded, DecodeError> {
    let res0 = FieldInfo::get(esr, "RES0", 37, 64);
    let iss2 = FieldInfo::get(esr, "ISS2", 32, 37);
    let ec = FieldInfo::get(esr, "EC", 26, 32);
    let il = FieldInfo::get_bit(esr, "IL", 25);
    let iss = FieldInfo::get(esr, "ISS", 0, 25);
    if res0.value != 0 {
        return Err(DecodeError::InvalidRes0 { res0: res0.value });
    }
    let (class, iss_decoded) = match ec.value {
        0b000000 => ("Unknown reason", None),
        0b000001 => ("Wrapped WF* instruction execution", None),
        0b000011 => ("Trapped MCR or MRC access with coproc=0b1111", None),
        0b000100 => ("Trapped MCRR or MRRC access with coproc=0b1111", None),
        0b000101 => ("Trapped MCR or MRC access with coproc=0b1110", None),
        0b000110 => ("Trapped LDC or STC access", None),
        0b000111 => ("Trapped access to SVE, Advanced SIMD or floating point", None),
        0b001010 => ("Trapped execution of an LD64B, ST64B, ST64BV, or ST64BV0 instruction", None),
        0b001100 => ("Trapped MRRC access with (coproc==0b1110)", None),
        0b001101 => ("Branch Target Exception", None),
        0b001110 => ("Illegal Execution state", None),
        0b010001 => ("SVC instruction execution in AArch32 state", None),
        0b010101 => ("SVC instruction execution in AArch64 state", None),
        0b011000 => ("Trapped MSR, MRS or System instruction execution in AArch64 state", None),
        0b011001 => ("Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, CPTR_EL2.TZ, or CPTR_EL3.EZ", None),
        0b011100 => ("Exception from a Pointer Authentication instruction authentication failure", None),
        0b100000 => ("Instruction Abort from a lower Exception level", None),
        0b100001 => ("Instruction Abort taken without a change in Exception level", None),
        0b100010 => ("PC alignment fault exception", None),
        0b100100 => ("Data Abort from a lower Exception level", Some(decode_iss_data_abort(iss.value)?)),
        0b100101 => ("Data Abort taken without a change in Exception level", Some(decode_iss_data_abort(iss.value)?)),
        0b100110 => ("SP alignment fault exception", None),
        0b101000 => ("Trapped floating-point exception taken from AArch32 state", None),
        0b101100 => ("Trapped floating-point exception taken from AArch64 state", None),
        0b101111 => ("SError interrupt", None),
        0b110000 => ("Breakpoint exception from a lower Exception level", None),
        0b110001 => ("Breakpoint exception taken without a change in Exception level", None),
        0b110010 => ("Software Step exception from a lower Exception level", None),
        0b110011 => ("Software Step exception taken without a change in Exception level", None),
        0b110100 => ("Watchpoint exception from a lower Exception level", None),
        0b110101 => ("Watchpoint exception taken without a change in Exception level", None),
        0b111000 => ("BKPT instruction execution in AArch32 state", None),
        0b111100 => ("BRK instruction execution in AArch64 state", None),
        _ => return Err(DecodeError::InvalidEc { ec: ec.value }),
    };
    let iss = FieldInfo {
        decoded: iss_decoded,
        ..iss
    };
    let ec = ec.with_decoded(Decoded {
        description: Some(class.to_string()),
        fields: vec![],
    });
    Ok(Decoded {
        description: Some(class.to_string()),
        fields: vec![res0, iss2, ec, il, iss],
    })
}
<commit_msg>Describe ISV, and don't try to decode RES0 fields if it's false.<commit_after>// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use bit_field::BitField;
use std::fmt::{self, Debug, Display, Formatter};
use thiserror::Error;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct FieldInfo {
    pub name: &'static str,
    pub start: usize,
    pub width: usize,
    pub value: u64,
    pub decoded: Option<Decoded>,
}

impl FieldInfo {
    fn get(register: u64, name: &'static str, start: usize, end: usize) -> Self {
        let value = register.get_bits(start..end);
        Self {
            name,
            start,
            width: end - start,
            value,
            decoded: None,
        }
    }

    fn get_bit(register: u64, name: &'static str, bit: usize) -> Self {
        Self::get(register, name, bit, bit + 1)
    }

    fn with_decoded(self, decoded: Decoded) -> Self {
        Self {
            decoded: Some(decoded),
            ..self
        }
    }

    fn with_description(self, description: String) -> Self {
        self.with_decoded(Decoded {
            description: Some(description),
            fields: vec![],
        })
    }

    fn as_bit(&self) -> bool {
        assert!(self.width == 1);
        self.value == 1
    }

    /// Assuming this field has a width of exactly 1, describe it with the given function.
    ///
    /// Panics if `self.width != 1`.
    fn describe_bit<F>(self, describer: F) -> Self
    where
        F: FnOnce(bool) -> &'static str,
    {
        let bit = self.as_bit();
        let description = Some(describer(bit).to_string());
        self.with_decoded(Decoded {
            description,
            fields: vec![],
        })
    }
}

impl Display for FieldInfo {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        if self.width == 1 {
            write!(
                f,
                "{}: {}",
                self.name,
                if self.value == 1 { "true" } else { "false" }
            )
        } else {
            write!(
                f,
                "{}: {:#02$x} {1:#03$b}",
                self.name,
                self.value,
                (self.width + 3) / 4 + 2,
                self.width + 2
            )
        }
    }
}

#[derive(Debug, Error)]
pub enum DecodeError {
    #[error("Invalid ESR, res0 is {res0:#x}")]
    InvalidRes0 { res0: u64 },
    #[error("Invalid EC {ec:#x}")]
    InvalidEc { ec: u64 },
    #[error("Invalid DFSC {dfsc:#x}")]
    InvalidDfsc { dfsc: u64 },
    #[error("ISV was false but instruction syndrome bits were nonzero {is:#x}")]
    UnexpectedInstructionSyndrome { is: u64 },
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum SyndromeAccessSize {
    Byte = 0b00,
    Halfword = 0b01,
    Word = 0b10,
    Doubleword = 0b11,
}

impl Display for SyndromeAccessSize {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let s = match self {
            Self::Byte => "byte",
            Self::Halfword => "halfword",
            Self::Word => "word",
            Self::Doubleword => "doubleword",
        };
        write!(f, "{}", s)
    }
}

fn describe_isv(isv: bool) -> &'static str {
    if isv {
        "Valid instruction syndrome"
    } else {
        "No valid instruction syndrome"
    }
}

fn describe_sf(sf: bool) -> &'static str {
    if sf {
        "64-bit wide register"
    } else {
        "32-bit wide register"
    }
}

fn describe_ar(ar: bool) -> &'static str {
    if ar {
        "Acquire/release semantics"
    } else {
        "No acquire/release semantics"
    }
}

fn describe_fnv(fnv: bool) -> &'static str {
    if fnv {
        "FAR is not valid, it holds an unknown value"
    } else {
        "FAR is valid"
    }
}

fn describe_wnr(wnr: bool) -> &'static str {
    if wnr {
        "Abort caused by writing to memory"
    } else {
        "Abort caused by reading from memory"
    }
}

fn describe_dfsc(dfsc: u64) -> Result<&'static str, DecodeError> {
    let description = match dfsc {
        0b000000 => "Address size fault, level 0 of translation or translation table base register.",
        0b000001 => "Address size fault, level 1.",
        0b000010 => "Address size fault, level 2.",
        0b000011 => "Address size fault, level 3.",
        0b000100 => "Translation fault, level 0.",
        0b000101 => "Translation fault, level 1.",
        0b000110 => "Translation fault, level 2.",
        0b000111 => "Translation fault, level 3.",
        0b001001 => "Access flag fault, level 1.",
        0b001010 => "Access flag fault, level 2.",
        0b001011 => "Access flag fault, level 3.",
        0b001000 => "Access flag fault, level 0.",
        0b001100 => "Permission fault, level 0.",
        0b001101 => "Permission fault, level 1.",
        0b001110 => "Permission fault, level 2.",
        0b001111 => "Permission fault, level 3.",
        0b010000 => "Synchronous External abort, not on translation table walk or hardware update of translation table.",
        0b010001 => "Synchronous Tag Check Fault.",
        0b010011 => "Synchronous External abort on translation table walk or hardware update of translation table, level -1.",
        0b010100 => "Synchronous External abort on translation table walk or hardware update of translation table, level 0.",
        0b010101 => "Synchronous External abort on translation table walk or hardware update of translation table, level 1.",
        0b010110 => "Synchronous External abort on translation table walk or hardware update of translation table, level 2.",
        0b010111 => "Synchronous External abort on translation table walk or hardware update of translation table, level 3.",
        0b011000 => "Synchronous parity or ECC error on memory access, not on translation table walk.",
        0b011011 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level -1.",
        0b011100 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 0.",
        0b011101 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 1.",
        0b011110 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 2.",
        0b011111 => "Synchronous parity or ECC error on memory access on translation table walk or hardware update of translation table, level 3.",
        0b100001 => "Alignment fault.",
        0b101001 => "Address size fault, level -1.",
        0b101011 => "Translation fault, level -1.",
        0b110000 => "TLB conflict abort.",
        0b110001 => "Unsupported atomic hardware update fault.",
        0b110100 => "IMPLEMENTATION DEFINED fault (Lockdown).",
        0b110101 => "IMPLEMENTATION DEFINED fault (Unsupported Exclusive or Atomic access).",
        _ => return Err(DecodeError::InvalidDfsc { dfsc }),
    };
    Ok(description)
}

fn decode_iss_data_abort(iss: u64) -> Result<Decoded, DecodeError> {
    let isv = FieldInfo::get_bit(iss, "ISV", 24).describe_bit(describe_isv);

    let intruction_syndrome_fields = if isv.as_bit() {
        // These fields are part of the instruction syndrome, and are only valid if ISV is true.
        let sas = FieldInfo::get(iss, "SAS", 22, 24);
        let sas_value = match sas.value {
            0b00 => SyndromeAccessSize::Byte,
            0b01 => SyndromeAccessSize::Halfword,
            0b10 => SyndromeAccessSize::Word,
            0b11 => SyndromeAccessSize::Doubleword,
            _ => unreachable!(),
        };
        let sas = sas.with_decoded(Decoded {
            description: Some(sas_value.to_string()),
            fields: vec![],
        });
        let sse = FieldInfo::get_bit(iss, "SSE", 21);
        let srt = FieldInfo::get(iss, "SRT", 16, 21);
        let sf = FieldInfo::get_bit(iss, "SF", 15).describe_bit(describe_sf);
        let ar = FieldInfo::get_bit(iss, "AR", 14).describe_bit(describe_ar);
        vec![sas, sse, srt, sf, ar]
    } else {
        let res0 = FieldInfo::get(iss, "RES0", 14, 24);
        if res0.value != 0 {
            return Err(DecodeError::UnexpectedInstructionSyndrome { is: res0.value });
        }
        vec![res0]
    };

    let vncr = FieldInfo::get_bit(iss, "VNCR", 13);
    let fnv = FieldInfo::get_bit(iss, "FnV", 10).describe_bit(describe_fnv);
    let ea = FieldInfo::get_bit(iss, "EA", 9);
    let cm = FieldInfo::get_bit(iss, "CM", 8);
    let s1ptw = FieldInfo::get_bit(iss, "S1PTW", 7);
    let wnr = FieldInfo::get_bit(iss, "WnR", 6).describe_bit(describe_wnr);
    let dfsc = FieldInfo::get(iss, "DFSC", 0, 6);
    let dfsc_description = describe_dfsc(dfsc.value)?;
    let dfsc = dfsc.with_description(dfsc_description.to_string());

    let mut fields = vec![isv];
    fields.extend(intruction_syndrome_fields);
    fields.extend(vec![vncr, fnv, ea, cm, s1ptw, wnr, dfsc]);
    Ok(Decoded {
        description: None,
        fields,
    })
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Decoded {
    pub description: Option<String>,
    pub fields: Vec<FieldInfo>,
}

pub fn decode(esr: u64) -> Result<Decoded, DecodeError> {
    let res0 = FieldInfo::get(esr, "RES0", 37, 64);
    let iss2 = FieldInfo::get(esr, "ISS2", 32, 37);
    let ec = FieldInfo::get(esr, "EC", 26, 32);
    let il = FieldInfo::get_bit(esr, "IL", 25);
    let iss = FieldInfo::get(esr, "ISS", 0, 25);
    if res0.value != 0 {
        return Err(DecodeError::InvalidRes0 { res0: res0.value });
    }
    let (class, iss_decoded) = match ec.value {
        0b000000 => ("Unknown reason", None),
        0b000001 => ("Wrapped WF* instruction execution", None),
        0b000011 => ("Trapped MCR or MRC access with coproc=0b1111", None),
        0b000100 => ("Trapped MCRR or MRRC access with coproc=0b1111", None),
        0b000101 => ("Trapped MCR or MRC access with coproc=0b1110", None),
        0b000110 => ("Trapped LDC or STC access", None),
        0b000111 => ("Trapped access to SVE, Advanced SIMD or floating point", None),
        0b001010 => ("Trapped execution of an LD64B, ST64B, ST64BV, or ST64BV0 instruction", None),
        0b001100 => ("Trapped MRRC access with (coproc==0b1110)", None),
        0b001101 => ("Branch Target Exception", None),
        0b001110 => ("Illegal Execution state", None),
        0b010001 => ("SVC instruction execution in AArch32 state", None),
        0b010101 => ("SVC instruction execution in AArch64 state", None),
        0b011000 => ("Trapped MSR, MRS or System instruction execution in AArch64 state", None),
        0b011001 => ("Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, CPTR_EL2.TZ, or CPTR_EL3.EZ", None),
        0b011100 => ("Exception from a Pointer Authentication instruction authentication failure", None),
        0b100000 => ("Instruction Abort from a lower Exception level", None),
        0b100001 => ("Instruction Abort taken without a change in Exception level", None),
        0b100010 => ("PC alignment fault exception", None),
        0b100100 => ("Data Abort from a lower Exception level", Some(decode_iss_data_abort(iss.value)?)),
        0b100101 => ("Data Abort taken without a change in Exception level", Some(decode_iss_data_abort(iss.value)?)),
        0b100110 => ("SP alignment fault exception", None),
        0b101000 => ("Trapped floating-point exception taken from AArch32 state", None),
        0b101100 => ("Trapped floating-point exception taken from AArch64 state", None),
        0b101111 => ("SError interrupt", None),
        0b110000 => ("Breakpoint exception from a lower Exception level", None),
        0b110001 => ("Breakpoint exception taken without a change in Exception level", None),
        0b110010 => ("Software Step exception from a lower Exception level", None),
        0b110011 => ("Software Step exception taken without a change in Exception level", None),
        0b110100 => ("Watchpoint exception from a lower Exception level", None),
        0b110101 => ("Watchpoint exception taken without a change in Exception level", None),
        0b111000 => ("BKPT instruction execution in AArch32 state", None),
        0b111100 => ("BRK instruction execution in AArch64 state", None),
        _ => return Err(DecodeError::InvalidEc { ec: ec.value }),
    };
    let iss = FieldInfo {
        decoded: iss_decoded,
        ..iss
    };
    let ec = ec.with_decoded(Decoded {
        description: Some(class.to_string()),
        fields: vec![],
    });
    Ok(Decoded {
        description: Some(class.to_string()),
        fields: vec![res0, iss2, ec, il, iss],
    })
}
<|endoftext|>


<commit_before>//! A library providing a generic connection pool.
#![feature(unsafe_destructor, core, std_misc)]
#![warn(missing_docs)]
#![allow(missing_copy_implementations)]
#![doc(html_root_url="https://sfackler.github.io/doc")]

#[macro_use]
extern crate log;
extern crate time;

use std::collections::RingBuf;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, Condvar};
use std::time::Duration;
use time::SteadyTime;

pub use config::{Config, ConfigError};

use task::ScheduledThreadPool;

mod config;
mod task;

/// A trait which provides connection-specific functionality.
pub trait ConnectionManager: Send+Sync {
    type Connection: Send;
    type Error;

    /// Attempts to create a new connection.
    fn connect(&self) -> Result<Self::Connection, Self::Error>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut Self::Connection) -> bool;
}

/// A trait which handles errors reported by the `ConnectionManager`.
pub trait ErrorHandler<E>: Send+Sync {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

/// An `ErrorHandler` which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NoopErrorHandler;

impl<E> ErrorHandler<E> for NoopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// An `ErrorHandler` which logs at the error level.
#[derive(Copy, Clone, Debug)]
pub struct LoggingErrorHandler;

impl<E> ErrorHandler<E> for LoggingErrorHandler where E: fmt::Debug {
    fn handle_error(&self, error: E) {
        error!("{:?}", error);
    }
}

struct PoolInternals<C> {
    conns: RingBuf<C>,
    num_conns: u32,
}

struct SharedPool<M> where M: ConnectionManager {
    config: Config,
    manager: M,
    error_handler: Box<ErrorHandler<<M as ConnectionManager>::Error>>,
    internals: Mutex<PoolInternals<<M as ConnectionManager>::Connection>>,
    cond: Condvar,
    thread_pool: ScheduledThreadPool,
}

fn add_connection<M>(delay: Duration, shared: &Arc<SharedPool<M>>) where M: ConnectionManager {
    let new_shared = shared.clone();
    shared.thread_pool.run_after(delay, move || {
        let shared = new_shared;
        match shared.manager.connect() {
            Ok(conn) => {
                let mut internals = shared.internals.lock().unwrap();
                internals.conns.push_back(conn);
                internals.num_conns += 1;
                shared.cond.notify_one();
            }
            Err(err) => {
                shared.error_handler.handle_error(err);
                add_connection(Duration::seconds(1), &shared);
            },
        }
    });
}

/// A generic connection pool.
pub struct Pool<M> where M: ConnectionManager {
    shared: Arc<SharedPool<M>>,
}

#[unsafe_destructor]
impl<M> Drop for Pool<M> where M: ConnectionManager {
    fn drop(&mut self) {
        self.shared.thread_pool.clear();
    }
}

impl<M> fmt::Debug for Pool<M> where M: ConnectionManager + fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Pool {{ idle_connections: {}, config: {:?}, manager: {:?} }}",
               self.shared.internals.lock().unwrap().conns.len(),
               self.shared.config,
               self.shared.manager)
    }
}

/// An error returned by `Pool::new` if it fails to initialize connections.
#[derive(Debug)]
pub struct InitializationError;

impl fmt::Display for InitializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for InitializationError {
    fn description(&self) -> &str {
        "Unable to initialize connections"
    }
}

/// An error returned by `Pool::get` if it times out without retrieving a connection.
#[derive(Debug)]
pub struct GetTimeout;

impl fmt::Display for GetTimeout {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for GetTimeout {
    fn description(&self) -> &str {
        "Timed out while waiting for a connection"
    }
}

impl<M> Pool<M> where M: ConnectionManager {
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value if `initialization_fail_fast` is set to true in
    /// the configuration and the pool is unable to open all of its
    /// connections.
    ///
    /// # Panics
    ///
    /// Panics if `config` is not valid.
    pub fn new(config: Config,
               manager: M,
               error_handler: Box<ErrorHandler<<M as ConnectionManager>::Error>>)
               -> Result<Pool<M>, InitializationError> {
        config.validate().unwrap();

        let internals = PoolInternals {
            conns: RingBuf::new(),
            num_conns: 0,
        };

        let shared = Arc::new(SharedPool {
            config: config,
            manager: manager,
            error_handler: error_handler,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
            thread_pool: ScheduledThreadPool::new(config.helper_threads as usize),
        });

        for _ in 0..config.pool_size {
            add_connection(Duration::zero(), &shared);
        }

        if shared.config.initialization_fail_fast {
            let internals = shared.internals.lock().unwrap();
            let initialized = shared.cond.wait_timeout_with(internals,
                                                            shared.config.connection_timeout,
                                                            |internals| {
                internals.unwrap().num_conns == shared.config.pool_size
            }).unwrap().1;

            if !initialized {
                return Err(InitializationError);
            }
        }

        Ok(Pool {
            shared: shared,
        })
    }

    /// Retrieves a connection from the pool.
    ///
    /// Waits for at most `Config::connection_timeout` before returning an
    /// error.
    pub fn get<'a>(&'a self) -> Result<PooledConnection<'a, M>, GetTimeout> {
        let end = SteadyTime::now() + self.shared.config.connection_timeout;
        let mut internals = self.shared.internals.lock().unwrap();

        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.shared.config.test_on_check_out {
                        if let Err(e) = self.shared.manager.is_valid(&mut conn) {
                            self.shared.error_handler.handle_error(e);
                            internals = self.shared.internals.lock().unwrap();
                            internals.num_conns -= 1;
                            add_connection(Duration::zero(), &self.shared);
                            continue
                        }
                    }

                    return Ok(PooledConnection {
                        pool: self,
                        conn: Some(conn),
                    })
                }
                None => {
                    let now = SteadyTime::now();
                    let (new_internals, no_timeout) =
                        self.shared.cond.wait_timeout(internals, end - now).unwrap();
                    internals = new_internals;

                    if !no_timeout {
                        return Err(GetTimeout);
                    }
                }
            }
        }
    }

    fn put_back(&self, mut conn: <M as ConnectionManager>::Connection) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.shared.manager.has_broken(&mut conn);

        let mut internals = self.shared.internals.lock().unwrap();
        if broken {
            internals.num_conns -= 1;
        } else {
            internals.conns.push_back(conn);
            self.shared.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<'a, M> where M: ConnectionManager {
    pool: &'a Pool<M>,
    conn: Option<<M as ConnectionManager>::Connection>,
}

impl<'a, M> fmt::Debug for PooledConnection<'a, M>
        where M: ConnectionManager + fmt::Debug,
        <M as ConnectionManager>::Connection: fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "PooledConnection {{ pool: {:?}, connection: {:?} }}", self.pool,
               self.conn.as_ref().unwrap())
    }
}

#[unsafe_destructor]
impl<'a, M> Drop for PooledConnection<'a, M> where M: ConnectionManager {
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<'a, M> Deref for PooledConnection<'a, M> where M: ConnectionManager {
    type Target = <M as ConnectionManager>::Connection;

    fn deref(&self) -> &<M as ConnectionManager>::Connection {
        self.conn.as_ref().unwrap()
    }
}

impl<'a, M> DerefMut for PooledConnection<'a, M> where M: ConnectionManager {
    fn deref_mut(&mut self) -> &mut <M as ConnectionManager>::Connection {
        self.conn.as_mut().unwrap()
    }
}
<commit_msg>Remove unneeded lint modifier<commit_after>//! A library providing a generic connection pool.
#![feature(unsafe_destructor, core, std_misc)]
#![warn(missing_docs)]
#![doc(html_root_url="https://sfackler.github.io/doc")]

#[macro_use]
extern crate log;
extern crate time;

use std::collections::RingBuf;
use std::error::Error;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, Condvar};
use std::time::Duration;
use time::SteadyTime;

pub use config::{Config, ConfigError};

use task::ScheduledThreadPool;

mod config;
mod task;

/// A trait which provides connection-specific functionality.
pub trait ConnectionManager: Send+Sync {
    type Connection: Send;
    type Error;

    /// Attempts to create a new connection.
    fn connect(&self) -> Result<Self::Connection, Self::Error>;

    /// Determines if the connection is still connected to the database.
    ///
    /// A standard implementation would check if a simple query like `SELECT 1`
    /// succeeds.
    fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error>;

    /// *Quickly* determines if the connection is no longer usable.
    ///
    /// This will be called synchronously every time a connection is returned
    /// to the pool, so it should *not* block. If it returns `true`, the
    /// connection will be discarded.
    ///
    /// For example, an implementation might check if the underlying TCP socket
    /// has disconnected. Implementations that do not support this kind of
    /// fast health check may simply return `false`.
    fn has_broken(&self, conn: &mut Self::Connection) -> bool;
}

/// A trait which handles errors reported by the `ConnectionManager`.
pub trait ErrorHandler<E>: Send+Sync {
    /// Handles an error.
    fn handle_error(&self, error: E);
}

/// An `ErrorHandler` which does nothing.
#[derive(Copy, Clone, Debug)]
pub struct NoopErrorHandler;

impl<E> ErrorHandler<E> for NoopErrorHandler {
    fn handle_error(&self, _: E) {}
}

/// An `ErrorHandler` which logs at the error level.
#[derive(Copy, Clone, Debug)]
pub struct LoggingErrorHandler;

impl<E> ErrorHandler<E> for LoggingErrorHandler where E: fmt::Debug {
    fn handle_error(&self, error: E) {
        error!("{:?}", error);
    }
}

struct PoolInternals<C> {
    conns: RingBuf<C>,
    num_conns: u32,
}

struct SharedPool<M> where M: ConnectionManager {
    config: Config,
    manager: M,
    error_handler: Box<ErrorHandler<<M as ConnectionManager>::Error>>,
    internals: Mutex<PoolInternals<<M as ConnectionManager>::Connection>>,
    cond: Condvar,
    thread_pool: ScheduledThreadPool,
}

fn add_connection<M>(delay: Duration, shared: &Arc<SharedPool<M>>) where M: ConnectionManager {
    let new_shared = shared.clone();
    shared.thread_pool.run_after(delay, move || {
        let shared = new_shared;
        match shared.manager.connect() {
            Ok(conn) => {
                let mut internals = shared.internals.lock().unwrap();
                internals.conns.push_back(conn);
                internals.num_conns += 1;
                shared.cond.notify_one();
            }
            Err(err) => {
                shared.error_handler.handle_error(err);
                add_connection(Duration::seconds(1), &shared);
            },
        }
    });
}

/// A generic connection pool.
pub struct Pool<M> where M: ConnectionManager {
    shared: Arc<SharedPool<M>>,
}

#[unsafe_destructor]
impl<M> Drop for Pool<M> where M: ConnectionManager {
    fn drop(&mut self) {
        self.shared.thread_pool.clear();
    }
}

impl<M> fmt::Debug for Pool<M> where M: ConnectionManager + fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Pool {{ idle_connections: {}, config: {:?}, manager: {:?} }}",
               self.shared.internals.lock().unwrap().conns.len(),
               self.shared.config,
               self.shared.manager)
    }
}

/// An error returned by `Pool::new` if it fails to initialize connections.
#[derive(Debug)]
pub struct InitializationError;

impl fmt::Display for InitializationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for InitializationError {
    fn description(&self) -> &str {
        "Unable to initialize connections"
    }
}

/// An error returned by `Pool::get` if it times out without retrieving a connection.
#[derive(Debug)]
pub struct GetTimeout;

impl fmt::Display for GetTimeout {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for GetTimeout {
    fn description(&self) -> &str {
        "Timed out while waiting for a connection"
    }
}

impl<M> Pool<M> where M: ConnectionManager {
    /// Creates a new connection pool.
    ///
    /// Returns an `Err` value if `initialization_fail_fast` is set to true in
    /// the configuration and the pool is unable to open all of its
    /// connections.
    ///
    /// # Panics
    ///
    /// Panics if `config` is not valid.
    pub fn new(config: Config,
               manager: M,
               error_handler: Box<ErrorHandler<<M as ConnectionManager>::Error>>)
               -> Result<Pool<M>, InitializationError> {
        config.validate().unwrap();

        let internals = PoolInternals {
            conns: RingBuf::new(),
            num_conns: 0,
        };

        let shared = Arc::new(SharedPool {
            config: config,
            manager: manager,
            error_handler: error_handler,
            internals: Mutex::new(internals),
            cond: Condvar::new(),
            thread_pool: ScheduledThreadPool::new(config.helper_threads as usize),
        });

        for _ in 0..config.pool_size {
            add_connection(Duration::zero(), &shared);
        }

        if shared.config.initialization_fail_fast {
            let internals = shared.internals.lock().unwrap();
            let initialized = shared.cond.wait_timeout_with(internals,
                                                            shared.config.connection_timeout,
                                                            |internals| {
                internals.unwrap().num_conns == shared.config.pool_size
            }).unwrap().1;

            if !initialized {
                return Err(InitializationError);
            }
        }

        Ok(Pool {
            shared: shared,
        })
    }

    /// Retrieves a connection from the pool.
    ///
    /// Waits for at most `Config::connection_timeout` before returning an
    /// error.
    pub fn get<'a>(&'a self) -> Result<PooledConnection<'a, M>, GetTimeout> {
        let end = SteadyTime::now() + self.shared.config.connection_timeout;
        let mut internals = self.shared.internals.lock().unwrap();

        loop {
            match internals.conns.pop_front() {
                Some(mut conn) => {
                    drop(internals);

                    if self.shared.config.test_on_check_out {
                        if let Err(e) = self.shared.manager.is_valid(&mut conn) {
                            self.shared.error_handler.handle_error(e);
                            internals = self.shared.internals.lock().unwrap();
                            internals.num_conns -= 1;
                            add_connection(Duration::zero(), &self.shared);
                            continue
                        }
                    }

                    return Ok(PooledConnection {
                        pool: self,
                        conn: Some(conn),
                    })
                }
                None => {
                    let now = SteadyTime::now();
                    let (new_internals, no_timeout) =
                        self.shared.cond.wait_timeout(internals, end - now).unwrap();
                    internals = new_internals;

                    if !no_timeout {
                        return Err(GetTimeout);
                    }
                }
            }
        }
    }

    fn put_back(&self, mut conn: <M as ConnectionManager>::Connection) {
        // This is specified to be fast, but call it before locking anyways
        let broken = self.shared.manager.has_broken(&mut conn);

        let mut internals = self.shared.internals.lock().unwrap();
        if broken {
            internals.num_conns -= 1;
        } else {
            internals.conns.push_back(conn);
            self.shared.cond.notify_one();
        }
    }
}

/// A smart pointer wrapping a connection.
pub struct PooledConnection<'a, M> where M: ConnectionManager {
    pool: &'a Pool<M>,
    conn: Option<<M as ConnectionManager>::Connection>,
}

impl<'a, M> fmt::Debug for PooledConnection<'a, M>
        where M: ConnectionManager + fmt::Debug,
        <M as ConnectionManager>::Connection: fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "PooledConnection {{ pool: {:?}, connection: {:?} }}", self.pool,
               self.conn.as_ref().unwrap())
    }
}

#[unsafe_destructor]
impl<'a, M> Drop for PooledConnection<'a, M> where M: ConnectionManager {
    fn drop(&mut self) {
        self.pool.put_back(self.conn.take().unwrap());
    }
}

impl<'a, M> Deref for PooledConnection<'a, M> where M: ConnectionManager {
    type Target = <M as ConnectionManager>::Connection;

    fn deref(&self) -> &<M as ConnectionManager>::Connection {
        self.conn.as_ref().unwrap()
    }
}

impl<'a, M> DerefMut for PooledConnection<'a, M> where M: ConnectionManager {
    fn deref_mut(&mut self) -> &mut <M as ConnectionManager>::Connection {
        self.conn.as_mut().unwrap()
    }
}
<|endoftext|>


<commit_before>// Regex matcher
//
// Supported expressions
// a      - character
// .      - wildcard
// *      - match none or more
// +      - match one or more
// ?      - match none or one
// \      - escape
// [0-9]  - numeral
// [a-z]  - lowercase
// [A-Z]  - uppercase
// [...]  - any of
// [^...] - none of
// (...)  - subexpression

mod expr;
mod tokenizer;
pub mod regex;

#[test]
fn it_can_recognize_phone_numbers() {
    use regex::SatisfiesRegex;
    let phone_regex = "(1[-.]?)?\\(?([0-9][0-9][0-9])\\)?[-. ]?([0-9][0-9][0-9])[-. ]?([0-9][0-9][0-9][0-9])";

    assert!(phone_regex.is_satisfied_by("(623) 456-8293".to_string()));
    assert!(phone_regex.is_satisfied_by("623.456.8293".to_string()));
    assert!(phone_regex.is_satisfied_by("(623).456.8293".to_string()));
    assert!(phone_regex.is_satisfied_by("623-456-8293".to_string()));

    assert!(phone_regex.is_satisfied_by("1-623-456-8293".to_string()));
    assert!(phone_regex.is_satisfied_by("1.623.456.8293".to_string()));
    assert!(phone_regex.is_satisfied_by("16234568293".to_string()));
    assert!(phone_regex.is_satisfied_by("6234568293".to_string()));

    assert!(phone_regex.is_not_satisfied_by("116234568293".to_string()));
}
<commit_msg>Add some more phone number cases<commit_after>// Regex matcher
//
// Supported expressions
// a      - character
// .      - wildcard
// *      - match none or more
// +      - match one or more
// ?      - match none or one
// \      - escape
// [0-9]  - numeral
// [a-z]  - lowercase
// [A-Z]  - uppercase
// [...]  - any of
// [^...] - none of
// (...)  - subexpression

mod expr;
mod tokenizer;
pub mod regex;

#[test]
fn it_can_recognize_phone_numbers() {
    use regex::SatisfiesRegex;
    let phone_regex = "(1[-.]?)?\\(?([0-9][0-9][0-9])\\)?[-. ]?([0-9][0-9][0-9])[-. ]?([0-9][0-9][0-9][0-9])";

    assert!(phone_regex.is_satisfied_by("(623) 456-8293".to_string()));
    assert!(phone_regex.is_satisfied_by("623.456.8293".to_string()));
    assert!(phone_regex.is_satisfied_by("(623).456.8293".to_string()));
    assert!(phone_regex.is_satisfied_by("623-456-8293".to_string()));

    assert!(phone_regex.is_satisfied_by("1-623-456-8293".to_string()));
    assert!(phone_regex.is_satisfied_by("1.623.456.8293".to_string()));
    assert!(phone_regex.is_satisfied_by("16234568293".to_string()));
    assert!(phone_regex.is_satisfied_by("6234568293".to_string()));

    assert!(phone_regex.is_not_satisfied_by("116234568293".to_string()));
    assert!(phone_regex.is_not_satisfied_by("1-6-23-456-8293".to_string()));
    assert!(phone_regex.is_not_satisfied_by("16-23-456-8293".to_string()));
    assert!(phone_regex.is_not_satisfied_by("1-800-GEICO".to_string()));

    // These are supported, but probably shouldn't be:
    assert!(phone_regex.is_satisfied_by("1-(800-2222222".to_string()));
    assert!(phone_regex.is_satisfied_by("1-800)-222 2222".to_string()));
}
<|endoftext|>


<commit_before>#![feature(collections, core, custom_derive, plugin, unboxed_closures)]
#![plugin(num_macros)]
#![allow(dead_code)]

extern crate byteorder;
extern crate num;

pub mod filter;
pub mod midi;
pub mod music;
pub mod synthesizer;
pub mod wave;
pub mod writer;

<commit_msg>Remove unused feature<commit_after>#![feature(core, custom_derive, plugin, unboxed_closures)]
#![plugin(num_macros)]
#![allow(dead_code)]

extern crate byteorder;
extern crate num;

pub mod filter;
pub mod midi;
pub mod music;
pub mod synthesizer;
pub mod wave;
pub mod writer;

<|endoftext|>


<commit_before>#![crate_id="mysql"]
#![comment="Mysql client library writen in rust"]
#![license="MIT"]
#![crate_type="rlib"]
#![crate_type="dylib"]

#![feature(unsafe_destructor)]
#![feature(phase)]

#![allow(dead_code)]
#![feature(macro_rules)]

#[cfg(test)]
extern crate test;
extern crate sync;
extern crate core;
extern crate debug;
extern crate time;

#[phase(plugin)]
extern crate lazy_static;

mod scramble;
pub mod consts;
pub mod error;
mod packet;
mod io;
pub mod value;
pub mod conn;
<commit_msg>Update for rust nightly<commit_after>#![crate_name="mysql"]
#![comment="Mysql client library writen in rust"]
#![license="MIT"]
#![crate_type="rlib"]
#![crate_type="dylib"]

#![feature(unsafe_destructor)]
#![feature(phase)]

#![allow(dead_code)]
#![feature(macro_rules)]

#[cfg(test)]
extern crate test;
extern crate sync;
extern crate core;
extern crate debug;
extern crate time;

#[phase(plugin)]
extern crate lazy_static;

mod scramble;
pub mod consts;
pub mod error;
mod packet;
mod io;
pub mod value;
pub mod conn;
<|endoftext|>