<commit_before>use super::internal::*;
use super::*;
use std::cmp::min;
use std::iter;

pub struct ChainIter<A, B>
    where A: ParallelIterator,
          B: ParallelIterator<Item = A::Item>
{
    a: A,
    b: B,
}

impl<A, B> ChainIter<A, B>
    where A: ParallelIterator,
          B: ParallelIterator<Item = A::Item>
{
    pub fn new(a: A, b: B) -> ChainIter<A, B> {
        ChainIter { a: a, b: b }
    }
}

impl<A, B> ParallelIterator for ChainIter<A, B>
    where A: ParallelIterator,
          B: ParallelIterator<Item = A::Item>
{
    type Item = A::Item;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let a = self.a.drive_unindexed(consumer.split_off());
        let b = self.b.drive_unindexed(consumer.split_off());
        consumer.to_reducer().reduce(a, b)
    }

    fn opt_len(&mut self) -> Option<usize> {
        // NB: Even though we could compute the indexed length as below,
        // we can't support collect's faux `UnindexedConsumer` in our
        // `drive_unindexed`, so we must leave this un-"specialized".
        //
        // match (self.a.opt_len(), self.b.opt_len()) {
        //     (Some(a_len), Some(b_len)) => a_len.checked_add(b_len),
        //     _ => None,
        // }
        None
    }
}

impl<A, B> BoundedParallelIterator for ChainIter<A, B>
    where A: BoundedParallelIterator,
          B: BoundedParallelIterator<Item = A::Item>
{
    fn upper_bound(&mut self) -> usize {
        self.a.upper_bound() + self.b.upper_bound()
    }

    fn drive<C>(mut self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        let (left, right, reducer) = consumer.split_at(self.a.upper_bound());
        let a = self.a.drive(left);
        let b = self.b.drive(right);
        reducer.reduce(a, b)
    }
}

impl<A, B> ExactParallelIterator for ChainIter<A, B>
    where A: ExactParallelIterator,
          B: ExactParallelIterator<Item = A::Item>
{
    fn len(&mut self) -> usize {
        self.a.len() + self.b.len()
    }
}

impl<A, B> IndexedParallelIterator for ChainIter<A, B>
    where A: IndexedParallelIterator,
          B: IndexedParallelIterator<Item = A::Item>
{
    fn with_producer<CB>(mut self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        let a_len = self.a.len();
        return self.a.with_producer(CallbackA {
            callback: callback,
            a_len: a_len,
            b: self.b,
        });

        struct CallbackA<CB, B> {
            callback: CB,
            a_len: usize,
            b: B,
        }

        impl<CB, B> ProducerCallback<B::Item> for CallbackA<CB, B>
            where B: IndexedParallelIterator,
                  CB: ProducerCallback<B::Item>
        {
            type Output = CB::Output;

            fn callback<A>(self, a_producer: A) -> Self::Output
                where A: Producer<Item = B::Item>
            {
                return self.b.with_producer(CallbackB {
                    callback: self.callback,
                    a_len: self.a_len,
                    a_producer: a_producer,
                });
            }
        }

        struct CallbackB<CB, A> {
            callback: CB,
            a_len: usize,
            a_producer: A,
        }

        impl<CB, A> ProducerCallback<A::Item> for CallbackB<CB, A>
            where A: Producer,
                  CB: ProducerCallback<A::Item>
        {
            type Output = CB::Output;

            fn callback<B>(self, b_producer: B) -> Self::Output
                where B: Producer<Item = A::Item>
            {
                let producer = ChainProducer::new(self.a_len, self.a_producer, b_producer);
                self.callback.callback(producer)
            }
        }

    }
}

/// ////////////////////////////////////////////////////////////////////////

pub struct ChainProducer<A, B>
    where A: Producer,
          B: Producer<Item = A::Item>
{
    a_len: usize,
    a: A,
    b: B,
}

impl<A, B> ChainProducer<A, B>
    where A: Producer,
          B: Producer<Item = A::Item>
{
    fn new(a_len: usize, a: A, b: B) -> Self {
        ChainProducer {
            a_len: a_len,
            a: a,
            b: b,
        }
    }
}

impl<A, B> Producer for ChainProducer<A, B>
    where A: Producer,
          B: Producer<Item = A::Item>
{
    fn weighted(&self) -> bool {
        self.a.weighted() || self.b.weighted()
    }

    fn cost(&mut self, len: usize) -> f64 {
        let a_len = min(self.a_len, len);
        let b_len = len - a_len;
        self.a.cost(a_len) + self.b.cost(b_len)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        if index <= self.a_len {
            let a_rem = self.a_len - index;
            let (a_left, a_right) = self.a.split_at(index);
            let (b_left, b_right) = self.b.split_at(0);
            (ChainProducer::new(index, a_left, b_left), ChainProducer::new(a_rem, a_right, b_right))
        } else {
            let (a_left, a_right) = self.a.split_at(self.a_len);
            let (b_left, b_right) = self.b.split_at(index - self.a_len);
            (ChainProducer::new(self.a_len, a_left, b_left),
             ChainProducer::new(0, a_right, b_right))
        }
    }
}

impl<A, B> IntoIterator for ChainProducer<A, B>
    where A: Producer,
          B: Producer<Item = A::Item>
{
    type Item = A::Item;
    type IntoIter = iter::Chain<A::IntoIter, B::IntoIter>;

    fn into_iter(self) -> Self::IntoIter {
        self.a.into_iter().chain(self.b)
    }
}
<commit_msg>Implement fold_with for ChainProducer<commit_after>use super::internal::*;
use super::*;
use std::cmp::min;
use std::iter;

pub struct ChainIter<A, B>
    where A: ParallelIterator,
          B: ParallelIterator<Item = A::Item>
{
    a: A,
    b: B,
}

impl<A, B> ChainIter<A, B>
    where A: ParallelIterator,
          B: ParallelIterator<Item = A::Item>
{
    pub fn new(a: A, b: B) -> ChainIter<A, B> {
        ChainIter { a: a, b: b }
    }
}

impl<A, B> ParallelIterator for ChainIter<A, B>
    where A: ParallelIterator,
          B: ParallelIterator<Item = A::Item>
{
    type Item = A::Item;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let a = self.a.drive_unindexed(consumer.split_off());
        let b = self.b.drive_unindexed(consumer.split_off());
        consumer.to_reducer().reduce(a, b)
    }

    fn opt_len(&mut self) -> Option<usize> {
        // NB: Even though we could compute the indexed length as below,
        // we can't support collect's faux `UnindexedConsumer` in our
        // `drive_unindexed`, so we must leave this un-"specialized".
        //
        // match (self.a.opt_len(), self.b.opt_len()) {
        //     (Some(a_len), Some(b_len)) => a_len.checked_add(b_len),
        //     _ => None,
        // }
        None
    }
}

impl<A, B> BoundedParallelIterator for ChainIter<A, B>
    where A: BoundedParallelIterator,
          B: BoundedParallelIterator<Item = A::Item>
{
    fn upper_bound(&mut self) -> usize {
        self.a.upper_bound() + self.b.upper_bound()
    }

    fn drive<C>(mut self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        let (left, right, reducer) = consumer.split_at(self.a.upper_bound());
        let a = self.a.drive(left);
        let b = self.b.drive(right);
        reducer.reduce(a, b)
    }
}

impl<A, B> ExactParallelIterator for ChainIter<A, B>
    where A: ExactParallelIterator,
          B: ExactParallelIterator<Item = A::Item>
{
    fn len(&mut self) -> usize {
        self.a.len() + self.b.len()
    }
}

impl<A, B> IndexedParallelIterator for ChainIter<A, B>
    where A: IndexedParallelIterator,
          B: IndexedParallelIterator<Item = A::Item>
{
    fn with_producer<CB>(mut self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        let a_len = self.a.len();
        return self.a.with_producer(CallbackA {
            callback: callback,
            a_len: a_len,
            b: self.b,
        });

        struct CallbackA<CB, B> {
            callback: CB,
            a_len: usize,
            b: B,
        }

        impl<CB, B> ProducerCallback<B::Item> for CallbackA<CB, B>
            where B: IndexedParallelIterator,
                  CB: ProducerCallback<B::Item>
        {
            type Output = CB::Output;

            fn callback<A>(self, a_producer: A) -> Self::Output
                where A: Producer<Item = B::Item>
            {
                return self.b.with_producer(CallbackB {
                    callback: self.callback,
                    a_len: self.a_len,
                    a_producer: a_producer,
                });
            }
        }

        struct CallbackB<CB, A> {
            callback: CB,
            a_len: usize,
            a_producer: A,
        }

        impl<CB, A> ProducerCallback<A::Item> for CallbackB<CB, A>
            where A: Producer,
                  CB: ProducerCallback<A::Item>
        {
            type Output = CB::Output;

            fn callback<B>(self, b_producer: B) -> Self::Output
                where B: Producer<Item = A::Item>
            {
                let producer = ChainProducer::new(self.a_len, self.a_producer, b_producer);
                self.callback.callback(producer)
            }
        }

    }
}

/// ////////////////////////////////////////////////////////////////////////

pub struct ChainProducer<A, B>
    where A: Producer,
          B: Producer<Item = A::Item>
{
    a_len: usize,
    a: A,
    b: B,
}

impl<A, B> ChainProducer<A, B>
    where A: Producer,
          B: Producer<Item = A::Item>
{
    fn new(a_len: usize, a: A, b: B) -> Self {
        ChainProducer {
            a_len: a_len,
            a: a,
            b: b,
        }
    }
}

impl<A, B> Producer for ChainProducer<A, B>
    where A: Producer,
          B: Producer<Item = A::Item>
{
    fn weighted(&self) -> bool {
        self.a.weighted() || self.b.weighted()
    }

    fn cost(&mut self, len: usize) -> f64 {
        let a_len = min(self.a_len, len);
        let b_len = len - a_len;
        self.a.cost(a_len) + self.b.cost(b_len)
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        if index <= self.a_len {
            let a_rem = self.a_len - index;
            let (a_left, a_right) = self.a.split_at(index);
            let (b_left, b_right) = self.b.split_at(0);
            (ChainProducer::new(index, a_left, b_left), ChainProducer::new(a_rem, a_right, b_right))
        } else {
            let (a_left, a_right) = self.a.split_at(self.a_len);
            let (b_left, b_right) = self.b.split_at(index - self.a_len);
            (ChainProducer::new(self.a_len, a_left, b_left),
             ChainProducer::new(0, a_right, b_right))
        }
    }

    fn fold_with<F>(self, mut folder: F) -> F
        where F: Folder<A::Item>,
    {
        folder = self.a.fold_with(folder);
        if folder.full() {
            folder
        } else {
            self.b.fold_with(folder)
        }
    }
}

impl<A, B> IntoIterator for ChainProducer<A, B>
    where A: Producer,
          B: Producer<Item = A::Item>
{
    type Item = A::Item;
    type IntoIter = iter::Chain<A::IntoIter, B::IntoIter>;

    fn into_iter(self) -> Self::IntoIter {
        self.a.into_iter().chain(self.b)
    }
}
<|endoftext|>


<commit_before>use std::io::{Cursor, Read, Write};

use codecs::{ToByte, FromByte};
use compression::snappy::SnappyReader;
use compression::{Compression, gzip};
use error::{Error, Result};
use utils::{TopicMessage, OffsetMessage};

use super::{HeaderRequest, HeaderResponse};
use super::{API_KEY_FETCH, API_VERSION};

#[derive(Debug)]
pub struct FetchRequest<'a, 'b> {
    pub header: HeaderRequest<'a>,
    pub replica: i32,
    pub max_wait_time: i32,
    pub min_bytes: i32,
    pub topic_partitions: Vec<TopicPartitionFetchRequest<'b>>
}

#[derive(Debug)]
pub struct TopicPartitionFetchRequest<'a> {
    pub topic: &'a str,
    pub partitions: Vec<PartitionFetchRequest>
}

#[derive(Debug)]
pub struct PartitionFetchRequest {
    pub partition: i32,
    pub offset: i64,
    pub max_bytes: i32
}

impl<'a, 'b> FetchRequest<'a, 'b> {

    pub fn new(correlation_id: i32, client_id: &'a str, max_wait_time: i32, min_bytes: i32)
               -> FetchRequest<'a, 'b> {
        FetchRequest {
            header: HeaderRequest::new(
                API_KEY_FETCH, API_VERSION, correlation_id, client_id),
            replica: -1,
            max_wait_time: max_wait_time,
            min_bytes: min_bytes,
            topic_partitions: vec!()
        }
    }

    pub fn add(&mut self, topic: &'b str, partition: i32, offset: i64, max_bytes: i32) {
        for tp in &mut self.topic_partitions {
            if tp.topic == topic {
                tp.add(partition, offset, max_bytes);
                return;
            }
        }
        let mut tp = TopicPartitionFetchRequest::new(topic);
        tp.add(partition, offset, max_bytes);
        self.topic_partitions.push(tp);
    }
}

impl<'a> TopicPartitionFetchRequest<'a> {
    pub fn new(topic: &'a str) -> TopicPartitionFetchRequest<'a> {
        TopicPartitionFetchRequest {
            topic: topic,
            partitions: vec!()
        }
    }

    pub fn add(&mut self, partition: i32, offset: i64, max_bytes: i32) {
        self.partitions.push(PartitionFetchRequest:: new(partition, offset, max_bytes))
    }
}

impl PartitionFetchRequest {
    pub fn new(partition: i32, offset: i64, max_bytes: i32) -> PartitionFetchRequest {
        PartitionFetchRequest {
            partition: partition,
            offset: offset,
            max_bytes: max_bytes,
        }
    }
}

impl<'a, 'b> ToByte for FetchRequest<'a, 'b> {
    fn encode<W: Write>(&self, buffer: &mut W) -> Result<()> {
        try_multi!(
            self.header.encode(buffer),
            self.replica.encode(buffer),
            self.max_wait_time.encode(buffer),
            self.min_bytes.encode(buffer),
            self.topic_partitions.encode(buffer)
        )
    }
}

impl<'a> ToByte for TopicPartitionFetchRequest<'a> {
    fn encode<W: Write>(&self, buffer: &mut W) -> Result<()> {
        try_multi!(
            self.topic.encode(buffer),
            self.partitions.encode(buffer)
        )
    }
}

impl ToByte for PartitionFetchRequest {
    fn encode<T:Write>(&self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.partition.encode(buffer),
            self.offset.encode(buffer),
            self.max_bytes.encode(buffer)
        )
    }
}

// --------------------------------------------------------------------

#[derive(Default, Debug)]
pub struct FetchResponse {
    pub header: HeaderResponse,
    pub topic_partitions: Vec<TopicPartitionFetchResponse>,
}

#[derive(Default, Debug)]
pub struct TopicPartitionFetchResponse {
    pub topic: String,
    pub partitions: Vec<PartitionFetchResponse>,
}

#[derive(Default, Debug)]
pub struct PartitionFetchResponse {
    pub partition: i32,
    pub error: i16,
    pub highwatermark_offset: i64,
    pub message_set: MessageSet
}

impl FetchResponse {
    pub fn into_messages(self) -> Vec<TopicMessage> {
        self.topic_partitions
            .into_iter()
            .flat_map(|tp| tp.into_messages())
            .collect()
    }
}

impl TopicPartitionFetchResponse {
    pub fn into_messages(self) -> Vec<TopicMessage> {
        let topic = self.topic;
        self.partitions
            .into_iter()
            .flat_map(|p| p.into_messages(topic.clone()))
            .collect()
    }
}

impl PartitionFetchResponse {
    pub fn into_messages(self, topic: String) -> Vec<TopicMessage> {
        if let Some(e) = Error::from_protocol_error(self.error) {
            return vec!(TopicMessage {
                topic: topic,
                partition: self.partition,
                message: Err(e),
            });
        }
        let partition = self.partition;
        self.message_set
            .into_messages()
            .into_iter()
            .map(|om| TopicMessage {
                topic: topic.clone(),
                partition: partition,
                message: Ok(om)
            })
            .collect()
    }
}

impl FromByte for FetchResponse {
    type R = FetchResponse;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.header.decode(buffer),
            self.topic_partitions.decode(buffer)
        )
    }
}

impl FromByte for TopicPartitionFetchResponse {
    type R = TopicPartitionFetchResponse;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.topic.decode(buffer),
            self.partitions.decode(buffer)
        )
    }
}

impl FromByte for PartitionFetchResponse {
    type R = PartitionFetchResponse;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.partition.decode(buffer),
            self.error.decode(buffer),
            self.highwatermark_offset.decode(buffer),
            self.message_set.decode(buffer)
        )
    }
}

#[derive(Default, Debug)]
pub struct MessageSet {
    pub message: Vec<MessageSetInner>
}

#[derive(Default, Debug)]
pub struct MessageSetInner {
    pub offset: i64,
    pub messagesize: i32,
    pub message: Message
}

#[derive(Default, Debug)]
pub struct Message {
    pub crc: i32,
    pub magic: i8,
    pub attributes: i8,
    pub key: Vec<u8>,
    pub value: Vec<u8>
}

impl MessageSet {
    fn into_messages(self) -> Vec<OffsetMessage> {
        self.message
            .into_iter()
            .flat_map(|m| m.into_messages())
            .collect()
    }
}

impl MessageSetInner {
    fn into_messages(self) -> Vec<OffsetMessage>{
        self.message.into_messages(self.offset)
    }
}

impl Message {
    fn into_messages(self, offset: i64) -> Vec<OffsetMessage> {
        match self.attributes & 3 {
            codec if codec == Compression::NONE as i8 => vec!(OffsetMessage{
                offset:offset,
                value: self.value
            }),
            codec if codec == Compression::GZIP as i8 => message_decode_gzip(self.value),
            codec if codec == Compression::SNAPPY as i8 => message_decode_snappy(self.value),
            _ => vec!()
        }
    }
}

fn message_decode_snappy(value: Vec<u8>) -> Vec<OffsetMessage> {
    // XXX avoid unwrap, have this return an error!!!
    let mut r = SnappyReader::new(&value).unwrap();
    let mset = MessageSet::decode_new(&mut r).unwrap();
    mset.into_messages()
}

fn message_decode_gzip(value: Vec<u8>) -> Vec<OffsetMessage>{
    // Gzip
    let mut buffer = Cursor::new(value);
    // XXX is the loop really necessary?
    match message_decode_loop_gzip(&mut buffer) {
        Ok(x) => x,
        Err(_) => vec!()
    }
}

fn message_decode_loop_gzip<T:Read>(buffer: &mut T) -> Result<Vec<OffsetMessage>> {
    let msg = try!(gzip::uncompress(buffer));
    let mset = try!(MessageSet::decode_new(&mut Cursor::new(msg)));
    Ok(mset.into_messages())
}

impl FromByte for MessageSet {
    type R = MessageSet;

    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        let mssize = try!(i32::decode_new(buffer));
        if mssize <= 0 { return Ok(()); }

        let mssize = mssize as u64;
        let mut buf = buffer.take(mssize);

        while buf.limit() > 0 {
            match MessageSetInner::decode_new(&mut buf) {
                Ok(val) => self.message.push(val),
                // handle partial trailing messages (see #17)
                Err(Error::UnexpectedEOF) => (),
                Err(err) => return Err(err)
            }
        }
        Ok(())
    }

    fn decode_new<T: Read>(buffer: &mut T) -> Result<Self::R> {
        let mut temp: Self::R = Default::default();
        while let Ok(mi) = MessageSetInner::decode_new(buffer) {
            temp.message.push(mi);
        }
        if temp.message.is_empty() {
            return Err(Error::UnexpectedEOF)
        }
        Ok(temp)
    }
}

impl FromByte for MessageSetInner {
    type R = MessageSetInner;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.offset.decode(buffer),
            self.messagesize.decode(buffer),
            self.message.decode(buffer)
        )
    }
}

impl FromByte for Message {
    type R = Message;

    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.crc.decode(buffer),
            self.magic.decode(buffer),
            self.attributes.decode(buffer),
            self.key.decode(buffer),
            self.value.decode(buffer)
        )
    }
}

// --------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use std::str;

    use super::FetchResponse;
    use codecs::FromByte;

    static FETCH1_TXT: &'static str =
        include_str!("../../test-data/fetch1.txt");
    static FETCH1_FETCH_RESPONSE_NOCOMPRESSION_K0821: &'static [u8] =
        include_bytes!("../../test-data/fetch1.mytopic.1p.nocompression.kafka.0821");
    static FETCH1_FETCH_RESPONSE_SNAPPY_K0821: &'static [u8] =
        include_bytes!("../../test-data/fetch1.mytopic.1p.snappy.kafka.0821");
    static FETCH1_FETCH_RESPONSE_SNAPPY_K0822: &'static [u8] =
        include_bytes!("../../test-data/fetch1.mytopic.1p.snappy.kafka.0822");

    fn test_decode_new_fetch_response(msg_per_line: &str, mut fetch_response_bytes: &[u8]) {
        let resp = FetchResponse::decode_new(&mut fetch_response_bytes);
        let resp = resp.unwrap();

        // ~ response for exactly one topic expected
        assert_eq!(1, resp.topic_partitions.len());

        let msgs = resp.into_messages();
        let original: Vec<_> = msg_per_line.lines().collect();
        assert_eq!(original.len(), msgs.len());
        for (msg, orig) in msgs.into_iter().zip(original.iter()) {
            assert_eq!(str::from_utf8(&msg.message.unwrap().value).unwrap(), *orig);
        }
    }

    #[test]
    fn test_decode_new_fetch_response_nocompression_k0821() {
        test_decode_new_fetch_response(FETCH1_TXT, FETCH1_FETCH_RESPONSE_NOCOMPRESSION_K0821);
    }

    #[test]
    fn test_decode_new_fetch_response_snappy_k0821() {
        test_decode_new_fetch_response(FETCH1_TXT, FETCH1_FETCH_RESPONSE_SNAPPY_K0821);
    }

    #[test]
    fn test_decode_new_fetch_response_snappy_k0822() {
        test_decode_new_fetch_response(FETCH1_TXT, FETCH1_FETCH_RESPONSE_SNAPPY_K0822);
    }

    #[cfg(feature = "nightly")]
    mod benches {
        use std::io::Cursor;
        use test::Bencher;

        use codecs::FromByte;
        use super::super::FetchResponse;

        fn bench_decode_new_fetch_response(b: &mut Bencher, data: &[u8]) {
            b.bytes = data.len() as u64;
            b.iter(|| FetchResponse::decode_new(&mut Cursor::new(data))
                   .unwrap()
                   .into_messages());
        }

        #[bench]
        fn bench_decode_new_fetch_response_nocompression_k0821(b: &mut Bencher) {
            bench_decode_new_fetch_response(b, super::FETCH1_FETCH_RESPONSE_NOCOMPRESSION_K0821)
        }

        #[bench]
        fn bench_decode_new_fetch_response_snappy_k0821(b: &mut Bencher) {
            bench_decode_new_fetch_response(b, super::FETCH1_FETCH_RESPONSE_SNAPPY_K0821)
        }

        #[bench]
        fn bench_decode_new_fetch_response_snappy_k0822(b: &mut Bencher) {
            bench_decode_new_fetch_response(b, super::FETCH1_FETCH_RESPONSE_SNAPPY_K0822)
        }
    }
}
<commit_msg>#! Test fetching gzipped messages<commit_after>use std::io::{Cursor, Read, Write};

use codecs::{ToByte, FromByte};
use compression::snappy::SnappyReader;
use compression::{Compression, gzip};
use error::{Error, Result};
use utils::{TopicMessage, OffsetMessage};

use super::{HeaderRequest, HeaderResponse};
use super::{API_KEY_FETCH, API_VERSION};

#[derive(Debug)]
pub struct FetchRequest<'a, 'b> {
    pub header: HeaderRequest<'a>,
    pub replica: i32,
    pub max_wait_time: i32,
    pub min_bytes: i32,
    pub topic_partitions: Vec<TopicPartitionFetchRequest<'b>>
}

#[derive(Debug)]
pub struct TopicPartitionFetchRequest<'a> {
    pub topic: &'a str,
    pub partitions: Vec<PartitionFetchRequest>
}

#[derive(Debug)]
pub struct PartitionFetchRequest {
    pub partition: i32,
    pub offset: i64,
    pub max_bytes: i32
}

impl<'a, 'b> FetchRequest<'a, 'b> {

    pub fn new(correlation_id: i32, client_id: &'a str, max_wait_time: i32, min_bytes: i32)
               -> FetchRequest<'a, 'b> {
        FetchRequest {
            header: HeaderRequest::new(
                API_KEY_FETCH, API_VERSION, correlation_id, client_id),
            replica: -1,
            max_wait_time: max_wait_time,
            min_bytes: min_bytes,
            topic_partitions: vec!()
        }
    }

    pub fn add(&mut self, topic: &'b str, partition: i32, offset: i64, max_bytes: i32) {
        for tp in &mut self.topic_partitions {
            if tp.topic == topic {
                tp.add(partition, offset, max_bytes);
                return;
            }
        }
        let mut tp = TopicPartitionFetchRequest::new(topic);
        tp.add(partition, offset, max_bytes);
        self.topic_partitions.push(tp);
    }
}

impl<'a> TopicPartitionFetchRequest<'a> {
    pub fn new(topic: &'a str) -> TopicPartitionFetchRequest<'a> {
        TopicPartitionFetchRequest {
            topic: topic,
            partitions: vec!()
        }
    }

    pub fn add(&mut self, partition: i32, offset: i64, max_bytes: i32) {
        self.partitions.push(PartitionFetchRequest:: new(partition, offset, max_bytes))
    }
}

impl PartitionFetchRequest {
    pub fn new(partition: i32, offset: i64, max_bytes: i32) -> PartitionFetchRequest {
        PartitionFetchRequest {
            partition: partition,
            offset: offset,
            max_bytes: max_bytes,
        }
    }
}

impl<'a, 'b> ToByte for FetchRequest<'a, 'b> {
    fn encode<W: Write>(&self, buffer: &mut W) -> Result<()> {
        try_multi!(
            self.header.encode(buffer),
            self.replica.encode(buffer),
            self.max_wait_time.encode(buffer),
            self.min_bytes.encode(buffer),
            self.topic_partitions.encode(buffer)
        )
    }
}

impl<'a> ToByte for TopicPartitionFetchRequest<'a> {
    fn encode<W: Write>(&self, buffer: &mut W) -> Result<()> {
        try_multi!(
            self.topic.encode(buffer),
            self.partitions.encode(buffer)
        )
    }
}

impl ToByte for PartitionFetchRequest {
    fn encode<T:Write>(&self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.partition.encode(buffer),
            self.offset.encode(buffer),
            self.max_bytes.encode(buffer)
        )
    }
}

// --------------------------------------------------------------------

#[derive(Default, Debug)]
pub struct FetchResponse {
    pub header: HeaderResponse,
    pub topic_partitions: Vec<TopicPartitionFetchResponse>,
}

#[derive(Default, Debug)]
pub struct TopicPartitionFetchResponse {
    pub topic: String,
    pub partitions: Vec<PartitionFetchResponse>,
}

#[derive(Default, Debug)]
pub struct PartitionFetchResponse {
    pub partition: i32,
    pub error: i16,
    pub highwatermark_offset: i64,
    pub message_set: MessageSet
}

impl FetchResponse {
    pub fn into_messages(self) -> Vec<TopicMessage> {
        self.topic_partitions
            .into_iter()
            .flat_map(|tp| tp.into_messages())
            .collect()
    }
}

impl TopicPartitionFetchResponse {
    pub fn into_messages(self) -> Vec<TopicMessage> {
        let topic = self.topic;
        self.partitions
            .into_iter()
            .flat_map(|p| p.into_messages(topic.clone()))
            .collect()
    }
}

impl PartitionFetchResponse {
    pub fn into_messages(self, topic: String) -> Vec<TopicMessage> {
        if let Some(e) = Error::from_protocol_error(self.error) {
            return vec!(TopicMessage {
                topic: topic,
                partition: self.partition,
                message: Err(e),
            });
        }
        let partition = self.partition;
        self.message_set
            .into_messages()
            .into_iter()
            .map(|om| TopicMessage {
                topic: topic.clone(),
                partition: partition,
                message: Ok(om)
            })
            .collect()
    }
}

impl FromByte for FetchResponse {
    type R = FetchResponse;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.header.decode(buffer),
            self.topic_partitions.decode(buffer)
        )
    }
}

impl FromByte for TopicPartitionFetchResponse {
    type R = TopicPartitionFetchResponse;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.topic.decode(buffer),
            self.partitions.decode(buffer)
        )
    }
}

impl FromByte for PartitionFetchResponse {
    type R = PartitionFetchResponse;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.partition.decode(buffer),
            self.error.decode(buffer),
            self.highwatermark_offset.decode(buffer),
            self.message_set.decode(buffer)
        )
    }
}

#[derive(Default, Debug)]
pub struct MessageSet {
    pub message: Vec<MessageSetInner>
}

#[derive(Default, Debug)]
pub struct MessageSetInner {
    pub offset: i64,
    pub messagesize: i32,
    pub message: Message
}

#[derive(Default, Debug)]
pub struct Message {
    pub crc: i32,
    pub magic: i8,
    pub attributes: i8,
    pub key: Vec<u8>,
    pub value: Vec<u8>
}

impl MessageSet {
    fn into_messages(self) -> Vec<OffsetMessage> {
        self.message
            .into_iter()
            .flat_map(|m| m.into_messages())
            .collect()
    }
}

impl MessageSetInner {
    fn into_messages(self) -> Vec<OffsetMessage>{
        self.message.into_messages(self.offset)
    }
}

impl Message {
    fn into_messages(self, offset: i64) -> Vec<OffsetMessage> {
        match self.attributes & 3 {
            codec if codec == Compression::NONE as i8 => vec!(OffsetMessage{
                offset:offset,
                value: self.value
            }),
            codec if codec == Compression::GZIP as i8 => message_decode_gzip(self.value),
            codec if codec == Compression::SNAPPY as i8 => message_decode_snappy(self.value),
            _ => vec!()
        }
    }
}

fn message_decode_snappy(value: Vec<u8>) -> Vec<OffsetMessage> {
    // XXX avoid unwrap, have this return an error!!!
    let mut r = SnappyReader::new(&value).unwrap();
    let mset = MessageSet::decode_new(&mut r).unwrap();
    mset.into_messages()
}

fn message_decode_gzip(value: Vec<u8>) -> Vec<OffsetMessage>{
    // Gzip
    let mut buffer = Cursor::new(value);
    // XXX is the loop really necessary?
    match message_decode_loop_gzip(&mut buffer) {
        Ok(x) => x,
        Err(_) => vec!()
    }
}

fn message_decode_loop_gzip<T:Read>(buffer: &mut T) -> Result<Vec<OffsetMessage>> {
    let msg = try!(gzip::uncompress(buffer));
    let mset = try!(MessageSet::decode_new(&mut Cursor::new(msg)));
    Ok(mset.into_messages())
}

impl FromByte for MessageSet {
    type R = MessageSet;

    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        let mssize = try!(i32::decode_new(buffer));
        if mssize <= 0 { return Ok(()); }

        let mssize = mssize as u64;
        let mut buf = buffer.take(mssize);

        while buf.limit() > 0 {
            match MessageSetInner::decode_new(&mut buf) {
                Ok(val) => self.message.push(val),
                // handle partial trailing messages (see #17)
                Err(Error::UnexpectedEOF) => (),
                Err(err) => return Err(err)
            }
        }
        Ok(())
    }

    fn decode_new<T: Read>(buffer: &mut T) -> Result<Self::R> {
        let mut temp: Self::R = Default::default();
        while let Ok(mi) = MessageSetInner::decode_new(buffer) {
            temp.message.push(mi);
        }
        if temp.message.is_empty() {
            return Err(Error::UnexpectedEOF)
        }
        Ok(temp)
    }
}

impl FromByte for MessageSetInner {
    type R = MessageSetInner;

    #[allow(unused_must_use)]
    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.offset.decode(buffer),
            self.messagesize.decode(buffer),
            self.message.decode(buffer)
        )
    }
}

impl FromByte for Message {
    type R = Message;

    fn decode<T: Read>(&mut self, buffer: &mut T) -> Result<()> {
        try_multi!(
            self.crc.decode(buffer),
            self.magic.decode(buffer),
            self.attributes.decode(buffer),
            self.key.decode(buffer),
            self.value.decode(buffer)
        )
    }
}

// --------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use std::str;

    use super::FetchResponse;
    use codecs::FromByte;

    static FETCH1_TXT: &'static str =
        include_str!("../../test-data/fetch1.txt");
    static FETCH1_FETCH_RESPONSE_NOCOMPRESSION_K0821: &'static [u8] =
        include_bytes!("../../test-data/fetch1.mytopic.1p.nocompression.kafka.0821");
    static FETCH1_FETCH_RESPONSE_SNAPPY_K0821: &'static [u8] =
        include_bytes!("../../test-data/fetch1.mytopic.1p.snappy.kafka.0821");
    static FETCH1_FETCH_RESPONSE_SNAPPY_K0822: &'static [u8] =
        include_bytes!("../../test-data/fetch1.mytopic.1p.snappy.kafka.0822");
    static FETCH1_FETCH_RESPONSE_GZIP_K0821: &'static [u8] =
        include_bytes!("../../test-data/fetch1.mytopic.1p.gzip.kafka.0821");

    fn test_decode_new_fetch_response(msg_per_line: &str, mut fetch_response_bytes: &[u8]) {
        let resp = FetchResponse::decode_new(&mut fetch_response_bytes);
        let resp = resp.unwrap();

        // ~ response for exactly one topic expected
        assert_eq!(1, resp.topic_partitions.len());

        let msgs = resp.into_messages();
        let original: Vec<_> = msg_per_line.lines().collect();
        assert_eq!(original.len(), msgs.len());
        for (msg, orig) in msgs.into_iter().zip(original.iter()) {
            assert_eq!(str::from_utf8(&msg.message.unwrap().value).unwrap(), *orig);
        }
    }

    #[test]
    fn test_decode_new_fetch_response_nocompression_k0821() {
        test_decode_new_fetch_response(FETCH1_TXT, FETCH1_FETCH_RESPONSE_NOCOMPRESSION_K0821);
    }

    #[test]
    fn test_decode_new_fetch_response_snappy_k0821() {
        test_decode_new_fetch_response(FETCH1_TXT, FETCH1_FETCH_RESPONSE_SNAPPY_K0821);
    }

    #[test]
    fn test_decode_new_fetch_response_snappy_k0822() {
        test_decode_new_fetch_response(FETCH1_TXT, FETCH1_FETCH_RESPONSE_SNAPPY_K0822);
    }

    #[test]
    fn test_decode_new_fetch_response_gzip_k0821() {
        test_decode_new_fetch_response(FETCH1_TXT, FETCH1_FETCH_RESPONSE_GZIP_K0821);
    }

    #[cfg(feature = "nightly")]
    mod benches {
        use std::io::Cursor;
        use test::Bencher;

        use codecs::FromByte;
        use super::super::FetchResponse;

        fn bench_decode_new_fetch_response(b: &mut Bencher, data: &[u8]) {
            b.bytes = data.len() as u64;
            b.iter(|| FetchResponse::decode_new(&mut Cursor::new(data))
                   .unwrap()
                   .into_messages());
        }

        #[bench]
        fn bench_decode_new_fetch_response_nocompression_k0821(b: &mut Bencher) {
            bench_decode_new_fetch_response(b, super::FETCH1_FETCH_RESPONSE_NOCOMPRESSION_K0821)
        }

        #[bench]
        fn bench_decode_new_fetch_response_snappy_k0821(b: &mut Bencher) {
            bench_decode_new_fetch_response(b, super::FETCH1_FETCH_RESPONSE_SNAPPY_K0821)
        }

        #[bench]
        fn bench_decode_new_fetch_response_snappy_k0822(b: &mut Bencher) {
            bench_decode_new_fetch_response(b, super::FETCH1_FETCH_RESPONSE_SNAPPY_K0822)
        }

        #[bench]
        fn bench_decode_new_fetch_response_gzip_k0821(b: &mut Bencher) {
            bench_decode_new_fetch_response(b, super::FETCH1_FETCH_RESPONSE_GZIP_K0821)
        }
    }
}
<|endoftext|>


<commit_before>use common::consts::get_version_string;
use platform::process::get_pid;
use platform::time::sleep_secs;
use platform::time::time_now;
use storage::Cache;

use super::Driver;
use super::cmd::Cmd;
use super::cmd::Delete;
use super::cmd::Get;
use super::cmd::Resp;
use super::cmd::Set;
use super::cmd::SetInstr;
use super::cmd::Stat;
use super::cmd::Value;

// Get and Set

#[test]
fn test_cmd_set_and_get_a_key() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Try to retrieve a key not set
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());

    // Set a key
    let set = Set::new(SetInstr::Set, key_name, 15, 0, blob.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(15, resp.get_first_value().unwrap().flags);
    assert_eq!(blob, resp.get_first_value().unwrap().data);

    // Set a key with noreply flag
    let set = Set::new(SetInstr::Set, "y", 15, 0, blob.clone(), true);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Empty);

    // Retrieve it
    let cmd = Cmd::Get(Get::one("y"));
    let resp = driver.run(cmd);
    assert_eq!(15, resp.get_first_value().unwrap().flags);
    assert_eq!(blob, resp.get_first_value().unwrap().data);
}

#[test]
fn test_cmd_set_and_get_multiple_keys() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let val1 = vec![1];
    let val3 = vec![3];

    // Set two keys
    let set = Set::new(SetInstr::Set, "a", 15, 0, val1.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    let set = Set::new(SetInstr::Set, "c", 17, 0, val3.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Try to retrieve three keys - get two
    let keys = vec!["a".to_string(), "b".to_string(), "c".to_string()];
    let cmd = Cmd::Get(Get::new(keys));
    let resp = driver.run(cmd);

    let values = resp.get_values().unwrap();
    let val1 = Value::new("a", 15, val1);
    let val3 = Value::new("c", 17, val3);
    assert_eq!(2, values.len());
    assert_eq!(val1, values[0]);
    assert_eq!(val3, values[1]);
}

// Delete

#[test]
fn test_cmd_delete() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Try to delete a key that does not exist
    let cmd = Cmd::Delete(Delete::new("z", false));
    let resp = driver.run(cmd);
    assert_eq!(Resp::NotFound, resp);

    // Again, but now with noreply flag
    let cmd = Cmd::Delete(Delete::new("z", true));
    let resp = driver.run(cmd);
    assert_eq!(Resp::Empty, resp);

    // Set a key we can delete later
    let set = Set::new(SetInstr::Set, "x", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // And another
    let set = Set::new(SetInstr::Set, "y", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Delete the first one
    let cmd = Cmd::Delete(Delete::new("x", false));
    let resp = driver.run(cmd);
    assert_eq!(Resp::Deleted, resp);

    // Make sure it's gone
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());

    // Delete the second - with noreply
    let cmd = Cmd::Delete(Delete::new("y", true));
    let resp = driver.run(cmd);
    assert_eq!(Resp::Empty, resp);

    // Make sure it's gone
    let cmd = Cmd::Get(Get::one("y"));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());
}

// Add

#[test]
fn test_cmd_add() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Add a new key
    let set = Set::new(SetInstr::Add, "x", 4, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Make sure it was added
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(vec![8, 9], resp.get_first_value().unwrap().data);
    assert_eq!(4, resp.get_first_value().unwrap().flags);

    // Try using add to overwrite an existing key
    let set = Set::new(SetInstr::Add, "x", 5, 0, vec![11], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::NotStored);

    // Make sure it was not overwritten
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(vec![8, 9], resp.get_first_value().unwrap().data);
    assert_eq!(4, resp.get_first_value().unwrap().flags);

    // Add with noreply
    let set = Set::new(SetInstr::Add, "y", 5, 0, vec![11], true);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Empty);

    // Make sure it was added
    let cmd = Cmd::Get(Get::one("y"));
    let resp = driver.run(cmd);
    assert_eq!(vec![11], resp.get_first_value().unwrap().data);
    assert_eq!(5, resp.get_first_value().unwrap().flags);
}

// Replace

#[test]
fn test_cmd_replace() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Try to replace an non-existent key
    let set = Set::new(SetInstr::Replace, "x", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::NotStored);

    // Set a key
    let set = Set::new(SetInstr::Set, "x", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Replace a valid key
    let set = Set::new(SetInstr::Replace, "x", 4, 0, vec![10], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Make sure it was updated
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(vec![10], resp.get_first_value().unwrap().data);
    assert_eq!(4, resp.get_first_value().unwrap().flags);

    // Replace a valid key in noreply mode
    let set = Set::new(SetInstr::Replace, "x", 6, 0, vec![11], true);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Empty);

    // Make sure it was updated
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(vec![11], resp.get_first_value().unwrap().data);
    assert_eq!(6, resp.get_first_value().unwrap().flags);
}

// Stats

#[test]
fn test_cmd_stats() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Set a key
    let set = Set::new(SetInstr::Set, "x", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it
    let cmd = Cmd::Get(Get::one("x"));
    driver.run(cmd);

    // Run stats
    let cmd = Cmd::Stats;
    let resp = driver.run(cmd);

    let st_pid = Stat::new("pid", get_pid().to_string());
    let st_bytes = Stat::new("bytes", "3".to_string());
    let st_uptime = Stat::new("uptime", "0".to_string());
    let st_time = Stat::new("time", (time_now() as u64).to_string());
    let st_version = Stat::new("version", get_version_string());
    let st_cmd_get = Stat::new("cmd_get", "1".to_string());
    let st_cmd_set = Stat::new("cmd_set", "1".to_string());
    let st_cmd_flush = Stat::new("cmd_flush", "0".to_string());
    let st_cmd_touch = Stat::new("cmd_touch", "0".to_string());
    let st_get_hits = Stat::new("get_hits", "1".to_string());
    let st_get_misses = Stat::new("get_misses", "0".to_string());
    let st_delete_hits = Stat::new("delete_hits", "0".to_string());
    let st_delete_misses = Stat::new("delete_misses", "0".to_string());
    let st_bytes_read = Stat::new("bytes_read", "0".to_string());
    let st_bytes_written = Stat::new("bytes_written", "0".to_string());
    let st_limit_maxbytes = Stat::new("limit_maxbytes", "100".to_string());
    let st_curr_items = Stat::new("curr_items", "1".to_string());
    let st_total_items = Stat::new("total_items", "1".to_string());
    let st_evictions = Stat::new("evictions", "0".to_string());
    let st_reclaimed = Stat::new("reclaimed", "0".to_string());

    let stats = resp.get_stats().unwrap();
    assert_eq!(*stats,
               (vec![st_pid,
                     st_uptime,
                     st_time,
                     st_version,
                     st_cmd_get,
                     st_cmd_set,
                     st_cmd_flush,
                     st_cmd_touch,
                     st_get_hits,
                     st_get_misses,
                     st_delete_hits,
                     st_delete_misses,
                     st_bytes_read,
                     st_bytes_written,
                     st_limit_maxbytes,
                     st_bytes,
                     st_curr_items,
                     st_total_items,
                     st_evictions,
                     st_reclaimed]));
}

// Version

#[test]
fn test_cmd_version() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Set a key
    let cmd = Cmd::Version;
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Version(get_version_string()));
}

// Item expiration cases

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_cmd_relative_exptime() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Set a key with exptime of 1 second
    let set = Set::new(SetInstr::Set, key_name, 0, 1, blob.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it right away - succeeds
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, resp.get_first_value().unwrap().data);

    // sleep 1.5 secs - long enough to expire key
    sleep_secs(1.5);

    // Retrieve the key again - it's gone
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_cmd_absolute_exptime() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];
    let exp = time_now().round() as u32 + 1;

    // Set a key with exptime of 1 second
    let set = Set::new(SetInstr::Set, key_name, 0, exp, blob.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it right away - succeeds
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, resp.get_first_value().unwrap().data);

    // sleep 2.5 secs - long enough to expire key
    sleep_secs(2.5);

    // Retrieve the key again - it's gone
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());
}
<commit_msg>organize test module<commit_after>use common::consts::get_version_string;
use platform::process::get_pid;
use platform::time::sleep_secs;
use platform::time::time_now;
use storage::Cache;

use super::Driver;
use super::cmd::Cmd;
use super::cmd::Delete;
use super::cmd::Get;
use super::cmd::Resp;
use super::cmd::Set;
use super::cmd::SetInstr;
use super::cmd::Stat;
use super::cmd::Value;

// Add

#[test]
fn test_cmd_add() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Add a new key
    let set = Set::new(SetInstr::Add, "x", 4, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Make sure it was added
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(vec![8, 9], resp.get_first_value().unwrap().data);
    assert_eq!(4, resp.get_first_value().unwrap().flags);

    // Try using add to overwrite an existing key
    let set = Set::new(SetInstr::Add, "x", 5, 0, vec![11], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::NotStored);

    // Make sure it was not overwritten
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(vec![8, 9], resp.get_first_value().unwrap().data);
    assert_eq!(4, resp.get_first_value().unwrap().flags);

    // Add with noreply
    let set = Set::new(SetInstr::Add, "y", 5, 0, vec![11], true);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Empty);

    // Make sure it was added
    let cmd = Cmd::Get(Get::one("y"));
    let resp = driver.run(cmd);
    assert_eq!(vec![11], resp.get_first_value().unwrap().data);
    assert_eq!(5, resp.get_first_value().unwrap().flags);
}

// Delete

#[test]
fn test_cmd_delete() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Try to delete a key that does not exist
    let cmd = Cmd::Delete(Delete::new("z", false));
    let resp = driver.run(cmd);
    assert_eq!(Resp::NotFound, resp);

    // Again, but now with noreply flag
    let cmd = Cmd::Delete(Delete::new("z", true));
    let resp = driver.run(cmd);
    assert_eq!(Resp::Empty, resp);

    // Set a key we can delete later
    let set = Set::new(SetInstr::Set, "x", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // And another
    let set = Set::new(SetInstr::Set, "y", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Delete the first one
    let cmd = Cmd::Delete(Delete::new("x", false));
    let resp = driver.run(cmd);
    assert_eq!(Resp::Deleted, resp);

    // Make sure it's gone
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());

    // Delete the second - with noreply
    let cmd = Cmd::Delete(Delete::new("y", true));
    let resp = driver.run(cmd);
    assert_eq!(Resp::Empty, resp);

    // Make sure it's gone
    let cmd = Cmd::Get(Get::one("y"));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());
}

// Get and Set

#[test]
fn test_cmd_set_and_get_a_key() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Try to retrieve a key not set
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());

    // Set a key
    let set = Set::new(SetInstr::Set, key_name, 15, 0, blob.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(15, resp.get_first_value().unwrap().flags);
    assert_eq!(blob, resp.get_first_value().unwrap().data);

    // Set a key with noreply flag
    let set = Set::new(SetInstr::Set, "y", 15, 0, blob.clone(), true);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Empty);

    // Retrieve it
    let cmd = Cmd::Get(Get::one("y"));
    let resp = driver.run(cmd);
    assert_eq!(15, resp.get_first_value().unwrap().flags);
    assert_eq!(blob, resp.get_first_value().unwrap().data);
}

#[test]
fn test_cmd_set_and_get_multiple_keys() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let val1 = vec![1];
    let val3 = vec![3];

    // Set two keys
    let set = Set::new(SetInstr::Set, "a", 15, 0, val1.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    let set = Set::new(SetInstr::Set, "c", 17, 0, val3.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Try to retrieve three keys - get two
    let keys = vec!["a".to_string(), "b".to_string(), "c".to_string()];
    let cmd = Cmd::Get(Get::new(keys));
    let resp = driver.run(cmd);

    let values = resp.get_values().unwrap();
    let val1 = Value::new("a", 15, val1);
    let val3 = Value::new("c", 17, val3);
    assert_eq!(2, values.len());
    assert_eq!(val1, values[0]);
    assert_eq!(val3, values[1]);
}

// Replace

#[test]
fn test_cmd_replace() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Try to replace an non-existent key
    let set = Set::new(SetInstr::Replace, "x", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::NotStored);

    // Set a key
    let set = Set::new(SetInstr::Set, "x", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Replace a valid key
    let set = Set::new(SetInstr::Replace, "x", 4, 0, vec![10], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Make sure it was updated
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(vec![10], resp.get_first_value().unwrap().data);
    assert_eq!(4, resp.get_first_value().unwrap().flags);

    // Replace a valid key in noreply mode
    let set = Set::new(SetInstr::Replace, "x", 6, 0, vec![11], true);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Empty);

    // Make sure it was updated
    let cmd = Cmd::Get(Get::one("x"));
    let resp = driver.run(cmd);
    assert_eq!(vec![11], resp.get_first_value().unwrap().data);
    assert_eq!(6, resp.get_first_value().unwrap().flags);
}

// Stats

#[test]
fn test_cmd_stats() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Set a key
    let set = Set::new(SetInstr::Set, "x", 0, 0, vec![8, 9], false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it
    let cmd = Cmd::Get(Get::one("x"));
    driver.run(cmd);

    // Run stats
    let cmd = Cmd::Stats;
    let resp = driver.run(cmd);

    let st_pid = Stat::new("pid", get_pid().to_string());
    let st_bytes = Stat::new("bytes", "3".to_string());
    let st_uptime = Stat::new("uptime", "0".to_string());
    let st_time = Stat::new("time", (time_now() as u64).to_string());
    let st_version = Stat::new("version", get_version_string());
    let st_cmd_get = Stat::new("cmd_get", "1".to_string());
    let st_cmd_set = Stat::new("cmd_set", "1".to_string());
    let st_cmd_flush = Stat::new("cmd_flush", "0".to_string());
    let st_cmd_touch = Stat::new("cmd_touch", "0".to_string());
    let st_get_hits = Stat::new("get_hits", "1".to_string());
    let st_get_misses = Stat::new("get_misses", "0".to_string());
    let st_delete_hits = Stat::new("delete_hits", "0".to_string());
    let st_delete_misses = Stat::new("delete_misses", "0".to_string());
    let st_bytes_read = Stat::new("bytes_read", "0".to_string());
    let st_bytes_written = Stat::new("bytes_written", "0".to_string());
    let st_limit_maxbytes = Stat::new("limit_maxbytes", "100".to_string());
    let st_curr_items = Stat::new("curr_items", "1".to_string());
    let st_total_items = Stat::new("total_items", "1".to_string());
    let st_evictions = Stat::new("evictions", "0".to_string());
    let st_reclaimed = Stat::new("reclaimed", "0".to_string());

    let stats = resp.get_stats().unwrap();
    assert_eq!(*stats,
               (vec![st_pid,
                     st_uptime,
                     st_time,
                     st_version,
                     st_cmd_get,
                     st_cmd_set,
                     st_cmd_flush,
                     st_cmd_touch,
                     st_get_hits,
                     st_get_misses,
                     st_delete_hits,
                     st_delete_misses,
                     st_bytes_read,
                     st_bytes_written,
                     st_limit_maxbytes,
                     st_bytes,
                     st_curr_items,
                     st_total_items,
                     st_evictions,
                     st_reclaimed]));
}

// Version

#[test]
fn test_cmd_version() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    // Set a key
    let cmd = Cmd::Version;
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Version(get_version_string()));
}

// Item expiration cases

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_cmd_relative_exptime() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];

    // Set a key with exptime of 1 second
    let set = Set::new(SetInstr::Set, key_name, 0, 1, blob.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it right away - succeeds
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, resp.get_first_value().unwrap().data);

    // sleep 1.5 secs - long enough to expire key
    sleep_secs(1.5);

    // Retrieve the key again - it's gone
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_cmd_absolute_exptime() {
    let cache = Cache::new(100);
    let mut driver = Driver::new(cache);

    let key_name = "x";
    let blob = vec![1, 2, 3];
    let exp = time_now().round() as u32 + 1;

    // Set a key with exptime of 1 second
    let set = Set::new(SetInstr::Set, key_name, 0, exp, blob.clone(), false);
    let cmd = Cmd::Set(set);
    let resp = driver.run(cmd);
    assert_eq!(resp, Resp::Stored);

    // Retrieve it right away - succeeds
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(blob, resp.get_first_value().unwrap().data);

    // sleep 2.5 secs - long enough to expire key
    sleep_secs(2.5);

    // Retrieve the key again - it's gone
    let cmd = Cmd::Get(Get::one(key_name));
    let resp = driver.run(cmd);
    assert_eq!(0, resp.get_values().unwrap().len());
}
<|endoftext|>


<commit_before>pub fn float_to_fixed(before: int, f: float) -> i32 {
    (1i32 << before) * (f as i32)
}

pub fn fixed_to_float(before: int, f: i32) -> float {
    f as float * 1.0f / ((1i32 << before) as float)
}

pub fn fixed_to_rounded_int(before: int, f: i32) -> int {
    let half = 1i32 << (before-1);
    if f > 0i32 {
        ((half + f) >> before) as int
    } else {
       -((half - f) >> before) as int
    }
}

/* Generate a 32-bit TrueType tag from its 4 charecters */
pub fn true_type_tag(a: char, b: char, c: char, d: char) -> u32 {
    (a << 24 | b << 16 | c << 8 | d) as u32
}

#[test]
fn test_true_type_tag() {
    assert true_type_tag('c', 'm', 'a', 'p') == 0x_63_6D_61_70_u32;
}
<commit_msg>charecters -> characters<commit_after>pub fn float_to_fixed(before: int, f: float) -> i32 {
    (1i32 << before) * (f as i32)
}

pub fn fixed_to_float(before: int, f: i32) -> float {
    f as float * 1.0f / ((1i32 << before) as float)
}

pub fn fixed_to_rounded_int(before: int, f: i32) -> int {
    let half = 1i32 << (before-1);
    if f > 0i32 {
        ((half + f) >> before) as int
    } else {
       -((half - f) >> before) as int
    }
}

/* Generate a 32-bit TrueType tag from its 4 characters */
pub fn true_type_tag(a: char, b: char, c: char, d: char) -> u32 {
    (a << 24 | b << 16 | c << 8 | d) as u32
}

#[test]
fn test_true_type_tag() {
    assert true_type_tag('c', 'm', 'a', 'p') == 0x_63_6D_61_70_u32;
}
<|endoftext|>


<commit_before>extern crate core;

use core::num::FromPrimitive;
use core::fmt;

use std::rand::random;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Trivial, OddBall};

#[derive(Copy)]
#[derive(Show)]
#[derive(PartialEq)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::String for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

impl fmt::String for Detector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Detector::{D12, D3, D9};
        let r = match self {
            &D12 => "12 oclock",
            &D3 => "3 oclock",
            &D9 => "9 oclock"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Trivial, // up-up-up -> down-down-down
    OddBall  // up-down-up -> down-up-down
}

#[derive(Show)]
#[derive(PartialEq)]
enum Detector {
    D12, // 12 o'clock
    D3, // 3 o'clock
    D9, // 9 o' clock
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, detector: &Detector) {
        self.spin = match detector {
            &Detector::D12 => SpinUp,
            &Detector::D3 => match random::<f32>() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
            &Detector::D9 => match random::<f32>() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
        };
    }

    // NOTE on spooky and premeditated only if measured in the same
    // direction must the spins be opposite

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let detector1 = Detector::D12; //Particle::get_detector_direction();
        let detector2 = Particle::get_detector_direction();

        self.measure (&detector1);

        if detector1 == detector2 { // 1/3
            friend.spin = match self.spin {
                SpinUp => SpinDown,
                SpinDown => SpinUp,
                _ => unreachable!()
            };
        } else { // 2/3
            friend.measure(&detector2);
        }

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    fn get_detector_direction () -> Detector {
        let rnd = random::<f32>();

        let detector = match rnd {
            0.0       ... 0.3333333 => Detector::D12,
            0.3333333 ... 0.6666666 => Detector::D3,
            0.6666666 ... 1.00 => Detector::D9,
            _ => unreachable!()
        };

        return detector;
    }

    pub fn hidden_information (&mut self, friend: &mut Particle, plan: Plan) -> Pair<Direction> {

        let rnd = random::<f32>();

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinUp,
            OddBall => match detector {
                Detector::D3 => SpinDown,
                _ => SpinUp
            }
        };
        friend.spin = spin;

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinDown,
            OddBall => match detector {
                Detector::D3 => SpinUp,
                _ => SpinDown
            }
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

// hidden_information should give +55.6% difference, spooky would give 50%
fn main () {

    let mut trials: f64 = 1000000f64;
    let mut num_different: f64 = 0f64;

    let particles = Particle::new_pair();
    let mut lhs = particles.lhs;
    let mut rhs = particles.rhs;

    for _ in range(0, trials as usize) {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        lhs.spooky(&mut rhs);

        if lhs.spin != rhs.spin {
            num_different += 1.0;
        }
    }

    println!("Percent different for spooky {}%", 100f64 * (num_different) / trials as f64);
    println!("      Should be about 1/2 or 50%");

    num_different = 0f64;

    for _ in range(0, trials as usize) {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        if random::<f32>() < 0.50 {
            lhs.hidden_information(&mut rhs, OddBall);
        } else {
            lhs.hidden_information(&mut rhs, Trivial);
        }

        //println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);
        if lhs.spin != rhs.spin {
            num_different += 1.0;
        }
    }

    println!("Percent different for hidden info {}%", 100f64 * (num_different) / trials as f64);
    println!("  Should be greater than 5/9th or {}%", 100.0 * 5.0/9.0);

}
<commit_msg>break out spooky and hidden into functions<commit_after>extern crate core;

use core::num::FromPrimitive;
use core::fmt;

use std::rand::random;

use Direction::{SpinUp, SpinDown, SpinSuper};
use Plan::{Trivial, OddBall};

#[derive(Copy)]
#[derive(Show)]
#[derive(PartialEq)]
enum Direction {
    SpinUp,
    SpinDown,
    SpinSuper,
}

impl fmt::String for Direction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let r = match self {
            &SpinUp => "SpinUp",
            &SpinDown => "SpinDown",
            &SpinSuper => "SpinSuper"
        };
        write!(f, "{}", r)
    }
}

impl fmt::String for Detector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use Detector::{D12, D3, D9};
        let r = match self {
            &D12 => "12 oclock",
            &D3 => "3 oclock",
            &D9 => "9 oclock"
        };
        write!(f, "{}", r)
    }
}

struct Pair<T> {
    lhs: T,
    rhs: T
}

struct Particle {
    spin: Direction
}

enum Plan {
    Trivial, // up-up-up -> down-down-down
    OddBall  // up-down-up -> down-up-down
}

#[derive(Show)]
#[derive(PartialEq)]
enum Detector {
    D12, // 12 o'clock
    D3, // 3 o'clock
    D9, // 9 o' clock
}

impl Particle {
    fn new_pair () -> Pair<Particle> {
        let d1 = SpinSuper;
        let d2 = SpinSuper;
        let p1 = Particle{spin: d1};
        let p2 = Particle{spin: d2};

        return Pair{lhs: p1, rhs: p2};
    }

    pub fn measure (&mut self, detector: &Detector) {
        self.spin = match detector {
            &Detector::D12 => SpinUp,
            &Detector::D3 => match random::<f32>() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
            &Detector::D9 => match random::<f32>() {
                0.0  ... 0.25 => SpinDown,
                0.25 ... 1.00 => SpinUp,
                _ => unreachable!()
            },
        };
    }

    // NOTE on spooky and premeditated only if measured in the same
    // direction must the spins be opposite

    // measure with with a message
    pub fn spooky (&mut self, friend: &mut Particle) -> Pair<Direction> {

        let detector1 = Detector::D12;
        let detector2 = Particle::get_detector_direction();

        self.measure (&detector1);

        if detector1 == detector2 { // 1/3
            friend.spin = match self.spin {
                SpinUp => SpinDown,
                SpinDown => SpinUp,
                _ => unreachable!()
            };
        } else { // 2/3
            friend.measure(&detector2);
        }

        return Pair{lhs: self.spin, rhs: friend.spin};
    }

    fn get_detector_direction () -> Detector {
        let rnd = random::<f32>();

        let detector = match rnd {
            0.0       ... 0.3333333 => Detector::D12,
            0.3333333 ... 0.6666666 => Detector::D3,
            0.6666666 ... 1.00 => Detector::D9,
            _ => unreachable!()
        };

        return detector;
    }

    pub fn hidden_information (&mut self, friend: &mut Particle, plan: Plan) -> Pair<Direction> {

        let rnd = random::<f32>();

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinUp,
            OddBall => match detector {
                Detector::D3 => SpinDown,
                _ => SpinUp
            }
        };
        friend.spin = spin;

        let detector = Particle::get_detector_direction();
        let spin = match plan {
            Trivial => SpinDown,
            OddBall => match detector {
                Detector::D3 => SpinUp,
                _ => SpinDown
            }
        };
        self.spin = spin;

        return Pair{lhs: self.spin, rhs: friend.spin};
    }
}

/**
 * run spooky for trials number of trials
 */
fn run_spooky (trials: f64) {
    let mut num_different: f64 = 0f64;

    let particles = Particle::new_pair();
    let mut lhs = particles.lhs;
    let mut rhs = particles.rhs;

    for _ in range(0, trials as usize) {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        lhs.spooky(&mut rhs);

        if lhs.spin != rhs.spin {
            num_different += 1.0;
        }
    }

    println!("Percent different for spooky {}%", 100f64 * (num_different) / trials as f64);
    println!("      Should be about 1/2 or 50%");
}

/**
 * Run test for hidden information, set the plan_probability to choose
 * OddBall vs Trivial
 */
fn run_hidden(trials: f64, plan_probability: f64) {

    let mut num_different = 0f64;
    let particles = Particle::new_pair();
    let mut lhs = particles.lhs;
    let mut rhs = particles.rhs;

    for _ in range(0, trials as usize) {
        let particles = Particle::new_pair();
        lhs = particles.lhs;
        rhs = particles.rhs;

        if random::<f32>() < 0.50 {
            lhs.hidden_information(&mut rhs, OddBall);
        } else {
            lhs.hidden_information(&mut rhs, Trivial);
        }

        //println!("lhs.spin {}, rhs.spin {}", lhs.spin, rhs.spin);
        if lhs.spin != rhs.spin {
            num_different += 1.0;
        }
    }

    println!("Percent different for hidden info {}%", 100f64 * (num_different) / trials as f64);
    println!("  Should be greater than 5/9th or {}%", 100.0 * 5.0/9.0);

}

// hidden_information should give +55.6% difference, spooky would give 50%
fn main () {

    let mut trials: f64 = 1000000f64;

    run_spooky(trials);
    run_hidden(trials, 0.5);
}
<|endoftext|>


<commit_before>use super::Mode;
use super::KeyMap;
use super::Key;
use super::Command;
use super::KeyMapState;
use super::Direction;
use super::WordEdgeMatch;
use super::OverlayType;

/// NormalMode mimics Vi's Normal mode.
pub struct NormalMode {
    keymap: KeyMap<Command>,
}

impl NormalMode {

    /// Create a new instance of NormalMode
    pub fn new() -> NormalMode {
        NormalMode {
            keymap: NormalMode::key_defaults(),
        }
    }

    /// Creates a KeyMap with default NormalMode key bindings
    fn key_defaults() -> KeyMap<Command> {
        let mut keymap = KeyMap::new();

        // movement
        keymap.bind_key(Key::Up, Command::MoveCursor(Direction::Up, 1));
        keymap.bind_key(Key::Down, Command::MoveCursor(Direction::Down, 1));
        keymap.bind_key(Key::Left, Command::MoveCursor(Direction::Left, 1));
        keymap.bind_key(Key::Right, Command::MoveCursor(Direction::Right, 1));
        keymap.bind_key(Key::Char('h'), Command::MoveCursor(Direction::Left, 1));
        keymap.bind_key(Key::Char('j'), Command::MoveCursor(Direction::Down, 1));
        keymap.bind_key(Key::Char('k'), Command::MoveCursor(Direction::Up, 1));
        keymap.bind_key(Key::Char('l'), Command::MoveCursor(Direction::Right, 1));
        keymap.bind_key(Key::Char('W'), Command::MoveCursor(Direction::RightWord(WordEdgeMatch::Whitespace), 1));
        keymap.bind_key(Key::Char('B'), Command::MoveCursor(Direction::LeftWord(WordEdgeMatch::Whitespace), 1));
        keymap.bind_key(Key::Char('w'), Command::MoveCursor(Direction::RightWord(WordEdgeMatch::Alphabet), 1));
        keymap.bind_key(Key::Char('b'), Command::MoveCursor(Direction::LeftWord(WordEdgeMatch::Alphabet), 1));
        keymap.bind_key(Key::Char('G'), Command::MoveCursor(Direction::LastLine, 0));
        keymap.bind_keys(&[Key::Char('g'), Key::Char('g')], Command::MoveCursor(Direction::FirstLine, 0));

        keymap.bind_key(Key::Char('0'), Command::LineStart);
        keymap.bind_key(Key::Char('$'), Command::LineEnd);

        // editing
        keymap.bind_keys(&[Key::Char('d'), Key::Char('W')], Command::Delete(Direction::RightWord(WordEdgeMatch::Whitespace), 1));
        keymap.bind_keys(&[Key::Char('d'), Key::Char('B')], Command::Delete(Direction::LeftWord(WordEdgeMatch::Whitespace), 1));
        keymap.bind_keys(&[Key::Char('d'), Key::Char('w')], Command::Delete(Direction::RightWord(WordEdgeMatch::Alphabet), 1));
        keymap.bind_keys(&[Key::Char('d'), Key::Char('b')], Command::Delete(Direction::LeftWord(WordEdgeMatch::Alphabet), 1));
        keymap.bind_key(Key::Char('x'), Command::Delete(Direction::Right, 1));
        keymap.bind_key(Key::Char('X'), Command::Delete(Direction::Left, 1));
        keymap.bind_key(Key::Char('u'), Command::Undo);
        keymap.bind_key(Key::Ctrl('r'), Command::Redo);

        // open a prompt to the user
        keymap.bind_key(Key::Char(':'), Command::SetOverlay(OverlayType::Prompt));

        keymap
    }

}

impl Mode for NormalMode {
    /// Given a key, pass it through the NormalMode KeyMap and return the associated Command, if any.
    fn handle_key_event(&mut self, key: Key) -> Command {
        let result = self.builder.check_key(key);
        println!("commandbuilder: {:?} > {:?}\n", key, result);
        if let command::BuilderEvent::Complete(c) = result {
            if let command::Action::Instruction(command::Instruction::SetOverlay(o)) = c.action {
                return Command::SetOverlay(OverlayType::Prompt);
            }
        }
        return Command::InsertChar('\n');

        // if let KeyMapState::Match(command) = self.keymap.check_key(key) {
        //     return command
        // }

        Command::Unknown
    }
}

#[cfg(test)]
mod tests {
    use editor::Command;
    use buffer::Direction;
    use keyboard::Key;
    use modes::Mode;
    use super::*;

    fn expect_key_command(k: Key, c: Command) {
        let mut mode: Box<Mode> = Box::new(NormalMode::new());
        let command = mode.handle_key_event(k);
        assert_eq!(command, c)
    }

    #[test]
    fn test_movement_keybindings() {
        expect_key_command(Key::Char('h'), Command::MoveCursor(Direction::Left, 1));
        expect_key_command(Key::Char('j'), Command::MoveCursor(Direction::Down, 1));
        expect_key_command(Key::Char('k'), Command::MoveCursor(Direction::Up, 1));
        expect_key_command(Key::Char('l'), Command::MoveCursor(Direction::Right, 1));
    }
}
<commit_msg>Add command::Builder to Normal mode<commit_after>use super::Mode;
use super::KeyMap;
use super::Key;
use super::Command;
use super::KeyMapState;
use super::Direction;
use super::WordEdgeMatch;
use super::OverlayType;

use command;

/// NormalMode mimics Vi's Normal mode.
pub struct NormalMode {
    keymap: KeyMap<Command>,
    builder: command::Builder,
}

impl NormalMode {

    /// Create a new instance of NormalMode
    pub fn new() -> NormalMode {
        NormalMode {
            keymap: NormalMode::key_defaults(),
            builder: command::Builder::new(),
        }
    }

    /// Creates a KeyMap with default NormalMode key bindings
    fn key_defaults() -> KeyMap<Command> {
        let mut keymap = KeyMap::new();

        // movement
        keymap.bind_key(Key::Up, Command::MoveCursor(Direction::Up, 1));
        keymap.bind_key(Key::Down, Command::MoveCursor(Direction::Down, 1));
        keymap.bind_key(Key::Left, Command::MoveCursor(Direction::Left, 1));
        keymap.bind_key(Key::Right, Command::MoveCursor(Direction::Right, 1));
        keymap.bind_key(Key::Char('h'), Command::MoveCursor(Direction::Left, 1));
        keymap.bind_key(Key::Char('j'), Command::MoveCursor(Direction::Down, 1));
        keymap.bind_key(Key::Char('k'), Command::MoveCursor(Direction::Up, 1));
        keymap.bind_key(Key::Char('l'), Command::MoveCursor(Direction::Right, 1));
        keymap.bind_key(Key::Char('W'), Command::MoveCursor(Direction::RightWord(WordEdgeMatch::Whitespace), 1));
        keymap.bind_key(Key::Char('B'), Command::MoveCursor(Direction::LeftWord(WordEdgeMatch::Whitespace), 1));
        keymap.bind_key(Key::Char('w'), Command::MoveCursor(Direction::RightWord(WordEdgeMatch::Alphabet), 1));
        keymap.bind_key(Key::Char('b'), Command::MoveCursor(Direction::LeftWord(WordEdgeMatch::Alphabet), 1));
        keymap.bind_key(Key::Char('G'), Command::MoveCursor(Direction::LastLine, 0));
        keymap.bind_keys(&[Key::Char('g'), Key::Char('g')], Command::MoveCursor(Direction::FirstLine, 0));

        keymap.bind_key(Key::Char('0'), Command::LineStart);
        keymap.bind_key(Key::Char('$'), Command::LineEnd);

        // editing
        keymap.bind_keys(&[Key::Char('d'), Key::Char('W')], Command::Delete(Direction::RightWord(WordEdgeMatch::Whitespace), 1));
        keymap.bind_keys(&[Key::Char('d'), Key::Char('B')], Command::Delete(Direction::LeftWord(WordEdgeMatch::Whitespace), 1));
        keymap.bind_keys(&[Key::Char('d'), Key::Char('w')], Command::Delete(Direction::RightWord(WordEdgeMatch::Alphabet), 1));
        keymap.bind_keys(&[Key::Char('d'), Key::Char('b')], Command::Delete(Direction::LeftWord(WordEdgeMatch::Alphabet), 1));
        keymap.bind_key(Key::Char('x'), Command::Delete(Direction::Right, 1));
        keymap.bind_key(Key::Char('X'), Command::Delete(Direction::Left, 1));
        keymap.bind_key(Key::Char('u'), Command::Undo);
        keymap.bind_key(Key::Ctrl('r'), Command::Redo);

        // open a prompt to the user
        keymap.bind_key(Key::Char(':'), Command::SetOverlay(OverlayType::Prompt));

        keymap
    }

}

impl Mode for NormalMode {
    /// Given a key, pass it through the NormalMode KeyMap and return the associated Command, if any.
    fn handle_key_event(&mut self, key: Key) -> Command {
        let result = self.builder.check_key(key);
        println!("commandbuilder: {:?} > {:?}\n", key, result);
        if let command::BuilderEvent::Complete(c) = result {
            if let command::Action::Instruction(command::Instruction::SetOverlay(o)) = c.action {
                return Command::SetOverlay(OverlayType::Prompt);
            }
        }
        return Command::InsertChar('\n');

        // if let KeyMapState::Match(command) = self.keymap.check_key(key) {
        //     return command
        // }

        Command::Unknown
    }
}

#[cfg(test)]
mod tests {
    use editor::Command;
    use buffer::Direction;
    use keyboard::Key;
    use modes::Mode;
    use super::*;

    fn expect_key_command(k: Key, c: Command) {
        let mut mode: Box<Mode> = Box::new(NormalMode::new());
        let command = mode.handle_key_event(k);
        assert_eq!(command, c)
    }

    #[test]
    fn test_movement_keybindings() {
        expect_key_command(Key::Char('h'), Command::MoveCursor(Direction::Left, 1));
        expect_key_command(Key::Char('j'), Command::MoveCursor(Direction::Down, 1));
        expect_key_command(Key::Char('k'), Command::MoveCursor(Direction::Up, 1));
        expect_key_command(Key::Char('l'), Command::MoveCursor(Direction::Right, 1));
    }
}
<|endoftext|>