<commit_before>//! Iron's HTTP Response representation and associated methods.

use std::io::{IoResult, File, MemReader};
use std::path::BytesContainer;

use anymap::AnyMap;
use http::status::{Status, InternalServerError, NotFound};
use OkStatus = http::status::Ok;
use http::headers::response::HeaderCollection;
use http::headers::content_type::MediaType;

use plugin::Extensible;

pub use HttpResponse = http::server::response::ResponseWriter;

use contenttype::get_content_type;

/// The response representation given to `Middleware`
pub struct Response {
    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Box<Reader>,

    /// The headers of the response.
    pub headers: Box<HeaderCollection>,

    /// The response status-code.
    pub status: Option<Status>,

    /// An AnyMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: AnyMap
}

impl Response {
    /// Construct a Response from an HttpResponse reference
    pub fn from_http(http_res: &mut HttpResponse) -> Response {
        Response {
            headers: http_res.headers.clone(),
            status: None, // Start with no response code.
            body: box MemReader::new(vec![]) as Box<Reader>,
            extensions: AnyMap::new()
        }
    }

    /// Write the `Status` and data to the `Response`.
    pub fn serve<S: BytesContainer>(&mut self, status: Status, body: S) {
        self.status = Some(status);
        self.body = box MemReader::new(body.container_as_bytes().to_vec()) as Box<Reader>;
    }

    /// Serve the file located at `path`.
    ///
    /// This usually means a request has been handled, and `Middleware`
    /// may want to `Unwind` after a file is served. If the status should be
    /// anything other than `200`, `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will error if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    /// from the file. `Middleware` should handle this gracefully.
    pub fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let file = try!(File::open(path));
        self.headers.content_type = path.extension_str().and_then(get_content_type);
        self.body = box file as Box<Reader>;
        self.status = Some(OkStatus);
        Ok(())
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(mut self, http_res: &mut HttpResponse) {
        http_res.headers = self.headers.clone();

        // Default to a 404 if no response code was set
        http_res.status = self.status.clone().unwrap_or(NotFound);

        // Read the body into the http_res body
        let _ = match self.body.read_to_end() {
            Ok(body) => {
                let plain_txt: MediaType = get_content_type("txt").unwrap();

                // Set content length and type
                http_res.headers.content_length =
                    Some(body.len());
                http_res.headers.content_type =
                    Some(http_res.headers.content_type.clone().unwrap_or(plain_txt));

                // Write the body
                http_res.write(body.as_slice())
            },
            Err(e) => Err(e)
        // Catch errors from reading + writing
        }.map_err(|e| {
            error!("Error reading/writing body: {}", e);
            http_res.status = InternalServerError;
            let _ = http_res.write(b"Internal Server Error")
                .map_err(|e| error!("Error writing error message: {}", e));
        });
    }
}

impl Extensible for Response {
    fn extensions(&self) -> &AnyMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut AnyMap {
        &mut self.extensions
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_content_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<commit_msg>(refactor) Make body optional to mark when body was written to.<commit_after>//! Iron's HTTP Response representation and associated methods.

use std::io::{IoResult, File, MemReader};
use std::path::BytesContainer;

use anymap::AnyMap;
use http::status::{Status, InternalServerError, NotFound};
use OkStatus = http::status::Ok;
use http::headers::response::HeaderCollection;
use http::headers::content_type::MediaType;

use plugin::Extensible;

pub use HttpResponse = http::server::response::ResponseWriter;

use contenttype::get_content_type;

/// The response representation given to `Middleware`
pub struct Response {
    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Option<Box<Reader>>,

    /// The headers of the response.
    pub headers: Box<HeaderCollection>,

    /// The response status-code.
    pub status: Option<Status>,

    /// An AnyMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: AnyMap
}

impl Response {
    /// Construct a Response from an HttpResponse reference
    pub fn from_http(http_res: &mut HttpResponse) -> Response {
        Response {
            headers: http_res.headers.clone(),
            status: None, // Start with no response code.
            body: None, // Start with no body.
            extensions: AnyMap::new()
        }
    }

    /// Write the `Status` and data to the `Response`.
    pub fn serve<S: BytesContainer>(&mut self, status: Status, body: S) {
        self.status = Some(status);
        self.body = Some(box MemReader::new(body.container_as_bytes().to_vec()) as Box<Reader>);
    }

    /// Serve the file located at `path`.
    ///
    /// This usually means a request has been handled, and `Middleware`
    /// may want to `Unwind` after a file is served. If the status should be
    /// anything other than `200`, `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will error if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    /// from the file. `Middleware` should handle this gracefully.
    pub fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let file = try!(File::open(path));
        self.headers.content_type = path.extension_str().and_then(get_content_type);
        self.body = Some(box file as Box<Reader>);
        self.status = Some(OkStatus);
        Ok(())
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(self, http_res: &mut HttpResponse) {
        http_res.headers = self.headers.clone();

        // Default to a 404 if no response code was set
        http_res.status = self.status.clone().unwrap_or(NotFound);

        // Read the body into the http_res body
        let mut body = self.body.unwrap_or_else(|| box MemReader::new(vec![]) as Box<Reader>);
        let _ = match body.read_to_end() {
            Ok(body_content) => {
                let plain_txt: MediaType = get_content_type("txt").unwrap();

                // Set content length and type
                http_res.headers.content_length =
                    Some(body_content.len());
                http_res.headers.content_type =
                    Some(http_res.headers.content_type.clone().unwrap_or(plain_txt));

                // Write the body
                http_res.write(body_content.as_slice())
            },
            Err(e) => Err(e)
        // Catch errors from reading + writing
        }.map_err(|e| {
            error!("Error reading/writing body: {}", e);
            http_res.status = InternalServerError;
            let _ = http_res.write(b"Internal Server Error")
                // Something is really, really wrong.
                .map_err(|e| error!("Error writing error message: {}", e));
        });
    }
}

impl Extensible for Response {
    fn extensions(&self) -> &AnyMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut AnyMap {
        &mut self.extensions
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_content_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<|endoftext|>


<commit_before>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;

/// Object representing an HTTP response.
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    http_version: HTTPVersion,
}

impl<R: Reader> Response<R> {
    pub fn new(status_code: StatusCode, mut headers: Vec<Header>,
               data: R, data_length: uint) -> Response<R>
    {
        // add Content-Length if not in the headers
        if headers.iter().find(|h| h.field.equiv(&"Content-Length")).is_none() {
            headers.unshift(
                Header{field: from_str("Content-Length").unwrap(), value: format!("{}", data_length)}
            );
        }

        Response {
            reader: data,
            status_code: status_code,
            headers: headers,
            http_version: HTTPVersion(1, 1),
        }
    }

    /// Returns the same request, but with an additional header.
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.headers.push(header);
        self
    }

    /// Returns the same request, but with a different status code.
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Forces an HTTP version.
    pub fn with_http_version(mut self, version: HTTPVersion) -> Response<R> {
        self.http_version = version;
        self
    }

    /// Cleans-up the headers so that they can be returned.
    fn purify_headers(&mut self) {
        // removing some unwanted headers, like Connection
        self.headers.retain(|h| !h.field.equiv(&"Connection"));

        // add Server if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                Header{field: from_str("Server").unwrap(), value: "tiny-http (Rust)".to_string()}
            );
        }

        // add Connection: close
        /*self.headers.push(
            Header{field: "Connection".to_string(), value: "close".to_string()}
        );*/
    }

    /// Prints the HTTP response to a writer.
    pub fn raw_print<W: Writer>(mut self, mut writer: W) -> IoResult<()> {
        self.purify_headers();

        // writing status line
        try!(write!(writer, "HTTP/{} {} {}\r\n",
            self.http_version,
            self.status_code.as_uint(),
            self.status_code.get_default_message()
        ));

        // writing headers
        for header in self.headers.iter() {
            try!(write!(writer, "{}: {}\r\n", header.field, header.value));
        }

        // separator between header and data
        try!(write!(writer, "\r\n"));

        // writing data
        try!(util::copy(&mut self.reader, &mut writer));

        Ok(())
    }
}

impl Response<File> {
    pub fn from_file(file: &Path) -> IoResult<Response<File>> {
        let mut file = try!(File::open(file));
        let stats = try!(file.stat());

        Ok(Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            stats.size as uint
        ))
    }
}

impl Response<MemReader> {
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            data_len
        )
    }

    pub fn from_string(data: String) -> Response<MemReader> {
        Response::from_data(data.into_bytes())
    }
}

impl Response<NullReader> {
    pub fn empty() -> Response<NullReader> {
        Response::new(
            StatusCode(204),
            Vec::new(),
            NullReader,
            0
        )
    }
}
<commit_msg>Add Response::not_modified()<commit_after>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;

/// Object representing an HTTP response.
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    http_version: HTTPVersion,
}

impl<R: Reader> Response<R> {
    pub fn new(status_code: StatusCode, mut headers: Vec<Header>,
               data: R, data_length: uint) -> Response<R>
    {
        // add Content-Length if not in the headers
        if headers.iter().find(|h| h.field.equiv(&"Content-Length")).is_none() {
            headers.unshift(
                Header{field: from_str("Content-Length").unwrap(), value: format!("{}", data_length)}
            );
        }

        Response {
            reader: data,
            status_code: status_code,
            headers: headers,
            http_version: HTTPVersion(1, 1),
        }
    }

    /// Returns the same request, but with an additional header.
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.headers.push(header);
        self
    }

    /// Returns the same request, but with a different status code.
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Forces an HTTP version.
    pub fn with_http_version(mut self, version: HTTPVersion) -> Response<R> {
        self.http_version = version;
        self
    }

    /// Cleans-up the headers so that they can be returned.
    fn purify_headers(&mut self) {
        // removing some unwanted headers, like Connection
        self.headers.retain(|h| !h.field.equiv(&"Connection"));

        // add Server if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                Header{field: from_str("Server").unwrap(), value: "tiny-http (Rust)".to_string()}
            );
        }

        // add Connection: close
        /*self.headers.push(
            Header{field: "Connection".to_string(), value: "close".to_string()}
        );*/
    }

    /// Prints the HTTP response to a writer.
    pub fn raw_print<W: Writer>(mut self, mut writer: W) -> IoResult<()> {
        self.purify_headers();

        // writing status line
        try!(write!(writer, "HTTP/{} {} {}\r\n",
            self.http_version,
            self.status_code.as_uint(),
            self.status_code.get_default_message()
        ));

        // writing headers
        for header in self.headers.iter() {
            try!(write!(writer, "{}: {}\r\n", header.field, header.value));
        }

        // separator between header and data
        try!(write!(writer, "\r\n"));

        // writing data
        try!(util::copy(&mut self.reader, &mut writer));

        Ok(())
    }
}

impl Response<File> {
    pub fn from_file(file: &Path) -> IoResult<Response<File>> {
        let mut file = try!(File::open(file));
        let stats = try!(file.stat());

        Ok(Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            stats.size as uint
        ))
    }
}

impl Response<MemReader> {
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            data_len
        )
    }

    pub fn from_string(data: String) -> Response<MemReader> {
        Response::from_data(data.into_bytes())
    }
}

impl Response<NullReader> {
    pub fn empty() -> Response<NullReader> {
        Response::new(
            StatusCode(204),
            Vec::new(),
            NullReader,
            0
        )
    }

    pub fn not_modified() -> Response<NullReader> {
        Response::new(
            StatusCode(304),
            Vec::new(),
            NullReader,
            0
        )
    }
}
<|endoftext|>


<commit_before>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;
use chunks::ChunksEncoder;

/// Object representing an HTTP response.
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    http_version: HTTPVersion,
}

impl<R: Reader> Response<R> {
    pub fn new(status_code: StatusCode, mut headers: Vec<Header>,
               data: R, data_length: uint) -> Response<R>
    {
        // add Content-Length if not in the headers
        if headers.iter().find(|h| h.field.equiv(&"Content-Length")).is_none() {
            headers.unshift(
                Header{field: from_str("Content-Length").unwrap(), value: format!("{}", data_length)}
            );
        }

        Response {
            reader: data,
            status_code: status_code,
            headers: headers,
            http_version: HTTPVersion(1, 1),
        }
    }

    /// Returns the same request, but with an additional header.
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.headers.push(header);
        self
    }

    /// Returns the same request, but with a different status code.
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Forces an HTTP version.
    pub fn with_http_version(mut self, version: HTTPVersion) -> Response<R> {
        self.http_version = version;
        self
    }

    /// Cleans-up the headers so that they can be returned.
    fn purify_headers(&mut self) {
        // removing some unwanted headers, like Connection
        self.headers.retain(|h| !h.field.equiv(&"Connection"));

        // add Server if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                Header{field: from_str("Server").unwrap(), value: "tiny-http (Rust)".to_string()}
            );
        }

        // add Connection: close
        /*self.headers.push(
            Header{field: "Connection".to_string(), value: "close".to_string()}
        );*/
    }

    /// Prints the HTTP response to a writer.
    pub fn raw_print<W: Writer>(mut self, writer: W) -> IoResult<()> {
        self.purify_headers();

        // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
        let chunks_threshold = 32768;
        let use_chunks =
            self.http_version >= HTTPVersion(1, 1) &&
            self.headers.iter().find(|h| h.field.equiv(&"Content-Length"))
                .and_then(|h| from_str::<uint>(h.value.as_slice()))
                .filtered(|val| *val < chunks_threshold)
                .is_none();

        if use_chunks {
            self.raw_print2(ChunksEncoder::new(writer))
        } else {
            self.raw_print2(writer)
        }
    }

    // continuation of the function above
    // TODO: is there a better way to do that?
    fn raw_print2<W: Writer>(mut self, mut writer: W) -> IoResult<()> {
        // writing status line
        try!(write!(writer, "HTTP/{} {} {}\r\n",
            self.http_version,
            self.status_code.as_uint(),
            self.status_code.get_default_message()
        ));

        // writing headers
        for header in self.headers.iter() {
            try!(write!(writer, "{}: {}\r\n", header.field, header.value));
        }

        // separator between header and data
        try!(write!(writer, "\r\n"));

        // writing data
        try!(util::copy(&mut self.reader, &mut writer));

        Ok(())
    }
}

impl Response<File> {
    pub fn from_file(file: &Path) -> IoResult<Response<File>> {
        let mut file = try!(File::open(file));
        let stats = try!(file.stat());

        Ok(Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            stats.size as uint
        ))
    }
}

impl Response<MemReader> {
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            data_len
        )
    }

    pub fn from_string(data: String) -> Response<MemReader> {
        Response::from_data(data.into_bytes())
    }
}

impl Response<NullReader> {
    pub fn empty() -> Response<NullReader> {
        Response::new(
            StatusCode(204),
            Vec::new(),
            NullReader,
            0
        )
    }

    pub fn not_modified() -> Response<NullReader> {
        Response::new(
            StatusCode(304),
            Vec::new(),
            NullReader,
            0
        )
    }
}
<commit_msg>Fix chunked encoding<commit_after>use common::{Header, HTTPVersion, StatusCode};
use std::io::{IoResult, MemReader};
use std::io::fs::File;
use std::io::util;
use std::io::util::NullReader;
use chunks::ChunksEncoder;

/// Object representing an HTTP response.
pub struct Response<R> {
    reader: R,
    status_code: StatusCode,
    headers: Vec<Header>,
    http_version: HTTPVersion,
}

impl<R: Reader> Response<R> {
    pub fn new(status_code: StatusCode, mut headers: Vec<Header>,
               data: R, data_length: uint) -> Response<R>
    {
        // add Content-Length if not in the headers
        if headers.iter().find(|h| h.field.equiv(&"Content-Length")).is_none() {
            headers.unshift(
                Header{field: from_str("Content-Length").unwrap(), value: format!("{}", data_length)}
            );
        }

        Response {
            reader: data,
            status_code: status_code,
            headers: headers,
            http_version: HTTPVersion(1, 1),
        }
    }

    /// Returns the same request, but with an additional header.
    pub fn with_header(mut self, header: Header) -> Response<R> {
        self.headers.push(header);
        self
    }

    /// Returns the same request, but with a different status code.
    pub fn with_status_code(mut self, code: StatusCode) -> Response<R> {
        self.status_code = code;
        self
    }

    /// Forces an HTTP version.
    pub fn with_http_version(mut self, version: HTTPVersion) -> Response<R> {
        self.http_version = version;
        self
    }

    /// Cleans-up the headers so that they can be returned.
    fn purify_headers(&mut self) {
        // removing some unwanted headers, like Connection
        self.headers.retain(|h| !h.field.equiv(&"Connection"));

        // add Server if not in the headers
        if self.headers.iter().find(|h| h.field.equiv(&"Server")).is_none() {
            self.headers.unshift(
                Header{field: from_str("Server").unwrap(), value: "tiny-http (Rust)".to_string()}
            );
        }

        // add Connection: close
        /*self.headers.push(
            Header{field: "Connection".to_string(), value: "close".to_string()}
        );*/
    }

    /// Prints the HTTP response to a writer.
    pub fn raw_print<W: Writer>(mut self, mut writer: W) -> IoResult<()> {
        self.purify_headers();

        // if we don't have a Content-Length, or if the Content-Length is too big, using chunks writer
        let chunks_threshold = 32768;
        let use_chunks =
            self.http_version >= HTTPVersion(1, 1) &&
            self.headers.iter().find(|h| h.field.equiv(&"Content-Length"))
                .and_then(|h| from_str::<uint>(h.value.as_slice()))
                .filtered(|val| *val < chunks_threshold)
                .is_none();

        // add transfer-encoding header
        if use_chunks {
            self.headers.push(
                Header{field: from_str("Transfer-Encoding").unwrap(), value: "chunked".to_string()}
            )
        }

        // writing status line
        try!(write!(writer, "HTTP/{} {} {}\r\n",
            self.http_version,
            self.status_code.as_uint(),
            self.status_code.get_default_message()
        ));

        // writing headers
        for header in self.headers.iter() {
            try!(write!(writer, "{}: {}\r\n", header.field, header.value));
        }

        // separator between header and data
        try!(write!(writer, "\r\n"));

        // writing data
        if use_chunks {
            let mut writer = ChunksEncoder::new(writer);
            try!(util::copy(&mut self.reader, &mut writer));
        } else {
            try!(util::copy(&mut self.reader, &mut writer));
        }

        Ok(())
    }
}

impl Response<File> {
    pub fn from_file(file: &Path) -> IoResult<Response<File>> {
        let mut file = try!(File::open(file));
        let stats = try!(file.stat());

        Ok(Response::new(
            StatusCode(200),
            Vec::new(),
            file,
            stats.size as uint
        ))
    }
}

impl Response<MemReader> {
    pub fn from_data(data: Vec<u8>) -> Response<MemReader> {
        let data_len = data.len();

        Response::new(
            StatusCode(200),
            Vec::new(),
            MemReader::new(data),
            data_len
        )
    }

    pub fn from_string(data: String) -> Response<MemReader> {
        Response::from_data(data.into_bytes())
    }
}

impl Response<NullReader> {
    pub fn empty() -> Response<NullReader> {
        Response::new(
            StatusCode(204),
            Vec::new(),
            NullReader,
            0
        )
    }

    pub fn not_modified() -> Response<NullReader> {
        Response::new(
            StatusCode(304),
            Vec::new(),
            NullReader,
            0
        )
    }
}
<|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
 */

extern crate chrono;

use std::collections::HashMap;
use utils::make_response;

pub trait ToOutput {
    fn to_output(&self) -> &[u8];
}

impl ToOutput for str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for &'static str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for String {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for Vec<u8> {
    fn to_output(&self) -> &[u8] {
        self.as_slice()
    }
}

#[derive(Debug)]
pub struct Response {
    code:       i32,
    cmsg:       String,
    ctype:      String,
    headers:    HashMap<String, String>,
    payload:    Vec<u8>,
}

impl Response {
    pub fn new() -> Response {
        let mut res = Response {
            code:       200,
            cmsg:       String::from("OK"),
            ctype:      String::from("text/plain"),
            headers:    HashMap::new(),
            payload:    Vec::with_capacity(2048),
        };

        let now = chrono::UTC::now().format("%a, %d %b %Y, %H:%M:%S GMT").to_string();

        res.add_header("Connection", "close");
        res.add_header("Server", "canteen/0.0.1");
        res.add_header("Date", &now);

        res
    }

    pub fn get_http_message(code: i32) -> String {
        let msg = match code {
            100 => "Continue",
            101 => "Switching Protocols",
            200 => "OK",
            201 => "Created",
            202 => "Accepted",
            203 => "Non-Authoritative Information",
            204 => "No Content",
            205 => "Reset Content",
            206 => "Partial Content",
            300 => "Multiple Choices",
            301 => "Moved Permanently",
            302 => "Found",
            303 => "See Other",
            304 => "Not Modified",
            305 => "Use Proxy",
            307 => "Temporary Redirect",
            400 => "Bad Request",
            401 => "Unauthorized",
            402 => "Payment Required",
            403 => "Forbidden",
            404 => "Not Found",
            405 => "Method Not Allowed",
            406 => "Not Acceptable",
            407 => "Proxy Authentication Required",
            408 => "Request Time Out",
            409 => "Conflict",
            410 => "Gone",
            411 => "Length Required",
            412 => "Precondition Failed",
            413 => "Request Entity Too Large",
            414 => "Request-URI Too Large",
            415 => "Unsupported Media Type",
            416 => "Requested Range Not Satisfiable",
            417 => "Expectation Failed",
            500 => "Internal Server Error",
            501 => "Not Implemented",
            502 => "Bad Gateway",
            503 => "Service Unavailable",
            504 => "Gateway Time-out",
            505 => "HTTP Version Not Supported",
            _     => "OK",
        };

        String::from(msg)
    }

    fn err_body(message: &str, path: &str) -> String {
        format!("\
                 \

Your request failed

{}: {}
", message, path)
    }

    pub fn err_403(path: &str) -> Response {
        make_response(Response::err_body("forbidden", path), "text/html", 403)
    }

    pub fn err_404(path: &str) -> Response {
        make_response(Response::err_body("not found", path), "text/html", 403)
    }

    pub fn err_500(path: &str) -> Response {
        make_response(Response::err_body("internal server error", path), "text/html", 500)
    }

    /* set the response code
     * ex: res.set_code(200, "OK");
     */
    pub fn set_code(&mut self, code: i32) {
        self.code = code;
        self.cmsg = Response::get_http_message(code);
    }

    /* set the content type
     * ex: res.set_content_type("text/html");
     */
    pub fn set_content_type(&mut self, ctype: &str) {
        self.ctype = String::from(ctype);
    }

    /* add an HTTP header
     * ex: res.add_header("Connection", "close");
     */
    pub fn add_header(&mut self, key: &str, value: &str) {
        if !self.headers.contains_key(key) {
            self.headers.insert(String::from(key), String::from(value));
        }
    }

    /* add data to the payload -- can take any type that has
     * implemented the canteen::response::ToOutput trait
     */
    pub fn append<T: ToOutput>(&mut self, payload: T) {
        self.payload.extend(payload.to_output().into_iter());
    }

    pub fn gen_output(&self) -> Vec<u8> {
        let mut output: Vec<u8> = Vec::with_capacity(self.payload.len() + 500);
        let mut inter = String::new();

        inter.push_str(&format!("HTTP/1.1 {} {}\r\n", self.code, self.cmsg));

        for (key, value) in &self.headers {
            inter.push_str(&format!("{}: {}\r\n", key, value));
        }

        inter.push_str(&format!("Content-Type: {}\r\n", self.ctype));
        inter.push_str(&format!("Content-Length: {}\r\n", self.payload.len()));
        inter.push_str("\r\n");

        output.extend(inter.as_bytes());
        output.extend(self.payload.iter());

        output
    }
}
<commit_msg>a couple minor fixes (change response code from a signed to an unsigned integer, because duh<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
 */

extern crate chrono;

use std::collections::HashMap;
use utils::make_response;

pub trait ToOutput {
    fn to_output(&self) -> &[u8];
}

impl ToOutput for str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for &'static str {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for String {
    fn to_output(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl ToOutput for Vec<u8> {
    fn to_output(&self) -> &[u8] {
        self.as_slice()
    }
}

#[derive(Debug)]
pub struct Response {
    code:       u16,
    cmsg:       String,
    ctype:      String,
    headers:    HashMap<String, String>,
    payload:    Vec<u8>,
}

impl Response {
    pub fn new() -> Response {
        let mut res = Response {
            code:       200,
            cmsg:       String::from("OK"),
            ctype:      String::from("text/plain"),
            headers:    HashMap::new(),
            payload:    Vec::with_capacity(2048),
        };

        let now = chrono::UTC::now().format("%a, %d %b %Y, %H:%M:%S GMT").to_string();

        res.add_header("Connection", "close");
        res.add_header("Server", "canteen/0.0.1");
        res.add_header("Date", &now);

        res
    }

    pub fn get_http_message(code: u16) -> String {
        let msg = match code {
            100 => "Continue",
            101 => "Switching Protocols",
            200 => "OK",
            201 => "Created",
            202 => "Accepted",
            203 => "Non-Authoritative Information",
            204 => "No Content",
            205 => "Reset Content",
            206 => "Partial Content",
            300 => "Multiple Choices",
            301 => "Moved Permanently",
            302 => "Found",
            303 => "See Other",
            304 => "Not Modified",
            305 => "Use Proxy",
            307 => "Temporary Redirect",
            400 => "Bad Request",
            401 => "Unauthorized",
            402 => "Payment Required",
            403 => "Forbidden",
            404 => "Not Found",
            405 => "Method Not Allowed",
            406 => "Not Acceptable",
            407 => "Proxy Authentication Required",
            408 => "Request Time Out",
            409 => "Conflict",
            410 => "Gone",
            411 => "Length Required",
            412 => "Precondition Failed",
            413 => "Request Entity Too Large",
            414 => "Request-URI Too Large",
            415 => "Unsupported Media Type",
            416 => "Requested Range Not Satisfiable",
            417 => "Expectation Failed",
            500 => "Internal Server Error",
            501 => "Not Implemented",
            502 => "Bad Gateway",
            503 => "Service Unavailable",
            504 => "Gateway Time-out",
            505 => "HTTP Version Not Supported",
            _   => "OK",
        };

        String::from(msg)
    }

    fn err_body(message: &str, path: &str) -> String {
        format!("\
                 \

Your request failed

{}: {}
", message, path)
    }

    pub fn err_403(path: &str) -> Response {
        make_response(Response::err_body("forbidden", path), "text/html", 403)
    }

    pub fn err_404(path: &str) -> Response {
        make_response(Response::err_body("not found", path), "text/html", 403)
    }

    pub fn err_500(path: &str) -> Response {
        make_response(Response::err_body("internal server error", path), "text/html", 500)
    }

    /* set the response code
     * ex: res.set_code(200, "OK");
     */
    pub fn set_code(&mut self, code: u16) {
        self.code = code;
        self.cmsg = Response::get_http_message(code);
    }

    /* set the content type
     * ex: res.set_content_type("text/html");
     */
    pub fn set_content_type(&mut self, ctype: &str) {
        self.ctype = String::from(ctype);
    }

    /* add an HTTP header
     * ex: res.add_header("Connection", "close");
     */
    pub fn add_header(&mut self, key: &str, value: &str) {
        if !self.headers.contains_key(key) {
            self.headers.insert(String::from(key), String::from(value));
        }
    }

    /* add data to the payload -- can take any type that has
     * implemented the canteen::response::ToOutput trait
     */
    pub fn append<T: ToOutput>(&mut self, payload: T) {
        self.payload.extend(payload.to_output().into_iter());
    }

    pub fn gen_output(&self) -> Vec<u8> {
        let mut output: Vec<u8> = Vec::with_capacity(self.payload.len() + 500);
        let mut inter = String::new();

        inter.push_str(&format!("HTTP/1.1 {} {}\r\n", self.code, self.cmsg));

        for (key, value) in &self.headers {
            inter.push_str(&format!("{}: {}\r\n", key, value));
        }

        inter.push_str(&format!("Content-Type: {}\r\n", self.ctype));
        inter.push_str(&format!("Content-Length: {}\r\n", self.payload.len()));
        inter.push_str("\r\n");

        output.extend(inter.as_bytes());
        output.extend(self.payload.iter());

        output
    }
}
<|endoftext|>


<commit_before>use crate::err::Result;
use crate::file::{SaveDir, TomlFile};
use serde::de::{self, Deserializer, Visitor};
use serde::ser::Serializer;
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::ops::Mul;
use std::path::{Path, PathBuf};
use std::result;

#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
    pub series_dir: PathBuf,
    pub reset_dates_on_rewatch: bool,
    pub episode: EpisodeConfig,
    pub tui: TuiConfig,
}

impl Config {
    pub fn new<P>(series_dir: P) -> Self
    where
        P: Into<PathBuf>,
    {
        Self {
            series_dir: series_dir.into(),
            ..Default::default()
        }
    }

    pub fn load_or_create() -> Result<Self> {
        match Self::load() {
            Ok(config) => Ok(config),
            Err(ref err) if err.is_file_nonexistant() => {
                let config = Config::default();
                config.save()?;
                Ok(config)
            }
            Err(err) => Err(err),
        }
    }

    pub fn stripped_path<'a, P>(&self, path: P) -> PathBuf
    where
        P: Into<Cow<'a, Path>>,
    {
        let path = path.into();

        match path.strip_prefix(&self.series_dir) {
            Ok(stripped) => stripped.into(),
            Err(_) => path.into_owned(),
        }
    }
}

impl Default for Config {
    fn default() -> Self {
        // Default series dir is ~/anime/
        let mut series_dir = dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("~/"));
        series_dir.push("anime");

        Self {
            series_dir,
            reset_dates_on_rewatch: false,
            episode: EpisodeConfig::default(),
            tui: TuiConfig::default(),
        }
    }
}

impl TomlFile for Config {
    fn filename() -> &'static str {
        "config"
    }

    fn save_dir() -> SaveDir {
        SaveDir::Config
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct EpisodeConfig {
    #[serde(rename = "percent_watched_to_progress")]
    pub pcnt_must_watch: Percentage,
    pub player: String,
    pub player_args: Vec<String>,
}

impl Default for EpisodeConfig {
    fn default() -> EpisodeConfig {
        EpisodeConfig {
            pcnt_must_watch: Percentage::new(50.0),
            player: String::from("mpv"),
            player_args: Vec::new(),
        }
    }
}

#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub struct Percentage(#[serde(with = "Percentage")] f32);

impl Percentage {
    pub fn new(value: f32) -> Percentage {
        Percentage(value / 100.0)
    }

    fn deserialize<'de, D>(de: D) -> result::Result<f32, D::Error>
    where
        D: Deserializer<'de>,
    {
        use std::fmt;

        struct PercentageVisitor;

        impl<'de> Visitor<'de> for PercentageVisitor {
            type Value = f32;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a positive percentage number")
            }

            fn visit_f32<E>(self, value: f32) -> result::Result<Self::Value, E>
            where
                E: de::Error,
            {
                if value.is_sign_negative() {
                    return Err(E::custom(format!(
                        "percentage must be greater than 0: {}",
                        value
                    )));
                }

                Ok(value / 100.0)
            }

            fn visit_f64<E>(self, value: f64) -> result::Result<Self::Value, E>
            where
                E: de::Error,
            {
                if value.is_sign_negative() {
                    return Err(E::custom(format!(
                        "percentage must be greater than 0: {}",
                        value
                    )));
                }

                Ok(value as f32 / 100.0)
            }
        }

        de.deserialize_f32(PercentageVisitor)
    }

    #[allow(clippy::trivially_copy_pass_by_ref)]
    fn serialize<S>(value: &f32, ser: S) -> result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        ser.serialize_f32(value * 100.0)
    }

    #[inline(always)]
    pub fn as_multiplier(self) -> f32 {
        self.0
    }
}

impl Mul<Percentage> for f32 {
    type Output = f32;

    fn mul(self, other: Percentage) -> Self::Output {
        self * other.as_multiplier()
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct TuiConfig {
    pub keys: TuiKeys,
}

impl Default for TuiConfig {
    fn default() -> TuiConfig {
        TuiConfig {
            keys: TuiKeys::default(),
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct TuiKeys {
    pub play_next_episode: char,
}

impl Default for TuiKeys {
    fn default() -> TuiKeys {
        TuiKeys {
            play_next_episode: '\n',
        }
    }
}
<commit_msg>anup: Auto-derive Default trait for TuiConfig<commit_after>use crate::err::Result;
use crate::file::{SaveDir, TomlFile};
use serde::de::{self, Deserializer, Visitor};
use serde::ser::Serializer;
use serde_derive::{Deserialize, Serialize};
use std::borrow::Cow;
use std::ops::Mul;
use std::path::{Path, PathBuf};
use std::result;

#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
    pub series_dir: PathBuf,
    pub reset_dates_on_rewatch: bool,
    pub episode: EpisodeConfig,
    pub tui: TuiConfig,
}

impl Config {
    pub fn new<P>(series_dir: P) -> Self
    where
        P: Into<PathBuf>,
    {
        Self {
            series_dir: series_dir.into(),
            ..Default::default()
        }
    }

    pub fn load_or_create() -> Result<Self> {
        match Self::load() {
            Ok(config) => Ok(config),
            Err(ref err) if err.is_file_nonexistant() => {
                let config = Config::default();
                config.save()?;
                Ok(config)
            }
            Err(err) => Err(err),
        }
    }

    pub fn stripped_path<'a, P>(&self, path: P) -> PathBuf
    where
        P: Into<Cow<'a, Path>>,
    {
        let path = path.into();

        match path.strip_prefix(&self.series_dir) {
            Ok(stripped) => stripped.into(),
            Err(_) => path.into_owned(),
        }
    }
}

impl Default for Config {
    fn default() -> Self {
        // Default series dir is ~/anime/
        let mut series_dir = dirs_next::home_dir().unwrap_or_else(|| PathBuf::from("~/"));
        series_dir.push("anime");

        Self {
            series_dir,
            reset_dates_on_rewatch: false,
            episode: EpisodeConfig::default(),
            tui: TuiConfig::default(),
        }
    }
}

impl TomlFile for Config {
    fn filename() -> &'static str {
        "config"
    }

    fn save_dir() -> SaveDir {
        SaveDir::Config
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct EpisodeConfig {
    #[serde(rename = "percent_watched_to_progress")]
    pub pcnt_must_watch: Percentage,
    pub player: String,
    pub player_args: Vec<String>,
}

impl Default for EpisodeConfig {
    fn default() -> EpisodeConfig {
        EpisodeConfig {
            pcnt_must_watch: Percentage::new(50.0),
            player: String::from("mpv"),
            player_args: Vec::new(),
        }
    }
}

#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub struct Percentage(#[serde(with = "Percentage")] f32);

impl Percentage {
    pub fn new(value: f32) -> Percentage {
        Percentage(value / 100.0)
    }

    fn deserialize<'de, D>(de: D) -> result::Result<f32, D::Error>
    where
        D: Deserializer<'de>,
    {
        use std::fmt;

        struct PercentageVisitor;

        impl<'de> Visitor<'de> for PercentageVisitor {
            type Value = f32;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a positive percentage number")
            }

            fn visit_f32<E>(self, value: f32) -> result::Result<Self::Value, E>
            where
                E: de::Error,
            {
                if value.is_sign_negative() {
                    return Err(E::custom(format!(
                        "percentage must be greater than 0: {}",
                        value
                    )));
                }

                Ok(value / 100.0)
            }

            fn visit_f64<E>(self, value: f64) -> result::Result<Self::Value, E>
            where
                E: de::Error,
            {
                if value.is_sign_negative() {
                    return Err(E::custom(format!(
                        "percentage must be greater than 0: {}",
                        value
                    )));
                }

                Ok(value as f32 / 100.0)
            }
        }

        de.deserialize_f32(PercentageVisitor)
    }

    #[allow(clippy::trivially_copy_pass_by_ref)]
    fn serialize<S>(value: &f32, ser: S) -> result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        ser.serialize_f32(value * 100.0)
    }

    #[inline(always)]
    pub fn as_multiplier(self) -> f32 {
        self.0
    }
}

impl Mul<Percentage> for f32 {
    type Output = f32;

    fn mul(self, other: Percentage) -> Self::Output {
        self * other.as_multiplier()
    }
}

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct TuiConfig {
    pub keys: TuiKeys,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct TuiKeys {
    pub play_next_episode: char,
}

impl Default for TuiKeys {
    fn default() -> TuiKeys {
        TuiKeys {
            play_next_episode: '\n',
        }
    }
}
<|endoftext|>


<commit_before>use shark;
use game_state;

pub static WATER_COLOR: [f32, ..4] = [0.0, 0.0, 0.45, 1.0];
pub static RADIUS: f64 = 0.1;
pub static SURFACE_Y: f64 = 0.8;
pub static INITIAL_GAME_STATE: game_state::GameState = game_state::Play;
pub static INITIAL_CAMERA_POS: [f64, ..2] = [0.0, 0.0];
pub static CAMERA_FOLLOW_PERCENTAGE: f64 = 0.2;

pub static YOU_WIN_TEXT: &'static str = "you win";
pub static YOU_WIN_TEXT_COLOR: [f32, ..4] = GREEN;
pub static YOU_WIN_POS: [f64, ..2] = [-0.42, 0.1];

pub static YOU_LOOSE_TEXT: &'static str = "you loose";
pub static YOU_LOOSE_TEXT_COLOR: [f32, ..4] = RED;
pub static YOU_LOOSE_POS: [f64, ..2] = [-0.55, 0.1];

pub static PLAYER_COLOR: [f32, ..4] = YELLOW;
pub static PLAYER_INITIAL_BLOOD: f64 = 1.0;
pub static PLAYER_INITIAL_AIR: f64 = 1.0;
pub static PLAYER_RADIUS: f64 = 0.1;
pub static PLAYER_SPEED_RIGHT: f64 = 0.1;
pub static PLAYER_SPEED_LEFT: f64 = 0.1;
pub static PLAYER_SPEED_UP: f64 = 0.1;
pub static PLAYER_SPEED_DOWN: f64 = 0.1;
pub static PLAYER_INITIAL_TWEEN_FACTOR: f64 = 0.0;
pub static PLAYER_TWEEN_SPEED: f64 = 1.0;

pub struct SharkSettings {
    pub speed_left: f64,
    pub speed_right: f64,
    pub speed_up: f64,
    pub speed_down: f64,
    pub initial_state: shark::SharkState,
    pub bite_damage: f64,
    pub sensor_distance: f64,
    pub attack_distance: f64,
    pub wait_seconds_before_initial_attack: f64,
    pub wait_seconds_before_repeat_attack: f64,
    pub test_color: [f32, ..4],
    pub radius: f64,
}

pub static SHARK_SETTINGS: SharkSettings = SharkSettings {
    speed_left: 0.1,
    speed_right: 0.1,
    speed_up: 0.1,
    speed_down: 0.1,
    initial_state: shark::Ignorant,
    bite_damage: 0.1,
    sensor_distance: 0.2,
    attack_distance: 2.0 * PLAYER_RADIUS,
    wait_seconds_before_initial_attack: 1.0,
    wait_seconds_before_repeat_attack: 1.0,
    test_color: BLACK,
    radius: 0.1,
};

pub static SHARK_SPEED_RIGHT: f64 = 0.1;
pub static SHARK_SPEED_LEFT: f64 = 0.1;
pub static SHARK_SPEED_UP: f64 = 0.1;
pub static SHARK_SPEED_DOWN: f64 = 0.1;

// shark 1.
pub static SHARK_1_SETTINGS: SharkSettings = SHARK_SETTINGS;
pub static SHARK_1_POS: [f64, ..2] = [-0.1, 0.1];

pub static BAR_RECTANGLE: [f64, ..4] = [0.3, -0.06, 1.5, 0.05];
pub static BAR_MARGIN: f64 = 0.01;
pub static BAR_TEXT_COLOR: [f32, ..4] = WHITE;

pub static AIR_BAR_INITIAL_VALUE: f64 = 0.5;
pub static AIR_BAR_POS: [f64, ..2] = [-0.9, 0.95];
pub static AIR_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static AIR_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_BLUE;
pub static AIR_BAR_BAR_COLOR: [f32, ..4] = LIGHT_BLUE;

pub static BLOOD_BAR_INITIAL_VALUE: f64 = 0.5;
pub static BLOOD_BAR_POS: [f64, ..2] = [-0.9, 0.85];
pub static BLOOD_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static BLOOD_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_RED;
pub static BLOOD_BAR_BAR_COLOR: [f32, ..4] = LIGHT_RED;

pub static BAR_BACKGROUND_HEIGHT: f64 = 0.275;
pub static BAR_BACKGROUND_COLOR: [f32, ..4] = [0.1, 0.1, 0.1, 0.9];
pub static BAR_BACKGROUND_COLOR_2: [f32, ..4] = [0.4, 0.4, 0.4, 0.8];
pub static BAR_BACKGROUND_MARGIN: f64 = 0.01;
pub static BAR_BACKGROUND_MARGIN_2: f64 = 0.02;

pub static BLACK: [f32, ..4] = [0.0, 0.0, 0.0, 1.0];
pub static WHITE: [f32, ..4] = [1.0, 1.0, 1.0, 1.0];
pub static GRAY: [f32, ..4] = [0.5, 0.5, 0.5, 1.0];
pub static DARK_GRAY: [f32, ..4] = [0.2, 0.2, 0.2, 1.0];

pub static RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];
pub static DARK_RED: [f32, ..4] = [0.5, 0.0, 0.0, 1.0];
pub static LIGHT_RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];

pub static GREEN: [f32, ..4] = [0.0, 1.0, 0.0, 1.0];

pub static BLUE: [f32, ..4] = [0.0, 0.0, 1.0, 1.0];
pub static DARK_BLUE: [f32, ..4] = [0.0, 0.0, 0.5, 1.0];
pub static LIGHT_BLUE: [f32, ..4] = [0.5, 0.5, 1.0, 1.0];

pub static YELLOW: [f32, ..4] = [0.0, 1.0, 1.0, 1.0];

pub static ORIGIN: [f64, ..2] = [0.0, 0.0];

<commit_msg>Made sharks swim faster<commit_after>use shark;
use game_state;

pub static WATER_COLOR: [f32, ..4] = [0.0, 0.0, 0.45, 1.0];
pub static RADIUS: f64 = 0.1;
pub static SURFACE_Y: f64 = 0.8;
pub static INITIAL_GAME_STATE: game_state::GameState = game_state::Play;
pub static INITIAL_CAMERA_POS: [f64, ..2] = [0.0, 0.0];
pub static CAMERA_FOLLOW_PERCENTAGE: f64 = 0.2;

pub static YOU_WIN_TEXT: &'static str = "you win";
pub static YOU_WIN_TEXT_COLOR: [f32, ..4] = GREEN;
pub static YOU_WIN_POS: [f64, ..2] = [-0.42, 0.1];

pub static YOU_LOOSE_TEXT: &'static str = "you loose";
pub static YOU_LOOSE_TEXT_COLOR: [f32, ..4] = RED;
pub static YOU_LOOSE_POS: [f64, ..2] = [-0.55, 0.1];

pub static PLAYER_COLOR: [f32, ..4] = YELLOW;
pub static PLAYER_INITIAL_BLOOD: f64 = 1.0;
pub static PLAYER_INITIAL_AIR: f64 = 1.0;
pub static PLAYER_RADIUS: f64 = 0.1;
pub static PLAYER_SPEED_RIGHT: f64 = 0.1;
pub static PLAYER_SPEED_LEFT: f64 = 0.1;
pub static PLAYER_SPEED_UP: f64 = 0.1;
pub static PLAYER_SPEED_DOWN: f64 = 0.1;
pub static PLAYER_INITIAL_TWEEN_FACTOR: f64 = 0.0;
pub static PLAYER_TWEEN_SPEED: f64 = 1.0;

pub struct SharkSettings {
    pub speed_left: f64,
    pub speed_right: f64,
    pub speed_up: f64,
    pub speed_down: f64,
    pub initial_state: shark::SharkState,
    pub bite_damage: f64,
    pub sensor_distance: f64,
    pub attack_distance: f64,
    pub wait_seconds_before_initial_attack: f64,
    pub wait_seconds_before_repeat_attack: f64,
    pub test_color: [f32, ..4],
    pub radius: f64,
}

pub static SHARK_OVERALL_SPEED: f64 = 2.0;
pub static SHARK_SETTINGS: SharkSettings = SharkSettings {
    speed_left: 0.1 * SHARK_OVERALL_SPEED,
    speed_right: 0.1 * SHARK_OVERALL_SPEED,
    speed_up: 0.1 * SHARK_OVERALL_SPEED,
    speed_down: 0.1 * SHARK_OVERALL_SPEED,
    initial_state: shark::Ignorant,
    bite_damage: 0.1,
    sensor_distance: 0.2,
    attack_distance: 2.0 * PLAYER_RADIUS,
    wait_seconds_before_initial_attack: 1.0,
    wait_seconds_before_repeat_attack: 1.0,
    test_color: BLACK,
    radius: 0.1,
};

pub static SHARK_SPEED_RIGHT: f64 = 0.1;
pub static SHARK_SPEED_LEFT: f64 = 0.1;
pub static SHARK_SPEED_UP: f64 = 0.1;
pub static SHARK_SPEED_DOWN: f64 = 0.1;

// shark 1.
pub static SHARK_1_SETTINGS: SharkSettings = SHARK_SETTINGS;
pub static SHARK_1_POS: [f64, ..2] = [-0.1, 0.1];

pub static BAR_RECTANGLE: [f64, ..4] = [0.3, -0.06, 1.5, 0.05];
pub static BAR_MARGIN: f64 = 0.01;
pub static BAR_TEXT_COLOR: [f32, ..4] = WHITE;

pub static AIR_BAR_INITIAL_VALUE: f64 = 0.5;
pub static AIR_BAR_POS: [f64, ..2] = [-0.9, 0.95];
pub static AIR_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static AIR_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_BLUE;
pub static AIR_BAR_BAR_COLOR: [f32, ..4] = LIGHT_BLUE;

pub static BLOOD_BAR_INITIAL_VALUE: f64 = 0.5;
pub static BLOOD_BAR_POS: [f64, ..2] = [-0.9, 0.85];
pub static BLOOD_BAR_TEXT_COLOR: [f32, ..4] = BAR_TEXT_COLOR;
pub static BLOOD_BAR_BACKGROUND_COLOR: [f32, ..4] = DARK_RED;
pub static BLOOD_BAR_BAR_COLOR: [f32, ..4] = LIGHT_RED;

pub static BAR_BACKGROUND_HEIGHT: f64 = 0.275;
pub static BAR_BACKGROUND_COLOR: [f32, ..4] = [0.1, 0.1, 0.1, 0.9];
pub static BAR_BACKGROUND_COLOR_2: [f32, ..4] = [0.4, 0.4, 0.4, 0.8];
pub static BAR_BACKGROUND_MARGIN: f64 = 0.01;
pub static BAR_BACKGROUND_MARGIN_2: f64 = 0.02;

pub static BLACK: [f32, ..4] = [0.0, 0.0, 0.0, 1.0];
pub static WHITE: [f32, ..4] = [1.0, 1.0, 1.0, 1.0];
pub static GRAY: [f32, ..4] = [0.5, 0.5, 0.5, 1.0];
pub static DARK_GRAY: [f32, ..4] = [0.2, 0.2, 0.2, 1.0];

pub static RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];
pub static DARK_RED: [f32, ..4] = [0.5, 0.0, 0.0, 1.0];
pub static LIGHT_RED: [f32, ..4] = [1.0, 0.0, 0.0, 1.0];

pub static GREEN: [f32, ..4] = [0.0, 1.0, 0.0, 1.0];

pub static BLUE: [f32, ..4] = [0.0, 0.0, 1.0, 1.0];
pub static DARK_BLUE: [f32, ..4] = [0.0, 0.0, 0.5, 1.0];
pub static LIGHT_BLUE: [f32, ..4] = [0.5, 0.5, 1.0, 1.0];

pub static YELLOW: [f32, ..4] = [0.0, 1.0, 1.0, 1.0];

pub static ORIGIN: [f64, ..2] = [0.0, 0.0];

<|endoftext|>


<commit_before>use std::mem::size_of;
use std::num::{NumCast, UnsignedInt};
use bitstream::Bitstream;
use error::{FlacError, FlacResult};

#[deriving(Copy)]
enum SubframeType {
    Constant,
    Verbatim,
    Fixed(u8),
    Lpc(u8)
}

#[deriving(Copy)]
struct SubframeHeader {
    sf_type: SubframeType,
    wasted_bits_per_sample: u8
}

fn read_subframe_header(input: &mut Bitstream) -> FlacResult<SubframeHeader> {
    // The first bit must be a 0 padding bit.
    if 0 != try!(input.read_leq_u8(1)) {
        return Err(FlacError::InvalidSubframeHeader);
    }

    // Next is a 6-bit subframe type.
    let sf_type = match try!(input.read_leq_u8(6)) {
        0 => SubframeType::Constant,
        1 => SubframeType::Verbatim,

        // Bit patterns 00001x, 0001xx and 01xxxx are reserved, this library
        // would not know how to handle them, so this is an error.
        n if (n & 0b111_110 == 0b000_010)
          || (n & 0b111_100 == 0b000_100)
          || (n & 0b110_000 == 0b010_000) => {
            return Err(FlacError::InvalidSubframeHeader);
        }

        n if n & 0b111_000 == 0b001_000 => {
            let order = n & 0b000_111;

            // A fixed frame has order up to 4, other bit patterns are reserved.
            if order > 4 { return Err(FlacError::InvalidSubframeHeader); }

            SubframeType::Fixed(order)
        }

        // The only possibility left is bit pattern 1xxxxx, an LPC subframe.
        n => {
            // The xxxxx bits are the order minus one.
            let order_mo = n & 0b011_111;
            SubframeType::Lpc(order_mo + 1)
        }
    };

    // Next bits indicates whether there are wasted bits per sample.
    let wastes_bits = 1 == try!(input.read_leq_u8(1));

    // If so, k - 1 zero bits follow, where k is the number of wasted bits.
    let wasted_bits = if !wastes_bits {
        0
    } else {
        let mut wbits = 1;
        while 1 != try!(input.read_leq_u8(1)) {
            wbits = wbits + 1;
        }
        wbits
    };

    let subframe_header = SubframeHeader {
        sf_type: sf_type,
        wasted_bits_per_sample: wasted_bits
    };
    Ok(subframe_header)
}

pub struct SubframeDecoder<'r> {
    block_size: u16,
    bits_per_sample: u8,
    header: SubframeHeader,
    input: &'r mut Bitstream<'r>
}

impl<'r> SubframeDecoder<'r> {
    pub fn new(block_size: u16,
               bits_per_sample: u8,
               input: &'r mut Bitstream<'r>)
               -> FlacResult<SubframeDecoder<'r>> {
        let header = try!(read_subframe_header(input));
        let decoder = SubframeDecoder {
            block_size: block_size,
            bits_per_sample: bits_per_sample,
            header: header,
            input: input
        };
        Ok(decoder)
    }

    /// Decodes the subframe into the provided buffer.
    ///
    /// The buffer must have _exactly_ the right size (the block size of the
    /// frame). The `Sample` type must be wide enough to accomodate for all
    /// bits per sample of the frame.
    pub fn decode<Sample>(&mut self, buffer: &mut [Sample]) -> FlacResult<()>
                          where Sample: UnsignedInt {
        // The sample type should be wide enough to accomodate for all bits of
        // the stream, but this can be verified at a higher level than here.
        // Still, it is a good idea to make the assumption explicit.
        //
        // TODO: the compiler refuses to compile the next line at the moment of
        // writing. Maybe in the future it will?
        // debug_assert!(self.bits_per_sample <= size_of<Sample>() * 8);

        // We assume that the buffer has the right size; obviously it cannot be
        // to small if we are to decode the entire subframe. Requiring it to
        // have the exact block size also ensures that there cannot be any
        // confusion about what happens to excess samples: there are none.
        debug_assert_eq!(self.block_size as uint, buffer.len());

        match self.header.sf_type {
            SubframeType::Constant => self.decode_constant(buffer),
            SubframeType::Verbatim => self.decode_verbatim(buffer),
            _ => Ok(()) // TODO: implement other decoders
        }
    }

    fn decode_constant<Sample>(&mut self, buffer: &mut [Sample])
                               -> FlacResult<()>
                               where Sample: UnsignedInt {
        // A constant block has <bits per sample> bits: the value of all
        // samples. The unwrap is safe, because it has been verified before
        // that the `Sample` type is wide enough for the bits per sample.
        let sample_u32 = try!(self.input.read_leq_u32(self.bits_per_sample));
        let sample = NumCast::from(sample_u32).unwrap();

        for s in buffer.iter_mut() {
            *s = sample;
        }

        Ok(())
    }

    fn decode_verbatim<Sample>(&mut self, buffer: &mut [Sample])
                               -> FlacResult<()>
                               where Sample: UnsignedInt {
        // A verbatim block stores samples without encoding whatsoever.
        for s in buffer.iter_mut() {
            // The unwrap is safe, because it has been verified before that the
            // `Sample` type is wide enough for the bits per sample.
            let sample_u32 = try!(self.input.read_leq_u32(self.bits_per_sample));
            *s = NumCast::from(sample_u32).unwrap();
        }

        Ok(())
    }
}
<commit_msg>refactor subframe decoder<commit_after>use std::num::{NumCast, UnsignedInt};
use bitstream::Bitstream;
use error::{FlacError, FlacResult};

#[deriving(Copy)]
enum SubframeType {
    Constant,
    Verbatim,
    Fixed(u8),
    Lpc(u8)
}

#[deriving(Copy)]
struct SubframeHeader {
    sf_type: SubframeType,
    wasted_bits_per_sample: u8
}

fn read_subframe_header(input: &mut Bitstream) -> FlacResult<SubframeHeader> {
    // The first bit must be a 0 padding bit.
    if 0 != try!(input.read_leq_u8(1)) {
        return Err(FlacError::InvalidSubframeHeader);
    }

    // Next is a 6-bit subframe type.
    let sf_type = match try!(input.read_leq_u8(6)) {
        0 => SubframeType::Constant,
        1 => SubframeType::Verbatim,

        // Bit patterns 00001x, 0001xx and 01xxxx are reserved, this library
        // would not know how to handle them, so this is an error.
        n if (n & 0b111_110 == 0b000_010)
          || (n & 0b111_100 == 0b000_100)
          || (n & 0b110_000 == 0b010_000) => {
            return Err(FlacError::InvalidSubframeHeader);
        }

        n if n & 0b111_000 == 0b001_000 => {
            let order = n & 0b000_111;

            // A fixed frame has order up to 4, other bit patterns are reserved.
            if order > 4 { return Err(FlacError::InvalidSubframeHeader); }

            SubframeType::Fixed(order)
        }

        // The only possibility left is bit pattern 1xxxxx, an LPC subframe.
        n => {
            // The xxxxx bits are the order minus one.
            let order_mo = n & 0b011_111;
            SubframeType::Lpc(order_mo + 1)
        }
    };

    // Next bits indicates whether there are wasted bits per sample.
    let wastes_bits = 1 == try!(input.read_leq_u8(1));

    // If so, k - 1 zero bits follow, where k is the number of wasted bits.
    let wasted_bits = if !wastes_bits {
        0
    } else {
        let mut wbits = 1;
        while 1 != try!(input.read_leq_u8(1)) {
            wbits = wbits + 1;
        }
        wbits
    };

    let subframe_header = SubframeHeader {
        sf_type: sf_type,
        wasted_bits_per_sample: wasted_bits
    };
    Ok(subframe_header)
}

pub struct SubframeDecoder<'r, Sample> {
    bits_per_sample: u8,
    input: &'r mut Bitstream<'r>
}

impl<'r, Sample> SubframeDecoder<'r, Sample>
where Sample: UnsignedInt {
    /// Creates a new subframe decoder capable of decoding several subframes.
    ///
    /// The size of the `Sample` type must be wide enough to accomodate for
    /// `bits_per_sample` bits per sample.
    pub fn new(bits_per_sample: u8, input: &'r mut Bitstream<'r>)
               -> SubframeDecoder<'r, Sample> {
        // The sample type should be wide enough to accomodate for all bits of
        // the stream, but this can be verified at a higher level than here.
        // Still, it is a good idea to make the assumption explicit.
        //
        // TODO: the compiler refuses to compile the next line at the moment of
        // writing. Maybe in the future it will?
        // use std::mem::size_of;
        // debug_assert!(bits_per_sample <= size_of<Sample>() * 8);

        SubframeDecoder { bits_per_sample: bits_per_sample, input: input }
    }

    /// Decodes the subframe into the provided block-size buffer.
    ///
    /// It is assumed that the length of the buffer is the block size.
    pub fn decode(&mut self, buffer: &mut [Sample]) -> FlacResult<()> {
        // First up is the subframe header.
        let header = try!(read_subframe_header(self.input));

        // Then decode the subframe, properly per type.
        match header.sf_type {
            SubframeType::Constant => try!(self.decode_constant(buffer)),
            SubframeType::Verbatim => try!(self.decode_verbatim(buffer)),
            _ => { } // TODO: implement other decoders
        }

        // Finally, everything must be shifted by 'wasted bits per sample' to
        // the left.
        if header.wasted_bits_per_sample > 0 {
            for s in buffer.iter_mut() {
                *s = *s << header.wasted_bits_per_sample as uint;
            }
        }

        Ok(())
    }

    fn decode_constant(&mut self, buffer: &mut [Sample]) -> FlacResult<()> {
        // A constant block has <bits per sample> bits: the value of all
        // samples. The unwrap is safe, because it has been verified before
        // that the `Sample` type is wide enough for the bits per sample.
        let sample_u32 = try!(self.input.read_leq_u32(self.bits_per_sample));
        let sample = NumCast::from(sample_u32).unwrap();

        for s in buffer.iter_mut() {
            *s = sample;
        }

        Ok(())
    }

    fn decode_verbatim(&mut self, buffer: &mut [Sample]) -> FlacResult<()> {
        // A verbatim block stores samples without encoding whatsoever.
        for s in buffer.iter_mut() {
            // The unwrap is safe, because it has been verified before that the
            // `Sample` type is wide enough for the bits per sample.
            let sample_u32 = try!(self.input.read_leq_u32(self.bits_per_sample));
            *s = NumCast::from(sample_u32).unwrap();
        }

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


<commit_before>//! Common utilities shared by unit tests.
#![cfg(test)]

use std::collections::HashSet;

use nalgebra::{Point3, Vector3};

use aabb::{AABB, Bounded};
use bounding_hierarchy::{BoundingHierarchy, BHShape};
use ray::Ray;

/// A vector represented as a tuple
pub type TupleVec = (f32, f32, f32);

/// Convert a `TupleVec` to a `nalgebra` point.
pub fn tuple_to_point(tpl: &TupleVec) -> Point3<f32> {
    Point3::new(tpl.0, tpl.1, tpl.2)
}

/// Convert a `TupleVec` to a `nalgebra` vector.
pub fn tuple_to_vector(tpl: &TupleVec) -> Vector3<f32> {
    Vector3::new(tpl.0, tpl.1, tpl.2)
}

/// Define some `Bounded` structure.
pub struct UnitBox {
    pub id: i32,
    pub pos: Point3<f32>,
    node_index: usize,
    pub has_good_bh_position: bool, // If the XBox's node in the BVH gets moved, we panic if this is true
}

/// `UnitBox`'s `AABB`s are unit `AABB`s centered on the given x-position.
impl Bounded for UnitBox {
    fn aabb(&self) -> AABB {
        let min = self.pos + Vector3::new(-0.5, -0.5, -0.5);
        let max = self.pos + Vector3::new(0.5, 0.5, 0.5);
        AABB::with_bounds(min, max)
    }
}

impl BHShape for UnitBox {
    fn set_bh_node_index(&mut self, index: usize) {
        self.node_index = index;
        if self.has_good_bh_position {
            panic!("An UnitBox's BVHNode has been moved even though it shouldn't have.");
        } else {
            self.has_good_bh_position = true;
        }
    }

    fn bh_node_index(&self) -> usize {
        self.node_index
    }
}

/// Generate 21 `UnitBox`s along the X axis centered on whole numbers (-10,9,..,10).
/// The index is set to the rounded x-coordinate of the box center.
pub fn generate_aligned_boxes() -> Vec<UnitBox> {
    // Create 21 boxes along the x-axis
    let mut shapes = Vec::new();
    for x in -10..11 {
        shapes.push(UnitBox {
            id: x,
            pos: Point3::new(x as f32, 0.0, 0.0),
            node_index: 0,
            has_good_bh_position: false,
        });
    }
    shapes
}

/// Creates a `BoundingHierarchy` for a fixed scene structure.
pub fn build_some_bh<BH: BoundingHierarchy>() -> (Vec<UnitBox>, BH) {
    let mut boxes = generate_aligned_boxes();
    let bh = BH::build(&mut boxes);
    (boxes, bh)
}

/// Given a ray, a bounding hierarchy, the complete list of shapes in the scene and a list of
/// expected hits, verifies, whether the ray hits only the expected shapes.
fn traverse_and_verify<BH: BoundingHierarchy>(ray_origin: Point3<f32>,
                                              ray_direction: Vector3<f32>,
                                              all_shapes: &Vec<UnitBox>,
                                              bh: &BH,
                                              expected_shapes: &HashSet<i32>) {
    let ray = Ray::new(ray_origin, ray_direction);
    let hit_shapes = bh.traverse(&ray, all_shapes);

    assert_eq!(expected_shapes.len(), hit_shapes.len());
    for shape in hit_shapes {
        assert!(expected_shapes.contains(&shape.id));
    }
}

/// Perform some fixed intersection tests on BH structures.
pub fn traverse_some_bh<BH: BoundingHierarchy>() {
    let (all_shapes, bh) = build_some_bh::<BH>();

    {
        // Define a ray which traverses the x-axis from afar.
        let origin = Point3::new(-1000.0, 0.0, 0.0);
        let direction = Vector3::new(1.0, 0.0, 0.0);
        let mut expected_shapes = HashSet::new();

        // It should hit everything.
        for id in -10..11 {
            expected_shapes.insert(id);
        }
        traverse_and_verify(origin, direction, &all_shapes, &bh, &expected_shapes);
    }

    {
        // Define a ray which traverses the y-axis from afar.
        let origin = Point3::new(0.0, -1000.0, 0.0);
        let direction = Vector3::new(0.0, 1.0, 0.0);

        // It should hit only one box.
        let mut expected_shapes = HashSet::new();
        expected_shapes.insert(0);
        traverse_and_verify(origin, direction, &all_shapes, &bh, &expected_shapes);
    }

    {
        // Define a ray which intersects the x-axis diagonally.
        let origin = Point3::new(6.0, 0.5, 0.0);
        let direction = Vector3::new(-2.0, -1.0, 0.0);

        // It should hit exactly three boxes.
        let mut expected_shapes = HashSet::new();
        expected_shapes.insert(4);
        expected_shapes.insert(5);
        expected_shapes.insert(6);
        traverse_and_verify(origin, direction, &all_shapes, &bh, &expected_shapes);
    }
}

/// A triangle struct. Instance of a more complex `Bounded` primitive.
pub struct Triangle {
    pub a: Point3<f32>,
    pub b: Point3<f32>,
    pub c: Point3<f32>,
    aabb: AABB,
    node_index: usize,
    has_good_bh_position: bool,
}

impl Triangle {
    fn new(a: Point3<f32>, b: Point3<f32>, c: Point3<f32>) -> Triangle {
        Triangle {
            a: a,
            b: b,
            c: c,
            aabb: AABB::empty().grow(&a).grow(&b).grow(&c),
            node_index: 0,
            has_good_bh_position: false,
        }
    }
}

impl Bounded for Triangle {
    fn aabb(&self) -> AABB {
        self.aabb
    }
}

impl BHShape for Triangle {
    fn set_bh_node_index(&mut self, index: usize) {
        self.node_index = index;
    }

    fn bh_node_index(&self) -> usize {
        self.node_index
    }
}

/// Creates a unit size cube centered at `pos` and pushes the triangles to `shapes`.
fn push_cube(pos: Point3<f32>, shapes: &mut Vec<Triangle>) {
    let top_front_right = pos + Vector3::new(0.5, 0.5, -0.5);
    let top_back_right = pos + Vector3::new(0.5, 0.5, 0.5);
    let top_back_left = pos + Vector3::new(-0.5, 0.5, 0.5);
    let top_front_left = pos + Vector3::new(-0.5, 0.5, -0.5);
    let bottom_front_right = pos + Vector3::new(0.5, -0.5, -0.5);
    let bottom_back_right = pos + Vector3::new(0.5, -0.5, 0.5);
    let bottom_back_left = pos + Vector3::new(-0.5, -0.5, 0.5);
    let bottom_front_left = pos + Vector3::new(-0.5, -0.5, -0.5);

    shapes.push(Triangle::new(top_back_right, top_front_right, top_front_left));
    shapes.push(Triangle::new(top_front_left, top_back_left, top_back_right));
    shapes.push(Triangle::new(bottom_front_left, bottom_front_right, bottom_back_right));
    shapes.push(Triangle::new(bottom_back_right, bottom_back_left, bottom_front_left));
    shapes.push(Triangle::new(top_back_left, top_front_left, bottom_front_left));
    shapes.push(Triangle::new(bottom_front_left, bottom_back_left, top_back_left));
    shapes.push(Triangle::new(bottom_front_right, top_front_right, top_back_right));
    shapes.push(Triangle::new(top_back_right, bottom_back_right, bottom_front_right));
    shapes.push(Triangle::new(top_front_left, top_front_right, bottom_front_right));
    shapes.push(Triangle::new(bottom_front_right, bottom_front_left, top_front_left));
    shapes.push(Triangle::new(bottom_back_right, top_back_right, top_back_left));
    shapes.push(Triangle::new(top_back_left, bottom_back_left, bottom_back_right));
}

/// Implementation of splitmix64.
/// For reference see: http://xoroshiro.di.unimi.it/splitmix64.c
fn splitmix64(x: &mut u64) -> u64 {
    *x = x.wrapping_add(0x9E3779B97F4A7C15u64);
    let mut z = *x;
    z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9u64);
    z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EBu64);
    z ^ (z >> 31)
}

/// Generates a new Point3, mutates the seed.
fn next_point3(seed: &mut u64) -> Point3<f32> {
    let u = splitmix64(seed);
    let a = ((u >> 32) & 0xFFFFFFFF) as i64 - 0x80000000;
    let b = (u & 0xFFFFFFFF) as i64 - 0x80000000;
    let c = a ^ b.rotate_left(6);
    Point3::new(a as f32, b as f32, c as f32) / 100_000.0
}

/// Creates `n` deterministic random cubes. Returns the `Vec` of surface `Triangle`s.
pub fn create_n_cubes(n: u64) -> Vec<Triangle> {
    let mut vec = Vec::new();
    let mut seed = 0;

    for _ in 0..n {
        push_cube(next_point3(&mut seed), &mut vec);
    }
    vec
}

/// Creates a `Ray` from the random `seed`. Mutates the `seed`.
pub fn create_ray(seed: &mut u64) -> Ray {
    let origin = next_point3(seed);
    let direction = next_point3(seed).to_vector();
    Ray::new(origin, direction)
}

/// Benchmark the construction of a `BoundingHierarchy` with 120,000 triangles.
fn build_n_triangles_bh<T: BoundingHierarchy>(n: u64, b: &mut ::test::Bencher) {
    let mut triangles = create_n_cubes(n);
    b.iter(|| {
        T::build(&mut triangles);
    });
}

/// Benchmark the construction of a `BoundingHierarchy` with 1,200 triangles.
pub fn build_1200_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    build_n_triangles_bh::<T>(100, b);
}

/// Benchmark the construction of a `BoundingHierarchy` with 12,000 triangles.
pub fn build_12k_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    build_n_triangles_bh::<T>(1_000, b);
}

/// Benchmark the construction of a `BoundingHierarchy` with 120,000 triangles.
pub fn build_120k_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    build_n_triangles_bh::<T>(10_000, b);
}

#[bench]
/// Benchmark intersecting 120,000 triangles directly.
fn bench_intersect_120k_triangles_list(b: &mut ::test::Bencher) {
    let triangles = create_n_cubes(10_000);
    let mut seed = 0;

    b.iter(|| {
        let ray = create_ray(&mut seed);

        // Iterate over the list of triangles.
        for triangle in &triangles {
            ray.intersects_triangle(&triangle.a, &triangle.b, &triangle.c);
        }
    });
}

#[bench]
/// Benchmark intersecting 120,000 triangles with preceeding `AABB` tests.
fn bench_intersect_120k_triangles_list_aabb(b: &mut ::test::Bencher) {
    let triangles = create_n_cubes(10_000);
    let mut seed = 0;

    b.iter(|| {
        let ray = create_ray(&mut seed);

        // Iterate over the list of triangles.
        for triangle in &triangles {
            // First test whether the ray intersects the AABB of the triangle.
            if ray.intersects_aabb(&triangle.aabb()) {
                ray.intersects_triangle(&triangle.a, &triangle.b, &triangle.c);
            }
        }
    });
}

/// Benchmark the traversal of a `BoundingHierarchy` with `n` triangles.
pub fn intersect_n_triangles<T: BoundingHierarchy>(n: u64, b: &mut ::test::Bencher) {
    let mut triangles = create_n_cubes(n);
    let structure = T::build(&mut triangles);
    let mut seed = 0;

    b.iter(|| {
        let ray = create_ray(&mut seed);

        // Traverse the `BoundingHierarchy` recursively.
        let hits = structure.traverse(&ray, &triangles);

        // Traverse the resulting list of positive AABB tests
        for triangle in &hits {
            ray.intersects_triangle(&triangle.a, &triangle.b, &triangle.c);
        }
    });
}

/// Benchmark the traversal of a `BoundingHierarchy` with 1,200 triangles.
pub fn intersect_1200_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    intersect_n_triangles::<T>(100, b);
}

/// Benchmark the traversal of a `BoundingHierarchy` with 12,000 triangles.
pub fn intersect_12k_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    intersect_n_triangles::<T>(1_000, b);
}

/// Benchmark the traversal of a `BoundingHierarchy` with 120,000 triangles.
pub fn intersect_120k_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    intersect_n_triangles::<T>(10_000, b);
}
<commit_msg>Update comments<commit_after>//! Common utilities shared by unit tests.
#![cfg(test)]

use std::collections::HashSet;

use nalgebra::{Point3, Vector3};

use aabb::{AABB, Bounded};
use bounding_hierarchy::{BoundingHierarchy, BHShape};
use ray::Ray;

/// A vector represented as a tuple
pub type TupleVec = (f32, f32, f32);

/// Convert a `TupleVec` to a `nalgebra` point.
pub fn tuple_to_point(tpl: &TupleVec) -> Point3<f32> {
    Point3::new(tpl.0, tpl.1, tpl.2)
}

/// Convert a `TupleVec` to a `nalgebra` vector.
pub fn tuple_to_vector(tpl: &TupleVec) -> Vector3<f32> {
    Vector3::new(tpl.0, tpl.1, tpl.2)
}

/// Define some `Bounded` structure.
pub struct UnitBox {
    pub id: i32,
    pub pos: Point3<f32>,
    node_index: usize,
    // If the XBox's node in the BVH gets moved, we panic if this is true.
    // For testing bvh optimization.
    pub has_good_bh_position: bool,
}

/// `UnitBox`'s `AABB`s are unit `AABB`s centered on the box's position.
impl Bounded for UnitBox {
    fn aabb(&self) -> AABB {
        let min = self.pos + Vector3::new(-0.5, -0.5, -0.5);
        let max = self.pos + Vector3::new(0.5, 0.5, 0.5);
        AABB::with_bounds(min, max)
    }
}

impl BHShape for UnitBox {
    fn set_bh_node_index(&mut self, index: usize) {
        self.node_index = index;
        if self.has_good_bh_position {
            panic!("An UnitBox's BVHNode has been moved even though it shouldn't have.");
        } else {
            self.has_good_bh_position = true;
        }
    }

    fn bh_node_index(&self) -> usize {
        self.node_index
    }
}

/// Generate 21 `UnitBox`s along the X axis centered on whole numbers (-10,9,..,10).
/// The index is set to the rounded x-coordinate of the box center.
pub fn generate_aligned_boxes() -> Vec<UnitBox> {
    // Create 21 boxes along the x-axis
    let mut shapes = Vec::new();
    for x in -10..11 {
        shapes.push(UnitBox {
            id: x,
            pos: Point3::new(x as f32, 0.0, 0.0),
            node_index: 0,
            has_good_bh_position: false,
        });
    }
    shapes
}

/// Creates a `BoundingHierarchy` for a fixed scene structure.
pub fn build_some_bh<BH: BoundingHierarchy>() -> (Vec<UnitBox>, BH) {
    let mut boxes = generate_aligned_boxes();
    let bh = BH::build(&mut boxes);
    (boxes, bh)
}

/// Given a ray, a bounding hierarchy, the complete list of shapes in the scene and a list of
/// expected hits, verifies, whether the ray hits only the expected shapes.
fn traverse_and_verify<BH: BoundingHierarchy>(ray_origin: Point3<f32>,
                                              ray_direction: Vector3<f32>,
                                              all_shapes: &Vec<UnitBox>,
                                              bh: &BH,
                                              expected_shapes: &HashSet<i32>) {
    let ray = Ray::new(ray_origin, ray_direction);
    let hit_shapes = bh.traverse(&ray, all_shapes);

    assert_eq!(expected_shapes.len(), hit_shapes.len());
    for shape in hit_shapes {
        assert!(expected_shapes.contains(&shape.id));
    }
}

/// Perform some fixed intersection tests on BH structures.
pub fn traverse_some_bh<BH: BoundingHierarchy>() {
    let (all_shapes, bh) = build_some_bh::<BH>();

    {
        // Define a ray which traverses the x-axis from afar.
        let origin = Point3::new(-1000.0, 0.0, 0.0);
        let direction = Vector3::new(1.0, 0.0, 0.0);
        let mut expected_shapes = HashSet::new();

        // It should hit everything.
        for id in -10..11 {
            expected_shapes.insert(id);
        }
        traverse_and_verify(origin, direction, &all_shapes, &bh, &expected_shapes);
    }

    {
        // Define a ray which traverses the y-axis from afar.
        let origin = Point3::new(0.0, -1000.0, 0.0);
        let direction = Vector3::new(0.0, 1.0, 0.0);

        // It should hit only one box.
        let mut expected_shapes = HashSet::new();
        expected_shapes.insert(0);
        traverse_and_verify(origin, direction, &all_shapes, &bh, &expected_shapes);
    }

    {
        // Define a ray which intersects the x-axis diagonally.
        let origin = Point3::new(6.0, 0.5, 0.0);
        let direction = Vector3::new(-2.0, -1.0, 0.0);

        // It should hit exactly three boxes.
        let mut expected_shapes = HashSet::new();
        expected_shapes.insert(4);
        expected_shapes.insert(5);
        expected_shapes.insert(6);
        traverse_and_verify(origin, direction, &all_shapes, &bh, &expected_shapes);
    }
}

/// A triangle struct. Instance of a more complex `Bounded` primitive.
pub struct Triangle {
    pub a: Point3<f32>,
    pub b: Point3<f32>,
    pub c: Point3<f32>,
    aabb: AABB,
    node_index: usize,
    has_good_bh_position: bool,
}

impl Triangle {
    fn new(a: Point3<f32>, b: Point3<f32>, c: Point3<f32>) -> Triangle {
        Triangle {
            a: a,
            b: b,
            c: c,
            aabb: AABB::empty().grow(&a).grow(&b).grow(&c),
            node_index: 0,
            has_good_bh_position: false,
        }
    }
}

impl Bounded for Triangle {
    fn aabb(&self) -> AABB {
        self.aabb
    }
}

impl BHShape for Triangle {
    fn set_bh_node_index(&mut self, index: usize) {
        self.node_index = index;
    }

    fn bh_node_index(&self) -> usize {
        self.node_index
    }
}

/// Creates a unit size cube centered at `pos` and pushes the triangles to `shapes`.
fn push_cube(pos: Point3<f32>, shapes: &mut Vec<Triangle>) {
    let top_front_right = pos + Vector3::new(0.5, 0.5, -0.5);
    let top_back_right = pos + Vector3::new(0.5, 0.5, 0.5);
    let top_back_left = pos + Vector3::new(-0.5, 0.5, 0.5);
    let top_front_left = pos + Vector3::new(-0.5, 0.5, -0.5);
    let bottom_front_right = pos + Vector3::new(0.5, -0.5, -0.5);
    let bottom_back_right = pos + Vector3::new(0.5, -0.5, 0.5);
    let bottom_back_left = pos + Vector3::new(-0.5, -0.5, 0.5);
    let bottom_front_left = pos + Vector3::new(-0.5, -0.5, -0.5);

    shapes.push(Triangle::new(top_back_right, top_front_right, top_front_left));
    shapes.push(Triangle::new(top_front_left, top_back_left, top_back_right));
    shapes.push(Triangle::new(bottom_front_left, bottom_front_right, bottom_back_right));
    shapes.push(Triangle::new(bottom_back_right, bottom_back_left, bottom_front_left));
    shapes.push(Triangle::new(top_back_left, top_front_left, bottom_front_left));
    shapes.push(Triangle::new(bottom_front_left, bottom_back_left, top_back_left));
    shapes.push(Triangle::new(bottom_front_right, top_front_right, top_back_right));
    shapes.push(Triangle::new(top_back_right, bottom_back_right, bottom_front_right));
    shapes.push(Triangle::new(top_front_left, top_front_right, bottom_front_right));
    shapes.push(Triangle::new(bottom_front_right, bottom_front_left, top_front_left));
    shapes.push(Triangle::new(bottom_back_right, top_back_right, top_back_left));
    shapes.push(Triangle::new(top_back_left, bottom_back_left, bottom_back_right));
}

/// Implementation of splitmix64.
/// For reference see: http://xoroshiro.di.unimi.it/splitmix64.c
fn splitmix64(x: &mut u64) -> u64 {
    *x = x.wrapping_add(0x9E3779B97F4A7C15u64);
    let mut z = *x;
    z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9u64);
    z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EBu64);
    z ^ (z >> 31)
}

/// Generates a new Point3, mutates the seed.
fn next_point3(seed: &mut u64) -> Point3<f32> {
    let u = splitmix64(seed);
    let a = ((u >> 32) & 0xFFFFFFFF) as i64 - 0x80000000;
    let b = (u & 0xFFFFFFFF) as i64 - 0x80000000;
    let c = a ^ b.rotate_left(6);
    Point3::new(a as f32, b as f32, c as f32) / 100_000.0
}

/// Creates `n` deterministic random cubes. Returns the `Vec` of surface `Triangle`s.
pub fn create_n_cubes(n: u64) -> Vec<Triangle> {
    let mut vec = Vec::new();
    let mut seed = 0;

    for _ in 0..n {
        push_cube(next_point3(&mut seed), &mut vec);
    }
    vec
}

/// Creates a `Ray` from the random `seed`. Mutates the `seed`.
pub fn create_ray(seed: &mut u64) -> Ray {
    let origin = next_point3(seed);
    let direction = next_point3(seed).to_vector();
    Ray::new(origin, direction)
}

/// Benchmark the construction of a `BoundingHierarchy` with 120,000 triangles.
fn build_n_triangles_bh<T: BoundingHierarchy>(n: u64, b: &mut ::test::Bencher) {
    let mut triangles = create_n_cubes(n);
    b.iter(|| {
        T::build(&mut triangles);
    });
}

/// Benchmark the construction of a `BoundingHierarchy` with 1,200 triangles.
pub fn build_1200_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    build_n_triangles_bh::<T>(100, b);
}

/// Benchmark the construction of a `BoundingHierarchy` with 12,000 triangles.
pub fn build_12k_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    build_n_triangles_bh::<T>(1_000, b);
}

/// Benchmark the construction of a `BoundingHierarchy` with 120,000 triangles.
pub fn build_120k_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    build_n_triangles_bh::<T>(10_000, b);
}

#[bench]
/// Benchmark intersecting 120,000 triangles directly.
fn bench_intersect_120k_triangles_list(b: &mut ::test::Bencher) {
    let triangles = create_n_cubes(10_000);
    let mut seed = 0;

    b.iter(|| {
        let ray = create_ray(&mut seed);

        // Iterate over the list of triangles.
        for triangle in &triangles {
            ray.intersects_triangle(&triangle.a, &triangle.b, &triangle.c);
        }
    });
}

#[bench]
/// Benchmark intersecting 120,000 triangles with preceeding `AABB` tests.
fn bench_intersect_120k_triangles_list_aabb(b: &mut ::test::Bencher) {
    let triangles = create_n_cubes(10_000);
    let mut seed = 0;

    b.iter(|| {
        let ray = create_ray(&mut seed);

        // Iterate over the list of triangles.
        for triangle in &triangles {
            // First test whether the ray intersects the AABB of the triangle.
            if ray.intersects_aabb(&triangle.aabb()) {
                ray.intersects_triangle(&triangle.a, &triangle.b, &triangle.c);
            }
        }
    });
}

/// Benchmark the traversal of a `BoundingHierarchy` with `n` triangles.
pub fn intersect_n_triangles<T: BoundingHierarchy>(n: u64, b: &mut ::test::Bencher) {
    let mut triangles = create_n_cubes(n);
    let structure = T::build(&mut triangles);
    let mut seed = 0;

    b.iter(|| {
        let ray = create_ray(&mut seed);

        // Traverse the `BoundingHierarchy` recursively.
        let hits = structure.traverse(&ray, &triangles);

        // Traverse the resulting list of positive AABB tests
        for triangle in &hits {
            ray.intersects_triangle(&triangle.a, &triangle.b, &triangle.c);
        }
    });
}

/// Benchmark the traversal of a `BoundingHierarchy` with 1,200 triangles.
pub fn intersect_1200_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    intersect_n_triangles::<T>(100, b);
}

/// Benchmark the traversal of a `BoundingHierarchy` with 12,000 triangles.
pub fn intersect_12k_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    intersect_n_triangles::<T>(1_000, b);
}

/// Benchmark the traversal of a `BoundingHierarchy` with 120,000 triangles.
pub fn intersect_120k_triangles_bh<T: BoundingHierarchy>(b: &mut ::test::Bencher) {
    intersect_n_triangles::<T>(10_000, b);
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::codemap::Span;
use std::collections::hashmap;
use std::gc::Gc;

pub enum AttributeValue {
  UIntValue(uint),
  StrValue(String),
  RefValue(String),
}

pub struct Attribute {
  pub value: AttributeValue,
  pub key_span: Span,
  pub value_span: Span,
}

impl Attribute {
  pub fn new(value: AttributeValue, key_span: Span, value_span: Span)
      -> Attribute {
    Attribute {
      value: value,
      key_span: key_span,
      value_span: value_span,
    }
  }
}

pub struct Node {
  pub name: Option<String>,
  pub name_span: Span,

  pub path: String,
  pub path_span: Span,

  pub attributes: hashmap::HashMap<String, Attribute>,

  pub subnodes: Vec<Gc<Node>>,
}

impl Node {
  pub fn new(name: Option<String>, name_span: Span, path: String,
      path_span: Span) -> Node {
    Node {
      name: name,
      name_span: name_span,
      path: path,
      path_span: path_span,
      attributes: hashmap::HashMap::new(),
      subnodes: Vec::new(),
    }
  }

  pub fn get_string_attr<'a>(&'a self, key: &str) -> Option<&'a String> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      StrValue(ref s) => Some(s),
      _ => None,
    })
  }

  pub fn get_int_attr(&self, key: &str) -> Option<uint> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      UIntValue(ref u) => Some(*u),
      _ => None,
    })
  }

  pub fn get_ref_attr<'a>(&'a self, key: &str) -> Option<&'a String> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      RefValue(ref s) => Some(s),
      _ => None,
    })
  }
}

pub struct PlatformTree {
  pub nodes: Vec<Gc<Node>>,
}

impl PlatformTree {
  pub fn new(nodes: Vec<Gc<Node>>) -> PlatformTree {
    PlatformTree {nodes: nodes}
  }
}
<commit_msg>Added deriving(Show) to node::* structs.<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syntax::codemap::Span;
use std::collections::hashmap;
use std::gc::Gc;

#[deriving(Show)]
pub enum AttributeValue {
  UIntValue(uint),
  StrValue(String),
  RefValue(String),
}

#[deriving(Show)]
pub struct Attribute {
  pub value: AttributeValue,
  pub key_span: Span,
  pub value_span: Span,
}

impl Attribute {
  pub fn new(value: AttributeValue, key_span: Span, value_span: Span)
      -> Attribute {
    Attribute {
      value: value,
      key_span: key_span,
      value_span: value_span,
    }
  }
}

#[deriving(Show)]
pub struct Node {
  pub name: Option<String>,
  pub name_span: Span,

  pub path: String,
  pub path_span: Span,

  pub attributes: hashmap::HashMap<String, Attribute>,

  pub subnodes: Vec<Gc<Node>>,
}

impl Node {
  pub fn new(name: Option<String>, name_span: Span, path: String,
      path_span: Span) -> Node {
    Node {
      name: name,
      name_span: name_span,
      path: path,
      path_span: path_span,
      attributes: hashmap::HashMap::new(),
      subnodes: Vec::new(),
    }
  }

  pub fn get_string_attr<'a>(&'a self, key: &str) -> Option<&'a String> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      StrValue(ref s) => Some(s),
      _ => None,
    })
  }

  pub fn get_int_attr(&self, key: &str) -> Option<uint> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      UIntValue(ref u) => Some(*u),
      _ => None,
    })
  }

  pub fn get_ref_attr<'a>(&'a self, key: &str) -> Option<&'a String> {
    self.attributes.find(&key.to_str()).and_then(|av| match av.value {
      RefValue(ref s) => Some(s),
      _ => None,
    })
  }
}

#[deriving(Show)]
pub struct PlatformTree {
  pub nodes: Vec<Gc<Node>>,
}

impl PlatformTree {
  pub fn new(nodes: Vec<Gc<Node>>) -> PlatformTree {
    PlatformTree {nodes: nodes}
  }
}
<|endoftext|>