<commit_before>use std::collections::HashMap;
use std::str::Utf8Error;
use std::num::{ParseIntError, ParseFloatError};
use quick_error::ResultExt;

use vsl::{VslRecord, VslRecordTag, VslIdent};

use nom::{self, IResult};

pub type TimeStamp = f64;

#[derive(Debug, Clone)]
pub struct AccessRecord {
    pub ident: VslIdent,
    pub start: TimeStamp,
    pub end: TimeStamp,
    pub transaction_type: TransactionType,
    pub transaction: HttpTransaction,
}

#[derive(Debug, Clone)]
pub enum TransactionType {
    Client,
    Backend {
        parent: VslIdent,
        reason: String,
    },
}

impl TransactionType {
    #[allow(dead_code)]
    pub fn is_backend(&self) -> bool {
        match self {
            &TransactionType::Backend { parent: _, reason: _ } => true,
            _ => false
        }
    }

    #[allow(dead_code)]
    pub fn get_backend_parent(&self) -> VslIdent {
        match self {
            &TransactionType::Backend { ref parent, reason: _ } => *parent,
            _ => panic!("unwrap_backend called on TransactionType that was Backend")
        }
    }

    #[allow(dead_code)]
    pub fn get_backend_reason(&self) -> &str {
        match self {
            &TransactionType::Backend { parent: _, ref reason } => reason,
            _ => panic!("unwrap_backend called on TransactionType that was Backend")
        }
    }
}

#[derive(Debug, Clone)]
pub struct HttpTransaction {
    pub request: HttpRequest,
    pub response: HttpResponse,
}

#[derive(Debug, Clone)]
pub struct HttpRequest {
    pub method: String,
    pub url: String,
    pub protocol: String,
    pub headers: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
pub struct HttpResponse {
    pub status_name: String,
    pub status_code: u32,
    pub headers: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
struct RecordBuilder {
    ident: VslIdent,
    transaction_type: Option<TransactionType>,
    start: Option<TimeStamp>,
    end: Option<TimeStamp>,
    method: Option<String>,
    url: Option<String>,
    protocol: Option<String>,
    status_name: Option<String>,
    status_code: Option<u32>,
    reason: Option<String>,
    req_headers: HashMap<String, String>,
    resp_headers: HashMap<String, String>,
}

#[derive(Debug)]
enum RecordBuilderResult {
    Building(RecordBuilder),
    Ready(AccessRecord),
}

trait IResultExt<O, E> {
    fn into_result(self) -> Result<O, E>;
}

impl<I, O, E> IResultExt<O, nom::Err<I, E>> for IResult<I, O, E> {
    fn into_result(self) -> Result<O, nom::Err<I, E>> {
        match self {
            IResult::Done(_, o) => Ok(o),
            IResult::Error(err) => Err(err),
            IResult::Incomplete(_) => panic!("got Incomplete IResult!"),
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum RecordBuilderError {
        NonUtf8VslMessage(err: Utf8Error) {
            display("VSL record message is not valid UTF-8 encoded string: {}", err)
            cause(err)
        }
        UnimplementedTransactionType(transaction_type: String) {
            display("Unimplemented transaction type '{}'", transaction_type)
        }
        InvalidMessageFormat(err: String) {
            display("Failed to parse message: {}", err)
            // Note: using context() since from() does not support lifetimes
            context(tag: VslRecordTag ,err: nom::Err<&'a str>)
                -> (format!("Nom parser failed on VSL record {:?}: {}", tag, err))
        }
        InvalidMessageFieldFormat(field_name: &'static str, err: String) {
            display("Failed to parse message field '{}': {}", field_name, err)
            context(field_name: &'static str, err: ParseFloatError)
                -> (field_name, format!("Float parsing error: {}", err))
            context(field_name: &'static str, err: ParseIntError)
                -> (field_name, format!("Integer parsing error: {}", err))
        }
    }
}

use nom::{rest_s, space, eof};
named!(label<&str, &str>, terminated!(take_until_s!(": "), tag_s!(": ")));
named!(space_terminated<&str, &str>, terminated!(is_not_s!(" "), space));
named!(space_terminated_eof<&str, &str>, terminated!(is_not_s!(" "), eof));

named!(slt_begin<&str, (&str, &str, &str)>, complete!(tuple!(
        space_terminated,           // Type ("sess", "req" or "bereq")
        space_terminated,           // Parent vxid
        space_terminated_eof)));    // Reason

named!(slt_timestamp<&str, (&str, &str, &str, &str)>, complete!(tuple!(
        label,                      // Event label
        space_terminated,           // Absolute time of event
        space_terminated,           // Time since start of work unit
        space_terminated_eof)));    // Time since last timestamp

named!(slt_method<&str, &str>, complete!(rest_s));
named!(slt_url<&str, &str>, complete!(rest_s));
named!(slt_protocol<&str, &str>, complete!(rest_s));

named!(slt_header<&str, (&str, &str)>, complete!(tuple!(
        label,      // Header name
        rest_s)));  // Header value

impl RecordBuilder {
    fn new(ident: VslIdent) -> RecordBuilder {
        RecordBuilder {
            ident: ident,
            transaction_type: None,
            start: None,
            end: None,
            method: None,
            url: None,
            protocol: None,
            status_name: None,
            status_code: None,
            reason: None,
            req_headers: HashMap::new(),
            resp_headers: HashMap::new()
        }
    }

    fn apply<'r>(self, vsl: &'r VslRecord) -> Result<RecordBuilderResult, RecordBuilderError> {
        let builder = match vsl.message() {
            Ok(message) => match vsl.tag {
                VslRecordTag::SLT_Begin => {
                    let (transaction_type, parent, reason) = try!(slt_begin(message).into_result().context(vsl.tag));
                    let parent = try!(parent.parse().context("parent vxid"));

                    let transaction_type = match transaction_type {
                        "bereq" => TransactionType::Backend {
                            parent: parent,
                            reason: reason.to_owned()
                        },
                        _ => return Err(RecordBuilderError::UnimplementedTransactionType(transaction_type.to_string()))
                    };

                    RecordBuilder {
                        transaction_type: Some(transaction_type),
                        .. self
                    }
                }
                VslRecordTag::SLT_Timestamp => {
                    let (label, timestamp, _sice_work_start, _since_last_timestamp) = try!(slt_timestamp(message).into_result().context(vsl.tag));
                    match label {
                        "Start" => RecordBuilder {
                                start: Some(try!(timestamp.parse().context("timestamp"))),
                                .. self
                            },
                            _ => {
                                warn!("Ignoring unknown SLT_Timestamp label variant: {}", label);
                                self
                            }
                    }
                }
                VslRecordTag::SLT_BereqMethod | VslRecordTag::SLT_ReqMethod => {
                    let method = try!(slt_method(message).into_result().context(vsl.tag));

                    RecordBuilder {
                        method: Some(method.to_string()),
                        .. self
                    }
                }
                VslRecordTag::SLT_BereqProtocol | VslRecordTag::SLT_ReqProtocol => {
                    let protocol = try!(slt_protocol(message).into_result().context(vsl.tag));

                    RecordBuilder {
                        protocol: Some(protocol.to_string()),
                        .. self
                    }
                }
                VslRecordTag::SLT_BereqURL | VslRecordTag::SLT_ReqURL => {
                    let url = try!(slt_url(message).into_result().context(vsl.tag));

                    RecordBuilder {
                        url: Some(url.to_string()),
                        .. self
                    }
                }
                VslRecordTag::SLT_BereqHeader | VslRecordTag::SLT_ReqHeader => {
                    let (name, value) = try!(slt_header(message).into_result().context(vsl.tag));

                    let mut headers = self.req_headers;
                    headers.insert(name.to_string(), value.to_string());

                    RecordBuilder {
                        req_headers: headers,
                        .. self
                    }
                }
                _ => {
                    warn!("Ignoring unknown VSL tag: {:?}", vsl.tag);
                    self
                }
            },
            Err(err) => return Err(RecordBuilderError::NonUtf8VslMessage(err))
        };

        Ok(RecordBuilderResult::Building(builder))
    }
}

#[derive(Debug)]
pub struct State {
    builders: HashMap<VslIdent, RecordBuilder>
}

impl State {
    pub fn new() -> State {
        State { builders: HashMap::new() }
    }

    pub fn apply(&mut self, vsl: &VslRecord) -> Option<AccessRecord> {
        //TODO: use entry API
        let builder = match self.builders.remove(&vsl.ident) {
            Some(builder) => builder,
            None => RecordBuilder::new(vsl.ident),
        };

        match builder.apply(vsl) {
            Ok(result) => match result {
                RecordBuilderResult::Building(builder) => {
                    self.builders.insert(vsl.ident, builder);
                    return None
                }
                RecordBuilderResult::Ready(record) => return Some(record),
            },
            Err(err) => {
                error!("Error while building record with ident {} while applying VSL record with tag {:?} and message {:?}: {}", vsl.ident, vsl.tag, vsl.message(), err);
                return None
            }
        }
    }

    #[cfg(test)]
    fn get(&self, ident: VslIdent) -> Option<&RecordBuilder> {
        self.builders.get(&ident)
    }
}

#[cfg(test)]
mod access_log_state_tests {
    pub use super::*;
    use vsl::{VslRecord, VslRecordTag};

    #[test]
    fn apply_non_utf8() {
        let mut state = State::new();

        state.apply(&VslRecord {
            tag: VslRecordTag::SLT_Begin,
            marker: 0,
            ident: 123,
            data: &[255, 0, 1, 2, 3]
        });

        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "bereq 321 fetch"));

        let builder = state.get(123).unwrap().clone();
        let transaction_type = builder.transaction_type.unwrap();

        assert_eq!(transaction_type.get_backend_parent(), 321);
        assert_eq!(transaction_type.get_backend_reason(), "fetch");
    }

    #[test]
    fn apply_begin_unimpl_transaction_type() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "foo 231 fetch"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin_parser_fail() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "foo bar"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin_float_parse_fail() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "bereq bar fetch"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_timestamp() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Timestamp, 123, "Start: 1469180762.484544 0.000000 0.000000"));

        let builder = state.get(123).unwrap().clone();
        assert_eq!(builder.start, Some(1469180762.484544));
    }

    #[test]
    fn apply_backend_request() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Timestamp, 123, "Start: 1469180762.484544 0.000000 0.000000"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqMethod, 123, "GET"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqURL, 123, "/foobar"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqProtocol, 123, "HTTP/1.1"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqHeader, 123, "Host: localhost:8080"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqHeader, 123, "User-Agent: curl/7.40.0"));

        let builder = state.get(123).unwrap().clone();
        assert_eq!(builder.start, Some(1469180762.484544));
        assert_eq!(builder.method, Some("GET".to_string()));
        assert_eq!(builder.url, Some("/foobar".to_string()));
        assert_eq!(builder.protocol, Some("HTTP/1.1".to_string()));
        assert_eq!(builder.req_headers.get("Host"), Some(&"localhost:8080".to_string()));
        assert_eq!(builder.req_headers.get("User-Agent"), Some(&"curl/7.40.0".to_string()));
    }
}
<commit_msg>cleanup<commit_after>use std::collections::HashMap;
use std::str::Utf8Error;
use std::num::{ParseIntError, ParseFloatError};
use quick_error::ResultExt;

use vsl::{VslRecord, VslRecordTag, VslIdent};

use nom::{self, IResult};

pub type TimeStamp = f64;

#[derive(Debug, Clone)]
pub struct AccessRecord {
    pub ident: VslIdent,
    pub start: TimeStamp,
    pub end: TimeStamp,
    pub transaction_type: TransactionType,
    pub transaction: HttpTransaction,
}

#[derive(Debug, Clone)]
pub enum TransactionType {
    Client,
    Backend {
        parent: VslIdent,
        reason: String,
    },
}

impl TransactionType {
    #[allow(dead_code)]
    pub fn is_backend(&self) -> bool {
        match self {
            &TransactionType::Backend { parent: _, reason: _ } => true,
            _ => false
        }
    }

    #[allow(dead_code)]
    pub fn get_backend_parent(&self) -> VslIdent {
        match self {
            &TransactionType::Backend { ref parent, reason: _ } => *parent,
            _ => panic!("unwrap_backend called on TransactionType that was Backend")
        }
    }

    #[allow(dead_code)]
    pub fn get_backend_reason(&self) -> &str {
        match self {
            &TransactionType::Backend { parent: _, ref reason } => reason,
            _ => panic!("unwrap_backend called on TransactionType that was Backend")
        }
    }
}

#[derive(Debug, Clone)]
pub struct HttpTransaction {
    pub request: HttpRequest,
    pub response: HttpResponse,
}

#[derive(Debug, Clone)]
pub struct HttpRequest {
    pub method: String,
    pub url: String,
    pub protocol: String,
    pub headers: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
pub struct HttpResponse {
    pub status_name: String,
    pub status_code: u32,
    pub headers: Vec<(String, String)>,
}

#[derive(Debug, Clone)]
struct RecordBuilder {
    ident: VslIdent,
    transaction_type: Option<TransactionType>,
    start: Option<TimeStamp>,
    end: Option<TimeStamp>,
    method: Option<String>,
    url: Option<String>,
    protocol: Option<String>,
    status_name: Option<String>,
    status_code: Option<u32>,
    reason: Option<String>,
    req_headers: HashMap<String, String>,
    resp_headers: HashMap<String, String>,
}

#[derive(Debug)]
enum RecordBuilderResult {
    Building(RecordBuilder),
    Ready(AccessRecord),
}

trait IResultExt<O, E> {
    fn into_result(self) -> Result<O, E>;
}

impl<I, O, E> IResultExt<O, nom::Err<I, E>> for IResult<I, O, E> {
    fn into_result(self) -> Result<O, nom::Err<I, E>> {
        match self {
            IResult::Done(_, o) => Ok(o),
            IResult::Error(err) => Err(err),
            IResult::Incomplete(_) => panic!("got Incomplete IResult!"),
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum RecordBuilderError {
        NonUtf8VslMessage(err: Utf8Error) {
            display("VSL record message is not valid UTF-8 encoded string: {}", err)
            cause(err)
        }
        UnimplementedTransactionType(transaction_type: String) {
            display("Unimplemented transaction type '{}'", transaction_type)
        }
        InvalidMessageFormat(err: String) {
            display("Failed to parse message: {}", err)
            // Note: using context() since from() does not support lifetimes
            context(tag: VslRecordTag ,err: nom::Err<&'a str>)
                -> (format!("Nom parser failed on VSL record {:?}: {}", tag, err))
        }
        InvalidMessageFieldFormat(field_name: &'static str, err: String) {
            display("Failed to parse message field '{}': {}", field_name, err)
            context(field_name: &'static str, err: ParseFloatError)
                -> (field_name, format!("Float parsing error: {}", err))
            context(field_name: &'static str, err: ParseIntError)
                -> (field_name, format!("Integer parsing error: {}", err))
        }
    }
}

use nom::{rest_s, space, eof};
named!(label<&str, &str>, terminated!(take_until_s!(": "), tag_s!(": ")));
named!(space_terminated<&str, &str>, terminated!(is_not_s!(" "), space));
named!(space_terminated_eof<&str, &str>, terminated!(is_not_s!(" "), eof));

named!(slt_begin<&str, (&str, &str, &str)>, complete!(tuple!(
        space_terminated,           // Type ("sess", "req" or "bereq")
        space_terminated,           // Parent vxid
        space_terminated_eof)));    // Reason

named!(slt_timestamp<&str, (&str, &str, &str, &str)>, complete!(tuple!(
        label,                      // Event label
        space_terminated,           // Absolute time of event
        space_terminated,           // Time since start of work unit
        space_terminated_eof)));    // Time since last timestamp

named!(slt_method<&str, &str>, complete!(rest_s));
named!(slt_url<&str, &str>, complete!(rest_s));
named!(slt_protocol<&str, &str>, complete!(rest_s));

named!(slt_header<&str, (&str, &str)>, complete!(tuple!(
        label,      // Header name
        rest_s)));  // Header value

impl RecordBuilder {
    fn new(ident: VslIdent) -> RecordBuilder {
        RecordBuilder {
            ident: ident,
            transaction_type: None,
            start: None,
            end: None,
            method: None,
            url: None,
            protocol: None,
            status_name: None,
            status_code: None,
            reason: None,
            req_headers: HashMap::new(),
            resp_headers: HashMap::new()
        }
    }

    fn apply<'r>(self, vsl: &'r VslRecord) -> Result<RecordBuilderResult, RecordBuilderError> {
        let builder = match vsl.message() {
            Ok(message) => match vsl.tag {
                VslRecordTag::SLT_Begin => {
                    let (transaction_type, parent, reason) = try!(slt_begin(message).into_result().context(vsl.tag));
                    let parent = try!(parent.parse().context("parent vxid"));

                    let transaction_type = match transaction_type {
                        "bereq" => TransactionType::Backend {
                            parent: parent,
                            reason: reason.to_owned()
                        },
                        _ => return Err(RecordBuilderError::UnimplementedTransactionType(transaction_type.to_string()))
                    };

                    RecordBuilder {
                        transaction_type: Some(transaction_type),
                        .. self
                    }
                }
                VslRecordTag::SLT_Timestamp => {
                    let (label, timestamp, _sice_work_start, _since_last_timestamp) = try!(slt_timestamp(message).into_result().context(vsl.tag));
                    match label {
                        "Start" => RecordBuilder {
                            start: Some(try!(timestamp.parse().context("timestamp"))),
                            .. self
                        },
                        _ => {
                            warn!("Ignoring unknown SLT_Timestamp label variant: {}", label);
                            self
                        }
                    }
                }
                VslRecordTag::SLT_BereqMethod | VslRecordTag::SLT_ReqMethod => {
                    let method = try!(slt_method(message).into_result().context(vsl.tag));

                    RecordBuilder {
                        method: Some(method.to_string()),
                        .. self
                    }
                }
                VslRecordTag::SLT_BereqProtocol | VslRecordTag::SLT_ReqProtocol => {
                    let protocol = try!(slt_protocol(message).into_result().context(vsl.tag));

                    RecordBuilder {
                        protocol: Some(protocol.to_string()),
                        .. self
                    }
                }
                VslRecordTag::SLT_BereqURL | VslRecordTag::SLT_ReqURL => {
                    let url = try!(slt_url(message).into_result().context(vsl.tag));

                    RecordBuilder {
                        url: Some(url.to_string()),
                        .. self
                    }
                }
                VslRecordTag::SLT_BereqHeader | VslRecordTag::SLT_ReqHeader => {
                    let (name, value) = try!(slt_header(message).into_result().context(vsl.tag));

                    let mut headers = self.req_headers;
                    headers.insert(name.to_string(), value.to_string());

                    RecordBuilder {
                        req_headers: headers,
                        .. self
                    }
                }
                _ => {
                    warn!("Ignoring unknown VSL tag: {:?}", vsl.tag);
                    self
                }
            },
            Err(err) => return Err(RecordBuilderError::NonUtf8VslMessage(err))
        };

        Ok(RecordBuilderResult::Building(builder))
    }
}

#[derive(Debug)]
pub struct State {
    builders: HashMap<VslIdent, RecordBuilder>
}

impl State {
    pub fn new() -> State {
        State { builders: HashMap::new() }
    }

    pub fn apply(&mut self, vsl: &VslRecord) -> Option<AccessRecord> {
        //TODO: use entry API
        let builder = match self.builders.remove(&vsl.ident) {
            Some(builder) => builder,
            None => RecordBuilder::new(vsl.ident),
        };

        match builder.apply(vsl) {
            Ok(result) => match result {
                RecordBuilderResult::Building(builder) => {
                    self.builders.insert(vsl.ident, builder);
                    return None
                }
                RecordBuilderResult::Ready(record) => return Some(record),
            },
            Err(err) => {
                error!("Error while building record with ident {} while applying VSL record with tag {:?} and message {:?}: {}", vsl.ident, vsl.tag, vsl.message(), err);
                return None
            }
        }
    }

    #[cfg(test)]
    fn get(&self, ident: VslIdent) -> Option<&RecordBuilder> {
        self.builders.get(&ident)
    }
}

#[cfg(test)]
mod access_log_state_tests {
    pub use super::*;
    use vsl::{VslRecord, VslRecordTag};

    #[test]
    fn apply_non_utf8() {
        let mut state = State::new();

        state.apply(&VslRecord {
            tag: VslRecordTag::SLT_Begin,
            marker: 0,
            ident: 123,
            data: &[255, 0, 1, 2, 3]
        });

        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "bereq 321 fetch"));

        let builder = state.get(123).unwrap().clone();
        let transaction_type = builder.transaction_type.unwrap();

        assert_eq!(transaction_type.get_backend_parent(), 321);
        assert_eq!(transaction_type.get_backend_reason(), "fetch");
    }

    #[test]
    fn apply_begin_unimpl_transaction_type() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "foo 231 fetch"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin_parser_fail() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "foo bar"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_begin_float_parse_fail() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Begin, 123, "bereq bar fetch"));
        assert!(state.get(123).is_none());
    }

    #[test]
    fn apply_timestamp() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Timestamp, 123, "Start: 1469180762.484544 0.000000 0.000000"));

        let builder = state.get(123).unwrap().clone();
        assert_eq!(builder.start, Some(1469180762.484544));
    }

    #[test]
    fn apply_backend_request() {
        let mut state = State::new();

        state.apply(&VslRecord::from_str(VslRecordTag::SLT_Timestamp, 123, "Start: 1469180762.484544 0.000000 0.000000"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqMethod, 123, "GET"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqURL, 123, "/foobar"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqProtocol, 123, "HTTP/1.1"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqHeader, 123, "Host: localhost:8080"));
        state.apply(&VslRecord::from_str(VslRecordTag::SLT_BereqHeader, 123, "User-Agent: curl/7.40.0"));

        let builder = state.get(123).unwrap().clone();
        assert_eq!(builder.start, Some(1469180762.484544));
        assert_eq!(builder.method, Some("GET".to_string()));
        assert_eq!(builder.url, Some("/foobar".to_string()));
        assert_eq!(builder.protocol, Some("HTTP/1.1".to_string()));
        assert_eq!(builder.req_headers.get("Host"), Some(&"localhost:8080".to_string()));
        assert_eq!(builder.req_headers.get("User-Agent"), Some(&"curl/7.40.0".to_string()));
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate num;

use self::num::complex::{Complex, Complex32, Complex64};
use std::cmp;
use pointer::CPtr;
use scalar::Scalar;
use vector;
use vector::BlasVector;

pub trait Copy {
    fn copy(x: &BlasVector<Self>, y: &mut BlasVector<Self>);
}

macro_rules! copy_impl(
    ($t: ty, $copy_fn: ident) => (
        impl Copy for $t {
            fn copy(x: &BlasVector<$t>, y: &mut BlasVector<$t>) {
                unsafe {
                    vector::ll::$copy_fn(x.len(),
                        x.as_ptr().as_c_ptr(),  x.inc(),
                        y.as_mut_ptr().as_c_ptr(), y.inc());
                }
            }
        }
    );
)

copy_impl!(f32,       cblas_scopy)
copy_impl!(f64,       cblas_dcopy)
copy_impl!(Complex32, cblas_ccopy)
copy_impl!(Complex64, cblas_zcopy)

pub trait Axpy {
    fn axpy(alpha: Self, x: &BlasVector<Self>, y: &mut BlasVector<Self>);
}

macro_rules! axpy_impl(
    ($t: ty, $update_fn: ident) => (
        impl Axpy for $t {
            fn axpy(alpha: $t, x: &BlasVector<$t>, y: &mut BlasVector<$t>) {
                unsafe {
                    let n = cmp::min(x.len(), y.len());

                    vector::ll::$update_fn(n,
                        (&alpha).as_const(),
                        x.as_ptr().as_c_ptr(), x.inc(),
                        y.as_mut_ptr().as_c_ptr(), y.inc());
                }
            }
        }
    );
)

axpy_impl!(f32,       cblas_saxpy)
axpy_impl!(f64,       cblas_daxpy)
axpy_impl!(Complex32, cblas_caxpy)
axpy_impl!(Complex64, cblas_zaxpy)

#[cfg(test)]
mod axpy_tests {
    extern crate num;
    extern crate test;

    use self::num::complex::Complex;
    use vector::ops::Axpy;

    #[test]
    fn real() {
        let x = vec![1f32,-2f32,3f32,4f32];
        let y = vec![3f32,7f32,-2f32,2f32];
        let mut z = y.clone();

        Axpy::axpy(1f32, &y, &mut z);
        Axpy::axpy(1f32, &x, &mut z);
        assert_eq!(z, vec![7f32,12f32,-1f32,8f32]);
    }

    #[test]
    fn complex() {
        let x = vec![Complex::new(1f32, 1f32), Complex::new(1f32, 3f32)];
        let y = vec![Complex::new(3f32, -2f32), Complex::new(2f32, 3f32)];
        let mut z = x.clone();

        Axpy::axpy(Complex::new(-1f32, 1f32), &y, &mut z);
        assert_eq!(z, vec![Complex::new(0f32, 6f32), Complex::new(-4f32, 2f32)]);
    }

}

pub trait Scal {
    fn scal(alpha: Self, x: &mut BlasVector<Self>);
}

macro_rules! scal_impl(
    ($t: ty, $scal_fn: ident) => (
        impl Scal for $t {
            #[inline]
            fn scal(alpha: $t, x: &mut BlasVector<$t>) {
                unsafe {
                    vector::ll::$scal_fn(x.len(),
                        alpha,
                        x.as_mut_ptr().as_c_ptr(), x.inc());
                }
            }
        }
    );

    ($t: ty, $scal_fn: ident, $real_scal_fn: ident) => (
        impl Scal for $t {
            #[inline]
            fn scal(alpha: $t, x: &mut BlasVector<$t>) {
                if alpha.im == 0.0 {
                    unsafe {
                        vector::ll::$real_scal_fn(x.len(),
                            alpha.re,
                            x.as_mut_ptr().as_c_ptr(), x.inc());
                    }
                } else {
                    unsafe {
                        vector::ll::$scal_fn(x.len(),
                            (&alpha).as_const(),
                            x.as_mut_ptr().as_c_ptr(), x.inc());
                    }
                }
            }
        }
    );
)

scal_impl!(f32, cblas_sscal)
scal_impl!(f64, cblas_dscal)
scal_impl!(Complex32, cblas_cscal, cblas_csscal)
scal_impl!(Complex64, cblas_zscal, cblas_zdscal)

#[cfg(test)]
mod scal_tests {
    extern crate num;
    extern crate test;

    use self::num::complex::Complex;
    use vector::ops::Scal;

    #[test]
    fn real() {
        let mut x = vec![1f32,-2f32,3f32,4f32];

        Scal::scal(-2f32, &mut x);
        assert_eq!(x, vec![-2f32, 4f32, -6f32, -8f32]);
    }

    #[test]
    fn complex() {
        let mut x = vec![Complex::new(1f32, 1f32), Complex::new(1f32, 3f32)];

        Scal::scal(Complex::new(1f32, 1f32), &mut x);
        assert_eq!(x, vec![Complex::new(0f32, 2f32), Complex::new(-2f32, 4f32)]);
    }

    #[test]
    fn complex_real() {
        let mut x = vec![Complex::new(1f32, 1f32), Complex::new(1f32, 3f32)];

        Scal::scal(Complex::new(2f32, 0f32), &mut x);
        assert_eq!(x, vec![Complex::new(2f32, 2f32), Complex::new(2f32, 6f32)]);
    }

}
<commit_msg>Add Swap trait<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

extern crate num;

use self::num::complex::{Complex, Complex32, Complex64};
use std::cmp;
use pointer::CPtr;
use scalar::Scalar;
use vector;
use vector::BlasVector;

pub trait Copy {
    fn copy(x: &BlasVector<Self>, y: &mut BlasVector<Self>);
}

macro_rules! copy_impl(
    ($t: ty, $copy_fn: ident) => (
        impl Copy for $t {
            fn copy(x: &BlasVector<$t>, y: &mut BlasVector<$t>) {
                unsafe {
                    vector::ll::$copy_fn(x.len(),
                        x.as_ptr().as_c_ptr(),  x.inc(),
                        y.as_mut_ptr().as_c_ptr(), y.inc());
                }
            }
        }
    );
)

copy_impl!(f32,       cblas_scopy)
copy_impl!(f64,       cblas_dcopy)
copy_impl!(Complex32, cblas_ccopy)
copy_impl!(Complex64, cblas_zcopy)

pub trait Axpy {
    fn axpy(alpha: Self, x: &BlasVector<Self>, y: &mut BlasVector<Self>);
}

macro_rules! axpy_impl(
    ($t: ty, $update_fn: ident) => (
        impl Axpy for $t {
            fn axpy(alpha: $t, x: &BlasVector<$t>, y: &mut BlasVector<$t>) {
                unsafe {
                    let n = cmp::min(x.len(), y.len());

                    vector::ll::$update_fn(n,
                        (&alpha).as_const(),
                        x.as_ptr().as_c_ptr(), x.inc(),
                        y.as_mut_ptr().as_c_ptr(), y.inc());
                }
            }
        }
    );
)

axpy_impl!(f32,       cblas_saxpy)
axpy_impl!(f64,       cblas_daxpy)
axpy_impl!(Complex32, cblas_caxpy)
axpy_impl!(Complex64, cblas_zaxpy)

#[cfg(test)]
mod axpy_tests {
    extern crate num;
    extern crate test;

    use self::num::complex::Complex;
    use vector::ops::Axpy;

    #[test]
    fn real() {
        let x = vec![1f32,-2f32,3f32,4f32];
        let y = vec![3f32,7f32,-2f32,2f32];
        let mut z = y.clone();

        Axpy::axpy(1f32, &y, &mut z);
        Axpy::axpy(1f32, &x, &mut z);
        assert_eq!(z, vec![7f32,12f32,-1f32,8f32]);
    }

    #[test]
    fn complex() {
        let x = vec![Complex::new(1f32, 1f32), Complex::new(1f32, 3f32)];
        let y = vec![Complex::new(3f32, -2f32), Complex::new(2f32, 3f32)];
        let mut z = x.clone();

        Axpy::axpy(Complex::new(-1f32, 1f32), &y, &mut z);
        assert_eq!(z, vec![Complex::new(0f32, 6f32), Complex::new(-4f32, 2f32)]);
    }

}

pub trait Scal {
    fn scal(alpha: Self, x: &mut BlasVector<Self>);
}

macro_rules! scal_impl(
    ($t: ty, $scal_fn: ident) => (
        impl Scal for $t {
            #[inline]
            fn scal(alpha: $t, x: &mut BlasVector<$t>) {
                unsafe {
                    vector::ll::$scal_fn(x.len(),
                        alpha,
                        x.as_mut_ptr().as_c_ptr(), x.inc());
                }
            }
        }
    );

    ($t: ty, $scal_fn: ident, $real_scal_fn: ident) => (
        impl Scal for $t {
            #[inline]
            fn scal(alpha: $t, x: &mut BlasVector<$t>) {
                if alpha.im == 0.0 {
                    unsafe {
                        vector::ll::$real_scal_fn(x.len(),
                            alpha.re,
                            x.as_mut_ptr().as_c_ptr(), x.inc());
                    }
                } else {
                    unsafe {
                        vector::ll::$scal_fn(x.len(),
                            (&alpha).as_const(),
                            x.as_mut_ptr().as_c_ptr(), x.inc());
                    }
                }
            }
        }
    );
)

scal_impl!(f32, cblas_sscal)
scal_impl!(f64, cblas_dscal)
scal_impl!(Complex32, cblas_cscal, cblas_csscal)
scal_impl!(Complex64, cblas_zscal, cblas_zdscal)

#[cfg(test)]
mod scal_tests {
    extern crate num;
    extern crate test;

    use self::num::complex::Complex;
    use vector::ops::Scal;

    #[test]
    fn real() {
        let mut x = vec![1f32,-2f32,3f32,4f32];

        Scal::scal(-2f32, &mut x);
        assert_eq!(x, vec![-2f32, 4f32, -6f32, -8f32]);
    }

    #[test]
    fn complex() {
        let mut x = vec![Complex::new(1f32, 1f32), Complex::new(1f32, 3f32)];

        Scal::scal(Complex::new(1f32, 1f32), &mut x);
        assert_eq!(x, vec![Complex::new(0f32, 2f32), Complex::new(-2f32, 4f32)]);
    }

    #[test]
    fn complex_real() {
        let mut x = vec![Complex::new(1f32, 1f32), Complex::new(1f32, 3f32)];

        Scal::scal(Complex::new(2f32, 0f32), &mut x);
        assert_eq!(x, vec![Complex::new(2f32, 2f32), Complex::new(2f32, 6f32)]);
    }

}

pub trait Swap {
    fn swap(x: &mut BlasVector<Self>, y: &mut BlasVector<Self>);
}

macro_rules! swap_impl(
    ($t: ty, $swap_fn: ident) => (
        impl Swap for $t {
            fn swap(x: &mut BlasVector<$t>, y: &mut BlasVector<$t>) {
                unsafe {
                    let n = cmp::min(x.len(), y.len());

                    vector::ll::$swap_fn(n,
                        x.as_mut_ptr().as_c_ptr(), x.inc(),
                        y.as_mut_ptr().as_c_ptr(), y.inc());
                }
            }
        }
    );
)

swap_impl!(f32,       cblas_sswap)
swap_impl!(f64,       cblas_dswap)
swap_impl!(Complex32, cblas_cswap)
swap_impl!(Complex64, cblas_zswap)

#[cfg(test)]
mod swap_tests {
    extern crate num;
    extern crate test;

    use self::num::complex::Complex;
    use vector::ops::Swap;

    #[test]
    fn real() {
        let mut x = vec![1f32,-2f32,3f32,4f32];
        let mut y = vec![2f32,-3f32,4f32,1f32];
        let xr = y.clone();
        let yr = x.clone();

        Swap::swap(&mut x, &mut y);
        assert_eq!(x, xr);
        assert_eq!(y, yr);
    }

    #[test]
    fn complex() {
        let mut x = vec![Complex::new(2f32, -3f32)];
        let mut y = vec![Complex::new(-1f32, 4f32)];
        let xr = y.clone();
        let yr = x.clone();

        Swap::swap(&mut x, &mut y);
        assert_eq!(x, xr);
        assert_eq!(y, yr);
    }

}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use cgmath::{Vector2, Vector3, deg};
use glutin::{Window, WindowBuilder, VirtualKeyCode, Event};
use glutin::ElementState::{Pressed, Released};
use glutin::MouseButton::{LeftMouseButton};
use core_types::{Size2, ZInt, MapPos};
use visualizer_types::{
    ZFloat,
    Color3,
    Color4,
    ColorId,
    WorldPos,
    ScreenPos,
    VertexCoord,
    TextureCoord,
};
use zgl::{Zgl};
use mesh::{Mesh};
use camera::Camera;
use shader::{Shader};
use geom;
use core_map::{MapPosIter};
use dir::{DirIter};
use picker::{TilePicker, PickResult};
use texture::{Texture};
use obj;

static BG_COLOR: Color3 = Color3{r: 0.0, g: 0.0, b: 0.4};

static VS_SRC: &'static str = "\
    #version 100\n\
    uniform mat4 mvp_mat;\n\
    attribute vec3 position;\n\
    attribute vec2 in_texture_coordinates;\n\
    varying vec2 texture_coordinates;\n\
    void main() {\n\
        gl_Position = mvp_mat * vec4(position, 1.0);\n\
        texture_coordinates = in_texture_coordinates;\n\
    }\n\
";

static FS_SRC: &'static str = "\
    #version 100\n\
    precision mediump float;\n\
    uniform sampler2D basic_texture;\n\
    uniform vec4 basic_color;
    varying vec2 texture_coordinates;\n\
    void main() {\n\
        gl_FragColor = basic_color\n\
            * texture2D(basic_texture, texture_coordinates);\n\
    }\n\
";

fn get_win_size(window: &Window) -> Size2<ZInt> {
    let (w, h) = window.get_inner_size().expect("Can`t get window size");
    Size2{w: w as ZInt, h: h as ZInt}
}

fn get_max_camera_pos(map_size: &Size2<ZInt>) -> WorldPos {
    let pos = geom::map_pos_to_world_pos(
        &MapPos{v: Vector2{x: map_size.w, y: map_size.h - 1}});
    WorldPos{v: Vector3{x: -pos.v.x, y: -pos.v.y, z: 0.0}}
}

fn generate_mesh(map_size: &Size2<ZInt>, zgl: &Zgl) -> Mesh {
    let mut vertex_data = Vec::new();
    let mut tex_data = Vec::new();
    for tile_pos in MapPosIter::new(map_size) {
        let pos = geom::map_pos_to_world_pos(&tile_pos);
        for dir in DirIter::new() {
            let num = dir.to_int();
            let vertex = geom::index_to_hex_vertex(num);
            let next_vertex = geom::index_to_hex_vertex(num + 1);
            vertex_data.push(VertexCoord{v: pos.v + vertex.v});
            vertex_data.push(VertexCoord{v: pos.v + next_vertex.v});
            vertex_data.push(VertexCoord{v: pos.v});
            tex_data.push(TextureCoord{v: Vector2{x: 0.0, y: 0.0}});
            tex_data.push(TextureCoord{v: Vector2{x: 1.0, y: 0.0}});
            tex_data.push(TextureCoord{v: Vector2{x: 0.5, y: 0.5}});
        }
    }
    let mut mesh = Mesh::new(zgl, vertex_data.as_slice());
    let tex = Texture::new(zgl, &Path::new("data/floor.png"));
    mesh.add_texture(zgl, tex, tex_data.as_slice());
    mesh
}

fn load_unit_mesh(zgl: &Zgl, name: &str) -> Mesh {
    let tex_path = Path::new(format!("data/{}.png", name).as_slice());
    let obj_path = Path::new(format!("data/{}.obj", name).as_slice());
    let tex = Texture::new(zgl, &tex_path);
    let obj = obj::Model::new(&obj_path);
    let mut mesh = Mesh::new(zgl, obj.build().as_slice());
    mesh.add_texture(zgl, tex, obj.build_tex_coord().as_slice());
    mesh
}

pub struct Visualizer {
    zgl: Zgl,
    window: Window,
    should_close: bool,
    shader: Shader,
    color_uniform_location: ColorId,
    camera: Camera,
    mouse_pos: ScreenPos,
    is_lmb_pressed: bool,
    win_size: Size2<ZInt>,
    mesh: Mesh, // TODO: map_mesh
    picker: TilePicker,
    unit_mesh: Mesh,
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let window_builder = WindowBuilder::new().with_gl_version((2, 0));
        let window = window_builder.build().ok().expect("Can`t create window");
        unsafe {
            window.make_current();
        };
        let win_size = get_win_size(&window);
        let mut zgl = Zgl::new(|s| window.get_proc_address(s));
        zgl.init_opengl();
        zgl.print_gl_info();
        let mut shader = Shader::new(&zgl, VS_SRC, FS_SRC);
        shader.enable_texture_coords(&zgl);
        shader.activate(&zgl);
        let color_uniform_location = shader.get_uniform_color(
            &zgl, "basic_color");
        zgl.set_clear_color(&BG_COLOR);
        let mut camera = Camera::new(&win_size);
        let map_size = Size2{w: 5, h: 8};
        camera.set_max_pos(get_max_camera_pos(&map_size));
        let mesh = generate_mesh(&map_size, &zgl);
        let picker = TilePicker::new(&zgl, &map_size);
        let unit_mesh = load_unit_mesh(&zgl, "tank");
        // let unit_mesh = load_unit_mesh(&zgl, "soldier");
        Visualizer {
            zgl: zgl,
            window: window,
            should_close: false,
            shader: shader,
            color_uniform_location: color_uniform_location,
            camera: camera,
            mouse_pos: ScreenPos{v: Vector2::from_value(0)},
            is_lmb_pressed: false,
            win_size: win_size,
            mesh: mesh,
            picker: picker,
            unit_mesh: unit_mesh,
        }
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    fn handle_event_mouse_move(&mut self, pos: &ScreenPos) {
        if self.is_lmb_pressed {
            let diff = pos.v - self.mouse_pos.v;
            let win_w = self.win_size.w as ZFloat;
            let win_h = self.win_size.h as ZFloat;
            self.camera.add_horizontal_angle(
                deg(diff.x as ZFloat * (360.0 / win_w)));
            self.camera.add_vertical_angle(
                deg(diff.y as ZFloat * (360.0 / win_h)));
        }
        self.mouse_pos = pos.clone();
    }

    fn handle_event_key_press(&mut self, key: VirtualKeyCode) {
        match key {
            VirtualKeyCode::Q | VirtualKeyCode::Escape => {
                self.should_close = true;
            },
            VirtualKeyCode::W | VirtualKeyCode::Up => {
                self.camera.move_camera(deg(270.0), 0.1);
            },
            VirtualKeyCode::S | VirtualKeyCode::Down => {
                self.camera.move_camera(deg(90.0), 0.1);
            },
            VirtualKeyCode::D | VirtualKeyCode::Right => {
                self.camera.move_camera(deg(0.0), 0.1);
            },
            VirtualKeyCode::A | VirtualKeyCode::Left => {
                self.camera.move_camera(deg(180.0), 0.1);
            },
            VirtualKeyCode::Minus => {
                self.camera.change_zoom(1.3);
            },
            VirtualKeyCode::Equals => {
                self.camera.change_zoom(0.7);
            },
            _ => {},
        }
    }

    fn handle_event(&mut self, event: &Event) {
        match *event {
            Event::Closed => {
                self.should_close = true;
            },
            Event::Resized(w, h) => {
                self.win_size = Size2{w: w as ZInt, h: h as ZInt};
                self.zgl.set_viewport(&self.win_size);
            },
            Event::MouseMoved((x, y)) => {
                let pos = ScreenPos{v: Vector2{x: x as ZInt, y: y as ZInt}};
                self.handle_event_mouse_move(&pos);
            },
            Event::MouseInput(Pressed, LeftMouseButton) => {
                self.is_lmb_pressed = true;
            },
            Event::MouseInput(Released, LeftMouseButton) => {
                self.is_lmb_pressed = false;
                let (r, g, b, a) = self.zgl.read_pixel_bytes(
                    &self.win_size, &self.mouse_pos);
                println!("r: {}, g: {}, b: {}, a: {}", r, g, b, a);
            },
            Event::KeyboardInput(Released, _, Some(key)) => {
                self.handle_event_key_press(key);
            },
            _ => {},
        }
    }

    fn handle_events(&mut self) {
        let events = self.window.poll_events().collect::<Vec<_>>();
        if events.is_empty() {
            return;
        }
        // println!("{}", events);
        for event in events.iter() {
            self.handle_event(event);
        }
    }

    fn draw(&mut self) {
        self.zgl.set_clear_color(&BG_COLOR);
        self.zgl.clear_screen();
        self.shader.activate(&self.zgl);
        self.shader.set_uniform_color(
            &self.zgl, &self.color_uniform_location,
            &Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0},
        );
        self.shader.set_uniform_mat4f(
            &self.zgl,
            self.shader.get_mvp_mat(),
            &self.camera.mat(&self.zgl),
        );
        self.mesh.draw(&self.zgl, &self.shader);
        self.unit_mesh.draw(&self.zgl, &self.shader);
        self.window.swap_buffers();
    }

    fn pick_tile(&mut self) {
        let pick_result = self.picker.pick_tile(
            &mut self.zgl, &self.camera, &self.win_size, &self.mouse_pos);
        match pick_result {
            PickResult::Nothing => {},
            PickResult::MapPos(map_pos) => {
                println!("PICKED: x: {}, y: {}", map_pos.v.x, map_pos.v.y);
            },
        }
    }

    pub fn tick(&mut self) {
        self.handle_events();
        // self.logic();
        self.pick_tile();
        self.draw();
        // self.update_time();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/visualizer.rs: mesh -> map_mesh<commit_after>// See LICENSE file for copyright and license details.

use cgmath::{Vector2, Vector3, deg};
use glutin::{Window, WindowBuilder, VirtualKeyCode, Event};
use glutin::ElementState::{Pressed, Released};
use glutin::MouseButton::{LeftMouseButton};
use core_types::{Size2, ZInt, MapPos};
use visualizer_types::{
    ZFloat,
    Color3,
    Color4,
    ColorId,
    WorldPos,
    ScreenPos,
    VertexCoord,
    TextureCoord,
};
use zgl::{Zgl};
use mesh::{Mesh};
use camera::Camera;
use shader::{Shader};
use geom;
use core_map::{MapPosIter};
use dir::{DirIter};
use picker::{TilePicker, PickResult};
use texture::{Texture};
use obj;

static BG_COLOR: Color3 = Color3{r: 0.0, g: 0.0, b: 0.4};

static VS_SRC: &'static str = "\
    #version 100\n\
    uniform mat4 mvp_mat;\n\
    attribute vec3 position;\n\
    attribute vec2 in_texture_coordinates;\n\
    varying vec2 texture_coordinates;\n\
    void main() {\n\
        gl_Position = mvp_mat * vec4(position, 1.0);\n\
        texture_coordinates = in_texture_coordinates;\n\
    }\n\
";

static FS_SRC: &'static str = "\
    #version 100\n\
    precision mediump float;\n\
    uniform sampler2D basic_texture;\n\
    uniform vec4 basic_color;
    varying vec2 texture_coordinates;\n\
    void main() {\n\
        gl_FragColor = basic_color\n\
            * texture2D(basic_texture, texture_coordinates);\n\
    }\n\
";

fn get_win_size(window: &Window) -> Size2<ZInt> {
    let (w, h) = window.get_inner_size().expect("Can`t get window size");
    Size2{w: w as ZInt, h: h as ZInt}
}

fn get_max_camera_pos(map_size: &Size2<ZInt>) -> WorldPos {
    let pos = geom::map_pos_to_world_pos(
        &MapPos{v: Vector2{x: map_size.w, y: map_size.h - 1}});
    WorldPos{v: Vector3{x: -pos.v.x, y: -pos.v.y, z: 0.0}}
}

fn generate_map_mesh(map_size: &Size2<ZInt>, zgl: &Zgl) -> Mesh {
    let mut vertex_data = Vec::new();
    let mut tex_data = Vec::new();
    for tile_pos in MapPosIter::new(map_size) {
        let pos = geom::map_pos_to_world_pos(&tile_pos);
        for dir in DirIter::new() {
            let num = dir.to_int();
            let vertex = geom::index_to_hex_vertex(num);
            let next_vertex = geom::index_to_hex_vertex(num + 1);
            vertex_data.push(VertexCoord{v: pos.v + vertex.v});
            vertex_data.push(VertexCoord{v: pos.v + next_vertex.v});
            vertex_data.push(VertexCoord{v: pos.v});
            tex_data.push(TextureCoord{v: Vector2{x: 0.0, y: 0.0}});
            tex_data.push(TextureCoord{v: Vector2{x: 1.0, y: 0.0}});
            tex_data.push(TextureCoord{v: Vector2{x: 0.5, y: 0.5}});
        }
    }
    let mut mesh = Mesh::new(zgl, vertex_data.as_slice());
    let tex = Texture::new(zgl, &Path::new("data/floor.png"));
    mesh.add_texture(zgl, tex, tex_data.as_slice());
    mesh
}

fn load_unit_mesh(zgl: &Zgl, name: &str) -> Mesh {
    let tex_path = Path::new(format!("data/{}.png", name).as_slice());
    let obj_path = Path::new(format!("data/{}.obj", name).as_slice());
    let tex = Texture::new(zgl, &tex_path);
    let obj = obj::Model::new(&obj_path);
    let mut mesh = Mesh::new(zgl, obj.build().as_slice());
    mesh.add_texture(zgl, tex, obj.build_tex_coord().as_slice());
    mesh
}

pub struct Visualizer {
    zgl: Zgl,
    window: Window,
    should_close: bool,
    shader: Shader,
    color_uniform_location: ColorId,
    camera: Camera,
    mouse_pos: ScreenPos,
    is_lmb_pressed: bool,
    win_size: Size2<ZInt>,
    map_mesh: Mesh,
    picker: TilePicker,
    unit_mesh: Mesh,
}

impl Visualizer {
    pub fn new() -> Visualizer {
        let window_builder = WindowBuilder::new().with_gl_version((2, 0));
        let window = window_builder.build().ok().expect("Can`t create window");
        unsafe {
            window.make_current();
        };
        let win_size = get_win_size(&window);
        let mut zgl = Zgl::new(|s| window.get_proc_address(s));
        zgl.init_opengl();
        zgl.print_gl_info();
        let mut shader = Shader::new(&zgl, VS_SRC, FS_SRC);
        shader.enable_texture_coords(&zgl);
        shader.activate(&zgl);
        let color_uniform_location = shader.get_uniform_color(
            &zgl, "basic_color");
        zgl.set_clear_color(&BG_COLOR);
        let mut camera = Camera::new(&win_size);
        let map_size = Size2{w: 5, h: 8};
        camera.set_max_pos(get_max_camera_pos(&map_size));
        let map_mesh = generate_map_mesh(&map_size, &zgl);
        let picker = TilePicker::new(&zgl, &map_size);
        let unit_mesh = load_unit_mesh(&zgl, "tank");
        // let unit_mesh = load_unit_mesh(&zgl, "soldier");
        Visualizer {
            zgl: zgl,
            window: window,
            should_close: false,
            shader: shader,
            color_uniform_location: color_uniform_location,
            camera: camera,
            mouse_pos: ScreenPos{v: Vector2::from_value(0)},
            is_lmb_pressed: false,
            win_size: win_size,
            map_mesh: map_mesh,
            picker: picker,
            unit_mesh: unit_mesh,
        }
    }

    pub fn is_running(&self) -> bool {
        !self.should_close
    }

    fn handle_event_mouse_move(&mut self, pos: &ScreenPos) {
        if self.is_lmb_pressed {
            let diff = pos.v - self.mouse_pos.v;
            let win_w = self.win_size.w as ZFloat;
            let win_h = self.win_size.h as ZFloat;
            self.camera.add_horizontal_angle(
                deg(diff.x as ZFloat * (360.0 / win_w)));
            self.camera.add_vertical_angle(
                deg(diff.y as ZFloat * (360.0 / win_h)));
        }
        self.mouse_pos = pos.clone();
    }

    fn handle_event_key_press(&mut self, key: VirtualKeyCode) {
        match key {
            VirtualKeyCode::Q | VirtualKeyCode::Escape => {
                self.should_close = true;
            },
            VirtualKeyCode::W | VirtualKeyCode::Up => {
                self.camera.move_camera(deg(270.0), 0.1);
            },
            VirtualKeyCode::S | VirtualKeyCode::Down => {
                self.camera.move_camera(deg(90.0), 0.1);
            },
            VirtualKeyCode::D | VirtualKeyCode::Right => {
                self.camera.move_camera(deg(0.0), 0.1);
            },
            VirtualKeyCode::A | VirtualKeyCode::Left => {
                self.camera.move_camera(deg(180.0), 0.1);
            },
            VirtualKeyCode::Minus => {
                self.camera.change_zoom(1.3);
            },
            VirtualKeyCode::Equals => {
                self.camera.change_zoom(0.7);
            },
            _ => {},
        }
    }

    fn handle_event(&mut self, event: &Event) {
        match *event {
            Event::Closed => {
                self.should_close = true;
            },
            Event::Resized(w, h) => {
                self.win_size = Size2{w: w as ZInt, h: h as ZInt};
                self.zgl.set_viewport(&self.win_size);
            },
            Event::MouseMoved((x, y)) => {
                let pos = ScreenPos{v: Vector2{x: x as ZInt, y: y as ZInt}};
                self.handle_event_mouse_move(&pos);
            },
            Event::MouseInput(Pressed, LeftMouseButton) => {
                self.is_lmb_pressed = true;
            },
            Event::MouseInput(Released, LeftMouseButton) => {
                self.is_lmb_pressed = false;
                let (r, g, b, a) = self.zgl.read_pixel_bytes(
                    &self.win_size, &self.mouse_pos);
                println!("r: {}, g: {}, b: {}, a: {}", r, g, b, a);
            },
            Event::KeyboardInput(Released, _, Some(key)) => {
                self.handle_event_key_press(key);
            },
            _ => {},
        }
    }

    fn handle_events(&mut self) {
        let events = self.window.poll_events().collect::<Vec<_>>();
        if events.is_empty() {
            return;
        }
        // println!("{}", events);
        for event in events.iter() {
            self.handle_event(event);
        }
    }

    fn draw(&mut self) {
        self.zgl.set_clear_color(&BG_COLOR);
        self.zgl.clear_screen();
        self.shader.activate(&self.zgl);
        self.shader.set_uniform_color(
            &self.zgl, &self.color_uniform_location,
            &Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0},
        );
        self.shader.set_uniform_mat4f(
            &self.zgl,
            self.shader.get_mvp_mat(),
            &self.camera.mat(&self.zgl),
        );
        self.map_mesh.draw(&self.zgl, &self.shader);
        self.unit_mesh.draw(&self.zgl, &self.shader);
        self.window.swap_buffers();
    }

    fn pick_tile(&mut self) {
        let pick_result = self.picker.pick_tile(
            &mut self.zgl, &self.camera, &self.win_size, &self.mouse_pos);
        match pick_result {
            PickResult::Nothing => {},
            PickResult::MapPos(map_pos) => {
                println!("PICKED: x: {}, y: {}", map_pos.v.x, map_pos.v.y);
            },
        }
    }

    pub fn tick(&mut self) {
        self.handle_events();
        // self.logic();
        self.pick_tile();
        self.draw();
        // self.update_time();
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use core::ptr::{read, write};

use common::memory::*;
use common::pci::*;
use common::pio::*;
use common::scheduler::*;

use programs::common::*;

#[repr(packed)]
struct BD {
    ptr: u32,
    samples: u32
}

struct AC97Resource {
    audio: usize,
    bus_master: usize
}

impl Resource for AC97Resource {
    fn url(&self) -> URL {
        return URL::from_string(&"audio://".to_string());
    }

    fn stat(&self) -> ResourceType {
        return ResourceType::File;
    }

    fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        return Option::None;
    }

    fn read_to_end(&mut self, vec: &mut Vec<u8>) -> Option<usize> {
        return Option::None;
    }

    fn write(&mut self, buf: &[u8]) -> Option<usize> {
        unsafe {
            let audio = self.audio as u16;
            let master_volume = audio + 2;
            let pcm_volume = audio + 0x18;

            outw(master_volume, 0);
            outw(pcm_volume, 0);

            let bus_master = self.bus_master as u16;

            let po_bdbar = bus_master + 0x10;
            let po_civ = bus_master + 0x14;
            let po_lvi = bus_master + 0x15;
            let po_sr = bus_master + 0x16;
            let po_picb = bus_master + 0x18;
            let po_piv = bus_master + 0x1A;
            let po_cr = bus_master + 0x1B;
            let glob_cnt = bus_master + 0x2C;
            let glob_sta = bus_master + 0x30;

            outb(po_cr, 0);

            let mut bdl = ind(po_bdbar) as *mut BD;
            if bdl as usize == 0 {
                bdl = alloc(32 * size_of::<BD>()) as *mut BD;
                outd(po_bdbar, bdl as u32);
            }

            for i in 0..32 {
                ptr::write(bdl.offset(i), BD {
                    ptr: 0,
                    samples: 0
                });
            }

            let mut wait = false;
            let mut position = 0;

            let mut lvi = inb(po_lvi);

            let start_lvi;
            if lvi == 0 {
                start_lvi = 31;
            }else{
                start_lvi = lvi - 1;
            }

            lvi += 1;
            if lvi >= 32 {
                lvi = 0;
            }
            loop {
                while wait {
                    if inb(po_civ) != lvi as u8 {
                        break;
                    }
                    Duration::new(0, 100000000).sleep();
                }

                dd(inb(po_civ) as usize);
                d(" / ");
                dd(lvi as usize);
                d(": ");
                dd(position);
                d(" / ");
                dd(buf.len());
                dl();

                let bytes = min(65534 * 2, (buf.len() - position + 1));
                let samples = bytes/2;

                ptr::write(bdl.offset(lvi as isize), BD {
                    ptr: buf.as_ptr().offset(position as isize) as u32,
                    samples: (samples & 0xFFFF) as u32
                });

                position += bytes;

                if position >= buf.len() {
                    break;
                }

                lvi += 1;

                if lvi >= 32 {
                    lvi = 0;
                }

                if lvi == start_lvi {
                    outb(po_lvi, start_lvi);
                    outb(po_cr, 1);
                    wait = true;
                }
            }

            outb(po_lvi, lvi);
            outb(po_cr, 1);

            loop {
                if inb(po_civ) == lvi {
                    outb(po_cr, 0);
                    break;
                }
                Duration::new(0, 100000000).sleep();
            }

            d("Finished ");
            dd(inb(po_civ) as usize);
            d(" / ");
            dd(lvi as usize);
            dl();
        }

        return Option::Some(buf.len());
    }

    fn seek(&mut self, pos: ResourceSeek) -> Option<usize> {
        return Option::None;
    }

    fn flush(&mut self) -> bool {
        return false;
    }
}

pub struct AC97 {
    pub audio: usize,
    pub bus_master: usize,
    pub irq: u8
}

impl SessionItem for AC97 {
    fn scheme(&self) -> String {
        return "audio".to_string();
    }

    fn open(&mut self, url: &URL) -> Box<Resource> {
        return box AC97Resource {
            audio: self.audio,
            bus_master: self.bus_master
        };
    }

    fn on_irq(&mut self, irq: u8){
        if irq == self.irq {
            d("AC97 IRQ\n");
        }
    }

    fn on_poll(&mut self){
    }
}

impl AC97 {
    pub unsafe fn new(bus: usize, slot: usize, func: usize) -> Box<AC97> {
        pci_write(bus, slot, func, 0x04, pci_read(bus, slot, func, 0x04) | (1 << 2)); // Bus mastering

        let mut module = box AC97 {
            audio: pci_read(bus, slot, 0, 0x10) & 0xFFFFFFF0,
            bus_master: pci_read(bus, slot, 0, 0x14) & 0xFFFFFFF0,
            irq: pci_read(bus, slot, func, 0x3C) as u8 & 0xF
        };

        module.init();

        return module;
    }

    pub unsafe fn init(&self){
        d("AC97 on: ");
        dh(self.audio);
        d(", ");
        dh(self.bus_master);
        d(", IRQ: ");
        dbh(self.irq);

        dl();
    }
}
<commit_msg>Wait for other files<commit_after>use core::ptr::{read, write};

use common::memory::*;
use common::pci::*;
use common::pio::*;
use common::scheduler::*;

use programs::common::*;

#[repr(packed)]
struct BD {
    ptr: u32,
    samples: u32
}

struct AC97Resource {
    audio: usize,
    bus_master: usize
}

impl Resource for AC97Resource {
    fn url(&self) -> URL {
        return URL::from_string(&"audio://".to_string());
    }

    fn stat(&self) -> ResourceType {
        return ResourceType::File;
    }

    fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        return Option::None;
    }

    fn read_to_end(&mut self, vec: &mut Vec<u8>) -> Option<usize> {
        return Option::None;
    }

    fn write(&mut self, buf: &[u8]) -> Option<usize> {
        unsafe {
            let audio = self.audio as u16;
            let master_volume = audio + 2;
            let pcm_volume = audio + 0x18;

            outw(master_volume, 0);
            outw(pcm_volume, 0);

            let bus_master = self.bus_master as u16;

            let po_bdbar = bus_master + 0x10;
            let po_civ = bus_master + 0x14;
            let po_lvi = bus_master + 0x15;
            let po_sr = bus_master + 0x16;
            let po_picb = bus_master + 0x18;
            let po_piv = bus_master + 0x1A;
            let po_cr = bus_master + 0x1B;
            let glob_cnt = bus_master + 0x2C;
            let glob_sta = bus_master + 0x30;

            loop {
                if inb(po_cr) & 1 == 0 {
                    break;
                }
                Duration::new(0, 10000000).sleep();
            }

            outb(po_cr, 0);

            let mut bdl = ind(po_bdbar) as *mut BD;
            if bdl as usize == 0 {
                bdl = alloc(32 * size_of::<BD>()) as *mut BD;
                outd(po_bdbar, bdl as u32);
            }

            for i in 0..32 {
                ptr::write(bdl.offset(i), BD {
                    ptr: 0,
                    samples: 0
                });
            }

            let mut wait = false;
            let mut position = 0;

            let mut lvi = inb(po_lvi);

            let start_lvi;
            if lvi == 0 {
                start_lvi = 31;
            }else{
                start_lvi = lvi - 1;
            }

            lvi += 1;
            if lvi >= 32 {
                lvi = 0;
            }
            loop {
                while wait {
                    if inb(po_civ) != lvi as u8 {
                        break;
                    }
                    Duration::new(0, 10000000).sleep();
                }

                dd(inb(po_civ) as usize);
                d(" / ");
                dd(lvi as usize);
                d(": ");
                dd(position);
                d(" / ");
                dd(buf.len());
                dl();

                let bytes = min(65534 * 2, (buf.len() - position + 1));
                let samples = bytes/2;

                ptr::write(bdl.offset(lvi as isize), BD {
                    ptr: buf.as_ptr().offset(position as isize) as u32,
                    samples: (samples & 0xFFFF) as u32
                });

                position += bytes;

                if position >= buf.len() {
                    break;
                }

                lvi += 1;

                if lvi >= 32 {
                    lvi = 0;
                }

                if lvi == start_lvi {
                    outb(po_lvi, start_lvi);
                    outb(po_cr, 1);
                    wait = true;
                }
            }

            outb(po_lvi, lvi);
            outb(po_cr, 1);

            loop {
                if inb(po_civ) == lvi {
                    outb(po_cr, 0);
                    break;
                }
                Duration::new(0, 10000000).sleep();
            }

            d("Finished ");
            dd(inb(po_civ) as usize);
            d(" / ");
            dd(lvi as usize);
            dl();
        }

        return Option::Some(buf.len());
    }

    fn seek(&mut self, pos: ResourceSeek) -> Option<usize> {
        return Option::None;
    }

    fn flush(&mut self) -> bool {
        return false;
    }
}

pub struct AC97 {
    pub audio: usize,
    pub bus_master: usize,
    pub irq: u8
}

impl SessionItem for AC97 {
    fn scheme(&self) -> String {
        return "audio".to_string();
    }

    fn open(&mut self, url: &URL) -> Box<Resource> {
        return box AC97Resource {
            audio: self.audio,
            bus_master: self.bus_master
        };
    }

    fn on_irq(&mut self, irq: u8){
        if irq == self.irq {
            d("AC97 IRQ\n");
        }
    }

    fn on_poll(&mut self){
    }
}

impl AC97 {
    pub unsafe fn new(bus: usize, slot: usize, func: usize) -> Box<AC97> {
        pci_write(bus, slot, func, 0x04, pci_read(bus, slot, func, 0x04) | (1 << 2)); // Bus mastering

        let mut module = box AC97 {
            audio: pci_read(bus, slot, 0, 0x10) & 0xFFFFFFF0,
            bus_master: pci_read(bus, slot, 0, 0x14) & 0xFFFFFFF0,
            irq: pci_read(bus, slot, func, 0x3C) as u8 & 0xF
        };

        module.init();

        return module;
    }

    pub unsafe fn init(&self){
        d("AC97 on: ");
        dh(self.audio);
        d(", ");
        dh(self.bus_master);
        d(", IRQ: ");
        dbh(self.irq);

        dl();
    }
}
<|endoftext|>


<commit_before>extern crate tempdir;
extern crate hyper;
extern crate grnenvlib;
#[macro_use]
extern crate clap;

use clap::{Arg, App, AppSettings, SubCommand};
use grnenvlib::command;

fn main() {
    default_main();
}

fn cli() -> App<'static, 'static> {
    App::new("grnenv-rs")
        .version(crate_version!())
        .author(crate_authors!())
        .about("A tiny tool for obtain and select multiple Groonga.")
        .setting(AppSettings::AllowExternalSubcommands)
        .subcommand(SubCommand::with_name("init").about("Prepare grnenv-rs."))
        .subcommand(SubCommand::with_name("install")
            .about("Install a given Groonga version and arch")
            .arg(Arg::with_name("VERSION").required(true))
            .arg(Arg::with_name("arch")
                .short("a")
                .long("arch")
                .value_name("ARCH")
                .help("Select architectures. e.g.) x86, x64")
                .takes_value(true)))
        .subcommand(SubCommand::with_name("switch")
            .about("Switch Groonga with given version and arch")
            .arg(Arg::with_name("VERSION").required(true))
            .arg(Arg::with_name("arch")
                .short("a")
                .long("arch")
                .value_name("ARCH")
                .help("Select architectures. e.g.) x86, x64")
                .takes_value(true)))
        .subcommand(SubCommand::with_name("versions").about("Display installed Groonga versions"))
        .subcommand(SubCommand::with_name("uninstall")
            .about("Uninstall a given Groonga version and arch")
            .arg(Arg::with_name("VERSION").required(true))
            .arg(Arg::with_name("arch")
                .short("a")
                .long("arch")
                .value_name("ARCH")
                .help("Select architectures. e.g.) x86, x64")
                .takes_value(true)))
        .subcommand(SubCommand::with_name("list").about("Display installable Groonga versions"))

}

#[cfg(not(windows))]
fn default_main() {
    let matches = cli().get_matches();
    match matches.subcommand() {
        ("init", _) => command::unix::init(),
        ("install", Some(m)) => command::unix::install(m),
        ("switch", Some(m)) => command::unix::switch(m),
        ("versions", _) => command::common::versions(),
        ("uninstall", Some(m)) => command::unix::uninstall(m),
        ("list", _) => command::unix::list(),
        (external, Some(ext_m)) => command::common::execute_external_command(external, ext_m),
        (_, _) => unreachable!(),
    }
}

#[cfg(windows)]
fn default_main() {
    let matches = cli().get_matches();
    match matches.subcommand() {
        ("init", _) => command::windows::init(),
        ("install", Some(m)) => command::windows::install(m),
        ("switch", Some(m)) => command::windows::switch(m),
        ("versions", _) => command::common::versions(),
        ("uninstall", Some(m)) => command::windows::uninstall(m),
        ("list", _) => command::windows::list(),
        (external, Some(ext_m)) => command::common::execute_external_command(external, ext_m),
        (_, _) => unreachable!(),
    }
}
<commit_msg>bin grnenv: Print help when taking no arguments<commit_after>extern crate tempdir;
extern crate hyper;
extern crate grnenvlib;
#[macro_use]
extern crate clap;

use clap::{Arg, App, AppSettings, SubCommand};
use grnenvlib::command;

fn main() {
    default_main();
}

fn cli() -> App<'static, 'static> {
    App::new("grnenv-rs")
        .version(crate_version!())
        .author(crate_authors!())
        .about("A tiny tool for obtain and select multiple Groonga.")
        .setting(AppSettings::AllowExternalSubcommands)
        .subcommand(SubCommand::with_name("init").about("Prepare grnenv-rs."))
        .subcommand(SubCommand::with_name("install")
            .about("Install a given Groonga version and arch")
            .arg(Arg::with_name("VERSION").required(true))
            .arg(Arg::with_name("arch")
                .short("a")
                .long("arch")
                .value_name("ARCH")
                .help("Select architectures. e.g.) x86, x64")
                .takes_value(true)))
        .subcommand(SubCommand::with_name("switch")
            .about("Switch Groonga with given version and arch")
            .arg(Arg::with_name("VERSION").required(true))
            .arg(Arg::with_name("arch")
                .short("a")
                .long("arch")
                .value_name("ARCH")
                .help("Select architectures. e.g.) x86, x64")
                .takes_value(true)))
        .subcommand(SubCommand::with_name("versions").about("Display installed Groonga versions"))
        .subcommand(SubCommand::with_name("uninstall")
            .about("Uninstall a given Groonga version and arch")
            .arg(Arg::with_name("VERSION").required(true))
            .arg(Arg::with_name("arch")
                .short("a")
                .long("arch")
                .value_name("ARCH")
                .help("Select architectures. e.g.) x86, x64")
                .takes_value(true)))
        .subcommand(SubCommand::with_name("list").about("Display installable Groonga versions"))

}

#[cfg(not(windows))]
fn default_main() {
    let mut app = cli();
    let matches = app.clone().get_matches();
    match matches.subcommand() {
        ("init", _) => command::unix::init(),
        ("install", Some(m)) => command::unix::install(m),
        ("switch", Some(m)) => command::unix::switch(m),
        ("versions", _) => command::common::versions(),
        ("uninstall", Some(m)) => command::unix::uninstall(m),
        ("list", _) => command::unix::list(),
        (external, Some(ext_m)) => command::common::execute_external_command(external, ext_m),
        (_, _) => {
            let _ = app.print_help();
        },
    }
}

#[cfg(windows)]
fn default_main() {
    let mut app = cli();
    let matches = app.clone().get_matches();
    match matches.subcommand() {
        ("init", _) => command::windows::init(),
        ("install", Some(m)) => command::windows::install(m),
        ("switch", Some(m)) => command::windows::switch(m),
        ("versions", _) => command::common::versions(),
        ("uninstall", Some(m)) => command::windows::uninstall(m),
        ("list", _) => command::windows::list(),
        (external, Some(ext_m)) => command::common::execute_external_command(external, ext_m),
        (_, _) => {
            let _ = app.print_help();
        },
    }
}
<|endoftext|>