<commit_before>pub mod doc_id_set;
pub mod statistics;
pub mod planner;

use kite::query::Query;
use kite::collectors::{Collector, DocumentMatch};
use byteorder::{ByteOrder, BigEndian};

use errors::RocksDBReadError;
use key_builder::KeyBuilder;
use document_index::DocRef;
use super::RocksDBIndexReader;
use search::doc_id_set::DocIdSet;
use search::statistics::StatisticsReader;
use search::planner::{SearchPlan, plan_query};
use search::planner::boolean_query::BooleanQueryOp;
use search::planner::score_function::{CombinatorScorer, ScoreFunctionOp};

impl<'a> RocksDBIndexReader<'a> {
    fn search_chunk_boolean_phase(&self, boolean_query: &Vec<BooleanQueryOp>, is_negated: bool, chunk: u32) -> Result<DocIdSet, RocksDBReadError> {
        // Execute boolean query
        let mut stack = Vec::new();
        for op in boolean_query.iter() {
            match *op {
                BooleanQueryOp::PushEmpty => {
                    stack.push(DocIdSet::new_filled(0));
                }
                BooleanQueryOp::PushFull => {
                    stack.push(DocIdSet::new_filled(65536));
                }
                BooleanQueryOp::PushTermDirectory(field_ref, term_ref) => {
                    let kb = KeyBuilder::chunk_dir_list(chunk, field_ref.ord(), term_ref.ord());
                    match self.snapshot.get(&kb.key()) {
                        Ok(Some(docid_set)) => {
                            let data = DocIdSet::FromRDB(docid_set);
                            stack.push(data);
                        }
                        Ok(None) => stack.push(DocIdSet::new_filled(0)),
                        Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                    }
                }
                BooleanQueryOp::PushDeletionList => {
                    let kb = KeyBuilder::chunk_del_list(chunk);
                    match self.snapshot.get(&kb.key()) {
                        Ok(Some(deletion_list)) => {
                            let data = DocIdSet::FromRDB(deletion_list);
                            stack.push(data);
                        }
                        Ok(None) => stack.push(DocIdSet::new_filled(0)),
                        Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                    }
                }
                BooleanQueryOp::And => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.intersection(&b));
                }
                BooleanQueryOp::Or => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.union(&b));
                }
                BooleanQueryOp::AndNot => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.exclusion(&b));
                }
            }
        }

        if !stack.len() == 1 {
            // This shouldn't be possible unless there's a bug in the planner
            panic!("boolean query executor: stack size too big ({})", stack.len());
        }
        let mut matches = stack.pop().unwrap();

        // Invert the list if the query is negated
        if is_negated {
            let kb = KeyBuilder::chunk_stat(chunk, b"total_docs");
            let total_docs = match self.snapshot.get(&kb.key()) {
                Ok(Some(total_docs)) => BigEndian::read_i64(&total_docs) as u32,
                Ok(None) => 0,
                Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
            };

            let all_docs = DocIdSet::new_filled(total_docs);
            matches = all_docs.exclusion(&matches);
        }

        Ok(matches)
    }

    fn score_doc(&self, doc_id: u16, score_function: &Vec<ScoreFunctionOp>, chunk: u32, mut stats: &mut StatisticsReader) -> Result<f64, RocksDBReadError> {
        // Execute score function
        let mut stack = Vec::new();
        for op in score_function.iter() {
            match *op {
                ScoreFunctionOp::Literal(val) => stack.push(val),
                ScoreFunctionOp::TermScorer(field_ref, term_ref, ref scorer) => {
                    let kb = KeyBuilder::chunk_dir_list(chunk, field_ref.ord(), term_ref.ord());
                    match self.snapshot.get(&kb.key()) {
                        Ok(Some(data)) => {
                            let docid_set = DocIdSet::FromRDB(data);

                            if docid_set.contains_doc(doc_id) {
                                // Read field length
                                // TODO: we only need this for BM25
                                let kb = KeyBuilder::stored_field_value(chunk, doc_id, field_ref.ord(), b"len");
                                let field_length = match self.snapshot.get(&kb.key()) {
                                    Ok(Some(value)) => {
                                        let length_sqrt = (value[0] as f64) / 3.0 + 1.0;
                                        length_sqrt * length_sqrt
                                    }
                                    Ok(None) => 1.0,
                                    Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                                };

                                // Read term frequency
                                let mut value_type = vec![b't', b'f'];
                                value_type.extend(term_ref.ord().to_string().as_bytes());
                                let kb = KeyBuilder::stored_field_value(chunk, doc_id, field_ref.ord(), &value_type);
                                let term_frequency = match self.snapshot.get(&kb.key()) {
                                    Ok(Some(value)) => BigEndian::read_i64(&value),
                                    Ok(None) => 1,
                                    Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                                };

                                let score = scorer.similarity_model.score(1, field_length, try!(stats.total_tokens(field_ref)) as u64, try!(stats.total_docs(field_ref)) as u64, try!(stats.term_document_frequency(field_ref, term_ref)) as u64);
                                stack.push(score * scorer.boost);
                            } else {
                                stack.push(0.0f64);
                            }
                        }
                        Ok(None) => stack.push(0.0f64),
                        Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                    }
                }
                ScoreFunctionOp::CombinatorScorer(num_vals, ref scorer) => {
                    let score = match *scorer {
                        CombinatorScorer::Avg => {
                            let mut total_score = 0.0f64;

                            for _ in 0..num_vals {
                                total_score += stack.pop().expect("document scorer: stack underflow");
                            }

                            total_score / num_vals as f64
                        }
                        CombinatorScorer::Max => {
                            let mut max_score = 0.0f64;

                            for _ in 0..num_vals {
                                let score = stack.pop().expect("document scorer: stack underflow");
                                if score > max_score {
                                    max_score = score
                                }
                            }

                            max_score
                        }
                    };

                    stack.push(score);
                }
            }
        }

        if !stack.len() == 1 {
            // This shouldn't be possible unless there's a bug in the planner
            panic!("document scorer: stack size too big ({})", stack.len());
        }

        Ok(stack.pop().expect("document scorer: stack underflow"))
    }

    fn search_chunk<C: Collector>(&self, collector: &mut C, plan: &SearchPlan, chunk: u32, mut stats: &mut StatisticsReader) -> Result<(), RocksDBReadError> {
        let matches = try!(self.search_chunk_boolean_phase(&plan.boolean_query, plan.boolean_query_is_negated, chunk));

        // Score documents and pass to collector
        for doc in matches.iter() {
            let score = try!(self.score_doc(doc, &plan.score_function, chunk, &mut stats));

            let doc_ref = DocRef::from_chunk_ord(chunk, doc);
            let doc_match = DocumentMatch::new_scored(doc_ref.as_u64(), score);
            collector.collect(doc_match);
        }

        Ok(())
    }

    pub fn search<C: Collector>(&self, collector: &mut C, query: &Query) -> Result<(), RocksDBReadError> {
        // Plan query
        let plan = plan_query(&self, query, collector.needs_score());

        // Initialise statistics reader
        let mut stats = StatisticsReader::new(&self);

        // Run query on each chunk
        for chunk in self.store.chunks.iter_active(&self.snapshot) {
            try!(self.search_chunk(collector, &plan, chunk, &mut stats));
        }

        Ok(())
    }
}
<commit_msg>Pass term_frequency into similarity model<commit_after>pub mod doc_id_set;
pub mod statistics;
pub mod planner;

use kite::query::Query;
use kite::collectors::{Collector, DocumentMatch};
use byteorder::{ByteOrder, BigEndian};

use errors::RocksDBReadError;
use key_builder::KeyBuilder;
use document_index::DocRef;
use super::RocksDBIndexReader;
use search::doc_id_set::DocIdSet;
use search::statistics::StatisticsReader;
use search::planner::{SearchPlan, plan_query};
use search::planner::boolean_query::BooleanQueryOp;
use search::planner::score_function::{CombinatorScorer, ScoreFunctionOp};

impl<'a> RocksDBIndexReader<'a> {
    fn search_chunk_boolean_phase(&self, boolean_query: &Vec<BooleanQueryOp>, is_negated: bool, chunk: u32) -> Result<DocIdSet, RocksDBReadError> {
        // Execute boolean query
        let mut stack = Vec::new();
        for op in boolean_query.iter() {
            match *op {
                BooleanQueryOp::PushEmpty => {
                    stack.push(DocIdSet::new_filled(0));
                }
                BooleanQueryOp::PushFull => {
                    stack.push(DocIdSet::new_filled(65536));
                }
                BooleanQueryOp::PushTermDirectory(field_ref, term_ref) => {
                    let kb = KeyBuilder::chunk_dir_list(chunk, field_ref.ord(), term_ref.ord());
                    match self.snapshot.get(&kb.key()) {
                        Ok(Some(docid_set)) => {
                            let data = DocIdSet::FromRDB(docid_set);
                            stack.push(data);
                        }
                        Ok(None) => stack.push(DocIdSet::new_filled(0)),
                        Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                    }
                }
                BooleanQueryOp::PushDeletionList => {
                    let kb = KeyBuilder::chunk_del_list(chunk);
                    match self.snapshot.get(&kb.key()) {
                        Ok(Some(deletion_list)) => {
                            let data = DocIdSet::FromRDB(deletion_list);
                            stack.push(data);
                        }
                        Ok(None) => stack.push(DocIdSet::new_filled(0)),
                        Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                    }
                }
                BooleanQueryOp::And => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.intersection(&b));
                }
                BooleanQueryOp::Or => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.union(&b));
                }
                BooleanQueryOp::AndNot => {
                    let b = stack.pop().expect("boolean query executor: stack underflow");
                    let a = stack.pop().expect("boolean query executor: stack underflow");
                    stack.push(a.exclusion(&b));
                }
            }
        }

        if !stack.len() == 1 {
            // This shouldn't be possible unless there's a bug in the planner
            panic!("boolean query executor: stack size too big ({})", stack.len());
        }
        let mut matches = stack.pop().unwrap();

        // Invert the list if the query is negated
        if is_negated {
            let kb = KeyBuilder::chunk_stat(chunk, b"total_docs");
            let total_docs = match self.snapshot.get(&kb.key()) {
                Ok(Some(total_docs)) => BigEndian::read_i64(&total_docs) as u32,
                Ok(None) => 0,
                Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
            };

            let all_docs = DocIdSet::new_filled(total_docs);
            matches = all_docs.exclusion(&matches);
        }

        Ok(matches)
    }

    fn score_doc(&self, doc_id: u16, score_function: &Vec<ScoreFunctionOp>, chunk: u32, mut stats: &mut StatisticsReader) -> Result<f64, RocksDBReadError> {
        // Execute score function
        let mut stack = Vec::new();
        for op in score_function.iter() {
            match *op {
                ScoreFunctionOp::Literal(val) => stack.push(val),
                ScoreFunctionOp::TermScorer(field_ref, term_ref, ref scorer) => {
                    let kb = KeyBuilder::chunk_dir_list(chunk, field_ref.ord(), term_ref.ord());
                    match self.snapshot.get(&kb.key()) {
                        Ok(Some(data)) => {
                            let docid_set = DocIdSet::FromRDB(data);

                            if docid_set.contains_doc(doc_id) {
                                // Read field length
                                // TODO: we only need this for BM25
                                let kb = KeyBuilder::stored_field_value(chunk, doc_id, field_ref.ord(), b"len");
                                let field_length = match self.snapshot.get(&kb.key()) {
                                    Ok(Some(value)) => {
                                        let length_sqrt = (value[0] as f64) / 3.0 + 1.0;
                                        length_sqrt * length_sqrt
                                    }
                                    Ok(None) => 1.0,
                                    Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                                };

                                // Read term frequency
                                let mut value_type = vec![b't', b'f'];
                                value_type.extend(term_ref.ord().to_string().as_bytes());
                                let kb = KeyBuilder::stored_field_value(chunk, doc_id, field_ref.ord(), &value_type);
                                let term_frequency = match self.snapshot.get(&kb.key()) {
                                    Ok(Some(value)) => BigEndian::read_i64(&value),
                                    Ok(None) => 1,
                                    Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                                };

                                let score = scorer.similarity_model.score(term_frequency as u32, field_length, try!(stats.total_tokens(field_ref)) as u64, try!(stats.total_docs(field_ref)) as u64, try!(stats.term_document_frequency(field_ref, term_ref)) as u64);
                                stack.push(score * scorer.boost);
                            } else {
                                stack.push(0.0f64);
                            }
                        }
                        Ok(None) => stack.push(0.0f64),
                        Err(e) => return Err(RocksDBReadError::new(kb.key().to_vec(), e))
                    }
                }
                ScoreFunctionOp::CombinatorScorer(num_vals, ref scorer) => {
                    let score = match *scorer {
                        CombinatorScorer::Avg => {
                            let mut total_score = 0.0f64;

                            for _ in 0..num_vals {
                                total_score += stack.pop().expect("document scorer: stack underflow");
                            }

                            total_score / num_vals as f64
                        }
                        CombinatorScorer::Max => {
                            let mut max_score = 0.0f64;

                            for _ in 0..num_vals {
                                let score = stack.pop().expect("document scorer: stack underflow");
                                if score > max_score {
                                    max_score = score
                                }
                            }

                            max_score
                        }
                    };

                    stack.push(score);
                }
            }
        }

        if !stack.len() == 1 {
            // This shouldn't be possible unless there's a bug in the planner
            panic!("document scorer: stack size too big ({})", stack.len());
        }

        Ok(stack.pop().expect("document scorer: stack underflow"))
    }

    fn search_chunk<C: Collector>(&self, collector: &mut C, plan: &SearchPlan, chunk: u32, mut stats: &mut StatisticsReader) -> Result<(), RocksDBReadError> {
        let matches = try!(self.search_chunk_boolean_phase(&plan.boolean_query, plan.boolean_query_is_negated, chunk));

        // Score documents and pass to collector
        for doc in matches.iter() {
            let score = try!(self.score_doc(doc, &plan.score_function, chunk, &mut stats));

            let doc_ref = DocRef::from_chunk_ord(chunk, doc);
            let doc_match = DocumentMatch::new_scored(doc_ref.as_u64(), score);
            collector.collect(doc_match);
        }

        Ok(())
    }

    pub fn search<C: Collector>(&self, collector: &mut C, query: &Query) -> Result<(), RocksDBReadError> {
        // Plan query
        let plan = plan_query(&self, query, collector.needs_score());

        // Initialise statistics reader
        let mut stats = StatisticsReader::new(&self);

        // Run query on each chunk
        for chunk in self.store.chunks.iter_active(&self.snapshot) {
            try!(self.search_chunk(collector, &plan, chunk, &mut stats));
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate para_bm;

use std::time::Duration;

use para_bm::{sleep_ns};

fn fast () {
    sleep_ns(1000);
}

fn slow () {
    sleep_ns(1000000);
}

fn my_bench<F> (f: F) where F: Fn() {

    // first "throw away" run
    let mut d = Duration::span(|| {
        f();
    });
    let ns = d.num_nanoseconds().unwrap();
    println!("num nano seconds first run {}", ns);

    // iterate to get more cache hits, etc...
    for _ in 0 .. 10 {
        d = Duration::span(|| {
            f();
        });
        let ns = d.num_nanoseconds().unwrap();
        println!("num nano seconds {}", ns);
    }
}

fn main () {

    my_bench(||{
        slow()
    });

    my_bench(||{
        fast()
    });

}
<commit_msg>take an average<commit_after>extern crate para_bm;

use std::time::Duration;

use para_bm::{sleep_ns};

fn fast () {
    sleep_ns(1000);
}

fn slow () {
    sleep_ns(1000000);
}

fn my_bench<F> (f: F) where F: Fn() {

    // first "throw away" run
    let mut d = Duration::span(|| {
        f();
    });
    let ns = d.num_nanoseconds().unwrap();
    println!("num nano seconds first run {}", ns);

    let mut sum = 0;
    // iterate to get more cache hits, etc...
    for _ in 0 .. 10 {
        d = Duration::span(|| {
            f();
        });
        let ns = d.num_nanoseconds().unwrap();
        sum = sum + ns;
        println!("num nano seconds {}", ns);

    }

    let avg = (sum as f64) / 10.0;
    println!("average run {}", avg);
}

fn main () {

    my_bench(||{
        slow()
    });

    my_bench(||{
        fast()
    });

}
<|endoftext|>


<commit_before>use crate::ops::Try;
use crate::iter::LoopState;

/// An iterator able to yield elements from both ends.
///
/// Something that implements `DoubleEndedIterator` has one extra capability
/// over something that implements [`Iterator`]: the ability to also take
/// `Item`s from the back, as well as the front.
///
/// It is important to note that both back and forth work on the same range,
/// and do not cross: iteration is over when they meet in the middle.
///
/// In a similar fashion to the [`Iterator`] protocol, once a
/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again
/// may or may not ever return `Some` again. `next()` and `next_back()` are
/// interchangeable for this purpose.
///
/// [`Iterator`]: trait.Iterator.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let numbers = vec![1, 2, 3, 4, 5, 6];
///
/// let mut iter = numbers.iter();
///
/// assert_eq!(Some(&1), iter.next());
/// assert_eq!(Some(&6), iter.next_back());
/// assert_eq!(Some(&5), iter.next_back());
/// assert_eq!(Some(&2), iter.next());
/// assert_eq!(Some(&3), iter.next());
/// assert_eq!(Some(&4), iter.next());
/// assert_eq!(None, iter.next());
/// assert_eq!(None, iter.next_back());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait DoubleEndedIterator: Iterator {
    /// Removes and returns an element from the end of the iterator.
    ///
    /// Returns `None` when there are no more elements.
    ///
    /// The [trait-level] docs contain more details.
    ///
    /// [trait-level]: trait.DoubleEndedIterator.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let numbers = vec![1, 2, 3, 4, 5, 6];
    ///
    /// let mut iter = numbers.iter();
    ///
    /// assert_eq!(Some(&1), iter.next());
    /// assert_eq!(Some(&6), iter.next_back());
    /// assert_eq!(Some(&5), iter.next_back());
    /// assert_eq!(Some(&2), iter.next());
    /// assert_eq!(Some(&3), iter.next());
    /// assert_eq!(Some(&4), iter.next());
    /// assert_eq!(None, iter.next());
    /// assert_eq!(None, iter.next_back());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn next_back(&mut self) -> Option<Self::Item>;

    /// Returns the `n`th element from the end of the iterator.
    ///
    /// This is essentially the reversed version of [`nth`]. Although like most indexing
    /// operations, the count starts from zero, so `nth_back(0)` returns the first value fro
    /// the end, `nth_back(1)` the second, and so on.
    ///
    /// Note that all elements between the end and the returned element will be
    /// consumed, including the returned element. This also means that calling
    /// `nth_back(0)` multiple times on the same iterator will return different
    /// elements.
    ///
    /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the
    /// iterator.
    ///
    /// [`None`]: ../../std/option/enum.Option.html#variant.None
    /// [`nth`]: ../../std/iter/trait.Iterator.html#method.nth
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    /// assert_eq!(a.iter().nth_back(2), Some(&1));
    /// ```
    ///
    /// Calling `nth_back()` multiple times doesn't rewind the iterator:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// let mut iter = a.iter();
    ///
    /// assert_eq!(iter.nth_back(1), Some(&2));
    /// assert_eq!(iter.nth_back(1), None);
    /// ```
    ///
    /// Returning `None` if there are less than `n + 1` elements:
    ///
    /// ```
    /// let a = [1, 2, 3];
    /// assert_eq!(a.iter().nth_back(10), None);
    /// ```
    #[inline]
    #[stable(feature = "iter_nth_back", since = "1.37.0")]
    fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
        for x in self.rev() {
            if n == 0 { return Some(x) }
            n -= 1;
        }
        None
    }

    /// This is the reverse version of [`try_fold()`]: it takes elements
    /// starting from the back of the iterator.
    ///
    /// [`try_fold()`]: trait.Iterator.html#method.try_fold
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = ["1", "2", "3"];
    /// let sum = a.iter()
    ///     .map(|&s| s.parse::<i32>())
    ///     .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y)));
    /// assert_eq!(sum, Ok(6));
    /// ```
    ///
    /// Short-circuiting:
    ///
    /// ```
    /// let a = ["1", "rust", "3"];
    /// let mut it = a.iter();
    /// let sum = it
    ///     .by_ref()
    ///     .map(|&s| s.parse::<i32>())
    ///     .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y)));
    /// assert!(sum.is_err());
    ///
    /// // Because it short-circuited, the remaining elements are still
    /// // available through the iterator.
    /// assert_eq!(it.next_back(), Some(&"1"));
    /// ```
    #[inline]
    #[stable(feature = "iterator_try_fold", since = "1.27.0")]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok=B>
    {
        let mut accum = init;
        while let Some(x) = self.next_back() {
            accum = f(accum, x)?;
        }
        Try::from_ok(accum)
    }

    /// An iterator method that reduces the iterator's elements to a single,
    /// final value, starting from the back.
    ///
    /// This is the reverse version of [`fold()`]: it takes elements starting from
    /// the back of the iterator.
    ///
    /// `rfold()` takes two arguments: an initial value, and a closure with two
    /// arguments: an 'accumulator', and an element. The closure returns the value that
    /// the accumulator should have for the next iteration.
    ///
    /// The initial value is the value the accumulator will have on the first
    /// call.
    ///
    /// After applying this closure to every element of the iterator, `rfold()`
    /// returns the accumulator.
    ///
    /// This operation is sometimes called 'reduce' or 'inject'.
    ///
    /// Folding is useful whenever you have a collection of something, and want
    /// to produce a single value from it.
    ///
    /// [`fold()`]: trait.Iterator.html#method.fold
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// // the sum of all of the elements of a
    /// let sum = a.iter()
    ///            .rfold(0, |acc, &x| acc + x);
    ///
    /// assert_eq!(sum, 6);
    /// ```
    ///
    /// This example builds a string, starting with an initial value
    /// and continuing with each element from the back until the front:
    ///
    /// ```
    /// let numbers = [1, 2, 3, 4, 5];
    ///
    /// let zero = "0".to_string();
    ///
    /// let result = numbers.iter().rfold(zero, |acc, &x| {
    ///     format!("({} + {})", x, acc)
    /// });
    ///
    /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
    /// ```
    #[inline]
    #[stable(feature = "iter_rfold", since = "1.27.0")]
    fn rfold<B, F>(mut self, accum: B, f: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> B,
    {
        #[inline]
        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
            move |acc, x| Ok(f(acc, x))
        }

        self.try_rfold(accum, ok(f)).unwrap()
    }

    /// Searches for an element of an iterator from the back that satisfies a predicate.
    ///
    /// `rfind()` takes a closure that returns `true` or `false`. It applies
    /// this closure to each element of the iterator, starting at the end, and if any
    /// of them return `true`, then `rfind()` returns [`Some(element)`]. If they all return
    /// `false`, it returns [`None`].
    ///
    /// `rfind()` is short-circuiting; in other words, it will stop processing
    /// as soon as the closure returns `true`.
    ///
    /// Because `rfind()` takes a reference, and many iterators iterate over
    /// references, this leads to a possibly confusing situation where the
    /// argument is a double reference. You can see this effect in the
    /// examples below, with `&&x`.
    ///
    /// [`Some(element)`]: ../../std/option/enum.Option.html#variant.Some
    /// [`None`]: ../../std/option/enum.Option.html#variant.None
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2));
    ///
    /// assert_eq!(a.iter().rfind(|&&x| x == 5), None);
    /// ```
    ///
    /// Stopping at the first `true`:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// let mut iter = a.iter();
    ///
    /// assert_eq!(iter.rfind(|&&x| x == 2), Some(&2));
    ///
    /// // we can still use `iter`, as there are more elements.
    /// assert_eq!(iter.next_back(), Some(&1));
    /// ```
    #[inline]
    #[stable(feature = "iter_rfind", since = "1.27.0")]
    fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        Self: Sized,
        P: FnMut(&Self::Item) -> bool
    {
        #[inline]
        fn check<T>(
            mut predicate: impl FnMut(&T) -> bool,
        ) -> impl FnMut((), T) -> LoopState<(), T> {
            move |(), x| {
                if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) }
            }
        }

        self.try_rfold((), check(predicate)).break_value()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
    fn next_back(&mut self) -> Option<I::Item> {
        (**self).next_back()
    }
    fn nth_back(&mut self, n: usize) -> Option<I::Item> {
        (**self).nth_back(n)
    }
}
<commit_msg>Fix typo in DoubleEndedIterator::nth_back doc<commit_after>use crate::ops::Try;
use crate::iter::LoopState;

/// An iterator able to yield elements from both ends.
///
/// Something that implements `DoubleEndedIterator` has one extra capability
/// over something that implements [`Iterator`]: the ability to also take
/// `Item`s from the back, as well as the front.
///
/// It is important to note that both back and forth work on the same range,
/// and do not cross: iteration is over when they meet in the middle.
///
/// In a similar fashion to the [`Iterator`] protocol, once a
/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again
/// may or may not ever return `Some` again. `next()` and `next_back()` are
/// interchangeable for this purpose.
///
/// [`Iterator`]: trait.Iterator.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// let numbers = vec![1, 2, 3, 4, 5, 6];
///
/// let mut iter = numbers.iter();
///
/// assert_eq!(Some(&1), iter.next());
/// assert_eq!(Some(&6), iter.next_back());
/// assert_eq!(Some(&5), iter.next_back());
/// assert_eq!(Some(&2), iter.next());
/// assert_eq!(Some(&3), iter.next());
/// assert_eq!(Some(&4), iter.next());
/// assert_eq!(None, iter.next());
/// assert_eq!(None, iter.next_back());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait DoubleEndedIterator: Iterator {
    /// Removes and returns an element from the end of the iterator.
    ///
    /// Returns `None` when there are no more elements.
    ///
    /// The [trait-level] docs contain more details.
    ///
    /// [trait-level]: trait.DoubleEndedIterator.html
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let numbers = vec![1, 2, 3, 4, 5, 6];
    ///
    /// let mut iter = numbers.iter();
    ///
    /// assert_eq!(Some(&1), iter.next());
    /// assert_eq!(Some(&6), iter.next_back());
    /// assert_eq!(Some(&5), iter.next_back());
    /// assert_eq!(Some(&2), iter.next());
    /// assert_eq!(Some(&3), iter.next());
    /// assert_eq!(Some(&4), iter.next());
    /// assert_eq!(None, iter.next());
    /// assert_eq!(None, iter.next_back());
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn next_back(&mut self) -> Option<Self::Item>;

    /// Returns the `n`th element from the end of the iterator.
    ///
    /// This is essentially the reversed version of [`nth`]. Although like most indexing
    /// operations, the count starts from zero, so `nth_back(0)` returns the first value from
    /// the end, `nth_back(1)` the second, and so on.
    ///
    /// Note that all elements between the end and the returned element will be
    /// consumed, including the returned element. This also means that calling
    /// `nth_back(0)` multiple times on the same iterator will return different
    /// elements.
    ///
    /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the
    /// iterator.
    ///
    /// [`None`]: ../../std/option/enum.Option.html#variant.None
    /// [`nth`]: ../../std/iter/trait.Iterator.html#method.nth
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    /// assert_eq!(a.iter().nth_back(2), Some(&1));
    /// ```
    ///
    /// Calling `nth_back()` multiple times doesn't rewind the iterator:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// let mut iter = a.iter();
    ///
    /// assert_eq!(iter.nth_back(1), Some(&2));
    /// assert_eq!(iter.nth_back(1), None);
    /// ```
    ///
    /// Returning `None` if there are less than `n + 1` elements:
    ///
    /// ```
    /// let a = [1, 2, 3];
    /// assert_eq!(a.iter().nth_back(10), None);
    /// ```
    #[inline]
    #[stable(feature = "iter_nth_back", since = "1.37.0")]
    fn nth_back(&mut self, mut n: usize) -> Option<Self::Item> {
        for x in self.rev() {
            if n == 0 { return Some(x) }
            n -= 1;
        }
        None
    }

    /// This is the reverse version of [`try_fold()`]: it takes elements
    /// starting from the back of the iterator.
    ///
    /// [`try_fold()`]: trait.Iterator.html#method.try_fold
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = ["1", "2", "3"];
    /// let sum = a.iter()
    ///     .map(|&s| s.parse::<i32>())
    ///     .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y)));
    /// assert_eq!(sum, Ok(6));
    /// ```
    ///
    /// Short-circuiting:
    ///
    /// ```
    /// let a = ["1", "rust", "3"];
    /// let mut it = a.iter();
    /// let sum = it
    ///     .by_ref()
    ///     .map(|&s| s.parse::<i32>())
    ///     .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y)));
    /// assert!(sum.is_err());
    ///
    /// // Because it short-circuited, the remaining elements are still
    /// // available through the iterator.
    /// assert_eq!(it.next_back(), Some(&"1"));
    /// ```
    #[inline]
    #[stable(feature = "iterator_try_fold", since = "1.27.0")]
    fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> R,
        R: Try<Ok=B>
    {
        let mut accum = init;
        while let Some(x) = self.next_back() {
            accum = f(accum, x)?;
        }
        Try::from_ok(accum)
    }

    /// An iterator method that reduces the iterator's elements to a single,
    /// final value, starting from the back.
    ///
    /// This is the reverse version of [`fold()`]: it takes elements starting from
    /// the back of the iterator.
    ///
    /// `rfold()` takes two arguments: an initial value, and a closure with two
    /// arguments: an 'accumulator', and an element. The closure returns the value that
    /// the accumulator should have for the next iteration.
    ///
    /// The initial value is the value the accumulator will have on the first
    /// call.
    ///
    /// After applying this closure to every element of the iterator, `rfold()`
    /// returns the accumulator.
    ///
    /// This operation is sometimes called 'reduce' or 'inject'.
    ///
    /// Folding is useful whenever you have a collection of something, and want
    /// to produce a single value from it.
    ///
    /// [`fold()`]: trait.Iterator.html#method.fold
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// // the sum of all of the elements of a
    /// let sum = a.iter()
    ///            .rfold(0, |acc, &x| acc + x);
    ///
    /// assert_eq!(sum, 6);
    /// ```
    ///
    /// This example builds a string, starting with an initial value
    /// and continuing with each element from the back until the front:
    ///
    /// ```
    /// let numbers = [1, 2, 3, 4, 5];
    ///
    /// let zero = "0".to_string();
    ///
    /// let result = numbers.iter().rfold(zero, |acc, &x| {
    ///     format!("({} + {})", x, acc)
    /// });
    ///
    /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))");
    /// ```
    #[inline]
    #[stable(feature = "iter_rfold", since = "1.27.0")]
    fn rfold<B, F>(mut self, accum: B, f: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> B,
    {
        #[inline]
        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
            move |acc, x| Ok(f(acc, x))
        }

        self.try_rfold(accum, ok(f)).unwrap()
    }

    /// Searches for an element of an iterator from the back that satisfies a predicate.
    ///
    /// `rfind()` takes a closure that returns `true` or `false`. It applies
    /// this closure to each element of the iterator, starting at the end, and if any
    /// of them return `true`, then `rfind()` returns [`Some(element)`]. If they all return
    /// `false`, it returns [`None`].
    ///
    /// `rfind()` is short-circuiting; in other words, it will stop processing
    /// as soon as the closure returns `true`.
    ///
    /// Because `rfind()` takes a reference, and many iterators iterate over
    /// references, this leads to a possibly confusing situation where the
    /// argument is a double reference. You can see this effect in the
    /// examples below, with `&&x`.
    ///
    /// [`Some(element)`]: ../../std/option/enum.Option.html#variant.Some
    /// [`None`]: ../../std/option/enum.Option.html#variant.None
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2));
    ///
    /// assert_eq!(a.iter().rfind(|&&x| x == 5), None);
    /// ```
    ///
    /// Stopping at the first `true`:
    ///
    /// ```
    /// let a = [1, 2, 3];
    ///
    /// let mut iter = a.iter();
    ///
    /// assert_eq!(iter.rfind(|&&x| x == 2), Some(&2));
    ///
    /// // we can still use `iter`, as there are more elements.
    /// assert_eq!(iter.next_back(), Some(&1));
    /// ```
    #[inline]
    #[stable(feature = "iter_rfind", since = "1.27.0")]
    fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
    where
        Self: Sized,
        P: FnMut(&Self::Item) -> bool
    {
        #[inline]
        fn check<T>(
            mut predicate: impl FnMut(&T) -> bool,
        ) -> impl FnMut((), T) -> LoopState<(), T> {
            move |(), x| {
                if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) }
            }
        }

        self.try_rfold((), check(predicate)).break_value()
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
    fn next_back(&mut self) -> Option<I::Item> {
        (**self).next_back()
    }
    fn nth_back(&mut self, n: usize) -> Option<I::Item> {
        (**self).nth_back(n)
    }
}
<|endoftext|>


<commit_before>crate mod transcribe;
crate mod macro_check;
crate mod macro_parser;
crate mod macro_rules;
crate mod quoted;
<commit_msg>docstring for mbe module<commit_after>//! This module implements declarative macros: old `macro_rules` and the newer
//! `macro`. Declarative macros are also known as "macro by example", and that's
//! why we call this module `mbe`. For external documentation, prefer the
//! official terminology: "declarative macros".

crate mod transcribe;
crate mod macro_check;
crate mod macro_parser;
crate mod macro_rules;
crate mod quoted;
<|endoftext|>


<commit_before>/// 12.230s on A4-5000 (1.5 GHz)
extern crate crypto;
use crypto::digest::Digest;
use crypto::md5::Md5;

fn main() { println!("{}", get_answer("iwrupvqb")); }

/// Computes the md5_hash of a string and returns true if it starts with six zeroes.
fn hash_is_match(input: &str) -> bool {
    let mut sh = Md5::new();
    sh.input_str(input);
    sh.result_str().starts_with("000000")
}

/// Continually hashes keys until the first key succeeds the `check_hash()` function.
fn get_answer(input: &str) -> usize {
    (1..).skip_while(|x| !hash_is_match(&format!("{}{:05}", input, x))).take(1).next().unwrap()
}
<commit_msg>Further Simplify Day 04<commit_after>/// 12.230s on A4-5000 (1.5 GHz)
extern crate crypto;
use crypto::digest::Digest;
use crypto::md5::Md5;

const KEY: &'static str = "iwrupvqb";

/// Continually hashes keys until the first key succeeds the `hash_matched()` function.
fn main() { println!("{}", (1..).skip_while(|x| !hash_matched(x)).take(1).next().unwrap()); }

/// Computes the md5_hash of a string and returns true if it starts with six zeroes.
fn hash_matched(input: &usize) -> bool {
    let mut sh = Md5::new();
    sh.input_str(&format!("{}{}", KEY, *input));
    sh.result_str().starts_with("000000")
}
<|endoftext|>


<commit_before>use super::bls::PublicKey;
use super::Hash256;
use crate::test_utils::TestRandom;
use rand::RngCore;
use ssz::{Decodable, DecodeError, Encodable, SszStream};

const STATUS_FLAG_INITIATED_EXIT: u8 = 1;
const STATUS_FLAG_WITHDRAWABLE: u8 = 2;

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum StatusFlags {
    InitiatedExit,
    Withdrawable,
}

impl From<u8> for StatusFlags {
    fn from(status_flag: u8) -> Self {
        match status_flag {
            STATUS_FLAG_INITIATED_EXIT => StatusFlags::InitiatedExit,
            STATUS_FLAG_WITHDRAWABLE => StatusFlags::Withdrawable,
            _ => unreachable!(),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct ValidatorRecord {
    pub pubkey: PublicKey,
    pub withdrawal_credentials: Hash256,
    pub randao_commitment: Hash256,
    pub randao_layers: u64,
    pub activation_slot: u64,
    pub exit_slot: u64,
    pub withdrawal_slot: u64,
    pub penalized_slot: u64,
    pub exit_count: u64,
    pub status_flags: Option<StatusFlags>,
    pub custody_commitment: Hash256,
    pub latest_custody_reseed_slot: u64,
    pub penultimate_custody_reseed_slot: u64,
}

impl ValidatorRecord {
    pub fn is_active_at(&self, slot: u64) -> bool {
        self.activation_slot <= slot && slot < self.exit_slot
    }
}

impl Default for ValidatorRecord {
    fn default() -> Self {
        Self {
            pubkey: PublicKey::default(),
            withdrawal_credentials: Hash256::default(),
            randao_commitment: Hash256::default(),
            randao_layers: 0,
            activation_slot: std::u64::MAX,
            exit_slot: std::u64::MAX,
            withdrawal_slot: std::u64::MAX,
            penalized_slot: std::u64::MAX,
            exit_count: 0,
            status_flags: None,
            custody_commitment: Hash256::default(),
            latest_custody_reseed_slot: 0, // NOTE: is `GENESIS_SLOT`
            penultimate_custody_reseed_slot: 0, // NOTE: is `GENESIS_SLOT`
        }
    }
}

impl Encodable for StatusFlags {
    fn ssz_append(&self, s: &mut SszStream) {
        let byte: u8 = match self {
            StatusFlags::InitiatedExit => STATUS_FLAG_INITIATED_EXIT,
            StatusFlags::Withdrawable => STATUS_FLAG_WITHDRAWABLE,
        };
        s.append(&byte);
    }
}

impl Decodable for StatusFlags {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (byte, i) = u8::ssz_decode(bytes, i)?;
        let status = match byte {
            1 => StatusFlags::InitiatedExit,
            2 => StatusFlags::Withdrawable,
            _ => return Err(DecodeError::Invalid),
        };
        Ok((status, i))
    }
}

impl<T: RngCore> TestRandom<T> for StatusFlags {
    fn random_for_test(rng: &mut T) -> Self {
        let options = vec![StatusFlags::InitiatedExit, StatusFlags::Withdrawable];
        options[(rng.next_u32() as usize) % options.len()].clone()
    }
}

impl Encodable for ValidatorRecord {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append(&self.pubkey);
        s.append(&self.withdrawal_credentials);
        s.append(&self.randao_commitment);
        s.append(&self.randao_layers);
        s.append(&self.activation_slot);
        s.append(&self.exit_slot);
        s.append(&self.withdrawal_slot);
        s.append(&self.penalized_slot);
        s.append(&self.exit_count);
        if let Some(status_flags) = self.status_flags {
            s.append(&status_flags);
        } else {
            s.append(&(0 as u8));
        }
        s.append(&self.custody_commitment);
        s.append(&self.latest_custody_reseed_slot);
        s.append(&self.penultimate_custody_reseed_slot);
    }
}

impl Decodable for ValidatorRecord {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
        let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?;
        let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
        let (randao_layers, i) = <_>::ssz_decode(bytes, i)?;
        let (activation_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (exit_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (withdrawal_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (penalized_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (exit_count, i) = <_>::ssz_decode(bytes, i)?;
        let (status_flags_byte, i): (u8, usize) = <_>::ssz_decode(bytes, i)?;
        let (custody_commitment, i) = <_>::ssz_decode(bytes, i)?;
        let (latest_custody_reseed_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (penultimate_custody_reseed_slot, i) = <_>::ssz_decode(bytes, i)?;

        let status_flags = if status_flags_byte == 0u8 {
            None
        } else {
            Some(StatusFlags::from(status_flags_byte))
        };

        Ok((
            Self {
                pubkey,
                withdrawal_credentials,
                randao_commitment,
                randao_layers,
                activation_slot,
                exit_slot,
                withdrawal_slot,
                penalized_slot,
                exit_count,
                status_flags,
                custody_commitment,
                latest_custody_reseed_slot,
                penultimate_custody_reseed_slot,
            },
            i,
        ))
    }
}

impl<T: RngCore> TestRandom<T> for ValidatorRecord {
    fn random_for_test(rng: &mut T) -> Self {
        Self {
            pubkey: <_>::random_for_test(rng),
            withdrawal_credentials: <_>::random_for_test(rng),
            randao_commitment: <_>::random_for_test(rng),
            randao_layers: <_>::random_for_test(rng),
            exit_count: <_>::random_for_test(rng),
            status_flags: Some(<_>::random_for_test(rng)),
            custody_commitment: <_>::random_for_test(rng),
            latest_custody_reseed_slot: <_>::random_for_test(rng),
            penultimate_custody_reseed_slot: <_>::random_for_test(rng),
            ..Self::default()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::ssz::ssz_encode;
    use super::*;
    use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};

    #[test]
    pub fn test_ssz_round_trip() {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let original = ValidatorRecord::random_for_test(&mut rng);

        let bytes = ssz_encode(&original);
        let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();

        assert_eq!(original, decoded);
    }

    #[test]
    pub fn test_validator_status_ssz_round_trip() {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let original = StatusFlags::random_for_test(&mut rng);

        let bytes = ssz_encode(&original);
        let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();

        assert_eq!(original, decoded);
    }

    #[test]
    fn test_validator_can_be_active() {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let mut validator = ValidatorRecord::random_for_test(&mut rng);

        let activation_slot = u64::random_for_test(&mut rng);
        let exit_slot = activation_slot + 234;

        validator.activation_slot = activation_slot;
        validator.exit_slot = exit_slot;

        for slot in (activation_slot - 100)..(exit_slot + 100) {
            if slot < activation_slot {
                assert!(!validator.is_active_at(slot));
            } else if slot >= exit_slot {
                assert!(!validator.is_active_at(slot));
            } else {
                assert!(validator.is_active_at(slot));
            }
        }
    }
}
<commit_msg>Simplify how the `StatusFlags` are handled wrt serialization<commit_after>use super::bls::PublicKey;
use super::Hash256;
use crate::test_utils::TestRandom;
use rand::RngCore;
use ssz::{Decodable, DecodeError, Encodable, SszStream};

const STATUS_FLAG_INITIATED_EXIT: u8 = 1;
const STATUS_FLAG_WITHDRAWABLE: u8 = 2;

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum StatusFlags {
    InitiatedExit,
    Withdrawable,
}

struct StatusFlagsDecodeError;

impl From<StatusFlagsDecodeError> for DecodeError {
    fn from(_: StatusFlagsDecodeError) -> DecodeError {
        DecodeError::Invalid
    }
}

fn status_flag_to_byte(flag: Option<StatusFlags>) -> u8 {
    if let Some(flag) = flag {
        match flag {
            StatusFlags::InitiatedExit => STATUS_FLAG_INITIATED_EXIT,
            StatusFlags::Withdrawable => STATUS_FLAG_WITHDRAWABLE,
        }
    } else {
        0
    }
}

fn status_flag_from_byte(flag: u8) -> Result<Option<StatusFlags>, StatusFlagsDecodeError> {
    match flag {
        0 => Ok(None),
        1 => Ok(Some(StatusFlags::InitiatedExit)),
        2 => Ok(Some(StatusFlags::Withdrawable)),
        _ => Err(StatusFlagsDecodeError),
    }
}

#[derive(Debug, Clone, PartialEq)]
pub struct ValidatorRecord {
    pub pubkey: PublicKey,
    pub withdrawal_credentials: Hash256,
    pub randao_commitment: Hash256,
    pub randao_layers: u64,
    pub activation_slot: u64,
    pub exit_slot: u64,
    pub withdrawal_slot: u64,
    pub penalized_slot: u64,
    pub exit_count: u64,
    pub status_flags: Option<StatusFlags>,
    pub custody_commitment: Hash256,
    pub latest_custody_reseed_slot: u64,
    pub penultimate_custody_reseed_slot: u64,
}

impl ValidatorRecord {
    pub fn is_active_at(&self, slot: u64) -> bool {
        self.activation_slot <= slot && slot < self.exit_slot
    }
}

impl Default for ValidatorRecord {
    fn default() -> Self {
        Self {
            pubkey: PublicKey::default(),
            withdrawal_credentials: Hash256::default(),
            randao_commitment: Hash256::default(),
            randao_layers: 0,
            activation_slot: std::u64::MAX,
            exit_slot: std::u64::MAX,
            withdrawal_slot: std::u64::MAX,
            penalized_slot: std::u64::MAX,
            exit_count: 0,
            status_flags: None,
            custody_commitment: Hash256::default(),
            latest_custody_reseed_slot: 0, // NOTE: is `GENESIS_SLOT`
            penultimate_custody_reseed_slot: 0, // NOTE: is `GENESIS_SLOT`
        }
    }
}

impl<T: RngCore> TestRandom<T> for StatusFlags {
    fn random_for_test(rng: &mut T) -> Self {
        let options = vec![StatusFlags::InitiatedExit, StatusFlags::Withdrawable];
        options[(rng.next_u32() as usize) % options.len()].clone()
    }
}

impl Encodable for ValidatorRecord {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append(&self.pubkey);
        s.append(&self.withdrawal_credentials);
        s.append(&self.randao_commitment);
        s.append(&self.randao_layers);
        s.append(&self.activation_slot);
        s.append(&self.exit_slot);
        s.append(&self.withdrawal_slot);
        s.append(&self.penalized_slot);
        s.append(&self.exit_count);
        s.append(&status_flag_to_byte(self.status_flags));
        s.append(&self.custody_commitment);
        s.append(&self.latest_custody_reseed_slot);
        s.append(&self.penultimate_custody_reseed_slot);
    }
}

impl Decodable for ValidatorRecord {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (pubkey, i) = <_>::ssz_decode(bytes, i)?;
        let (withdrawal_credentials, i) = <_>::ssz_decode(bytes, i)?;
        let (randao_commitment, i) = <_>::ssz_decode(bytes, i)?;
        let (randao_layers, i) = <_>::ssz_decode(bytes, i)?;
        let (activation_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (exit_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (withdrawal_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (penalized_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (exit_count, i) = <_>::ssz_decode(bytes, i)?;
        let (status_flags_byte, i): (u8, usize) = <_>::ssz_decode(bytes, i)?;
        let (custody_commitment, i) = <_>::ssz_decode(bytes, i)?;
        let (latest_custody_reseed_slot, i) = <_>::ssz_decode(bytes, i)?;
        let (penultimate_custody_reseed_slot, i) = <_>::ssz_decode(bytes, i)?;

        let status_flags = status_flag_from_byte(status_flags_byte)?;

        Ok((
            Self {
                pubkey,
                withdrawal_credentials,
                randao_commitment,
                randao_layers,
                activation_slot,
                exit_slot,
                withdrawal_slot,
                penalized_slot,
                exit_count,
                status_flags,
                custody_commitment,
                latest_custody_reseed_slot,
                penultimate_custody_reseed_slot,
            },
            i,
        ))
    }
}

impl<T: RngCore> TestRandom<T> for ValidatorRecord {
    fn random_for_test(rng: &mut T) -> Self {
        Self {
            pubkey: <_>::random_for_test(rng),
            withdrawal_credentials: <_>::random_for_test(rng),
            randao_commitment: <_>::random_for_test(rng),
            randao_layers: <_>::random_for_test(rng),
            exit_count: <_>::random_for_test(rng),
            status_flags: Some(<_>::random_for_test(rng)),
            custody_commitment: <_>::random_for_test(rng),
            latest_custody_reseed_slot: <_>::random_for_test(rng),
            penultimate_custody_reseed_slot: <_>::random_for_test(rng),
            ..Self::default()
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::ssz::ssz_encode;
    use super::*;
    use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};

    #[test]
    pub fn test_ssz_round_trip() {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let original = ValidatorRecord::random_for_test(&mut rng);

        let bytes = ssz_encode(&original);
        let (decoded, _) = <_>::ssz_decode(&bytes, 0).unwrap();

        assert_eq!(original, decoded);
    }

    #[test]
    fn test_validator_can_be_active() {
        let mut rng = XorShiftRng::from_seed([42; 16]);
        let mut validator = ValidatorRecord::random_for_test(&mut rng);

        let activation_slot = u64::random_for_test(&mut rng);
        let exit_slot = activation_slot + 234;

        validator.activation_slot = activation_slot;
        validator.exit_slot = exit_slot;

        for slot in (activation_slot - 100)..(exit_slot + 100) {
            if slot < activation_slot {
                assert!(!validator.is_active_at(slot));
            } else if slot >= exit_slot {
                assert!(!validator.is_active_at(slot));
            } else {
                assert!(validator.is_active_at(slot));
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

generate_error_module!(
    generate_error_types!(AnnotationError, AnnotationErrorKind,
        StoreReadError         => "Store read error",
        StoreWriteError        => "Store write error",
        StoreIdGenerationError => "Error generating StoreId object",

        LinkError              => "Link error",
        LinkingError           => "Error while linking"

    );
);

pub use self::error::AnnotationError;
pub use self::error::AnnotationErrorKind;
pub use self::error::MapErrInto;

<commit_msg>Rewrite error module<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

generate_error_module!(
    generate_error_types!(AnnotationError, AnnotationErrorKind,
        StoreReadError   => "Store read error",
        StoreWriteError  => "Store write error",

        LinkingError     => "Error while linking",
        HeaderWriteError => "Couldn't write Header for annotation"
    );
);

pub use self::error::AnnotationError;
pub use self::error::AnnotationErrorKind;
pub use self::error::MapErrInto;

<|endoftext|>


<commit_before>use std::time::Duration;

pub struct TimeoutUtils {}

impl TimeoutUtils {
    pub fn short_timeout() -> Duration {
        Duration::from_secs(5)
    }

    pub fn medium_timeout() -> Duration {
        Duration::from_secs(10)
    }

    pub fn long_timeout() -> Duration {
        Duration::from_secs(100)
    }
}<commit_msg>Increase test timeouts (medium and long x2).<commit_after>use std::time::Duration;

pub struct TimeoutUtils {}

impl TimeoutUtils {
    pub fn short_timeout() -> Duration {
        Duration::from_secs(5)
    }

    pub fn medium_timeout() -> Duration {
        Duration::from_secs(20)
    }

    pub fn long_timeout() -> Duration {
        Duration::from_secs(200)
    }
}<|endoftext|>


<commit_before>use time;
use std::rand;
use std::rand::Rng;
use std::mem;

use cgmath::point::{Point2};
use cgmath::vector::{Vec2};
use cgmath::aabb::{Aabb2};
use color::rgb::consts::*;

use calx::app::App;
use calx::app;
use calx::renderer::Renderer;
use calx::renderer;
use calx::rectutil::RectUtil;

use area::{Location, Area, uphill, DijkstraMap, DIRECTIONS6};
use dijkstra;
use area;
use areaview;
use fov::Fov;
use fov;
use mapgen::MapGen;
use mob;
use mob::Mob;
use transform::Transform;
use sprite;

// XXX: Indiscriminate blob of stuff ahoy
pub struct Game {
    area: ~Area,
    pos: Location,
    seen: ~Fov,
    remembered: ~Fov,
    mobs: ~[Mob],
    player_dijkstra: Option<DijkstraMap>,
    rng: rand::StdRng,
    stop: bool,
    depth: uint,
}

static GUN_RANGE: uint = 8;

// Smart action in a given direction
pub enum ProbeResult {
    // Free to walk, nothing to attack.
    Move,
    // Can't walk nor attack.
    Blocked,
    // Something next to you, melee attack.
    Melee(uint),
    // Something in the distance, can shoot it.
    Ranged(uint),
}

impl Game {
    pub fn new() -> Game {
        let mut ret = Game {
            area: ~Area::new(area::Rock),
            pos: Location(Point2::new(0i8, 0i8)),
            seen: ~Fov::new(),
            remembered: ~Fov::new(),
            mobs: ~[],
            player_dijkstra: None,
            rng: rand::rng(),
            stop: true,
            depth: 0,
        };
        ret.next_level();
        ret
    }

    pub fn player<'a>(&'a mut self) -> &'a mut Mob {
        for i in self.mobs.mut_iter() {
            if i.t == mob::Player {
                return i;
            }
        }
        fail!("No player mob");
    }

    pub fn player_idx(&self) -> uint {
        for (i, mob) in self.mobs.iter().enumerate() {
            if mob.t == mob::Player {
                return i;
            }
        }
        fail!("No player mob");
    }

    pub fn open_cells(&self) -> ~[Location] {
        let mut ret = ~[];
        for &loc in self.area.iter() {
            if self.area.get(loc).is_walkable() && self.mob_at(loc).is_none() {
                ret.push(loc);
            }
        }
        ret
    }

    pub fn has_player(&self) -> bool {
        for i in self.mobs.iter() {
            if i.t == mob::Player {
                return true;
            }
        }
        false
    }

    pub fn mob_idx_at<'a>(&'a self, loc: Location) -> Option<uint> {
        for (i, mob) in self.mobs.iter().enumerate() {
            if mob.loc == loc && mob.is_alive() {
                return Some(i);
            }
        }
        None
    }

    pub fn drawable_mob_at<'a>(&'a self, loc: Location) -> Option<&'a Mob> {
        let mut ret = None;
        for i in self.mobs.iter() {
            if i.loc == loc {
                // Make sure you show up the live mob if there's a live
                // one and corpses here.
                if i.is_alive() || ret.is_none() { ret = Some(i); }
            }
        }
        ret
    }

    pub fn mob_at<'a>(&'a self, loc: Location) -> Option<&'a Mob> {
        for i in self.mobs.iter() {
            if i.loc == loc && i.is_alive() {
                return Some(i);
            }
        }
        None
    }

    pub fn mob_at_mut<'a>(&'a mut self, loc: Location) -> Option<&'a mut Mob> {
        for i in self.mobs.mut_iter() {
            if i.loc == loc {
                return Some(i);
            }
        }
        None
    }

    pub fn next_level(&mut self) {
        // Player state doesn't persist level-to-level.
        self.mobs = ~[Mob::new(mob::Player, Location(Point2::new(0i8, 0i8)))];
        self.area = ~Area::new(area::Rock);
        self.area.gen_cave(&mut self.rng);
        self.depth += 1;

        self.player().loc = Location(Point2::new(0i8, 0i8));

        let sites = self.open_cells();
        for &spawn_loc in self.rng.sample(sites.iter(), 6 + self.depth).iter() {
            // TODO: Minimal depth consideration.
            // TODO: Special spawn logic for the boss.
            let kind = self.rng.choose(
                &[mob::Morlock, mob::BigMorlock, mob::BurrowingMorlock, mob::Centipede]);
            self.mobs.push(Mob::new(kind, *spawn_loc));
        }

        self.seen = ~Fov::new();
        self.remembered = ~Fov::new();
    }

    pub fn area_name(&self) -> ~str {
        format!("Floor {}", self.depth)
    }

    pub fn object_name(&self, loc: Location) -> ~str {
        match self.mob_at(loc) {
            Some(mob) => mob.data().name,
            None => ~"",
        }
    }

    pub fn attack(&mut self, _agent_idx: uint, target_idx: uint) {
        // TODO: More interesting logic.
        //self.mobs.remove(target_idx);
        let mob = &mut self.mobs[target_idx];
        mob.hits -= 1;

        if mob.hits > 0 {
            mob.anim_state = mob::Hurt(time::precise_time_s());
        } else {
            mob.anim_state = mob::Dying(time::precise_time_s());
        }
    }

    pub fn is_walkable(&self, loc: Location) -> bool {
        self.area.get(loc).is_walkable() && self.mob_idx_at(loc).is_none()
    }

    pub fn melee_probe_dir(&self, mob_idx: uint, dir: &Vec2<int>) -> ProbeResult {
        let loc = self.mobs[mob_idx].loc + *dir;
        let mut walk_state = Move;

        match self.mob_idx_at(loc) {
            Some(mob_idx) => { return Melee(mob_idx); },
            _ => ()
        };

        if !self.area.get(loc).is_walkable() {
            walk_state = Blocked;
        }

        walk_state
    }

    pub fn probe_dir(&self, dir: &Vec2<int>) -> ProbeResult {
        let mut loc = self.mobs[self.player_idx()].loc + *dir;
        let mut walk_state = Move;

        match self.mob_idx_at(loc) {
            Some(mob_idx) => { return Melee(mob_idx); },
            _ => ()
        };

        if !self.area.get(loc).is_walkable() {
            walk_state = Blocked;
        }

        if self.area.get(loc).blocks_shot() {
            return walk_state;
        }

        for _ in range(1, GUN_RANGE) {
            loc = loc + *dir;

            match self.mob_idx_at(loc) {
                Some(mob_idx) => { return Ranged(mob_idx); },
                _ => ()
            };

            if self.area.get(loc).blocks_shot() {
                return walk_state;
            }
        }

        walk_state
    }

    pub fn walk_neighbors(&self, loc: Location) -> ~[Location] {
        let mut ret = ~[];
        for &v in DIRECTIONS6.iter() {
            if self.is_walkable(loc + v) {
               ret.push(loc + v);
            }
        }
        ret
    }

    pub fn msg(&mut self, _txt: &str) {
        // TODO
    }

    pub fn pass(&mut self) {
        let player_idx = self.player_idx();
        if self.mobs[player_idx].ammo < 6 {
            self.msg("reload");
            self.mobs[player_idx].ammo += 1;
        }
        self.update();
    }

    pub fn smart_move(&mut self, dirs: &[Vec2<int>]) -> bool {
        let player_idx = self.player_idx();

        for d in dirs.iter() {
            match self.probe_dir(d) {
                Blocked => { continue; },
                Move => {
                    let new_loc = self.player().loc + *d;
                    self.player().loc = new_loc;
                    if self.area.get(new_loc) == area::Downstairs {
                        self.next_level();
                    }
                    self.update();
                    return true;
                },
                Melee(mob_idx) => {
                    self.attack(player_idx, mob_idx);
                    self.update();
                    return true;
                },
                Ranged(mob_idx) => {
                    if self.mobs[player_idx].ammo > 0 {
                        self.attack(player_idx, mob_idx);
                        self.mobs[player_idx].ammo -= 1;
                    } else {
                        self.msg("reload");
                        self.mobs[player_idx].ammo += 1;
                    }
                    self.update();
                    return true;
                },
            }
        }
        false
    }

    pub fn mob_move(&mut self, mob_idx: uint, dir: &Vec2<int>) -> bool {
        match self.melee_probe_dir(mob_idx, dir) {
            Blocked => { return false; },
            Move => {
                self.mobs[mob_idx].loc = self.mobs[mob_idx].loc + *dir;
                return true;
            }
            Melee(target_idx) => {
                if self.mobs[target_idx].t == mob::Player {
                    self.attack(mob_idx, target_idx);
                    return true;
                } else {
                    return false;
                }
            },
            _ => { return false; }
        };
    }

    pub fn update(&mut self) {
        if self.has_player() && self.player().is_alive() {
            self.pos = self.player().loc;
            self.player_dijkstra = Some(dijkstra::build_map(
                    ~[self.pos], |&loc| self.walk_neighbors(loc), 256));
        } else {
            self.player_dijkstra = None;
        }

        for i in range(0, self.mobs.len()) {
            if !self.mobs[i].is_alive() || self.mobs[i].t == mob::Player { continue; }

            // Wander around randomly if there's no player to hunt.
            if self.player_dijkstra.is_none() {
                let dir = self.rng.choose(area::DIRECTIONS6);
                self.mob_move(i, &dir);
                continue;
            }

            match uphill(self.player_dijkstra.get_ref(), self.mobs[i].loc) {
                Some(new_loc) => {
                    // TODO: Attack if close enough.
                    match self.mob_idx_at(new_loc) {
                        Some(mob_idx) => {
                            if self.mobs[mob_idx].t == mob::Player {
                                self.attack(i, mob_idx);
                            }
                        },
                        None => {
                            self.mobs[i].loc = new_loc;
                        },
                    };
                },
                None => (),
            }
        }
    }

    pub fn draw<R: Renderer>(&mut self, app: &mut App<R>) {
        let mouse = app.r.get_mouse();
        let xf = Transform::new(self.pos);
        let cursor_chart_loc = xf.to_chart(&mouse.pos);

        let mut tmp_seen = ~fov::fov(self.area, self.pos, 12);
        mem::swap(self.seen, tmp_seen);
        // Move old fov to map memory.
        self.remembered.add(tmp_seen);

        for mob in self.mobs.mut_iter() {
            mob.update_anim();
        }

        areaview::draw_area(self, app);
        app.r.draw_tile(areaview::CURSOR_BOTTOM, &xf.to_screen(cursor_chart_loc), sprite::FLOOR_Z, &FIREBRICK, renderer::ColorKeyDraw);
        app.r.draw_tile(areaview::CURSOR_TOP, &xf.to_screen(cursor_chart_loc), sprite::BLOCK_Z, &FIREBRICK, renderer::ColorKeyDraw);

        let text_zone = Aabb2::new(Point2::new(0.0f32, 200.0f32), Point2::new(240.0f32, 360.0f32));
        app.set_color(&LIGHTSLATEGRAY);
        app.print_words(&text_zone, app::Left, "Hello, player. This is a friendly status message.");

        app.set_color(&CRIMSON);
        let mut health_str = ~"hits: ";
        for _ in range(0, self.player().hits) { health_str = health_str + "o"; }
        app.print_words(&RectUtil::new(0f32, 0f32, 120f32, 8f32), app::Left, health_str);

        app.set_color(&ROYALBLUE);
        let mut ammo_str = ~"ammo: ";
        for _ in range(0, self.player().ammo) { ammo_str = ammo_str + "|"; }
        app.print_words(&RectUtil::new(0f32, 8f32, 120f32, 16f32), app::Left, ammo_str);

        app.set_color(&CORNFLOWERBLUE);
        app.print_words(&Aabb2::new(Point2::new(260.0f32, 0.0f32), Point2::new(380.0f32, 16.0f32)),
            app::Center, self.object_name(cursor_chart_loc));

        app.set_color(&LIGHTSLATEGRAY);
        app.print_words(&Aabb2::new(Point2::new(560.0f32, 0.0f32), Point2::new(640.0f32, 16.0f32)),
            app::Right, self.area_name());

        if !self.stop {
            if !self.area.fully_explored(self.remembered) {
                let map = self.area.explore_map(self.remembered);
                match uphill(&map, self.pos) {
                    Some(p) => { if self.area.get(p).is_walkable() { self.pos = p; } },
                    None => (),
                }
            }
        }

        if self.area.get(self.pos) == area::Downstairs {
            self.next_level();
        }
    }
}
<commit_msg>Help text in status view<commit_after>use time;
use std::rand;
use std::rand::Rng;
use std::mem;

use cgmath::point::{Point2};
use cgmath::vector::{Vec2};
use cgmath::aabb::{Aabb2};
use color::rgb::consts::*;

use calx::app::App;
use calx::app;
use calx::renderer::Renderer;
use calx::renderer;
use calx::rectutil::RectUtil;

use area::{Location, Area, uphill, DijkstraMap, DIRECTIONS6};
use dijkstra;
use area;
use areaview;
use fov::Fov;
use fov;
use mapgen::MapGen;
use mob;
use mob::Mob;
use transform::Transform;
use sprite;

// XXX: Indiscriminate blob of stuff ahoy
pub struct Game {
    area: ~Area,
    pos: Location,
    seen: ~Fov,
    remembered: ~Fov,
    mobs: ~[Mob],
    player_dijkstra: Option<DijkstraMap>,
    rng: rand::StdRng,
    stop: bool,
    depth: uint,
}

static GUN_RANGE: uint = 8;

// Smart action in a given direction
pub enum ProbeResult {
    // Free to walk, nothing to attack.
    Move,
    // Can't walk nor attack.
    Blocked,
    // Something next to you, melee attack.
    Melee(uint),
    // Something in the distance, can shoot it.
    Ranged(uint),
}

impl Game {
    pub fn new() -> Game {
        let mut ret = Game {
            area: ~Area::new(area::Rock),
            pos: Location(Point2::new(0i8, 0i8)),
            seen: ~Fov::new(),
            remembered: ~Fov::new(),
            mobs: ~[],
            player_dijkstra: None,
            rng: rand::rng(),
            stop: true,
            depth: 0,
        };
        ret.next_level();
        ret
    }

    pub fn player<'a>(&'a mut self) -> &'a mut Mob {
        for i in self.mobs.mut_iter() {
            if i.t == mob::Player {
                return i;
            }
        }
        fail!("No player mob");
    }

    pub fn player_idx(&self) -> uint {
        for (i, mob) in self.mobs.iter().enumerate() {
            if mob.t == mob::Player {
                return i;
            }
        }
        fail!("No player mob");
    }

    pub fn open_cells(&self) -> ~[Location] {
        let mut ret = ~[];
        for &loc in self.area.iter() {
            if self.area.get(loc).is_walkable() && self.mob_at(loc).is_none() {
                ret.push(loc);
            }
        }
        ret
    }

    pub fn has_player(&self) -> bool {
        for i in self.mobs.iter() {
            if i.t == mob::Player {
                return true;
            }
        }
        false
    }

    pub fn mob_idx_at<'a>(&'a self, loc: Location) -> Option<uint> {
        for (i, mob) in self.mobs.iter().enumerate() {
            if mob.loc == loc && mob.is_alive() {
                return Some(i);
            }
        }
        None
    }

    pub fn drawable_mob_at<'a>(&'a self, loc: Location) -> Option<&'a Mob> {
        let mut ret = None;
        for i in self.mobs.iter() {
            if i.loc == loc {
                // Make sure you show up the live mob if there's a live
                // one and corpses here.
                if i.is_alive() || ret.is_none() { ret = Some(i); }
            }
        }
        ret
    }

    pub fn mob_at<'a>(&'a self, loc: Location) -> Option<&'a Mob> {
        for i in self.mobs.iter() {
            if i.loc == loc && i.is_alive() {
                return Some(i);
            }
        }
        None
    }

    pub fn mob_at_mut<'a>(&'a mut self, loc: Location) -> Option<&'a mut Mob> {
        for i in self.mobs.mut_iter() {
            if i.loc == loc {
                return Some(i);
            }
        }
        None
    }

    pub fn next_level(&mut self) {
        // Player state doesn't persist level-to-level.
        self.mobs = ~[Mob::new(mob::Player, Location(Point2::new(0i8, 0i8)))];
        self.area = ~Area::new(area::Rock);
        self.area.gen_cave(&mut self.rng);
        self.depth += 1;

        self.player().loc = Location(Point2::new(0i8, 0i8));

        let sites = self.open_cells();
        for &spawn_loc in self.rng.sample(sites.iter(), 6 + self.depth).iter() {
            // TODO: Minimal depth consideration.
            // TODO: Special spawn logic for the boss.
            let kind = self.rng.choose(
                &[mob::Morlock, mob::BigMorlock, mob::BurrowingMorlock, mob::Centipede]);
            self.mobs.push(Mob::new(kind, *spawn_loc));
        }

        self.seen = ~Fov::new();
        self.remembered = ~Fov::new();
    }

    pub fn area_name(&self) -> ~str {
        format!("Floor {}", self.depth)
    }

    pub fn object_name(&self, loc: Location) -> ~str {
        match self.mob_at(loc) {
            Some(mob) => mob.data().name,
            None => ~"",
        }
    }

    pub fn attack(&mut self, _agent_idx: uint, target_idx: uint) {
        // TODO: More interesting logic.
        //self.mobs.remove(target_idx);
        let mob = &mut self.mobs[target_idx];
        mob.hits -= 1;

        if mob.hits > 0 {
            mob.anim_state = mob::Hurt(time::precise_time_s());
        } else {
            mob.anim_state = mob::Dying(time::precise_time_s());
        }
    }

    pub fn is_walkable(&self, loc: Location) -> bool {
        self.area.get(loc).is_walkable() && self.mob_idx_at(loc).is_none()
    }

    pub fn melee_probe_dir(&self, mob_idx: uint, dir: &Vec2<int>) -> ProbeResult {
        let loc = self.mobs[mob_idx].loc + *dir;
        let mut walk_state = Move;

        match self.mob_idx_at(loc) {
            Some(mob_idx) => { return Melee(mob_idx); },
            _ => ()
        };

        if !self.area.get(loc).is_walkable() {
            walk_state = Blocked;
        }

        walk_state
    }

    pub fn probe_dir(&self, dir: &Vec2<int>) -> ProbeResult {
        let mut loc = self.mobs[self.player_idx()].loc + *dir;
        let mut walk_state = Move;

        match self.mob_idx_at(loc) {
            Some(mob_idx) => { return Melee(mob_idx); },
            _ => ()
        };

        if !self.area.get(loc).is_walkable() {
            walk_state = Blocked;
        }

        if self.area.get(loc).blocks_shot() {
            return walk_state;
        }

        for _ in range(1, GUN_RANGE) {
            loc = loc + *dir;

            match self.mob_idx_at(loc) {
                Some(mob_idx) => { return Ranged(mob_idx); },
                _ => ()
            };

            if self.area.get(loc).blocks_shot() {
                return walk_state;
            }
        }

        walk_state
    }

    pub fn walk_neighbors(&self, loc: Location) -> ~[Location] {
        let mut ret = ~[];
        for &v in DIRECTIONS6.iter() {
            if self.is_walkable(loc + v) {
               ret.push(loc + v);
            }
        }
        ret
    }

    pub fn msg(&mut self, _txt: &str) {
        // TODO
    }

    pub fn pass(&mut self) {
        let player_idx = self.player_idx();
        if self.mobs[player_idx].ammo < 6 {
            self.msg("reload");
            self.mobs[player_idx].ammo += 1;
        }
        self.update();
    }

    pub fn smart_move(&mut self, dirs: &[Vec2<int>]) -> bool {
        let player_idx = self.player_idx();

        for d in dirs.iter() {
            match self.probe_dir(d) {
                Blocked => { continue; },
                Move => {
                    let new_loc = self.player().loc + *d;
                    self.player().loc = new_loc;
                    if self.area.get(new_loc) == area::Downstairs {
                        self.next_level();
                    }
                    self.update();
                    return true;
                },
                Melee(mob_idx) => {
                    self.attack(player_idx, mob_idx);
                    self.update();
                    return true;
                },
                Ranged(mob_idx) => {
                    if self.mobs[player_idx].ammo > 0 {
                        self.attack(player_idx, mob_idx);
                        self.mobs[player_idx].ammo -= 1;
                    } else {
                        self.msg("reload");
                        self.mobs[player_idx].ammo += 1;
                    }
                    self.update();
                    return true;
                },
            }
        }
        false
    }

    pub fn mob_move(&mut self, mob_idx: uint, dir: &Vec2<int>) -> bool {
        match self.melee_probe_dir(mob_idx, dir) {
            Blocked => { return false; },
            Move => {
                self.mobs[mob_idx].loc = self.mobs[mob_idx].loc + *dir;
                return true;
            }
            Melee(target_idx) => {
                if self.mobs[target_idx].t == mob::Player {
                    self.attack(mob_idx, target_idx);
                    return true;
                } else {
                    return false;
                }
            },
            _ => { return false; }
        };
    }

    pub fn update(&mut self) {
        if self.has_player() && self.player().is_alive() {
            self.pos = self.player().loc;
            self.player_dijkstra = Some(dijkstra::build_map(
                    ~[self.pos], |&loc| self.walk_neighbors(loc), 256));
        } else {
            self.player_dijkstra = None;
        }

        for i in range(0, self.mobs.len()) {
            if !self.mobs[i].is_alive() || self.mobs[i].t == mob::Player { continue; }

            // Wander around randomly if there's no player to hunt.
            if self.player_dijkstra.is_none() {
                let dir = self.rng.choose(area::DIRECTIONS6);
                self.mob_move(i, &dir);
                continue;
            }

            match uphill(self.player_dijkstra.get_ref(), self.mobs[i].loc) {
                Some(new_loc) => {
                    // TODO: Attack if close enough.
                    match self.mob_idx_at(new_loc) {
                        Some(mob_idx) => {
                            if self.mobs[mob_idx].t == mob::Player {
                                self.attack(i, mob_idx);
                            }
                        },
                        None => {
                            self.mobs[i].loc = new_loc;
                        },
                    };
                },
                None => (),
            }
        }
    }

    pub fn draw<R: Renderer>(&mut self, app: &mut App<R>) {
        let mouse = app.r.get_mouse();
        let xf = Transform::new(self.pos);
        let cursor_chart_loc = xf.to_chart(&mouse.pos);

        let mut tmp_seen = ~fov::fov(self.area, self.pos, 12);
        mem::swap(self.seen, tmp_seen);
        // Move old fov to map memory.
        self.remembered.add(tmp_seen);

        for mob in self.mobs.mut_iter() {
            mob.update_anim();
        }

        areaview::draw_area(self, app);
        app.r.draw_tile(areaview::CURSOR_BOTTOM, &xf.to_screen(cursor_chart_loc), sprite::FLOOR_Z, &FIREBRICK, renderer::ColorKeyDraw);
        app.r.draw_tile(areaview::CURSOR_TOP, &xf.to_screen(cursor_chart_loc), sprite::BLOCK_Z, &FIREBRICK, renderer::ColorKeyDraw);

        let text_zone = Aabb2::new(Point2::new(0.0f32, 200.0f32), Point2::new(240.0f32, 360.0f32));
        app.set_color(&LIGHTSLATEGRAY);
        app.print_words(&text_zone, app::Left, "Morlock Hunter\n\ncontrols\n--------\n\
                        QWE\nASD to move and shoot\nSPACE to rest and reload\n\
                        ESC to exit");

        app.set_color(&CRIMSON);
        let mut health_str = ~"hits: ";
        for _ in range(0, self.player().hits) { health_str = health_str + "o"; }
        app.print_words(&RectUtil::new(0f32, 0f32, 120f32, 8f32), app::Left, health_str);

        app.set_color(&ROYALBLUE);
        let mut ammo_str = ~"ammo: ";
        for _ in range(0, self.player().ammo) { ammo_str = ammo_str + "|"; }
        app.print_words(&RectUtil::new(0f32, 8f32, 120f32, 16f32), app::Left, ammo_str);

        app.set_color(&CORNFLOWERBLUE);
        app.print_words(&Aabb2::new(Point2::new(260.0f32, 0.0f32), Point2::new(380.0f32, 16.0f32)),
            app::Center, self.object_name(cursor_chart_loc));

        app.set_color(&LIGHTSLATEGRAY);
        app.print_words(&Aabb2::new(Point2::new(560.0f32, 0.0f32), Point2::new(640.0f32, 16.0f32)),
            app::Right, self.area_name());

        if !self.stop {
            if !self.area.fully_explored(self.remembered) {
                let map = self.area.explore_map(self.remembered);
                match uphill(&map, self.pos) {
                    Some(p) => { if self.area.get(p).is_walkable() { self.pos = p; } },
                    None => (),
                }
            }
        }

        if self.area.get(self.pos) == area::Downstairs {
            self.next_level();
        }
    }
}
<|endoftext|>