<commit_before>extern crate hyper;

use std::sync::mpsc::{Receiver, channel};
use std::thread;
use args::Config;
use run_info::RunInfo;
use misc::split_number;
use tokio_core::reactor::Core;
use chrono::{Duration, Local, DateTime};
use hyper::{Client, Url};
use std::str::FromStr;
use hyper::client::HttpConnector;

use futures::{Future, stream};
use futures::future::{ok, loop_fn, Loop};
use futures::Stream;
use futures_utils::stopwatch;
use request_result::RequestResult;

/// Delegates and manages all the work.
pub struct Boss {
    /// Number of requests successfully completed
    pub requests_completed: usize,
    /// Number of active connections
    pub connections: usize,
    num_threads: usize,
}

impl Boss {
    pub fn new(num_threads: usize) -> Self {
        Boss {
            requests_completed: 0,
            connections: 0,
            num_threads: num_threads,
        }
    }

    pub fn start_workforce(&self, config: &Config) -> RunInfo {
        let (tx, rx) = channel();
        let desired_connections_per_worker_iter = split_number(config.num_connections,
                                                               self.num_threads);
        // start num_threads workers
        for desired_connections_per_worker in desired_connections_per_worker_iter {
            let tx = tx.clone();
            let url = config.url.clone();
            let duration = config.duration;
            let timeout = config.timeout.to_std().unwrap();
            let hyper_url = Url::from_str(&url).expect("Invalid URL");
            let start_time = Local::now();
            let wanted_end_time = start_time + duration;
            thread::spawn(move || {

                let mut core = Core::new().unwrap();
                let hyper_client = hyper::Client::configure()
                    .keep_alive_timeout(Some(timeout))
                    .build(&core.handle());

                let iterator = (0..desired_connections_per_worker).map(|_| {
                    create_looping_worker(duration,
                                          hyper_url.clone(),
                                          &hyper_client,
                                          wanted_end_time)
                });
                let future = stream::futures_unordered(iterator)
                    .fold(RunInfo::new(duration), |mut runinfo_acc, runinfo| {
                        runinfo_acc.merge(&runinfo);
                        ok(runinfo_acc)
                    });
                let res = core.run(future).unwrap();
                tx.send(res).unwrap();
            });
        }

        self.collect_workers(rx, config.duration)
    }

    /// Collects information from all workers
    fn collect_workers(&self, rx: Receiver<RunInfo>, run_duration: Duration) -> RunInfo {
        rx.iter()
            .take(self.num_threads)
            .fold(RunInfo::new(run_duration), |mut runinfo_acc, runinfo| {
                runinfo_acc.merge(&runinfo);
                runinfo_acc
            })
    }
}

fn create_looping_worker<'a>(duration: Duration,
                             url: Url,
                             hyper_client: &'a Client<HttpConnector>,
                             wanted_end_time: DateTime<Local>)
                             -> impl Future<Item = RunInfo, Error = ()> + 'a {
    let runinfo = RunInfo::new(duration);
    loop_fn((runinfo), move |mut runinfo| {
        let url = url.clone();
        send_request(url, hyper_client).then(move |res| {
            match res {
                // on request success
                Ok(request_res) => {
                    // update histogram
                    request_res.latency
                        .num_nanoseconds()
                        .map(|x| runinfo.histogram.increment(x as u64).ok());
                    runinfo.requests_completed += 1;

                    let state = runinfo;

                    let now_time = Local::now();
                    if now_time < wanted_end_time {
                        Ok(Loop::Continue(state))
                    } else {
                        Ok(Loop::Break(state))
                    }
                }
                // on request failure
                Err(_) => {
                    runinfo.num_failed_requests += 1;
                    let state = runinfo;
                    let now_time = Local::now();
                    if now_time < wanted_end_time {
                        Ok(Loop::Continue(state))
                    } else {
                        Ok(Loop::Break(state))
                    }
                }
            }
        })
    })
}

fn send_request<C>(url: Url,
                   hyper_client: &Client<C>)
                   -> impl Future<Item = RequestResult, Error = hyper::Error>
    where C: hyper::client::Connect
{
    stopwatch(hyper_client.get(url)).and_then(|(_, latency)| {
        let request_result = RequestResult::new(latency);
        Ok(request_result)
    })
}
<commit_msg>loop_iter<commit_after>extern crate hyper;

use std::sync::mpsc::{Receiver, channel};
use std::thread;
use args::Config;
use run_info::RunInfo;
use misc::split_number;
use tokio_core::reactor::Core;
use chrono::{Duration, Local, DateTime};
use hyper::{Client, Url};
use std::str::FromStr;
use hyper::client::HttpConnector;

use futures::{Future, stream};
use futures::future::{ok, loop_fn, Loop};
use futures::Stream;
use futures_utils::stopwatch;
use request_result::RequestResult;

/// Delegates and manages all the work.
pub struct Boss {
    /// Number of requests successfully completed
    pub requests_completed: usize,
    /// Number of active connections
    pub connections: usize,
    num_threads: usize,
}

impl Boss {
    pub fn new(num_threads: usize) -> Self {
        Boss {
            requests_completed: 0,
            connections: 0,
            num_threads: num_threads,
        }
    }

    pub fn start_workforce(&self, config: &Config) -> RunInfo {
        let (tx, rx) = channel();
        let desired_connections_per_worker_iter = split_number(config.num_connections,
                                                               self.num_threads);
        // start num_threads workers
        for desired_connections_per_worker in desired_connections_per_worker_iter {
            let tx = tx.clone();
            let url = config.url.clone();
            let duration = config.duration;
            let timeout = config.timeout.to_std().unwrap();
            let hyper_url = Url::from_str(&url).expect("Invalid URL");
            let start_time = Local::now();
            let wanted_end_time = start_time + duration;
            thread::spawn(move || {

                let mut core = Core::new().unwrap();
                let hyper_client = hyper::Client::configure()
                    .keep_alive_timeout(Some(timeout))
                    .build(&core.handle());

                let iterator = (0..desired_connections_per_worker).map(|_| {
                    create_looping_worker(duration,
                                          hyper_url.clone(),
                                          &hyper_client,
                                          wanted_end_time)
                });
                let future = stream::futures_unordered(iterator)
                    .fold(RunInfo::new(duration), |mut runinfo_acc, runinfo| {
                        runinfo_acc.merge(&runinfo);
                        ok(runinfo_acc)
                    });
                let res = core.run(future).unwrap();
                tx.send(res).unwrap();
            });
        }

        self.collect_workers(rx, config.duration)
    }

    /// Collects information from all workers
    fn collect_workers(&self, rx: Receiver<RunInfo>, run_duration: Duration) -> RunInfo {
        rx.iter()
            .take(self.num_threads)
            .fold(RunInfo::new(run_duration), |mut runinfo_acc, runinfo| {
                runinfo_acc.merge(&runinfo);
                runinfo_acc
            })
    }
}

fn create_looping_worker<'a>(duration: Duration,
                             url: Url,
                             hyper_client: &'a Client<HttpConnector>,
                             wanted_end_time: DateTime<Local>)
                             -> impl Future<Item = RunInfo, Error = ()> + 'a {
    let runinfo = RunInfo::new(duration);
    loop_fn((runinfo), move |mut runinfo| {
        let url = url.clone();
        send_request(url, hyper_client).then(move |res| {
            match res {
                // on request success
                Ok(request_res) => {
                    // update histogram
                    request_res.latency
                        .num_nanoseconds()
                        .map(|x| runinfo.histogram.increment(x as u64).ok());
                    runinfo.requests_completed += 1;
                    loop_iter(runinfo, wanted_end_time)
                }
                // on request failure
                Err(_) => {
                    runinfo.num_failed_requests += 1;
                    loop_iter(runinfo, wanted_end_time)
                }
            }
        })
    })
}

/// Determines what the next loop iteration should be; Continue or break.
fn loop_iter(state: RunInfo,
             wanted_end_time: DateTime<Local>)
             -> impl Future<Item = Loop<RunInfo, RunInfo>, Error = ()> {
    let now_time = Local::now();
    if now_time < wanted_end_time {
        ok(Loop::Continue(state))
    } else {
        ok(Loop::Break(state))
    }
}

fn send_request<C>(url: Url,
                   hyper_client: &Client<C>)
                   -> impl Future<Item = RequestResult, Error = hyper::Error>
    where C: hyper::client::Connect
{
    stopwatch(hyper_client.get(url)).and_then(|(_, latency)| {
        let request_result = RequestResult::new(latency);
        Ok(request_result)
    })
}
<|endoftext|>


<commit_before>extern crate ascii;

use std::marker::PhantomData;

use self::ascii::AsciiChar;

use combinator::{Expected, ParserExt, satisfy, Satisfy, skip_many, SkipMany, token, Token, With};
use primitives::{Consumed, ConsumedResult, Error, Info, Parser, ParseError, Stream};

/// Parses a u8acter and succeeds if the u8acter is equal to `c`
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::byte::byte;
/// # fn main() {
/// let result = byte(b'!')
///     .parse(&b"!"[..])
///     .map(|x| x.0);
/// assert_eq!(result, Ok(b'!'));
/// # }
/// ```
#[inline(always)]
pub fn byte<I>(c: u8) -> Token<I>
    where I: Stream<Item = u8>
{
    token(c)
}

impl_token_parser! { Digit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

macro_rules! byte_parser {
    ($name: ident, $ty : ident, $f : ident) => ({
        let f = static_fn!((c, u8) -> bool {
            AsciiChar::from(c).map(|c| c.$f()).unwrap_or(false)
        });
        $ty(satisfy(f).expected(stringify!($name)), PhantomData)
    })
}

/// Parses a digit from a stream containing u8acters
#[inline(always)]
pub fn digit<I>() -> Digit<I>
    where I: Stream<Item = u8>
{
    byte_parser!(digit, Digit, is_digit)
}

impl_token_parser! { Space(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

/// Parses whitespace
#[inline(always)]
pub fn space<I>() -> Space<I>
    where I: Stream<Item = u8>
{
    byte_parser!(space, Space, is_whitespace)
}

impl_token_parser! { Spaces(), u8, Expected<SkipMany<Space<I>>> }
/// Skips over zero or more spaces
#[inline(always)]
pub fn spaces<I>() -> Spaces<I>
    where I: Stream<Item = u8>
{
    Spaces(skip_many(space()).expected("whitespaces"), PhantomData)
}

impl_token_parser! { Newline(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

/// Parses a newline character
#[inline(always)]
pub fn newline<I>() -> Newline<I>
    where I: Stream<Item = u8>
{
    Newline(satisfy(static_fn!((ch, u8) -> bool { ch == b'\n' })).expected("lf newline"),
            PhantomData)
}

impl_token_parser! { CrLf(), u8, Expected<With<Satisfy<I, fn (u8) -> bool>, Newline<I>>> }

/// Parses carriage return and newline, returning the newline character.
#[inline(always)]
pub fn crlf<I>() -> CrLf<I>
    where I: Stream<Item = u8>
{
    CrLf(satisfy(static_fn!((ch, u8) -> bool { ch == b'\r' }))
             .with(newline())
             .expected("crlf newline"),
         PhantomData)
}

impl_token_parser! { Tab(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses a tab u8acter
#[inline(always)]
pub fn tab<I>() -> Tab<I>
    where I: Stream<Item = u8>
{
    Tab(satisfy(static_fn!((ch, u8) -> bool { ch == b'\t' })).expected("tab"),
        PhantomData)
}

impl_token_parser! { Upper(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an uppercase letter
#[inline(always)]
pub fn upper<I>() -> Upper<I>
    where I: Stream<Item = u8>
{
    byte_parser!(upper, Upper, is_uppercase)
}

impl_token_parser! { Lower(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an lowercase letter
#[inline(always)]
pub fn lower<I>() -> Lower<I>
    where I: Stream<Item = u8>
{
    byte_parser!(lower, Lower, is_lowercase)
}

impl_token_parser! { AlphaNum(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses either an alphabet letter or digit
#[inline(always)]
pub fn alpha_num<I>() -> AlphaNum<I>
    where I: Stream<Item = u8>
{
    byte_parser!(alpha_num, AlphaNum, is_alphanumeric)
}

impl_token_parser! { Letter(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an alphabet letter
#[inline(always)]
pub fn letter<I>() -> Letter<I>
    where I: Stream<Item = u8>
{
    byte_parser!(letter, Letter, is_alphabetic)
}

impl_token_parser! { HexDigit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses a hexdecimal digit with uppercase and lowercase
#[inline(always)]
pub fn hex_digit<I>() -> HexDigit<I>
    where I: Stream<Item = u8>
{
    byte_parser!(hex_digit, HexDigit, is_hex)
}

#[derive(Clone)]
pub struct Bytes<I>(&'static [u8], PhantomData<I>);
impl<'a, I> Parser for Bytes<I>
    where I: Stream<Item = u8, Range = &'a [u8]>
{
    type Input = I;
    type Output = &'static [u8];
    #[inline]
    fn parse_lazy(&mut self, mut input: I) -> ConsumedResult<&'static [u8], I> {
        let start = input.position();
        let mut consumed = false;
        for &c in self.0 {
            match ::primitives::uncons(input) {
                Ok((other, rest)) => {
                    if c != other {
                        return Err(if consumed {
                                let errors = vec![Error::Unexpected(Info::Token(other)),
                                                  Error::Expected(Info::Range(self.0))];
                                let error = ParseError::from_errors(start, errors);
                                Consumed::Consumed(error)
                            } else {
                                Consumed::Empty(ParseError::empty(start))
                            })
                            .into();
                    }
                    consumed = true;
                    input = rest.into_inner();
                }
                Err(error) => {
                    return error.combine_fast(|mut error| {
                        error.position = start;
                        Err(if consumed {
                                Consumed::Consumed(error)
                            } else {
                                Consumed::Empty(error)
                            })
                            .into()
                    })
                }
            }
        }
        Ok((self.0,
            if consumed {
                Consumed::Consumed(input)
            } else {
                Consumed::Empty(input)
            }))
            .into()
    }
    fn add_error(&mut self, errors: &mut ParseError<Self::Input>) {
        errors.add_error(Error::Expected(Info::Range(self.0)));
    }
}

/// Parses the bytes `s`. If you have a stream implementing `RangeStream` such as `&[u8]` you can
/// also use the `range` parser which may be more efficient.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::byte::bytes;
/// # fn main() {
/// let result = bytes(b"rust")
///     .parse(&b"rust"[..])
///     .map(|x| x.0);
/// assert_eq!(result, Ok(&b"rust"[..]));
/// # }
/// ```
#[inline(always)]
pub fn bytes<'a, I>(s: &'static [u8]) -> Bytes<I>
    where I: Stream<Item = u8, Range = &'a [u8]>
{
    Bytes(s, PhantomData)
}
<commit_msg>docs: u8acter -> character<commit_after>extern crate ascii;

use std::marker::PhantomData;

use self::ascii::AsciiChar;

use combinator::{Expected, ParserExt, satisfy, Satisfy, skip_many, SkipMany, token, Token, With};
use primitives::{Consumed, ConsumedResult, Error, Info, Parser, ParseError, Stream};

/// Parses a character and succeeds if the character is equal to `c`
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::byte::byte;
/// # fn main() {
/// let result = byte(b'!')
///     .parse(&b"!"[..])
///     .map(|x| x.0);
/// assert_eq!(result, Ok(b'!'));
/// # }
/// ```
#[inline(always)]
pub fn byte<I>(c: u8) -> Token<I>
    where I: Stream<Item = u8>
{
    token(c)
}

impl_token_parser! { Digit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

macro_rules! byte_parser {
    ($name: ident, $ty : ident, $f : ident) => ({
        let f = static_fn!((c, u8) -> bool {
            AsciiChar::from(c).map(|c| c.$f()).unwrap_or(false)
        });
        $ty(satisfy(f).expected(stringify!($name)), PhantomData)
    })
}

/// Parses a digit from a stream containing characters
#[inline(always)]
pub fn digit<I>() -> Digit<I>
    where I: Stream<Item = u8>
{
    byte_parser!(digit, Digit, is_digit)
}

impl_token_parser! { Space(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

/// Parses whitespace
#[inline(always)]
pub fn space<I>() -> Space<I>
    where I: Stream<Item = u8>
{
    byte_parser!(space, Space, is_whitespace)
}

impl_token_parser! { Spaces(), u8, Expected<SkipMany<Space<I>>> }
/// Skips over zero or more spaces
#[inline(always)]
pub fn spaces<I>() -> Spaces<I>
    where I: Stream<Item = u8>
{
    Spaces(skip_many(space()).expected("whitespaces"), PhantomData)
}

impl_token_parser! { Newline(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }

/// Parses a newline character
#[inline(always)]
pub fn newline<I>() -> Newline<I>
    where I: Stream<Item = u8>
{
    Newline(satisfy(static_fn!((ch, u8) -> bool { ch == b'\n' })).expected("lf newline"),
            PhantomData)
}

impl_token_parser! { CrLf(), u8, Expected<With<Satisfy<I, fn (u8) -> bool>, Newline<I>>> }

/// Parses carriage return and newline, returning the newline character.
#[inline(always)]
pub fn crlf<I>() -> CrLf<I>
    where I: Stream<Item = u8>
{
    CrLf(satisfy(static_fn!((ch, u8) -> bool { ch == b'\r' }))
             .with(newline())
             .expected("crlf newline"),
         PhantomData)
}

impl_token_parser! { Tab(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses a tab character
#[inline(always)]
pub fn tab<I>() -> Tab<I>
    where I: Stream<Item = u8>
{
    Tab(satisfy(static_fn!((ch, u8) -> bool { ch == b'\t' })).expected("tab"),
        PhantomData)
}

impl_token_parser! { Upper(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an uppercase letter
#[inline(always)]
pub fn upper<I>() -> Upper<I>
    where I: Stream<Item = u8>
{
    byte_parser!(upper, Upper, is_uppercase)
}

impl_token_parser! { Lower(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an lowercase letter
#[inline(always)]
pub fn lower<I>() -> Lower<I>
    where I: Stream<Item = u8>
{
    byte_parser!(lower, Lower, is_lowercase)
}

impl_token_parser! { AlphaNum(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses either an alphabet letter or digit
#[inline(always)]
pub fn alpha_num<I>() -> AlphaNum<I>
    where I: Stream<Item = u8>
{
    byte_parser!(alpha_num, AlphaNum, is_alphanumeric)
}

impl_token_parser! { Letter(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses an alphabet letter
#[inline(always)]
pub fn letter<I>() -> Letter<I>
    where I: Stream<Item = u8>
{
    byte_parser!(letter, Letter, is_alphabetic)
}

impl_token_parser! { HexDigit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
/// Parses a hexdecimal digit with uppercase and lowercase
#[inline(always)]
pub fn hex_digit<I>() -> HexDigit<I>
    where I: Stream<Item = u8>
{
    byte_parser!(hex_digit, HexDigit, is_hex)
}

#[derive(Clone)]
pub struct Bytes<I>(&'static [u8], PhantomData<I>);
impl<'a, I> Parser for Bytes<I>
    where I: Stream<Item = u8, Range = &'a [u8]>
{
    type Input = I;
    type Output = &'static [u8];
    #[inline]
    fn parse_lazy(&mut self, mut input: I) -> ConsumedResult<&'static [u8], I> {
        let start = input.position();
        let mut consumed = false;
        for &c in self.0 {
            match ::primitives::uncons(input) {
                Ok((other, rest)) => {
                    if c != other {
                        return Err(if consumed {
                                let errors = vec![Error::Unexpected(Info::Token(other)),
                                                  Error::Expected(Info::Range(self.0))];
                                let error = ParseError::from_errors(start, errors);
                                Consumed::Consumed(error)
                            } else {
                                Consumed::Empty(ParseError::empty(start))
                            })
                            .into();
                    }
                    consumed = true;
                    input = rest.into_inner();
                }
                Err(error) => {
                    return error.combine_fast(|mut error| {
                        error.position = start;
                        Err(if consumed {
                                Consumed::Consumed(error)
                            } else {
                                Consumed::Empty(error)
                            })
                            .into()
                    })
                }
            }
        }
        Ok((self.0,
            if consumed {
                Consumed::Consumed(input)
            } else {
                Consumed::Empty(input)
            }))
            .into()
    }
    fn add_error(&mut self, errors: &mut ParseError<Self::Input>) {
        errors.add_error(Error::Expected(Info::Range(self.0)));
    }
}

/// Parses the bytes `s`. If you have a stream implementing `RangeStream` such as `&[u8]` you can
/// also use the `range` parser which may be more efficient.
///
/// ```
/// # extern crate combine;
/// # use combine::*;
/// # use combine::byte::bytes;
/// # fn main() {
/// let result = bytes(b"rust")
///     .parse(&b"rust"[..])
///     .map(|x| x.0);
/// assert_eq!(result, Ok(&b"rust"[..]));
/// # }
/// ```
#[inline(always)]
pub fn bytes<'a, I>(s: &'static [u8]) -> Bytes<I>
    where I: Stream<Item = u8, Range = &'a [u8]>
{
    Bytes(s, PhantomData)
}
<|endoftext|>


<commit_before>
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver, SendError};

use std::thread;

use rocket::Request;
use rocket::request::{FromRequest, Outcome};
use rocket::Outcome::{Success, Failure};
use rocket::http::Status;

use serial;
use serial::prelude::*;
use std::io::{Read, Write};

use std::collections::HashMap;

type TxChannelType = (String, Sender<String>);

#[derive(Clone)]
pub struct CommChannelTx(Sender<TxChannelType>);

impl CommChannelTx {
    pub fn send(&self, msg: String) -> Result<Receiver<String>, SendError<TxChannelType>> {
        let (response_tx, response_rx) = mpsc::channel();

        self.0.send((msg, response_tx))?;

        Ok(response_rx)
    }
}

// Inject the tx comm channel into each request
impl<'a, 'r> FromRequest<'a, 'r> for CommChannelTx {
    type Error = ();

    fn from_request(_: &'a Request<'r>) -> Outcome<Self, Self::Error> {
        if let &Some(ref comm) = unsafe { &COMM_CHANNEL_TX } {
            Success(comm.clone())
        } else {
            Failure((Status::InternalServerError, ()))
        }
    }
}

static mut COMM_CHANNEL_TX: Option<CommChannelTx> = None;

fn calc_checksum(input: &str) -> u8 {
    input.as_bytes().into_iter().fold(0, |csum, ch| csum ^ ch)
}

fn process_incoming_msg(raw_msg: &str) -> Result<(u64, &str), ()> {
    if raw_msg.len() < 4 {
        return Err(());
    }

    if raw_msg.as_bytes()[raw_msg.len() - 3] as char != '*' {
        return Err(());
    }

    let packet_csum = u8::from_str_radix(&raw_msg[(raw_msg.len() - 2)..], 16).unwrap();

    let msg_str = &raw_msg[..(raw_msg.len() - 3)];
    let calc_csum = calc_checksum(msg_str);

    if packet_csum != calc_csum {
        return Err(());
    }

    let comma_pos = msg_str.find(',').ok_or(())?;
    let transaction_id = msg_str[..comma_pos].parse().map_err(|_| ())?;
    let msg_payload_str = &msg_str[(comma_pos + 1)..];

    Ok((transaction_id, msg_payload_str))
}

fn comm_func<T>(channel_rx: Receiver<TxChannelType>, mut comm: T)
    where T: Read + Write
{
    let mut transaction_id_ctr: u64 = 0;
    let mut pending_transactions = HashMap::new();

    let mut current_packet = String::new();

    enum ParserState {
        WaitingForDollar,
        Receiving,
    }

    let mut current_state = ParserState::WaitingForDollar;

    loop {
        // Transmit all pending messages
        while let Ok((msg, resp_tx)) = channel_rx.try_recv() {
            transaction_id_ctr = transaction_id_ctr.wrapping_add(1);

            pending_transactions.insert(transaction_id_ctr, resp_tx);

            let mut out = format!("${},{}*", transaction_id_ctr, msg);
            let csum = calc_checksum(&out[1..(out.len() - 1)]);
            out.push_str(&format!("{:X}\r\n", csum));

            debug!("server -> mcu: '{}'", &out[..(out.len() - 2)]);

            let _ = comm.write_all(out.as_bytes());
        }

        // Parse all incoming chars
        let mut incoming = [0; 100];
        while let Ok(incoming_len) = comm.read(&mut incoming) {

            debug!("Rx buffer is now: {:?}", incoming.to_vec());

            for i in 0..incoming_len {
                let ch = incoming[i] as char;

                match current_state {
                    ParserState::WaitingForDollar => {
                        if ch == '$' {
                            current_state = ParserState::Receiving;
                        }
                    }
                    ParserState::Receiving => {
                        current_packet.push(ch);

                        if &current_packet[(current_packet.len() - 2)..] == "\r\n" {

                            match process_incoming_msg(&current_packet[..(current_packet.len() -
                                                           2)]) {
                                Ok((trans_id, payload_str)) => {
                                    debug!("Received trans id {}, payload {}",
                                           trans_id,
                                           payload_str);

                                    if let Some(response_channel) =
                                        pending_transactions.remove(&trans_id) {
                                        let _ = response_channel.send(payload_str.to_string());
                                    } else {
                                        warn!("Unexpected transition id {}!", trans_id);
                                    }
                                }
                                Err(e) => warn!("{:?}", e),
                            }

                            current_packet.clear();
                            current_state = ParserState::WaitingForDollar;
                        }
                    }
                }
            }
        }
    }
}

pub fn init() -> thread::JoinHandle<()> {
    let mut serial_port = serial::open("/dev/ttyUSB0").expect("Could not open serial port.");

    let settings = serial::PortSettings {
        baud_rate: serial::Baud115200,
        char_size: serial::Bits8,
        parity: serial::ParityNone,
        stop_bits: serial::Stop1,
        flow_control: serial::FlowNone,
    };
    serial_port.configure(&settings).expect("Could not configure the serial port.");

    let (channel_tx, channel_rx) = mpsc::channel();

    let join_handle = thread::spawn(|| comm_func(channel_rx, serial_port));

    unsafe { COMM_CHANNEL_TX = Some(CommChannelTx(channel_tx)) };

    join_handle
}
<commit_msg>Fixed checksum formatting & RX buffer indexing bugs<commit_after>
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver, SendError};

use std::thread;

use rocket::Request;
use rocket::request::{FromRequest, Outcome};
use rocket::Outcome::{Success, Failure};
use rocket::http::Status;

use serial;
use serial::prelude::*;
use std::io::{Read, Write};

use std::collections::HashMap;

type TxChannelType = (String, Sender<String>);

#[derive(Clone)]
pub struct CommChannelTx(Sender<TxChannelType>);

impl CommChannelTx {
    pub fn send(&self, msg: String) -> Result<Receiver<String>, SendError<TxChannelType>> {
        let (response_tx, response_rx) = mpsc::channel();

        self.0.send((msg, response_tx))?;

        Ok(response_rx)
    }
}

// Inject the tx comm channel into each request
impl<'a, 'r> FromRequest<'a, 'r> for CommChannelTx {
    type Error = ();

    fn from_request(_: &'a Request<'r>) -> Outcome<Self, Self::Error> {
        if let &Some(ref comm) = unsafe { &COMM_CHANNEL_TX } {
            Success(comm.clone())
        } else {
            Failure((Status::InternalServerError, ()))
        }
    }
}

static mut COMM_CHANNEL_TX: Option<CommChannelTx> = None;

fn calc_checksum(input: &str) -> u8 {
    input.as_bytes().into_iter().fold(0, |csum, ch| csum ^ ch)
}

fn process_incoming_msg(raw_msg: &str) -> Result<(u64, &str), ()> {
    if raw_msg.len() < 4 {
        return Err(());
    }

    if raw_msg.as_bytes()[raw_msg.len() - 3] as char != '*' {
        return Err(());
    }

    let packet_csum = u8::from_str_radix(&raw_msg[(raw_msg.len() - 2)..], 16).unwrap();

    let msg_str = &raw_msg[..(raw_msg.len() - 3)];
    let calc_csum = calc_checksum(msg_str);

    if packet_csum != calc_csum {
        return Err(());
    }

    let comma_pos = msg_str.find(',').ok_or(())?;
    let transaction_id = msg_str[..comma_pos].parse().map_err(|_| ())?;
    let msg_payload_str = &msg_str[(comma_pos + 1)..];

    Ok((transaction_id, msg_payload_str))
}

fn comm_func<T>(channel_rx: Receiver<TxChannelType>, mut comm: T)
    where T: Read + Write
{
    let mut transaction_id_ctr: u64 = 0;
    let mut pending_transactions = HashMap::new();

    let mut current_packet = String::new();

    enum ParserState {
        WaitingForDollar,
        Receiving,
    }

    let mut current_state = ParserState::WaitingForDollar;

    loop {
        // Transmit all pending messages
        while let Ok((msg, resp_tx)) = channel_rx.try_recv() {
            transaction_id_ctr = transaction_id_ctr.wrapping_add(1);

            pending_transactions.insert(transaction_id_ctr, resp_tx);

            let mut out = format!("${},{}*", transaction_id_ctr, msg);
            let csum = calc_checksum(&out[1..(out.len() - 1)]);
            out.push_str(&format!("{:02X}\r\n", csum));

            debug!("server -> mcu: '{}'", &out[..(out.len() - 2)]);

            let _ = comm.write_all(out.as_bytes());
        }

        // Parse all incoming chars
        let mut incoming = [0; 100];
        while let Ok(incoming_len) = comm.read(&mut incoming) {

            debug!("Rx buffer is now: {:?}", incoming.to_vec());

            for i in 0..incoming_len {
                let ch = incoming[i] as char;

                match current_state {
                    ParserState::WaitingForDollar => {
                        if ch == '$' {
                            current_state = ParserState::Receiving;
                        }
                    }
                    ParserState::Receiving => {
                        current_packet.push(ch);

                        let len = current_packet.len();
                        if len >= 2 && &current_packet[(len - 2)..] == "\r\n" {

                            match process_incoming_msg(&current_packet[..(len - 2)]) {
                                Ok((trans_id, payload_str)) => {
                                    debug!("Received trans id {}, payload {}",
                                           trans_id,
                                           payload_str);

                                    if let Some(response_channel) =
                                        pending_transactions.remove(&trans_id) {
                                        let _ = response_channel.send(payload_str.to_string());
                                    } else {
                                        warn!("Unexpected transition id {}!", trans_id);
                                    }
                                }
                                Err(e) => warn!("{:?}", e),
                            }

                            current_packet.clear();
                            current_state = ParserState::WaitingForDollar;
                        }
                    }
                }
            }
        }
    }
}

pub fn init() -> thread::JoinHandle<()> {
    let mut serial_port = serial::open("/dev/ttyUSB0").expect("Could not open serial port.");

    let settings = serial::PortSettings {
        baud_rate: serial::Baud115200,
        char_size: serial::Bits8,
        parity: serial::ParityNone,
        stop_bits: serial::Stop1,
        flow_control: serial::FlowNone,
    };
    serial_port.configure(&settings).expect("Could not configure the serial port.");

    let (channel_tx, channel_rx) = mpsc::channel();

    let join_handle = thread::spawn(|| comm_func(channel_rx, serial_port));

    unsafe { COMM_CHANNEL_TX = Some(CommChannelTx(channel_tx)) };

    join_handle
}
<|endoftext|>


<commit_before>use field::{Field, Content};
use ui::UI;
use ui::EndMessage;
use piston_window::*;
use common::{ParamType, MoveDestination, GameEndState};
use chrono::{DateTime, UTC, Duration};

enum RenderState {
    // redraw picture on current buffer
    First,

    // redraw picture on next buffer
    Second,

    // needn't redraw picture
    None
}

impl RenderState {

    // Update render state and return flag necessity of redrawing pickture
    fn update_state(&mut self) -> bool {
        match *self {
            RenderState::First  => *self = RenderState::Second,
            RenderState::Second => *self = RenderState::None,
            RenderState::None   => return false
        }

        true
    }

    fn reset(&mut self) {
        *self = RenderState::First
    }
}

pub struct Game<'a> {
    field: Field,
    ui: UI<'a>,
    msg: EndMessage<'a>,
    glyphs: Glyphs,
    mouse_x: f64,
    mouse_y: f64,
    game_ended: bool,
    panel_width: u32,
    in_ui: bool,
    game_start : Option<DateTime<UTC>>,
    last_time : Option<DateTime<UTC>>,
    game_end : Option<DateTime<UTC>>,
    // state of rendering for drawing picture on both buffers
    render_state: RenderState
}

impl<'a> Game<'a> {
    pub fn new(glyphs: Glyphs, width: u32, height: u32, mines: u32) -> Game<'a> {
        Game {
            field: Field::new(width, height, mines),
            ui: UI::new(width, height, mines),
            msg: EndMessage::new(),
            glyphs: glyphs,
            mouse_x: 0.0,
            mouse_y: 0.0,
            game_ended: false,
            panel_width: 350,
            in_ui: false,
            game_start: None,
            game_end: None,
            last_time: None,
            render_state: RenderState::First
        }
    }

    pub fn render(&mut self, window: &PistonWindow) {
        if !self.render_state.update_state() {
            return;
        }

        window.draw_2d(|c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);
            let field_rect = self.get_field_rect(window);
            self.field.draw(c, g, field_rect, &mut self.glyphs);

            let ui_rect = self.get_ui_rect(window);

            let dur = match self.game_start {
                Some(game_start) => match self.game_end {
                    Some(game_end) => game_end - game_start,
                    None => UTC::now() - game_start,
                },
                None => Duration::seconds(0),
            };

            self.ui.draw(c, g, ui_rect, &mut self.glyphs, self.field.total_mines(), self.field.count_marked(), dur);

            let msg_rect = self.get_msg_rect(window);
            self.msg.draw(c, g, msg_rect, &mut self.glyphs);
        });
    }

    fn get_field_rect(&self, window: &PistonWindow) -> [u32; 4] {
        let mut w = window.size().width - self.panel_width;
        w = (w /self.field.get_width()) * self.field.get_width();
        let mut h = window.size().height;
        h = (h /self.field.get_height()) * self.field.get_height();
        [0, 0, w, h]
    }

    fn get_ui_rect(&self, window: &PistonWindow) -> [u32; 4] {
        let mut field_w = window.size().width - self.panel_width;
        field_w = (field_w /self.field.get_width()) * self.field.get_width();
        let w = window.size().width - field_w;
        let h = window.size().height;
        [field_w, 0, w, h]
    }

    fn get_msg_rect(&self, window: &PistonWindow) -> [u32; 4] {
        let w_w = window.size().width;
        let w_h = window.size().height;
        let (m_w, m_h) = EndMessage::size();

        [
            ( (w_w-m_w) / 2 ),
            ( (w_h-m_h) / 2 ),
            m_w,
            m_h
        ]
    }

    pub fn proc_key(&mut self, button: Button, window: &PistonWindow) {
        let mut need_redraw = true;
        if self.in_ui {
            match button {
                Button::Keyboard(key) => {
                    match  key {
                        Key::H => {
                            match self.ui.proc_key(ParamType::Height) {
                                Some(h) => {
                                    self.in_ui = false;
                                    self.field.reinit_field(h, ParamType::Height);
                                    self.restart();
                                }
                                _ => need_redraw = false
                            }
                        },
                        Key::M => {
                            match self.ui.proc_key(ParamType::Mines) {
                                Some(m) => {
                                    self.in_ui = false;
                                    self.field.reinit_field(m, ParamType::Mines);
                                    self.restart();
                                }
                                _ => need_redraw = false
                            }
                        },
                        Key::W => {
                            match self.ui.proc_key(ParamType::Width) {
                                Some(w) => {
                                    self.in_ui = false;
                                    self.field.reinit_field(w, ParamType::Width);
                                    self.restart();
                                }
                                _ => need_redraw = false
                            }
                        },
                        Key::Up => self.ui.change_selected(MoveDestination::Up),
                        Key::Down => self.ui.change_selected(MoveDestination::Down),
                        Key::Left => self.ui.change_selected(MoveDestination::Left),
                        Key::Right => self.ui.change_selected(MoveDestination::Right),
                        _ => need_redraw = false
                    }
                }
                _ => need_redraw = false
            }
        } else {
            match button {
                Button::Keyboard(key) => {
                    match key {
                        Key::R => self.restart(),
                        Key::Up => self.field.move_selection(MoveDestination::Up),
                        Key::Down => self.field.move_selection(MoveDestination::Down),
                        Key::Left => self.field.move_selection(MoveDestination::Left),
                        Key::Right => self.field.move_selection(MoveDestination::Right),
                        Key::Space => {
                            let ind = self.field.get_selected_ind();
                            self.open_cell(ind);
                        },
                        Key::LCtrl | Key::RCtrl => {
                            let ind = self.field.get_selected_ind();
                            self.toggle_mark(ind);
                        }
                        Key::H => {
                            self.ui.proc_key(ParamType::Height);
                            self.in_ui = true;
                        },
                        Key::M =>{
                            self.ui.proc_key(ParamType::Mines);
                            self.in_ui = true;
                        },
                        Key::W => {
                            self.ui.proc_key(ParamType::Width);
                            self.in_ui = true;
                        },
                        _ => need_redraw = false
                    }
                },
                Button::Mouse(btn) => {
                    let field_rect = self.get_field_rect(window);
                    let cell_w = field_rect[2] / self.field.get_width();
                    let cell_h = field_rect[3] / self.field.get_height();
                    let mouse_x = self.mouse_x.floor() as u32;
                    let mouse_y = self.mouse_y.floor() as u32;
                    if (mouse_x < field_rect[0]) || (mouse_x > field_rect[0] + field_rect[2]) ||
                       (mouse_y < field_rect[1]) || (mouse_y > field_rect[1] + field_rect[3]) {
                        return;
                    }
                    let x = (mouse_x - field_rect[0]) / cell_w;
                    let y = (mouse_y - field_rect[1]) / cell_h;
                    let w = self.field.get_width();
                    match btn {
                        MouseButton::Left => {
                            self.open_cell(x + y*w);
                        },
                        MouseButton::Right => {

                            self.toggle_mark(x + y*w);
                        },
                        _ => need_redraw = false
                    }
                }
                Button::Joystick(btn) => {
                    println!("{:?}", btn);
                }
            }
        }

        if need_redraw {
            self.render_state.reset();
        }
    }

    fn toggle_mark(&mut self, i: u32) {
        if self.game_ended || self.field.revealed(i) {
            return;
        }
        self.field.toggle_mark(i);
    }

    fn open_cell(&mut self, i: u32) {
        if self.game_ended {
            return;
        }
        if self.game_start == None {
            self.game_start = Some(UTC::now());
        }

        if !self.field.revealed(i) {
            self.check_reveal(i);
        } else {
            self.reveal_neighborhood(i);
        }
    }

    fn reveal_neighborhood(&mut self, i: u32) {
        let cells_count_opt = {
            if let &Content::Number(cells_count) = self.field.get_content(i) {
                Some(cells_count)
            } else {
                None
            }
        };

        if let Some(cells_count) = cells_count_opt {
            if self.field.get_neighborhood_count(i) == cells_count {
                let on_left_edge = i % self.field.get_width() == 0;
                let on_right_edge = (i+1) % self.field.get_width() == 0;

                for rdelta in -1..2i32 {
                    for cdelta in -1..2i32 {
                        if on_left_edge && (cdelta == -1) {
                            continue;
                        }
                        if on_right_edge && (cdelta == 1) {
                            continue;
                        }
                        let tgt = (i as i32) + rdelta*(self.field.get_width() as i32) + cdelta;
                        if (tgt < 0) || (tgt >= self.field.get_size() as i32) {
                            continue;
                        }
                        self.check_reveal(tgt as u32);
                    }
                }
            }
        }
    }

    pub fn check_reveal(&mut self, i : u32) {
        if self.field.marked(i) {
            return;
        }
        match *self.field.reveal(i) {
            Content::Mine(_) => {
                self.field.reveal_all();
                self.game_ended = true;
                self.field.set_killer(i);
                self.game_end = Some(UTC::now());
                self.msg.show( GameEndState::Lose );
                println!("Game over :(");
            },
            Content::None => {
                self.field.chain_reveal(i);
                if self.field.is_victory() {
                    self.msg.show( GameEndState::Win );
                    println!("You win :)");
                    self.game_ended = true;
                    self.game_end = Some(UTC::now());
                }
            }
            Content::Number(_i) => {
                if self.field.is_victory() {
                    self.msg.show( GameEndState::Win );
                    println!("You win :)");
                    self.game_ended = true;
                    self.game_end = Some(UTC::now());
                }
            }
        }
    }

    pub fn mouse_move(&mut self, mouse_rel: [f64; 2]) {
        self.mouse_x = mouse_rel[0];
        self.mouse_y = mouse_rel[1];
    }

    pub fn update_state(&mut self) {
        if let Some(_) = self.game_start {
            if let None = self.game_end {
                let now = UTC::now();
                match self.last_time {
                    Some(last_time) => {
                        let time_from_last_tick = now - last_time;
                        if time_from_last_tick >= Duration::seconds(1) {
                            self.last_time = Some(now);
                            self.render_state.reset();
                        }
                    },
                    None => self.last_time = Some(now),
                }
            }
        }
    }

    pub fn resize(&mut self) {
        self.render_state.reset();
    }

    fn restart(&mut self) {
        self.game_ended = false;
        self.msg.hide();
        self.game_start = None;
        self.game_end = None;
        self.last_time = None;
        self.field.restart();
        self.render_state.reset();
    }
}
<commit_msg>chore: delete debug printing<commit_after>use field::{Field, Content};
use ui::UI;
use ui::EndMessage;
use piston_window::*;
use common::{ParamType, MoveDestination, GameEndState};
use chrono::{DateTime, UTC, Duration};

enum RenderState {
    // redraw picture on current buffer
    First,

    // redraw picture on next buffer
    Second,

    // needn't redraw picture
    None
}

impl RenderState {

    // Update render state and return flag necessity of redrawing pickture
    fn update_state(&mut self) -> bool {
        match *self {
            RenderState::First  => *self = RenderState::Second,
            RenderState::Second => *self = RenderState::None,
            RenderState::None   => return false
        }

        true
    }

    fn reset(&mut self) {
        *self = RenderState::First
    }
}

pub struct Game<'a> {
    field: Field,
    ui: UI<'a>,
    msg: EndMessage<'a>,
    glyphs: Glyphs,
    mouse_x: f64,
    mouse_y: f64,
    game_ended: bool,
    panel_width: u32,
    in_ui: bool,
    game_start : Option<DateTime<UTC>>,
    last_time : Option<DateTime<UTC>>,
    game_end : Option<DateTime<UTC>>,
    // state of rendering for drawing picture on both buffers
    render_state: RenderState
}

impl<'a> Game<'a> {
    pub fn new(glyphs: Glyphs, width: u32, height: u32, mines: u32) -> Game<'a> {
        Game {
            field: Field::new(width, height, mines),
            ui: UI::new(width, height, mines),
            msg: EndMessage::new(),
            glyphs: glyphs,
            mouse_x: 0.0,
            mouse_y: 0.0,
            game_ended: false,
            panel_width: 350,
            in_ui: false,
            game_start: None,
            game_end: None,
            last_time: None,
            render_state: RenderState::First
        }
    }

    pub fn render(&mut self, window: &PistonWindow) {
        if !self.render_state.update_state() {
            return;
        }

        window.draw_2d(|c, g| {
            clear([0.0, 0.0, 0.0, 1.0], g);
            let field_rect = self.get_field_rect(window);
            self.field.draw(c, g, field_rect, &mut self.glyphs);

            let ui_rect = self.get_ui_rect(window);

            let dur = match self.game_start {
                Some(game_start) => match self.game_end {
                    Some(game_end) => game_end - game_start,
                    None => UTC::now() - game_start,
                },
                None => Duration::seconds(0),
            };

            self.ui.draw(c, g, ui_rect, &mut self.glyphs, self.field.total_mines(), self.field.count_marked(), dur);

            let msg_rect = self.get_msg_rect(window);
            self.msg.draw(c, g, msg_rect, &mut self.glyphs);
        });
    }

    fn get_field_rect(&self, window: &PistonWindow) -> [u32; 4] {
        let mut w = window.size().width - self.panel_width;
        w = (w /self.field.get_width()) * self.field.get_width();
        let mut h = window.size().height;
        h = (h /self.field.get_height()) * self.field.get_height();
        [0, 0, w, h]
    }

    fn get_ui_rect(&self, window: &PistonWindow) -> [u32; 4] {
        let mut field_w = window.size().width - self.panel_width;
        field_w = (field_w /self.field.get_width()) * self.field.get_width();
        let w = window.size().width - field_w;
        let h = window.size().height;
        [field_w, 0, w, h]
    }

    fn get_msg_rect(&self, window: &PistonWindow) -> [u32; 4] {
        let w_w = window.size().width;
        let w_h = window.size().height;
        let (m_w, m_h) = EndMessage::size();

        [
            ( (w_w-m_w) / 2 ),
            ( (w_h-m_h) / 2 ),
            m_w,
            m_h
        ]
    }

    pub fn proc_key(&mut self, button: Button, window: &PistonWindow) {
        let mut need_redraw = true;
        if self.in_ui {
            match button {
                Button::Keyboard(key) => {
                    match  key {
                        Key::H => {
                            match self.ui.proc_key(ParamType::Height) {
                                Some(h) => {
                                    self.in_ui = false;
                                    self.field.reinit_field(h, ParamType::Height);
                                    self.restart();
                                }
                                _ => need_redraw = false
                            }
                        },
                        Key::M => {
                            match self.ui.proc_key(ParamType::Mines) {
                                Some(m) => {
                                    self.in_ui = false;
                                    self.field.reinit_field(m, ParamType::Mines);
                                    self.restart();
                                }
                                _ => need_redraw = false
                            }
                        },
                        Key::W => {
                            match self.ui.proc_key(ParamType::Width) {
                                Some(w) => {
                                    self.in_ui = false;
                                    self.field.reinit_field(w, ParamType::Width);
                                    self.restart();
                                }
                                _ => need_redraw = false
                            }
                        },
                        Key::Up => self.ui.change_selected(MoveDestination::Up),
                        Key::Down => self.ui.change_selected(MoveDestination::Down),
                        Key::Left => self.ui.change_selected(MoveDestination::Left),
                        Key::Right => self.ui.change_selected(MoveDestination::Right),
                        _ => need_redraw = false
                    }
                }
                _ => need_redraw = false
            }
        } else {
            match button {
                Button::Keyboard(key) => {
                    match key {
                        Key::R => self.restart(),
                        Key::Up => self.field.move_selection(MoveDestination::Up),
                        Key::Down => self.field.move_selection(MoveDestination::Down),
                        Key::Left => self.field.move_selection(MoveDestination::Left),
                        Key::Right => self.field.move_selection(MoveDestination::Right),
                        Key::Space => {
                            let ind = self.field.get_selected_ind();
                            self.open_cell(ind);
                        },
                        Key::LCtrl | Key::RCtrl => {
                            let ind = self.field.get_selected_ind();
                            self.toggle_mark(ind);
                        }
                        Key::H => {
                            self.ui.proc_key(ParamType::Height);
                            self.in_ui = true;
                        },
                        Key::M =>{
                            self.ui.proc_key(ParamType::Mines);
                            self.in_ui = true;
                        },
                        Key::W => {
                            self.ui.proc_key(ParamType::Width);
                            self.in_ui = true;
                        },
                        _ => need_redraw = false
                    }
                },
                Button::Mouse(btn) => {
                    let field_rect = self.get_field_rect(window);
                    let cell_w = field_rect[2] / self.field.get_width();
                    let cell_h = field_rect[3] / self.field.get_height();
                    let mouse_x = self.mouse_x.floor() as u32;
                    let mouse_y = self.mouse_y.floor() as u32;
                    if (mouse_x < field_rect[0]) || (mouse_x > field_rect[0] + field_rect[2]) ||
                       (mouse_y < field_rect[1]) || (mouse_y > field_rect[1] + field_rect[3]) {
                        return;
                    }
                    let x = (mouse_x - field_rect[0]) / cell_w;
                    let y = (mouse_y - field_rect[1]) / cell_h;
                    let w = self.field.get_width();
                    match btn {
                        MouseButton::Left => {
                            self.open_cell(x + y*w);
                        },
                        MouseButton::Right => {

                            self.toggle_mark(x + y*w);
                        },
                        _ => need_redraw = false
                    }
                }
                Button::Joystick(_) => {
                    // Doen't work for me (Logitech Rumble F510)
                    // println!("{:?}", btn);
                }
            }
        }

        if need_redraw {
            self.render_state.reset();
        }
    }

    fn toggle_mark(&mut self, i: u32) {
        if self.game_ended || self.field.revealed(i) {
            return;
        }
        self.field.toggle_mark(i);
    }

    fn open_cell(&mut self, i: u32) {
        if self.game_ended {
            return;
        }
        if self.game_start == None {
            self.game_start = Some(UTC::now());
        }

        if !self.field.revealed(i) {
            self.check_reveal(i);
        } else {
            self.reveal_neighborhood(i);
        }
    }

    fn reveal_neighborhood(&mut self, i: u32) {
        let cells_count_opt = {
            if let &Content::Number(cells_count) = self.field.get_content(i) {
                Some(cells_count)
            } else {
                None
            }
        };

        if let Some(cells_count) = cells_count_opt {
            if self.field.get_neighborhood_count(i) == cells_count {
                let on_left_edge = i % self.field.get_width() == 0;
                let on_right_edge = (i+1) % self.field.get_width() == 0;

                for rdelta in -1..2i32 {
                    for cdelta in -1..2i32 {
                        if on_left_edge && (cdelta == -1) {
                            continue;
                        }
                        if on_right_edge && (cdelta == 1) {
                            continue;
                        }
                        let tgt = (i as i32) + rdelta*(self.field.get_width() as i32) + cdelta;
                        if (tgt < 0) || (tgt >= self.field.get_size() as i32) {
                            continue;
                        }
                        self.check_reveal(tgt as u32);
                    }
                }
            }
        }
    }

    pub fn check_reveal(&mut self, i : u32) {
        if self.field.marked(i) {
            return;
        }
        match *self.field.reveal(i) {
            Content::Mine(_) => {
                self.field.reveal_all();
                self.game_ended = true;
                self.field.set_killer(i);
                self.game_end = Some(UTC::now());
                self.msg.show( GameEndState::Lose );
                println!("Game over :(");
            },
            Content::None => {
                self.field.chain_reveal(i);
                if self.field.is_victory() {
                    self.msg.show( GameEndState::Win );
                    println!("You win :)");
                    self.game_ended = true;
                    self.game_end = Some(UTC::now());
                }
            }
            Content::Number(_i) => {
                if self.field.is_victory() {
                    self.msg.show( GameEndState::Win );
                    println!("You win :)");
                    self.game_ended = true;
                    self.game_end = Some(UTC::now());
                }
            }
        }
    }

    pub fn mouse_move(&mut self, mouse_rel: [f64; 2]) {
        self.mouse_x = mouse_rel[0];
        self.mouse_y = mouse_rel[1];
    }

    pub fn update_state(&mut self) {
        if let Some(_) = self.game_start {
            if let None = self.game_end {
                let now = UTC::now();
                match self.last_time {
                    Some(last_time) => {
                        let time_from_last_tick = now - last_time;
                        if time_from_last_tick >= Duration::seconds(1) {
                            self.last_time = Some(now);
                            self.render_state.reset();
                        }
                    },
                    None => self.last_time = Some(now),
                }
            }
        }
    }

    pub fn resize(&mut self) {
        self.render_state.reset();
    }

    fn restart(&mut self) {
        self.game_ended = false;
        self.msg.hide();
        self.game_start = None;
        self.game_end = None;
        self.last_time = None;
        self.field.restart();
        self.render_state.reset();
    }
}
<|endoftext|>


<commit_before>use color::Color;
use rand::{thread_rng, Rng};

pub enum MoveDirection {
    Left,
    Right
}

pub enum PieceGenerator{
    Random(usize),
    Exact(Vec<Piece>),
}

impl PieceGenerator {
    pub fn next(&mut self) -> Piece {
        match self {
            &mut PieceGenerator::Random(max_col) => {
                let mut rng = thread_rng();

                Piece {
                    row: 0,
                    col: rng.gen_range(0, max_col),
                    color: Color::rand(),
                }
            },
            &mut PieceGenerator::Exact(ref mut pieces) => pieces.remove(0),
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Piece {
    row: usize,
    col: usize,
    color: Color,
}

impl Piece {
    pub fn row(&self) -> usize {
        self.row
    }

    pub fn col(&self) -> usize {
        self.col
    }

    pub fn color(&self) -> Color {
        self.color.clone()
    }

    pub fn color_rgba(&self) -> [f32; 4]{
        self.color.as_rgba()
    }
}

pub struct Game {
    current_piece: Piece,
    piece_generator: PieceGenerator,
    board: Vec<Vec<Option<Color>>>,
    num_rows_cleared: u64,
    width: usize,
    height: usize,
}

impl Game {
    pub fn new(height: usize, width: usize, mut piece_generator: PieceGenerator) -> Game {
        let piece = piece_generator.next();

        Game {
            piece_generator: piece_generator,
            current_piece: piece,
            board: vec![vec![None; width]; height],
            num_rows_cleared: 0,
            width: width,
            height: height,
        }
    }

    pub fn drop_piece(&mut self) {
        let col = self.current_piece.col();
        let color = self.current_piece.color();

        let first_free_row = self.board
            .iter()
            .rposition(|row| row.get(col.clone()).unwrap_or(&None).is_none())
            .unwrap();

        self.board.get_mut(first_free_row).unwrap()[col] = Some(color);

        self.current_piece = self.piece_generator.next();
    }

    pub fn get_pieces(&self) -> Vec<Piece> {
        self.board.iter()
            .enumerate()
            .flat_map(|(row_num, col)| {
                let pieces: Vec<Piece> = col.iter()
                    .enumerate()
                    .filter_map(|(col_num, color)| {
                        if let Some(c) = color.clone() {
                            Some(Piece { row: row_num, col: col_num, color: c })
                        } else {
                            None
                        }
                    }).collect();
                pieces
            })
            .chain(vec![self.current_piece.clone()])
            .collect()
    }

    pub fn move_piece(&mut self, direction: MoveDirection) {
        let col = self.current_piece.col();

        let new_col = match direction {
            MoveDirection::Left if col > 0 => col - 1,
            MoveDirection::Right if col < self.width - 1 => col + 1,
            _ => col,
        };

        self.current_piece.col = new_col;
    }

    pub fn step(&mut self) {
        let row = self.current_piece.row();

        if row < self.height - 1  {
            let new_row = row + 1;

            let is_piece_below = self.board.get(new_row.clone())
                .unwrap_or(&vec![])
                .get(self.current_piece.col())
                .unwrap_or(&None)
                .is_some();

            if is_piece_below {
                self.drop_piece();
            } else {
                self.current_piece = Piece {
                    row: new_row,
                    col: self.current_piece.col(),
                    color: self.current_piece.color(),
                }
            }
        } else {
            self.drop_piece();
        }
    }

    pub fn num_rows_cleared(&self) -> u64 {
        self.num_rows_cleared
    }
}

#[cfg(test)]
mod tests {
    use game::Game;
    use game::MoveDirection;
    use game::Piece;
    use game::PieceGenerator;
    use color::Color;

    const HEIGHT: usize = 16;
    const WIDTH: usize = 4;

    #[test]
    fn move_right() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 0, col: 1, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.move_piece(MoveDirection::Right);

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn move_left() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 3, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 0, col: 2, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.move_piece(MoveDirection::Left);

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn move_right_stops_at_game_edge() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: WIDTH - 1, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 0, col: WIDTH - 1, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.move_piece(MoveDirection::Right);

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn move_left_stops_at_game_edge() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 0, col: 0, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.move_piece(MoveDirection::Left);

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn drop_piece_empty_board() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Yellow },
        ];

        let expected_pieces = vec![
            Piece { row: HEIGHT - 1, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Yellow },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.drop_piece();

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn drop_piece_on_another_piece() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Yellow },
            Piece { row: 0, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Blue },
        ];

        let mut expected_pieces = vec![
            Piece { row: HEIGHT - 2, col: 0, color: Color::Red },
            Piece { row: HEIGHT - 1, col: 0, color: Color::Yellow },
            Piece { row: 0, col: 0, color: Color::Blue },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.drop_piece();
        game.drop_piece();

        let mut actual_pieces = game.get_pieces();

        expected_pieces.sort();
        actual_pieces.sort();

        assert_eq!(expected_pieces, actual_pieces);
    }

    #[test]
    fn step_moves_current_piece_down() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 1, col: 0, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.step();

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn step_to_bottom_drops_and_creates_new_piece() {
        let pieces_to_drop = vec![
            Piece { row: HEIGHT - 1, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Yellow },
        ];

        let expected_pieces = vec![
            Piece { row: HEIGHT - 1, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Yellow },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.step();

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn step_to_other_piece_drops_and_creates_new_piece() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
            Piece { row: HEIGHT - 2, col: 0, color: Color::Yellow },
            Piece { row: 0, col: 0, color: Color::Blue },
        ];

        let mut expected_pieces = vec![
            Piece { row: HEIGHT - 1, col: 0, color: Color::Red },
            Piece { row: HEIGHT - 2, col: 0, color: Color::Yellow },
            Piece { row: 0, col: 0, color: Color::Blue },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.drop_piece();
        game.step();

        let mut actual_pieces = game.get_pieces();

        expected_pieces.sort();
        actual_pieces.sort();

        assert_eq!(expected_pieces, actual_pieces);
    }
}
<commit_msg>refactor step<commit_after>use color::Color;
use rand::{thread_rng, Rng};

pub enum MoveDirection {
    Left,
    Right
}

pub enum PieceGenerator{
    Random(usize),
    Exact(Vec<Piece>),
}

impl PieceGenerator {
    pub fn next(&mut self) -> Piece {
        match self {
            &mut PieceGenerator::Random(max_col) => {
                let mut rng = thread_rng();

                Piece {
                    row: 0,
                    col: rng.gen_range(0, max_col),
                    color: Color::rand(),
                }
            },
            &mut PieceGenerator::Exact(ref mut pieces) => pieces.remove(0),
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Piece {
    row: usize,
    col: usize,
    color: Color,
}

impl Piece {
    pub fn row(&self) -> usize {
        self.row
    }

    pub fn col(&self) -> usize {
        self.col
    }

    pub fn color(&self) -> Color {
        self.color.clone()
    }

    pub fn color_rgba(&self) -> [f32; 4]{
        self.color.as_rgba()
    }
}

pub struct Game {
    current_piece: Piece,
    piece_generator: PieceGenerator,
    board: Vec<Vec<Option<Color>>>,
    num_rows_cleared: u64,
    width: usize,
    height: usize,
}

impl Game {
    pub fn new(height: usize, width: usize, mut piece_generator: PieceGenerator) -> Game {
        let piece = piece_generator.next();

        Game {
            piece_generator: piece_generator,
            current_piece: piece,
            board: vec![vec![None; width]; height],
            num_rows_cleared: 0,
            width: width,
            height: height,
        }
    }

    pub fn drop_piece(&mut self) {
        let col = self.current_piece.col();
        let color = self.current_piece.color();

        let first_free_row = self.board
            .iter()
            .rposition(|row| row.get(col.clone()).unwrap_or(&None).is_none())
            .unwrap();

        self.board.get_mut(first_free_row).unwrap()[col] = Some(color);

        self.current_piece = self.piece_generator.next();
    }

    pub fn get_pieces(&self) -> Vec<Piece> {
        self.board.iter()
            .enumerate()
            .flat_map(|(row_num, col)| {
                let pieces: Vec<Piece> = col.iter()
                    .enumerate()
                    .filter_map(|(col_num, color)| {
                        if let Some(c) = color.clone() {
                            Some(Piece { row: row_num, col: col_num, color: c })
                        } else {
                            None
                        }
                    }).collect();
                pieces
            })
            .chain(vec![self.current_piece.clone()])
            .collect()
    }

    pub fn move_piece(&mut self, direction: MoveDirection) {
        let col = self.current_piece.col();

        let new_col = match direction {
            MoveDirection::Left if col > 0 => col - 1,
            MoveDirection::Right if col < self.width - 1 => col + 1,
            _ => col,
        };

        self.current_piece.col = new_col;
    }

    pub fn step(&mut self) {
        let row = self.current_piece.row();
        let new_row = row + 1;

        let is_valid_row = new_row < self.height;
        let is_piece_below = self.board.get(new_row.clone())
            .unwrap_or(&vec![])
            .get(self.current_piece.col())
            .unwrap_or(&None)
            .is_some();

        if is_valid_row && !is_piece_below {
            self.current_piece = Piece {
                row: new_row,
                col: self.current_piece.col(),
                color: self.current_piece.color(),
            }
        } else {
            self.drop_piece();
        }
    }

    pub fn num_rows_cleared(&self) -> u64 {
        self.num_rows_cleared
    }
}

#[cfg(test)]
mod tests {
    use game::Game;
    use game::MoveDirection;
    use game::Piece;
    use game::PieceGenerator;
    use color::Color;

    const HEIGHT: usize = 16;
    const WIDTH: usize = 4;

    #[test]
    fn move_right() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 0, col: 1, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.move_piece(MoveDirection::Right);

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn move_left() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 3, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 0, col: 2, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.move_piece(MoveDirection::Left);

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn move_right_stops_at_game_edge() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: WIDTH - 1, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 0, col: WIDTH - 1, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.move_piece(MoveDirection::Right);

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn move_left_stops_at_game_edge() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 0, col: 0, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.move_piece(MoveDirection::Left);

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn drop_piece_empty_board() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Yellow },
        ];

        let expected_pieces = vec![
            Piece { row: HEIGHT - 1, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Yellow },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.drop_piece();

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn drop_piece_on_another_piece() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Yellow },
            Piece { row: 0, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Blue },
        ];

        let mut expected_pieces = vec![
            Piece { row: HEIGHT - 2, col: 0, color: Color::Red },
            Piece { row: HEIGHT - 1, col: 0, color: Color::Yellow },
            Piece { row: 0, col: 0, color: Color::Blue },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.drop_piece();
        game.drop_piece();

        let mut actual_pieces = game.get_pieces();

        expected_pieces.sort();
        actual_pieces.sort();

        assert_eq!(expected_pieces, actual_pieces);
    }

    #[test]
    fn step_moves_current_piece_down() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
        ];

        let expected_pieces = vec![
            Piece { row: 1, col: 0, color: Color::Red },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.step();

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn step_to_bottom_drops_and_creates_new_piece() {
        let pieces_to_drop = vec![
            Piece { row: HEIGHT - 1, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Yellow },
        ];

        let expected_pieces = vec![
            Piece { row: HEIGHT - 1, col: 0, color: Color::Red },
            Piece { row: 0, col: 0, color: Color::Yellow },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.step();

        assert_eq!(expected_pieces, game.get_pieces());
    }

    #[test]
    fn step_to_other_piece_drops_and_creates_new_piece() {
        let pieces_to_drop = vec![
            Piece { row: 0, col: 0, color: Color::Red },
            Piece { row: HEIGHT - 2, col: 0, color: Color::Yellow },
            Piece { row: 0, col: 0, color: Color::Blue },
        ];

        let mut expected_pieces = vec![
            Piece { row: HEIGHT - 1, col: 0, color: Color::Red },
            Piece { row: HEIGHT - 2, col: 0, color: Color::Yellow },
            Piece { row: 0, col: 0, color: Color::Blue },
        ];

        let mut game = Game::new(
            HEIGHT,
            WIDTH,
            PieceGenerator::Exact(pieces_to_drop),
        );

        game.drop_piece();
        game.step();

        let mut actual_pieces = game.get_pieces();

        expected_pieces.sort();
        actual_pieces.sort();

        assert_eq!(expected_pieces, actual_pieces);
    }
}
<|endoftext|>


<commit_before>use std::num::{NumCast};
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::cmp::{Ordering};
use primitive::Primitive;
use ::{Anchor};

/// 2D geometric vector.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V2<T>(pub T, pub T);

impl<T: Eq> Eq for V2<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn add(self, rhs: V2<U>) -> V2<V> { V2(self.0 + rhs.0, self.1 + rhs.1) }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn sub(self, rhs: V2<U>) -> V2<V> { V2(self.0 - rhs.0, self.1 - rhs.1) }
}

impl<T: Neg<Output=U>, U> Neg<> for V2<T> {
    type Output = V2<U>;
    fn neg(self) -> V2<U> { V2(-self.0, -self.1) }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V2<T> {
    type Output = V2<V>;
    fn mul(self, rhs: U) -> V2<V> { V2(self.0 * rhs, self.1 * rhs) }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V2<T> {
    type Output = V2<V>;
    fn div(self, rhs: U) -> V2<V> { V2(self.0 / rhs, self.1 / rhs) }
}

impl<T> V2<T> {
    pub fn to_array(self) -> [T; 2] { [self.0, self.1] }
}

impl<T> V2<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V2<U> {
        V2(f(self.0), f(self.1))
    }
}

impl<T: Primitive> V2<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V2<T>) -> V2<T> { V2(self.0 * rhs.0, self.1 * rhs.1) }

    /// Componentwise division.
    pub fn div(self, rhs: V2<T>) -> V2<T> { V2(self.0 / rhs.0, self.1 / rhs.1) }

    /// Dot product.
    pub fn dot(self, rhs: V2<T>) -> T { self.0 * rhs.0 + self.1 * rhs.1 }
}

impl<T: Ord+Copy> Ord for V2<T> {
    fn cmp(&self, other: &V2<T>) -> Ordering {
        (self.0, self.1).cmp(&(other.0, other.1))
    }
}

/// 3D geometric vector
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V3<T>(pub T, pub T, pub T);

impl<T: Eq> Eq for V3<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn add(self, rhs: V3<U>) -> V3<V> { V3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2) }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn sub(self, rhs: V3<U>) -> V3<V> { V3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2) }
}

impl<T: Neg<Output=U>, U> Neg<> for V3<T> {
    type Output = V3<U>;
    fn neg(self) -> V3<U> { V3(-self.0, -self.1, -self.2) }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V3<T> {
    type Output = V3<V>;
    fn mul(self, rhs: U) -> V3<V> { V3(self.0 * rhs, self.1 * rhs, self.2 * rhs) }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V3<T> {
    type Output = V3<V>;
    fn div(self, rhs: U) -> V3<V> { V3(self.0 / rhs, self.1 / rhs, self.2 / rhs) }
}

impl<T> V3<T> {
    pub fn to_array(self) -> [T; 3] { [self.0, self.1, self.2] }
}

impl<T> V3<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V3<U> {
        V3(f(self.0), f(self.1), f(self.2))
    }
}

impl<T: Primitive> V3<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V3<T>) -> V3<T> { V3(self.0 * rhs.0, self.1 * rhs.1, self.2 * rhs.2) }

    /// Componentwise division.
    pub fn div(self, rhs: V3<T>) -> V3<T> { V3(self.0 / rhs.0, self.1 / rhs.1, self.2 / rhs.2) }

    /// Dot product.
    pub fn dot(self, rhs: V3<T>) -> T { self.0 * rhs.0 + self.1 * rhs.1 + self.2 * rhs.2 }
}

impl<T: Ord+Copy> Ord for V3<T> {
    fn cmp(&self, other: &V3<T>) -> Ordering {
        (self.0, self.1, self.2).cmp(&(other.0, other.1, other.2))
    }
}

/// A rectangle type consisting of position and size vectors.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct Rect<T>(pub V2<T>, pub V2<T>);

impl<T: Eq> Eq for Rect<T> { }

impl<T: Primitive> Rect<T> {
    pub fn area(&self) -> T { (self.1).0 * (self.1).1 }

    pub fn mn(&self) -> V2<T> { self.0 }
    pub fn mx(&self) -> V2<T> { self.0 + self.1 }
    pub fn dim(&self) -> V2<T> { self.1 }

    pub fn point(&self, anchor: Anchor) -> V2<T> {
        match anchor {
            Anchor::TopLeft => self.mn(),
            Anchor::TopRight => V2((self.0).0 + (self.1).0, (self.0).1),
            Anchor::BottomLeft => V2((self.0).0, (self.0).1 + (self.1).1),
            Anchor::BottomRight => self.mx(),
            Anchor::Top => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1),
            Anchor::Left => V2((self.0).0, (self.0).1 + (self.1).1 / NumCast::from(2).unwrap()),
            Anchor::Right => V2((self.0).0 + (self.1).0, (self.0).1 + (self.1).1 / NumCast::from(2).unwrap()),
            Anchor::Bottom => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1 + (self.1).1),
            Anchor::Center => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1 + (self.1).1 / NumCast::from(2).unwrap())
        }
    }

    /// Grow the rectangle to enclose point p.
    pub fn grow(&mut self, p: V2<T>) {
        let (mn, mx) = (self.mn(), self.mx());

        if p.0 < mn.0 {
            (self.1).0 = (self.1).0 + mn.0 - p.0;
            (self.0).0 = p.0;
        }

        if p.1 < mn.1 {
            (self.1).1 = (self.1).1 + mn.1 - p.1;
            (self.0).1 = p.1;
        }

        if p.0 > mx.0 { (self.1).0 = p.0 - mn.0; }

        if p.1 > mx.1 { (self.1).1 = p.1 - mn.1; }
    }

    pub fn intersects(&self, rhs: &Rect<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let (rmn, rmx) = (rhs.mn(), rhs.mx());

        !(mx.0 <= rmn.0 || mn.0 >= rmx.0 ||
          mx.1 <= rmn.1 || mn.1 >= rmx.1)
    }

    pub fn contains(&self, p: &V2<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        p.0 >= mn.0 && p.1 >= mn.1 && p.0 < mx.0 && p.1 < mx.1
    }

    /// Return an iterator for all the points in the rectangle.
    pub fn iter(&self) -> RectIter<T> {
        RectIter {
            x: (self.0).0,
            y: (self.0).1,
            x0: (self.0).0,
            x1: (self.0).0 + (self.1).0,
            y1: (self.0).1 + (self.1).1,
        }
    }
}

impl<T: Add<U, Output=T> + Clone, U> Add<V2<U>> for Rect<T> {
    type Output = Rect<T>;
    fn add(self, rhs: V2<U>) -> Rect<T> { Rect(self.0 + rhs, self.1.clone()) }
}

/// Iterator for the integer points within a rectangle.
pub struct RectIter<T> {
    x: T,
    y: T,
    x0: T,
    x1: T,
    y1: T,
}

impl<T: Primitive> Iterator for RectIter<T> {
    type Item = V2<T>;
    fn next(&mut self) -> Option<V2<T>> {
        if self.y >= self.y1 { return None; }
        let ret = Some(V2(self.x, self.y));
        self.x = self.x + NumCast::from(1).unwrap();
        if self.x >= self.x1 {
            self.x = self.x0;
            self.y = self.y + NumCast::from(1).unwrap();
        }
        ret
    }
}
<commit_msg>Rectangle edge contains query<commit_after>use std::num::{NumCast};
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::cmp::{Ordering};
use primitive::Primitive;
use ::{Anchor};

/// 2D geometric vector.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V2<T>(pub T, pub T);

impl<T: Eq> Eq for V2<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn add(self, rhs: V2<U>) -> V2<V> { V2(self.0 + rhs.0, self.1 + rhs.1) }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V2<U>> for V2<T> {
    type Output = V2<V>;
    fn sub(self, rhs: V2<U>) -> V2<V> { V2(self.0 - rhs.0, self.1 - rhs.1) }
}

impl<T: Neg<Output=U>, U> Neg<> for V2<T> {
    type Output = V2<U>;
    fn neg(self) -> V2<U> { V2(-self.0, -self.1) }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V2<T> {
    type Output = V2<V>;
    fn mul(self, rhs: U) -> V2<V> { V2(self.0 * rhs, self.1 * rhs) }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V2<T> {
    type Output = V2<V>;
    fn div(self, rhs: U) -> V2<V> { V2(self.0 / rhs, self.1 / rhs) }
}

impl<T> V2<T> {
    pub fn to_array(self) -> [T; 2] { [self.0, self.1] }
}

impl<T> V2<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V2<U> {
        V2(f(self.0), f(self.1))
    }
}

impl<T: Primitive> V2<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V2<T>) -> V2<T> { V2(self.0 * rhs.0, self.1 * rhs.1) }

    /// Componentwise division.
    pub fn div(self, rhs: V2<T>) -> V2<T> { V2(self.0 / rhs.0, self.1 / rhs.1) }

    /// Dot product.
    pub fn dot(self, rhs: V2<T>) -> T { self.0 * rhs.0 + self.1 * rhs.1 }
}

impl<T: Ord+Copy> Ord for V2<T> {
    fn cmp(&self, other: &V2<T>) -> Ordering {
        (self.0, self.1).cmp(&(other.0, other.1))
    }
}

/// 3D geometric vector
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct V3<T>(pub T, pub T, pub T);

impl<T: Eq> Eq for V3<T> { }

impl<T: Add<U, Output=V>, U, V> Add<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn add(self, rhs: V3<U>) -> V3<V> { V3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2) }
}

impl<T: Sub<U, Output=V>, U, V> Sub<V3<U>> for V3<T> {
    type Output = V3<V>;
    fn sub(self, rhs: V3<U>) -> V3<V> { V3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2) }
}

impl<T: Neg<Output=U>, U> Neg<> for V3<T> {
    type Output = V3<U>;
    fn neg(self) -> V3<U> { V3(-self.0, -self.1, -self.2) }
}

impl<T: Mul<U, Output=V>, U: Copy, V> Mul<U> for V3<T> {
    type Output = V3<V>;
    fn mul(self, rhs: U) -> V3<V> { V3(self.0 * rhs, self.1 * rhs, self.2 * rhs) }
}

impl<T: Div<U, Output=V>, U: Copy, V> Div<U> for V3<T> {
    type Output = V3<V>;
    fn div(self, rhs: U) -> V3<V> { V3(self.0 / rhs, self.1 / rhs, self.2 / rhs) }
}

impl<T> V3<T> {
    pub fn to_array(self) -> [T; 3] { [self.0, self.1, self.2] }
}

impl<T> V3<T> {
    pub fn map<U, F: Fn(T) -> U>(self, f: F) -> V3<U> {
        V3(f(self.0), f(self.1), f(self.2))
    }
}

impl<T: Primitive> V3<T> {
    /// Componentwise multiplication.
    pub fn mul(self, rhs: V3<T>) -> V3<T> { V3(self.0 * rhs.0, self.1 * rhs.1, self.2 * rhs.2) }

    /// Componentwise division.
    pub fn div(self, rhs: V3<T>) -> V3<T> { V3(self.0 / rhs.0, self.1 / rhs.1, self.2 / rhs.2) }

    /// Dot product.
    pub fn dot(self, rhs: V3<T>) -> T { self.0 * rhs.0 + self.1 * rhs.1 + self.2 * rhs.2 }
}

impl<T: Ord+Copy> Ord for V3<T> {
    fn cmp(&self, other: &V3<T>) -> Ordering {
        (self.0, self.1, self.2).cmp(&(other.0, other.1, other.2))
    }
}

/// A rectangle type consisting of position and size vectors.
#[derive(Copy, Debug, PartialEq, PartialOrd, Clone, Default, Hash, RustcDecodable, RustcEncodable)]
pub struct Rect<T>(pub V2<T>, pub V2<T>);

impl<T: Eq> Eq for Rect<T> { }

impl<T: Primitive> Rect<T> {
    pub fn area(&self) -> T { (self.1).0 * (self.1).1 }

    pub fn mn(&self) -> V2<T> { self.0 }
    pub fn mx(&self) -> V2<T> { self.0 + self.1 }
    pub fn dim(&self) -> V2<T> { self.1 }

    pub fn point(&self, anchor: Anchor) -> V2<T> {
        match anchor {
            Anchor::TopLeft => self.mn(),
            Anchor::TopRight => V2((self.0).0 + (self.1).0, (self.0).1),
            Anchor::BottomLeft => V2((self.0).0, (self.0).1 + (self.1).1),
            Anchor::BottomRight => self.mx(),
            Anchor::Top => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1),
            Anchor::Left => V2((self.0).0, (self.0).1 + (self.1).1 / NumCast::from(2).unwrap()),
            Anchor::Right => V2((self.0).0 + (self.1).0, (self.0).1 + (self.1).1 / NumCast::from(2).unwrap()),
            Anchor::Bottom => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1 + (self.1).1),
            Anchor::Center => V2((self.0).0 + (self.1).0 / NumCast::from(2).unwrap(), (self.0).1 + (self.1).1 / NumCast::from(2).unwrap())
        }
    }

    /// Grow the rectangle to enclose point p.
    pub fn grow(&mut self, p: V2<T>) {
        let (mn, mx) = (self.mn(), self.mx());

        if p.0 < mn.0 {
            (self.1).0 = (self.1).0 + mn.0 - p.0;
            (self.0).0 = p.0;
        }

        if p.1 < mn.1 {
            (self.1).1 = (self.1).1 + mn.1 - p.1;
            (self.0).1 = p.1;
        }

        if p.0 > mx.0 { (self.1).0 = p.0 - mn.0; }

        if p.1 > mx.1 { (self.1).1 = p.1 - mn.1; }
    }

    pub fn intersects(&self, rhs: &Rect<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let (rmn, rmx) = (rhs.mn(), rhs.mx());

        !(mx.0 <= rmn.0 || mn.0 >= rmx.0 ||
          mx.1 <= rmn.1 || mn.1 >= rmx.1)
    }

    pub fn contains(&self, p: &V2<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        p.0 >= mn.0 && p.1 >= mn.1 && p.0 < mx.0 && p.1 < mx.1
    }

    pub fn edge_contains(&self, p: &V2<T>) -> bool {
        let (mn, mx) = (self.mn(), self.mx());
        let one = NumCast::from(1).unwrap();
        p.0 == mn.0 || p.1 == mn.1 || p.0 == mx.0 - one || p.1 == mx.1 - one
    }

    /// Return an iterator for all the points in the rectangle.
    pub fn iter(&self) -> RectIter<T> {
        RectIter {
            x: (self.0).0,
            y: (self.0).1,
            x0: (self.0).0,
            x1: (self.0).0 + (self.1).0,
            y1: (self.0).1 + (self.1).1,
        }
    }
}

impl<T: Add<U, Output=T> + Clone, U> Add<V2<U>> for Rect<T> {
    type Output = Rect<T>;
    fn add(self, rhs: V2<U>) -> Rect<T> { Rect(self.0 + rhs, self.1.clone()) }
}

/// Iterator for the integer points within a rectangle.
pub struct RectIter<T> {
    x: T,
    y: T,
    x0: T,
    x1: T,
    y1: T,
}

impl<T: Primitive> Iterator for RectIter<T> {
    type Item = V2<T>;
    fn next(&mut self) -> Option<V2<T>> {
        if self.y >= self.y1 { return None; }
        let ret = Some(V2(self.x, self.y));
        self.x = self.x + NumCast::from(1).unwrap();
        if self.x >= self.x1 {
            self.x = self.x0;
            self.y = self.y + NumCast::from(1).unwrap();
        }
        ret
    }
}
<|endoftext|>


<commit_before>// Core types.
// Copyright (c) 2015 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use std::os;

use types::{Params, CommandCallback};

/// The command is the basic type of command line applications in cli.  This
/// handles command line parsing.
pub struct Command {
    name: String,  // The name of the command to use
    callback: CommandCallback,  // The callback to execute
    params: Params,  // The parameters to register with this command
    help: String,  // The help message to use for this command
    epilog: String,  // Printed at the end of the help page
    short_help: String,  // The short help to use for this command, this is shown on the command listing of the parent command
    add_help_option: bool,  // Whether this command registers "--help", default to be true
}

impl Command {
    pub fn new(name: &str, callback: CommandCallback) -> Command {
        Command {
            name: name.to_string(),
            callback: callback,
            params: Vec::new(),
            help: String::new(),
            epilog: String::new(),
            short_help: String::new(),
            add_help_option: true,
        }
    }

    pub fn get_usage(&self) -> String {
    }

    pub fn get_help(&self) -> String {
    }

    pub fn invoke(&self) {
        let args = os::args();
    }
}
<commit_msg>Added run<commit_after>// Core types.
// Copyright (c) 2015 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use std::os;
use std::path::Path;

use types::{Params, CommandCallback};

/// The command is the basic type of command line applications in cli.  This
/// handles command line parsing.
pub struct Command {
    name: String,  // The name of the command to use
    callback: CommandCallback,  // The callback to execute
    params: Params,  // The parameters to register with this command
    help: String,  // The help message to use for this command
    epilog: String,  // Printed at the end of the help page
    short_help: String,  // The short help to use for this command, this is shown on the command listing of the parent command
    add_help_option: bool,  // Whether this command registers "--help", default to be true
}

impl Command {
    pub fn new(name: &str, callback: CommandCallback) -> Command {
        Command {
            name: name.to_string(),
            callback: callback,
            params: Vec::new(),
            help: String::new(),
            epilog: String::new(),
            short_help: String::new(),
            add_help_option: true,
        }
    }

    pub fn get_usage(&self) -> String {
    }

    pub fn get_help(&self) -> String {
    }

    /// This invokes the command with given arguments.
    pub fn invoke(&self, pragram_name: String, args: Vec<String>) {
    }

    /// Create the parser and parses the arguments.
    fn parse_args(&self, args: Vec<String>) {
    }

    /// This is the way to run one command application.
    pub fn run(&self) {
        let mut args = os::args();
        let program_path = Path::new(args.remove(0).as_slice());
        let program_name = program_path.file_name().unwrap().to_str().unwrap();
        self.invoke(program_name.to_string(), args);
    }
}
<|endoftext|>