<commit_before>use std::collections::BTreeMap;
use std::hash::Hasher;
use std::iter;
use std::str::{CharIndices, SplitWhitespace};
use std::ops;

use itertools::{GroupBy, Itertools};

use Query::*;
use super::*;
use util::*;

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to postings.
#[derive(Debug)]
pub struct InvertedIndex {
    // Maps terms to their postings
    index: BTreeMap<String, PostingsMap>,
    // Maps doc ids to their docs
    docs: BTreeMap<String, Document>,
}

impl InvertedIndex {
    /// Constructs a new, empty 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 previous_version = self.docs.insert(doc.id.clone(), doc.clone());
        if let Some(previous_version) = previous_version {
            let previous_analyzed = analyze_doc(previous_version.content());
            for (ngram, _) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&doc.id);
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        let analyzed = analyze_doc(doc.content());
        for (ngram, position) in analyzed {
            self.index
                .entry(ngram)
                .or_insert_with(BTreeMap::new)
                .entry(doc.id.clone())
                .or_insert_with(Vec::new)
                .search_coalesce(0, position);
        }
    }

    /// Performs a search to the specification of the given query
    pub fn query(&self, query: &Query) -> Vec<SearchResult> {
        let postings = self.query_rec(query);
        self.compute_results(postings)
    }

    /// A helper method for performing a Match query
    pub fn search(&self, query: &str) -> Vec<SearchResult> {
        self.query(&Match(query))
    }

    fn postings(&self, query: &str) -> PostingsMap {
        analyze_query(query).unique().flat_map(|word| self.index.get(&word)).merge_postings()
    }

    fn phrase(&self, phrase: &str) -> PostingsMap {
        let terms: Vec<_> = analyze_query(phrase).collect();
        let postings: Vec<_> = terms.windows(2)
                                    .map(|adjacent_terms| {
                                        let term0 = &adjacent_terms[0];
                                        let term1 = &adjacent_terms[1];
                                        if let (Some(posting0), Some(posting1)) =
                                               (self.index.get(term0), self.index.get(term1)) {
                                            posting0.intersect_positionally(posting1)
                                        } else {
                                            PostingsMap::new()
                                        }
                                    })
                                    .collect();
        postings.intersect_postings()
    }

    fn query_rec(&self, query: &Query) -> PostingsMap {
        match *query {
            Match(query) => self.postings(query),
            And(queries) => {
                let postings: Vec<_> = queries.iter().map(|q| self.query_rec(q)).collect();
                postings.intersect_postings()
            }
            Or(queries) => queries.into_iter().map(|q| self.query_rec(q)).merge_postings(),
            Phrase(phrase) => self.phrase(phrase),
        }
    }

    fn compute_results(&self, postings: PostingsMap) -> Vec<SearchResult> {
        let mut results: Vec<_> = postings.into_iter()
                                          .map(|(doc_id, positions)| {
                                              SearchResult::new(&self.docs[&doc_id], positions)
                                          })
                                          .collect();
        results.sort_by(|result1, result2| result2.score.partial_cmp(&result1.score).unwrap());
        results
    }
}

type Tokens<'a> = iter::FlatMap<
                iter::Enumerate<
                    iter::Filter<
                        GroupBy<bool, CharIndices<'a>, fn(&(usize, char)) -> bool>,
                        fn(&(bool, Vec<(usize, char)>)) -> bool>>,
                iter::Map<ops::Range<usize>, Ngrams>,
                fn((usize, (bool, Vec<(usize, char)>))) -> iter::Map<ops::Range<usize>, Ngrams>>;

type QueryTokens<'a> = iter::Map<SplitWhitespace<'a>, fn(&str) -> String>;

fn analyze_query(query: &str) -> QueryTokens {
    query.split_whitespace().map(str::to_lowercase)
}

fn analyze_doc(doc: &str) -> Tokens {
    doc.char_indices()
       .group_by(is_whitespace as fn(&(usize, char)) -> bool)
       .filter(not_whitespace as fn(&(bool, Vec<(usize, char)>)) -> bool)
       .enumerate()
       .flat_map(ngrams)
}

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

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

impl Fn<(usize,)> for Ngrams {
    extern "rust-call" fn call(&self, (to,): (usize,)) -> (String, Position) {
        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, Position::new((start, finish), self.position))
    }
}

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

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

#[cfg(test)]
mod test {
    use super::super::*;
    use Query::{And, Match, Or};
    use std::collections::BTreeMap;

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

    }

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

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

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

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

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

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

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

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

    #[test]
    fn test_and() {
        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");
        let doc3 = Document::new("3", "what did you do yesterday");
        index.index(doc1.clone());
        index.index(doc2.clone());
        index.index(doc3.clone());
        let search_results = index.query(&And(&[Match("today"), Match("you")]));
        let expected: BTreeMap<_, _> = [(doc2,
                                         vec![Position::new((9, 12), 2),
                                              Position::new((13, 18), 3)])]
                                           .iter()
                                           .cloned()
                                           .collect();
        assert_eq!(search_results.len(), expected.len());
        for search_result in &search_results {
            assert_eq!(&search_result.positions,
                       &expected[search_result.doc])
        }
    }

    #[test]
    fn test_and_or() {
        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");
        let doc3 = Document::new("3", "what did you do yesterday");
        index.index(doc1.clone());
        index.index(doc2.clone());
        index.index(doc3.clone());
        let search_results = index.query(&Or(&[Match("you"),
                                               And(&[Match("today"), Match("you")])]));
        let expected: BTreeMap<_, _> = [(doc2,
                                         vec![Position::new((9, 12), 2),
                                              Position::new((13, 18), 3)]),
                                        (doc3, vec![Position::new((9, 12), 2)])]
                                           .iter()
                                           .cloned()
                                           .collect();
        assert_eq!(search_results.len(), expected.len());
        for search_result in &search_results {
            assert_eq!(&search_result.positions,
                       &expected[search_result.doc])
        }
    }

    // TODO(tjk): Add more phrase query tests
    #[test]
    fn test_phrase() {
        let mut index = InvertedIndex::new();
        let doc1 = Document::new("1", "learn to program in rust today");
        index.index(doc1.clone());
        println!("{:?}", index.phrase("learn to program"));
        println!("{:?}", index.phrase("learn to pro"));
    }

    #[test]
    fn test_phrase2() {
        let mut index = InvertedIndex::new();
        let doc1 = Document::new("1", "is is is");
        index.index(doc1.clone());
        println!("{:?}", index.phrase("i i"));
    }
}
<commit_msg>Add phrase query tests<commit_after>use std::collections::BTreeMap;
use std::hash::Hasher;
use std::iter;
use std::str::{CharIndices, SplitWhitespace};
use std::ops;

use itertools::{GroupBy, Itertools};

use Query::*;
use super::*;
use util::*;

/// A basic implementation of an `Index`, the inverted index is a data structure that maps
/// from words to postings.
#[derive(Debug)]
pub struct InvertedIndex {
    // Maps terms to their postings
    index: BTreeMap<String, PostingsMap>,
    // Maps doc ids to their docs
    docs: BTreeMap<String, Document>,
}

impl InvertedIndex {
    /// Constructs a new, empty 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 previous_version = self.docs.insert(doc.id.clone(), doc.clone());
        if let Some(previous_version) = previous_version {
            let previous_analyzed = analyze_doc(previous_version.content());
            for (ngram, _) in previous_analyzed {
                let is_empty = {
                    let docs_for_ngram = self.index.get_mut(&ngram).unwrap();
                    docs_for_ngram.remove(&doc.id);
                    docs_for_ngram.is_empty()
                };
                if is_empty {
                    self.index.remove(&ngram);
                }
            }
        }

        let analyzed = analyze_doc(doc.content());
        for (ngram, position) in analyzed {
            self.index
                .entry(ngram)
                .or_insert_with(BTreeMap::new)
                .entry(doc.id.clone())
                .or_insert_with(Vec::new)
                .search_coalesce(0, position);
        }
    }

    /// Performs a search to the specification of the given query
    pub fn query(&self, query: &Query) -> Vec<SearchResult> {
        let postings = self.query_rec(query);
        self.compute_results(postings)
    }

    /// A helper method for performing a Match query
    pub fn search(&self, query: &str) -> Vec<SearchResult> {
        self.query(&Match(query))
    }

    fn postings(&self, query: &str) -> PostingsMap {
        analyze_query(query).unique().flat_map(|word| self.index.get(&word)).merge_postings()
    }

    fn phrase(&self, phrase: &str) -> PostingsMap {
        let terms: Vec<_> = analyze_query(phrase).collect();
        let postings: Vec<_> = terms.windows(2)
                                    .map(|adjacent_terms| {
                                        let term0 = &adjacent_terms[0];
                                        let term1 = &adjacent_terms[1];
                                        if let (Some(posting0), Some(posting1)) =
                                               (self.index.get(term0), self.index.get(term1)) {
                                            posting0.intersect_positionally(posting1)
                                        } else {
                                            PostingsMap::new()
                                        }
                                    })
                                    .collect();
        postings.intersect_postings()
    }

    fn query_rec(&self, query: &Query) -> PostingsMap {
        match *query {
            Match(query) => self.postings(query),
            And(queries) => {
                let postings: Vec<_> = queries.iter().map(|q| self.query_rec(q)).collect();
                postings.intersect_postings()
            }
            Or(queries) => queries.into_iter().map(|q| self.query_rec(q)).merge_postings(),
            Phrase(phrase) => self.phrase(phrase),
        }
    }

    fn compute_results(&self, postings: PostingsMap) -> Vec<SearchResult> {
        let mut results: Vec<_> = postings.into_iter()
                                          .map(|(doc_id, positions)| {
                                              SearchResult::new(&self.docs[&doc_id], positions)
                                          })
                                          .collect();
        results.sort_by(|result1, result2| result2.score.partial_cmp(&result1.score).unwrap());
        results
    }
}

type Tokens<'a> = iter::FlatMap<
                iter::Enumerate<
                    iter::Filter<
                        GroupBy<bool, CharIndices<'a>, fn(&(usize, char)) -> bool>,
                        fn(&(bool, Vec<(usize, char)>)) -> bool>>,
                iter::Map<ops::Range<usize>, Ngrams>,
                fn((usize, (bool, Vec<(usize, char)>))) -> iter::Map<ops::Range<usize>, Ngrams>>;

type QueryTokens<'a> = iter::Map<SplitWhitespace<'a>, fn(&str) -> String>;

fn analyze_query(query: &str) -> QueryTokens {
    query.split_whitespace().map(str::to_lowercase)
}

fn analyze_doc(doc: &str) -> Tokens {
    doc.char_indices()
       .group_by(is_whitespace as fn(&(usize, char)) -> bool)
       .filter(not_whitespace as fn(&(bool, Vec<(usize, char)>)) -> bool)
       .enumerate()
       .flat_map(ngrams)
}

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

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

impl Fn<(usize,)> for Ngrams {
    extern "rust-call" fn call(&self, (to,): (usize,)) -> (String, Position) {
        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, Position::new((start, finish), self.position))
    }
}

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

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

#[cfg(test)]
mod test {
    use Query::*;
    use Document;
    use InvertedIndex;
    use Position;
    use SearchResult;
    use std::collections::BTreeMap;

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

    }

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

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

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

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

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

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

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

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

    #[test]
    fn test_and() {
        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");
        let doc3 = Document::new("3", "what did you do yesterday");
        index.index(doc1.clone());
        index.index(doc2.clone());
        index.index(doc3.clone());
        let search_results = index.query(&And(&[Match("today"), Match("you")]));
        let expected: BTreeMap<_, _> = [(doc2,
                                         vec![Position::new((9, 12), 2),
                                              Position::new((13, 18), 3)])]
                                           .iter()
                                           .cloned()
                                           .collect();
        assert_eq!(search_results.len(), expected.len());
        for search_result in &search_results {
            assert_eq!(&search_result.positions,
                       &expected[search_result.doc])
        }
    }

    #[test]
    fn test_and_or() {
        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");
        let doc3 = Document::new("3", "what did you do yesterday");
        index.index(doc1.clone());
        index.index(doc2.clone());
        index.index(doc3.clone());
        let search_results = index.query(&Or(&[Match("you"),
                                               And(&[Match("today"), Match("you")])]));
        let expected: BTreeMap<_, _> = [(doc2,
                                         vec![Position::new((9, 12), 2),
                                              Position::new((13, 18), 3)]),
                                        (doc3, vec![Position::new((9, 12), 2)])]
                                           .iter()
                                           .cloned()
                                           .collect();
        assert_eq!(search_results.len(), expected.len());
        for search_result in &search_results {
            assert_eq!(&search_result.positions,
                       &expected[search_result.doc])
        }
    }

    #[test]
    fn test_phrase() {
        let mut index = InvertedIndex::new();
        let doc1 = Document::new("1", "learn to program in rust today");
        index.index(doc1.clone());
        let search_results = index.query(&Phrase("learn to program"));
        let expected: BTreeMap<_, _> = [(doc1.clone(), vec![Position::new((0, 5), 0),
                                                    Position::new((6, 8), 1),
                                                    Position::new((9, 16), 2)])]
                                            .iter().cloned().collect();
        assert_eq!(search_results.len(), expected.len());
        for search_result in &search_results {
            assert_eq!(&search_result.positions, &expected[search_result.doc]);
        }
        let search_results = index.query(&Phrase("lear t pro"));
        let expected: BTreeMap<_, _> = [(doc1, vec![Position::new((0, 4), 0),
                                                    Position::new((6, 7), 1),
                                                    Position::new((9, 12), 2)])]
                                            .iter().cloned().collect();
        assert_eq!(search_results.len(), expected.len());
        for search_result in &search_results {
            assert_eq!(&search_result.positions, &expected[search_result.doc]);
        }
    }

    #[test]
    fn test_phrase2() {
        let mut index = InvertedIndex::new();
        let doc1 = Document::new("1", "is is is");
        index.index(doc1.clone());
        let expected: BTreeMap<_, _> = [(doc1.clone(), vec![Position::new((0, 1), 0),
                                                            Position::new((3, 4), 1),
                                                            Position::new((6, 7), 2)])]
                                            .iter().cloned().collect();
        let search_results = index.query(&Phrase("i i"));
        assert_eq!(search_results.len(), expected.len());
        for search_result in &search_results {
            assert_eq!(&search_result.positions, &expected[search_result.doc]);
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use ast::*;

struct Environment {
    symbol_tables: Vec<HashMap<String, i64>>
}

impl Environment {
    fn new() -> Environment {
        Environment {
            symbol_tables: Vec::new()
        }
    }

    fn start_scope(&mut self) {
        self.symbol_tables.push(HashMap::new());
    }

    fn end_scope(&mut self) {
        self.symbol_tables.pop();
    }

    fn declare(&mut self, variable: &Variable, value: i64) {
        match *variable {
            Variable::Identifier(ref binding, ref id)
            | Variable::IdentifierWithType(ref binding, ref id, _) => {
                // TODO: binding
                self.symbol_tables.last_mut().unwrap().insert(id.clone(), value);
            }
        };
    }

    fn set(&mut self, identifier: &String, value: i64) {
        for table in self.symbol_tables.iter_mut().rev() {
            // TODO: Entry API
            if table.contains_key(identifier) {
                table.insert(identifier.clone(), value);
                return;
            }
        }
        panic!(format!("reference error: '{}' was not declared", identifier));
    }

    fn get_value(&mut self, identifier: &String) -> i64 {
        for table in self.symbol_tables.iter().rev() {
            // TODO: Entry API
            if let Some(val) = table.get(identifier) {
                return *val
            }
        }
        panic!(format!("reference error: '{}' was not declared", identifier));
    }
}

pub fn interpret_program(ast: &Vec<Statement>) {
    let mut env = Environment::new();
    env.start_scope();
    for statement in ast.iter() {
        interpret_statement(statement, &mut env);
    }
    env.end_scope();
}

fn interpret_statement(s: &Statement, env: &mut Environment) {
    match *s {
        Statement::VariableDeclaration(ref variable, ref expr) => {
            let val = interpret_expr(expr, env);
            env.declare(variable, val);
            println!("{:?} => {}", variable, val);
        },
        Statement::Assignment(ref lhs_expr, ref expr) => {
            let val = interpret_expr(expr, env);
            match *lhs_expr {
                LhsExpr::Identifier(ref id) => env.set(id, val)
            };
        },
        Statement::Block(ref statements) => {
            env.start_scope();
            for statement in statements.iter() {
                interpret_statement(statement, env);
            }
            env.end_scope();
        },
        // TODO: other statements
        _ => {}
    }
}

fn interpret_expr(e: &Expr, env: &mut Environment) -> i64 {
    match *e {
        Expr::Number(x) => x,
        Expr::BinaryExpression(ref expr1, ref op, ref expr2) => {
            let val1 = interpret_expr(expr1, env);
            let val2 = interpret_expr(expr2, env);
            match *op {
                BinaryOp::Add => val1 + val2,
                BinaryOp::Sub => val1 - val2,
                BinaryOp::Mul => val1 * val2,
                BinaryOp::Div => val1 / val2,
            }
        },
        Expr::Identifier(ref id) => env.get_value(&id),
        // TODO: other exprs
        _ => 0
    }
}<commit_msg>Handle Statement::Expr case in interpreter<commit_after>use std::collections::HashMap;
use ast::*;

struct Environment {
    symbol_tables: Vec<HashMap<String, i64>>
}

impl Environment {
    fn new() -> Environment {
        Environment {
            symbol_tables: Vec::new()
        }
    }

    fn start_scope(&mut self) {
        self.symbol_tables.push(HashMap::new());
    }

    fn end_scope(&mut self) {
        self.symbol_tables.pop();
    }

    fn declare(&mut self, variable: &Variable, value: i64) {
        match *variable {
            Variable::Identifier(ref binding, ref id)
            | Variable::IdentifierWithType(ref binding, ref id, _) => {
                // TODO: binding
                self.symbol_tables.last_mut().unwrap().insert(id.clone(), value);
            }
        };
    }

    fn set(&mut self, identifier: &String, value: i64) {
        for table in self.symbol_tables.iter_mut().rev() {
            // TODO: Entry API
            if table.contains_key(identifier) {
                table.insert(identifier.clone(), value);
                return;
            }
        }
        panic!(format!("reference error: '{}' was not declared", identifier));
    }

    fn get_value(&mut self, identifier: &String) -> i64 {
        for table in self.symbol_tables.iter().rev() {
            // TODO: Entry API
            if let Some(val) = table.get(identifier) {
                return *val
            }
        }
        panic!(format!("reference error: '{}' was not declared", identifier));
    }
}

pub fn interpret_program(ast: &Vec<Statement>) {
    let mut env = Environment::new();
    env.start_scope();
    for statement in ast.iter() {
        interpret_statement(statement, &mut env);
    }
    env.end_scope();
}

fn interpret_statement(s: &Statement, env: &mut Environment) {
    match *s {
        Statement::VariableDeclaration(ref variable, ref expr) => {
            let val = interpret_expr(expr, env);
            env.declare(variable, val);
            println!("{:?} => {}", variable, val);
        },
        Statement::Assignment(ref lhs_expr, ref expr) => {
            let val = interpret_expr(expr, env);
            match *lhs_expr {
                LhsExpr::Identifier(ref id) => env.set(id, val)
            };
        },
        Statement::Block(ref statements) => {
            env.start_scope();
            for statement in statements.iter() {
                interpret_statement(statement, env);
            }
            env.end_scope();
        },
        Statement::Expression(ref expr) => {
            interpret_expr(expr, env);
        }
    }
}

fn interpret_expr(e: &Expr, env: &mut Environment) -> i64 {
    match *e {
        Expr::Number(x) => x,
        Expr::BinaryExpression(ref expr1, ref op, ref expr2) => {
            let val1 = interpret_expr(expr1, env);
            let val2 = interpret_expr(expr2, env);
            match *op {
                BinaryOp::Add => val1 + val2,
                BinaryOp::Sub => val1 - val2,
                BinaryOp::Mul => val1 * val2,
                BinaryOp::Div => val1 / val2,
            }
        },
        Expr::Identifier(ref id) => env.get_value(&id),
        // TODO: other exprs
        _ => 0
    }
}<|endoftext|>


<commit_before>pub struct Profile {
    units: usize,
    steps: usize,
    time: f64,
    time_step: f64,
    data: Vec<f64>,
}

impl Profile {
    pub fn new(units: usize, time_step: f64) -> Profile {
        Profile {
            units: units,
            steps: 0,
            time: 0.0,
            time_step: time_step,
            data: Vec::with_capacity(units),
        }
    }

    pub fn accumulate(&mut self, unit: usize, time: f64, time_step: f64, data: &[f64]) {
        debug_assert!(unit < self.units);
        debug_assert!(time >= self.time);

        let (t1, t2) = (self.time, time);
        let (s1, s2) = (self.time_step, time_step);
        let end_time = t2 + (data.len() as f64) * s2;

        let steps = ((end_time - t1) / s1).ceil() as usize;
        if steps > self.steps {
            self.data.extend(vec![0.0; (steps - self.steps) * self.units]);
            self.steps = steps;
        }

        let offset = (time / s2).fract();
        let mut time = t2;
        while time < end_time {
            let l1 = (time / s1).floor() * s1;
            let l2 = offset + ((time - offset) / s2).floor() * s2;

            let r1 = l1 + s1;
            let r2 = l2 + s2;

            let weight = if l1 <= l2 {
                if r2 <= r1 { 1.0 } else { (r1 - l2) / s2 }
            } else {
                if r1 <= r2 { s1 / s2 } else { (r2 - l1) / s2 }
            };

            let j1 = ((time - t1) / s1) as usize;
            let j2 = ((time - t2) / s2) as usize;
            self.data[j1 * self.units + unit] += weight * data[j2];

            time = r1.min(r2);
        }
    }
}

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

    #[test]
    fn accumulate_padding() {
        let mut profile = Profile::new(2, 0.5);

        profile.accumulate(0, 4.0, 1.0, &[]);
        assert_eq!(profile.steps, 8);
        assert_eq!(&profile.data, &vec![0.0; 2 * 8]);

        profile.accumulate(0, 2.5, 1.0, &[]);
        assert_eq!(profile.steps, 8);
        assert_eq!(&profile.data, &vec![0.0; 2 * 8]);

        profile.accumulate(0, 6.5, 1.0, &[]);
        assert_eq!(profile.steps, 13);
        assert_eq!(&profile.data, &vec![0.0; 2 * 13]);

        profile.accumulate(0, 6.55, 1.0, &[]);
        assert_eq!(profile.steps, 14);
        assert_eq!(&profile.data, &vec![0.0; 2 * 14]);
    }

    #[test]
    fn accumulate_synchronous() {
        let mut profile = Profile::new(2, 1.0);

        profile.accumulate(0, 1.0, 1.0, &[1.0, 2.0]);
        assert_eq!(profile.steps, 3);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           1.0, 0.0,
           2.0, 0.0,
        ]);

        profile.accumulate(0, 1.0, 1.0, &[1.0, 2.0, 3.0]);
        assert_eq!(profile.steps, 4);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           2.0, 0.0,
           4.0, 0.0,
           3.0, 0.0,
        ]);
    }

    #[test]
    fn accumulate_asynchronous() {
        let mut profile = Profile::new(2, 1.0);

        profile.accumulate(1, 1.5, 1.0, &[1.0, 2.0, 3.0]);
        assert_eq!(profile.steps, 5);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           0.0, 0.5,
           0.0, 1.5,
           0.0, 2.5,
           0.0, 1.5,
        ]);

        profile.accumulate(0, 0.5, 0.25, &[1.0, 2.0, 3.0, 1.0, 3.0]);
        assert_eq!(profile.steps, 5);
        assert_eq!(&profile.data, &vec![
           3.0, 0.0,
           7.0, 0.5,
           0.0, 1.5,
           0.0, 2.5,
           0.0, 1.5,
        ]);

        profile.accumulate(0, 1.25, 1.0, &[1.0, 2.0, 3.0, 0.0, 4.0]);
        assert_eq!(profile.steps, 7);
        assert_eq!(&profile.data, &vec![
           3.00, 0.0,
           7.75, 0.5,
           1.75, 1.5,
           2.75, 2.5,
           0.75, 1.5,
           3.00, 0.0,
           1.00, 0.0,
        ]);
    }
}
<commit_msg>Refactor Profile::accumulate<commit_after>pub struct Profile {
    units: usize,
    steps: usize,
    time: f64,
    time_step: f64,
    data: Vec<f64>,
}

impl Profile {
    pub fn new(units: usize, time_step: f64) -> Profile {
        Profile {
            units: units,
            steps: 0,
            time: 0.0,
            time_step: time_step,
            data: Vec::with_capacity(units),
        }
    }

    pub fn accumulate(&mut self, unit: usize, time: f64, time_step: f64, data: &[f64]) {
        debug_assert!(unit < self.units);
        debug_assert!(time >= self.time);

        let (t1, t2) = (self.time, time);
        let (d1, d2) = (self.time_step, time_step);

        let s2 = data.len();
        let s1 = ((t2 - t1 + (s2 as f64) * d2) / d1).ceil() as usize;

        if s1 > self.steps {
            self.data.extend(vec![0.0; (s1 - self.steps) * self.units]);
            self.steps = s1;
        }

        let mut j1 = ((t2 - t1) / d1) as usize;
        let mut j2 = 0;

        macro_rules! add(
            ($weight:expr) => (self.data[j1 * self.units + unit] += $weight * data[j2]);
        );

        while j1 < s1 && j2 < s2 {
            let l1 = t1 + (j1 as f64) * d1;
            let l2 = t2 + (j2 as f64) * d2;

            let r1 = l1 + d1;
            let r2 = l2 + d2;

            if l1 < l2 {
                if r2 < r1 {
                    add!(1.0);
                    j2 += 1;
                } else {
                    add!((r1 - l2) / d2);
                    j1 += 1;
                }
            } else {
                if r1 < r2 {
                    add!(d1 / d2);
                    j1 += 1;
                } else {
                    add!((r2 - l1) / d2);
                    j2 += 1;
                }
            }
        }
    }
}

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

    #[test]
    fn accumulate_padding() {
        let mut profile = Profile::new(2, 0.5);

        profile.accumulate(0, 4.0, 1.0, &[]);
        assert_eq!(profile.steps, 8);
        assert_eq!(&profile.data, &vec![0.0; 2 * 8]);

        profile.accumulate(0, 2.5, 1.0, &[]);
        assert_eq!(profile.steps, 8);
        assert_eq!(&profile.data, &vec![0.0; 2 * 8]);

        profile.accumulate(0, 6.5, 1.0, &[]);
        assert_eq!(profile.steps, 13);
        assert_eq!(&profile.data, &vec![0.0; 2 * 13]);

        profile.accumulate(0, 6.55, 1.0, &[]);
        assert_eq!(profile.steps, 14);
        assert_eq!(&profile.data, &vec![0.0; 2 * 14]);
    }

    #[test]
    fn accumulate_synchronous() {
        let mut profile = Profile::new(2, 1.0);

        profile.accumulate(0, 1.0, 1.0, &[1.0, 2.0]);
        assert_eq!(profile.steps, 3);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           1.0, 0.0,
           2.0, 0.0,
        ]);

        profile.accumulate(0, 1.0, 1.0, &[1.0, 2.0, 3.0]);
        assert_eq!(profile.steps, 4);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           2.0, 0.0,
           4.0, 0.0,
           3.0, 0.0,
        ]);
    }

    #[test]
    fn accumulate_asynchronous() {
        let mut profile = Profile::new(2, 1.0);

        profile.accumulate(1, 1.5, 1.0, &[1.0, 2.0, 3.0]);
        assert_eq!(profile.steps, 5);
        assert_eq!(&profile.data, &vec![
           0.0, 0.0,
           0.0, 0.5,
           0.0, 1.5,
           0.0, 2.5,
           0.0, 1.5,
        ]);

        profile.accumulate(0, 0.5, 0.25, &[1.0, 2.0, 3.0, 1.0, 3.0]);
        assert_eq!(profile.steps, 5);
        assert_eq!(&profile.data, &vec![
           3.0, 0.0,
           7.0, 0.5,
           0.0, 1.5,
           0.0, 2.5,
           0.0, 1.5,
        ]);

        profile.accumulate(0, 1.25, 1.0, &[1.0, 2.0, 3.0, 0.0, 4.0]);
        assert_eq!(profile.steps, 7);
        assert_eq!(&profile.data, &vec![
           3.00, 0.0,
           7.75, 0.5,
           1.75, 1.5,
           2.75, 2.5,
           0.75, 1.5,
           3.00, 0.0,
           1.00, 0.0,
        ]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(missing_docs)]
#![unstable(feature = "core")]

//! Contains struct definitions for the layout of compiler built-in types.
//!
//! They can be used as targets of transmutes in unsafe code for manipulating
//! the raw representations directly.
//!
//! Their definition should always match the ABI defined in `rustc::back::abi`.

use marker::Copy;
use mem;

/// The representation of a slice like `&[T]`.
///
/// This struct is guaranteed to have the layout of types like `&[T]`,
/// `&str`, and `Box<[T]>`, but is not the type of such slices
/// (e.g. the fields are not directly accessible on a `&[T]`) nor does
/// it control that layout (changing the definition will not change
/// the layout of a `&[T]`). It is only designed to be used by unsafe
/// code that needs to manipulate the low-level details.
///
/// However, it is not recommended to use this type for such code,
/// since there are alternatives which may be safer:
///
/// - Creating a slice from a data pointer and length can be done with
///   `std::slice::from_raw_parts` or `std::slice::from_raw_parts_mut`
///   instead of `std::mem::transmute`ing a value of type `Slice`.
/// - Extracting the data pointer and length from a slice can be
///   performed with the `as_ptr` (or `as_mut_ptr`) and `len`
///   methods.
///
/// If one does decide to convert a slice value to a `Slice`, the
/// `Repr` trait in this module provides a method for a safe
/// conversion from `&[T]` (and `&str`) to a `Slice`, more type-safe
/// than a call to `transmute`.
///
/// # Examples
///
/// ```
/// use std::raw::{self, Repr};
///
/// let slice: &[u16] = &[1, 2, 3, 4];
///
/// let repr: raw::Slice<u16> = slice.repr();
/// println!("data pointer = {:?}, length = {}", repr.data, repr.len);
/// ```
#[repr(C)]
pub struct Slice<T> {
    pub data: *const T,
    pub len: uint,
}

impl<T> Copy for Slice<T> {}

/// The representation of an old closure.
#[repr(C)]
#[derive(Copy)]
#[unstable(feature = "core")]
#[deprecated(reason = "unboxed new closures do not have a universal representation; \
                       `&Fn` (etc) trait objects should use `TraitObject` instead",
             since= "1.0.0")]
pub struct Closure {
    pub code: *mut (),
    pub env: *mut (),
}

/// The representation of a trait object like `&SomeTrait`.
///
/// This struct has the same layout as types like `&SomeTrait` and
/// `Box<AnotherTrait>`. The [Static and Dynamic Dispatch chapter of the
/// Book][moreinfo] contains more details about the precise nature of
/// these internals.
///
/// [moreinfo]: ../../book/static-and-dynamic-dispatch.html#representation
///
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g. the fields are not directly accessible
/// on a `&SomeTrait`) nor does it control that layout (changing the
/// definition will not change the layout of a `&SometTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
/// There is no `Repr` implementation for `TraitObject` because there
/// is no way to refer to all trait objects generically, so the only
/// way to create values of this type is with functions like
/// `std::mem::transmute`. Similarly, the only way to create a true
/// trait object from a `TraitObject` value is with `transmute`.
///
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
/// behaviour.
///
/// # Examples
///
/// ```
/// use std::mem;
/// use std::raw;
///
/// // an example trait
/// trait Foo {
///     fn bar(&self) -> i32;
/// }
/// impl Foo for i32 {
///     fn bar(&self) -> i32 {
///          *self + 1
///     }
/// }
///
/// let value: i32 = 123;
///
/// // let the compiler make a trait object
/// let object: &Foo = &value;
///
/// // look at the raw representation
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
///
/// // the data pointer is the address of `value`
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
///
///
/// let other_value: i32 = 456;
///
/// // construct a new object, pointing to a different `i32`, being
/// // careful to use the `i32` vtable from `object`
/// let synthesized: &Foo = unsafe {
///      mem::transmute(raw::TraitObject {
///          data: &other_value as *const _ as *mut (),
///          vtable: raw_object.vtable
///      })
/// };
///
/// // it should work just like we constructed a trait object out of
/// // `other_value` directly
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
#[derive(Copy)]
pub struct TraitObject {
    pub data: *mut (),
    pub vtable: *mut (),
}

/// This trait is meant to map equivalences between raw structs and their
/// corresponding rust values.
pub trait Repr<T> {
    /// This function "unwraps" a rust value (without consuming it) into its raw
    /// struct representation. This can be used to read/write different values
    /// for the struct. This is a safe method because by default it does not
    /// enable write-access to the fields of the return value in safe code.
    #[inline]
    fn repr(&self) -> T { unsafe { mem::transmute_copy(&self) } }
}

impl<T> Repr<Slice<T>> for [T] {}
impl Repr<Slice<u8>> for str {}
<commit_msg>Make std::raw::Repr an unsafe trait<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(missing_docs)]
#![unstable(feature = "core")]

//! Contains struct definitions for the layout of compiler built-in types.
//!
//! They can be used as targets of transmutes in unsafe code for manipulating
//! the raw representations directly.
//!
//! Their definition should always match the ABI defined in `rustc::back::abi`.

use marker::Copy;
use mem;

/// The representation of a slice like `&[T]`.
///
/// This struct is guaranteed to have the layout of types like `&[T]`,
/// `&str`, and `Box<[T]>`, but is not the type of such slices
/// (e.g. the fields are not directly accessible on a `&[T]`) nor does
/// it control that layout (changing the definition will not change
/// the layout of a `&[T]`). It is only designed to be used by unsafe
/// code that needs to manipulate the low-level details.
///
/// However, it is not recommended to use this type for such code,
/// since there are alternatives which may be safer:
///
/// - Creating a slice from a data pointer and length can be done with
///   `std::slice::from_raw_parts` or `std::slice::from_raw_parts_mut`
///   instead of `std::mem::transmute`ing a value of type `Slice`.
/// - Extracting the data pointer and length from a slice can be
///   performed with the `as_ptr` (or `as_mut_ptr`) and `len`
///   methods.
///
/// If one does decide to convert a slice value to a `Slice`, the
/// `Repr` trait in this module provides a method for a safe
/// conversion from `&[T]` (and `&str`) to a `Slice`, more type-safe
/// than a call to `transmute`.
///
/// # Examples
///
/// ```
/// use std::raw::{self, Repr};
///
/// let slice: &[u16] = &[1, 2, 3, 4];
///
/// let repr: raw::Slice<u16> = slice.repr();
/// println!("data pointer = {:?}, length = {}", repr.data, repr.len);
/// ```
#[repr(C)]
pub struct Slice<T> {
    pub data: *const T,
    pub len: uint,
}

impl<T> Copy for Slice<T> {}

/// The representation of an old closure.
#[repr(C)]
#[derive(Copy)]
#[unstable(feature = "core")]
#[deprecated(reason = "unboxed new closures do not have a universal representation; \
                       `&Fn` (etc) trait objects should use `TraitObject` instead",
             since= "1.0.0")]
pub struct Closure {
    pub code: *mut (),
    pub env: *mut (),
}

/// The representation of a trait object like `&SomeTrait`.
///
/// This struct has the same layout as types like `&SomeTrait` and
/// `Box<AnotherTrait>`. The [Static and Dynamic Dispatch chapter of the
/// Book][moreinfo] contains more details about the precise nature of
/// these internals.
///
/// [moreinfo]: ../../book/static-and-dynamic-dispatch.html#representation
///
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g. the fields are not directly accessible
/// on a `&SomeTrait`) nor does it control that layout (changing the
/// definition will not change the layout of a `&SometTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
/// There is no `Repr` implementation for `TraitObject` because there
/// is no way to refer to all trait objects generically, so the only
/// way to create values of this type is with functions like
/// `std::mem::transmute`. Similarly, the only way to create a true
/// trait object from a `TraitObject` value is with `transmute`.
///
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
/// behaviour.
///
/// # Examples
///
/// ```
/// use std::mem;
/// use std::raw;
///
/// // an example trait
/// trait Foo {
///     fn bar(&self) -> i32;
/// }
/// impl Foo for i32 {
///     fn bar(&self) -> i32 {
///          *self + 1
///     }
/// }
///
/// let value: i32 = 123;
///
/// // let the compiler make a trait object
/// let object: &Foo = &value;
///
/// // look at the raw representation
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
///
/// // the data pointer is the address of `value`
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
///
///
/// let other_value: i32 = 456;
///
/// // construct a new object, pointing to a different `i32`, being
/// // careful to use the `i32` vtable from `object`
/// let synthesized: &Foo = unsafe {
///      mem::transmute(raw::TraitObject {
///          data: &other_value as *const _ as *mut (),
///          vtable: raw_object.vtable
///      })
/// };
///
/// // it should work just like we constructed a trait object out of
/// // `other_value` directly
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
#[derive(Copy)]
pub struct TraitObject {
    pub data: *mut (),
    pub vtable: *mut (),
}

/// This trait is meant to map equivalences between raw structs and their
/// corresponding rust values.
pub unsafe trait Repr<T> {
    /// This function "unwraps" a rust value (without consuming it) into its raw
    /// struct representation. This can be used to read/write different values
    /// for the struct. This is a safe method because by default it does not
    /// enable write-access to the fields of the return value in safe code.
    #[inline]
    fn repr(&self) -> T { unsafe { mem::transmute_copy(&self) } }
}

unsafe impl<T> Repr<Slice<T>> for [T] {}
unsafe impl Repr<Slice<u8>> for str {}
<|endoftext|>


<commit_before>//! Support code for rustc's built in unit-test and micro-benchmarking
//! framework.
//!
//! Almost all user code will only be interested in `Bencher` and
//! `black_box`. All other interactions (such as writing tests and
//! benchmarks themselves) should be done via the `#[test]` and
//! `#[bench]` attributes.
//!
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.

#![crate_name = "test"]
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       test(attr(deny(warnings))))]
#![feature(asm)]
#![feature(staged_api)]
#![feature(test)]

extern crate libtest;
pub use libtest::{
    assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static,
    Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic,
    StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts,
    TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk,
};

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))]
pub fn black_box<T>(dummy: T) -> T {
    // we need to "use" the argument in some way LLVM can't
    // introspect.
    unsafe { asm!("" : : "r"(&dummy)) }
    dummy
}
#[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))]
#[inline(never)]
pub fn black_box<T>(dummy: T) -> T {
    dummy
}
<commit_msg>Export stats::Summary from libtest<commit_after>//! Support code for rustc's built in unit-test and micro-benchmarking
//! framework.
//!
//! Almost all user code will only be interested in `Bencher` and
//! `black_box`. All other interactions (such as writing tests and
//! benchmarks themselves) should be done via the `#[test]` and
//! `#[bench]` attributes.
//!
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.

#![crate_name = "test"]
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
       test(attr(deny(warnings))))]
#![feature(asm)]
#![feature(staged_api)]
#![feature(test)]

extern crate libtest;

// FIXME: we should be more explicit about the exact APIs that we
// export to users.
pub use libtest::{
    assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static,
    Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic,
    StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts,
    TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk, stats::Summary
};

/// A function that is opaque to the optimizer, to allow benchmarks to
/// pretend to use outputs to assist in avoiding dead-code
/// elimination.
///
/// This function is a no-op, and does not even read from `dummy`.
#[cfg(not(any(target_arch = "asmjs", target_arch = "wasm32")))]
pub fn black_box<T>(dummy: T) -> T {
    // we need to "use" the argument in some way LLVM can't
    // introspect.
    unsafe { asm!("" : : "r"(&dummy)) }
    dummy
}
#[cfg(any(target_arch = "asmjs", target_arch = "wasm32"))]
#[inline(never)]
pub fn black_box<T>(dummy: T) -> T {
    dummy
}
<|endoftext|>


<commit_before>#![cfg(feature = "llvm")]
use std::io::{Read, Write};

use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::execution_engine::ExecutionEngine;
use inkwell::types::BasicTypeEnum;
use inkwell::values::{BasicValue, FunctionValue, IntValue, PointerValue};
use inkwell::AddressSpace;
use inkwell::IntPredicate;
use inkwell::OptimizationLevel;

use structs::Op;
use structs::Op::*;

pub struct LlvmState<'a> {
    input: &'a mut dyn Read,
    output: &'a mut dyn Write,
}

struct Compiler<'ctx, 'a> {
    context: &'ctx Context,
    builder: &'a Builder<'ctx>,
    execution_engine: &'a ExecutionEngine<'ctx>,
    function: FunctionValue<'ctx>,

    memory: PointerValue<'ctx>,
    state: PointerValue<'ctx>,

    getcharfn: FunctionValue<'ctx>,
    putcharfn: FunctionValue<'ctx>,
}

impl<'ctx, 'a> Compiler<'ctx, 'a> {
    fn compile(&self, ops: &[Op], start_ptr: IntValue<'ctx>) -> IntValue<'ctx> {
        let byte = self.context.i8_type();
        let size_t = self.context.ptr_sized_int_type(
            self.execution_engine.get_target_data(),
            Some(AddressSpace::Generic),
        );

        let builder = self.builder;
        let mut ptr = start_ptr;

        for op in ops {
            match op {
                Mov(i) => {
                    ptr = builder.build_int_add(ptr, size_t.const_int((*i) as u64, true), "ptr");
                }
                Add(i) => {
                    let mem_ptr =
                        unsafe { builder.build_in_bounds_gep(self.memory, &[ptr], "mem_ptr") };
                    builder.build_store(
                        mem_ptr,
                        builder.build_int_add(
                            builder.build_load(mem_ptr, "v").into_int_value(),
                            byte.const_int((*i).into(), true),
                            "v",
                        ),
                    );
                }
                In => {
                    let mem_ptr =
                        unsafe { builder.build_in_bounds_gep(self.memory, &[ptr], "mem_ptr") };
                    let result = builder.build_call(
                        self.getcharfn,
                        &[
                            mem_ptr.as_basic_value_enum(),
                            self.state.as_basic_value_enum(),
                        ],
                        "call",
                    );
                    let exit_block = self.context.append_basic_block(self.function, "exit");
                    let next_block = self.context.append_basic_block(self.function, "next");
                    builder.build_conditional_branch(
                        builder.build_int_compare(
                            IntPredicate::EQ,
                            result.try_as_basic_value().left().unwrap().into_int_value(),
                            self.context.bool_type().const_zero(),
                            "eof",
                        ),
                        exit_block,
                        next_block,
                    );
                    builder.position_at_end(exit_block);
                    builder.build_return(None);
                    builder.position_at_end(next_block);
                }
                Out => {
                    let mem_ptr =
                        unsafe { builder.build_in_bounds_gep(self.memory, &[ptr], "mem_ptr") };
                    builder.build_call(
                        self.putcharfn,
                        &[
                            builder.build_load(mem_ptr, "v"),
                            self.state.as_basic_value_enum(),
                        ],
                        "call",
                    );
                }
                Loop(ref ops) => {
                    let current_block = self.builder.get_insert_block().unwrap();
                    let test_block = self.context.append_basic_block(self.function, "test");
                    let body_block = self.context.append_basic_block(self.function, "body");
                    let next_block = self.context.append_basic_block(self.function, "next");

                    builder.build_unconditional_branch(test_block);
                    builder.position_at_end(test_block);

                    let test_ptr_phi = builder.build_phi(size_t, "ptr");
                    test_ptr_phi.add_incoming(&[(&ptr, current_block)]);
                    ptr = test_ptr_phi.as_basic_value().into_int_value();

                    let mem_ptr =
                        unsafe { builder.build_in_bounds_gep(self.memory, &[ptr], "mem_ptr") };
                    builder.build_conditional_branch(
                        builder.build_int_compare(
                            IntPredicate::EQ,
                            builder.build_load(mem_ptr, "v").into_int_value(),
                            byte.const_int(0, false),
                            "iszero",
                        ),
                        next_block,
                        body_block,
                    );
                    builder.position_at_end(body_block);
                    let ptrreg_loop = self.compile(ops.get(), ptr);
                    test_ptr_phi
                        .add_incoming(&[(&ptrreg_loop, self.builder.get_insert_block().unwrap())]);

                    builder.build_unconditional_branch(test_block);
                    self.builder.position_at_end(next_block);
                }
                Transfer(_, _) => {
                    panic!("Transfer is not implemented for the LLVM backend.");
                }
            }
        }

        return ptr;
    }
}

const MEMSIZE: usize = 30000;

impl<'a> LlvmState<'a> {
    pub fn new<'b>(input: &'b mut dyn Read, output: &'b mut dyn Write) -> LlvmState<'b> {
        LlvmState { input, output }
    }

    pub fn run(&mut self, ops: &[Op]) -> bool {
        let context = Context::create();
        let module = context.create_module("program");
        let execution_engine = module
            .create_jit_execution_engine(OptimizationLevel::Default)
            .unwrap();
        let builder = context.create_builder();

        let byte = context.i8_type();
        let size_t = context.ptr_sized_int_type(
            execution_engine.get_target_data(),
            Some(AddressSpace::Generic),
        );
        let getcharfn = module.add_function(
            "getchar",
            context.bool_type().fn_type(
                &[
                    byte.ptr_type(AddressSpace::Generic).into(),
                    BasicTypeEnum::PointerType(byte.ptr_type(AddressSpace::Generic)),
                ],
                false,
            ),
            None,
        );
        let putcharfn = module.add_function(
            "putchar",
            context.void_type().fn_type(
                &[
                    byte.into(),
                    BasicTypeEnum::PointerType(byte.ptr_type(AddressSpace::Generic)),
                ],
                false,
            ),
            None,
        );

        let function = module.add_function(
            "run",
            context.void_type().fn_type(
                &[
                    BasicTypeEnum::PointerType(byte.ptr_type(AddressSpace::Generic)),
                    BasicTypeEnum::PointerType(byte.ptr_type(AddressSpace::Generic)),
                ],
                false,
            ),
            None,
        );
        let entry_block = context.append_basic_block(function, "entry");
        builder.position_at_end(entry_block);

        let compiler = Compiler {
            context: &context,
            builder: &builder,
            execution_engine: &execution_engine,
            function,

            memory: function.get_nth_param(0).unwrap().into_pointer_value(),
            state: function.get_nth_param(1).unwrap().into_pointer_value(),

            getcharfn,
            putcharfn,
        };

        compiler.compile(ops, size_t.const_zero());
        builder.build_return(None);

        module.verify().unwrap();

        execution_engine.add_global_mapping(&getcharfn, LlvmState::getchar as usize);
        execution_engine.add_global_mapping(&putcharfn, LlvmState::putchar as usize);

        let mut memory: [i8; MEMSIZE] = [0; MEMSIZE];
        unsafe {
            execution_engine
                .get_function::<unsafe extern "C" fn(*mut [i8; MEMSIZE], *mut std::ffi::c_void) -> u64>(
                    "run",
                )
                .unwrap()
                .call(&mut memory as *mut [i8; MEMSIZE], /* FIXME: evil */ std::mem::transmute(self));
        };

        true
    }

    extern "C" fn getchar(ch: &mut u8, state: &mut LlvmState) -> bool {
        let mut c = [0u8];
        if state.input.read(&mut c).unwrap() == 0 {
            return false;
        }
        *ch = c[0];
        true
    }

    extern "C" fn putchar(ch: u8, state: &mut LlvmState) {
        state.output.write_all(&[ch]).unwrap();
    }
}
<commit_msg>fix: use build_gep<commit_after>#![cfg(feature = "llvm")]
use std::io::{Read, Write};

use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::execution_engine::ExecutionEngine;
use inkwell::types::BasicTypeEnum;
use inkwell::values::{BasicValue, FunctionValue, IntValue, PointerValue};
use inkwell::AddressSpace;
use inkwell::IntPredicate;
use inkwell::OptimizationLevel;

use structs::Op;
use structs::Op::*;

pub struct LlvmState<'a> {
    input: &'a mut dyn Read,
    output: &'a mut dyn Write,
}

struct Compiler<'ctx, 'a> {
    context: &'ctx Context,
    builder: &'a Builder<'ctx>,
    execution_engine: &'a ExecutionEngine<'ctx>,
    function: FunctionValue<'ctx>,

    memory: PointerValue<'ctx>,
    state: PointerValue<'ctx>,

    getcharfn: FunctionValue<'ctx>,
    putcharfn: FunctionValue<'ctx>,
}

impl<'ctx, 'a> Compiler<'ctx, 'a> {
    fn compile(&self, ops: &[Op], start_ptr: IntValue<'ctx>) -> IntValue<'ctx> {
        let byte = self.context.i8_type();
        let size_t = self.context.ptr_sized_int_type(
            self.execution_engine.get_target_data(),
            Some(AddressSpace::Generic),
        );

        let builder = self.builder;
        let mut ptr = start_ptr;

        for op in ops {
            match op {
                Mov(i) => {
                    ptr = builder.build_int_add(ptr, size_t.const_int((*i) as u64, true), "ptr");
                }
                Add(i) => {
                    let mem_ptr = unsafe { builder.build_gep(self.memory, &[ptr], "mem_ptr") };
                    builder.build_store(
                        mem_ptr,
                        builder.build_int_add(
                            builder.build_load(mem_ptr, "v").into_int_value(),
                            byte.const_int((*i).into(), true),
                            "v",
                        ),
                    );
                }
                In => {
                    let mem_ptr = unsafe { builder.build_gep(self.memory, &[ptr], "mem_ptr") };
                    let result = builder.build_call(
                        self.getcharfn,
                        &[
                            mem_ptr.as_basic_value_enum(),
                            self.state.as_basic_value_enum(),
                        ],
                        "call",
                    );
                    let exit_block = self.context.append_basic_block(self.function, "exit");
                    let next_block = self.context.append_basic_block(self.function, "next");
                    builder.build_conditional_branch(
                        builder.build_int_compare(
                            IntPredicate::EQ,
                            result.try_as_basic_value().left().unwrap().into_int_value(),
                            self.context.bool_type().const_zero(),
                            "eof",
                        ),
                        exit_block,
                        next_block,
                    );
                    builder.position_at_end(exit_block);
                    builder.build_return(None);
                    builder.position_at_end(next_block);
                }
                Out => {
                    let mem_ptr = unsafe { builder.build_gep(self.memory, &[ptr], "mem_ptr") };
                    builder.build_call(
                        self.putcharfn,
                        &[
                            builder.build_load(mem_ptr, "v"),
                            self.state.as_basic_value_enum(),
                        ],
                        "call",
                    );
                }
                Loop(ref ops) => {
                    let current_block = self.builder.get_insert_block().unwrap();
                    let test_block = self.context.append_basic_block(self.function, "test");
                    let body_block = self.context.append_basic_block(self.function, "body");
                    let next_block = self.context.append_basic_block(self.function, "next");

                    builder.build_unconditional_branch(test_block);
                    builder.position_at_end(test_block);

                    let test_ptr_phi = builder.build_phi(size_t, "ptr");
                    test_ptr_phi.add_incoming(&[(&ptr, current_block)]);
                    ptr = test_ptr_phi.as_basic_value().into_int_value();

                    let mem_ptr = unsafe { builder.build_gep(self.memory, &[ptr], "mem_ptr") };
                    builder.build_conditional_branch(
                        builder.build_int_compare(
                            IntPredicate::EQ,
                            builder.build_load(mem_ptr, "v").into_int_value(),
                            byte.const_int(0, false),
                            "iszero",
                        ),
                        next_block,
                        body_block,
                    );
                    builder.position_at_end(body_block);
                    let ptrreg_loop = self.compile(ops.get(), ptr);
                    test_ptr_phi
                        .add_incoming(&[(&ptrreg_loop, self.builder.get_insert_block().unwrap())]);

                    builder.build_unconditional_branch(test_block);
                    self.builder.position_at_end(next_block);
                }
                Transfer(_, _) => {
                    panic!("Transfer is not implemented for the LLVM backend.");
                }
            }
        }

        return ptr;
    }
}

const MEMSIZE: usize = 30000;

impl<'a> LlvmState<'a> {
    pub fn new<'b>(input: &'b mut dyn Read, output: &'b mut dyn Write) -> LlvmState<'b> {
        LlvmState { input, output }
    }

    pub fn run(&mut self, ops: &[Op]) -> bool {
        let context = Context::create();
        let module = context.create_module("program");
        let execution_engine = module
            .create_jit_execution_engine(OptimizationLevel::Default)
            .unwrap();
        let builder = context.create_builder();

        let byte = context.i8_type();
        let size_t = context.ptr_sized_int_type(
            execution_engine.get_target_data(),
            Some(AddressSpace::Generic),
        );
        let getcharfn = module.add_function(
            "getchar",
            context.bool_type().fn_type(
                &[
                    byte.ptr_type(AddressSpace::Generic).into(),
                    BasicTypeEnum::PointerType(byte.ptr_type(AddressSpace::Generic)),
                ],
                false,
            ),
            None,
        );
        let putcharfn = module.add_function(
            "putchar",
            context.void_type().fn_type(
                &[
                    byte.into(),
                    BasicTypeEnum::PointerType(byte.ptr_type(AddressSpace::Generic)),
                ],
                false,
            ),
            None,
        );

        let function = module.add_function(
            "run",
            context.void_type().fn_type(
                &[
                    BasicTypeEnum::PointerType(byte.ptr_type(AddressSpace::Generic)),
                    BasicTypeEnum::PointerType(byte.ptr_type(AddressSpace::Generic)),
                ],
                false,
            ),
            None,
        );
        let entry_block = context.append_basic_block(function, "entry");
        builder.position_at_end(entry_block);

        let compiler = Compiler {
            context: &context,
            builder: &builder,
            execution_engine: &execution_engine,
            function,

            memory: function.get_nth_param(0).unwrap().into_pointer_value(),
            state: function.get_nth_param(1).unwrap().into_pointer_value(),

            getcharfn,
            putcharfn,
        };

        compiler.compile(ops, size_t.const_zero());
        builder.build_return(None);

        module.verify().unwrap();

        execution_engine.add_global_mapping(&getcharfn, LlvmState::getchar as usize);
        execution_engine.add_global_mapping(&putcharfn, LlvmState::putchar as usize);

        let mut memory: [i8; MEMSIZE] = [0; MEMSIZE];
        unsafe {
            execution_engine
                .get_function::<unsafe extern "C" fn(*mut [i8; MEMSIZE], *mut std::ffi::c_void) -> u64>(
                    "run",
                )
                .unwrap()
                .call(&mut memory as *mut [i8; MEMSIZE], /* FIXME: evil */ std::mem::transmute(self));
        };

        true
    }

    extern "C" fn getchar(ch: &mut u8, state: &mut LlvmState) -> bool {
        let mut c = [0u8];
        if state.input.read(&mut c).unwrap() == 0 {
            return false;
        }
        *ch = c[0];
        true
    }

    extern "C" fn putchar(ch: u8, state: &mut LlvmState) {
        state.output.write_all(&[ch]).unwrap();
    }
}
<|endoftext|>


<commit_before>//! Bindings to the Hypervisor Framework

use libc::*;

pub mod consts;

/// Hypervisor Framework return code
pub type hv_return_t = uint32_t;

/// Options for hv_vcpu_create()
pub type hv_vm_options_t = uint64_t;

// Creating and Destroying VM Instances
extern {
    /// Creates a VM instance for the current task
    pub fn hv_vm_create(flags: hv_vm_options_t) -> hv_return_t;

    /// Destroys the VM instance associated with the current task
    pub fn hv_vm_destroy() -> hv_return_t;
}

/// Type of a vCPU ID
pub type hv_vcpuid_t = c_uint;

// Creating and Managing vCPU Instances
extern {
    /// Creates a vCPU instance for the current thread
    pub fn hv_vcpu_create(vcpu: *mut hv_vcpuid_t, flags: hv_vm_options_t) -> hv_return_t;

    /// Executes a vCPU
    pub fn hv_vcpu_run(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Forces an immediate VMEXIT of a set of vCPUs of the VM
    pub fn hv_vcpu_interrupt(vcpu: *const hv_vcpuid_t, vcpu_count: c_uint) -> hv_return_t;

    /// Returns the cumulative execution time of a vCPU in nanoseconds
    pub fn hv_vcpu_get_exec_time(vcpu: hv_vcpuid_t, time: *mut uint64_t) -> hv_return_t;

    /// Forces flushing of cached vCPU state
    pub fn hv_vcpu_flush(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Invalidates the TLB of a vCPU
    pub fn hv_vcpu_invalidate_tlb(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Destroys the vCPU instance associated with the current thread
    pub fn hv_vcpu_destroy(vcpu: hv_vcpuid_t) -> hv_return_t;
}

/// x86 architectural register IDs
#[repr(C)]
pub enum hv_x86_reg_t {
	HV_X86_RIP,
	HV_X86_RFLAGS,
	HV_X86_RAX,
	HV_X86_RCX,
	HV_X86_RDX,
	HV_X86_RBX,
	HV_X86_RSI,
	HV_X86_RDI,
	HV_X86_RSP,
	HV_X86_RBP,
	HV_X86_R8,
	HV_X86_R9,
	HV_X86_R10,
	HV_X86_R11,
	HV_X86_R12,
	HV_X86_R13,
	HV_X86_R14,
	HV_X86_R15,
	HV_X86_CS,
	HV_X86_SS,
	HV_X86_DS,
	HV_X86_ES,
	HV_X86_FS,
	HV_X86_GS,
	HV_X86_IDT_BASE,
	HV_X86_IDT_LIMIT,
	HV_X86_GDT_BASE,
	HV_X86_GDT_LIMIT,
	HV_X86_LDTR,
	HV_X86_LDT_BASE,
	HV_X86_LDT_LIMIT,
	HV_X86_LDT_AR,
	HV_X86_TR,
	HV_X86_TSS_BASE,
	HV_X86_TSS_LIMIT,
	HV_X86_TSS_AR,
	HV_X86_CR0,
	HV_X86_CR1,
	HV_X86_CR2,
	HV_X86_CR3,
	HV_X86_CR4,
	HV_X86_DR0,
	HV_X86_DR1,
	HV_X86_DR2,
	HV_X86_DR3,
	HV_X86_DR4,
	HV_X86_DR5,
	HV_X86_DR6,
	HV_X86_DR7,
	HV_X86_TPR,
	HV_X86_XCR0,
	HV_X86_REGISTERS_MAX,
}

// Accessing Registers
extern {
    /// Returns the current value of an architectural x86 register
    /// of a vCPU
    pub fn hv_vcpu_read_register(vcpu: hv_vcpuid_t, reg: hv_x86_reg_t, value: *mut uint64_t) -> hv_return_t;

    /// Sets the value of an architectural x86 register of a vCPU
    pub fn hv_vcpu_write_register(vcpu: hv_vcpuid_t, reg: hv_x86_reg_t, value: uint64_t) -> hv_return_t;
}

// Accessing Floating Point (FP) State
extern {
    /// Returns the current architectural x86 floating point and
    /// SIMD state of a vCPU
    pub fn hv_vcpu_read_fpstate(vcpu: hv_vcpuid_t, buffer: *mut c_void, size: size_t) -> hv_return_t;

    /// Sets the architectural x86 floating point and SIMD state of
    /// a vCPU
    pub fn hv_vcpu_write_fpstate(vcpu: hv_vcpuid_t, buffer: *const c_void, size: size_t) -> hv_return_t;
}

// Accessing Machine Specific Registers (MSRs)
extern {
    /// Enables an MSR to be used natively by the VM
    pub fn hv_vcpu_enable_native_msr(vcpu: hv_vcpuid_t, msr: uint32_t, enable: bool) -> hv_return_t;

    /// Returns the current value of an MSR of a vCPU
    pub fn hv_vcpu_read_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *mut uint64_t) -> hv_return_t;

    /// Set the value of an MSR of a vCPU
    pub fn hv_vcpu_write_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *const uint64_t) -> hv_return_t;
}

// Managing Timestamp-Counters (TSC)
extern {
    /// Synchronizes guest Timestamp-Counters (TSC) across all vCPUs
    pub fn hv_vm_sync_tsc(tsc: uint64_t) -> hv_return_t;
}

/// Type of a user virtual address
pub type hv_uvaddr_t = *const c_void;

/// Guest physical memory region permissions for hv_vm_map()
/// and hv_vm_protect()
pub type hv_memory_flags_t = uint64_t;

/// Type of a guest physical address
pub type hv_gpaddr_t = uint64_t;

// Managing Memory Regions
extern {
    /// Maps a region in the virtual address space of the current
    /// task into the guest physical address space of the VM
    pub fn hv_vm_map(uva: hv_uvaddr_t, gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t;

    /// Unmaps a region in the guest physical address space of the VM
    pub fn hv_vm_unmap(gpa: hv_gpaddr_t, size: size_t) -> hv_return_t;

    /// Modifies the permissions of a region in the guest physical
    /// address space of the VM
    pub fn hv_vm_protect(gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t;
}

/// Enum type of VMX cabability fields
#[repr(C)]
pub enum hv_vmx_capability_t {
    /// Pin-based VMX capabilities
	HV_VMX_CAP_PINBASED                           = 0,
    /// Primary proc-based VMX capabilities
	HV_VMX_CAP_PROCBASED                          = 1,
    /// Secondary proc-based VMX capabilities
	HV_VMX_CAP_PROCBASED2                         = 2,
    /// VM-entry VMX capabilities
	HV_VMX_CAP_ENTRY                              = 3,
    /// VM-exit VMX capabilities
	HV_VMX_CAP_EXIT                               = 4,
    /// VMX preemption timer frequency
	HV_VMX_CAP_PREEMPTION_TIMER                   = 32
}

// Managing Virtual Machine Control Structure (VMCS)
extern {
    /// Returns the current value of a VMCS field of a vCPU
    pub fn hv_vmx_vcpu_read_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: *mut uint64_t) -> hv_return_t;

    /// Sets the value of a VMCS field of a vCPU
    pub fn hv_vmx_vcpu_write_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: uint64_t) -> hv_return_t;

    /// Returns the VMX capabilities of the host processor
    pub fn hv_vmx_read_capability(field: hv_vmx_capability_t, value: *mut uint64_t) -> hv_return_t;

    /// Sets the address of the guest APIC for a vCPU in the
    /// guest physical address space of the VM
    pub fn hv_vmx_vcpu_set_apic_address(vcpu: hv_vcpuid_t, gpa: hv_gpaddr_t) -> hv_return_t;
}
<commit_msg>Remove tabs in osx/ffi.rs<commit_after>//! Bindings to the Hypervisor Framework

use libc::*;

pub mod consts;

/// Hypervisor Framework return code
pub type hv_return_t = uint32_t;

/// Options for hv_vcpu_create()
pub type hv_vm_options_t = uint64_t;

// Creating and Destroying VM Instances
extern {
    /// Creates a VM instance for the current task
    pub fn hv_vm_create(flags: hv_vm_options_t) -> hv_return_t;

    /// Destroys the VM instance associated with the current task
    pub fn hv_vm_destroy() -> hv_return_t;
}

/// Type of a vCPU ID
pub type hv_vcpuid_t = c_uint;

// Creating and Managing vCPU Instances
extern {
    /// Creates a vCPU instance for the current thread
    pub fn hv_vcpu_create(vcpu: *mut hv_vcpuid_t, flags: hv_vm_options_t) -> hv_return_t;

    /// Executes a vCPU
    pub fn hv_vcpu_run(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Forces an immediate VMEXIT of a set of vCPUs of the VM
    pub fn hv_vcpu_interrupt(vcpu: *const hv_vcpuid_t, vcpu_count: c_uint) -> hv_return_t;

    /// Returns the cumulative execution time of a vCPU in nanoseconds
    pub fn hv_vcpu_get_exec_time(vcpu: hv_vcpuid_t, time: *mut uint64_t) -> hv_return_t;

    /// Forces flushing of cached vCPU state
    pub fn hv_vcpu_flush(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Invalidates the TLB of a vCPU
    pub fn hv_vcpu_invalidate_tlb(vcpu: hv_vcpuid_t) -> hv_return_t;

    /// Destroys the vCPU instance associated with the current thread
    pub fn hv_vcpu_destroy(vcpu: hv_vcpuid_t) -> hv_return_t;
}

/// x86 architectural register IDs
#[repr(C)]
pub enum hv_x86_reg_t {
	HV_X86_RIP,
	HV_X86_RFLAGS,
	HV_X86_RAX,
	HV_X86_RCX,
	HV_X86_RDX,
	HV_X86_RBX,
	HV_X86_RSI,
	HV_X86_RDI,
	HV_X86_RSP,
	HV_X86_RBP,
	HV_X86_R8,
	HV_X86_R9,
	HV_X86_R10,
	HV_X86_R11,
	HV_X86_R12,
	HV_X86_R13,
	HV_X86_R14,
	HV_X86_R15,
	HV_X86_CS,
	HV_X86_SS,
	HV_X86_DS,
	HV_X86_ES,
	HV_X86_FS,
	HV_X86_GS,
	HV_X86_IDT_BASE,
	HV_X86_IDT_LIMIT,
	HV_X86_GDT_BASE,
	HV_X86_GDT_LIMIT,
	HV_X86_LDTR,
	HV_X86_LDT_BASE,
	HV_X86_LDT_LIMIT,
	HV_X86_LDT_AR,
	HV_X86_TR,
	HV_X86_TSS_BASE,
	HV_X86_TSS_LIMIT,
	HV_X86_TSS_AR,
	HV_X86_CR0,
	HV_X86_CR1,
	HV_X86_CR2,
	HV_X86_CR3,
	HV_X86_CR4,
	HV_X86_DR0,
	HV_X86_DR1,
	HV_X86_DR2,
	HV_X86_DR3,
	HV_X86_DR4,
	HV_X86_DR5,
	HV_X86_DR6,
	HV_X86_DR7,
	HV_X86_TPR,
	HV_X86_XCR0,
	HV_X86_REGISTERS_MAX,
}

// Accessing Registers
extern {
    /// Returns the current value of an architectural x86 register
    /// of a vCPU
    pub fn hv_vcpu_read_register(vcpu: hv_vcpuid_t, reg: hv_x86_reg_t, value: *mut uint64_t) -> hv_return_t;

    /// Sets the value of an architectural x86 register of a vCPU
    pub fn hv_vcpu_write_register(vcpu: hv_vcpuid_t, reg: hv_x86_reg_t, value: uint64_t) -> hv_return_t;
}

// Accessing Floating Point (FP) State
extern {
    /// Returns the current architectural x86 floating point and
    /// SIMD state of a vCPU
    pub fn hv_vcpu_read_fpstate(vcpu: hv_vcpuid_t, buffer: *mut c_void, size: size_t) -> hv_return_t;

    /// Sets the architectural x86 floating point and SIMD state of
    /// a vCPU
    pub fn hv_vcpu_write_fpstate(vcpu: hv_vcpuid_t, buffer: *const c_void, size: size_t) -> hv_return_t;
}

// Accessing Machine Specific Registers (MSRs)
extern {
    /// Enables an MSR to be used natively by the VM
    pub fn hv_vcpu_enable_native_msr(vcpu: hv_vcpuid_t, msr: uint32_t, enable: bool) -> hv_return_t;

    /// Returns the current value of an MSR of a vCPU
    pub fn hv_vcpu_read_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *mut uint64_t) -> hv_return_t;

    /// Set the value of an MSR of a vCPU
    pub fn hv_vcpu_write_msr(vcpu: hv_vcpuid_t, msr: uint32_t, value: *const uint64_t) -> hv_return_t;
}

// Managing Timestamp-Counters (TSC)
extern {
    /// Synchronizes guest Timestamp-Counters (TSC) across all vCPUs
    pub fn hv_vm_sync_tsc(tsc: uint64_t) -> hv_return_t;
}

/// Type of a user virtual address
pub type hv_uvaddr_t = *const c_void;

/// Guest physical memory region permissions for hv_vm_map()
/// and hv_vm_protect()
pub type hv_memory_flags_t = uint64_t;

/// Type of a guest physical address
pub type hv_gpaddr_t = uint64_t;

// Managing Memory Regions
extern {
    /// Maps a region in the virtual address space of the current
    /// task into the guest physical address space of the VM
    pub fn hv_vm_map(uva: hv_uvaddr_t, gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t;

    /// Unmaps a region in the guest physical address space of the VM
    pub fn hv_vm_unmap(gpa: hv_gpaddr_t, size: size_t) -> hv_return_t;

    /// Modifies the permissions of a region in the guest physical
    /// address space of the VM
    pub fn hv_vm_protect(gpa: hv_gpaddr_t, size: size_t, flags: hv_memory_flags_t) -> hv_return_t;
}

/// Enum type of VMX cabability fields
#[repr(C)]
pub enum hv_vmx_capability_t {
    /// Pin-based VMX capabilities
    HV_VMX_CAP_PINBASED                           = 0,
    /// Primary proc-based VMX capabilities
    HV_VMX_CAP_PROCBASED                          = 1,
    /// Secondary proc-based VMX capabilities
    HV_VMX_CAP_PROCBASED2                         = 2,
    /// VM-entry VMX capabilities
    HV_VMX_CAP_ENTRY                              = 3,
    /// VM-exit VMX capabilities
    HV_VMX_CAP_EXIT                               = 4,
    /// VMX preemption timer frequency
    HV_VMX_CAP_PREEMPTION_TIMER                   = 32
}

// Managing Virtual Machine Control Structure (VMCS)
extern {
    /// Returns the current value of a VMCS field of a vCPU
    pub fn hv_vmx_vcpu_read_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: *mut uint64_t) -> hv_return_t;

    /// Sets the value of a VMCS field of a vCPU
    pub fn hv_vmx_vcpu_write_vmcs(vcpu: hv_vcpuid_t, field: uint32_t, value: uint64_t) -> hv_return_t;

    /// Returns the VMX capabilities of the host processor
    pub fn hv_vmx_read_capability(field: hv_vmx_capability_t, value: *mut uint64_t) -> hv_return_t;

    /// Sets the address of the guest APIC for a vCPU in the
    /// guest physical address space of the VM
    pub fn hv_vmx_vcpu_set_apic_address(vcpu: hv_vcpuid_t, gpa: hv_gpaddr_t) -> hv_return_t;
}
<|endoftext|>