<commit_before>// Copyright 2015 The tiny-http Contributors
//
// 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 std::ascii::AsciiExt;

use std::io::Error as IoError;
use std::io::{self, Cursor, Read, Write, ErrorKind};

use std::net::SocketAddr;
use std::fmt;
use std::str::FromStr;

use {Header, HTTPVersion, Method, Response, StatusCode};
use util::EqualReader;
use chunked_transfer::Decoder;

/// Represents an HTTP request made by a client.
///
/// A `Request` object is what is produced by the server, and is your what
/// your code must analyse and answer.
///
/// This object implements the `Send` trait, therefore you can dispatch your requests to
/// worker threads.
///
/// # Pipelining
///
/// If a client sends multiple requests in a row (without waiting for the response), then you will
/// get multiple `Request` objects simultaneously. This is called *requests pipelining*.
/// Tiny-http automatically reorders the responses so that you don't need to worry about the order
/// in which you call `respond` or `into_writer`.
///
/// This mechanic is disabled if:
///
///  - The body of a request is large enough (handling requires pipelining requires storing the
///    body of the request in a buffer ; if the body is too big, tiny-http will avoid doing that)
///  - A request sends a `Expect: 100-continue` header (which means that the client waits to
///    know whether its body will be processed before sending it)
///  - A request sends a `Connection: close` header or `Connection: upgrade` header (used for
///    websockets), which indicates that this is the last request that will be received on this
///    connection
///
/// # Automatic cleanup
///
/// If a `Request` object is destroyed without `into_writer` or `respond` being called,
/// an empty response with a 500 status code (internal server error) will automatically be
/// sent back to the client.
/// This means that if your code fails during the handling of a request, this "internal server
/// error" response will automatically be sent during the stack unwinding.
pub struct Request {
    // where to read the body from
    data_reader: Option<Box<Read + Send + 'static>>,

    // if this writer is empty, then the request has been answered
    response_writer: Option<Box<Write + Send + 'static>>,

    remote_addr: SocketAddr,

    method: Method,

    path: String,

    http_version: HTTPVersion,

    headers: Vec<Header>,

    body_length: Option<usize>,

    // true if a `100 Continue` response must be sent when `as_reader()` is called
    must_send_continue: bool,
}

/// Error that can happen when building a `Request` object.
pub enum RequestCreationError {
    /// The client sent an `Expect` header that was not recognized by tiny-http.
    ExpectationFailed,

    /// Error while reading data from the socket during the creation of the `Request`.
    CreationIoError(IoError),
}

impl From<IoError> for RequestCreationError {
    fn from(err: IoError) -> RequestCreationError {
        RequestCreationError::CreationIoError(err)
    }
}

/// Builds a new request.
///
/// After the request line and headers have been read from the socket, a new `Request` object
/// is built.
///
/// You must pass a `Read` that will allow the `Request` object to read from the incoming data.
/// It is the responsibility of the `Request` to read only the data of the request and not further.
///
/// The `Write` object will be used by the `Request` to write the response.
pub fn new_request<R, W>(method: Method, path: String,
                         version: HTTPVersion, headers: Vec<Header>,
                         remote_addr: SocketAddr, mut source_data: R, writer: W)
                         -> Result<Request, RequestCreationError>
                         where R: Read + Send + 'static, W: Write + Send + 'static
{
    // finding the transfer-encoding header
    let transfer_encoding = headers.iter()
        .find(|h: &&Header| h.field.equiv(&"Transfer-Encoding"))
        .map(|h| h.value.clone());

    // finding the content-length header
    let content_length = if transfer_encoding.is_some() {
        // if transfer-encoding is specified, the Content-Length
        // header must be ignored (RFC2616 #4.4)
        None

    } else {
        headers.iter()
               .find(|h: &&Header| h.field.equiv(&"Content-Length"))
               .and_then(|h| FromStr::from_str(h.value.as_str()).ok())
    };

    // true if the client sent a `Expect: 100-continue` header
    let expects_continue = {
        match headers.iter().find(|h: &&Header| h.field.equiv(&"Expect")).map(|h| AsRef::<str>::as_ref(h.value.as_ref())) {
            None => false,
            Some(v) if v.eq_ignore_ascii_case("100-continue")
                => true,
            _ => return Err(RequestCreationError::ExpectationFailed)
        }
    };

    // true if the client sent a `Connection: upgrade` header
    let connection_upgrade = {
        match headers.iter().find(|h: &&Header| h.field.equiv(&"Connection")).map(|h| AsRef::<str>::as_ref(h.value.as_ref())) {
            None => false,
            Some(v) if v.eq_ignore_ascii_case("upgrade")
                => true,
            _ => false
        }
    };

    // we wrap `source_data` around a reading whose nature depends on the transfer-encoding and
    // content-length headers
    let reader =
        if connection_upgrade {
            // if we have a `Connection: upgrade`, always keeping the whole reader
            Box::new(source_data) as Box<Read + Send + 'static>

        } else if let Some(content_length) = content_length {
            if content_length == 0 {
                Box::new(io::empty()) as Box<Read + Send + 'static>

            } else if content_length <= 1024 && !expects_continue {
                // if the content-length is small enough, we just read everything into a buffer

                let mut buffer = vec![0; content_length];
                let mut offset = 0;

                loop {
                    if offset == content_length {
                        break;
                    }

                    let read = try!(source_data.read(&mut buffer[offset..]));
                    if read == 0 {
                        // the socket returned EOF, but we were before the expected content-length
                        // aborting
                        let info = "Connection has been closed before we received enough data";
                        let err = IoError::new(ErrorKind::ConnectionAborted, info);
                        return Err(RequestCreationError::CreationIoError(err));
                    }

                    offset += read;
                }

                Box::new(Cursor::new(buffer)) as Box<Read + Send + 'static>

            } else {
                let (data_reader, _) = EqualReader::new(source_data, content_length);   // TODO:
                Box::new(data_reader) as Box<Read + Send + 'static>
            }

        } else if transfer_encoding.is_some() {
            // if a transfer-encoding was specified, then "chunked" is ALWAYS applied
            // over the message (RFC2616 #3.6)
            Box::new(Decoder::new(source_data)) as Box<Read + Send + 'static>

        } else {
            // if we have neither a Content-Length nor a Transfer-Encoding,
            // assuming that we have no data
            // TODO: could also be multipart/byteranges
            Box::new(io::empty()) as Box<Read + Send + 'static>
        };

    Ok(Request {
        data_reader: Some(reader),
        response_writer: Some(Box::new(writer) as Box<Write + Send + 'static>),
        remote_addr: remote_addr,
        method: method,
        path: path,
        http_version: version,
        headers: headers,
        body_length: content_length,
        must_send_continue: expects_continue,
    })
}

impl Request {
    /// Returns the method requested by the client (eg. `GET`, `POST`, etc.).
    #[inline]
    pub fn get_method(&self) -> &Method {
        &self.method
    }

    /// Returns the resource requested by the client.
    #[inline]
    pub fn get_url(&self) -> &str {
        &self.path
    }

    /// Returns a list of all headers sent by the client.
    #[inline]
    pub fn get_headers(&self) -> &[Header] {
        &self.headers
    }

    /// Returns the HTTP version of the request.
    #[inline]
    pub fn get_http_version(&self) -> &HTTPVersion {
        &self.http_version
    }

    /// Returns the length of the body in bytes.
    ///
    /// Returns `None` if the length is unknown.
    #[inline]
    pub fn get_body_length(&self) -> Option<usize> {
        self.body_length
    }

    /// Returns the length of the body in bytes.
    #[inline]
    pub fn get_remote_addr(&self) -> &SocketAddr {
        &self.remote_addr
    }

/*      // FIXME: reimplement this
    /// Sends a response with a `Connection: upgrade` header, then turns the `Request` into a `Stream`.
    ///
    /// The main purpose of this function is to support websockets.
    /// If you detect that the request wants to use some kind of protocol upgrade, you can
    ///  call this function to obtain full control of the socket stream.
    ///
    /// If you call this on a non-websocket request, tiny-http will wait until this `Stream` object
    ///  is destroyed before continuing to read or write on the socket. Therefore you should always
    ///  destroy it as soon as possible.
    pub fn upgrade<R: Read>(mut self, protocol: &str, response: Response<R>) -> Box<Read + Write + Send> {
        use util::CustomStream;

        response.raw_print(self.response_writer.as_mut().unwrap().by_ref(), self.http_version,
                           self.headers, false, Some(protocol)).ok();   // TODO: unused result

        self.response_writer.as_mut().unwrap().flush().ok();    // TODO: unused result

        let stream = CustomStream::new(self.into_reader_impl(), self.into_writer_impl());
        Box::new(stream) as Box<Read + Write + Send>
    }*/

    /// Allows to read the body of the request.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # extern crate rustc_serialize;
    /// # extern crate tiny_http;
    /// # use rustc_serialize::json::Json;
    /// # use std::io::Read;
    /// # fn get_content_type(_: &tiny_http::Request) -> &'static str { "" }
    /// # fn main() {
    /// # let server = tiny_http::ServerBuilder::new().build().unwrap();
    /// let mut request = server.recv().unwrap();
    ///
    /// if get_content_type(&request) == "application/json" {
    ///     let mut content = String::new();
    ///     request.as_reader().read_to_string(&mut content).unwrap();
    ///     let json: Json = content.parse().unwrap();
    /// }
    /// # }
    /// ```
    ///
    /// If the client sent a `Expect: 100-continue` header with the request, calling this
    ///  function will send back a `100 Continue` response.
    #[inline]
    pub fn as_reader(&mut self) -> &mut Read {
        if self.must_send_continue {
            let msg = Response::new_empty(StatusCode(100));
            msg.raw_print(self.response_writer.as_mut().unwrap().by_ref(),
                          self.http_version.clone(), &self.headers, true, None).ok();
            self.response_writer.as_mut().unwrap().flush().ok();
            self.must_send_continue = false;
        }

        self.data_reader.as_mut().unwrap()
    }

    /// Turns the `Request` into a writer.
    ///
    /// The writer has a raw access to the stream to the user.
    /// This function is useful for things like CGI.
    ///
    /// Note that the destruction of the `Writer` object may trigger
    /// some events. For exemple if a client has sent multiple requests and the requests
    /// have been processed in parallel, the destruction of a writer will trigger
    /// the writing of the next response.
    /// Therefore you should always destroy the `Writer` as soon as possible.
    #[inline]
    pub fn into_writer(mut self) -> Box<Write + Send + 'static> {
        self.into_writer_impl()
    }

    fn into_writer_impl(&mut self) -> Box<Write + Send + 'static> {
        use std::mem;

        assert!(self.response_writer.is_some());

        let mut writer = None;
        mem::swap(&mut self.response_writer, &mut writer);
        writer.unwrap()
    }

    // TODO: unused
    /*fn into_reader_impl(&mut self) -> AnyReader {
        use std::mem;

        assert!(self.data_reader.is_some());

        let mut reader = None;
        mem::swap(&mut self.data_reader, &mut reader);
        reader.unwrap()
    }*/

    /// Sends a response to this request.
    #[inline]
    pub fn respond<R>(mut self, response: Response<R>) where R: Read {
        self.respond_impl(response)
    }

    fn respond_impl<R>(&mut self, response: Response<R>) where R: Read {
        let mut writer = self.into_writer_impl();

        let do_not_send_body = self.method.equiv(&"HEAD");

        match response.raw_print(writer.by_ref(),
                                 self.http_version.clone(), &self.headers,
                                 do_not_send_body, None)
        {
            Ok(_) => (),
            Err(ref err) if err.kind() == ErrorKind::BrokenPipe => (),
            Err(ref err) if err.kind() == ErrorKind::ConnectionAborted => (),
            Err(ref err) if err.kind() == ErrorKind::ConnectionRefused => (),
            Err(ref err) if err.kind() == ErrorKind::ConnectionReset => (),
            Err(ref err) =>
                println!("error while sending answer: {}", err)     // TODO: handle better?
        };

        writer.flush().ok();
    }
}

impl fmt::Debug for Request {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(formatter, "Request({} {} from {})", self.method, self.path, self.remote_addr)
    }
}

impl Drop for Request {
    fn drop(&mut self) {
        if self.response_writer.is_some() {
            let response = Response::empty(500);
            self.respond_impl(response);
        }
    }
}

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

    #[test]
    fn must_be_send() {
        #![allow(dead_code)]
        fn f<T: Send>(_: &T) {}
        fn bar(rq: &Request) { f(rq); }
    }
}
<commit_msg>Convert `loop` to `while`<commit_after>// Copyright 2015 The tiny-http Contributors
//
// 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 std::ascii::AsciiExt;

use std::io::Error as IoError;
use std::io::{self, Cursor, Read, Write, ErrorKind};

use std::net::SocketAddr;
use std::fmt;
use std::str::FromStr;

use {Header, HTTPVersion, Method, Response, StatusCode};
use util::EqualReader;
use chunked_transfer::Decoder;

/// Represents an HTTP request made by a client.
///
/// A `Request` object is what is produced by the server, and is your what
/// your code must analyse and answer.
///
/// This object implements the `Send` trait, therefore you can dispatch your requests to
/// worker threads.
///
/// # Pipelining
///
/// If a client sends multiple requests in a row (without waiting for the response), then you will
/// get multiple `Request` objects simultaneously. This is called *requests pipelining*.
/// Tiny-http automatically reorders the responses so that you don't need to worry about the order
/// in which you call `respond` or `into_writer`.
///
/// This mechanic is disabled if:
///
///  - The body of a request is large enough (handling requires pipelining requires storing the
///    body of the request in a buffer ; if the body is too big, tiny-http will avoid doing that)
///  - A request sends a `Expect: 100-continue` header (which means that the client waits to
///    know whether its body will be processed before sending it)
///  - A request sends a `Connection: close` header or `Connection: upgrade` header (used for
///    websockets), which indicates that this is the last request that will be received on this
///    connection
///
/// # Automatic cleanup
///
/// If a `Request` object is destroyed without `into_writer` or `respond` being called,
/// an empty response with a 500 status code (internal server error) will automatically be
/// sent back to the client.
/// This means that if your code fails during the handling of a request, this "internal server
/// error" response will automatically be sent during the stack unwinding.
pub struct Request {
    // where to read the body from
    data_reader: Option<Box<Read + Send + 'static>>,

    // if this writer is empty, then the request has been answered
    response_writer: Option<Box<Write + Send + 'static>>,

    remote_addr: SocketAddr,

    method: Method,

    path: String,

    http_version: HTTPVersion,

    headers: Vec<Header>,

    body_length: Option<usize>,

    // true if a `100 Continue` response must be sent when `as_reader()` is called
    must_send_continue: bool,
}

/// Error that can happen when building a `Request` object.
pub enum RequestCreationError {
    /// The client sent an `Expect` header that was not recognized by tiny-http.
    ExpectationFailed,

    /// Error while reading data from the socket during the creation of the `Request`.
    CreationIoError(IoError),
}

impl From<IoError> for RequestCreationError {
    fn from(err: IoError) -> RequestCreationError {
        RequestCreationError::CreationIoError(err)
    }
}

/// Builds a new request.
///
/// After the request line and headers have been read from the socket, a new `Request` object
/// is built.
///
/// You must pass a `Read` that will allow the `Request` object to read from the incoming data.
/// It is the responsibility of the `Request` to read only the data of the request and not further.
///
/// The `Write` object will be used by the `Request` to write the response.
pub fn new_request<R, W>(method: Method, path: String,
                         version: HTTPVersion, headers: Vec<Header>,
                         remote_addr: SocketAddr, mut source_data: R, writer: W)
                         -> Result<Request, RequestCreationError>
                         where R: Read + Send + 'static, W: Write + Send + 'static
{
    // finding the transfer-encoding header
    let transfer_encoding = headers.iter()
        .find(|h: &&Header| h.field.equiv(&"Transfer-Encoding"))
        .map(|h| h.value.clone());

    // finding the content-length header
    let content_length = if transfer_encoding.is_some() {
        // if transfer-encoding is specified, the Content-Length
        // header must be ignored (RFC2616 #4.4)
        None

    } else {
        headers.iter()
               .find(|h: &&Header| h.field.equiv(&"Content-Length"))
               .and_then(|h| FromStr::from_str(h.value.as_str()).ok())
    };

    // true if the client sent a `Expect: 100-continue` header
    let expects_continue = {
        match headers.iter().find(|h: &&Header| h.field.equiv(&"Expect")).map(|h| AsRef::<str>::as_ref(h.value.as_ref())) {
            None => false,
            Some(v) if v.eq_ignore_ascii_case("100-continue")
                => true,
            _ => return Err(RequestCreationError::ExpectationFailed)
        }
    };

    // true if the client sent a `Connection: upgrade` header
    let connection_upgrade = {
        match headers.iter().find(|h: &&Header| h.field.equiv(&"Connection")).map(|h| AsRef::<str>::as_ref(h.value.as_ref())) {
            None => false,
            Some(v) if v.eq_ignore_ascii_case("upgrade")
                => true,
            _ => false
        }
    };

    // we wrap `source_data` around a reading whose nature depends on the transfer-encoding and
    // content-length headers
    let reader =
        if connection_upgrade {
            // if we have a `Connection: upgrade`, always keeping the whole reader
            Box::new(source_data) as Box<Read + Send + 'static>

        } else if let Some(content_length) = content_length {
            if content_length == 0 {
                Box::new(io::empty()) as Box<Read + Send + 'static>

            } else if content_length <= 1024 && !expects_continue {
                // if the content-length is small enough, we just read everything into a buffer

                let mut buffer = vec![0; content_length];
                let mut offset = 0;

                while offset != content_length {
                    let read = try!(source_data.read(&mut buffer[offset..]));
                    if read == 0 {
                        // the socket returned EOF, but we were before the expected content-length
                        // aborting
                        let info = "Connection has been closed before we received enough data";
                        let err = IoError::new(ErrorKind::ConnectionAborted, info);
                        return Err(RequestCreationError::CreationIoError(err));
                    }

                    offset += read;
                }

                Box::new(Cursor::new(buffer)) as Box<Read + Send + 'static>

            } else {
                let (data_reader, _) = EqualReader::new(source_data, content_length);   // TODO:
                Box::new(data_reader) as Box<Read + Send + 'static>
            }

        } else if transfer_encoding.is_some() {
            // if a transfer-encoding was specified, then "chunked" is ALWAYS applied
            // over the message (RFC2616 #3.6)
            Box::new(Decoder::new(source_data)) as Box<Read + Send + 'static>

        } else {
            // if we have neither a Content-Length nor a Transfer-Encoding,
            // assuming that we have no data
            // TODO: could also be multipart/byteranges
            Box::new(io::empty()) as Box<Read + Send + 'static>
        };

    Ok(Request {
        data_reader: Some(reader),
        response_writer: Some(Box::new(writer) as Box<Write + Send + 'static>),
        remote_addr: remote_addr,
        method: method,
        path: path,
        http_version: version,
        headers: headers,
        body_length: content_length,
        must_send_continue: expects_continue,
    })
}

impl Request {
    /// Returns the method requested by the client (eg. `GET`, `POST`, etc.).
    #[inline]
    pub fn get_method(&self) -> &Method {
        &self.method
    }

    /// Returns the resource requested by the client.
    #[inline]
    pub fn get_url(&self) -> &str {
        &self.path
    }

    /// Returns a list of all headers sent by the client.
    #[inline]
    pub fn get_headers(&self) -> &[Header] {
        &self.headers
    }

    /// Returns the HTTP version of the request.
    #[inline]
    pub fn get_http_version(&self) -> &HTTPVersion {
        &self.http_version
    }

    /// Returns the length of the body in bytes.
    ///
    /// Returns `None` if the length is unknown.
    #[inline]
    pub fn get_body_length(&self) -> Option<usize> {
        self.body_length
    }

    /// Returns the length of the body in bytes.
    #[inline]
    pub fn get_remote_addr(&self) -> &SocketAddr {
        &self.remote_addr
    }

/*      // FIXME: reimplement this
    /// Sends a response with a `Connection: upgrade` header, then turns the `Request` into a `Stream`.
    ///
    /// The main purpose of this function is to support websockets.
    /// If you detect that the request wants to use some kind of protocol upgrade, you can
    ///  call this function to obtain full control of the socket stream.
    ///
    /// If you call this on a non-websocket request, tiny-http will wait until this `Stream` object
    ///  is destroyed before continuing to read or write on the socket. Therefore you should always
    ///  destroy it as soon as possible.
    pub fn upgrade<R: Read>(mut self, protocol: &str, response: Response<R>) -> Box<Read + Write + Send> {
        use util::CustomStream;

        response.raw_print(self.response_writer.as_mut().unwrap().by_ref(), self.http_version,
                           self.headers, false, Some(protocol)).ok();   // TODO: unused result

        self.response_writer.as_mut().unwrap().flush().ok();    // TODO: unused result

        let stream = CustomStream::new(self.into_reader_impl(), self.into_writer_impl());
        Box::new(stream) as Box<Read + Write + Send>
    }*/

    /// Allows to read the body of the request.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # extern crate rustc_serialize;
    /// # extern crate tiny_http;
    /// # use rustc_serialize::json::Json;
    /// # use std::io::Read;
    /// # fn get_content_type(_: &tiny_http::Request) -> &'static str { "" }
    /// # fn main() {
    /// # let server = tiny_http::ServerBuilder::new().build().unwrap();
    /// let mut request = server.recv().unwrap();
    ///
    /// if get_content_type(&request) == "application/json" {
    ///     let mut content = String::new();
    ///     request.as_reader().read_to_string(&mut content).unwrap();
    ///     let json: Json = content.parse().unwrap();
    /// }
    /// # }
    /// ```
    ///
    /// If the client sent a `Expect: 100-continue` header with the request, calling this
    ///  function will send back a `100 Continue` response.
    #[inline]
    pub fn as_reader(&mut self) -> &mut Read {
        if self.must_send_continue {
            let msg = Response::new_empty(StatusCode(100));
            msg.raw_print(self.response_writer.as_mut().unwrap().by_ref(),
                          self.http_version.clone(), &self.headers, true, None).ok();
            self.response_writer.as_mut().unwrap().flush().ok();
            self.must_send_continue = false;
        }

        self.data_reader.as_mut().unwrap()
    }

    /// Turns the `Request` into a writer.
    ///
    /// The writer has a raw access to the stream to the user.
    /// This function is useful for things like CGI.
    ///
    /// Note that the destruction of the `Writer` object may trigger
    /// some events. For exemple if a client has sent multiple requests and the requests
    /// have been processed in parallel, the destruction of a writer will trigger
    /// the writing of the next response.
    /// Therefore you should always destroy the `Writer` as soon as possible.
    #[inline]
    pub fn into_writer(mut self) -> Box<Write + Send + 'static> {
        self.into_writer_impl()
    }

    fn into_writer_impl(&mut self) -> Box<Write + Send + 'static> {
        use std::mem;

        assert!(self.response_writer.is_some());

        let mut writer = None;
        mem::swap(&mut self.response_writer, &mut writer);
        writer.unwrap()
    }

    // TODO: unused
    /*fn into_reader_impl(&mut self) -> AnyReader {
        use std::mem;

        assert!(self.data_reader.is_some());

        let mut reader = None;
        mem::swap(&mut self.data_reader, &mut reader);
        reader.unwrap()
    }*/

    /// Sends a response to this request.
    #[inline]
    pub fn respond<R>(mut self, response: Response<R>) where R: Read {
        self.respond_impl(response)
    }

    fn respond_impl<R>(&mut self, response: Response<R>) where R: Read {
        let mut writer = self.into_writer_impl();

        let do_not_send_body = self.method.equiv(&"HEAD");

        match response.raw_print(writer.by_ref(),
                                 self.http_version.clone(), &self.headers,
                                 do_not_send_body, None)
        {
            Ok(_) => (),
            Err(ref err) if err.kind() == ErrorKind::BrokenPipe => (),
            Err(ref err) if err.kind() == ErrorKind::ConnectionAborted => (),
            Err(ref err) if err.kind() == ErrorKind::ConnectionRefused => (),
            Err(ref err) if err.kind() == ErrorKind::ConnectionReset => (),
            Err(ref err) =>
                println!("error while sending answer: {}", err)     // TODO: handle better?
        };

        writer.flush().ok();
    }
}

impl fmt::Debug for Request {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(formatter, "Request({} {} from {})", self.method, self.path, self.remote_addr)
    }
}

impl Drop for Request {
    fn drop(&mut self) {
        if self.response_writer.is_some() {
            let response = Response::empty(500);
            self.respond_impl(response);
        }
    }
}

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

    #[test]
    fn must_be_send() {
        #![allow(dead_code)]
        fn f<T: Send>(_: &T) {}
        fn bar(rq: &Request) { f(rq); }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

pub struct Scanner {
    source: String,
    tokens: Vec<Token>,
    start: usize,
    current: usize,
    line: i32,
}

impl Scanner {
    pub fn new(source: String) -> Self {
        Scanner {
            source: source,
            tokens: Vec::new(),
            start: 0,
            current: 0,
            line: 1,
        }
    }

    pub fn scan_tokens(&mut self) -> Vec<Token> {
        while !self.is_at_end() {
            self.start = self.current;
            match self.scan_token() {
                Ok(token) => {
                    if !token.token_type.is_ignored() {
                        self.tokens.push(token);
                    }
                }
                Err(_) => {}
            }
        }
        self.tokens
            .push(Token::new(TokenType::EOF, "", Literal::Nil, self.line));
        self.tokens.to_vec()
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn scan_token(&mut self) -> Result<Token, ScanError> {
        let c = self.advance();
        match c {
            '(' => Ok(self.create_token(TokenType::LEFT_PAREN)),
            ')' => Ok(self.create_token(TokenType::RIGHT_PAREN)),
            '{' => Ok(self.create_token(TokenType::LEFT_BRACE)),
            '}' => Ok(self.create_token(TokenType::RIGHT_BRACE)),
            ',' => Ok(self.create_token(TokenType::COMMA)),
            '.' => Ok(self.create_token(TokenType::DOT)),
            '-' => Ok(self.create_token(TokenType::MINUS)),
            '+' => Ok(self.create_token(TokenType::PLUS)),
            ';' => Ok(self.create_token(TokenType::SEMICOLON)),
            '*' => Ok(self.create_token(TokenType::STAR)),
            // TODO: A bit of duplication here. Should refactor at some point.
            '!' => {
                if self.match_char('=') {
                    self.advance();
                    Ok(self.create_token(TokenType::BANG_EQUAL))
                } else {
                    Ok(self.create_token(TokenType::BANG))
                }
            }
            '=' => {
                if self.match_char('=') {
                    self.advance();
                    Ok(self.create_token(TokenType::EQUAL_EQUAL))
                } else {
                    Ok(self.create_token(TokenType::EQUAL))
                }
            }
            '<' => {
                if self.match_char('=') {
                    self.advance();
                    Ok(self.create_token(TokenType::LESS_EQUAL))
                } else {
                    Ok(self.create_token(TokenType::LESS))
                }
            }
            '>' => {
                if self.match_char('=') {
                    self.advance();
                    Ok(self.create_token(TokenType::GREATER_EQUAL))
                } else {
                    Ok(self.create_token(TokenType::GREATER))
                }
            }
            '/' => {
                if self.match_char('/') {
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.advance();
                    }
                    Ok(self.create_token(TokenType::COMMENT))
                } else {
                    Ok(self.create_token(TokenType::SLASH))
                }
            }
            ' ' | '\r' | '\t' => Ok(self.create_token(TokenType::WHITESPACE)),
            '\n' => {
                self.line += 1;
                Ok(self.create_token(TokenType::NEWLINE))
            }
            '"' => self.scan_string(),
            c if c.is_digit(10) => self.scan_number(),
            c if c.is_alphabetic() => self.scan_identifier(),
            _ => Err(ScanError::new(self.line, "Unexpected character.")),
        }
    }

    fn scan_string(&mut self) -> Result<Token, ScanError> {
        while self.peek() != '"' && !self.is_at_end() {
            if self.peek() == '\n' {
                self.line += 1;
            }
            self.advance();
        }
        // Unterminated string.
        if self.is_at_end() {
            return Err(ScanError::new(self.line, "Unterminated string."));
        }

        // The closing ".
        self.advance();

        // Trim the surrounding quotes.
        let value = &self.source[self.start + 1..self.current - 1];
        Ok(self.create_token_with_literal(TokenType::STRING, Literal::String(value.to_owned())))
    }

    fn scan_number(&mut self) -> Result<Token, ScanError> {
        while self.peek().is_digit(10) {
            self.advance();
        }

        // Look for a fractional part.
        if self.peek() == '.' && self.peek_next().is_digit(10) {
            // Consume the "."
            self.advance();
            while self.peek().is_digit(10) {
                self.advance();
            }
        }
        let value = &self.source[self.start..self.current];
        Ok(self.create_token_with_literal(TokenType::NUMBER,
                                          Literal::Number(value.parse::<f64>().unwrap())))
    }

    fn scan_identifier(&mut self) -> Result<Token, ScanError> {
        while self.peek().is_alphanumeric() {
            self.advance();
        }

        let text = &self.source[self.start..self.current];
        let token_type = match KEYWORDS.get(text) {
            Some(t) => *t,
            None => TokenType::IDENTIFIER,
        };

        Ok(self.create_token(token_type))
    }

    fn peek(&self) -> char {
        if self.is_at_end() {
            return '\0';
        }
        let b = self.source.as_bytes();
        b[self.current] as char
    }

    fn peek_next(&self) -> char {
        if self.current + 1 >= self.source.len() {
            return '\0';
        }
        let b = self.source.as_bytes();
        b[self.current + 1] as char
    }

    fn match_char(&self, c: char) -> bool {
        self.peek() == c
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        let b = self.source.as_bytes();
        b[self.current - 1] as char
    }

    fn create_token(&self, token_type: TokenType) -> Token {
        self.create_token_with_literal(token_type, Literal::Nil)
    }

    fn create_token_with_literal(&self, token_type: TokenType, literal: Literal) -> Token {
        let s = &self.source[self.start..self.current];
        Token::new(token_type, s, literal, self.line)
    }
}

#[derive(Clone, Debug)]
pub struct Token {
    token_type: TokenType,
    lexeme: String,
    literal: Literal,
    line: i32,
}

impl Token {
    pub fn new(token_type: TokenType, lexeme: &str, literal: Literal, line: i32) -> Self {
        Token {
            token_type: token_type,
            lexeme: lexeme.to_owned(),
            literal: literal,
            line: line,
        }
    }
}

#[derive(Clone, Copy, Debug)]
#[allow(non_camel_case_types)]
pub enum TokenType {
    // Single-character tokens.
    LEFT_PAREN,
    RIGHT_PAREN,
    LEFT_BRACE,
    RIGHT_BRACE,
    COMMA,
    DOT,
    MINUS,
    PLUS,
    SEMICOLON,
    SLASH,
    STAR,

    // One or two character tokens.
    BANG,
    BANG_EQUAL,
    EQUAL,
    EQUAL_EQUAL,
    GREATER,
    GREATER_EQUAL,
    LESS,
    LESS_EQUAL,

    // Literals.
    IDENTIFIER,
    STRING,
    NUMBER,

    // Keywords.
    AND,
    CLASS,
    ELSE,
    FALSE,
    FUN,
    FOR,
    IF,
    NIL,
    OR,
    PRINT,
    RETURN,
    SUPER,
    THIS,
    TRUE,
    VAR,
    WHILE,

    EOF,

    // IGNORED lexemes
    COMMENT,
    WHITESPACE,
    NEWLINE,
}

impl TokenType {
    fn is_ignored(&self) -> bool {
        let n = *self as u8;
        n > 38
    }
}

#[derive(Clone, Debug)]
pub enum Literal {
    String(String),
    Number(f64),
    Nil,
}

pub struct ScanError {
    line: i32,
    message: String,
}

impl ScanError {
    fn new(line: i32, message: &str) -> Self {
        ScanError {
            line: line,
            message: message.to_owned(),
        }
    }
}

lazy_static! {
    static ref KEYWORDS: HashMap<&'static str, TokenType> = {
        let mut m = HashMap::new();
        m.insert("and", TokenType::AND);
        m.insert("class", TokenType::CLASS);
        m.insert("else", TokenType::ELSE);
        m.insert("false", TokenType::FALSE);
        m.insert("for", TokenType::FOR);
        m.insert("fun", TokenType::FUN);
        m.insert("if", TokenType::IF);
        m.insert("nil", TokenType::NIL);
        m.insert("or", TokenType::OR);
        m.insert("print", TokenType::PRINT);
        m.insert("return", TokenType::RETURN);
        m.insert("super", TokenType::SUPER);
        m.insert("this", TokenType::THIS);
        m.insert("true", TokenType::TRUE);
        m.insert("var", TokenType::VAR);
        m.insert("while", TokenType::WHILE);
        m
    };
}
<commit_msg>add support for storing literal values for `FALSE` and `TRUE` lexemes<commit_after>use std::collections::HashMap;

pub struct Scanner {
    source: String,
    tokens: Vec<Token>,
    start: usize,
    current: usize,
    line: i32,
}

impl Scanner {
    pub fn new(source: String) -> Self {
        Scanner {
            source: source,
            tokens: Vec::new(),
            start: 0,
            current: 0,
            line: 1,
        }
    }

    pub fn scan_tokens(&mut self) -> Vec<Token> {
        while !self.is_at_end() {
            self.start = self.current;
            match self.scan_token() {
                Ok(token) => {
                    if !token.token_type.is_ignored() {
                        self.tokens.push(token);
                    }
                }
                Err(_) => {}
            }
        }
        self.tokens
            .push(Token::new(TokenType::EOF, "", Literal::Nil, self.line));
        self.tokens.to_vec()
    }

    fn is_at_end(&self) -> bool {
        self.current >= self.source.len()
    }

    fn scan_token(&mut self) -> Result<Token, ScanError> {
        let c = self.advance();
        match c {
            '(' => Ok(self.create_token(TokenType::LEFT_PAREN)),
            ')' => Ok(self.create_token(TokenType::RIGHT_PAREN)),
            '{' => Ok(self.create_token(TokenType::LEFT_BRACE)),
            '}' => Ok(self.create_token(TokenType::RIGHT_BRACE)),
            ',' => Ok(self.create_token(TokenType::COMMA)),
            '.' => Ok(self.create_token(TokenType::DOT)),
            '-' => Ok(self.create_token(TokenType::MINUS)),
            '+' => Ok(self.create_token(TokenType::PLUS)),
            ';' => Ok(self.create_token(TokenType::SEMICOLON)),
            '*' => Ok(self.create_token(TokenType::STAR)),
            // TODO: A bit of duplication here. Should refactor at some point.
            '!' => {
                if self.match_char('=') {
                    self.advance();
                    Ok(self.create_token(TokenType::BANG_EQUAL))
                } else {
                    Ok(self.create_token(TokenType::BANG))
                }
            }
            '=' => {
                if self.match_char('=') {
                    self.advance();
                    Ok(self.create_token(TokenType::EQUAL_EQUAL))
                } else {
                    Ok(self.create_token(TokenType::EQUAL))
                }
            }
            '<' => {
                if self.match_char('=') {
                    self.advance();
                    Ok(self.create_token(TokenType::LESS_EQUAL))
                } else {
                    Ok(self.create_token(TokenType::LESS))
                }
            }
            '>' => {
                if self.match_char('=') {
                    self.advance();
                    Ok(self.create_token(TokenType::GREATER_EQUAL))
                } else {
                    Ok(self.create_token(TokenType::GREATER))
                }
            }
            '/' => {
                if self.match_char('/') {
                    while self.peek() != '\n' && !self.is_at_end() {
                        self.advance();
                    }
                    Ok(self.create_token(TokenType::COMMENT))
                } else {
                    Ok(self.create_token(TokenType::SLASH))
                }
            }
            ' ' | '\r' | '\t' => Ok(self.create_token(TokenType::WHITESPACE)),
            '\n' => {
                self.line += 1;
                Ok(self.create_token(TokenType::NEWLINE))
            }
            '"' => self.scan_string(),
            c if c.is_digit(10) => self.scan_number(),
            c if c.is_alphabetic() => self.scan_identifier(),
            _ => Err(ScanError::new(self.line, "Unexpected character.")),
        }
    }

    fn scan_string(&mut self) -> Result<Token, ScanError> {
        while self.peek() != '"' && !self.is_at_end() {
            if self.peek() == '\n' {
                self.line += 1;
            }
            self.advance();
        }
        // Unterminated string.
        if self.is_at_end() {
            return Err(ScanError::new(self.line, "Unterminated string."));
        }

        // The closing ".
        self.advance();

        // Trim the surrounding quotes.
        let value = &self.source[self.start + 1..self.current - 1];
        Ok(self.create_token_with_literal(TokenType::STRING, Literal::String(value.to_owned())))
    }

    fn scan_number(&mut self) -> Result<Token, ScanError> {
        while self.peek().is_digit(10) {
            self.advance();
        }

        // Look for a fractional part.
        if self.peek() == '.' && self.peek_next().is_digit(10) {
            // Consume the "."
            self.advance();
            while self.peek().is_digit(10) {
                self.advance();
            }
        }
        let value = &self.source[self.start..self.current];
        Ok(self.create_token_with_literal(TokenType::NUMBER,
                                          Literal::Number(value.parse::<f64>().unwrap())))
    }

    fn scan_identifier(&mut self) -> Result<Token, ScanError> {
        while self.peek().is_alphanumeric() {
            self.advance();
        }

        let text = &self.source[self.start..self.current];
        let token_type = match KEYWORDS.get(text) {
            Some(t) => *t,
            None => TokenType::IDENTIFIER,
        };
        Ok(match token_type {
               TokenType::TRUE => {
                   self.create_token_with_literal(token_type, Literal::Boolean(true))
               }
               TokenType::FALSE => {
                   self.create_token_with_literal(token_type, Literal::Boolean(false))
               }
               _ => self.create_token(token_type),
           })
    }

    fn peek(&self) -> char {
        if self.is_at_end() {
            return '\0';
        }
        let b = self.source.as_bytes();
        b[self.current] as char
    }

    fn peek_next(&self) -> char {
        if self.current + 1 >= self.source.len() {
            return '\0';
        }
        let b = self.source.as_bytes();
        b[self.current + 1] as char
    }

    fn match_char(&self, c: char) -> bool {
        self.peek() == c
    }

    fn advance(&mut self) -> char {
        self.current += 1;
        let b = self.source.as_bytes();
        b[self.current - 1] as char
    }

    fn create_token(&self, token_type: TokenType) -> Token {
        self.create_token_with_literal(token_type, Literal::Nil)
    }

    fn create_token_with_literal(&self, token_type: TokenType, literal: Literal) -> Token {
        let s = &self.source[self.start..self.current];
        Token::new(token_type, s, literal, self.line)
    }
}

#[derive(Clone, Debug)]
pub struct Token {
    token_type: TokenType,
    lexeme: String,
    literal: Literal,
    line: i32,
}

impl Token {
    pub fn new(token_type: TokenType, lexeme: &str, literal: Literal, line: i32) -> Self {
        Token {
            token_type: token_type,
            lexeme: lexeme.to_owned(),
            literal: literal,
            line: line,
        }
    }
}

#[derive(Clone, Copy, Debug)]
#[allow(non_camel_case_types)]
pub enum TokenType {
    // Single-character tokens.
    LEFT_PAREN,
    RIGHT_PAREN,
    LEFT_BRACE,
    RIGHT_BRACE,
    COMMA,
    DOT,
    MINUS,
    PLUS,
    SEMICOLON,
    SLASH,
    STAR,

    // One or two character tokens.
    BANG,
    BANG_EQUAL,
    EQUAL,
    EQUAL_EQUAL,
    GREATER,
    GREATER_EQUAL,
    LESS,
    LESS_EQUAL,

    // Literals.
    IDENTIFIER,
    STRING,
    NUMBER,

    // Keywords.
    AND,
    CLASS,
    ELSE,
    FALSE,
    FUN,
    FOR,
    IF,
    NIL,
    OR,
    PRINT,
    RETURN,
    SUPER,
    THIS,
    TRUE,
    VAR,
    WHILE,

    EOF,

    // IGNORED lexemes
    COMMENT,
    WHITESPACE,
    NEWLINE,
}

impl TokenType {
    fn is_ignored(&self) -> bool {
        let n = *self as u8;
        n > 38
    }
}

#[derive(Clone, Debug)]
pub enum Literal {
    String(String),
    Number(f64),
    Boolean(bool),
    Nil,
}

pub struct ScanError {
    line: i32,
    message: String,
}

impl ScanError {
    fn new(line: i32, message: &str) -> Self {
        ScanError {
            line: line,
            message: message.to_owned(),
        }
    }
}

lazy_static! {
    static ref KEYWORDS: HashMap<&'static str, TokenType> = {
        let mut m = HashMap::new();
        m.insert("and", TokenType::AND);
        m.insert("class", TokenType::CLASS);
        m.insert("else", TokenType::ELSE);
        m.insert("false", TokenType::FALSE);
        m.insert("for", TokenType::FOR);
        m.insert("fun", TokenType::FUN);
        m.insert("if", TokenType::IF);
        m.insert("nil", TokenType::NIL);
        m.insert("or", TokenType::OR);
        m.insert("print", TokenType::PRINT);
        m.insert("return", TokenType::RETURN);
        m.insert("super", TokenType::SUPER);
        m.insert("this", TokenType::THIS);
        m.insert("true", TokenType::TRUE);
        m.insert("var", TokenType::VAR);
        m.insert("while", TokenType::WHILE);
        m
    };
}
<|endoftext|>


<commit_before>//! Register information and driver to program xAPIC, X2APIC and I/O APIC

pub mod ioapic;
pub mod x2apic;
pub mod xapic;

/// Specify IPI Delivery Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DeliveryMode {
    /// Delivers the interrupt specified in the vector field to the target processor or processors.
    Fixed = 0b000,
    /// Same as fixed mode, except that the interrupt is delivered to the processor executing at the
    /// lowest priority among the set of processors specified in the destination field. The ability
    /// for a processor to send a lowest priority IPI is model specific and should be avoided by
    /// BIOS and operating system software.
    LowestPriority = 0b001,
    /// Delivers an SMI interrupt to the target processor or processors.
    /// The vector field must be programmed to 00H for future compatibility.
    SMI = 0b010,
    /// Reserved
    _Reserved = 0b11,
    /// Delivers an NMI interrupt to the target processor or processors.
    /// The vector information is ignored.
    NMI = 0b100,
    /// Delivers an INIT request to the target processor or processors, which causes them to perform an INIT.
    Init = 0b101,
    /// Sends a special start-up IPI (called a SIPI) to the target processor or processors.
    /// The vector typically points to a start-up routine that is part of the
    /// BIOS boot-strap code (see Section 8.4, Multiple-Processor (MP) Initialization). I
    /// PIs sent with this delivery mode are not automatically retried if the source
    /// APIC is unable to deliver it. It is up to the software to deter- mine if the
    /// SIPI was not successfully delivered and to reissue the SIPI if necessary.
    StartUp = 0b110,
}

/// Sepcify IPI Destination Mode.
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DestinationMode {
    Physical = 0,
    Logical = 1,
}

/// Specify Delivery Status
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DeliveryStatus {
    Idle = 0,
    SendPending = 1,
}

/// IPI Level
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum Level {
    Deassert = 0,
    Assert = 1,
}

/// IPI Trigger Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum TriggerMode {
    Edge = 0,
    Level = 1,
}

/// IPI Destination Shorthand
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DestinationShorthand {
    NoShorthand = 0b00,
    Myself = 0b01,
    AllIncludingSelf = 0b10,
    AllExcludingSelf = 0b11,
}

/// Abstract the IPI control register
#[derive(Debug, Eq, PartialEq)]
pub struct Icr(u64);

impl Icr {
    /// Short-hand to create a Icr value.
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        vector: u8,
        destination: ApicId,
        destination_shorthand: DestinationShorthand,
        delivery_mode: DeliveryMode,
        destination_mode: DestinationMode,
        delivery_status: DeliveryStatus,
        level: Level,
        trigger_mode: TriggerMode,
    ) -> Icr {
        let destination: u8 = match destination {
            ApicId::XApic(d) => d,
            ApicId::X2Apic(_d) => {
                unreachable!("x2APIC destinations currently unsupported, adjust Icr construction!")
            }
        };

        Icr((destination as u64) << 56
            | (destination_shorthand as u64) << 18
            | (trigger_mode as u64) << 15
            | (level as u64) << 14
            | (delivery_status as u64) << 12
            | (destination_mode as u64) << 11
            | (delivery_mode as u64) << 8
            | (vector as u64))
    }

    /// Get lower 32-bits of the Icr register.
    pub fn lower(&self) -> u32 {
        self.0 as u32
    }

    /// Get upper 32-bits of the Icr register.
    pub fn upper(&self) -> u32 {
        (self.0 >> 32) as u32
    }
}

/// Encodes the id of a core.
#[derive(Debug, Eq, PartialEq)]
pub enum ApicId {
    /// A core destination encoded as an xAPIC ID.
    XApic(u8),
    /// A core destination encoded as an x2APIC ID.
    X2Apic(u32),
}

/// Abstracts common interface of local APIC (x2APIC, xAPIC) hardware devices.
pub trait ApicControl {
    /// Is a bootstrap processor?
    fn bsp(&self) -> bool;

    /// Return APIC ID.
    fn id(&self) -> u32;

    /// Read APIC version
    fn version(&self) -> u32;

    /// End Of Interrupt -- Acknowledge interrupt delivery.
    fn eoi(&mut self);

    /// Enable TSC deadline timer.
    fn tsc_enable(&mut self);

    /// Set TSC deadline value.
    fn tsc_set(&self, value: u64);

    /// Send a INIT IPI to a core.
    unsafe fn ipi_init(&mut self, core: ApicId);

    /// Deassert INIT IPI.
    unsafe fn ipi_init_deassert(&mut self);

    /// Send a STARTUP IPI to a core.
    unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8);

    /// Send a generic IPI.
    unsafe fn send_ipi(&mut self, icr: Icr);
}
<commit_msg>Make ApicId Copy+Clone.<commit_after>//! Register information and driver to program xAPIC, X2APIC and I/O APIC

pub mod ioapic;
pub mod x2apic;
pub mod xapic;

/// Specify IPI Delivery Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DeliveryMode {
    /// Delivers the interrupt specified in the vector field to the target processor or processors.
    Fixed = 0b000,
    /// Same as fixed mode, except that the interrupt is delivered to the processor executing at the
    /// lowest priority among the set of processors specified in the destination field. The ability
    /// for a processor to send a lowest priority IPI is model specific and should be avoided by
    /// BIOS and operating system software.
    LowestPriority = 0b001,
    /// Delivers an SMI interrupt to the target processor or processors.
    /// The vector field must be programmed to 00H for future compatibility.
    SMI = 0b010,
    /// Reserved
    _Reserved = 0b11,
    /// Delivers an NMI interrupt to the target processor or processors.
    /// The vector information is ignored.
    NMI = 0b100,
    /// Delivers an INIT request to the target processor or processors, which causes them to perform an INIT.
    Init = 0b101,
    /// Sends a special start-up IPI (called a SIPI) to the target processor or processors.
    /// The vector typically points to a start-up routine that is part of the
    /// BIOS boot-strap code (see Section 8.4, Multiple-Processor (MP) Initialization). I
    /// PIs sent with this delivery mode are not automatically retried if the source
    /// APIC is unable to deliver it. It is up to the software to deter- mine if the
    /// SIPI was not successfully delivered and to reissue the SIPI if necessary.
    StartUp = 0b110,
}

/// Sepcify IPI Destination Mode.
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DestinationMode {
    Physical = 0,
    Logical = 1,
}

/// Specify Delivery Status
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DeliveryStatus {
    Idle = 0,
    SendPending = 1,
}

/// IPI Level
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum Level {
    Deassert = 0,
    Assert = 1,
}

/// IPI Trigger Mode
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum TriggerMode {
    Edge = 0,
    Level = 1,
}

/// IPI Destination Shorthand
#[derive(Debug, Eq, PartialEq)]
#[repr(u64)]
pub enum DestinationShorthand {
    NoShorthand = 0b00,
    Myself = 0b01,
    AllIncludingSelf = 0b10,
    AllExcludingSelf = 0b11,
}

/// Abstract the IPI control register
#[derive(Debug, Eq, PartialEq)]
pub struct Icr(u64);

impl Icr {
    /// Short-hand to create a Icr value.
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        vector: u8,
        destination: ApicId,
        destination_shorthand: DestinationShorthand,
        delivery_mode: DeliveryMode,
        destination_mode: DestinationMode,
        delivery_status: DeliveryStatus,
        level: Level,
        trigger_mode: TriggerMode,
    ) -> Icr {
        let destination: u8 = match destination {
            ApicId::XApic(d) => d,
            ApicId::X2Apic(_d) => {
                unreachable!("x2APIC destinations currently unsupported, adjust Icr construction!")
            }
        };

        Icr((destination as u64) << 56
            | (destination_shorthand as u64) << 18
            | (trigger_mode as u64) << 15
            | (level as u64) << 14
            | (delivery_status as u64) << 12
            | (destination_mode as u64) << 11
            | (delivery_mode as u64) << 8
            | (vector as u64))
    }

    /// Get lower 32-bits of the Icr register.
    pub fn lower(&self) -> u32 {
        self.0 as u32
    }

    /// Get upper 32-bits of the Icr register.
    pub fn upper(&self) -> u32 {
        (self.0 >> 32) as u32
    }
}

/// Encodes the id of a core.
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum ApicId {
    /// A core destination encoded as an xAPIC ID.
    XApic(u8),
    /// A core destination encoded as an x2APIC ID.
    X2Apic(u32),
}

/// Abstracts common interface of local APIC (x2APIC, xAPIC) hardware devices.
pub trait ApicControl {
    /// Is a bootstrap processor?
    fn bsp(&self) -> bool;

    /// Return APIC ID.
    fn id(&self) -> u32;

    /// Read APIC version
    fn version(&self) -> u32;

    /// End Of Interrupt -- Acknowledge interrupt delivery.
    fn eoi(&mut self);

    /// Enable TSC deadline timer.
    fn tsc_enable(&mut self);

    /// Set TSC deadline value.
    fn tsc_set(&self, value: u64);

    /// Send a INIT IPI to a core.
    unsafe fn ipi_init(&mut self, core: ApicId);

    /// Deassert INIT IPI.
    unsafe fn ipi_init_deassert(&mut self);

    /// Send a STARTUP IPI to a core.
    unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8);

    /// Send a generic IPI.
    unsafe fn send_ipi(&mut self, icr: Icr);
}
<|endoftext|>


<commit_before>pub type Time = f32;

pub struct Behavior<'a, A> where A: 'a {
  closure: Box<Fn(Time) -> A + 'a>,
  next: Option<(Time, &'a Behavior<'a, A>)>
}

impl<'a, A> Behavior<'a, A> {
  pub fn new<F>(act: F, next: Option<(Time, &'a Self)>) -> Self where F: Fn(Time) -> A + 'a {
    Behavior {
      closure: Box::new(act),
      next: next
    }
  }

  pub fn run(&'a self, t: Time) -> (A, &'a Self) {
    let next = self.next;

    match next {
      Some((node_t, node)) if t >= node_t => node.run(t),
      _ => ((self.closure)(t), self)
    }
  }

  pub fn switch(&mut self, t: Time, sw: &'a Self) {
    self.next = Some((t, sw))
  }
}
<commit_msg>Fixed #4.<commit_after>/// Time used to synchronized the behaviors.
pub type Time = f32;

/// A behavior that might switch to another one.
///
/// A `Behavior` is a simple closure of time into `A`. Optionally, a `Behavior` might express the
/// need to switch to another behavior at runtime, based on the current time. That enables dynamic
/// switching of code with ease and a few boilerplate.
///
/// Keep in mind a `Behavior` is a closure that implements `Fn<Time>`.
pub struct Behavior<'a, A> where A: 'a {
  closure: Box<Fn(Time) -> A + 'a>,
  next: Option<(Time, &'a Behavior<'a, A>)>
}

impl<'a, A> Behavior<'a, A> {
  /// Create a new behavior that will behave as `act` until the optional next behavior is triggered.
  pub fn new<F>(act: F, next: Option<(Time, &'a Self)>) -> Self where F: Fn(Time) -> A + 'a {
    Behavior {
      closure: Box::new(act),
      next: next
    }
  }

  /// Run a behavior with the current time. The returned reference is the same reference as `self`
  /// if no switching has occurred. If it has, that reference represents the new switched behavior.
  ///
  /// There are two ways to use behaviors:
  ///
  ///   1. ignoring the returned reference ;
  ///   2. always updating the source reference with the returned one.
  ///
  /// The first way is very handy because of how switching is implemented – reference chaining. You
  /// can use the very first reference of a long behavior reference lists, you’ll always get the
  /// corresponding behavior for the given time. This is very handy especially when debugging, since
  /// you might jump in time.
  ///
  /// The second way is much efficient if you are using a time that goes forward until the end of
  /// the application – which should be the case for the release target. Because you always replace
  /// your reference with the *maybe*-switched one, you are sure that a switch will be always
  /// performed in *O(1)* complexity – while the first way is *O(N)*.
  pub fn run(&'a self, t: Time) -> (A, &'a Self) {
    let next = self.next;

    match next {
      Some((node_t, node)) if t >= node_t => node.run(t),
      _ => ((self.closure)(t), self)
    }
  }

  /// Create a new behavior that will switch to another based on the current time.
  ///
  /// This function discards the switching property of the input behavior.
  pub fn switch(&'a self, t: Time, sw: &'a Self) -> Self {
    Behavior {
      closure: Box::new(move |t| {
          (self.closure)(t)
        }),
      next: Some((t, sw))
    }
  }
}
<|endoftext|>


<commit_before>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate byteorder;
extern crate docopt;
extern crate rustc_serialize;

#[cfg(test)] extern crate quickcheck;
#[cfg(test)] extern crate tempdir;

mod args;
mod file;
mod tape;
mod wav;

use std::convert::From;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::Path;

use tape::Tape;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(Debug)]
enum Error {
    Io(io::Error)
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error { Error::Io(e) }
}

type Result<T> = std::result::Result<T, Error>;

#[allow(dead_code)]
fn main() {
    let cmd = args::parse();
    let result = match cmd {
        args::Command::Version => print_version(),
        args::Command::List(path) => list_files(&path),
        args::Command::Add(path, files) =>  {
            let input_files: Vec<&Path> = files.iter().map(|f| f.as_path()).collect();
            add_files(&path, &input_files)
        },
        args::Command::Extract(path) => extract_all(&path),
        args::Command::Export(path, output) => export(&*path, &*output),
    };
    if result.is_err() {
        match result.unwrap_err() {
            Error::Io(e) =>
                println!("Error: IO operation failed: {}", e),
        }
    }
}

fn print_version() -> Result<()> {
    println!("MSX CAS Packager (MCP) v{}", VERSION);
    println!("Copyright (C) 2015 Alvaro Polo");
    println!("");
    println!("This program is subject to the terms of the Mozilla Public License v2.0.");
    println!("");
    Ok(())
}

fn list_files(path: &Path) -> Result<()> {
    let tape = try!(tape::Tape::from_file(path));
    for file in tape.files() {
        match file {
            tape::File::Bin(name, begin, end, start, data) => {
                println!("bin    | {:6} | {:5} bytes | [0x{:x},0x{:x}]:0x{:x}",
                    name, data.len(), begin, end, start);
            },
            tape::File::Basic(name, data) => {
                println!("basic  | {:6} | {:5} bytes |", name, data.len());
            },
            tape::File::Ascii(name, data) => {
                let nbytes = data.iter().fold(0, |size, chunk| size + chunk.len());
                println!("ascii  | {:6} | {:5} bytes |", name, nbytes);
            },
            tape::File::Custom(data) => {
                println!("custom |        | {:5} bytes |", data.len());
            }
        };
    }
    Ok(())
}

fn extract_all(path: &Path) -> Result<()> {
    let tape = try!(tape::Tape::from_file(path));
    let mut next_custom = 0;
    for file in tape.files() {
        let out_path = file.name()
            .map(|n| n.to_string())
            .unwrap_or_else(|| format!("custom.{:03}", { next_custom += 1; next_custom }));
        print!("Extracting {}... ", out_path);
        try!(extract_file(&file, Path::new(&out_path)));
        println!("Done");
    }
    Ok(())
}

fn extract_file(file: &tape::File, out_path: &Path) -> Result<()> {
    let (out_filename, clash) = try!(file::unique_filename(out_path));
    if clash {
        println!("Warning: filename {:?} already exists, writing output to {:?}",
            out_path, out_filename);
    }
    let mut ofile = try!(File::create(&out_filename));
    match file {
        &tape::File::Bin(_, _, _, _, data) => {
            // First, write the BIN file ID byte not present in cassete
            try!(ofile.write_all(&[0xfe]));
            try!(ofile.write_all(data));
        },
        &tape::File::Basic(_, data) => {
            try!(ofile.write_all(data));
        },
        &tape::File::Ascii(_, ref chunks) => {
            for chunk in chunks {
                let last = chunk.iter().position(|b| *b == 0x1a).unwrap_or(chunk.len());
                try!(ofile.write_all(&chunk[..last]));
            }
        },
        &tape::File::Custom(ref data) => {
            try!(ofile.write_all(data));
        },
    }
    Ok(())
}

fn add_files(path: &Path, files: &[&Path]) -> Result<()> {
    let mut tape = Tape::from_file(path).unwrap_or_else(|_| Tape::new());
    for file in files {
        if file::is_bin_file(file) {
            print!("Adding binary file {:?}... ", file.as_os_str());
            try!(add_bin_file(&mut tape, &file));
        } else if file::is_ascii_file(file) {
            print!("Adding ascii file {:?}... ", file.as_os_str());
            try!(add_ascii_file(&mut tape, &file));
        } else if file::is_basic_file(file) {
            print!("Adding basic file {:?}... ", file.as_os_str());
            try!(add_basic_file(&mut tape, &file));
        } else {
            print!("Adding custom file {:?}... ", file.as_os_str());
            try!(add_custom_file(&mut tape, &file));
        }
        println!("Done");
    }
    try!(save_tape(&tape, &path));
    Ok(())
}

fn add_bin_file(tape: &mut tape::Tape, file: &Path) -> Result<()> {
    let data = try!(file::read_content(file));
    // Skip bin file ID byte if present
    let bytes = if data[0] == 0xfe { &data[1..] } else { &data[..] };
    let (fname, truncated) = try!(file::file_name_of(file));
    if truncated {
        println!("Warning: file name truncated to {}", String::from_utf8_lossy(&fname));
    }
    tape.append_bin(&fname, bytes);
    Ok(())
}

fn add_basic_file(tape: &mut tape::Tape, file: &Path) -> Result<()> {
    let data = try!(file::read_content(file));
    let (fname, truncated) = try!(file::file_name_of(file));
    if truncated {
        println!("Warning: file name truncated to {}", String::from_utf8_lossy(&fname));
    }
    tape.append_basic(&fname, &data);
    Ok(())
}

fn add_ascii_file(tape: &mut tape::Tape, file: &Path) -> Result<()> {
    let data = try!(file::read_content(file));
    let (fname, truncated) = try!(file::file_name_of(file));
    if truncated {
        println!("Warning: file name truncated to {}", String::from_utf8_lossy(&fname));
    }
    tape.append_ascii(&fname, &data);
    Ok(())
}

fn add_custom_file(tape: &mut tape::Tape, file: &Path) -> Result<()> {
    let data = try!(file::read_content(file));
    tape.append_custom(&data);
    Ok(())
}

fn save_tape(tape: &tape::Tape, file: &Path) -> Result<()> {
    let mut buff = Vec::with_capacity(64*1024);
    for block in tape.blocks() {
        try!(buff.write_all(block.data()));
    }
    try!(file::write_content(file, &buff));
    Ok(())
}

fn export(cas_path: &Path, wav_path: &Path) -> Result<()> {
    let tape = try!(Tape::from_file(cas_path));
    let mut exporter = wav::Exporter::new();
    let mut wav_file = try!(File::create(wav_path));

    for (block, i) in tape.blocks().iter().zip(0..tape.blocks().len()) {
        print!("Encoding block {}... ", i);
        let mut nbytes = 0;
        if block.is_file_header() {
            nbytes += exporter.write_long_silence().ok().unwrap();
            nbytes += exporter.write_long_header().ok().unwrap();
        } else {
            nbytes += exporter.write_short_silence().ok().unwrap();
            nbytes += exporter.write_short_header().ok().unwrap();
        }
        nbytes += exporter.write_data(block.data_without_prefix()).ok().unwrap();
        println!("{} KiB", nbytes / 1024);
    }
    exporter.export(&mut wav_file).ok();
    Ok(())
}
<commit_msg>Improve warning messages output<commit_after>//
// MSX CAS Packager
// Copyright (c) 2015 Alvaro Polo
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate byteorder;
extern crate docopt;
extern crate rustc_serialize;

#[cfg(test)] extern crate quickcheck;
#[cfg(test)] extern crate tempdir;

mod args;
mod file;
mod tape;
mod wav;

use std::convert::From;
use std::fs::File;
use std::io;
use std::io::Write;
use std::path::Path;

use tape::Tape;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(Debug)]
enum Error {
    Io(io::Error)
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Error { Error::Io(e) }
}

type Result<T> = std::result::Result<T, Error>;

#[allow(dead_code)]
fn main() {
    let cmd = args::parse();
    let result = match cmd {
        args::Command::Version => print_version(),
        args::Command::List(path) => list_files(&path),
        args::Command::Add(path, files) =>  {
            let input_files: Vec<&Path> = files.iter().map(|f| f.as_path()).collect();
            add_files(&path, &input_files)
        },
        args::Command::Extract(path) => extract_all(&path),
        args::Command::Export(path, output) => export(&*path, &*output),
    };
    if result.is_err() {
        match result.unwrap_err() {
            Error::Io(e) =>
                println!("Error: IO operation failed: {}", e),
        }
    }
}

fn print_version() -> Result<()> {
    println!("MSX CAS Packager (MCP) v{}", VERSION);
    println!("Copyright (C) 2015 Alvaro Polo");
    println!("");
    println!("This program is subject to the terms of the Mozilla Public License v2.0.");
    println!("");
    Ok(())
}

fn list_files(path: &Path) -> Result<()> {
    let tape = try!(tape::Tape::from_file(path));
    for file in tape.files() {
        match file {
            tape::File::Bin(name, begin, end, start, data) => {
                println!("bin    | {:6} | {:5} bytes | [0x{:x},0x{:x}]:0x{:x}",
                    name, data.len(), begin, end, start);
            },
            tape::File::Basic(name, data) => {
                println!("basic  | {:6} | {:5} bytes |", name, data.len());
            },
            tape::File::Ascii(name, data) => {
                let nbytes = data.iter().fold(0, |size, chunk| size + chunk.len());
                println!("ascii  | {:6} | {:5} bytes |", name, nbytes);
            },
            tape::File::Custom(data) => {
                println!("custom |        | {:5} bytes |", data.len());
            }
        };
    }
    Ok(())
}

fn extract_all(path: &Path) -> Result<()> {
    let tape = try!(tape::Tape::from_file(path));
    let mut next_custom = 0;
    for file in tape.files() {
        let out_path = file.name()
            .map(|n| n.to_string())
            .unwrap_or_else(|| format!("custom.{:03}", { next_custom += 1; next_custom }));
        print!("Extracting {}... ", out_path);
        try!(extract_file(&file, Path::new(&out_path)));
        println!("Done");
    }
    Ok(())
}

fn extract_file(file: &tape::File, out_path: &Path) -> Result<()> {
    let (out_filename, clash) = try!(file::unique_filename(out_path));
    if clash {
        print!("Warning: filename {:?} already exists, writing output to {:?}... ",
            out_path, out_filename);
    }
    let mut ofile = try!(File::create(&out_filename));
    match file {
        &tape::File::Bin(_, _, _, _, data) => {
            // First, write the BIN file ID byte not present in cassete
            try!(ofile.write_all(&[0xfe]));
            try!(ofile.write_all(data));
        },
        &tape::File::Basic(_, data) => {
            try!(ofile.write_all(data));
        },
        &tape::File::Ascii(_, ref chunks) => {
            for chunk in chunks {
                let last = chunk.iter().position(|b| *b == 0x1a).unwrap_or(chunk.len());
                try!(ofile.write_all(&chunk[..last]));
            }
        },
        &tape::File::Custom(ref data) => {
            try!(ofile.write_all(data));
        },
    }
    Ok(())
}

fn add_files(path: &Path, files: &[&Path]) -> Result<()> {
    let mut tape = Tape::from_file(path).unwrap_or_else(|_| Tape::new());
    for file in files {
        if file::is_bin_file(file) {
            print!("Adding binary file {:?}... ", file.as_os_str());
            try!(add_bin_file(&mut tape, &file));
        } else if file::is_ascii_file(file) {
            print!("Adding ascii file {:?}... ", file.as_os_str());
            try!(add_ascii_file(&mut tape, &file));
        } else if file::is_basic_file(file) {
            print!("Adding basic file {:?}... ", file.as_os_str());
            try!(add_basic_file(&mut tape, &file));
        } else {
            print!("Adding custom file {:?}... ", file.as_os_str());
            try!(add_custom_file(&mut tape, &file));
        }
        println!("Done");
    }
    try!(save_tape(&tape, &path));
    Ok(())
}

fn add_bin_file(tape: &mut tape::Tape, file: &Path) -> Result<()> {
    let data = try!(file::read_content(file));
    // Skip bin file ID byte if present
    let bytes = if data[0] == 0xfe { &data[1..] } else { &data[..] };
    let (fname, truncated) = try!(file::file_name_of(file));
    if truncated {
        print!("Warning: file name truncated to {}... ", String::from_utf8_lossy(&fname));
    }
    tape.append_bin(&fname, bytes);
    Ok(())
}

fn add_basic_file(tape: &mut tape::Tape, file: &Path) -> Result<()> {
    let data = try!(file::read_content(file));
    let (fname, truncated) = try!(file::file_name_of(file));
    if truncated {
        print!("Warning: file name truncated to {}... ", String::from_utf8_lossy(&fname));
    }
    tape.append_basic(&fname, &data);
    Ok(())
}

fn add_ascii_file(tape: &mut tape::Tape, file: &Path) -> Result<()> {
    let data = try!(file::read_content(file));
    let (fname, truncated) = try!(file::file_name_of(file));
    if truncated {
        print!("Warning: file name truncated to {}... ", String::from_utf8_lossy(&fname));
    }
    tape.append_ascii(&fname, &data);
    Ok(())
}

fn add_custom_file(tape: &mut tape::Tape, file: &Path) -> Result<()> {
    let data = try!(file::read_content(file));
    tape.append_custom(&data);
    Ok(())
}

fn save_tape(tape: &tape::Tape, file: &Path) -> Result<()> {
    let mut buff = Vec::with_capacity(64*1024);
    for block in tape.blocks() {
        try!(buff.write_all(block.data()));
    }
    try!(file::write_content(file, &buff));
    Ok(())
}

fn export(cas_path: &Path, wav_path: &Path) -> Result<()> {
    let tape = try!(Tape::from_file(cas_path));
    let mut exporter = wav::Exporter::new();
    let mut wav_file = try!(File::create(wav_path));

    for (block, i) in tape.blocks().iter().zip(0..tape.blocks().len()) {
        print!("Encoding block {}... ", i);
        let mut nbytes = 0;
        if block.is_file_header() {
            nbytes += exporter.write_long_silence().ok().unwrap();
            nbytes += exporter.write_long_header().ok().unwrap();
        } else {
            nbytes += exporter.write_short_silence().ok().unwrap();
            nbytes += exporter.write_short_header().ok().unwrap();
        }
        nbytes += exporter.write_data(block.data_without_prefix()).ok().unwrap();
        println!("{} KiB", nbytes / 1024);
    }
    exporter.export(&mut wav_file).ok();
    Ok(())
}
<|endoftext|>


<commit_before>use crate::aabb::Bounded;
use crate::bvh::{BVHNode, BVH};
use crate::ray::Ray;

/// Iterator to traverse a [`BVH`] without memory allocations
#[allow(clippy::upper_case_acronyms)]
pub struct BVHTraverseIterator<'a, Shape: Bounded> {
    /// Reference to the BVH to traverse
    bvh: &'a BVH,
    /// Reference to the input ray
    ray: &'a Ray,
    /// Reference to the input shapes array
    shapes: &'a [Shape],
    /// Traversal stack. 4 billion items seems enough?
    stack: [usize; 32],
    /// Position of the iterator in bvh.nodes
    node_index: usize,
    /// Size of the traversal stack
    stack_size: usize,
    /// Whether or not we have a valid node (or leaf)
    has_node: bool,
}

impl<'a, Shape: Bounded> BVHTraverseIterator<'a, Shape> {
    /// Creates a new `BVHTraverseIterator`
    pub fn new(bvh: &'a BVH, ray: &'a Ray, shapes: &'a [Shape]) -> Self {
        BVHTraverseIterator {
            bvh,
            ray,
            shapes,
            stack: [0; 32],
            node_index: 0,
            stack_size: 0,
            has_node: true,
        }
    }

    /// Test if stack is empty.
    fn is_stack_empty(&self) -> bool {
        self.stack_size == 0
    }

    /// Push node onto stack.
    ///
    /// # Panics
    ///
    /// Panics if `stack[stack_size]` is out of bounds.
    fn stack_push(&mut self, node: usize) {
        self.stack[self.stack_size] = node;
        self.stack_size += 1;
    }

    /// Pop the stack and return the node.
    ///
    /// # Panics
    ///
    /// Panics if `stack_size` underflows.
    fn stack_pop(&mut self) -> usize {
        self.stack_size -= 1;
        self.stack[self.stack_size]
    }

    /// Attempt to move to the left node child of the current node.
    /// If it is a leaf, or the ray does not intersect the node `AABB`, `has_node` will become false.
    fn move_left(&mut self) {
        match self.bvh.nodes[self.node_index] {
            BVHNode::Node {
                child_l_index,
                ref child_l_aabb,
                ..
            } => {
                if self.ray.intersects_aabb(child_l_aabb) {
                    self.node_index = child_l_index;
                    self.has_node = true;
                } else {
                    self.has_node = false;
                }
            }
            BVHNode::Leaf { .. } => {
                self.has_node = false;
            }
        }
    }

    /// Attempt to move to the right node child of the current node.
    /// If it is a leaf, or the ray does not intersect the node `AABB`, `has_node` will become false.
    fn move_right(&mut self) {
        match self.bvh.nodes[self.node_index] {
            BVHNode::Node {
                child_r_index,
                ref child_r_aabb,
                ..
            } => {
                if self.ray.intersects_aabb(child_r_aabb) {
                    self.node_index = child_r_index;
                    self.has_node = true;
                } else {
                    self.has_node = false;
                }
            }
            BVHNode::Leaf { .. } => {
                self.has_node = false;
            }
        }
    }
}

impl<'a, Shape: Bounded> Iterator for BVHTraverseIterator<'a, Shape> {
    type Item = &'a Shape;

    fn next(&mut self) -> Option<&'a Shape> {
        loop {
            if self.is_stack_empty() && !self.has_node {
                // Completed traversal.
                break;
            }
            if self.has_node {
                // If we have any node, save it and attempt to move to its left child.
                self.stack_push(self.node_index);
                self.move_left();
            } else {
                // Go back up the stack and see if a node or leaf was pushed.
                self.node_index = self.stack_pop();
                match self.bvh.nodes[self.node_index] {
                    BVHNode::Node { .. } => {
                        // If a node was pushed, now attempt to move to its right child.
                        self.move_right();
                    }
                    BVHNode::Leaf { shape_index, .. } => {
                        // We previously pushed a leaf node. This is the "visit" of the in-order traverse.
                        // Next time we call `next()` we try to pop the stack again.
                        self.has_node = false;
                        return Some(&self.shapes[shape_index]);
                    }
                }
            }
        }
        None
    }
}

// Copy of part of the BH testing in testbase.
// TODO: Once iterators are part of the BoundingHierarchy trait we can move all this to testbase.
#[cfg(test)]
mod tests {
    use crate::bvh::{BVHNode, BVH};
    use std::collections::HashSet;
    use std::f32;

    use nalgebra::{Point3, Vector3};

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

    /// Define some `Bounded` structure.
    pub struct UnitBox {
        pub id: i32,
        pub pos: Point3<f32>,
        node_index: usize,
    }

    impl UnitBox {
        pub fn new(id: i32, pos: Point3<f32>) -> UnitBox {
            UnitBox {
                id: id,
                pos: pos,
                node_index: 0,
            }
        }
    }

    /// `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;
        }

        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::new(x, Point3::new(x as f32, 0.0, 0.0)));
        }
        shapes
    }

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

    /// 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_vec(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        let ray = Ray::new(ray_origin, ray_direction);
        let hit_shapes = bvh.traverse(&ray, all_shapes);

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

    fn traverse_and_verify_iterator(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        let ray = Ray::new(ray_origin, ray_direction);
        let it = bvh.traverse_iterator(&ray, all_shapes);

        let mut count = 0;
        for shape in it {
            assert!(expected_shapes.contains(&shape.id));
            count += 1;
        }
        assert_eq!(expected_shapes.len(), count);
    }

    fn traverse_and_verify_base(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        traverse_and_verify_vec(ray_origin, ray_direction, all_shapes, bvh, expected_shapes);
        traverse_and_verify_iterator(ray_origin, ray_direction, all_shapes, bvh, expected_shapes);
    }

    /// Perform some fixed intersection tests on BH structures.
    pub fn traverse_some_bvh() {
        let (all_shapes, bh) = build_some_bvh();

        {
            // 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_base(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_base(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_base(origin, direction, &all_shapes, &bh, &expected_shapes);
        }
    }

    #[test]
    /// Runs some primitive tests for intersections of a ray with a fixed scene given as a BVH.
    fn test_traverse_bvh() {
        traverse_some_bvh();
    }

    #[test]
    /// Verify contents of the bounding hierarchy for a fixed scene structure
    fn test_bvh_shape_indices() {
        use std::collections::HashSet;

        let (all_shapes, bh) = build_some_bvh();

        // It should find all shape indices.
        let expected_shapes: HashSet<_> = (0..all_shapes.len()).collect();
        let mut found_shapes = HashSet::new();

        for node in bh.nodes.iter() {
            match *node {
                BVHNode::Node { .. } => {
                    assert_eq!(node.shape_index(), None);
                }
                BVHNode::Leaf { .. } => {
                    found_shapes.insert(
                        node.shape_index()
                            .expect("getting a shape index from a leaf node"),
                    );
                }
            }
        }

        assert_eq!(expected_shapes, found_shapes);
    }
}

#[cfg(all(feature = "bench", test))]
mod bench {
    use crate::bvh::BVH;
    use crate::testbase::{create_ray, load_sponza_scene};

    #[bench]
    /// Benchmark the traversal of a `BVH` with the Sponza scene with Vec return.
    fn bench_intersect_128rays_sponza_vec(b: &mut ::test::Bencher) {
        let (mut triangles, bounds) = load_sponza_scene();
        let bvh = BVH::build(&mut triangles);

        let mut seed = 0;
        b.iter(|| {
            for _ in 0..128 {
                let ray = create_ray(&mut seed, &bounds);

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

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

    #[bench]
    /// Benchmark the traversal of a `BVH` with the Sponza scene with `BVHTraverseIterator`.
    fn bench_intersect_128rays_sponza_iter(b: &mut ::test::Bencher) {
        let (mut triangles, bounds) = load_sponza_scene();
        let bvh = BVH::build(&mut triangles);

        let mut seed = 0;
        b.iter(|| {
            for _ in 0..128 {
                let ray = create_ray(&mut seed, &bounds);

                // Traverse the `BVH` recursively.
                let hits = bvh.traverse_iterator(&ray, &triangles);

                // Traverse the resulting list of positive `AABB` tests
                for triangle in hits {
                    ray.intersects_triangle(&triangle.a, &triangle.b, &triangle.c);
                }
            }
        });
    }
}
<commit_msg>Removed duplicated testbase code where possible<commit_after>use crate::aabb::Bounded;
use crate::bvh::{BVHNode, BVH};
use crate::ray::Ray;

/// Iterator to traverse a [`BVH`] without memory allocations
#[allow(clippy::upper_case_acronyms)]
pub struct BVHTraverseIterator<'a, Shape: Bounded> {
    /// Reference to the BVH to traverse
    bvh: &'a BVH,
    /// Reference to the input ray
    ray: &'a Ray,
    /// Reference to the input shapes array
    shapes: &'a [Shape],
    /// Traversal stack. 4 billion items seems enough?
    stack: [usize; 32],
    /// Position of the iterator in bvh.nodes
    node_index: usize,
    /// Size of the traversal stack
    stack_size: usize,
    /// Whether or not we have a valid node (or leaf)
    has_node: bool,
}

impl<'a, Shape: Bounded> BVHTraverseIterator<'a, Shape> {
    /// Creates a new `BVHTraverseIterator`
    pub fn new(bvh: &'a BVH, ray: &'a Ray, shapes: &'a [Shape]) -> Self {
        BVHTraverseIterator {
            bvh,
            ray,
            shapes,
            stack: [0; 32],
            node_index: 0,
            stack_size: 0,
            has_node: true,
        }
    }

    /// Test if stack is empty.
    fn is_stack_empty(&self) -> bool {
        self.stack_size == 0
    }

    /// Push node onto stack.
    ///
    /// # Panics
    ///
    /// Panics if `stack[stack_size]` is out of bounds.
    fn stack_push(&mut self, node: usize) {
        self.stack[self.stack_size] = node;
        self.stack_size += 1;
    }

    /// Pop the stack and return the node.
    ///
    /// # Panics
    ///
    /// Panics if `stack_size` underflows.
    fn stack_pop(&mut self) -> usize {
        self.stack_size -= 1;
        self.stack[self.stack_size]
    }

    /// Attempt to move to the left node child of the current node.
    /// If it is a leaf, or the ray does not intersect the node `AABB`, `has_node` will become false.
    fn move_left(&mut self) {
        match self.bvh.nodes[self.node_index] {
            BVHNode::Node {
                child_l_index,
                ref child_l_aabb,
                ..
            } => {
                if self.ray.intersects_aabb(child_l_aabb) {
                    self.node_index = child_l_index;
                    self.has_node = true;
                } else {
                    self.has_node = false;
                }
            }
            BVHNode::Leaf { .. } => {
                self.has_node = false;
            }
        }
    }

    /// Attempt to move to the right node child of the current node.
    /// If it is a leaf, or the ray does not intersect the node `AABB`, `has_node` will become false.
    fn move_right(&mut self) {
        match self.bvh.nodes[self.node_index] {
            BVHNode::Node {
                child_r_index,
                ref child_r_aabb,
                ..
            } => {
                if self.ray.intersects_aabb(child_r_aabb) {
                    self.node_index = child_r_index;
                    self.has_node = true;
                } else {
                    self.has_node = false;
                }
            }
            BVHNode::Leaf { .. } => {
                self.has_node = false;
            }
        }
    }
}

impl<'a, Shape: Bounded> Iterator for BVHTraverseIterator<'a, Shape> {
    type Item = &'a Shape;

    fn next(&mut self) -> Option<&'a Shape> {
        loop {
            if self.is_stack_empty() && !self.has_node {
                // Completed traversal.
                break;
            }
            if self.has_node {
                // If we have any node, save it and attempt to move to its left child.
                self.stack_push(self.node_index);
                self.move_left();
            } else {
                // Go back up the stack and see if a node or leaf was pushed.
                self.node_index = self.stack_pop();
                match self.bvh.nodes[self.node_index] {
                    BVHNode::Node { .. } => {
                        // If a node was pushed, now attempt to move to its right child.
                        self.move_right();
                    }
                    BVHNode::Leaf { shape_index, .. } => {
                        // We previously pushed a leaf node. This is the "visit" of the in-order traverse.
                        // Next time we call `next()` we try to pop the stack again.
                        self.has_node = false;
                        return Some(&self.shapes[shape_index]);
                    }
                }
            }
        }
        None
    }
}

// Copy of part of the BH testing in testbase.
// TODO: Once iterators are part of the BoundingHierarchy trait we can move all this to testbase.
#[cfg(test)]
mod tests {
    use crate::bvh::BVH;
    use crate::ray::Ray;
    use crate::testbase::{generate_aligned_boxes, UnitBox};
    use nalgebra::{Point3, Vector3};
    use std::collections::HashSet;

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

    /// 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_vec(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        let ray = Ray::new(ray_origin, ray_direction);
        let hit_shapes = bvh.traverse(&ray, all_shapes);

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

    fn traverse_and_verify_iterator(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        let ray = Ray::new(ray_origin, ray_direction);
        let it = bvh.traverse_iterator(&ray, all_shapes);

        let mut count = 0;
        for shape in it {
            assert!(expected_shapes.contains(&shape.id));
            count += 1;
        }
        assert_eq!(expected_shapes.len(), count);
    }

    fn traverse_and_verify_base(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        traverse_and_verify_vec(ray_origin, ray_direction, all_shapes, bvh, expected_shapes);
        traverse_and_verify_iterator(ray_origin, ray_direction, all_shapes, bvh, expected_shapes);
    }

    /// Perform some fixed intersection tests on BH structures.
    pub fn traverse_some_bvh() {
        let (all_shapes, bvh) = build_some_bvh();

        {
            // 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_base(origin, direction, &all_shapes, &bvh, &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_base(origin, direction, &all_shapes, &bvh, &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_base(origin, direction, &all_shapes, &bvh, &expected_shapes);
        }
    }

    #[test]
    /// Runs some primitive tests for intersections of a ray with a fixed scene given as a BVH.
    fn test_traverse_bvh() {
        traverse_some_bvh();
    }
}

#[cfg(all(feature = "bench", test))]
mod bench {
    use crate::bvh::BVH;
    use crate::testbase::{create_ray, load_sponza_scene};

    #[bench]
    /// Benchmark the traversal of a `BVH` with the Sponza scene with Vec return.
    fn bench_intersect_128rays_sponza_vec(b: &mut ::test::Bencher) {
        let (mut triangles, bounds) = load_sponza_scene();
        let bvh = BVH::build(&mut triangles);

        let mut seed = 0;
        b.iter(|| {
            for _ in 0..128 {
                let ray = create_ray(&mut seed, &bounds);

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

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

    #[bench]
    /// Benchmark the traversal of a `BVH` with the Sponza scene with `BVHTraverseIterator`.
    fn bench_intersect_128rays_sponza_iter(b: &mut ::test::Bencher) {
        let (mut triangles, bounds) = load_sponza_scene();
        let bvh = BVH::build(&mut triangles);

        let mut seed = 0;
        b.iter(|| {
            for _ in 0..128 {
                let ray = create_ray(&mut seed, &bounds);

                // Traverse the `BVH` recursively.
                let hits = bvh.traverse_iterator(&ray, &triangles);

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


<commit_before>use cli::Command;

#[warn(unused_imports)]
use std::io::prelude::*;
use std::fs::File;

pub const DEFAULT_CONTENT: &'static str =
"## Funzzy events file
# more details see: http://cristian.github.com/funzzy
#
# list here all the events and the commands that it should execute

- name: run my tests
  when:
    change: 'src/**'
    run: ls -a
";

/// # InitCommand
/// Creates a funzzy yaml boilerplate.
///
pub struct InitCommand {
    pub file_name: &'static str
}
impl InitCommand {
    pub fn new() -> Self {
        InitCommand {
            file_name: ""
        }
    }
}

impl Command for InitCommand {
    fn execute(&self) -> Result<(), &str>{
        let mut yaml:File = match File::create(self.file_name) {
           Ok(f) => f,
           Err(err) => panic!("File not created. Cause: {}", err)
        };

        match yaml.write_all(DEFAULT_CONTENT.as_ref()) {
           Ok(_) => Ok(()),
           Err(_) => panic!("Cannot write file.")
        }
    }
}
<commit_msg>chore: change bootstrap site<commit_after>use cli::Command;

#[warn(unused_imports)]
use std::io::prelude::*;
use std::fs::File;

pub const DEFAULT_CONTENT: &'static str =
"## Funzzy events file
# more details see: https://github.com/cristianoliveira/funzzy
#
# list here all the events and the commands that it should execute

- name: run my tests
  when:
    change: 'src/**'
    run: ls -a
";

/// # InitCommand
/// Creates a funzzy yaml boilerplate.
///
pub struct InitCommand {
    pub file_name: &'static str
}
impl InitCommand {
    pub fn new() -> Self {
        InitCommand {
            file_name: ""
        }
    }
}

impl Command for InitCommand {
    fn execute(&self) -> Result<(), &str>{
        let mut yaml:File = match File::create(self.file_name) {
           Ok(f) => f,
           Err(err) => panic!("File not created. Cause: {}", err)
        };

        match yaml.write_all(DEFAULT_CONTENT.as_ref()) {
           Ok(_) => Ok(()),
           Err(_) => panic!("Cannot write file.")
        }
    }
}
<|endoftext|>