<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
    }
}
<commit_msg>Add program.execute(&mut self, &mut VM)<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                while index < self.instructions.len() {
                    let command = &self.instructions[index];
                    vm.apply(command);
                    index = index + 1;
                }
                self.instruction_pointer = Some(index);
            }
        }
    }
}
<|endoftext|>


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

use bucket::Bucket;
use chrono::{DateTime, Utc};
use command::Command;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};
use curl::easy::{Easy, List, ReadError};
use hex::ToHex;
use url::Url;
use serde_xml;

use serde_types::AwsError;
use signing;
use error::{S3Result, ErrorKind};

use EMPTY_PAYLOAD_SHA;
use LONG_DATE;

/// Collection of HTTP headers sent to S3 service, in key/value format.
pub type Headers = HashMap<String, String>;

/// Collection of HTTP query parameters sent to S3 service, in key/value
/// format.
pub type Query = HashMap<String, String>;

// Temporary structure for making a request
pub struct Request<'a> {
    pub bucket: &'a Bucket,
    pub path: &'a str,
    pub command: Command<'a>,
    pub datetime: DateTime<Utc>,
}

impl<'a> Request<'a> {
    pub fn new<'b>(bucket: &'b Bucket, path: &'b str, command: Command<'b>) -> Request<'b> {
        Request {
            bucket,
            path,
            command,
            datetime: Utc::now(),
        }
    }

    fn url(&self) -> Url {
        let mut url_str = format!("{}://{}", self.bucket.scheme(), self.bucket.host());
        url_str.push_str("/");
        url_str.push_str(self.bucket.name());
        if !self.path.starts_with('/') {
            url_str.push_str("/");
        }
        url_str.push_str(&signing::uri_encode(self.path, false));

        // Since every part of this URL is either pre-encoded or statically
        // generated, there's really no way this should fail.
        let mut url = Url::parse(&url_str).expect("static URL parsing");

        for (key, value) in &self.bucket.extra_query {
            url.query_pairs_mut().append_pair(key, value);
        }

        if let Command::List { prefix, delimiter, continuation_token } = self.command {
            let mut query_pairs = url.query_pairs_mut();
            delimiter.map(|d| query_pairs.append_pair("delimiter", d));
            query_pairs.append_pair("prefix", prefix);
            query_pairs.append_pair("list-type", "2");
            if let Some(token) = continuation_token {
                query_pairs.append_pair("continuation-token", token);
            }
        }

        url
    }

    fn content_length(&self) -> usize {
        match self.command {
            Command::Put { content, .. } => content.len(),
            _ => 0,
        }
    }

    fn content_type(&self) -> String {
        match self.command {
            Command::Put { content_type, .. } => content_type.into(),
            _ => "text/plain".into(),
        }
    }

    fn sha256(&self) -> String {
        match self.command {
            Command::Put { content, .. } => {
                let mut sha = Sha256::default();
                sha.input(content);
                sha.result().as_slice().to_hex()
            }
            _ => EMPTY_PAYLOAD_SHA.into(),
        }
    }

    fn long_date(&self) -> String {
        self.datetime.format(LONG_DATE).to_string()
    }

    fn canonical_request(&self, headers: &Headers) -> String {
        signing::canonical_request(self.command.http_verb(),
                                   &self.url(),
                                   headers,
                                   &self.sha256())
    }

    fn string_to_sign(&self, request: &str) -> String {
        signing::string_to_sign(&self.datetime, &self.bucket.region(), request)
    }

    fn signing_key(&self) -> Vec<u8> {
        signing::signing_key(&self.datetime,
                             self.bucket.secret_key(),
                             &self.bucket.region(),
                             "s3")
    }

    fn authorization(&self, headers: &Headers) -> String {
        let canonical_request = self.canonical_request(headers);
        let string_to_sign = self.string_to_sign(&canonical_request);
        let mut hmac = Hmac::<Sha256>::new(&self.signing_key());
        hmac.input(string_to_sign.as_bytes());
        let signature = hmac.result().code().to_hex();
        let signed_header = signing::signed_header_string(headers);
        signing::authorization_header(self.bucket.access_key(),
                                      &self.datetime,
                                      &self.bucket.region(),
                                      &signed_header,
                                      &signature)
    }

    fn headers(&self) -> S3Result<Headers> {
        // Generate this once, but it's used in more than one place.
        let sha256 = self.sha256();

        // Start with extra_headers, that way our headers replace anything with
        // the same name.
        let mut headers: Headers = self.bucket.extra_headers.clone();
        headers.insert("Host".into(), self.bucket.host().into());
        headers.insert("Content-Length".into(), self.content_length().to_string());
        headers.insert("Content-Type".into(), self.content_type());
        headers.insert("X-Amz-Content-Sha256".into(), sha256.clone());
        headers.insert("X-Amz-Date".into(), self.long_date());

        self.bucket.credentials().token.as_ref().map(|token| {
            headers.insert("X-Amz-Security-Token".into(), token.clone());
        });

        // This must be last, as it signs the other headers
        let authorization = self.authorization(&headers);
        headers.insert("Authorization".into(), authorization);

        // The format of RFC2822 is somewhat malleable, so including it in
        // signed headers can cause signature mismatches. We do include the
        // X-Amz-Date header, so requests are still properly limited to a date
        // range and can't be used again e.g. reply attacks. Adding this header
        // after the generation of the Authorization header leaves it out of
        // the signed headers.
        headers.insert("Date".into(), self.datetime.to_rfc2822());

        Ok(headers)
    }

    fn load_content(&self, handle: &mut Easy) -> S3Result<Cursor<&[u8]>> {
        if let Command::Put { content, .. } = self.command {
            try!(handle.put(true));
            try!(handle.post_field_size(content.len() as u64));
            Ok(Cursor::new(content))
        } else {
            Ok(Cursor::new(&[] as &[u8]))
        }
    }

    pub fn execute(&self) -> S3Result<(Vec<u8>, u32)> {
        let mut handle = Easy::new();
        handle.url(self.url().as_str())?;

        // Special handling to load PUT content
        let mut content_cursor = try!(self.load_content(&mut handle));

        // Set GET, PUT, etc
        handle.custom_request(self.command.http_verb())?;

        // Build and set a Curl List of headers
        let mut list = List::new();
        for (key, value) in &self.headers()? {
            let header = format!("{}: {}", key, value);
            list.append(&header)?;
        }
        handle.http_headers(list)?;

        if cfg!(feature = "no-verify-ssl") {
            handle.ssl_verify_peer(false)?;
        }

        // Run the transfer
        let mut dst = Vec::new();
        {
            let mut transfer = handle.transfer();

            transfer.read_function(|buf| content_cursor.read(buf).or(Err(ReadError::Abort)))?;

            transfer.write_function(|data| {
                dst.extend_from_slice(data);
                Ok(data.len())
            })?;

            transfer.perform()?;
        }
        let resp_code = handle.response_code()?;
        if resp_code < 300 {
            Ok((dst, resp_code))
        } else {
            let deserialized: AwsError = serde_xml::deserialize(dst.as_slice())?;
            let err = ErrorKind::AwsError {
                info: deserialized,
                status: resp_code,
                body: String::from_utf8_lossy(dst.as_slice()).into_owned(),
            };
            Err(err.into())
        }
    }
}

#[cfg(test)]
mod tests {
    use bucket::Bucket;
    use command::Command;
    use credentials::Credentials;
    use request::Request;

    #[test]
    fn url_uses_https_by_default() {
        let region = "custom-region".parse().unwrap();
        let bucket = Bucket::new("my-first-bucket", region, Credentials::default());
        let path = "/my-first/path";
        let request = Request::new(&bucket, path, Command::Get);

        assert_eq!(request.url().scheme(), "https");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        assert_eq!(*host, "custom-region".to_string());
    }

    #[test]
    fn url_uses_scheme_from_custom_region_if_defined() {
        let region = "http://custom-region".parse().unwrap();
        let bucket = Bucket::new("my-second-bucket", region, Credentials::default());
        let path = "/my-second/path";
        let request = Request::new(&bucket, path, Command::Get);

        assert_eq!(request.url().scheme(), "http");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        assert_eq!(*host, "custom-region".to_string());
    }
}
<commit_msg>Make clippy happy again<commit_after>use std::collections::HashMap;
use std::io::{Read, Cursor};

use bucket::Bucket;
use chrono::{DateTime, Utc};
use command::Command;
use hmac::{Hmac, Mac};
use sha2::{Digest, Sha256};
use curl::easy::{Easy, List, ReadError};
use hex::ToHex;
use url::Url;
use serde_xml;

use serde_types::AwsError;
use signing;
use error::{S3Result, ErrorKind};

use EMPTY_PAYLOAD_SHA;
use LONG_DATE;

/// Collection of HTTP headers sent to S3 service, in key/value format.
pub type Headers = HashMap<String, String>;

/// Collection of HTTP query parameters sent to S3 service, in key/value
/// format.
pub type Query = HashMap<String, String>;

// Temporary structure for making a request
pub struct Request<'a> {
    pub bucket: &'a Bucket,
    pub path: &'a str,
    pub command: Command<'a>,
    pub datetime: DateTime<Utc>,
}

impl<'a> Request<'a> {
    pub fn new<'b>(bucket: &'b Bucket, path: &'b str, command: Command<'b>) -> Request<'b> {
        Request {
            bucket,
            path,
            command,
            datetime: Utc::now(),
        }
    }

    fn url(&self) -> Url {
        let mut url_str = format!("{}://{}", self.bucket.scheme(), self.bucket.host());
        url_str.push_str("/");
        url_str.push_str(self.bucket.name());
        if !self.path.starts_with('/') {
            url_str.push_str("/");
        }
        url_str.push_str(&signing::uri_encode(self.path, false));

        // Since every part of this URL is either pre-encoded or statically
        // generated, there's really no way this should fail.
        let mut url = Url::parse(&url_str).expect("static URL parsing");

        for (key, value) in &self.bucket.extra_query {
            url.query_pairs_mut().append_pair(key, value);
        }

        if let Command::List { prefix, delimiter, continuation_token } = self.command {
            let mut query_pairs = url.query_pairs_mut();
            delimiter.map(|d| query_pairs.append_pair("delimiter", d));
            query_pairs.append_pair("prefix", prefix);
            query_pairs.append_pair("list-type", "2");
            if let Some(token) = continuation_token {
                query_pairs.append_pair("continuation-token", token);
            }
        }

        url
    }

    fn content_length(&self) -> usize {
        match self.command {
            Command::Put { content, .. } => content.len(),
            _ => 0,
        }
    }

    fn content_type(&self) -> String {
        match self.command {
            Command::Put { content_type, .. } => content_type.into(),
            _ => "text/plain".into(),
        }
    }

    fn sha256(&self) -> String {
        match self.command {
            Command::Put { content, .. } => {
                let mut sha = Sha256::default();
                sha.input(content);
                sha.result().as_slice().to_hex()
            }
            _ => EMPTY_PAYLOAD_SHA.into(),
        }
    }

    fn long_date(&self) -> String {
        self.datetime.format(LONG_DATE).to_string()
    }

    fn canonical_request(&self, headers: &Headers) -> String {
        signing::canonical_request(self.command.http_verb(),
                                   &self.url(),
                                   headers,
                                   &self.sha256())
    }

    fn string_to_sign(&self, request: &str) -> String {
        signing::string_to_sign(&self.datetime, &self.bucket.region(), request)
    }

    fn signing_key(&self) -> Vec<u8> {
        signing::signing_key(&self.datetime,
                             self.bucket.secret_key(),
                             &self.bucket.region(),
                             "s3")
    }

    fn authorization(&self, headers: &Headers) -> String {
        let canonical_request = self.canonical_request(headers);
        let string_to_sign = self.string_to_sign(&canonical_request);
        let mut hmac = Hmac::<Sha256>::new(&self.signing_key());
        hmac.input(string_to_sign.as_bytes());
        let signature = hmac.result().code().to_hex();
        let signed_header = signing::signed_header_string(headers);
        signing::authorization_header(self.bucket.access_key(),
                                      &self.datetime,
                                      &self.bucket.region(),
                                      &signed_header,
                                      &signature)
    }

    fn headers(&self) -> S3Result<Headers> {
        // Generate this once, but it's used in more than one place.
        let sha256 = self.sha256();

        // Start with extra_headers, that way our headers replace anything with
        // the same name.
        let mut headers: Headers = self.bucket.extra_headers.clone();
        headers.insert("Host".into(), self.bucket.host().into());
        headers.insert("Content-Length".into(), self.content_length().to_string());
        headers.insert("Content-Type".into(), self.content_type());
        headers.insert("X-Amz-Content-Sha256".into(), sha256.clone());
        headers.insert("X-Amz-Date".into(), self.long_date());

        if let Some(token) = self.bucket.credentials().token.as_ref() {
            headers.insert("X-Amz-Security-Token".into(), token.clone());
        }

        // This must be last, as it signs the other headers
        let authorization = self.authorization(&headers);
        headers.insert("Authorization".into(), authorization);

        // The format of RFC2822 is somewhat malleable, so including it in
        // signed headers can cause signature mismatches. We do include the
        // X-Amz-Date header, so requests are still properly limited to a date
        // range and can't be used again e.g. reply attacks. Adding this header
        // after the generation of the Authorization header leaves it out of
        // the signed headers.
        headers.insert("Date".into(), self.datetime.to_rfc2822());

        Ok(headers)
    }

    fn load_content(&self, handle: &mut Easy) -> S3Result<Cursor<&[u8]>> {
        if let Command::Put { content, .. } = self.command {
            try!(handle.put(true));
            try!(handle.post_field_size(content.len() as u64));
            Ok(Cursor::new(content))
        } else {
            Ok(Cursor::new(&[] as &[u8]))
        }
    }

    pub fn execute(&self) -> S3Result<(Vec<u8>, u32)> {
        let mut handle = Easy::new();
        handle.url(self.url().as_str())?;

        // Special handling to load PUT content
        let mut content_cursor = try!(self.load_content(&mut handle));

        // Set GET, PUT, etc
        handle.custom_request(self.command.http_verb())?;

        // Build and set a Curl List of headers
        let mut list = List::new();
        for (key, value) in &self.headers()? {
            let header = format!("{}: {}", key, value);
            list.append(&header)?;
        }
        handle.http_headers(list)?;

        if cfg!(feature = "no-verify-ssl") {
            handle.ssl_verify_peer(false)?;
        }

        // Run the transfer
        let mut dst = Vec::new();
        {
            let mut transfer = handle.transfer();

            transfer.read_function(|buf| content_cursor.read(buf).or(Err(ReadError::Abort)))?;

            transfer.write_function(|data| {
                dst.extend_from_slice(data);
                Ok(data.len())
            })?;

            transfer.perform()?;
        }
        let resp_code = handle.response_code()?;
        if resp_code < 300 {
            Ok((dst, resp_code))
        } else {
            let deserialized: AwsError = serde_xml::deserialize(dst.as_slice())?;
            let err = ErrorKind::AwsError {
                info: deserialized,
                status: resp_code,
                body: String::from_utf8_lossy(dst.as_slice()).into_owned(),
            };
            Err(err.into())
        }
    }
}

#[cfg(test)]
mod tests {
    use bucket::Bucket;
    use command::Command;
    use credentials::Credentials;
    use request::Request;

    #[test]
    fn url_uses_https_by_default() {
        let region = "custom-region".parse().unwrap();
        let bucket = Bucket::new("my-first-bucket", region, Credentials::default());
        let path = "/my-first/path";
        let request = Request::new(&bucket, path, Command::Get);

        assert_eq!(request.url().scheme(), "https");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        assert_eq!(*host, "custom-region".to_string());
    }

    #[test]
    fn url_uses_scheme_from_custom_region_if_defined() {
        let region = "http://custom-region".parse().unwrap();
        let bucket = Bucket::new("my-second-bucket", region, Credentials::default());
        let path = "/my-second/path";
        let request = Request::new(&bucket, path, Command::Get);

        assert_eq!(request.url().scheme(), "http");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        assert_eq!(*host, "custom-region".to_string());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std;
use std::collections::HashMap;
use serde_json;
use serde::de::DeserializeOwned;

/// This enum represents the various types of HTTP requests.
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub enum Method {
    Get,
    Put,
    Post,
    Delete,
    NoImpl,
}

/// This enum represents the errors that might be encountered.
#[derive(Debug)]
pub enum RequestError {
    JsonStrError(serde_json::Error),
    StrCopyError(std::string::FromUtf8Error),
}

impl From<serde_json::Error> for RequestError {
    fn from(err: serde_json::Error) -> RequestError {
        RequestError::JsonStrError(err)
    }
}

impl From<std::string::FromUtf8Error> for RequestError {
    fn from(err: std::string::FromUtf8Error) -> RequestError {
        RequestError::StrCopyError(err)
    }
}

impl std::fmt::Display for RequestError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            RequestError::JsonStrError(err) => write!(f, "JSON error: {}", err),
            RequestError::StrCopyError(err) => write!(f, "UTF-8 error: {}", err),
        }
    }
}

impl std::error::Error for RequestError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            RequestError::JsonStrError(err) => Some(err),
            RequestError::StrCopyError(err) => Some(err),
        }
    }
}

/// A trait that allows for extracting variables from URIs.
pub trait FromUri {
    /// A function to parse a string into the correct type.
    fn from_uri(data: &str) -> Self;
}

impl FromUri for String {
    fn from_uri(data: &str) -> String {
        String::from(data)
    }
}

impl FromUri for i32 {
    fn from_uri(data: &str) -> i32 {
        data.parse::<i32>().expect("matched integer can't be parsed")
    }
}

impl FromUri for u32 {
    fn from_uri(data: &str) -> u32 {
        data.parse::<u32>().expect("matched integer can't be parsed")
    }
}

impl FromUri for f32 {
    fn from_uri(data: &str) -> f32 {
        data.parse::<f32>().expect("matched float can't be parsed")
    }
}

/// This struct represents a request from an HTTP client.
#[derive(Debug)]
pub struct Request {
    pub method:  Method,
    pub path:    String,
    pub payload: Vec<u8>,
    pub params:  HashMap<String, String>,
    headers:     HashMap<String, String>,
}

impl Request {
    /// Create a new, empty Request.
    pub fn new() -> Request {
        Request {
            method:  Method::NoImpl,
            path:    String::new(),
            headers: HashMap::new(),
            params:  HashMap::new(),
            payload: Vec::with_capacity(2048),
        }
    }

    /// Get an HTTP header contained in the Request.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Request, Response};
    /// use canteen::utils;
    ///
    /// // Given the route "/hello"
    /// fn handler(req: &Request) -> Response {
    ///     let browser = req.get_header("User-Agent");
    ///
    ///     match browser {
    ///         Some(ua) => utils::make_response(format!("You're using {}!", ua), "text/plain", 200),
    ///         None     => utils::make_response("Bad browser, no user agent!", "text/plain", 200),
    ///     }
    /// }
    /// ```
    pub fn get_header(&self, name: &str) -> Option<String> {
        let key = String::from(name.to_lowercase());

        match self.headers.get(&key) {
            Some(val)   => Some(val.clone()),
            None        => None,
        }
    }

    /// Get a variable from the URI.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Request, Response};
    /// use canteen::utils;
    ///
    /// // Given the route "/hello/<str:name>"
    /// fn handler(req: &Request) -> Response {
    ///     let name: String = req.get("name");
    ///     utils::make_response(format!("<b>Hello, {}!</b>", name), "text/html", 200)
    /// }
    /// ```
    pub fn get<T: FromUri>(&self, name: &str) -> T {
        if !self.params.contains_key(name) {
            panic!("invalid route parameter {:?}", name);
        }

        FromUri::from_uri(&self.params[name])
    }

    /// Get a raw JSON payload from the request.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Request, Response};
    /// use canteen::utils;
    ///
    /// // Given the POST route "/hello"
    /// fn handler(req: &Request) -> Response {
    ///     let data = req.get_json();
    ///
    ///     match data {
    ///         Ok(val) => utils::make_response(format!("We got: {}", val), "text/plain", 200),
    ///         Err(_)  => utils::make_response("We got nothing :(", "text/plain", 200),
    ///     }
    /// }
    /// ```
    pub fn get_json(&self) -> Result<serde_json::Value, RequestError> {
        let payload = String::from_utf8(self.payload.clone())?;
        let data = serde_json::from_str(&payload)?;

        Ok(data)
    }

    /// Get a composed JSON payload from the request.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use canteen::{Request, Response};
    ///
    /// #[derive(RustcDecodable)]
    /// struct Foo {
    ///     item: i32,
    /// }
    ///
    /// // Given the POST route "/hello"
    /// fn handler(req: &Request) -> Response {
    ///     let data: Foo = req.get_json_obj();
    ///
    ///     match data {
    ///         Ok(foo) => utils::make_response(format!("We got: {}!", data.item), "text/plain", 200),
    ///         Err(_)  => utils::make_response("We got nothing :(", "text/plain", 200),
    ///     }
    /// }
    /// ```
    pub fn get_json_obj<T>(&self) -> Result<T, RequestError>
                where T: DeserializeOwned {
        let payload = String::from_utf8(self.payload.clone())?;
        let data = serde_json::from_str(&payload)?;

        Ok(data)
    }

    fn parse(&mut self, rqstr: &str) {
        let mut buf: Vec<&str> = rqstr.splitn(2, "\r\n").collect();
        let ask: Vec<&str> = buf[0].splitn(3, ' ').collect();

        self.method = match ask[0] {
            "GET"           => Method::Get,
            "PUT" | "PATCH" => Method::Put,
            "POST"          => Method::Post,
            "DELETE"        => Method::Delete,
            _               => Method::NoImpl,
        };
        self.path = String::from(ask[1]);

        loop {
            buf = buf[1].splitn(2, "\r\n").collect();

            if buf[0] == "" {
                if buf.len() == 1 || buf[1] == "" {
                    // no payload
                    break;
                }

                self.payload.extend(buf[1].as_bytes());
                break;
            }

            let hdr: Vec<&str> = buf[0].splitn(2, ": ").collect();

            if hdr.len() == 2 {
                self.headers.insert(String::from(hdr[0].to_lowercase()), String::from(hdr[1]));
            }
        }
    }
}

impl Default for Request {
    fn default() -> Self {
        Self::new()
    }
}

impl std::str::FromStr for Request {
    type Err = RequestError;

    /// Create a Request from an HTTP request string.
    fn from_str(rqstr: &str) -> Result<Self, Self::Err> {
        let mut req = Request::new();
        req.parse(rqstr);
        Ok(req)
    }
}

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

    #[derive(Deserialize)]
    struct Foo {
        item: i32,
    }

    #[test]
    fn test_fromuri_trait_i32() {
        let pos = String::from("1234");
        assert_eq!(1234, <i32 as FromUri>::from_uri(&pos));

        let neg = String::from("-4321");
        assert_eq!(-4321, <i32 as FromUri>::from_uri(&neg));
    }

    #[test]
    fn test_fromuri_trait_u32() {
        let orig = String::from("1234");
        assert_eq!(1234, <u32 as FromUri>::from_uri(&orig));
    }

    #[test]
    fn test_fromuri_trait_string() {
        let orig = String::from("foobar");
        assert_eq!("foobar", <String as FromUri>::from_uri(&orig));
    }

    #[test]
    fn test_fromuri_trait_float() {
        let pos = String::from("123.45");
        assert_eq!(123.45f32, <f32 as FromUri>::from_uri(&pos));

        let neg = String::from("-54.321");
        assert_eq!(-54.321f32, <f32 as FromUri>::from_uri(&neg));
    }

    #[test]
    fn test_get_fromuri_i32() {
        let mut req = Request::new();
        req.params.insert(String::from("test"), String::from("1234"));
        let val: i32 = req.get("test");

        assert_eq!(1234, val);
    }

    #[test]
    fn test_get_json() {
        let mut req = Request::new();
        req.payload.extend_from_slice("{ \"item\": 123 }".as_bytes());

        let data = req.get_json().unwrap();

        assert_eq!(true, data.is_object());

        let obj = data.as_object().unwrap();
        let val = obj.get("item").unwrap();

        assert_eq!(true, val.is_u64());
        assert_eq!(123u64, val.as_u64().unwrap());
    }

    #[test]
    fn test_get_json_obj() {
        let mut req = Request::new();
        req.payload.extend_from_slice("{ \"item\": 123 }".as_bytes());

        let data: Foo = req.get_json_obj().unwrap();

        assert_eq!(123, data.item);
    }
}
<commit_msg>Add `OPTIONS` as a valid HTTP verb<commit_after>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std;
use std::collections::HashMap;
use serde_json;
use serde::de::DeserializeOwned;

/// This enum represents the various types of HTTP requests.
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub enum Method {
    Get,
    Put,
    Post,
    Delete,
    Options,
    NoImpl,
}

/// This enum represents the errors that might be encountered.
#[derive(Debug)]
pub enum RequestError {
    JsonStrError(serde_json::Error),
    StrCopyError(std::string::FromUtf8Error),
}

impl From<serde_json::Error> for RequestError {
    fn from(err: serde_json::Error) -> RequestError {
        RequestError::JsonStrError(err)
    }
}

impl From<std::string::FromUtf8Error> for RequestError {
    fn from(err: std::string::FromUtf8Error) -> RequestError {
        RequestError::StrCopyError(err)
    }
}

impl std::fmt::Display for RequestError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            RequestError::JsonStrError(err) => write!(f, "JSON error: {}", err),
            RequestError::StrCopyError(err) => write!(f, "UTF-8 error: {}", err),
        }
    }
}

impl std::error::Error for RequestError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            RequestError::JsonStrError(err) => Some(err),
            RequestError::StrCopyError(err) => Some(err),
        }
    }
}

/// A trait that allows for extracting variables from URIs.
pub trait FromUri {
    /// A function to parse a string into the correct type.
    fn from_uri(data: &str) -> Self;
}

impl FromUri for String {
    fn from_uri(data: &str) -> String {
        String::from(data)
    }
}

impl FromUri for i32 {
    fn from_uri(data: &str) -> i32 {
        data.parse::<i32>().expect("matched integer can't be parsed")
    }
}

impl FromUri for u32 {
    fn from_uri(data: &str) -> u32 {
        data.parse::<u32>().expect("matched integer can't be parsed")
    }
}

impl FromUri for f32 {
    fn from_uri(data: &str) -> f32 {
        data.parse::<f32>().expect("matched float can't be parsed")
    }
}

/// This struct represents a request from an HTTP client.
#[derive(Debug)]
pub struct Request {
    pub method:  Method,
    pub path:    String,
    pub payload: Vec<u8>,
    pub params:  HashMap<String, String>,
    headers:     HashMap<String, String>,
}

impl Request {
    /// Create a new, empty Request.
    pub fn new() -> Request {
        Request {
            method:  Method::NoImpl,
            path:    String::new(),
            headers: HashMap::new(),
            params:  HashMap::new(),
            payload: Vec::with_capacity(2048),
        }
    }

    /// Get an HTTP header contained in the Request.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Request, Response};
    /// use canteen::utils;
    ///
    /// // Given the route "/hello"
    /// fn handler(req: &Request) -> Response {
    ///     let browser = req.get_header("User-Agent");
    ///
    ///     match browser {
    ///         Some(ua) => utils::make_response(format!("You're using {}!", ua), "text/plain", 200),
    ///         None     => utils::make_response("Bad browser, no user agent!", "text/plain", 200),
    ///     }
    /// }
    /// ```
    pub fn get_header(&self, name: &str) -> Option<String> {
        let key = String::from(name.to_lowercase());

        match self.headers.get(&key) {
            Some(val)   => Some(val.clone()),
            None        => None,
        }
    }

    /// Get a variable from the URI.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Request, Response};
    /// use canteen::utils;
    ///
    /// // Given the route "/hello/<str:name>"
    /// fn handler(req: &Request) -> Response {
    ///     let name: String = req.get("name");
    ///     utils::make_response(format!("<b>Hello, {}!</b>", name), "text/html", 200)
    /// }
    /// ```
    pub fn get<T: FromUri>(&self, name: &str) -> T {
        if !self.params.contains_key(name) {
            panic!("invalid route parameter {:?}", name);
        }

        FromUri::from_uri(&self.params[name])
    }

    /// Get a raw JSON payload from the request.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Request, Response};
    /// use canteen::utils;
    ///
    /// // Given the POST route "/hello"
    /// fn handler(req: &Request) -> Response {
    ///     let data = req.get_json();
    ///
    ///     match data {
    ///         Ok(val) => utils::make_response(format!("We got: {}", val), "text/plain", 200),
    ///         Err(_)  => utils::make_response("We got nothing :(", "text/plain", 200),
    ///     }
    /// }
    /// ```
    pub fn get_json(&self) -> Result<serde_json::Value, RequestError> {
        let payload = String::from_utf8(self.payload.clone())?;
        let data = serde_json::from_str(&payload)?;

        Ok(data)
    }

    /// Get a composed JSON payload from the request.
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// use canteen::{Request, Response};
    ///
    /// #[derive(RustcDecodable)]
    /// struct Foo {
    ///     item: i32,
    /// }
    ///
    /// // Given the POST route "/hello"
    /// fn handler(req: &Request) -> Response {
    ///     let data: Foo = req.get_json_obj();
    ///
    ///     match data {
    ///         Ok(foo) => utils::make_response(format!("We got: {}!", data.item), "text/plain", 200),
    ///         Err(_)  => utils::make_response("We got nothing :(", "text/plain", 200),
    ///     }
    /// }
    /// ```
    pub fn get_json_obj<T>(&self) -> Result<T, RequestError>
                where T: DeserializeOwned {
        let payload = String::from_utf8(self.payload.clone())?;
        let data = serde_json::from_str(&payload)?;

        Ok(data)
    }

    fn parse(&mut self, rqstr: &str) {
        let mut buf: Vec<&str> = rqstr.splitn(2, "\r\n").collect();
        let ask: Vec<&str> = buf[0].splitn(3, ' ').collect();

        self.method = match ask[0] {
            "GET"           => Method::Get,
            "PUT" | "PATCH" => Method::Put,
            "POST"          => Method::Post,
            "DELETE"        => Method::Delete,
            "OPTIONS"       => Method::Options,
            _               => Method::NoImpl,
        };
        self.path = String::from(ask[1]);

        loop {
            buf = buf[1].splitn(2, "\r\n").collect();

            if buf[0] == "" {
                if buf.len() == 1 || buf[1] == "" {
                    // no payload
                    break;
                }

                self.payload.extend(buf[1].as_bytes());
                break;
            }

            let hdr: Vec<&str> = buf[0].splitn(2, ": ").collect();

            if hdr.len() == 2 {
                self.headers.insert(String::from(hdr[0].to_lowercase()), String::from(hdr[1]));
            }
        }
    }
}

impl Default for Request {
    fn default() -> Self {
        Self::new()
    }
}

impl std::str::FromStr for Request {
    type Err = RequestError;

    /// Create a Request from an HTTP request string.
    fn from_str(rqstr: &str) -> Result<Self, Self::Err> {
        let mut req = Request::new();
        req.parse(rqstr);
        Ok(req)
    }
}

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

    #[derive(Deserialize)]
    struct Foo {
        item: i32,
    }

    #[test]
    fn test_fromuri_trait_i32() {
        let pos = String::from("1234");
        assert_eq!(1234, <i32 as FromUri>::from_uri(&pos));

        let neg = String::from("-4321");
        assert_eq!(-4321, <i32 as FromUri>::from_uri(&neg));
    }

    #[test]
    fn test_fromuri_trait_u32() {
        let orig = String::from("1234");
        assert_eq!(1234, <u32 as FromUri>::from_uri(&orig));
    }

    #[test]
    fn test_fromuri_trait_string() {
        let orig = String::from("foobar");
        assert_eq!("foobar", <String as FromUri>::from_uri(&orig));
    }

    #[test]
    fn test_fromuri_trait_float() {
        let pos = String::from("123.45");
        assert_eq!(123.45f32, <f32 as FromUri>::from_uri(&pos));

        let neg = String::from("-54.321");
        assert_eq!(-54.321f32, <f32 as FromUri>::from_uri(&neg));
    }

    #[test]
    fn test_get_fromuri_i32() {
        let mut req = Request::new();
        req.params.insert(String::from("test"), String::from("1234"));
        let val: i32 = req.get("test");

        assert_eq!(1234, val);
    }

    #[test]
    fn test_get_json() {
        let mut req = Request::new();
        req.payload.extend_from_slice("{ \"item\": 123 }".as_bytes());

        let data = req.get_json().unwrap();

        assert_eq!(true, data.is_object());

        let obj = data.as_object().unwrap();
        let val = obj.get("item").unwrap();

        assert_eq!(true, val.is_u64());
        assert_eq!(123u64, val.as_u64().unwrap());
    }

    #[test]
    fn test_get_json_obj() {
        let mut req = Request::new();
        req.payload.extend_from_slice("{ \"item\": 123 }".as_bytes());

        let data: Foo = req.get_json_obj().unwrap();

        assert_eq!(123, data.item);
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate "termbox-sys" as termbox;

use termbox::RawEvent;
use libc::{c_int, c_uint};

#[deriving(Copy)]
pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

#[deriving(Copy)]
pub enum Color {
    Default,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White
}

#[deriving(Copy)]
pub enum Style {
    Normal,
    Bold,
    Underline,
    BoldUnderline,
    Reverse
}

fn nil_raw_event() -> RawEvent {
    RawEvent{etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0}
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> Event {
    match ev_type {
        0 => Event::NoEvent,
        1 => {
            return Event::KeyEvent(ev.emod, ev.key, ev.ch);
        },
        2 => {
            return Event::ResizeEvent(ev.w, ev.h);
        },
        _ => { panic!("Unknown event"); }
    }
}

pub fn convert_color(c: Color) -> u16 {
    match c {
        Color::Default => 0x00,
        Color::Black   => 0x01,
        Color::Red     => 0x02,
        Color::Green   => 0x03,
        Color::Yellow  => 0x04,
        Color::Blue    => 0x05,
        Color::Magenta => 0x06,
        Color::Cyan    => 0x07,
        Color::White   => 0x08,
    }
}

pub fn convert_style(sty: Style) -> u16 {
    match sty {
        Style::Normal         => 0x0000,
        Style::Bold           => 0x0100,
        Style::Underline      => 0x0200,
        Style::BoldUnderline  => 0x0300,
        Style::Reverse        => 0x0400,
    }
}

pub fn init() -> int {
    unsafe {
        termbox::tb_init() as int
    }
}

pub fn shutdown() {
    unsafe { termbox::tb_shutdown() }
}

pub fn width() -> uint {
    unsafe { termbox::tb_width() as uint }
}

pub fn height() -> uint {
    unsafe { termbox::tb_height() as uint }
}

pub fn clear() {
    unsafe { termbox::tb_clear() }
}

pub fn present() {
    unsafe { termbox::tb_present() }
}

pub fn set_cursor(x: int, y: int) {
    unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
}

pub fn change_cell(x: uint, y: uint, ch: u32, fg: u16, bg: u16) {
    unsafe {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }
}

pub fn print(x: uint, y: uint, sty: Style, fg: Color, bg: Color, s: &str) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    for (i, ch) in s.chars().enumerate() {
        change_cell(x+i, y, ch as u32, fg, bg);
    }
}

pub fn print_char(x: uint, y: uint, sty: Style, fg: Color, bg: Color, ch: char) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    change_cell(x, y, ch as u32, fg, bg);
}

pub fn poll_event() -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_poll_event(&ev as *const RawEvent);
        return unpack_event(rc, &ev);
    }
}

pub fn peek_event(timeout: uint) -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_peek_event(&ev as *const RawEvent, timeout as c_uint);
        return unpack_event(rc, &ev);
    }
}
<commit_msg>Remove unneeded `return`s.<commit_after>extern crate libc;
extern crate "termbox-sys" as termbox;

use termbox::RawEvent;
use libc::{c_int, c_uint};

#[deriving(Copy)]
pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

#[deriving(Copy)]
pub enum Color {
    Default,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White
}

#[deriving(Copy)]
pub enum Style {
    Normal,
    Bold,
    Underline,
    BoldUnderline,
    Reverse
}

fn nil_raw_event() -> RawEvent {
    RawEvent{etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0}
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> Event {
    match ev_type {
        0 => Event::NoEvent,
        1 => Event::KeyEvent(ev.emod, ev.key, ev.ch),
        2 => Event::ResizeEvent(ev.w, ev.h),
        _ => panic!("Unknown event")
    }
}

pub fn convert_color(c: Color) -> u16 {
    match c {
        Color::Default => 0x00,
        Color::Black   => 0x01,
        Color::Red     => 0x02,
        Color::Green   => 0x03,
        Color::Yellow  => 0x04,
        Color::Blue    => 0x05,
        Color::Magenta => 0x06,
        Color::Cyan    => 0x07,
        Color::White   => 0x08,
    }
}

pub fn convert_style(sty: Style) -> u16 {
    match sty {
        Style::Normal         => 0x0000,
        Style::Bold           => 0x0100,
        Style::Underline      => 0x0200,
        Style::BoldUnderline  => 0x0300,
        Style::Reverse        => 0x0400,
    }
}

pub fn init() -> int {
    unsafe {
        termbox::tb_init() as int
    }
}

pub fn shutdown() {
    unsafe { termbox::tb_shutdown() }
}

pub fn width() -> uint {
    unsafe { termbox::tb_width() as uint }
}

pub fn height() -> uint {
    unsafe { termbox::tb_height() as uint }
}

pub fn clear() {
    unsafe { termbox::tb_clear() }
}

pub fn present() {
    unsafe { termbox::tb_present() }
}

pub fn set_cursor(x: int, y: int) {
    unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
}

pub fn change_cell(x: uint, y: uint, ch: u32, fg: u16, bg: u16) {
    unsafe {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }
}

pub fn print(x: uint, y: uint, sty: Style, fg: Color, bg: Color, s: &str) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    for (i, ch) in s.chars().enumerate() {
        change_cell(x+i, y, ch as u32, fg, bg);
    }
}

pub fn print_char(x: uint, y: uint, sty: Style, fg: Color, bg: Color, ch: char) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    change_cell(x, y, ch as u32, fg, bg);
}

pub fn poll_event() -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_poll_event(&ev as *const RawEvent);
        unpack_event(rc, &ev)
    }
}

pub fn peek_event(timeout: uint) -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_peek_event(&ev as *const RawEvent, timeout as c_uint);
        unpack_event(rc, &ev)
    }
}
<|endoftext|>


<commit_before>//! Module defining all sensor related structures.

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use optional::Optional;

//--- Templates ---//

/// A trait for all possible sensor templates.
/// the `SensorTemplate`s are capable of registering themselves in a `Sensors` struct
pub trait SensorTemplate : Send+Sync {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors);
}

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensorTemplate {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

impl SensorTemplate for PeopleNowPresentSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        if value_str.parse::<i64>().map(|value|{
            let sensor = PeopleNowPresentSensor {
                location: self.location.clone(),
                name: self.name.clone(),
                names: self.names.clone(),
                description: self.description.clone(),
                value: value,
            };

            match sensors.people_now_present {
                Optional::Value(ref mut vec_sensors) => {
                    vec_sensors.push(sensor)
                }
                Optional::Absent => {
                    sensors.people_now_present = Optional::Value(vec![sensor])
                }
            }
        }).is_err() {
            warn!("Could not parse '{}': omiting the sensor", value_str);
        }
    }
}

#[derive(Debug, Clone)]
pub struct TemperatureSensorTemplate {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

impl SensorTemplate for TemperatureSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        if value_str.parse::<f64>().map(|value|{
            let sensor = TemperatureSensor {
                unit: self.unit.clone(),
                location: self.location.clone(),
                name: self.name.clone(),
                description: self.description.clone(),
                value: value,
            };
            match sensors.temperature {
                Optional::Value(ref mut vec_sensors) => {
                    vec_sensors.push(sensor)
                }
                Optional::Absent => {
                    sensors.temperature = Optional::Value(vec![sensor])
                }
            }
        }).is_err() {
            warn!("Could not parse '{}': omiting the sensor", value_str);
        }
    }
}

//--- Structures ---//

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensor {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
    pub value: i64,
}

#[derive(Debug, Clone)]
pub struct TemperatureSensor {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
    pub value: f64,
}

#[derive(Debug, Clone)]
pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

//--- Serialization ---//

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.people_now_present.as_ref().map_or((), |v| { d.insert("people_now_present".to_string(), v.to_json()); });
        self.temperature.as_ref().map_or((), |v| { d.insert("temperature".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        self.location.as_ref().map_or((), |v| { d.insert("location".to_string(), v.to_json()); });
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.names.as_ref().map_or((), |v| { d.insert("names".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}
<commit_msg>Better logging and error handling<commit_after>//! Module defining all sensor related structures.

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use optional::Optional;

//--- Templates ---//

/// A trait for all possible sensor templates.
/// the `SensorTemplate`s are capable of registering themselves in a `Sensors` struct
pub trait SensorTemplate : Send+Sync {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors);
}

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensorTemplate {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
}

impl SensorTemplate for PeopleNowPresentSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        if value_str.parse::<i64>().map(|value|{
            let sensor = PeopleNowPresentSensor {
                location: self.location.clone(),
                name: self.name.clone(),
                names: self.names.clone(),
                description: self.description.clone(),
                value: value,
            };

            match sensors.people_now_present {
                Optional::Value(ref mut vec_sensors) => {
                    vec_sensors.push(sensor)
                }
                Optional::Absent => {
                    sensors.people_now_present = Optional::Value(vec![sensor])
                }
            }
        }).is_err() {
            warn!("Could not parse value '{}', omiting PeopleNowPresentSensor", value_str);
        }
    }
}

#[derive(Debug, Clone)]
pub struct TemperatureSensorTemplate {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
}

impl SensorTemplate for TemperatureSensorTemplate {
    fn to_sensor(&self, value_str: &str, sensors: &mut Sensors) {
        if value_str.parse::<f64>().map(|value|{
            let sensor = TemperatureSensor {
                unit: self.unit.clone(),
                location: self.location.clone(),
                name: self.name.clone(),
                description: self.description.clone(),
                value: value,
            };
            match sensors.temperature {
                Optional::Value(ref mut vec_sensors) => {
                    vec_sensors.push(sensor)
                }
                Optional::Absent => {
                    sensors.temperature = Optional::Value(vec![sensor])
                }
            }
        }).is_err() {
            warn!("Could not parse value '{}', omiting TemperatureSensor", value_str);
        }
    }
}

//--- Structures ---//

#[derive(Debug, Clone)]
pub struct PeopleNowPresentSensor {
    pub location: Optional<String>,
    pub name: Optional<String>,
    pub names: Optional<Vec<String>>,
    pub description: Optional<String>,
    pub value: i64,
}

#[derive(Debug, Clone)]
pub struct TemperatureSensor {
    pub unit: String,
    pub location: String,
    pub name: Optional<String>,
    pub description: Optional<String>,
    pub value: f64,
}

#[derive(Debug, Clone)]
pub struct Sensors {
    pub people_now_present: Optional<Vec<PeopleNowPresentSensor>>,
    pub temperature: Optional<Vec<TemperatureSensor>>,
}

//--- Serialization ---//

impl ToJson for Sensors {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        self.people_now_present.as_ref().map_or((), |v| { d.insert("people_now_present".to_string(), v.to_json()); });
        self.temperature.as_ref().map_or((), |v| { d.insert("temperature".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for PeopleNowPresentSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        self.location.as_ref().map_or((), |v| { d.insert("location".to_string(), v.to_json()); });
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.names.as_ref().map_or((), |v| { d.insert("names".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}

impl ToJson for TemperatureSensor {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("value".to_string(), self.value.to_json());
        d.insert("unit".to_string(), self.unit.to_json());
        d.insert("location".to_string(), self.location.to_json());
        self.name.as_ref().map_or((), |v| { d.insert("name".to_string(), v.to_json()); });
        self.description.as_ref().map_or((), |v| { d.insert("description".to_string(), v.to_json()); });
        Json::Object(d)
    }
}
<|endoftext|>


<commit_before>use std::any::{AnyRefExt, AnyMutRefExt};
use std::collections::HashMap;
use std::fmt::Show;
use std::str;
use serialize::base64::{FromBase64, ToBase64, STANDARD};

use conduit::{Request, Response};
use conduit_middleware;
use cookie::Cookie;

use super::RequestCookies;

pub struct SessionMiddleware {
    cookie_name: String,
}

impl SessionMiddleware {
    pub fn new(cookie: &str) -> SessionMiddleware {
        SessionMiddleware { cookie_name: cookie.to_string() }
    }

    pub fn decode(&self, cookie: Cookie) -> HashMap<String, String> {
        let mut ret = HashMap::new();
        let bytes = cookie.value.as_slice().from_base64().unwrap_or(Vec::new());
        let mut parts = bytes.as_slice().split(|&a| a == 0xff);
        loop {
            match (parts.next(), parts.next()) {
                (Some(key), Some(value)) => {
                    match (str::from_utf8(key), str::from_utf8(value)) {
                        (Some(key), Some(value)) => {
                            ret.insert(key.to_string(), value.to_string());
                        }
                        _ => {}
                    }
                }
                _ => break
            }
        }
        return ret;
    }

    pub fn encode(&self, h: &HashMap<String, String>) -> String {
        let mut ret = Vec::new();
        for (i, (k, v)) in h.iter().enumerate() {
            if i != 0 { ret.push(0xff) }
            ret.push_all(k.as_bytes());
            ret.push(0xff);
            ret.push_all(v.as_bytes());
        }
        ret.as_slice().to_base64(STANDARD)
    }
}

impl conduit_middleware::Middleware for SessionMiddleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show>> {
        let session = {
            let jar = req.cookies();
            jar.find(self.cookie_name.as_slice()).map(|cookie| {
                self.decode(cookie)
            }).unwrap_or_else(|| HashMap::new())
        };
        req.mut_extensions().insert("conduit.cookie.session", box session);
        Ok(())
    }

    fn after(&self, req: &mut Request, res: Result<Response, Box<Show>>)
        -> Result<Response, Box<Show>>
    {
        let session = req.mut_extensions().pop(&"conduit.cookie.session");
        let session = session.expect("session must be present after request");
        let session = session.as_ref::<HashMap<String, String>>().unwrap();
        let encoded = self.encode(session);
        req.cookies().add(Cookie::new(self.cookie_name.to_string(), encoded));
        return res;
    }
}

pub trait RequestSession<'a> {
    fn session(self) -> &'a mut HashMap<String, String>;
}

impl<'a> RequestSession<'a> for &'a mut Request {
    fn session(self) -> &'a mut HashMap<String, String> {
        self.mut_extensions().find_mut(&"conduit.cookie.session")
            .and_then(|a| a.as_mut::<HashMap<String, String>>())
            .expect("missing cookie session")
    }
}

#[cfg(test)]
mod test {

    use conduit::{Request, Response, Handler, Post};
    use conduit_middleware::MiddlewareBuilder;
    use test::MockRequest;
    use std::collections::HashMap;
    use std::io::MemReader;

    use {RequestSession, Middleware, SessionMiddleware};

    #[test]
    fn simple() {
        let mut req = MockRequest::new(Post, "/articles");

        // Set the session cookie
        let mut app = MiddlewareBuilder::new(set_session);
        app.add(Middleware::new(b"foo"));
        app.add(SessionMiddleware::new("lol"));
        let response = app.call(&mut req).ok().unwrap();

        let v = response.headers.get(&"Set-Cookie".to_string());
        assert!(v.as_slice()[0].as_slice().starts_with("lol"));

        // Use the session cookie
        req.header("Cookie", v.as_slice()[0].as_slice());
        let mut app = MiddlewareBuilder::new(use_session);
        app.add(Middleware::new(b"foo"));
        app.add(SessionMiddleware::new("lol"));
        assert!(app.call(&mut req).is_ok());

        fn set_session(req: &mut Request) -> Result<Response, String> {
            assert!(req.session().insert("foo".to_string(), "bar".to_string()));
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
        fn use_session(req: &mut Request) -> Result<Response, String> {
            assert_eq!(req.session().find_equiv(&"foo").unwrap().as_slice(),
                       "bar");
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
    }
}
<commit_msg>Put session in a signed cookie<commit_after>use std::any::{AnyRefExt, AnyMutRefExt};
use std::collections::HashMap;
use std::fmt::Show;
use std::str;
use serialize::base64::{FromBase64, ToBase64, STANDARD};

use conduit::{Request, Response};
use conduit_middleware;
use cookie::Cookie;

use super::RequestCookies;

pub struct SessionMiddleware {
    cookie_name: String,
}

impl SessionMiddleware {
    pub fn new(cookie: &str) -> SessionMiddleware {
        SessionMiddleware { cookie_name: cookie.to_string() }
    }

    pub fn decode(&self, cookie: Cookie) -> HashMap<String, String> {
        let mut ret = HashMap::new();
        let bytes = cookie.value.as_slice().from_base64().unwrap_or(Vec::new());
        let mut parts = bytes.as_slice().split(|&a| a == 0xff);
        loop {
            match (parts.next(), parts.next()) {
                (Some(key), Some(value)) => {
                    match (str::from_utf8(key), str::from_utf8(value)) {
                        (Some(key), Some(value)) => {
                            ret.insert(key.to_string(), value.to_string());
                        }
                        _ => {}
                    }
                }
                _ => break
            }
        }
        return ret;
    }

    pub fn encode(&self, h: &HashMap<String, String>) -> String {
        let mut ret = Vec::new();
        for (i, (k, v)) in h.iter().enumerate() {
            if i != 0 { ret.push(0xff) }
            ret.push_all(k.as_bytes());
            ret.push(0xff);
            ret.push_all(v.as_bytes());
        }
        ret.as_slice().to_base64(STANDARD)
    }
}

impl conduit_middleware::Middleware for SessionMiddleware {
    fn before(&self, req: &mut Request) -> Result<(), Box<Show>> {
        let session = {
            let jar = req.cookies().signed();
            jar.find(self.cookie_name.as_slice()).map(|cookie| {
                self.decode(cookie)
            }).unwrap_or_else(|| HashMap::new())
        };
        req.mut_extensions().insert("conduit.cookie.session", box session);
        Ok(())
    }

    fn after(&self, req: &mut Request, res: Result<Response, Box<Show>>)
        -> Result<Response, Box<Show>>
    {
        let session = req.mut_extensions().pop(&"conduit.cookie.session");
        let session = session.expect("session must be present after request");
        let session = session.as_ref::<HashMap<String, String>>().unwrap();
        let encoded = self.encode(session);
        let cookie = Cookie::new(self.cookie_name.to_string(), encoded);
        req.cookies().signed().add(cookie);
        return res;
    }
}

pub trait RequestSession<'a> {
    fn session(self) -> &'a mut HashMap<String, String>;
}

impl<'a> RequestSession<'a> for &'a mut Request {
    fn session(self) -> &'a mut HashMap<String, String> {
        self.mut_extensions().find_mut(&"conduit.cookie.session")
            .and_then(|a| a.as_mut::<HashMap<String, String>>())
            .expect("missing cookie session")
    }
}

#[cfg(test)]
mod test {

    use conduit::{Request, Response, Handler, Post};
    use conduit_middleware::MiddlewareBuilder;
    use test::MockRequest;
    use std::collections::HashMap;
    use std::io::MemReader;

    use {RequestSession, Middleware, SessionMiddleware};

    #[test]
    fn simple() {
        let mut req = MockRequest::new(Post, "/articles");

        // Set the session cookie
        let mut app = MiddlewareBuilder::new(set_session);
        app.add(Middleware::new(b"foo"));
        app.add(SessionMiddleware::new("lol"));
        let response = app.call(&mut req).ok().unwrap();

        let v = response.headers.get(&"Set-Cookie".to_string());
        assert!(v.as_slice()[0].as_slice().starts_with("lol"));

        // Use the session cookie
        req.header("Cookie", v.as_slice()[0].as_slice());
        let mut app = MiddlewareBuilder::new(use_session);
        app.add(Middleware::new(b"foo"));
        app.add(SessionMiddleware::new("lol"));
        assert!(app.call(&mut req).is_ok());

        fn set_session(req: &mut Request) -> Result<Response, String> {
            assert!(req.session().insert("foo".to_string(), "bar".to_string()));
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
        fn use_session(req: &mut Request) -> Result<Response, String> {
            assert_eq!(req.session().find_equiv(&"foo").unwrap().as_slice(),
                       "bar");
            Ok(Response {
                status: (200, "OK"),
                headers: HashMap::new(),
                body: box MemReader::new(Vec::new()),
            })
        }
    }
}
<|endoftext|>


<commit_before>// Standard library imports
use std::mem;

// srmat imports
use matelt::{MatrixElt};
use matrix::{Matrix};
use discrete::*;

#[doc = "
Defines a view on a matrix.

A view on a matrix is a subset of
chosen rows and columns.

"]
pub struct MatrixView<'a, T:'a+MatrixElt>{
    // Reference to the associated matrix
    m : &'a Matrix<T>,
    // start row
    start_row : uint,
    // number or rows
    rows  : uint,
    // skip between rows (by default 1)
    row_skip : uint,
    // start column
    start_col : uint,
    // Number of columns
    cols : uint,
    // Skip between columns (by default 1)
    col_skip : uint
}

/// Static functions for creating  a view
impl<'a, T:MatrixElt> MatrixView<'a, T> {
    pub fn new(m : &Matrix<T>, start_row : int, start_col : int , num_rows: uint, num_cols : uint) -> MatrixView<T> {
        let r = mod_n(start_row, m.num_rows() as int);
        let c = mod_n(start_col, m.num_cols() as int);
        let row_skip = 1u;
        let col_skip = 1u;
        assert!(r + row_skip*num_rows <= m.num_rows());
        assert!(c + col_skip*num_cols <= m.num_cols());
        let result : MatrixView<T> = MatrixView{
            m : m,
            start_row : r,
            start_col : c,
            rows: num_rows,
            cols : num_cols,
            row_skip : row_skip,
            col_skip : col_skip
        };
        result
    }
    //// Returns the number of rows in the view
    pub fn num_rows(&self) -> uint {
        self.rows
    }

    /// Returns the number of columns in the view
    pub fn num_cols(&self) -> uint {
        self.cols
    }

    /// Returns the size of view in an (r, c) tuple
    pub fn size (&self)-> (uint, uint){
        (self.rows, self.cols)
    }
    /// Returns the number of cells in view
    pub fn num_cells(&self)->uint {
        self.rows * self.cols
    }
    /// Indicates if the view is a row vector
    pub fn is_row(&self) -> bool {
        self.rows == 1
    }

    /// Indicates if the view is a column vector
    pub fn is_col(&self) -> bool {
        self.cols == 1
    }

    /// Indicates if the view is a scalar actually
    pub fn is_scalar(&self) -> bool {
        self.num_cells() == 1
    }

    /// Indicates if the view is a vector
    pub fn is_vector(&self) -> bool {
        (self.rows == 1) ^ (self.cols == 1)
    }

    /// Indicates if the view is empty
    pub fn is_empty(&self) -> bool {
        self.rows * self.cols == 0
    }

    /// Indicates if the view is square
    pub fn is_square(&self) -> bool {
        self.rows == self.cols
    }

    /// Gets an element in the view
    #[inline]
    pub fn get(&self, r : uint, c : uint) -> T  {
        assert!(r < self.rows);
        assert!(c < self.cols);
        let ptr = self.m.as_ptr();
        let offset = self.cell_to_offset(r, c);
        assert!((offset as uint) < self.m.capacity());
        unsafe {
            *ptr.offset(offset)
        }
    }

    /// Sets an element in the view
    #[inline]
    pub fn set(&mut self, r : uint, c : uint, value : T) {
        assert!(r < self.rows);
        assert!(c < self.cols);
        let ptr = self.m.as_ptr();
        // I know more than the compiler
        // I am allowing modification of the underlying buffer
        let ptr : *mut T = unsafe { mem::transmute(ptr) };
        let offset = self.cell_to_offset(r, c);
        assert!((offset as uint) < self.m.capacity());
        unsafe {
            *ptr.offset(offset) = value;
        }
    }

    /// Converts an index to cell address (row, column)
    #[inline]
    pub fn index_to_cell(&self, index : uint) -> (uint, uint){
        assert!(index < self.num_cells());
        let c = index / self.rows;
        let r = index - c*self.rows;
        (r, c)
    }

    /// Converts a cell address to an index (r, c) to index
    #[inline]
    pub fn cell_to_index(&self, r : uint,  c: uint) -> uint{
        assert!(r < self.rows);
        assert!(c < self.cols);
        c * self.rows + r
    }

    /******************************************************
     *
     *   Private implementation of MatrixView
     *
     *******************************************************/

    /// Maps a cell index to actual offset in the internal buffer
    #[inline]
    fn cell_to_offset(&self, r : uint,  c: uint)-> int {
        let r = self.start_row + r * self.row_skip;
        let c = self.start_col + c * self.col_skip;
        (c * self.m.stride() + r) as int
    }

}

/// Functions to construct new views out of a view and other conversions
impl<'a, T:MatrixElt> MatrixView<'a, T> {
    /// Converts the view to vector from standard library
    pub fn to_std_vec(&self) -> Vec<T> {
        let mut vec: Vec<T> = Vec::with_capacity(self.num_cells());
        // We iterate over elements in matrix and push in the vector
        let ptr = self.m.as_ptr();
        for c in range(0, self.cols){
            for r in range (0, self.rows){
                let offset = self.cell_to_offset(r, c);
                vec.push(unsafe{*ptr.offset(offset)});
            }
        }
        vec
    }
}

impl<'a, T:MatrixElt> MatrixView<'a, T> {
}

impl<'a, T:MatrixElt> MatrixView<'a, T> {
}

/******************************************************
 *
 *   Unit tests follow.
 *
 *******************************************************/

#[cfg(test)]
mod test{
    use matrix::{Matrix, MatrixI64};

    #[test]
    fn test_basic(){
        let m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        let mut v1 = m1.view(2, 3, 4, 4);
        assert_eq!(v1.size(), (4u, 4u));
        assert_eq!(v1.num_rows(), 4);
        assert_eq!(v1.num_cols(), 4);
        assert_eq!(v1.is_scalar(), false);
        assert_eq!(v1.is_vector(), false);
        assert_eq!(v1.is_row(), false);
        assert_eq!(v1.is_col(), false);
        assert_eq!(v1.get(1,1), 44);
        v1.set(1,1, 300);
        assert_eq!(v1.get(1,1), 300);
    }
    #[test]
    fn test_view_multiple(){
        let m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        // We can create multiple views easily.
        let v1 = m1.view(1, 1, 4, 4);
        let v2 = m1.view(2, 2, 4, 4);
        let v3 = m1.view(2, 3, 4, 4);
        assert_eq!(v1.get(0, 0), 12);
        assert_eq!(v2.get(0, 0), 23);
        assert_eq!(v3.get(0, 0), 33);
    }

    #[test]
    fn test_view_matrix_mutability(){
        let mut m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        {
            let v1 = m1.view(2, 2, 4, 4);
            // The following line doesn't compile since we have borrowed an
            // immutable reference of m1 in v1.
            //m1.set(0, 0, 2);
            assert_eq!(v1.get(0, 0), 23);
        }
        m1.set(0, 0, 2);
    }

    #[test]
    fn test_cell_index_mapping(){
        let rows = 20;
        let cols = 10;
        let m : MatrixI64 = Matrix::new(rows, cols);
        let vrows = 4;
        let vcols = 3;
        let v = m.view(1, 1, vrows, vcols);
        assert_eq!(v.index_to_cell(3 + 2*vrows), (3, 2));
        assert_eq!(v.cell_to_index(3, 2), 3 + 2*vrows);
        assert_eq!(v.cell_to_index(3, 2), 11);
        assert_eq!(v.index_to_cell(11), (3, 2));
    }

    #[test]
    fn test_to_std_vec(){
        let m :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        let vrows = 4;
        let vcols = 3;
        let mv = m.view(1, 1, vrows, vcols);
        let vv : Vec<i64> = vec![12, 13, 14, 15,
        22, 23, 24, 25,
        32, 33, 34, 35];
        assert_eq!(mv.to_std_vec(), vv);
    }

}

<commit_msg>addition over view.<commit_after>// Standard library imports
use std::mem;
use std::ops;

// srmat imports
use matelt::{MatrixElt};
use matrix::{Matrix};
use materr::*;
use discrete::*;

#[doc = "
Defines a view on a matrix.

A view on a matrix is a subset of
chosen rows and columns.

"]
pub struct MatrixView<'a, T:'a+MatrixElt>{
    // Reference to the associated matrix
    m : &'a Matrix<T>,
    // start row
    start_row : uint,
    // number or rows
    rows  : uint,
    // skip between rows (by default 1)
    row_skip : uint,
    // start column
    start_col : uint,
    // Number of columns
    cols : uint,
    // Skip between columns (by default 1)
    col_skip : uint
}

/// Static functions for creating  a view
impl<'a, T:MatrixElt> MatrixView<'a, T> {
    pub fn new(m : &Matrix<T>, start_row : int, start_col : int , num_rows: uint, num_cols : uint) -> MatrixView<T> {
        let r = mod_n(start_row, m.num_rows() as int);
        let c = mod_n(start_col, m.num_cols() as int);
        let row_skip = 1u;
        let col_skip = 1u;
        assert!(r + row_skip*num_rows <= m.num_rows());
        assert!(c + col_skip*num_cols <= m.num_cols());
        let result : MatrixView<T> = MatrixView{
            m : m,
            start_row : r,
            start_col : c,
            rows: num_rows,
            cols : num_cols,
            row_skip : row_skip,
            col_skip : col_skip
        };
        result
    }
    //// Returns the number of rows in the view
    pub fn num_rows(&self) -> uint {
        self.rows
    }

    /// Returns the number of columns in the view
    pub fn num_cols(&self) -> uint {
        self.cols
    }

    /// Returns the size of view in an (r, c) tuple
    pub fn size (&self)-> (uint, uint){
        (self.rows, self.cols)
    }
    /// Returns the number of cells in view
    pub fn num_cells(&self)->uint {
        self.rows * self.cols
    }
    /// Indicates if the view is a row vector
    pub fn is_row(&self) -> bool {
        self.rows == 1
    }

    /// Indicates if the view is a column vector
    pub fn is_col(&self) -> bool {
        self.cols == 1
    }

    /// Indicates if the view is a scalar actually
    pub fn is_scalar(&self) -> bool {
        self.num_cells() == 1
    }

    /// Indicates if the view is a vector
    pub fn is_vector(&self) -> bool {
        (self.rows == 1) ^ (self.cols == 1)
    }

    /// Indicates if the view is empty
    pub fn is_empty(&self) -> bool {
        self.rows * self.cols == 0
    }

    /// Indicates if the view is square
    pub fn is_square(&self) -> bool {
        self.rows == self.cols
    }

    /// Gets an element in the view
    #[inline]
    pub fn get(&self, r : uint, c : uint) -> T  {
        assert!(r < self.rows);
        assert!(c < self.cols);
        let ptr = self.m.as_ptr();
        let offset = self.cell_to_offset(r, c);
        assert!((offset as uint) < self.m.capacity());
        unsafe {
            *ptr.offset(offset)
        }
    }

    /// Sets an element in the view
    #[inline]
    pub fn set(&mut self, r : uint, c : uint, value : T) {
        assert!(r < self.rows);
        assert!(c < self.cols);
        let ptr = self.m.as_ptr();
        // I know more than the compiler
        // I am allowing modification of the underlying buffer
        let ptr : *mut T = unsafe { mem::transmute(ptr) };
        let offset = self.cell_to_offset(r, c);
        assert!((offset as uint) < self.m.capacity());
        unsafe {
            *ptr.offset(offset) = value;
        }
    }

    /// Converts an index to cell address (row, column)
    #[inline]
    pub fn index_to_cell(&self, index : uint) -> (uint, uint){
        assert!(index < self.num_cells());
        let c = index / self.rows;
        let r = index - c*self.rows;
        (r, c)
    }

    /// Converts a cell address to an index (r, c) to index
    #[inline]
    pub fn cell_to_index(&self, r : uint,  c: uint) -> uint{
        assert!(r < self.rows);
        assert!(c < self.cols);
        c * self.rows + r
    }

    /******************************************************
     *
     *   Private implementation of MatrixView
     *
     *******************************************************/

    /// Maps a cell index to actual offset in the internal buffer
    #[inline]
    fn cell_to_offset(&self, r : uint,  c: uint)-> int {
        let r = self.start_row + r * self.row_skip;
        let c = self.start_col + c * self.col_skip;
        (c * self.m.stride() + r) as int
    }

}

/// Functions to construct new views out of a view and other conversions
impl<'a, T:MatrixElt> MatrixView<'a, T> {
    /// Converts the view to vector from standard library
    pub fn to_std_vec(&self) -> Vec<T> {
        let mut vec: Vec<T> = Vec::with_capacity(self.num_cells());
        // We iterate over elements in matrix and push in the vector
        let ptr = self.m.as_ptr();
        for c in range(0, self.cols){
            for r in range (0, self.rows){
                let offset = self.cell_to_offset(r, c);
                vec.push(unsafe{*ptr.offset(offset)});
            }
        }
        vec
    }
}

impl<'a, T:MatrixElt> MatrixView<'a, T> {
}

impl<'a, T:MatrixElt> MatrixView<'a, T> {
}

/// View + View =  Matrix addition
impl<'a, 'b, T:MatrixElt> ops::Add<MatrixView<'b, T>, Matrix<T>> for MatrixView<'a, T> {
    fn add(&self, rhs: &MatrixView<T>) -> Matrix<T> {
        // Validate dimensions are same.
        if self.size() != rhs.size(){
            fail!(DimensionsMismatch.to_string());
        }
        let mut result : Matrix<T> = Matrix::new(self.rows, self.cols);
        let pa = self.m.as_ptr();
        let pb = rhs.m.as_ptr();
        let pc = result.as_mut_ptr();
        for c in range (0, self.cols){
            for r in range(0, self.rows){
                let dst_offset = result.cell_to_offset(r, c);
                let a_offset  = self.cell_to_offset(r, c);
                let b_offset = rhs.cell_to_offset(r, c);
                unsafe{
                    *pc.offset(dst_offset) = *pa.offset(a_offset) + *pb.offset(b_offset);
                }
            }
        }
        result
    }
}

/******************************************************
 *
 *   Unit tests follow.
 *
 *******************************************************/

#[cfg(test)]
mod test{
    use matrix::{Matrix, MatrixI64};

    #[test]
    fn test_basic(){
        let m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        let mut v1 = m1.view(2, 3, 4, 4);
        assert_eq!(v1.size(), (4u, 4u));
        assert_eq!(v1.num_rows(), 4);
        assert_eq!(v1.num_cols(), 4);
        assert_eq!(v1.is_scalar(), false);
        assert_eq!(v1.is_vector(), false);
        assert_eq!(v1.is_row(), false);
        assert_eq!(v1.is_col(), false);
        assert_eq!(v1.get(1,1), 44);
        v1.set(1,1, 300);
        assert_eq!(v1.get(1,1), 300);
    }
    #[test]
    fn test_view_multiple(){
        let m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        // We can create multiple views easily.
        let v1 = m1.view(1, 1, 4, 4);
        let v2 = m1.view(2, 2, 4, 4);
        let v3 = m1.view(2, 3, 4, 4);
        assert_eq!(v1.get(0, 0), 12);
        assert_eq!(v2.get(0, 0), 23);
        assert_eq!(v3.get(0, 0), 33);
    }

    #[test]
    fn test_view_matrix_mutability(){
        let mut m1 :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        {
            let v1 = m1.view(2, 2, 4, 4);
            // The following line doesn't compile since we have borrowed an
            // immutable reference of m1 in v1.
            //m1.set(0, 0, 2);
            assert_eq!(v1.get(0, 0), 23);
        }
        m1.set(0, 0, 2);
    }

    #[test]
    fn test_cell_index_mapping(){
        let rows = 20;
        let cols = 10;
        let m : MatrixI64 = Matrix::new(rows, cols);
        let vrows = 4;
        let vcols = 3;
        let v = m.view(1, 1, vrows, vcols);
        assert_eq!(v.index_to_cell(3 + 2*vrows), (3, 2));
        assert_eq!(v.cell_to_index(3, 2), 3 + 2*vrows);
        assert_eq!(v.cell_to_index(3, 2), 11);
        assert_eq!(v.index_to_cell(11), (3, 2));
    }

    #[test]
    fn test_to_std_vec(){
        let m :  MatrixI64 = Matrix::from_iter(10, 8, range(1, 100));
        let vrows = 4;
        let vcols = 3;
        let mv = m.view(1, 1, vrows, vcols);
        let vv : Vec<i64> = vec![12, 13, 14, 15,
        22, 23, 24, 25,
        32, 33, 34, 35];
        assert_eq!(mv.to_std_vec(), vv);
    }

    #[test]
    fn test_addition(){
        let m :  MatrixI64 = Matrix::from_iter(10, 10, range(1, 200));
        let v1   = m.view(2, 2, 2, 2); // 23 , 24 , 33, 34
        let v2 = m.view(1, 1, 2, 2);  // 12, 13, 22, 33
        let m2 = v1 + v2; //
        let m3 : MatrixI64 = Matrix::from_slice(2, 2, vec![35, 37, 55, 57].as_slice());
        assert_eq!(m2, m3);
    }
}

<|endoftext|>