<commit_before>#![warn(rust_2018_idioms)]
extern crate conduit;

use std::io::prelude::*;
use std::io::Cursor;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

use conduit::{
    header::{HeaderName, HeaderValue},
    Extensions, HeaderMap, Host, Method, Scheme, TypeMap, Version,
};

pub struct MockRequest {
    path: String,
    method: Method,
    query_string: Option<String>,
    body: Option<Vec<u8>>,
    headers: HeaderMap,
    extensions: TypeMap,
    reader: Option<Cursor<Vec<u8>>>,
}

impl MockRequest {
    pub fn new(method: Method, path: &str) -> MockRequest {
        let headers = HeaderMap::new();

        MockRequest {
            path: path.to_string(),
            extensions: TypeMap::new(),
            query_string: None,
            body: None,
            headers,
            method,
            reader: None,
        }
    }

    pub fn with_method(&mut self, method: Method) -> &mut MockRequest {
        self.method = method;
        self
    }

    pub fn with_path(&mut self, path: &str) -> &mut MockRequest {
        self.path = path.to_string();
        self
    }

    pub fn with_query(&mut self, string: &str) -> &mut MockRequest {
        self.query_string = Some(string.to_string());
        self
    }

    pub fn with_body(&mut self, bytes: &[u8]) -> &mut MockRequest {
        self.body = Some(bytes.to_vec());
        self.reader = None;
        self
    }

    pub fn header(&mut self, name: HeaderName, value: &str) -> &mut MockRequest {
        self.headers
            .insert(name, HeaderValue::from_str(value).unwrap());
        self
    }
}

impl conduit::RequestExt for MockRequest {
    fn http_version(&self) -> Version {
        Version::HTTP_11
    }

    fn method(&self) -> &Method {
        &self.method
    }
    fn scheme(&self) -> Scheme {
        Scheme::Http
    }
    fn host(&self) -> Host<'_> {
        Host::Name("example.com")
    }
    fn virtual_root(&self) -> Option<&str> {
        None
    }

    fn path(&self) -> &str {
        &self.path
    }

    fn query_string(&self) -> Option<&str> {
        self.query_string.as_ref().map(|s| &s[..])
    }

    fn remote_addr(&self) -> SocketAddr {
        SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80))
    }

    fn content_length(&self) -> Option<u64> {
        self.body.as_ref().map(|b| b.len() as u64)
    }

    fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    fn body(&mut self) -> &mut dyn Read {
        if self.reader.is_none() {
            let body = self.body.clone().unwrap_or_default();
            self.reader = Some(Cursor::new(body));
        }
        self.reader.as_mut().unwrap()
    }

    fn extensions(&self) -> &Extensions {
        &self.extensions
    }
    fn mut_extensions(&mut self) -> &mut Extensions {
        &mut self.extensions
    }
}

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

    use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

    use conduit::{header, Host, Method, RequestExt, Scheme, Version};

    #[test]
    fn simple_request_test() {
        let mut req = MockRequest::new(Method::GET, "/");

        assert_eq!(req.http_version(), Version::HTTP_11);
        assert_eq!(req.method(), Method::GET);
        assert_eq!(req.scheme(), Scheme::Http);
        assert_eq!(req.host(), Host::Name("example.com"));
        assert_eq!(req.virtual_root(), None);
        assert_eq!(req.path(), "/");
        assert_eq!(req.query_string(), None);
        assert_eq!(
            req.remote_addr(),
            SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80))
        );
        assert_eq!(req.content_length(), None);
        assert_eq!(req.headers().len(), 0);
        let mut s = String::new();
        req.body().read_to_string(&mut s).ok().expect("No body");
        assert_eq!(s, "".to_string());
    }

    #[test]
    fn request_body_test() {
        let mut req = MockRequest::new(Method::POST, "/articles");
        req.with_body(b"Hello world");

        assert_eq!(req.method(), Method::POST);
        assert_eq!(req.path(), "/articles");
        let mut s = String::new();
        req.body().read_to_string(&mut s).ok().expect("No body");
        assert_eq!(s, "Hello world".to_string());
        assert_eq!(req.content_length(), Some(11));
    }

    #[test]
    fn request_query_test() {
        let mut req = MockRequest::new(Method::POST, "/articles");
        req.with_query("foo=bar");

        assert_eq!(req.query_string().expect("No query string"), "foo=bar");
    }

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(Method::POST, "/articles");
        req.header(header::USER_AGENT, "lulz");
        req.header(header::DNT, "1");

        assert_eq!(req.headers().len(), 2);
        assert_eq!(req.headers().get(header::USER_AGENT).unwrap(), "lulz");
        assert_eq!(req.headers().get(header::DNT).unwrap(), "1");
    }
}
<commit_msg>Improve header API<commit_after>#![warn(rust_2018_idioms)]
extern crate conduit;

use std::io::prelude::*;
use std::io::Cursor;
use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

use conduit::{
    header::{HeaderValue, IntoHeaderName},
    Extensions, HeaderMap, Host, Method, Scheme, TypeMap, Version,
};

pub struct MockRequest {
    path: String,
    method: Method,
    query_string: Option<String>,
    body: Option<Vec<u8>>,
    headers: HeaderMap,
    extensions: TypeMap,
    reader: Option<Cursor<Vec<u8>>>,
}

impl MockRequest {
    pub fn new(method: Method, path: &str) -> MockRequest {
        let headers = HeaderMap::new();

        MockRequest {
            path: path.to_string(),
            extensions: TypeMap::new(),
            query_string: None,
            body: None,
            headers,
            method,
            reader: None,
        }
    }

    pub fn with_method(&mut self, method: Method) -> &mut MockRequest {
        self.method = method;
        self
    }

    pub fn with_path(&mut self, path: &str) -> &mut MockRequest {
        self.path = path.to_string();
        self
    }

    pub fn with_query(&mut self, string: &str) -> &mut MockRequest {
        self.query_string = Some(string.to_string());
        self
    }

    pub fn with_body(&mut self, bytes: &[u8]) -> &mut MockRequest {
        self.body = Some(bytes.to_vec());
        self.reader = None;
        self
    }

    pub fn header<K>(&mut self, name: K, value: &str) -> &mut MockRequest
    where
        K: IntoHeaderName,
    {
        self.headers
            .insert(name, HeaderValue::from_str(value).unwrap());
        self
    }
}

impl conduit::RequestExt for MockRequest {
    fn http_version(&self) -> Version {
        Version::HTTP_11
    }

    fn method(&self) -> &Method {
        &self.method
    }
    fn scheme(&self) -> Scheme {
        Scheme::Http
    }
    fn host(&self) -> Host<'_> {
        Host::Name("example.com")
    }
    fn virtual_root(&self) -> Option<&str> {
        None
    }

    fn path(&self) -> &str {
        &self.path
    }

    fn query_string(&self) -> Option<&str> {
        self.query_string.as_ref().map(|s| &s[..])
    }

    fn remote_addr(&self) -> SocketAddr {
        SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80))
    }

    fn content_length(&self) -> Option<u64> {
        self.body.as_ref().map(|b| b.len() as u64)
    }

    fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    fn body(&mut self) -> &mut dyn Read {
        if self.reader.is_none() {
            let body = self.body.clone().unwrap_or_default();
            self.reader = Some(Cursor::new(body));
        }
        self.reader.as_mut().unwrap()
    }

    fn extensions(&self) -> &Extensions {
        &self.extensions
    }
    fn mut_extensions(&mut self) -> &mut Extensions {
        &mut self.extensions
    }
}

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

    use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};

    use conduit::{header, Host, Method, RequestExt, Scheme, Version};

    #[test]
    fn simple_request_test() {
        let mut req = MockRequest::new(Method::GET, "/");

        assert_eq!(req.http_version(), Version::HTTP_11);
        assert_eq!(req.method(), Method::GET);
        assert_eq!(req.scheme(), Scheme::Http);
        assert_eq!(req.host(), Host::Name("example.com"));
        assert_eq!(req.virtual_root(), None);
        assert_eq!(req.path(), "/");
        assert_eq!(req.query_string(), None);
        assert_eq!(
            req.remote_addr(),
            SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 80))
        );
        assert_eq!(req.content_length(), None);
        assert_eq!(req.headers().len(), 0);
        let mut s = String::new();
        req.body().read_to_string(&mut s).ok().expect("No body");
        assert_eq!(s, "".to_string());
    }

    #[test]
    fn request_body_test() {
        let mut req = MockRequest::new(Method::POST, "/articles");
        req.with_body(b"Hello world");

        assert_eq!(req.method(), Method::POST);
        assert_eq!(req.path(), "/articles");
        let mut s = String::new();
        req.body().read_to_string(&mut s).ok().expect("No body");
        assert_eq!(s, "Hello world".to_string());
        assert_eq!(req.content_length(), Some(11));
    }

    #[test]
    fn request_query_test() {
        let mut req = MockRequest::new(Method::POST, "/articles");
        req.with_query("foo=bar");

        assert_eq!(req.query_string().expect("No query string"), "foo=bar");
    }

    #[test]
    fn request_headers() {
        let mut req = MockRequest::new(Method::POST, "/articles");
        req.header(header::USER_AGENT, "lulz");
        req.header(header::DNT, "1");

        assert_eq!(req.headers().len(), 2);
        assert_eq!(req.headers().get(header::USER_AGENT).unwrap(), "lulz");
        assert_eq!(req.headers().get(header::DNT).unwrap(), "1");
    }
}
<|endoftext|>


<commit_before>//! This crate provides safe bindings to
//! [wlroots](https://github.com/swaywm/wlroots).
//!
//! Start your [Compositor](struct.Compositor.html) by implementing an [input
//! manager](manager/struct.InputManager.html) and an [output
//! manager](manager/struct.OutputManager.html) on two separate structs.
#![cfg_attr(not(feature = "unstable"), allow(unused_imports, unused_macros))]

#![allow(unused_unsafe)]
#[macro_use]
extern crate bitflags;
extern crate lazy_static;
pub extern crate libc;
extern crate vsprintf;
#[macro_use]
pub extern crate wlroots_sys;
extern crate wlroots_dehandle;
pub extern crate xkbcommon;

pub use wlroots_dehandle::wlroots_dehandle;
pub(crate) use wlroots_sys::wayland_sys;

#[macro_use]
mod macros;
#[cfg(feature = "unstable")]
mod manager;
#[cfg(feature = "unstable")]
mod compositor;
#[cfg(feature = "unstable")]
mod errors;
#[cfg(feature = "unstable")]
mod events;
mod types;
#[cfg(feature = "unstable")]
pub mod extensions;
#[cfg(feature = "unstable")]
mod render;
pub mod utils;
#[cfg(feature = "unstable")]
mod xwayland;
#[cfg(feature = "unstable")]
mod backend;

pub use types::*;

#[cfg(feature = "unstable")]
pub use self::backend::*;
#[cfg(feature = "unstable")]
pub use self::compositor::{compositor_handle, terminate, Compositor, CompositorBuilder,
                            CompositorHandle, CompositorHandler};
#[cfg(feature = "unstable")]
pub use events::*;
#[cfg(feature = "unstable")]
pub use self::manager::{InputManagerHandler, KeyboardHandler, OutputBuilder, OutputBuilderResult,
                        OutputHandler, OutputManagerHandler, PointerHandler, TabletPadHandler,
                        TabletToolHandler, TouchHandler, XdgV6ShellHandler,
                        XdgV6ShellManagerHandler, XdgShellHandler, XdgShellManagerHandler,
                        DragIconHandler};

#[cfg(feature = "unstable")]
pub use self::xwayland::{XWaylandManagerHandler, XWaylandServer, XWaylandSurface,
                         XWaylandSurfaceHandle, XWaylandSurfaceHandler, XWaylandSurfaceHints,
                         XWaylandSurfaceSizeHints};
#[cfg(feature = "unstable")]
pub use wlroots_sys::{wlr_keyboard_modifiers as KeyboardModifiers,
                      wlr_tablet_tool_axes as TabletToolAxes,
                      wl_shm_format::{self, *},
                      wlr_axis_orientation::{self, *}, wlr_axis_source::{self, *},
                      wlr_button_state::{self, *}, wlr_input_device_type::{self, *},
                      wlr_key_state::{self, *}, wlr_keyboard_modifier::{self, *},
                      wlr_tablet_pad_ring_source::{self, *},
                      wlr_tablet_pad_strip_source::{self, *},
                      wlr_tablet_tool_proximity_state::{self, *}};

#[cfg(feature = "unstable")]
pub use self::render::*;

#[cfg(feature = "unstable")]
pub use self::errors::*;

<commit_msg>Remove the basic starter help<commit_after>//! This crate provides safe bindings to
//! [wlroots](https://github.com/swaywm/wlroots).
#![cfg_attr(not(feature = "unstable"), allow(unused_imports, unused_macros))]

#![allow(unused_unsafe)]
#[macro_use]
extern crate bitflags;
extern crate lazy_static;
pub extern crate libc;
extern crate vsprintf;
#[macro_use]
pub extern crate wlroots_sys;
extern crate wlroots_dehandle;
pub extern crate xkbcommon;

pub use wlroots_dehandle::wlroots_dehandle;
pub(crate) use wlroots_sys::wayland_sys;

#[macro_use]
mod macros;
#[cfg(feature = "unstable")]
mod manager;
#[cfg(feature = "unstable")]
mod compositor;
#[cfg(feature = "unstable")]
mod errors;
#[cfg(feature = "unstable")]
mod events;
mod types;
#[cfg(feature = "unstable")]
pub mod extensions;
#[cfg(feature = "unstable")]
mod render;
pub mod utils;
#[cfg(feature = "unstable")]
mod xwayland;
#[cfg(feature = "unstable")]
mod backend;

pub use types::*;

#[cfg(feature = "unstable")]
pub use self::backend::*;
#[cfg(feature = "unstable")]
pub use self::compositor::{compositor_handle, terminate, Compositor, CompositorBuilder,
                            CompositorHandle, CompositorHandler};
#[cfg(feature = "unstable")]
pub use events::*;
#[cfg(feature = "unstable")]
pub use self::manager::{InputManagerHandler, KeyboardHandler, OutputBuilder, OutputBuilderResult,
                        OutputHandler, OutputManagerHandler, PointerHandler, TabletPadHandler,
                        TabletToolHandler, TouchHandler, XdgV6ShellHandler,
                        XdgV6ShellManagerHandler, XdgShellHandler, XdgShellManagerHandler,
                        DragIconHandler};

#[cfg(feature = "unstable")]
pub use self::xwayland::{XWaylandManagerHandler, XWaylandServer, XWaylandSurface,
                         XWaylandSurfaceHandle, XWaylandSurfaceHandler, XWaylandSurfaceHints,
                         XWaylandSurfaceSizeHints};
#[cfg(feature = "unstable")]
pub use wlroots_sys::{wlr_keyboard_modifiers as KeyboardModifiers,
                      wlr_tablet_tool_axes as TabletToolAxes,
                      wl_shm_format::{self, *},
                      wlr_axis_orientation::{self, *}, wlr_axis_source::{self, *},
                      wlr_button_state::{self, *}, wlr_input_device_type::{self, *},
                      wlr_key_state::{self, *}, wlr_keyboard_modifier::{self, *},
                      wlr_tablet_pad_ring_source::{self, *},
                      wlr_tablet_pad_strip_source::{self, *},
                      wlr_tablet_tool_proximity_state::{self, *}};

#[cfg(feature = "unstable")]
pub use self::render::*;

#[cfg(feature = "unstable")]
pub use self::errors::*;

<|endoftext|>


<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.

/*!
# Simple usage

## Creating the server

The easiest way to create a server is to call `Server::http()`.

The `http()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```no_run
let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

## Receiving requests

Calling `server.recv()` will block until the next request is available.
This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```no_run
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();

loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // do something with the request
    // ...
}
```

In a real-case scenario, you will probably want to spawn multiple worker tasks and call
`server.recv()` on all of them. Like this:

```no_run
# use std::sync::Arc;
# use std::thread;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
let server = Arc::new(server);
let mut guards = Vec::with_capacity(4);

for _ in (0 .. 4) {
    let server = server.clone();

    let guard = thread::spawn(move || {
        loop {
            let rq = server.recv().unwrap();

            // ...
        }
    });

    guards.push(guard);
}
```

If you don't want to block, you can call `server.try_recv()` instead.

## Handling requests

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.method()` and `request.url()` which return
the requested method (`GET`, `POST`, etc.) and url.

To handle a request, you need to create a `Response` object. See the docs of this object for
more infos. Here is an example of creating a `Response` from a file:

```no_run
# use std::fs::File;
# use std::path::Path;
let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
```

All that remains to do is call `request.respond()`:

```no_run
# use std::fs::File;
# use std::path::Path;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
# let request = server.recv().unwrap();
# let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
let _ = request.respond(response);
```
*/
#![crate_name = "tiny_http"]
#![crate_type = "lib"]
#![forbid(unsafe_code)]

#[macro_use]
extern crate log;

extern crate ascii;
extern crate chunked_transfer;
extern crate encoding;
extern crate url;
extern crate chrono;

#[cfg(feature = "ssl")]
extern crate openssl;

use std::error::Error;
use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::thread;
use std::net;
use std::net::{ToSocketAddrs, TcpStream, Shutdown};
use std::time::Duration;
use std::sync::atomic::Ordering::Relaxed;

use client::ClientConnection;
use util::MessagesQueue;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::Request;
pub use response::{ResponseBox, Response};

mod client;
mod common;
mod request;
mod response;

#[allow(dead_code)]     // TODO: remove when everything is implemented
mod util;

/// The main class of this library.
///
/// Destroying this object will immediatly close the listening socket annd the reading
///  part of all the client's connections. Requests that have already been returned by
///  the `recv()` function will not close and the responses will be transferred to the client.
pub struct Server {
    // should be false as long as the server exists
    // when set to true, all the subtasks will close within a few hundreds ms
    close: Arc<AtomicBool>,

    // queue for messages received by child threads
    messages: Arc<MessagesQueue<Message>>,

    // result of TcpListener::local_addr()
    listening_addr: net::SocketAddr,
}

enum Message {
    Error(IoError),
    NewRequest(Request),
}

impl From<IoError> for Message {
    fn from(e: IoError) -> Message {
        Message::Error(e)
    }
}

impl From<Request> for Message {
    fn from(rq: Request) -> Message {
        Message::NewRequest(rq)
    }
}

// this trait is to make sure that Server implements Share and Send
#[doc(hidden)]
trait MustBeShareDummy : Sync + Send {}
#[doc(hidden)]
impl MustBeShareDummy for Server {}

pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Represents the parameters required to create a server.
#[derive(Debug, Clone)]
pub struct ServerConfig<A> where A: ToSocketAddrs {
    /// The addresses to listen to.
    pub addr: A,

    /// If `Some`, then the server will use SSL to encode the communications.
    pub ssl: Option<SslConfig>,
}

/// Configuration of the server for SSL.
#[derive(Debug, Clone)]
pub struct SslConfig {
    /// Contains the public certificate to send to clients.
    pub certificate: Vec<u8>,
    /// Contains the ultra-secret private key used to decode communications.
    pub private_key: Vec<u8>,
}

impl Server {
    /// Shortcut for a simple server on a specific address.
    #[inline]
    pub fn http<A>(addr: A) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: None,
        })
    }

    /// Shortcut for an HTTPS server on a specific address.
    #[cfg(feature = "ssl")]
    #[inline]
    pub fn https<A>(addr: A, config: SslConfig)
                    -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: Some(config),
        })
    }

    /// Builds a new server that listens on the specified address.
    pub fn new<A>(config: ServerConfig<A>) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        // building the "close" variable
        let close_trigger = Arc::new(AtomicBool::new(false));

        // building the TcpListener
        let (server, local_addr) = {
            let listener = try!(net::TcpListener::bind(config.addr));
            let local_addr = try!(listener.local_addr());
            debug!("Server listening on {}", local_addr);
            (listener, local_addr)
        };

        // building the SSL capabilities
        #[cfg(feature = "ssl")]
        type SslContext = openssl::ssl::SslContext;
        #[cfg(not(feature = "ssl"))]
        type SslContext = ();
        let ssl: Option<SslContext> = match config.ssl {
            #[cfg(feature = "ssl")]
            Some(mut config) => {
                use std::io::Cursor;
                use openssl::ssl;
                use openssl::x509::X509;
                use openssl::crypto::pkey::PKey;
                use openssl::ssl::SSL_VERIFY_NONE;

                let mut ctxt = try!(SslContext::new(ssl::SslMethod::Sslv23));
                try!(ctxt.set_cipher_list("DEFAULT"));
                let certificate = try!(X509::from_pem(&mut Cursor::new(&config.certificate[..])));
                try!(ctxt.set_certificate(&certificate));
                let private_key = try!(PKey::private_key_from_pem(&mut Cursor::new(&config.private_key[..])));
                try!(ctxt.set_private_key(&private_key));
                ctxt.set_verify(SSL_VERIFY_NONE, None);
                try!(ctxt.check_private_key());

                // let's wipe the certificate and private key from memory, because we're
                // better safe than sorry
                for b in &mut config.certificate { *b = 0; }
                for b in &mut config.private_key { *b = 0; }

                Some(ctxt)
            },
            #[cfg(not(feature = "ssl"))]
            Some(_) => return Err("Building a server with SSL requires enabling the `ssl` feature \
                                   in tiny-http".to_owned().into()),
            None => None,
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are pushed in the messages queue
        let messages = MessagesQueue::with_capacity(8);

        let inside_close_trigger = close_trigger.clone();
        let inside_messages = messages.clone();
        thread::spawn(move || {
            // a tasks pool is used to dispatch the connections into threads
            let tasks_pool = util::TaskPool::new();

            debug!("Running accept thread");
            while !inside_close_trigger.load(Relaxed) {
                let new_client = match server.accept() {
                    Ok((sock, _)) => {
                        use util::RefinedTcpStream;
                        let (read_closable, write_closable) = match ssl {
                            None => {
                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(feature = "ssl")]
                            Some(ref ssl) => {
                                // trying to apply SSL over the connection
                                // if an error occurs, we just close the socket and resume listening
                                let sock = match openssl::ssl::SslStream::accept(ssl, sock) {
                                    Ok(s) => s,
                                    Err(_) => continue
                                };

                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(not(feature = "ssl"))]
                            Some(_) => unreachable!(),
                        };

                        Ok(ClientConnection::new(write_closable, read_closable))
                    },
                    Err(e) => Err(e),
                };

                match new_client {
                    Ok(client) => {
                        let messages = inside_messages.clone();
                        let mut client = Some(client);
                        tasks_pool.spawn(Box::new(move || {
                            if let Some(client) = client.take() {
                                for rq in client {
                                    messages.push(rq.into());
                                }
                            }
                        }));
                    },

                    Err(e) => {
                        error!("Error accepting new client: {}", e);
                        inside_messages.push(e.into());
                        break;
                    }
                }
            }
            debug!("Terminating accept thread");
        });

        // result
        Ok(Server {
            messages: messages,
            close: close_trigger,
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[inline]
    pub fn incoming_requests(&self) -> IncomingRequests {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[inline]
    pub fn server_addr(&self) -> net::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    pub fn num_connections(&self) -> usize {
        unimplemented!()
        //self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    pub fn recv(&self) -> IoResult<Request> {
        match self.messages.pop() {
            Message::Error(err) => return Err(err),
            Message::NewRequest(rq) => return Ok(rq),
        }
    }

    /// Same as `recv()` but doesn't block longer than timeout
    pub fn recv_timeout(&self, timeout: Duration) -> IoResult<Option<Request>> {
        match self.messages.pop_timeout(timeout) {
            Some(Message::Error(err)) => return Err(err),
            Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
            None => return Ok(None)
        }
    }

    /// Same as `recv()` but doesn't block.
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        match self.messages.try_pop() {
            Some(Message::Error(err)) => return Err(err),
            Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
            None => return Ok(None)
        }
    }
}

impl<'a> Iterator for IncomingRequests<'a> {
    type Item = Request;
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.close.store(true, Relaxed);
        // Connect briefly to ourselves to unblock the accept thread
        let maybe_stream = TcpStream::connect(self.listening_addr);
        if let Ok(stream) = maybe_stream {
            let _ = stream.shutdown(Shutdown::Both);
        }
    }
}
<commit_msg>Make ReadWrite trait public<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.

/*!
# Simple usage

## Creating the server

The easiest way to create a server is to call `Server::http()`.

The `http()` function returns an `IoResult<Server>` which will return an error
in the case where the server creation fails (for example if the listening port is already
occupied).

```no_run
let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
```

A newly-created `Server` will immediatly start listening for incoming connections and HTTP
requests.

## Receiving requests

Calling `server.recv()` will block until the next request is available.
This function returns an `IoResult<Request>`, so you need to handle the possible errors.

```no_run
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();

loop {
    // blocks until the next request is received
    let request = match server.recv() {
        Ok(rq) => rq,
        Err(e) => { println!("error: {}", e); break }
    };

    // do something with the request
    // ...
}
```

In a real-case scenario, you will probably want to spawn multiple worker tasks and call
`server.recv()` on all of them. Like this:

```no_run
# use std::sync::Arc;
# use std::thread;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
let server = Arc::new(server);
let mut guards = Vec::with_capacity(4);

for _ in (0 .. 4) {
    let server = server.clone();

    let guard = thread::spawn(move || {
        loop {
            let rq = server.recv().unwrap();

            // ...
        }
    });

    guards.push(guard);
}
```

If you don't want to block, you can call `server.try_recv()` instead.

## Handling requests

The `Request` object returned by `server.recv()` contains informations about the client's request.
The most useful methods are probably `request.method()` and `request.url()` which return
the requested method (`GET`, `POST`, etc.) and url.

To handle a request, you need to create a `Response` object. See the docs of this object for
more infos. Here is an example of creating a `Response` from a file:

```no_run
# use std::fs::File;
# use std::path::Path;
let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
```

All that remains to do is call `request.respond()`:

```no_run
# use std::fs::File;
# use std::path::Path;
# let server = tiny_http::Server::http("0.0.0.0:0").unwrap();
# let request = server.recv().unwrap();
# let response = tiny_http::Response::from_file(File::open(&Path::new("image.png")).unwrap());
let _ = request.respond(response);
```
*/
#![crate_name = "tiny_http"]
#![crate_type = "lib"]
#![forbid(unsafe_code)]

#[macro_use]
extern crate log;

extern crate ascii;
extern crate chunked_transfer;
extern crate encoding;
extern crate url;
extern crate chrono;

#[cfg(feature = "ssl")]
extern crate openssl;

use std::error::Error;
use std::io::Error as IoError;
use std::io::Result as IoResult;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::thread;
use std::net;
use std::net::{ToSocketAddrs, TcpStream, Shutdown};
use std::time::Duration;
use std::sync::atomic::Ordering::Relaxed;

use client::ClientConnection;
use util::MessagesQueue;

pub use common::{Header, HeaderField, HTTPVersion, Method, StatusCode};
pub use request::{Request, ReadWrite};
pub use response::{ResponseBox, Response};

mod client;
mod common;
mod request;
mod response;

#[allow(dead_code)]     // TODO: remove when everything is implemented
mod util;

/// The main class of this library.
///
/// Destroying this object will immediatly close the listening socket annd the reading
///  part of all the client's connections. Requests that have already been returned by
///  the `recv()` function will not close and the responses will be transferred to the client.
pub struct Server {
    // should be false as long as the server exists
    // when set to true, all the subtasks will close within a few hundreds ms
    close: Arc<AtomicBool>,

    // queue for messages received by child threads
    messages: Arc<MessagesQueue<Message>>,

    // result of TcpListener::local_addr()
    listening_addr: net::SocketAddr,
}

enum Message {
    Error(IoError),
    NewRequest(Request),
}

impl From<IoError> for Message {
    fn from(e: IoError) -> Message {
        Message::Error(e)
    }
}

impl From<Request> for Message {
    fn from(rq: Request) -> Message {
        Message::NewRequest(rq)
    }
}

// this trait is to make sure that Server implements Share and Send
#[doc(hidden)]
trait MustBeShareDummy : Sync + Send {}
#[doc(hidden)]
impl MustBeShareDummy for Server {}

pub struct IncomingRequests<'a> {
    server: &'a Server
}

/// Represents the parameters required to create a server.
#[derive(Debug, Clone)]
pub struct ServerConfig<A> where A: ToSocketAddrs {
    /// The addresses to listen to.
    pub addr: A,

    /// If `Some`, then the server will use SSL to encode the communications.
    pub ssl: Option<SslConfig>,
}

/// Configuration of the server for SSL.
#[derive(Debug, Clone)]
pub struct SslConfig {
    /// Contains the public certificate to send to clients.
    pub certificate: Vec<u8>,
    /// Contains the ultra-secret private key used to decode communications.
    pub private_key: Vec<u8>,
}

impl Server {
    /// Shortcut for a simple server on a specific address.
    #[inline]
    pub fn http<A>(addr: A) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: None,
        })
    }

    /// Shortcut for an HTTPS server on a specific address.
    #[cfg(feature = "ssl")]
    #[inline]
    pub fn https<A>(addr: A, config: SslConfig)
                    -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        Server::new(ServerConfig {
            addr: addr,
            ssl: Some(config),
        })
    }

    /// Builds a new server that listens on the specified address.
    pub fn new<A>(config: ServerConfig<A>) -> Result<Server, Box<Error + Send + Sync + 'static>>
        where A: ToSocketAddrs
    {
        // building the "close" variable
        let close_trigger = Arc::new(AtomicBool::new(false));

        // building the TcpListener
        let (server, local_addr) = {
            let listener = try!(net::TcpListener::bind(config.addr));
            let local_addr = try!(listener.local_addr());
            debug!("Server listening on {}", local_addr);
            (listener, local_addr)
        };

        // building the SSL capabilities
        #[cfg(feature = "ssl")]
        type SslContext = openssl::ssl::SslContext;
        #[cfg(not(feature = "ssl"))]
        type SslContext = ();
        let ssl: Option<SslContext> = match config.ssl {
            #[cfg(feature = "ssl")]
            Some(mut config) => {
                use std::io::Cursor;
                use openssl::ssl;
                use openssl::x509::X509;
                use openssl::crypto::pkey::PKey;
                use openssl::ssl::SSL_VERIFY_NONE;

                let mut ctxt = try!(SslContext::new(ssl::SslMethod::Sslv23));
                try!(ctxt.set_cipher_list("DEFAULT"));
                let certificate = try!(X509::from_pem(&mut Cursor::new(&config.certificate[..])));
                try!(ctxt.set_certificate(&certificate));
                let private_key = try!(PKey::private_key_from_pem(&mut Cursor::new(&config.private_key[..])));
                try!(ctxt.set_private_key(&private_key));
                ctxt.set_verify(SSL_VERIFY_NONE, None);
                try!(ctxt.check_private_key());

                // let's wipe the certificate and private key from memory, because we're
                // better safe than sorry
                for b in &mut config.certificate { *b = 0; }
                for b in &mut config.private_key { *b = 0; }

                Some(ctxt)
            },
            #[cfg(not(feature = "ssl"))]
            Some(_) => return Err("Building a server with SSL requires enabling the `ssl` feature \
                                   in tiny-http".to_owned().into()),
            None => None,
        };

        // creating a task where server.accept() is continuously called
        // and ClientConnection objects are pushed in the messages queue
        let messages = MessagesQueue::with_capacity(8);

        let inside_close_trigger = close_trigger.clone();
        let inside_messages = messages.clone();
        thread::spawn(move || {
            // a tasks pool is used to dispatch the connections into threads
            let tasks_pool = util::TaskPool::new();

            debug!("Running accept thread");
            while !inside_close_trigger.load(Relaxed) {
                let new_client = match server.accept() {
                    Ok((sock, _)) => {
                        use util::RefinedTcpStream;
                        let (read_closable, write_closable) = match ssl {
                            None => {
                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(feature = "ssl")]
                            Some(ref ssl) => {
                                // trying to apply SSL over the connection
                                // if an error occurs, we just close the socket and resume listening
                                let sock = match openssl::ssl::SslStream::accept(ssl, sock) {
                                    Ok(s) => s,
                                    Err(_) => continue
                                };

                                RefinedTcpStream::new(sock)
                            },
                            #[cfg(not(feature = "ssl"))]
                            Some(_) => unreachable!(),
                        };

                        Ok(ClientConnection::new(write_closable, read_closable))
                    },
                    Err(e) => Err(e),
                };

                match new_client {
                    Ok(client) => {
                        let messages = inside_messages.clone();
                        let mut client = Some(client);
                        tasks_pool.spawn(Box::new(move || {
                            if let Some(client) = client.take() {
                                for rq in client {
                                    messages.push(rq.into());
                                }
                            }
                        }));
                    },

                    Err(e) => {
                        error!("Error accepting new client: {}", e);
                        inside_messages.push(e.into());
                        break;
                    }
                }
            }
            debug!("Terminating accept thread");
        });

        // result
        Ok(Server {
            messages: messages,
            close: close_trigger,
            listening_addr: local_addr,
        })
    }

    /// Returns an iterator for all the incoming requests.
    ///
    /// The iterator will return `None` if the server socket is shutdown.
    #[inline]
    pub fn incoming_requests(&self) -> IncomingRequests {
        IncomingRequests { server: self }
    }

    /// Returns the address the server is listening to.
    #[inline]
    pub fn server_addr(&self) -> net::SocketAddr {
        self.listening_addr.clone()
    }

    /// Returns the number of clients currently connected to the server.
    pub fn num_connections(&self) -> usize {
        unimplemented!()
        //self.requests_receiver.lock().len()
    }

    /// Blocks until an HTTP request has been submitted and returns it.
    pub fn recv(&self) -> IoResult<Request> {
        match self.messages.pop() {
            Message::Error(err) => return Err(err),
            Message::NewRequest(rq) => return Ok(rq),
        }
    }

    /// Same as `recv()` but doesn't block longer than timeout
    pub fn recv_timeout(&self, timeout: Duration) -> IoResult<Option<Request>> {
        match self.messages.pop_timeout(timeout) {
            Some(Message::Error(err)) => return Err(err),
            Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
            None => return Ok(None)
        }
    }

    /// Same as `recv()` but doesn't block.
    pub fn try_recv(&self) -> IoResult<Option<Request>> {
        match self.messages.try_pop() {
            Some(Message::Error(err)) => return Err(err),
            Some(Message::NewRequest(rq)) => return Ok(Some(rq)),
            None => return Ok(None)
        }
    }
}

impl<'a> Iterator for IncomingRequests<'a> {
    type Item = Request;
    fn next(&mut self) -> Option<Request> {
        self.server.recv().ok()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.close.store(true, Relaxed);
        // Connect briefly to ourselves to unblock the accept thread
        let maybe_stream = TcpStream::connect(self.listening_addr);
        if let Ok(stream) = maybe_stream {
            let _ = stream.shutdown(Shutdown::Both);
        }
    }
}
<|endoftext|>


<commit_before>extern crate mio;
extern crate regex;

#[cfg(test)]
mod tests;

pub mod route;
pub mod request;
pub mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::collections::HashSet;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

pub use route::*;
pub use request::*;
pub use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::new(),
            o_buf:  Vec::new(),
        }
    }

    fn readable(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(_) => {
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None    => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    /* write the client's output buffer to the socket.
     *
     * the following return values mean:
     *  - Ok(true):  we can close the connection
     *  - Ok(false): keep listening for writeable event and continue next time
     *  - Err(e):    something dun fucked up
     */
    fn writable(&mut self) -> Result<bool> {
        let out = self.o_buf.clone();

        match self.sock.write(&out.as_slice()) {
            Ok(sz)  => {
                if sz == self.o_buf.len() {
                    /* we did it! */
                    self.events.remove(EventSet::writable());
                    return Ok(true);
                } else {
                    self.o_buf = self.o_buf.split_off(sz);

                    return Ok(false);
                }
            },
            Err(e)  => {
                panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
            }
        }

        Ok(false)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/* our primary object. similar interface to Flask, the
 * Python microframework. much faster, however! :)
 */
pub struct Canteen {
    routes:  HashMap<RouteDef, Route>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = u32;

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).writable() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }
}

impl Canteen {
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            server:  TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:   Token(1),
            conns:   Slab::new_starting_at(Token(2), 2048),
            default: Route::err_404,
        }
    }

    pub fn add_route(&mut self, path: &str, mlist: Vec<Method>, handler: fn(&Request) -> Response) {
        let mut methods: HashSet<Method> = HashSet::new();

        for m in mlist {
            methods.insert(m);
        }

        for m in methods {
            let rd = RouteDef {
                pathdef:    String::from(path),
                method:     m,
            };

            if self.routes.contains_key(&rd) {
                panic!("a route handler for {} has already been defined!", path);
            }

            self.routes.insert(rd, Route::new(&path, m, handler));
        }
    }

    pub fn set_default(&mut self, handler: fn(&Request) -> Response) {
        self.default = handler;
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        &mut self.conns[token]
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn handle_request(&self, req: &mut Request) -> Vec<u8> {
        let mut handler: fn(&Request) -> Response = self.default;

        for (_, route) in &self.routes {
            match (route).is_match(req) {
                true  => {
                    handler = route.handler;
                    req.params = route.parse(&req.path);
                    break;
                },
                false => continue,
            }
        }

        handler(req).gen_output()
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).readable() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                let mut req = Request::from_str(&rqstr);
                let output = self.handle_request(&mut req);

                self.get_client(token).o_buf.extend(output);
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        let _ = self.get_client(token).reregister(evl);

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        /* kill the connection */
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<commit_msg>allow for method chaining when adding routes<commit_after>extern crate mio;
extern crate regex;

#[cfg(test)]
mod tests;

pub mod route;
pub mod request;
pub mod response;

use std::io::Result;
use std::io::prelude::*;
use std::net::ToSocketAddrs;
use std::collections::HashMap;
use std::collections::HashSet;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

pub use route::*;
pub use request::*;
pub use response::*;

struct Client {
    sock:   TcpStream,
    token:  Token,
    events: EventSet,
    i_buf:  Vec<u8>,
    o_buf:  Vec<u8>,
}

impl Client {
    fn new(sock: TcpStream, token: Token) -> Client {
        Client {
            sock:   sock,
            token:  token,
            events: EventSet::hup(),
            i_buf:  Vec::new(),
            o_buf:  Vec::new(),
        }
    }

    fn readable(&mut self) -> Result<bool> {
        let mut buf: Vec<u8> = Vec::with_capacity(2048);

        match self.sock.try_read_buf(&mut buf) {
            Ok(size)  => {
                match size {
                    Some(_) => {
                        self.events.remove(EventSet::readable());
                        self.events.insert(EventSet::writable());
                        self.i_buf.extend(buf);
                        return Ok(true);
                    },
                    None    => {
                        return Ok(false);
                    },
                }
            },
            Err(e)  => {
                panic!("failed to read from socket! <token: {:?}> <error: {:?}>", self.token, e);
            },
        }

        Ok(false)
    }

    /* write the client's output buffer to the socket.
     *
     * the following return values mean:
     *  - Ok(true):  we can close the connection
     *  - Ok(false): keep listening for writeable event and continue next time
     *  - Err(e):    something dun fucked up
     */
    fn writable(&mut self) -> Result<bool> {
        let out = self.o_buf.clone();

        match self.sock.write(&out.as_slice()) {
            Ok(sz)  => {
                if sz == self.o_buf.len() {
                    /* we did it! */
                    self.events.remove(EventSet::writable());
                    return Ok(true);
                } else {
                    self.o_buf = self.o_buf.split_off(sz);

                    return Ok(false);
                }
            },
            Err(e)  => {
                panic!("failed to write to socket! <token: {:?}> <error: {:?}>", self.token, e);
            }
        }

        Ok(false)
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        self.events.insert(EventSet::readable());

        evl.register(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to re-register client! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }
}

/* our primary object. similar interface to Flask, the
 * Python microframework. much faster, however! :)
 */
pub struct Canteen {
    routes:  HashMap<RouteDef, Route>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = u32;

    fn ready(&mut self, evl: &mut EventLoop<Canteen>, token: Token, events: EventSet) {
        if events.is_error() || events.is_hup() {
            self.reset_connection(token);
            return;
        }

        if events.is_readable() {
            if self.token == token {
                self.accept(evl);
            } else {
                self.readable(evl, token)
                    .and_then(|_| self.get_client(token)
                                      .reregister(evl))
                    .unwrap_or_else(|e| {
                        panic!("read event failed! <token: {:?}> <error: {:?}>", token, e);
                    });
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).writable() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => { panic!("something really bad happened!"); },
            }
        }
    }
}

impl Canteen {
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            server:  TcpListener::bind(&addr.to_socket_addrs().unwrap().next().unwrap()).unwrap(),
            token:   Token(1),
            conns:   Slab::new_starting_at(Token(2), 2048),
            default: Route::err_404,
        }
    }

    pub fn add_route(&mut self, path: &str, mlist: Vec<Method>, handler: fn(&Request) -> Response) -> &mut Canteen {
        let mut methods: HashSet<Method> = HashSet::new();

        for m in mlist {
            methods.insert(m);
        }

        for m in methods {
            let rd = RouteDef {
                pathdef:    String::from(path),
                method:     m,
            };

            if self.routes.contains_key(&rd) {
                panic!("a route handler for {} has already been defined!", path);
            }

            self.routes.insert(rd, Route::new(&path, m, handler));
        }

        self
    }

    pub fn set_default(&mut self, handler: fn(&Request) -> Response) {
        self.default = handler;
    }

    fn get_client<'a>(&'a mut self, token: Token) -> &'a mut Client {
        &mut self.conns[token]
    }

    fn accept(&mut self, evl: &mut EventLoop<Canteen>) {
        let (sock, _) = match self.server.accept() {
            Ok(s)   => {
                match s {
                    Some(sock)  => sock,
                    None        => {
                        panic!("failed to accept new connection!");
                    }
                }
            },
            Err(e)  => {
                panic!("failed to accept new connection! <error: {:?}>", e);
            },
        };

        match self.conns.insert_with(|token| Client::new(sock, token)) {
            Some(token) => {
                match self.get_client(token).register(evl) {
                    Ok(_)   => {},
                    Err(e)  => {
                        panic!("failed to register client! <token: {:?}> <error: {:?}>", token, e);
                    },
                }
            },
            None        => {
                panic!("failed to add client connection!");
            },
        }

        self.reregister(evl);
    }

    fn handle_request(&self, req: &mut Request) -> Vec<u8> {
        let mut handler: fn(&Request) -> Response = self.default;

        for (_, route) in &self.routes {
            match (route).is_match(req) {
                true  => {
                    handler = route.handler;
                    req.params = route.parse(&req.path);
                    break;
                },
                false => continue,
            }
        }

        handler(req).gen_output()
    }

    fn readable(&mut self, evl: &mut EventLoop<Canteen>, token: Token) -> Result<bool> {
        match self.get_client(token).readable() {
            Ok(true)    => {
                let buf = self.get_client(token).i_buf.clone();
                let rqstr = String::from_utf8(buf).unwrap();
                let mut req = Request::from_str(&rqstr);
                let output = self.handle_request(&mut req);

                self.get_client(token).o_buf.extend(output);
            },
            Ok(false)   => {},
            Err(e)      => {
                panic!("message wasn't actually readable! <error: {:?}>", e);
            },
        };

        let _ = self.get_client(token).reregister(evl);

        Ok(true)
    }

    fn reset_connection(&mut self, token: Token) {
        /* kill the connection */
        self.conns.remove(token);
    }

    fn register(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.register(&self.server, self.token, EventSet::readable(), PollOpt::edge() | PollOpt::oneshot())
           .or_else(|e| {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           })
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        match evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()) {
            Ok(_)   => {},
            Err(e)  => {
               panic!("failed to register server! <token: {:?}> <error: {:?}>", self.token, e);
           }
        };
    }

    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<|endoftext|>


<commit_before>#![feature(libc)]
#![feature(plugin)]
#![feature(alloc)]

#![allow(dead_code)]
#![allow(unused_imports)]

extern crate libc;
#[macro_use] extern crate bitflags;

mod nginx;

use std::ffi::CString;
use std::ptr;
use std::mem;
use std::boxed;

use nginx::ffi::{
   ngx_str_t, ngx_http_request_t, ngx_pcalloc, ngx_palloc, ngx_conf_t, ngx_command_t, ngx_http_core_module,
   ngx_http_conf_ctx_t, ngx_int_t, ngx_http_output_filter, ngx_chain_t, ngx_http_send_header, ngx_buf_t,
   ngx_uint_t, ngx_http_core_loc_conf_t, ngx_log_error_core,
};

use libc::{size_t, c_void, c_uchar, c_char};

const NGX_CONF_OK: *const c_char = 0 as *const c_char;
const NGX_CONF_ERROR: *const c_char = -1 as *const c_char;

const NGX_OK:        ngx_int_t =  0;
const NGX_ERROR:     ngx_int_t = -1;
const NGX_AGAIN:     ngx_int_t = -2;
const NGX_BUSY:      ngx_int_t = -3;
const NGX_DONE:      ngx_int_t = -4;
const NGX_DECLINED:  ngx_int_t = -5;
const NGX_ABORT:     ngx_int_t = -6;

const NGX_HTTP_OK:                      ngx_uint_t = 200;
const NGX_HTTP_INTERNAL_SERVER_ERROR:   ngx_uint_t = 500;

macro_rules! ngx_http_conf_get_module_loc_conf {
   ($cf:expr, $module:expr) => ({
      (*
         (
            (*
               (
                  (*$cf).ctx as *mut ngx_http_conf_ctx_t
               )
            ).loc_conf
         ).offset($module.ctx_index as isize)
      ) as *mut ngx_http_core_loc_conf_t
   })
}

macro_rules! ngx_alloc_buf {
   ($pool:expr) => (
      ngx_palloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! ngx_calloc_buf {
   ($pool:expr) => (
      ngx_pcalloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! log_error_core {
   ($level:expr, $log:expr, $err:expr, $fmt:expr, $( $arg:expr ),*) => (
      ngx_log_error_core($level, $log.raw, $err, $fmt, $( $arg ),*)
   )
}

bitflags! {
    flags BufFlags: u32 {
        const FLAG_TEMPORARY        = 0b0000000000000001,
        const FLAG_MEMORY           = 0b0000000000000010,
        const FLAG_MMAP             = 0b0000000000000100,
        const FLAG_RECYCLED         = 0b0000000000001000,
        const FLAG_IN_FILE          = 0b0000000000010000,
        const FLAG_FLUSH            = 0b0000000000100000,
        const FLAG_SYNC             = 0b0000000001000000,
        const FLAG_LAST_BUF         = 0b0000000010000000,
        const FLAG_LAST_IN_CHAIN    = 0b0000000100000000,
        const FLAG_LAST_SHADOW      = 0b0000001000000000,
        const FLAG_TEMP_FILE        = 0b0000010000000000,
    }
}

macro_rules! simple_http_module_command {
   ($command:ident, $handler:ident) => (
      #[no_mangle]
      pub extern fn $command(
         cf: *mut ngx_conf_t,
         _: *mut ngx_command_t,
         _: *mut c_void
      ) -> *const c_char {
         unsafe {
            let clcf = ngx_http_conf_get_module_loc_conf!(cf, ngx_http_core_module);
            (*clcf).handler = Some($handler);
         }

         NGX_CONF_OK
      }
   )
}

simple_http_module_command!(ngx_http_sample_module_command, ngx_http_sample_handler);

#[no_mangle]
pub extern fn ngx_http_sample_handler(r: *mut ngx_http_request_t) -> ngx_int_t
{
   let request = nginx::HttpRequest::new(r);

   unsafe {
      let log = request.connection().unwrap().log().unwrap();

      let ngx_http_sample_text: ngx_str_t = sample_text_from_rust(r);

      (*r).headers_out.status = NGX_HTTP_OK;
      (*r).headers_out.content_length_n = ngx_http_sample_text.len as i64;

      let rc: ngx_int_t = ngx_http_send_header(r);
      if rc == NGX_ERROR || rc > NGX_OK { //|| (*r).header_only) {
         return rc;
      }

      let b: *mut ngx_buf_t = ngx_calloc_buf!((*r).pool) as *mut ngx_buf_t;

      if b.is_null() {
         return NGX_HTTP_INTERNAL_SERVER_ERROR as i64;
      };

      let out: Box<ngx_chain_t> = Box::new(
         ngx_chain_t {
            buf: b,
            next: ptr::null_mut()
         }
      );

      let headers_in = (*r).headers_in;

      let cstr_template = CString::new("BITS: \"%s\"").unwrap();
      let b1 = CString::new(format!("{:032b}", headers_in._bindgen_bitfield_1_)).unwrap();

      log_error_core!(
         2, log, 0,
         cstr_template.as_ptr(),
         b1.as_ptr()
      );

      let out: *mut ngx_chain_t = boxed::into_raw(out);

      (*b).start = ngx_http_sample_text.data;
      (*b).pos = (*b).start;

      (*b).end = ngx_http_sample_text.data.offset(ngx_http_sample_text.len as isize);
      (*b).last = (*b).end;

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      (*b)._bindgen_bitfield_1_ = buf_flags.bits();

      ngx_http_output_filter(r, out)
   }
}

fn sample_text_from_rust(r: *mut ngx_http_request_t) -> ngx_str_t
{
   let s = CString::new("<meta charset=\"utf-8\">Здравейте!".to_string()).unwrap();
   let len = s.to_bytes().len() as size_t;

   let result = ngx_str_t {
      len: len,
      data: unsafe {
         ngx_pcalloc((*r).pool, len) as *mut u8
      },
   };

   unsafe {
      ptr::copy_nonoverlapping(result.data, s.as_ptr() as *const u8, len as usize);
   }

   result
}

#[no_mangle]
pub extern fn dump_request(r: *mut ngx_http_request_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "REQ: \
         method=\"%ud\" \
         http_version=\"%ud\" \
         request_line=\"%V\" \
         uri=\"%V\" \
         args=\"%V\" \
         exten=\"%V\" \
         unparsed_uri=\"%V\" \
         method_name=\"%V\" \
         http_protocol=\"%V\" \
         bit1=\"%s\" \
         bit2=\"%s\" \
         bit3=\"%s\" \
         bit4=\"%s\" \
         bits=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_1_)).unwrap();
      let b2 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_2_)).unwrap();
      let b3 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_3_)).unwrap();
      let b4 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_4_)).unwrap();

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      let bits = CString::new(format!("{:032b}", buf_flags.bits())).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*r).method,
         (*r).http_version,
         &((*r).request_line),
         &((*r).uri),
         &((*r).args),
         &((*r).exten),
         &((*r).unparsed_uri),
         &((*r).method_name),
         &((*r).http_protocol),
         b1.as_ptr(),
         b2.as_ptr(),
         b3.as_ptr(),
         b4.as_ptr(),
         bits.as_ptr(),
      );
   }
}

#[no_mangle]
pub extern fn dump_buffer(r: *mut ngx_http_request_t, b: *mut ngx_buf_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "BUF: \
         pos=\"%p\" \
         last=\"%p\" \
         start=\"%p\" \
         end=\"%p\" \
         num=\"%d\" \
         bit1=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:064b}", (*b)._bindgen_bitfield_1_)).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*b).pos,
         (*b).last,
         (*b).start,
         (*b).end,
         (*b).num,
         b1.as_ptr(),
      );
   }
}
<commit_msg>Bitflags identation fix.<commit_after>#![feature(libc)]
#![feature(plugin)]
#![feature(alloc)]

#![allow(dead_code)]
#![allow(unused_imports)]

extern crate libc;
#[macro_use] extern crate bitflags;

mod nginx;

use std::ffi::CString;
use std::ptr;
use std::mem;
use std::boxed;

use nginx::ffi::{
   ngx_str_t, ngx_http_request_t, ngx_pcalloc, ngx_palloc, ngx_conf_t, ngx_command_t, ngx_http_core_module,
   ngx_http_conf_ctx_t, ngx_int_t, ngx_http_output_filter, ngx_chain_t, ngx_http_send_header, ngx_buf_t,
   ngx_uint_t, ngx_http_core_loc_conf_t, ngx_log_error_core,
};

use libc::{size_t, c_void, c_uchar, c_char};

const NGX_CONF_OK: *const c_char = 0 as *const c_char;
const NGX_CONF_ERROR: *const c_char = -1 as *const c_char;

const NGX_OK:        ngx_int_t =  0;
const NGX_ERROR:     ngx_int_t = -1;
const NGX_AGAIN:     ngx_int_t = -2;
const NGX_BUSY:      ngx_int_t = -3;
const NGX_DONE:      ngx_int_t = -4;
const NGX_DECLINED:  ngx_int_t = -5;
const NGX_ABORT:     ngx_int_t = -6;

const NGX_HTTP_OK:                      ngx_uint_t = 200;
const NGX_HTTP_INTERNAL_SERVER_ERROR:   ngx_uint_t = 500;

macro_rules! ngx_http_conf_get_module_loc_conf {
   ($cf:expr, $module:expr) => ({
      (*
         (
            (*
               (
                  (*$cf).ctx as *mut ngx_http_conf_ctx_t
               )
            ).loc_conf
         ).offset($module.ctx_index as isize)
      ) as *mut ngx_http_core_loc_conf_t
   })
}

macro_rules! ngx_alloc_buf {
   ($pool:expr) => (
      ngx_palloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! ngx_calloc_buf {
   ($pool:expr) => (
      ngx_pcalloc($pool, mem::size_of::<ngx_buf_t>() as u64)
   )
}

macro_rules! log_error_core {
   ($level:expr, $log:expr, $err:expr, $fmt:expr, $( $arg:expr ),*) => (
      ngx_log_error_core($level, $log.raw, $err, $fmt, $( $arg ),*)
   )
}

bitflags! {
   flags BufFlags: u32 {
      const FLAG_TEMPORARY        = 0b0000000000000001,
      const FLAG_MEMORY           = 0b0000000000000010,
      const FLAG_MMAP             = 0b0000000000000100,
      const FLAG_RECYCLED         = 0b0000000000001000,
      const FLAG_IN_FILE          = 0b0000000000010000,
      const FLAG_FLUSH            = 0b0000000000100000,
      const FLAG_SYNC             = 0b0000000001000000,
      const FLAG_LAST_BUF         = 0b0000000010000000,
      const FLAG_LAST_IN_CHAIN    = 0b0000000100000000,
      const FLAG_LAST_SHADOW      = 0b0000001000000000,
      const FLAG_TEMP_FILE        = 0b0000010000000000,
   }
}

macro_rules! simple_http_module_command {
   ($command:ident, $handler:ident) => (
      #[no_mangle]
      pub extern fn $command(
         cf: *mut ngx_conf_t,
         _: *mut ngx_command_t,
         _: *mut c_void
      ) -> *const c_char {
         unsafe {
            let clcf = ngx_http_conf_get_module_loc_conf!(cf, ngx_http_core_module);
            (*clcf).handler = Some($handler);
         }

         NGX_CONF_OK
      }
   )
}

simple_http_module_command!(ngx_http_sample_module_command, ngx_http_sample_handler);

#[no_mangle]
pub extern fn ngx_http_sample_handler(r: *mut ngx_http_request_t) -> ngx_int_t
{
   let request = nginx::HttpRequest::new(r);

   let log = request.connection().unwrap().log().unwrap();

   let ngx_http_sample_text: ngx_str_t = sample_text_from_rust(r);

   unsafe {

      (*r).headers_out.status = NGX_HTTP_OK;
      (*r).headers_out.content_length_n = ngx_http_sample_text.len as i64;

      let rc: ngx_int_t = ngx_http_send_header(r);
      if rc == NGX_ERROR || rc > NGX_OK { //|| (*r).header_only) {
         return rc;
      }

      let b: *mut ngx_buf_t = ngx_calloc_buf!((*r).pool) as *mut ngx_buf_t;

      if b.is_null() {
         return NGX_HTTP_INTERNAL_SERVER_ERROR as i64;
      };

      let out: Box<ngx_chain_t> = Box::new(
         ngx_chain_t {
            buf: b,
            next: ptr::null_mut()
         }
      );

      let headers_in = (*r).headers_in;

      let cstr_template = CString::new("BITS: \"%s\"").unwrap();
      let b1 = CString::new(format!("{:032b}", headers_in._bindgen_bitfield_1_)).unwrap();

      log_error_core!(
         2, log, 0,
         cstr_template.as_ptr(),
         b1.as_ptr()
      );

      let out: *mut ngx_chain_t = boxed::into_raw(out);

      (*b).start = ngx_http_sample_text.data;
      (*b).pos = (*b).start;

      (*b).end = ngx_http_sample_text.data.offset(ngx_http_sample_text.len as isize);
      (*b).last = (*b).end;

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      (*b)._bindgen_bitfield_1_ = buf_flags.bits();

      ngx_http_output_filter(r, out)
   }
}

fn sample_text_from_rust(r: *mut ngx_http_request_t) -> ngx_str_t
{
   let s = CString::new("<meta charset=\"utf-8\">Здравейте!".to_string()).unwrap();
   let len = s.to_bytes().len() as size_t;

   let result = ngx_str_t {
      len: len,
      data: unsafe {
         ngx_pcalloc((*r).pool, len) as *mut u8
      },
   };

   unsafe {
      ptr::copy_nonoverlapping(result.data, s.as_ptr() as *const u8, len as usize);
   }

   result
}

#[no_mangle]
pub extern fn dump_request(r: *mut ngx_http_request_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "REQ: \
         method=\"%ud\" \
         http_version=\"%ud\" \
         request_line=\"%V\" \
         uri=\"%V\" \
         args=\"%V\" \
         exten=\"%V\" \
         unparsed_uri=\"%V\" \
         method_name=\"%V\" \
         http_protocol=\"%V\" \
         bit1=\"%s\" \
         bit2=\"%s\" \
         bit3=\"%s\" \
         bit4=\"%s\" \
         bits=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_1_)).unwrap();
      let b2 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_2_)).unwrap();
      let b3 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_3_)).unwrap();
      let b4 = CString::new(format!("{:032b}", (*r)._bindgen_bitfield_4_)).unwrap();

      let buf_flags = FLAG_MEMORY | FLAG_LAST_BUF | FLAG_LAST_IN_CHAIN;
      let bits = CString::new(format!("{:032b}", buf_flags.bits())).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*r).method,
         (*r).http_version,
         &((*r).request_line),
         &((*r).uri),
         &((*r).args),
         &((*r).exten),
         &((*r).unparsed_uri),
         &((*r).method_name),
         &((*r).http_protocol),
         b1.as_ptr(),
         b2.as_ptr(),
         b3.as_ptr(),
         b4.as_ptr(),
         bits.as_ptr(),
      );
   }
}

#[no_mangle]
pub extern fn dump_buffer(r: *mut ngx_http_request_t, b: *mut ngx_buf_t) {
   unsafe {
      let log = (*(*r).connection).log;

      let template = "BUF: \
         pos=\"%p\" \
         last=\"%p\" \
         start=\"%p\" \
         end=\"%p\" \
         num=\"%d\" \
         bit1=\"%s\" \
      ";
      let cstr_template = CString::new(template).unwrap();

      let b1 = CString::new(format!("{:064b}", (*b)._bindgen_bitfield_1_)).unwrap();

      ngx_log_error_core(
         2, log, 0,
         cstr_template.as_ptr(),
         (*b).pos,
         (*b).last,
         (*b).start,
         (*b).end,
         (*b).num,
         b1.as_ptr(),
      );
   }
}
<|endoftext|>


<commit_before>#![feature(const_fn)]
#![no_std]

#[cfg(test)]
mod tests;

use core::mem::size_of;

#[derive(Debug, Clone, Copy)]
pub struct BitField<T: Number>(T);

impl<T> BitField<T>
    where T: Number
{
    pub const fn new(value: T) -> BitField<T> {
        BitField(value)
    }

    pub fn bits(&self) -> T {
        self.0
    }

    pub fn get_bit(&self, bit: u8) -> bool {
        assert!(bit < self.length());
        self.get_range(bit..(bit + 1)) == T::one()
    }

    pub fn get_range(&self, range: Range<u8>) -> T {
        assert!(range.start < self.length());
        assert!(range.end <= self.length());
        assert!(range.start < range.end);

        // shift away high bits
        let bits = self.0 << (self.length() - range.end) >> (self.length() - range.end);

        // shift away low bits
        bits >> range.start
    }

    pub fn set_bit(&mut self, bit: u8, value: bool) -> &mut Self {
        assert!(bit < self.length());
        if value {
            self.0 |= T::one() << bit;
        } else {
            self.0 &= !(T::one() << bit);
        }
        self
    }

    pub fn set_range(&mut self, range: Range<u8>, value: T) -> &mut Self {
        assert!(range.start < self.length());
        assert!(range.end <= self.length());
        assert!(range.start < range.end);
        assert!(value << (self.length() - (range.end - range.start)) >>
                (self.length() - (range.end - range.start)) == value,
                "value too big");

        let bitmask: T = !(!T::zero() << (self.length() - range.end) >>
                           (self.length() - range.end) >>
                           range.start << range.start);

        let bits = self.0 & bitmask;
        // set bits
        self.0 = bits | (value << range.start);

        self
    }

    fn length(&self) -> u8 {
        size_of::<T>() as u8 * 8
    }
}

use core::ops::{Range, Shl, Shr, BitAnd, BitOr, BitOrAssign, BitAndAssign, Not};
use core::fmt::Debug;

pub trait Number: Debug + Copy + Eq +
    Not<Output=Self> + Shl<u8, Output=Self> + Shr<u8, Output=Self> +
    BitAnd<Self, Output=Self> + BitOr<Self, Output=Self>  + BitAndAssign + BitOrAssign {

    fn zero() -> Self;
    fn one() -> Self;
}

macro_rules! number_impl {
    ($($t:ty)*) => ($(
        impl Number for $t {
            fn zero() -> Self { 0 }
            fn one() -> Self { 1 }
        }
    )*)
}

number_impl! { u8 u16 u32 u64 usize }
<commit_msg>Replace the BitField struct with a trait<commit_after>#![feature(const_fn)]
#![no_std]

#[cfg(test)]
mod tests;

use core::ops::{Range, Shl, Shr, BitAndAssign, BitOrAssign, Not, BitAnd, BitOr};
use core::mem::size_of;

pub trait BitField: Copy + Eq + Not<Output = Self> +
    Shl<u8, Output = Self> + Shr<u8, Output = Self> +
    BitAnd<Self, Output=Self> + BitOr<Self, Output=Self> + BitAndAssign + BitOrAssign
{
    fn zero() -> Self;
    fn one() -> Self;
    fn length(&self) -> u8;

    fn get_bit(&self, bit: u8) -> bool {
        assert!(bit < self.length());
        self.get_range(bit..(bit + 1)) == Self::one()
    }

    fn get_range(&self, range: Range<u8>) -> Self {
        assert!(range.start < self.length());
        assert!(range.end <= self.length());
        assert!(range.start < range.end);

// shift away high bits
        let bits = *self << (self.length() - range.end) >> (self.length() - range.end);

// shift away low bits
        bits >> range.start
    }

    fn set_bit(&mut self, bit: u8, value: bool) -> &mut Self {
        assert!(bit < self.length());
        if value {
            *self |= Self::one() << bit;
        } else {
            *self &= !(Self::one() << bit);
        }
        self
    }

    fn set_range(&mut self, range: Range<u8>, value: Self) -> &mut Self {
        assert!(range.start < self.length());
        assert!(range.end <= self.length());
        assert!(range.start < range.end);
        assert!(value << (self.length() - (range.end - range.start)) >>
                (self.length() - (range.end - range.start)) == value,
                "value too big");

        let bitmask: Self = !(!Self::zero() << (self.length() - range.end) >>
                              (self.length() - range.end) >>
                              range.start << range.start);

        let bits = *self & bitmask;
// set bits
        *self = bits | (value << range.start);

        self
    }
}

macro_rules! bitfield_impl {
    ($($t:ty)*) => ($(
        impl BitField for $t {
            fn zero() -> Self { 0 }
            fn one() -> Self { 1 }
            fn length(&self) -> u8 {
                size_of::<Self>() as u8 * 8
            }
        }
    )*)
}

bitfield_impl! { u8 u16 u32 u64 usize }
<|endoftext|>


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

use Data::*;
use Expression::*;

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

#[derive(Clone,Debug)]
pub enum Expression {
    NilLiteral,
    BooleanLiteral(bool),
    NumberLiteral(f64),
    StrLiteral(String),
    Variable(String),
    Assignment{left: String, right: Box<Expression>},
    FunctionCall{name: String, args: Vec<Expression>},
}

impl Expression {
    pub fn eval(&self, p: &mut Program) -> Data {
        match self {
            &NilLiteral => Nil,
            &BooleanLiteral(b) => Boolean(b),
            &NumberLiteral(n) => Number(n),
            &StrLiteral(ref s) => Str(s.clone()),
            &Variable(ref name) => {
                match p.vars.get(name) {
                    Some(d) => d.clone(),
                    None => Nil,
                }
            },
            &Assignment{ref left, ref right} => {
                let res = right.eval(p);
                p.vars.insert(left.clone(), res.clone());
                res
            },
            &FunctionCall{ref name, ref args} => {
                let f = match name.as_ref() {
                    "println" => println,
                    _ => return Nil,
                };

                let mut new_args = Vec::new();
                for item in args.iter() {
                    new_args.push(item.eval(p));
                }

                f(&new_args)
            },
        }
    }
}

pub struct Program {
    pub vars: HashMap<String, Data>,
    pub funcs: HashMap<String, i64>,
}

impl Program {
    pub fn new() -> Self {
        Program {
            vars: HashMap::new(),
            funcs: HashMap::new(),
        }
    }

    pub fn eval(&mut self, e: &Expression) -> Data {
        e.eval(self)
    }
}

pub fn println(v: &Vec<Data>) -> Data {
    for item in v {
        print!("{:?}", item);
    }
    println!("");
    Data::Nil
}

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

    #[test]
    fn test_things() {
        let mut ast: Vec<Expression> = Vec::new();
        ast.push(Assignment {
            left: "x".to_owned(),
            right: Box::new(NumberLiteral(2.0)),
        });
        ast.push(FunctionCall {
            name: "println".to_owned(),
            args: vec![Variable("x".to_owned())]
        });

        let mut p = Program::new();
        for exp in ast {
            p.eval(&exp);
        }
    }
}
<commit_msg>Add binary ops<commit_after>use std::collections::HashMap;

use BinaryOp::*;
use Data::*;
use Expression::*;

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

#[derive(Clone,Debug)]
pub enum Expression {
    NilLiteral,
    BooleanLiteral(bool),
    NumberLiteral(f64),
    StrLiteral(String),
    Variable(String),
    Assignment{left: String, right: Box<Expression>},
    FunctionCall{name: String, args: Vec<Expression>},
    BinaryExpr{left: Box<Expression>, op: BinaryOp, right: Box<Expression>},
}

impl Expression {
    pub fn eval(&self, p: &mut Program) -> Data {
        match self {
            &NilLiteral => Nil,
            &BooleanLiteral(b) => Boolean(b),
            &NumberLiteral(n) => Number(n),
            &StrLiteral(ref s) => Str(s.clone()),
            &Variable(ref name) => {
                match p.vars.get(name) {
                    Some(d) => d.clone(),
                    None => Nil,
                }
            },
            &Assignment{ref left, ref right} => {
                let res = right.eval(p);
                p.vars.insert(left.clone(), res.clone());
                res
            },
            &FunctionCall{ref name, ref args} => {
                let f = match name.as_ref() {
                    "println" => println,
                    _ => return Nil,
                };

                let mut new_args = Vec::new();
                for item in args.iter() {
                    new_args.push(item.eval(p));
                }

                f(&new_args)
            },
            &BinaryExpr{ref left, ref op, ref right} => {
                let (left_data, right_data) = (left.eval(p), right.eval(p));
                op.eval(&left_data, &right_data)
            },
        }
    }
}

#[derive(Clone,Debug)]
pub enum BinaryOp {
    Add,
    Sub,
    Mul,
    Div,
    Eq,
    Lt,
    LtEq,
    Gt,
    GtEq,
}

impl BinaryOp {
    fn eval(&self, left: &Data, right: &Data) -> Data {
        match (self, left, right) {
            (&Add, &Number(l), &Number(r)) => Number(l+r),
            (&Sub, &Number(l), &Number(r)) => Number(l-r),
            (&Mul, &Number(l), &Number(r)) => Number(l*r),
            (&Div, &Number(l), &Number(r)) => Number(l/r),
            (&Eq, _, _) => Boolean(left == right),
            (&Lt, &Number(l), &Number(r)) => Boolean(l < r),
            (&LtEq, &Number(l), &Number(r)) => Boolean(l <= r),
            (&Gt, &Number(l), &Number(r)) => Boolean(l > r),
            (&GtEq, &Number(l), &Number(r)) => Boolean(l >= r),
            _ => Nil,
        }
    }
}

pub struct Program {
    pub vars: HashMap<String, Data>,
    pub funcs: HashMap<String, i64>,
}

impl Program {
    pub fn new() -> Self {
        Program {
            vars: HashMap::new(),
            funcs: HashMap::new(),
        }
    }

    pub fn eval(&mut self, e: &Expression) -> Data {
        e.eval(self)
    }
}

pub fn println(v: &Vec<Data>) -> Data {
    for item in v {
        print!("{:?}", item);
    }
    println!("");
    Data::Nil
}

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

    #[test]
    fn test_things() {
        let mut ast: Vec<Expression> = Vec::new();
        ast.push(Assignment {
            left: "x".to_owned(),
            right: Box::new(NumberLiteral(2.0)),
        });
        ast.push(FunctionCall {
            name: "println".to_owned(),
            args: vec![Variable("x".to_owned())]
        });

        let mut p = Program::new();
        for exp in ast {
            p.eval(&exp);
        }
    }

    #[test]
    fn test_binary_expr() {
        let cases = vec![
            // Add
            (Add, Number(1.0), Number(2.0), Number(3.0)),
            (Add, Boolean(false), Number(2.0), Nil),
            (Add, Number(2.0), Str("1.0".to_owned()), Nil),
            // Sub
            (Sub, Number(1.0), Number(2.0), Number(-1.0)),
            (Sub, Boolean(false), Number(2.0), Nil),
            (Sub, Number(2.0), Str("1.0".to_owned()), Nil),
            // Mul
            (Mul, Number(1.5), Number(2.0), Number(3.0)),
            (Mul, Boolean(false), Number(2.0), Nil),
            (Mul, Number(2.0), Str("1.0".to_owned()), Nil),
            // Div
            (Div, Number(1.0), Number(2.0), Number(0.5)),
            (Div, Boolean(false), Number(2.0), Nil),
            (Div, Number(2.0), Str("1.0".to_owned()), Nil),
            // Eq
            (Eq, Number(2.0), Number(2.0), Boolean(true)),
            (Eq, Number(-2.0), Number(2.0), Boolean(false)),
            (Eq, Str("foo".to_owned()), Str("foo".to_owned()), Boolean(true)),
            (Eq, Str("foo".to_owned()), Str("bar".to_owned()), Boolean(false)),
            (Eq, Boolean(false), Boolean(false), Boolean(true)),
            (Eq, Boolean(true), Boolean(true), Boolean(true)),
            (Eq, Boolean(true), Boolean(false), Boolean(false)),
            (Eq, Nil, Boolean(false), Boolean(false)),
            (Eq, Nil, Nil, Boolean(true)),
            // Lt
            (Lt, Number(-1.0), Number(0.5), Boolean(true)),
            (Lt, Number(1.0), Number(1.0), Boolean(false)),
            (Lt, Number(1.0), Number(0.5), Boolean(false)),
            // LtEq
            (LtEq, Number(-1.0), Number(0.5), Boolean(true)),
            (LtEq, Number(1.0), Number(1.0), Boolean(true)),
            (LtEq, Number(1.0), Number(0.5), Boolean(false)),
            // Gt
            (Gt, Number(-1.0), Number(0.5), Boolean(false)),
            (Gt, Number(1.0), Number(1.0), Boolean(false)),
            (Gt, Number(1.0), Number(0.5), Boolean(true)),
            // GtEq
            (GtEq, Number(-1.0), Number(0.5), Boolean(false)),
            (GtEq, Number(1.0), Number(1.0), Boolean(true)),
            (GtEq, Number(1.0), Number(0.5), Boolean(true)),
        ];

        for (op, left, right, exp) in cases {
            assert_eq!(op.eval(&left, &right), exp);
        }
    }
}
<|endoftext|>