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

//! # Canteen
//!
//! ## Description
//!
//! A pure Rust clone of [Flask](http://flask.pocoo.org), a simple but powerful Python
//! web framework.
//!
//! The principle behind Canteen is simple -- handler functions are defined as simple
//! Rust functions that take a `Request` and return a `Response`. Handlers are then attached
//! to one or more routes and HTTP methods/verbs. Routes are specified using a simple
//! syntax that lets you define variables within them; variables that can then be
//! extracted to perform various operations. Currently, the following variable types can
//! be used:
//!
//! - `<str:name>` will match anything inside a path segment, returns a `String`
//! - `<int:name>` will return a signed integer (`i32`) from a path segment
//!   - ex: `cnt.add_route("/api/foo/<int:foo_id>", &[Method::Get], my_handler)` will match
//!   `"/api/foo/123"` but not `"/api/foo/123.34"` or `"/api/foo/bar"`
//! - `<uint:name>` will return an unsigned integer (`u32`)
//! - `<float:name>` does the same thing as the `int` parameter definition, but matches numbers
//! with decimal points and returns an `f32`
//! - `<path:name>` will greedily take all path data contained, returns a `String`
//!   - ex: `cnt.add_route("/static/<path:name>", &[Method::Get], utils::static_file)` will
//!   serve anything in the `/static/` directory as a file
//!
//! After the handlers are attached to routes, the next step is to simply start the
//! server. Any time a request is received, it is dispatched with the associated handler
//! to a threadpool worker. The worker notifies the parent process when it's finished,
//! and then the response is transmitted back to the client. Pretty straightforward stuff!
//!
//! ## Example
//!
//! ```rust
//! extern crate canteen;
//!
//! use canteen::{Canteen, Request, Response, Method};
//! use canteen::utils;
//!
//! fn hello_handler(_: &Request) -> Response {
//!     let mut res = Response::new();
//!
//!     res.set_status(200);
//!     res.set_content_type("text/plain");
//!     res.append("Hello, world!");
//!
//!     res
//! }
//!
//! fn double_handler(req: &Request) -> Response {
//!     let to_dbl: i32 = req.get("to_dbl");
//!
//!     /* simpler response generation syntax */
//!     utils::make_response(format!("{}", to_dbl * 2), "text/plain", 200)
//! }
//!
//! fn main() {
//!     let mut cnt = Canteen::new(("127.0.0.1", 8080));
//!
//!     // set the default route handler to show a 404 message
//!     cnt.set_default(utils::err_404);
//!
//!     // respond to requests to / with "Hello, world!"
//!     cnt.add_route("/", &[Method::Get], hello_handler);
//!
//!     // pull a variable from the path and do something with it
//!     cnt.add_route("/double/<int:to_dbl>", &[Method::Get], double_handler);
//!
//!     // serve raw files from the /static/ directory
//!     cnt.add_route("/static/<path:path>", &[Method::Get], utils::static_file);
//!
//!     /* cnt.run() */;
//! }
//! ```

extern crate mio;
extern crate regex;
extern crate chrono;
extern crate rustc_serialize;
extern crate threadpool;

pub mod utils;
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 threadpool::ThreadPool;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

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::with_capacity(2048),
            o_buf:  Vec::new(),
        }
    }

    fn receive(&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(_)  => {
                return Ok(false);
            },
        }

        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 send(&mut self) -> Result<bool> {
        if self.o_buf.len() == 0 {
            return Ok(false);
        }

        while self.o_buf.len() > 0 {
            match self.sock.write(&self.o_buf.as_slice()) {
                Ok(sz)  => {
                    if sz == self.o_buf.len() {
                        // we did it!
                        self.events.remove(EventSet::writable());
                        break;
                    } else {
                        // keep going
                        self.o_buf = self.o_buf.split_off(sz);
                    }
                },
                Err(_)  => {
                    return Ok(true);
                }
            }
        }

        Ok(true)
    }

    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())
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
    }
}

/// The primary struct provided by the library. The aim is to have a similar
/// interface to Flask, the Python microframework.
pub struct Canteen {
    routes:  HashMap<route::RouteDef, route::Route>,
    rcache:  HashMap<route::RouteDef, route::RouteDef>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
    tpool:   ThreadPool,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = (Token, Vec<u8>);

    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)).ok();
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).send() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => {},
            }
        }
    }

    fn notify(&mut self, evl: &mut EventLoop<Canteen>, msg: (Token, Vec<u8>)) {
        let (token, output) = msg;
        let mut client = self.get_client(token);

        client.o_buf = output;
        let _ = client.reregister(evl);
    }
}

impl Canteen {
    /// Creates a new Canteen instance.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8081));
    /// ```
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            rcache:  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: utils::err_404,
            tpool:   ThreadPool::new(255),
        }
    }

    /// Adds a new route definition to be handled by Canteen.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Canteen, Request, Response, Method};
    /// use canteen::utils;
    ///
    /// fn handler(_: &Request) -> Response {
    ///     utils::make_response("<b>Hello, world!</b>", "text/html", 200)
    /// }
    ///
    /// fn main() {
    ///     let mut cnt = Canteen::new(("127.0.0.1", 8082));
    ///     cnt.add_route("/hello", &[Method::Get], handler);
    /// }
    /// ```
    pub fn add_route(&mut self, path: &str, mlist: &[Method],
                     handler: fn(&Request) -> Response) -> &mut Canteen {
        let mut methods: HashSet<Method> = HashSet::new();

        // make them unique
        for m in mlist {
            methods.insert(*m);
        }

        for m in methods {
            let rd = route::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::Route::new(&path, m, handler));
        }

        self
    }

    /// Defines a default route for undefined paths.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    /// use canteen::utils;
    ///
    /// let mut cnt = Canteen::new(("127.0.0.1", 8083));
    /// cnt.set_default(utils::err_404);
    /// ```
    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(&mut self, token: Token, tx: Sender<(Token, Vec<u8>)>, rqstr: &str) {
        let mut req = Request::from_str(&rqstr);
        let resolved = route::RouteDef { pathdef: req.path.clone(), method: req.method };
        let mut handler: fn(&Request) -> Response = self.default;

        if self.rcache.contains_key(&resolved) {
            let ref route = self.routes[&self.rcache[&resolved]];

            handler = route.handler;
            req.params = route.parse(&req.path);
        } else {
            for (path, route) in &self.routes {
                match (route).is_match(&req) {
                    true  => {
                        handler = route.handler;
                        req.params = route.parse(&req.path);
                        self.rcache.insert(resolved, (*path).clone());
                        break;
                    },
                    false => continue,
                }
            }
        }

        self.tpool.execute(move || {
            let _ = tx.send((token, handler(&req).gen_output()));
        });
    }

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

        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())
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()).ok();
    }

    /// Creates the listener and starts a Canteen server's event loop.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8084));
    /// /* cnt.run(); */
    /// ```
    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<commit_msg>vastly simplify the accept() logic<commit_after>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

//! # Canteen
//!
//! ## Description
//!
//! A pure Rust clone of [Flask](http://flask.pocoo.org), a simple but powerful Python
//! web framework.
//!
//! The principle behind Canteen is simple -- handler functions are defined as simple
//! Rust functions that take a `Request` and return a `Response`. Handlers are then attached
//! to one or more routes and HTTP methods/verbs. Routes are specified using a simple
//! syntax that lets you define variables within them; variables that can then be
//! extracted to perform various operations. Currently, the following variable types can
//! be used:
//!
//! - `<str:name>` will match anything inside a path segment, returns a `String`
//! - `<int:name>` will return a signed integer (`i32`) from a path segment
//!   - ex: `cnt.add_route("/api/foo/<int:foo_id>", &[Method::Get], my_handler)` will match
//!   `"/api/foo/123"` but not `"/api/foo/123.34"` or `"/api/foo/bar"`
//! - `<uint:name>` will return an unsigned integer (`u32`)
//! - `<float:name>` does the same thing as the `int` parameter definition, but matches numbers
//! with decimal points and returns an `f32`
//! - `<path:name>` will greedily take all path data contained, returns a `String`
//!   - ex: `cnt.add_route("/static/<path:name>", &[Method::Get], utils::static_file)` will
//!   serve anything in the `/static/` directory as a file
//!
//! After the handlers are attached to routes, the next step is to simply start the
//! server. Any time a request is received, it is dispatched with the associated handler
//! to a threadpool worker. The worker notifies the parent process when it's finished,
//! and then the response is transmitted back to the client. Pretty straightforward stuff!
//!
//! ## Example
//!
//! ```rust
//! extern crate canteen;
//!
//! use canteen::{Canteen, Request, Response, Method};
//! use canteen::utils;
//!
//! fn hello_handler(_: &Request) -> Response {
//!     let mut res = Response::new();
//!
//!     res.set_status(200);
//!     res.set_content_type("text/plain");
//!     res.append("Hello, world!");
//!
//!     res
//! }
//!
//! fn double_handler(req: &Request) -> Response {
//!     let to_dbl: i32 = req.get("to_dbl");
//!
//!     /* simpler response generation syntax */
//!     utils::make_response(format!("{}", to_dbl * 2), "text/plain", 200)
//! }
//!
//! fn main() {
//!     let mut cnt = Canteen::new(("127.0.0.1", 8080));
//!
//!     // set the default route handler to show a 404 message
//!     cnt.set_default(utils::err_404);
//!
//!     // respond to requests to / with "Hello, world!"
//!     cnt.add_route("/", &[Method::Get], hello_handler);
//!
//!     // pull a variable from the path and do something with it
//!     cnt.add_route("/double/<int:to_dbl>", &[Method::Get], double_handler);
//!
//!     // serve raw files from the /static/ directory
//!     cnt.add_route("/static/<path:path>", &[Method::Get], utils::static_file);
//!
//!     /* cnt.run() */;
//! }
//! ```

extern crate mio;
extern crate regex;
extern crate chrono;
extern crate rustc_serialize;
extern crate threadpool;

pub mod utils;
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 threadpool::ThreadPool;
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;
use mio::*;

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::with_capacity(2048),
            o_buf:  Vec::new(),
        }
    }

    fn receive(&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(_)  => {
                return Ok(false);
            },
        }

        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 send(&mut self) -> Result<bool> {
        if self.o_buf.len() == 0 {
            return Ok(false);
        }

        while self.o_buf.len() > 0 {
            match self.sock.write(&self.o_buf.as_slice()) {
                Ok(sz)  => {
                    if sz == self.o_buf.len() {
                        // we did it!
                        self.events.remove(EventSet::writable());
                        break;
                    } else {
                        // keep going
                        self.o_buf = self.o_buf.split_off(sz);
                    }
                },
                Err(_)  => {
                    return Ok(true);
                }
            }
        }

        Ok(true)
    }

    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())
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) -> Result<()> {
        evl.reregister(&self.sock, self.token, self.events, PollOpt::edge() | PollOpt::oneshot())
    }
}

/// The primary struct provided by the library. The aim is to have a similar
/// interface to Flask, the Python microframework.
pub struct Canteen {
    routes:  HashMap<route::RouteDef, route::Route>,
    rcache:  HashMap<route::RouteDef, route::RouteDef>,
    server:  TcpListener,
    token:   Token,
    conns:   Slab<Client>,
    default: fn(&Request) -> Response,
    tpool:   ThreadPool,
}

impl Handler for Canteen {
    type Timeout = ();
    type Message = (Token, Vec<u8>);

    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)).ok();
            }

            return;
        }

        if events.is_writable() {
            match self.get_client(token).send() {
                Ok(true)    => { self.reset_connection(token); },
                Ok(false)   => { let _ = self.get_client(token).reregister(evl); },
                Err(_)      => {},
            }
        }
    }

    fn notify(&mut self, evl: &mut EventLoop<Canteen>, msg: (Token, Vec<u8>)) {
        let (token, output) = msg;
        let mut client = self.get_client(token);

        client.o_buf = output;
        let _ = client.reregister(evl);
    }
}

impl Canteen {
    /// Creates a new Canteen instance.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8081));
    /// ```
    pub fn new<A: ToSocketAddrs>(addr: A) -> Canteen {
        Canteen {
            routes:  HashMap::new(),
            rcache:  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: utils::err_404,
            tpool:   ThreadPool::new(255),
        }
    }

    /// Adds a new route definition to be handled by Canteen.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::{Canteen, Request, Response, Method};
    /// use canteen::utils;
    ///
    /// fn handler(_: &Request) -> Response {
    ///     utils::make_response("<b>Hello, world!</b>", "text/html", 200)
    /// }
    ///
    /// fn main() {
    ///     let mut cnt = Canteen::new(("127.0.0.1", 8082));
    ///     cnt.add_route("/hello", &[Method::Get], handler);
    /// }
    /// ```
    pub fn add_route(&mut self, path: &str, mlist: &[Method],
                     handler: fn(&Request) -> Response) -> &mut Canteen {
        let mut methods: HashSet<Method> = HashSet::new();

        // make them unique
        for m in mlist {
            methods.insert(*m);
        }

        for m in methods {
            let rd = route::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::Route::new(&path, m, handler));
        }

        self
    }

    /// Defines a default route for undefined paths.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    /// use canteen::utils;
    ///
    /// let mut cnt = Canteen::new(("127.0.0.1", 8083));
    /// cnt.set_default(utils::err_404);
    /// ```
    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>) {
        if let Ok(s) = self.server.accept() {
            if let Some((sock, _)) = s {
                if let Some(token) = self.conns.insert_with(|token| Client::new(sock, token)) {
                    self.get_client(token).register(evl).ok();
                }
            }
        }

        self.reregister(evl);
    }

    fn handle_request(&mut self, token: Token, tx: Sender<(Token, Vec<u8>)>, rqstr: &str) {
        let mut req = Request::from_str(&rqstr);
        let resolved = route::RouteDef { pathdef: req.path.clone(), method: req.method };
        let mut handler: fn(&Request) -> Response = self.default;

        if self.rcache.contains_key(&resolved) {
            let ref route = self.routes[&self.rcache[&resolved]];

            handler = route.handler;
            req.params = route.parse(&req.path);
        } else {
            for (path, route) in &self.routes {
                match (route).is_match(&req) {
                    true  => {
                        handler = route.handler;
                        req.params = route.parse(&req.path);
                        self.rcache.insert(resolved, (*path).clone());
                        break;
                    },
                    false => continue,
                }
            }
        }

        self.tpool.execute(move || {
            let _ = tx.send((token, handler(&req).gen_output()));
        });
    }

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

        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())
    }

    fn reregister(&mut self, evl: &mut EventLoop<Canteen>) {
        evl.reregister(&self.server, self.token,
                             EventSet::readable(),
                             PollOpt::edge() | PollOpt::oneshot()).ok();
    }

    /// Creates the listener and starts a Canteen server's event loop.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use canteen::Canteen;
    ///
    /// let cnt = Canteen::new(("127.0.0.1", 8084));
    /// /* cnt.run(); */
    /// ```
    pub fn run(&mut self) {
        let mut evl = EventLoop::new().unwrap();
        self.register(&mut evl).ok();
        evl.run(self).unwrap();
    }
}
<|endoftext|>


<commit_before>//! A crate for parsing Markdown in Rust
#![crate_name = "markdown"]
#![deny(missing_docs)]
// #![deny(warnings)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate regex;

#[macro_use]
extern crate pipeline;

use std::fs::File;
use std::path::Path;
use std::io::{Read, Error};

mod parser;
mod html;

use parser::Block;

/// Converts a Markdown string to HTML
pub fn to_html(text: &str) -> String {
    let result = parser::parse(text);
    html::to_html(&result)
}

/// Converts a Markdown string to a tokenset of Markdown items
pub fn tokenize(text: &str) -> Vec<Block> {
    parser::parse(text)
}

/// Opens a file and converts its contents to HTML
pub fn file_to_html(path: &Path) -> Result<String, Error> {
    let mut file = match File::open(path) {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut text = String::new();
    match file.read_to_string(&mut text) {
        Ok(_) => (),
        Err(e) => return Err(e),
    }

    let result = parser::parse(&text);
    Ok(html::to_html(&result))
}
<commit_msg>Replace match blocks with try! macro<commit_after>//! A crate for parsing Markdown in Rust
#![crate_name = "markdown"]
#![deny(missing_docs)]
// #![deny(warnings)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate regex;

#[macro_use]
extern crate pipeline;

use std::fs::File;
use std::path::Path;
use std::io::{self, Read};

mod parser;
mod html;

use parser::Block;

/// Converts a Markdown string to HTML
pub fn to_html(text: &str) -> String {
    let result = parser::parse(text);
    html::to_html(&result)
}

/// Converts a Markdown string to a tokenset of Markdown items
pub fn tokenize(text: &str) -> Vec<Block> {
    parser::parse(text)
}

/// Opens a file and converts its contents to HTML
pub fn file_to_html(path: &Path) -> io::Result<String> {
    let mut file = try!(File::open(path));

    let mut text = String::new();
    try!(file.read_to_string(&mut text));

    let result = parser::parse(&text);
    Ok(html::to_html(&result))
}
<|endoftext|>


<commit_before>/* 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/. */

use std::collections::HashMap;
use futures::Stream;

struct Statement(Node, Entity, Node, Entity);

struct Rule(Node, Entity, Node);

enum Node {
    Entity(Entity),
    Literal(Literal)
}

struct Entity {
    identifier: String
}

impl Entity {
    fn is_valid(identifier: &str) -> bool {
        //return "[a-zA-Z_][^\\s\\(\\)\\[\\]\\{\\}'\"`<>\\\\]*".toRegex().matches(identifier)
        unimplemented!()
    }
    fn from(identifier: &str) -> Result<Entity, String> {
        if Entity::is_valid(identifier) {
            Result::Ok(Entity { identifier: String::from(identifier) })
        } else {
            unimplemented!()
        }
    }
    fn a() -> Entity {
        Entity { identifier: String::from("_a") }
    }
    fn default() -> Entity {
        Entity { identifier: String::from("_") }
    }
    fn identifier(&self) -> &String {
        &self.identifier
    }
}

enum Literal {
    StringLiteral(String),
    LangLiteral(LangLiteral),
    BooleanLiteral(bool),
    LongLiteral(i64),
    DoubleLiteral(f64)//,
//    ListLiteral,
//    BagLiteral,
//    AltLiteral
}

enum Range {
    LangLiteralRange(LangLiteral, LangLiteral),
    StringLiteralRange(String, String),
    LongLiteralRange(u64, u64),
    DoubleLiteralRange(f64, f64)
}

struct LangLiteral {
    value: String,
    tag: String
}

impl LangLiteral {
    fn valid_tag(tag: &str) -> bool {
        //return "[a-zA-Z]+(-[a-zA-Z0-9]+)*".toRegex().matches(langTag)
        unimplemented!()
    }
    fn from(value: &str, tag: &str) -> Result<LangLiteral, String> {
        if LangLiteral::valid_tag(tag) {
            Result::Ok(LangLiteral { value: String::from(value), tag: String::from(tag) })
        } else {
            unimplemented!()
        }
    }
    fn value(&self) -> &String {
        &self.value
    }
    fn tag(&self) -> &String {
        &self.tag
    }
}

trait LigatureStore {
    /**
     * Returns a collection based on the name passed.
     * Calling this function will not create a new collection, it just binds a Store and Collection name.
     */
    fn collection(&self, collection_name: Entity) -> dyn LigatureCollection;

    /**
     * Creates a new collection or does nothing if collection already exists.
     * Regardless the collection is returned.
     */
    fn create_collection(&self, collection_name: Entity) -> dyn LigatureCollection;

    /**
     * Deletes the collection of the name given and does nothing if the collection doesn't exist.
     */
    fn delete_collection(&self, collection_name: Entity);

    /**
     * Returns a Iterator of all existing collections.
     */
    fn all_collections(&self) -> dyn Stream<Item = dyn LigatureCollection>;

    /**
     * Close connection with the Store.
     */
    fn close(&self);

    /**
     * Returns an implementation specific map of details about this Store useful for debugging.
     */
    fn details(&self) -> HashMap<String, String>;
}

/**
 * Manages a collection of Statements and Rules, supports ontologies, and querying.
 */
trait LigatureCollection {
    fn collection_name(&self) -> Entity;
    fn read_tx(&self) -> dyn ReadTx;
    fn write_tx(&self) -> dyn WriteTx;
}

trait ReadTx {
    /**
     * Accepts nothing but returns a Stream of all Statements in the Collection.
     */
    fn all_statements(&self) -> dyn Stream<Item = Statement>;

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    fn match_statements(&self, subject: Option<Node>, predicate: Option<Entity>, object: Option<Node>, graph: Option<Entity>) -> dyn Stream<Item = Statement>;

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    fn match_range(&self, subject: Option<Node>, predicate: Option<Entity>, range: Range, graph: Option<Entity>) -> dyn Stream<Item = Statement>;

    /**
     * Accepts nothing but returns a seq of all Rules in the Collection.
     */
    fn all_rules(&self) -> dyn Stream<Item = Rule>;

    /**
     * Is passed a pattern and returns a seq with all matching rules.
     */
    fn match_rules(&self, subject: Option<Node>, predicate: Option<Entity>, object: Option<Node>) -> dyn Stream<Item = Rule>;

    /**
     * Cancels this transaction.
     */
    fn cancel(&self);
}

trait WriteTx: ReadTx {
    /**
     * Returns a new, unique to this collection identifier in the form _:NUMBER"
     */
    fn new_entity(&self) -> Entity;
    fn add_statement(&self, statement: Statement);
    fn remove_statement(&self, statement: Statement);
    fn add_rule(&self, rule: Rule);
    fn remove_rule(&self, rule: Rule);
    fn commit(&self);
}
<commit_msg>removing details method<commit_after>/* 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/. */

use std::collections::HashMap;
use futures::Stream;

struct Statement(Node, Entity, Node, Entity);

struct Rule(Node, Entity, Node);

enum Node {
    Entity(Entity),
    Literal(Literal)
}

struct Entity {
    identifier: String
}

impl Entity {
    fn is_valid(identifier: &str) -> bool {
        //return "[a-zA-Z_][^\\s\\(\\)\\[\\]\\{\\}'\"`<>\\\\]*".toRegex().matches(identifier)
        unimplemented!()
    }
    fn from(identifier: &str) -> Result<Entity, String> {
        if Entity::is_valid(identifier) {
            Result::Ok(Entity { identifier: String::from(identifier) })
        } else {
            unimplemented!()
        }
    }
    fn a() -> Entity {
        Entity { identifier: String::from("_a") }
    }
    fn default() -> Entity {
        Entity { identifier: String::from("_") }
    }
    fn identifier(&self) -> &String {
        &self.identifier
    }
}

enum Literal {
    StringLiteral(String),
    LangLiteral(LangLiteral),
    BooleanLiteral(bool),
    LongLiteral(i64),
    DoubleLiteral(f64)//,
//    ListLiteral,
//    BagLiteral,
//    AltLiteral
}

enum Range {
    LangLiteralRange(LangLiteral, LangLiteral),
    StringLiteralRange(String, String),
    LongLiteralRange(u64, u64),
    DoubleLiteralRange(f64, f64)
}

struct LangLiteral {
    value: String,
    tag: String
}

impl LangLiteral {
    fn valid_tag(tag: &str) -> bool {
        //return "[a-zA-Z]+(-[a-zA-Z0-9]+)*".toRegex().matches(langTag)
        unimplemented!()
    }
    fn from(value: &str, tag: &str) -> Result<LangLiteral, String> {
        if LangLiteral::valid_tag(tag) {
            Result::Ok(LangLiteral { value: String::from(value), tag: String::from(tag) })
        } else {
            unimplemented!()
        }
    }
    fn value(&self) -> &String {
        &self.value
    }
    fn tag(&self) -> &String {
        &self.tag
    }
}

trait LigatureStore {
    /**
     * Returns a collection based on the name passed.
     * Calling this function will not create a new collection, it just binds a Store and Collection name.
     */
    fn collection(&self, collection_name: Entity) -> dyn LigatureCollection;

    /**
     * Creates a new collection or does nothing if collection already exists.
     * Regardless the collection is returned.
     */
    fn create_collection(&self, collection_name: Entity) -> dyn LigatureCollection;

    /**
     * Deletes the collection of the name given and does nothing if the collection doesn't exist.
     */
    fn delete_collection(&self, collection_name: Entity);

    /**
     * Returns a Iterator of all existing collections.
     */
    fn all_collections(&self) -> dyn Stream<Item = dyn LigatureCollection>;

    /**
     * Close connection with the Store.
     */
    fn close(&self);
}

/**
 * Manages a collection of Statements and Rules, supports ontologies, and querying.
 */
trait LigatureCollection {
    fn collection_name(&self) -> Entity;
    fn read_tx(&self) -> dyn ReadTx;
    fn write_tx(&self) -> dyn WriteTx;
}

trait ReadTx {
    /**
     * Accepts nothing but returns a Stream of all Statements in the Collection.
     */
    fn all_statements(&self) -> dyn Stream<Item = Statement>;

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    fn match_statements(&self, subject: Option<Node>, predicate: Option<Entity>, object: Option<Node>, graph: Option<Entity>) -> dyn Stream<Item = Statement>;

    /**
     * Is passed a pattern and returns a seq with all matching Statements.
     */
    fn match_range(&self, subject: Option<Node>, predicate: Option<Entity>, range: Range, graph: Option<Entity>) -> dyn Stream<Item = Statement>;

    /**
     * Accepts nothing but returns a seq of all Rules in the Collection.
     */
    fn all_rules(&self) -> dyn Stream<Item = Rule>;

    /**
     * Is passed a pattern and returns a seq with all matching rules.
     */
    fn match_rules(&self, subject: Option<Node>, predicate: Option<Entity>, object: Option<Node>) -> dyn Stream<Item = Rule>;

    /**
     * Cancels this transaction.
     */
    fn cancel(&self);
}

trait WriteTx: ReadTx {
    /**
     * Returns a new, unique to this collection identifier in the form _:NUMBER"
     */
    fn new_entity(&self) -> Entity;
    fn add_statement(&self, statement: Statement);
    fn remove_statement(&self, statement: Statement);
    fn add_rule(&self, rule: Rule);
    fn remove_rule(&self, rule: Rule);
    fn commit(&self);
}
<|endoftext|>


<commit_before>#![feature(plugin_registrar, macro_rules, globs)]

extern crate rustc;
extern crate rustc_trans;
extern crate syntax;

use std::io::Command;
use std::io::fs::PathExtensions;
use std::os;
use std::str;
use std::sync::{Once, ONCE_INIT};

use rustc::plugin::Registry;
use syntax::abi;
use syntax::ast;
use syntax::attr;
use syntax::ptr::P;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, DummyResult};
use syntax::ext::base::MacResult;
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::parse::token::{special_idents, InternedString};
use syntax::print::pprust;
use syntax::util::small_vector::SmallVector;

use self::State::*;
use self::SystemDeps::*;
use self::Favor::*;

struct LibInfo {
    lib: String,
    state: State,
    deps: Vec<(String, bool)>, // (name, static)
    locs: Vec<Path>,
}

struct MacItems {
    items: Vec<P<ast::Item>>,
}

enum State { Dynamic, Static(SystemDeps) }
enum SystemDeps { SystemDynamic, SystemStatic }
enum Favor { FavorDynamic, FavorStatic }

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("link_config", expand_link_config);
}

fn expand_link_config(ecx: &mut ExtCtxt, span: Span,
                      tts: &[ast::TokenTree]) -> Box<MacResult+'static> {
    macro_rules! try_dummy( ($e:expr) => (
        match $e { Ok(s) => s, Err(()) => return DummyResult::any(span) }
    ) )

    let mut parser = ecx.new_parser_from_tts(tts);
    let (pkg, sp) = try_dummy!(parse_string(ecx, &mut parser));
    let mut favor_dynamic = FavorDynamic;
    let mut dylib_state = Some(Dynamic);
    let mut static_state = Some(Static(SystemDynamic));
    if parser.eat(&token::Comma) && parser.eat(&token::OpenDelim(token::Bracket)) {
        while !parser.eat(&token::CloseDelim(token::Bracket)) {
            parser.eat(&token::Comma);
            let (modifier, sp) = try_dummy!(parse_string(ecx, &mut parser));
            match modifier.as_slice() {
                "only_static" => {
                    dylib_state = None;
                    favor_dynamic = FavorStatic;
                }
                "only_dylib" => {
                    static_state = None;
                    favor_dynamic = FavorDynamic;
                }
                "system_static" => static_state = Some(Static(SystemStatic)),
                "favor_static" => favor_dynamic = FavorStatic,
                s => ecx.span_err(sp, format!("unknown modifier: `{}`",
                                              s).as_slice()),
            }
        }
    }
    if !parser.eat(&token::Eof) {
        ecx.span_err(parser.span, "only one string literal allowed");
        return DummyResult::any(span);
    }

    let dyn = try_dummy!(system_pkgconfig(ecx, sp, pkg.as_slice(), dylib_state));
    let statik = try_dummy!(system_pkgconfig(ecx, sp, pkg.as_slice(), static_state));

    let mut items = Vec::new();
    match dyn {
        Some(info) => items.push(block(ecx, sp, &info, favor_dynamic)),
        None => {}
    }
    match statik {
        Some(info) => items.push(block(ecx, sp, &info, favor_dynamic)),
        None => {}
    }
    box MacItems { items: items } as Box<MacResult>
}

fn system_pkgconfig(ecx: &mut ExtCtxt, sp: Span, pkg: &str,
                    state: Option<State>) -> Result<Option<LibInfo>, ()> {
    let state = match state {
        Some(state) => state,
        None => return Ok(None),
    };
    add_cargo_pkg_config_paths();

    let mut cmd = Command::new("pkg-config");
    cmd.arg(pkg).arg("--libs").env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");
    match state {
        Static(..) => { cmd.arg("--static"); }
        Dynamic => {}
    }
    let out = match cmd.output() {
        Ok(out) => out,
        Err(e) => {
            ecx.span_err(sp, format!("could not run pkg-config: {}", e).as_slice());
            return Err(())
        }
    };
    let stdout = str::from_utf8(out.output.as_slice()).unwrap();
    let stderr = str::from_utf8(out.error.as_slice()).unwrap();
    if !out.status.success() {
        let mut msg = format!("pkg-config did not exit successfully: {}",
                              out.status);
        if stdout.len() > 0 {
            msg.push_str("\n--- stdout\n");
            msg.push_str(stdout);
        }
        if stderr.len() > 0 {
            msg.push_str("\n--- stderr\n");
            msg.push_str(stderr);
        }
        ecx.span_err(sp, msg.as_slice());
        return Err(())
    }

    let mut libs = Vec::new();
    let mut locs = Vec::new();
    for arg in stdout.split(' ').filter(|l| !l.is_empty()) {
        if arg.starts_with("-l") {
            libs.push(arg.slice_from(2));
        } else if arg.starts_with("-L") {
            locs.push(Path::new(arg.slice_from(2).to_string()));
        }
    }

    let allow_static = match state {
        Static(..) => true,
        _ => false,
    };
    let allow_static_system = match state {
        Static(SystemStatic) => true,
        _ => false,
    };

    let cargo_locs = cargo_native_dirs();
    let libs = libs.into_iter().map(|lib| {
        let mut candidates = cargo_locs.iter().chain(locs.iter());
        (lib.to_string(), allow_static && candidates.any(|base| {
            (allow_static_system || !base.as_vec().starts_with(b"/usr")) &&
                (base.join(format!("lib{}.a", lib)).exists() ||
                 base.join(format!("{}.lib", lib)).exists() ||
                 base.join(format!("lib{}.lib", lib)).exists())
        }))
    }).collect();
    Ok(Some(LibInfo {
        lib: pkg.to_string(),
        deps: libs,
        locs: locs,
        state: state,
    }))
}

fn block(ecx: &mut ExtCtxt, sp: Span, info: &LibInfo,
         favor: Favor) -> P<ast::Item> {
    let lib = token::intern_and_get_ident(info.lib.as_slice());
    let s = match favor {
        FavorDynamic => InternedString::new("statik"),
        FavorStatic => InternedString::new("dylib"),
    };
    let cfg = ecx.meta_name_value(sp, s, ast::LitStr(lib, ast::CookedStr));
    let cfg = match (info.state, favor) {
        (Static(..), FavorDynamic) |
        (Dynamic, FavorStatic) => cfg,
        (Dynamic, FavorDynamic) |
        (Static(..), FavorStatic) => {
            ecx.meta_list(sp, InternedString::new("not"), vec![cfg])
        }
    };
    let cfg = ecx.meta_list(sp, InternedString::new("cfg"), vec![cfg]);

    let attrs = vec![ecx.attribute(sp, cfg)].into_iter();
    let attrs = attrs.chain(info.deps.iter().map(|&(ref l, statik)| {
        // Build #[link(name = <l>)]
        let l = token::intern_and_get_ident(l.as_slice());
        let mut items = Vec::new();
        items.push(ecx.meta_name_value(sp, InternedString::new("name"),
                                       ast::LitStr(l, ast::CookedStr)));
        if statik {
            let l = InternedString::new("static");
            items.push(ecx.meta_name_value(sp, InternedString::new("kind"),
                                           ast::LitStr(l, ast::CookedStr)));
        }
        let list = ecx.meta_list(sp, InternedString::new("link"), items);
        ecx.attribute(sp, list)
    }));
    let attrs = attrs.chain(info.locs.iter().map(|l| {
        let l = token::intern_and_get_ident(format!("-L{}", l.display()).as_slice());
        let args = ecx.meta_name_value(sp, InternedString::new("link_args"),
                                       ast::LitStr(l, ast::CookedStr));
        ecx.attribute(sp, args)
    }));
    let mut attrs = attrs.map(|attr| {
        attr::mark_used(&attr);
        attr
    });

    ecx.item(sp, special_idents::invalid, attrs.collect(),
             ast::ItemForeignMod(ast::ForeignMod {
        abi: abi::C,
        view_items: Vec::new(),
        items: Vec::new(),
    }))
}

fn parse_string(ecx: &mut ExtCtxt,
                parser: &mut Parser) -> Result<(String, Span), ()> {
    let entry = ecx.expander().fold_expr(parser.parse_expr());
    match entry.node {
        ast::ExprLit(ref lit) => {
            match lit.node {
                ast::LitStr(ref s, _) => return Ok((s.to_string(), entry.span)),
                _ => {}
            }
        }
        _ => {}
    }
    ecx.span_err(entry.span, format!(
        "expected string literal but got `{}`",
        pprust::expr_to_string(&*entry)).as_slice());
    Err(())
}

impl MacResult for MacItems {
    fn make_items(self: Box<MacItems>) -> Option<SmallVector<P<ast::Item>>> {
        Some(self.items.into_iter().collect())
    }
}

// lol hax
fn cargo_native_dirs() -> Vec<Path> {
    match rustc_trans::driver::handle_options(os::args()) {
        Some(matches) => {
            matches.opt_strs("L").into_iter().filter_map(|s| {
                if s.as_slice().contains("native") {
                    Some(Path::new(s))
                } else {
                    None
                }
            }).collect()
        }
        None => Vec::new()
    }
}

fn add_cargo_pkg_config_paths() {
    static mut DONE: Once = ONCE_INIT;
    unsafe { DONE.doit(add_cargo_pkg_config_paths) }

    fn add_cargo_pkg_config_paths() {
        let path = os::getenv_as_bytes("PKG_CONFIG_PATH").unwrap_or(Vec::new());
        let mut pkg_config_path = os::split_paths(path.as_slice());
        pkg_config_path.push_all(cargo_native_dirs().as_slice());
        let pkg_config_path = os::join_paths(pkg_config_path.as_slice())
                                 .unwrap();
        os::setenv("PKG_CONFIG_PATH", pkg_config_path.as_slice());
    }
}
<commit_msg>Fixes compilation error introduced by rustc 0.13.0-nightly (a31ad6bfc 2014-12-06 23:12:17 +0000)<commit_after>#![feature(plugin_registrar, macro_rules, globs)]

extern crate rustc;
extern crate rustc_driver;
extern crate syntax;

use std::io::Command;
use std::io::fs::PathExtensions;
use std::os;
use std::str;
use std::sync::{Once, ONCE_INIT};

use rustc::plugin::Registry;
use syntax::abi;
use syntax::ast;
use syntax::attr;
use syntax::ptr::P;
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, DummyResult};
use syntax::ext::base::MacResult;
use syntax::ext::build::AstBuilder;
use syntax::fold::Folder;
use syntax::parse::parser::Parser;
use syntax::parse::token;
use syntax::parse::token::{special_idents, InternedString};
use syntax::print::pprust;
use syntax::util::small_vector::SmallVector;

use self::State::*;
use self::SystemDeps::*;
use self::Favor::*;

struct LibInfo {
    lib: String,
    state: State,
    deps: Vec<(String, bool)>, // (name, static)
    locs: Vec<Path>,
}

struct MacItems {
    items: Vec<P<ast::Item>>,
}

enum State { Dynamic, Static(SystemDeps) }
enum SystemDeps { SystemDynamic, SystemStatic }
enum Favor { FavorDynamic, FavorStatic }

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_macro("link_config", expand_link_config);
}

fn expand_link_config(ecx: &mut ExtCtxt, span: Span,
                      tts: &[ast::TokenTree]) -> Box<MacResult+'static> {
    macro_rules! try_dummy( ($e:expr) => (
        match $e { Ok(s) => s, Err(()) => return DummyResult::any(span) }
    ) )

    let mut parser = ecx.new_parser_from_tts(tts);
    let (pkg, sp) = try_dummy!(parse_string(ecx, &mut parser));
    let mut favor_dynamic = FavorDynamic;
    let mut dylib_state = Some(Dynamic);
    let mut static_state = Some(Static(SystemDynamic));
    if parser.eat(&token::Comma) && parser.eat(&token::OpenDelim(token::Bracket)) {
        while !parser.eat(&token::CloseDelim(token::Bracket)) {
            parser.eat(&token::Comma);
            let (modifier, sp) = try_dummy!(parse_string(ecx, &mut parser));
            match modifier.as_slice() {
                "only_static" => {
                    dylib_state = None;
                    favor_dynamic = FavorStatic;
                }
                "only_dylib" => {
                    static_state = None;
                    favor_dynamic = FavorDynamic;
                }
                "system_static" => static_state = Some(Static(SystemStatic)),
                "favor_static" => favor_dynamic = FavorStatic,
                s => ecx.span_err(sp, format!("unknown modifier: `{}`",
                                              s).as_slice()),
            }
        }
    }
    if !parser.eat(&token::Eof) {
        ecx.span_err(parser.span, "only one string literal allowed");
        return DummyResult::any(span);
    }

    let dyn = try_dummy!(system_pkgconfig(ecx, sp, pkg.as_slice(), dylib_state));
    let statik = try_dummy!(system_pkgconfig(ecx, sp, pkg.as_slice(), static_state));

    let mut items = Vec::new();
    match dyn {
        Some(info) => items.push(block(ecx, sp, &info, favor_dynamic)),
        None => {}
    }
    match statik {
        Some(info) => items.push(block(ecx, sp, &info, favor_dynamic)),
        None => {}
    }
    box MacItems { items: items } as Box<MacResult>
}

fn system_pkgconfig(ecx: &mut ExtCtxt, sp: Span, pkg: &str,
                    state: Option<State>) -> Result<Option<LibInfo>, ()> {
    let state = match state {
        Some(state) => state,
        None => return Ok(None),
    };
    add_cargo_pkg_config_paths();

    let mut cmd = Command::new("pkg-config");
    cmd.arg(pkg).arg("--libs").env("PKG_CONFIG_ALLOW_SYSTEM_LIBS", "1");
    match state {
        Static(..) => { cmd.arg("--static"); }
        Dynamic => {}
    }
    let out = match cmd.output() {
        Ok(out) => out,
        Err(e) => {
            ecx.span_err(sp, format!("could not run pkg-config: {}", e).as_slice());
            return Err(())
        }
    };
    let stdout = str::from_utf8(out.output.as_slice()).unwrap();
    let stderr = str::from_utf8(out.error.as_slice()).unwrap();
    if !out.status.success() {
        let mut msg = format!("pkg-config did not exit successfully: {}",
                              out.status);
        if stdout.len() > 0 {
            msg.push_str("\n--- stdout\n");
            msg.push_str(stdout);
        }
        if stderr.len() > 0 {
            msg.push_str("\n--- stderr\n");
            msg.push_str(stderr);
        }
        ecx.span_err(sp, msg.as_slice());
        return Err(())
    }

    let mut libs = Vec::new();
    let mut locs = Vec::new();
    for arg in stdout.split(' ').filter(|l| !l.is_empty()) {
        if arg.starts_with("-l") {
            libs.push(arg.slice_from(2));
        } else if arg.starts_with("-L") {
            locs.push(Path::new(arg.slice_from(2).to_string()));
        }
    }

    let allow_static = match state {
        Static(..) => true,
        _ => false,
    };
    let allow_static_system = match state {
        Static(SystemStatic) => true,
        _ => false,
    };

    let cargo_locs = cargo_native_dirs();
    let libs = libs.into_iter().map(|lib| {
        let mut candidates = cargo_locs.iter().chain(locs.iter());
        (lib.to_string(), allow_static && candidates.any(|base| {
            (allow_static_system || !base.as_vec().starts_with(b"/usr")) &&
                (base.join(format!("lib{}.a", lib)).exists() ||
                 base.join(format!("{}.lib", lib)).exists() ||
                 base.join(format!("lib{}.lib", lib)).exists())
        }))
    }).collect();
    Ok(Some(LibInfo {
        lib: pkg.to_string(),
        deps: libs,
        locs: locs,
        state: state,
    }))
}

fn block(ecx: &mut ExtCtxt, sp: Span, info: &LibInfo,
         favor: Favor) -> P<ast::Item> {
    let lib = token::intern_and_get_ident(info.lib.as_slice());
    let s = match favor {
        FavorDynamic => InternedString::new("statik"),
        FavorStatic => InternedString::new("dylib"),
    };
    let cfg = ecx.meta_name_value(sp, s, ast::LitStr(lib, ast::CookedStr));
    let cfg = match (info.state, favor) {
        (Static(..), FavorDynamic) |
        (Dynamic, FavorStatic) => cfg,
        (Dynamic, FavorDynamic) |
        (Static(..), FavorStatic) => {
            ecx.meta_list(sp, InternedString::new("not"), vec![cfg])
        }
    };
    let cfg = ecx.meta_list(sp, InternedString::new("cfg"), vec![cfg]);

    let attrs = vec![ecx.attribute(sp, cfg)].into_iter();
    let attrs = attrs.chain(info.deps.iter().map(|&(ref l, statik)| {
        // Build #[link(name = <l>)]
        let l = token::intern_and_get_ident(l.as_slice());
        let mut items = Vec::new();
        items.push(ecx.meta_name_value(sp, InternedString::new("name"),
                                       ast::LitStr(l, ast::CookedStr)));
        if statik {
            let l = InternedString::new("static");
            items.push(ecx.meta_name_value(sp, InternedString::new("kind"),
                                           ast::LitStr(l, ast::CookedStr)));
        }
        let list = ecx.meta_list(sp, InternedString::new("link"), items);
        ecx.attribute(sp, list)
    }));
    let attrs = attrs.chain(info.locs.iter().map(|l| {
        let l = token::intern_and_get_ident(format!("-L{}", l.display()).as_slice());
        let args = ecx.meta_name_value(sp, InternedString::new("link_args"),
                                       ast::LitStr(l, ast::CookedStr));
        ecx.attribute(sp, args)
    }));
    let attrs = attrs.map(|attr| {
        attr::mark_used(&attr);
        attr
    });

    ecx.item(sp, special_idents::invalid, attrs.collect(),
             ast::ItemForeignMod(ast::ForeignMod {
        abi: abi::C,
        view_items: Vec::new(),
        items: Vec::new(),
    }))
}

fn parse_string(ecx: &mut ExtCtxt,
                parser: &mut Parser) -> Result<(String, Span), ()> {
    let entry = ecx.expander().fold_expr(parser.parse_expr());
    match entry.node {
        ast::ExprLit(ref lit) => {
            match lit.node {
                ast::LitStr(ref s, _) => return Ok((s.to_string(), entry.span)),
                _ => {}
            }
        }
        _ => {}
    }
    ecx.span_err(entry.span, format!(
        "expected string literal but got `{}`",
        pprust::expr_to_string(&*entry)).as_slice());
    Err(())
}

impl MacResult for MacItems {
    fn make_items(self: Box<MacItems>) -> Option<SmallVector<P<ast::Item>>> {
        Some(self.items.into_iter().collect())
    }
}

// lol hax
fn cargo_native_dirs() -> Vec<Path> {
    match rustc_driver::handle_options(os::args()) {
        Some(matches) => {
            matches.opt_strs("L").into_iter().filter_map(|s| {
                if s.as_slice().contains("native") {
                    Some(Path::new(s))
                } else {
                    None
                }
            }).collect()
        }
        None => Vec::new()
    }
}

fn add_cargo_pkg_config_paths() {
    static mut DONE: Once = ONCE_INIT;
    unsafe { DONE.doit(add_cargo_pkg_config_paths) }

    fn add_cargo_pkg_config_paths() {
        let path = os::getenv_as_bytes("PKG_CONFIG_PATH").unwrap_or(Vec::new());
        let mut pkg_config_path = os::split_paths(path.as_slice());
        pkg_config_path.push_all(cargo_native_dirs().as_slice());
        let pkg_config_path = os::join_paths(pkg_config_path.as_slice())
                                 .unwrap();
        os::setenv("PKG_CONFIG_PATH", pkg_config_path.as_slice());
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate crc;
extern crate time;

use std::borrow::Cow;
use std::io::{Cursor, Read, Write};
use std::vec::Vec;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crc::crc32;

#[derive(Debug, Eq, PartialEq)]
pub struct Entry<'a> {
    key: Cow<'a, [u8]>,
    value: Cow<'a, [u8]>,
    timestamp: u32,
    deleted: bool,
}

const STATIC_SIZE: usize = 14; // crc(4) + timestamp(4) + key_size(2) + value_size(4)
const TOMBSTONE: u32 = !0;

impl<'a> Entry<'a> {
    pub fn new<K, V>(key: K, value: V) -> Entry<'a>
        where Cow<'a, [u8]>: From<K>,
              Cow<'a, [u8]>: From<V>
    {
        let v = Cow::from(value);
        assert!(v.len() < TOMBSTONE as usize);

        Entry {
            key: Cow::from(key),
            value: v,
            timestamp: time::now().to_timespec().sec as u32,
            deleted: false,
        }
    }

    pub fn deleted(&self) -> Entry<'a> {
        Entry {
            key: self.key.clone(),
            value: Cow::Borrowed(&[]),
            timestamp: time::now().to_timespec().sec as u32,
            deleted: true,
        }
    }

    pub fn size(&self) -> usize {
        STATIC_SIZE + self.key.len() + self.value.len()
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        let mut cursor = Cursor::new(Vec::with_capacity(self.size()));
        cursor.set_position(4);
        cursor.write_u32::<LittleEndian>(self.timestamp).unwrap();
        cursor.write_u16::<LittleEndian>(self.key.len() as u16).unwrap();

        if self.deleted {
            cursor.write_u32::<LittleEndian>(TOMBSTONE).unwrap();
            cursor.write_all(&self.key).unwrap();
        } else {
            cursor.write_u32::<LittleEndian>(self.value.len() as u32).unwrap();
            cursor.write_all(&self.key).unwrap();
            cursor.write_all(&self.value).unwrap();
        }

        let checksum = crc32::checksum_ieee(&cursor.get_ref()[4..]);
        cursor.set_position(0);
        cursor.write_u32::<LittleEndian>(checksum).unwrap();

        cursor.into_inner()
    }

    pub fn from_bytes(bytes: &'a [u8]) -> Entry<'a> {
        let mut cursor = Cursor::new(bytes);

        let checksum = cursor.read_u32::<LittleEndian>().unwrap();
        assert_eq!(crc32::checksum_ieee(&bytes[4..]), checksum);

        let timestamp = cursor.read_u32::<LittleEndian>().unwrap();
        let key_size = cursor.read_u16::<LittleEndian>().unwrap();
        let value_size = cursor.read_u32::<LittleEndian>().unwrap();

        Entry {
            key: Cow::from(&bytes[STATIC_SIZE..STATIC_SIZE + key_size as usize]),
            value: Cow::from(&bytes[STATIC_SIZE + key_size as usize..]),
            timestamp: timestamp,
            deleted: value_size == TOMBSTONE,
        }
    }

    pub fn from_read<R: Read>(reader: &mut R) -> Entry<'a> {
        let mut header = vec![0u8; STATIC_SIZE as usize];
        reader.read(&mut header).unwrap();

        let mut cursor = Cursor::new(header);
        let checksum = cursor.read_u32::<LittleEndian>().unwrap();
        let timestamp = cursor.read_u32::<LittleEndian>().unwrap();
        let key_size = cursor.read_u16::<LittleEndian>().unwrap();
        let value_size = cursor.read_u32::<LittleEndian>().unwrap();

        let mut key = vec![0u8; key_size as usize];
        reader.read_exact(&mut key).unwrap();

        let deleted = value_size == TOMBSTONE;

        let value = if deleted {
            let empty: &[u8] = &[];
            Cow::from(empty)
        } else {
            let mut value = vec![0u8; value_size as usize];
            reader.read_exact(&mut value).unwrap();
            Cow::from(value)
        };

        let crc = {
            // unfortunately I had to inline the checksum code since it only accepts slices as
            // arguments (and I wanted to keep the iterator to avoid needless copying)
            let mut v: u32 = !0;
            let t = &crc32::IEEE_TABLE;
            for i in cursor.get_ref()[4..].iter().chain(key.iter().chain(value.iter())) {
                v = t[((v as u8) ^ i) as usize] ^ (v >> 8)
            }
            !v
        };

        assert_eq!(crc, checksum);

        Entry {
            key: Cow::from(key),
            value: Cow::from(value),
            timestamp: timestamp,
            deleted: deleted,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use Entry;

    #[test]
    fn test_serialization() {
        let key: &[u8] = &[0, 0, 0];
        let value: &[u8] = &[0, 0, 0];
        let entry = Entry::new(key, value);

        assert_eq!(entry.to_bytes().len(), 20);
        assert_eq!(entry, Entry::from_bytes(&entry.to_bytes()));
        assert_eq!(entry, Entry::from_read(&mut Cursor::new(entry.to_bytes())));
        assert_eq!(entry.deleted(),
                   Entry::from_bytes(&entry.deleted().to_bytes()));
        assert_eq!(entry.deleted(),
                   Entry::from_read(&mut Cursor::new(entry.deleted().to_bytes())));

        let empty_entry = Entry::new(key, vec![]);
        assert_eq!(empty_entry, Entry::from_bytes(&empty_entry.to_bytes()));
        assert_eq!(empty_entry,
                   Entry::from_read(&mut Cursor::new(&empty_entry.to_bytes())));
        assert_eq!(empty_entry.deleted(),
                   Entry::from_bytes(&empty_entry.deleted().to_bytes()));
        assert_eq!(empty_entry.deleted(),
                   Entry::from_read(&mut Cursor::new(&empty_entry.deleted().to_bytes())));

        assert!(Entry::from_bytes(&empty_entry.deleted().to_bytes()).deleted);
        assert!(Entry::from_read(&mut Cursor::new(&empty_entry.deleted().to_bytes())).deleted);
        assert!(empty_entry.deleted().deleted);
    }

    #[test]
    fn test_deleted() {
        let key: &[u8] = &[0, 0, 0];
        let value: &[u8] = &[0, 0, 0];
        let entry = Entry::new(key, value);

        assert!(entry.deleted().deleted);
        assert_eq!(entry.deleted().value.len(), 0);
    }
}
<commit_msg>implement streaming serialization<commit_after>extern crate byteorder;
extern crate crc;
extern crate time;

use std::borrow::Cow;
use std::io::{Cursor, Read, Write};
use std::vec::Vec;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crc::crc32;

#[derive(Debug, Eq, PartialEq)]
pub struct Entry<'a> {
    key: Cow<'a, [u8]>,
    value: Cow<'a, [u8]>,
    timestamp: u32,
    deleted: bool,
}

const STATIC_SIZE: usize = 14; // crc(4) + timestamp(4) + key_size(2) + value_size(4)
const TOMBSTONE: u32 = !0;

impl<'a> Entry<'a> {
    pub fn new<K, V>(key: K, value: V) -> Entry<'a>
        where Cow<'a, [u8]>: From<K>,
              Cow<'a, [u8]>: From<V>
    {
        let v = Cow::from(value);
        assert!(v.len() < TOMBSTONE as usize);

        Entry {
            key: Cow::from(key),
            value: v,
            timestamp: time::now().to_timespec().sec as u32,
            deleted: false,
        }
    }

    pub fn deleted(&self) -> Entry<'a> {
        Entry {
            key: self.key.clone(),
            value: Cow::Borrowed(&[]),
            timestamp: time::now().to_timespec().sec as u32,
            deleted: true,
        }
    }

    pub fn size(&self) -> usize {
        STATIC_SIZE + self.key.len() + self.value.len()
    }

    pub fn to_bytes(&self) -> Vec<u8> {
        let mut cursor = Cursor::new(Vec::with_capacity(self.size()));
        cursor.set_position(4);
        cursor.write_u32::<LittleEndian>(self.timestamp).unwrap();
        cursor.write_u16::<LittleEndian>(self.key.len() as u16).unwrap();

        if self.deleted {
            cursor.write_u32::<LittleEndian>(TOMBSTONE).unwrap();
            cursor.write_all(&self.key).unwrap();
        } else {
            cursor.write_u32::<LittleEndian>(self.value.len() as u32).unwrap();
            cursor.write_all(&self.key).unwrap();
            cursor.write_all(&self.value).unwrap();
        }

        let checksum = crc32::checksum_ieee(&cursor.get_ref()[4..]);
        cursor.set_position(0);
        cursor.write_u32::<LittleEndian>(checksum).unwrap();

        cursor.into_inner()
    }

    pub fn write_bytes<W: Write>(&self, writer: &mut W) {
        let mut cursor = Cursor::new(Vec::with_capacity(STATIC_SIZE));
        cursor.set_position(4);
        cursor.write_u32::<LittleEndian>(self.timestamp).unwrap();
        cursor.write_u16::<LittleEndian>(self.key.len() as u16).unwrap();

        if self.deleted {
            cursor.write_u32::<LittleEndian>(TOMBSTONE).unwrap();
        } else {
            cursor.write_u32::<LittleEndian>(self.value.len() as u32).unwrap();
        }

        let checksum = {
            // unfortunately I had to inline the checksum code since it only accepts slices as
            // arguments (and I wanted to keep the iterator to avoid needless copying)
            let mut v: u32 = !0;
            let t = &crc32::IEEE_TABLE;
            for i in cursor.get_ref()[4..].iter().chain(self.key.iter().chain(self.value.iter())) {
                v = t[((v as u8) ^ i) as usize] ^ (v >> 8)
            }
            !v
        };

        cursor.set_position(0);
        cursor.write_u32::<LittleEndian>(checksum).unwrap();

        writer.write_all(&cursor.into_inner()).unwrap();
        writer.write_all(&self.key).unwrap();

        if !self.deleted {
            writer.write_all(&self.value).unwrap();
        }
    }

    pub fn from_bytes(bytes: &'a [u8]) -> Entry<'a> {
        let mut cursor = Cursor::new(bytes);

        let checksum = cursor.read_u32::<LittleEndian>().unwrap();
        assert_eq!(crc32::checksum_ieee(&bytes[4..]), checksum);

        let timestamp = cursor.read_u32::<LittleEndian>().unwrap();
        let key_size = cursor.read_u16::<LittleEndian>().unwrap();
        let value_size = cursor.read_u32::<LittleEndian>().unwrap();

        Entry {
            key: Cow::from(&bytes[STATIC_SIZE..STATIC_SIZE + key_size as usize]),
            value: Cow::from(&bytes[STATIC_SIZE + key_size as usize..]),
            timestamp: timestamp,
            deleted: value_size == TOMBSTONE,
        }
    }

    pub fn from_read<R: Read>(reader: &mut R) -> Entry<'a> {
        let mut header = vec![0u8; STATIC_SIZE as usize];
        reader.read(&mut header).unwrap();

        let mut cursor = Cursor::new(header);
        let checksum = cursor.read_u32::<LittleEndian>().unwrap();
        let timestamp = cursor.read_u32::<LittleEndian>().unwrap();
        let key_size = cursor.read_u16::<LittleEndian>().unwrap();
        let value_size = cursor.read_u32::<LittleEndian>().unwrap();

        let mut key = vec![0u8; key_size as usize];
        reader.read_exact(&mut key).unwrap();

        let deleted = value_size == TOMBSTONE;

        let value = if deleted {
            let empty: &[u8] = &[];
            Cow::from(empty)
        } else {
            let mut value = vec![0u8; value_size as usize];
            reader.read_exact(&mut value).unwrap();
            Cow::from(value)
        };

        let crc = {
            // unfortunately I had to inline the checksum code since it only accepts slices as
            // arguments (and I wanted to keep the iterator to avoid needless copying)
            let mut v: u32 = !0;
            let t = &crc32::IEEE_TABLE;
            for i in cursor.get_ref()[4..].iter().chain(key.iter().chain(value.iter())) {
                v = t[((v as u8) ^ i) as usize] ^ (v >> 8)
            }
            !v
        };

        assert_eq!(crc, checksum);

        Entry {
            key: Cow::from(key),
            value: Cow::from(value),
            timestamp: timestamp,
            deleted: deleted,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;

    use Entry;

    #[test]
    fn test_serialization() {
        let key: &[u8] = &[0, 0, 0];
        let value: &[u8] = &[0, 0, 0];
        let entry = Entry::new(key, value);

        assert_eq!(entry.to_bytes().len(), 20);

        assert_eq!(entry, Entry::from_bytes(&entry.to_bytes()));
        assert_eq!(entry, Entry::from_read(&mut Cursor::new(entry.to_bytes())));
        let mut v = Vec::new();
        entry.write_bytes(&mut v);
        assert_eq!(entry, Entry::from_bytes(&v));

        assert_eq!(entry.deleted(),
                   Entry::from_bytes(&entry.deleted().to_bytes()));
        assert_eq!(entry.deleted(),
                   Entry::from_read(&mut Cursor::new(entry.deleted().to_bytes())));
        v.clear();
        entry.deleted().write_bytes(&mut v);
        assert_eq!(entry.deleted(), Entry::from_bytes(&v));

        let empty_entry = Entry::new(key, vec![]);
        assert_eq!(empty_entry, Entry::from_bytes(&empty_entry.to_bytes()));
        assert_eq!(empty_entry,
                   Entry::from_read(&mut Cursor::new(&empty_entry.to_bytes())));
        v.clear();
        empty_entry.write_bytes(&mut v);
        assert_eq!(empty_entry, Entry::from_bytes(&v));

        assert_eq!(empty_entry.deleted(),
                   Entry::from_bytes(&empty_entry.deleted().to_bytes()));
        assert_eq!(empty_entry.deleted(),
                   Entry::from_read(&mut Cursor::new(&empty_entry.deleted().to_bytes())));
        v.clear();
        empty_entry.deleted().write_bytes(&mut v);
        assert_eq!(empty_entry.deleted(), Entry::from_bytes(&v));

        assert!(Entry::from_bytes(&empty_entry.deleted().to_bytes()).deleted);
        assert!(Entry::from_read(&mut Cursor::new(&empty_entry.deleted().to_bytes())).deleted);
        assert!(Entry::from_bytes(&v).deleted);
        assert!(empty_entry.deleted().deleted);
    }

    #[test]
    fn test_deleted() {
        let key: &[u8] = &[0, 0, 0];
        let value: &[u8] = &[0, 0, 0];
        let entry = Entry::new(key, value);

        assert!(entry.deleted().deleted);
        assert_eq!(entry.deleted().value.len(), 0);
    }
}
<|endoftext|>


<commit_before>extern crate time;

use std::fmt;
use time::precise_time_ns;
use std::io::fs::File;
use std::mem;
use std::rt;
use std::sync::Arc;
use std::sync::Mutex;
use std::collections::HashMap;

#[derive(Clone)]
struct TimeDB {
    times: Arc<Mutex<HashMap<&'static str, InvocationTracking>>>,
}

fn time_db() -> TimeDB {
    use std::sync::{Once, ONCE_INIT};
    static mut TIMEDB : *const TimeDB = 0 as *const TimeDB;
    static mut ONCE: Once = ONCE_INIT;
    unsafe {
        ONCE.call_once(|| {
            let timedb = TimeDB {
                times: Arc::new(Mutex::new(HashMap::new())),
            };
            TIMEDB = mem::transmute(box timedb);

            // Make sure to free it at exit
            rt::at_exit(|| {
                mem::transmute::<_, Box<TimeDB>>(TIMEDB);
                TIMEDB = 0 as *const _;
            });
        });
        (*TIMEDB).clone()
    }
}

#[derive(Copy)]
struct InvocationTracking {
    count: u64,
    total_time: u64,
}

impl fmt::Show for InvocationTracking {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let avg_time = match self.count == 0 {
            true => 0.0f64,
            false => self.total_time as f64 / self.count as f64,
        };
        write!(f, "{} | {} ns/call", self.count, avg_time)
    }
}

impl InvocationTracking {
    fn new(t: &TimeIt) -> InvocationTracking {
        let mut i = InvocationTracking {
            count: 0,
            total_time: 0,
        };
        i.add_time(t);
        return i;
    }
    fn add_time(&mut self, t: &TimeIt) {
        let dur = precise_time_ns() - t.start_time;
        self.count += 1;
        self.total_time += dur;
    }
}

impl TimeDB {
    fn add_time(&mut self, time: &TimeIt) {
        let ref mut m = self.times.lock().unwrap();
        if !m.contains_key(time.name) {
            m.insert(time.name, InvocationTracking::new(time));
        } else {
            m.get_mut(time.name).unwrap().add_time(time);
        }
    }
}

impl fmt::Show for TimeDB {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ref m = self.times.lock().unwrap();
        for (name, res) in m.iter() {
            try!(writeln!(f, "{} => {}", name, res));
        }
        write!(f, "")
    }
}

pub struct TimeIt {
    start_time: u64,
    name: &'static str,
}

impl TimeIt {
    pub fn new(name: &'static str) -> TimeIt {
        TimeIt {
            start_time: precise_time_ns(),
            name: name,
        }
    }
}

impl Drop for TimeIt {
    fn drop(&mut self) {
        time_db().add_time(self);
    }
}

pub struct TimeFileSave {
    file_name: &'static str,
}

impl Drop for TimeFileSave {
    fn drop(&mut self) {
        match File::create(&Path::new(self.file_name)) {
            Err(_) => {}
            Ok(mut f) => {
                let m1 : TimeDB = time_db();
                let _ = write!(&mut f, "{}", m1);
            }
        };
    }
}

impl TimeFileSave {
    pub fn new(file_name: &'static str) -> TimeFileSave {
        TimeFileSave {
            file_name: file_name,
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use TimeIt;
    use time_db;
    use TimeFileSave;

    #[test]
    fn test_times() {
        {
            time_3();
        }
        {
            TimeFileSave::new("test_result.txt");
        }
        let td = time_db();
        let m = td.times.lock().unwrap();
        assert_eq!(m.get("time_1").unwrap().count, 2);
        assert_eq!(m.get("time_3").unwrap().count, 1);
    }

    fn time_1() -> u64{
        TimeIt::new("time_1");
        let a = 3u64;
        return a * 3;
    }

    fn time_3() {
        TimeIt::new("time_3");
        time_1();
        time_1();
    }
}
<commit_msg>Fix for latest rust<commit_after>extern crate time;

use std::fmt;
use time::precise_time_ns;
use std::io::fs::File;
use std::mem;
use std::rt;
use std::sync::Arc;
use std::sync::Mutex;
use std::collections::HashMap;

#[derive(Clone)]
struct TimeDB {
    times: Arc<Mutex<HashMap<&'static str, InvocationTracking>>>,
}

fn time_db() -> TimeDB {
    use std::sync::{Once, ONCE_INIT};
    static mut TIMEDB : *const TimeDB = 0 as *const TimeDB;
    static mut ONCE: Once = ONCE_INIT;
    unsafe {
        ONCE.call_once(|| {
            let timedb = TimeDB {
                times: Arc::new(Mutex::new(HashMap::new())),
            };
            TIMEDB = mem::transmute(Box::new(timedb));

            // Make sure to free it at exit
            rt::at_exit(|| {
                mem::transmute::<_, Box<TimeDB>>(TIMEDB);
                TIMEDB = 0 as *const _;
            });
        });
        (*TIMEDB).clone()
    }
}

#[derive(Copy)]
struct InvocationTracking {
    count: u64,
    total_time: u64,
}

impl fmt::Show for InvocationTracking {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let avg_time = match self.count == 0 {
            true => 0.0f64,
            false => self.total_time as f64 / self.count as f64,
        };
        write!(f, "{} | {} ns/call", self.count, avg_time)
    }
}

impl InvocationTracking {
    fn new(t: &TimeIt) -> InvocationTracking {
        let mut i = InvocationTracking {
            count: 0,
            total_time: 0,
        };
        i.add_time(t);
        return i;
    }
    fn add_time(&mut self, t: &TimeIt) {
        let dur = precise_time_ns() - t.start_time;
        self.count += 1;
        self.total_time += dur;
    }
}

impl TimeDB {
    fn add_time(&mut self, time: &TimeIt) {
        let ref mut m = self.times.lock().unwrap();
        if !m.contains_key(time.name) {
            m.insert(time.name, InvocationTracking::new(time));
        } else {
            m.get_mut(time.name).unwrap().add_time(time);
        }
    }
}

impl fmt::Show for TimeDB {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let ref m = self.times.lock().unwrap();
        for (name, res) in m.iter() {
            try!(writeln!(f, "{} => {:?}", name, res));
        }
        write!(f, "")
    }
}

pub struct TimeIt {
    start_time: u64,
    name: &'static str,
}

impl TimeIt {
    pub fn new(name: &'static str) -> TimeIt {
        TimeIt {
            start_time: precise_time_ns(),
            name: name,
        }
    }
}

impl Drop for TimeIt {
    fn drop(&mut self) {
        time_db().add_time(self);
    }
}

pub struct TimeFileSave {
    file_name: &'static str,
}

impl Drop for TimeFileSave {
    fn drop(&mut self) {
        match File::create(&Path::new(self.file_name)) {
            Err(_) => {}
            Ok(mut f) => {
                let m1 : TimeDB = time_db();
                let _ = write!(&mut f, "{:?}", m1);
            }
        };
    }
}

impl TimeFileSave {
    pub fn new(file_name: &'static str) -> TimeFileSave {
        TimeFileSave {
            file_name: file_name,
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use TimeIt;
    use time_db;
    use TimeFileSave;

    #[test]
    fn test_times() {
        {
            time_3();
        }
        {
            TimeFileSave::new("test_result.txt");
        }
        let td = time_db();
        let m = td.times.lock().unwrap();
        assert_eq!(m.get("time_1").unwrap().count, 2);
        assert_eq!(m.get("time_3").unwrap().count, 1);
    }

    fn time_1() -> u64{
        TimeIt::new("time_1");
        let a = 3u64;
        return a * 3;
    }

    fn time_3() {
        TimeIt::new("time_3");
        time_1();
        time_1();
    }
}
<|endoftext|>


<commit_before>#![feature(trace_macros)]
#![feature(log_syntax)]

extern crate num;
extern crate rand;
extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
extern crate linked_hash_map;

pub mod nn;
use rutorch::*;
use std::ops::{Index, IndexMut};
//use std::convert::From;
use std::cmp::max;
use std::slice;

trait Storage {
    fn new() -> Self;
    fn sized(len: isize) -> Self;
}

pub struct FloatStorage {
    t: *mut THFloatStorage,
}

impl Storage for FloatStorage {
    fn new() -> Self {
        unsafe { FloatStorage { t: THFloatStorage_new() } }
    }
    fn sized(size: isize) -> Self {
        unsafe { FloatStorage { t: THFloatStorage_newWithSize(size) } }
    }
}
// XXX annotate with lifetime for safety's sake
impl FloatStorage {
    fn into_slice(&self) -> &[f32] {
        unsafe { slice::from_raw_parts((*self.t).data, (*self.t).size as usize) }
    }
    fn into_slice_mut(&mut self) -> &mut [f32] {
        unsafe { slice::from_raw_parts_mut((*self.t).data, (*self.t).size as usize) }
    }
    pub fn iter(&self) -> slice::Iter<f32> {
        self.into_slice().iter()
    }
    pub fn iter_mut(&mut self) -> slice::IterMut<f32> {
        self.into_slice_mut().iter_mut()
    }
}

impl Index<isize> for FloatStorage {
    type Output = f32;

    fn index(&self, idx: isize) -> &f32 {
        unsafe { &*(*self.t).data.offset(idx) }
    }
}

impl IndexMut<isize> for FloatStorage {
    fn index_mut(&mut self, idx: isize) -> &mut f32 {
        unsafe { &mut *(*self.t).data.offset(idx) }
    }
}

//fn from(args: &ArgsArray<T>) -> Self;

trait Tensor<'a> {
    fn new() -> Self;
    fn sized(size: &'a [isize]) -> Self;
    fn randn(dims: &'a [isize]) -> Self;
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

pub struct Parameter {}

impl<'a> Tensor<'a> for FloatTensor {
    fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }

    fn sized(dims: &'a [isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::sized(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    fn randn(dims: &'a [isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::sized(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &f32 {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut f32 {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}

/*
    def __init__(self):
        self._backend = thnn_backend
        self._parameters = OrderedDict()
        self._buffers = OrderedDict()
        self._backward_hooks = OrderedDict()
        self._forward_hooks = OrderedDict()
        self._modules = OrderedDict()
        self.training = True
*/

/*
impl fmt::Display for FloatTensor {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match (*self.t).size
		write!(f, "[torchrs.FloatTensor of size ]")
	}
}
*/
#[cfg(test)]
mod tests {
    use super::*;
    use nn::*;

#[derive(ModParse)]

pub struct MyModSmallA<'a> {
	delegate: Module<'a>,
}

impl <'a>MyModSmallA<'a> {
	pub fn new() -> Self {
		let mut t = MyModSmallA {delegate: Module::new()};
		t.init_module();
		t
	}
}

#[derive(ModParse)]
pub struct MyModBig<'a> {
	delegate: Module<'a>,
	#[module]
	a: Linear<'a> ,
	#[module]
	b: MyModSmallA<'a>
}

impl <'a>ModIntf<'a> for MyModBig<'a> {
	fn delegate(&mut self) -> &mut Module<'a> {
				&mut self.delegate

	}
	fn forward(&mut self /* Tensor */ ) /* -> Tensor */{}
}
impl <'a>ModIntf<'a> for MyModSmallA<'a> {
	fn delegate(&mut self) -> &mut Module<'a> {
				&mut self.delegate

	}
	fn forward(&mut self /* Tensor */ ) /* -> Tensor */{}
}
impl <'a> MyModBig<'a> {
	pub fn new() -> MyModBig<'a>  {
		let mut t = MyModBig {delegate: Module::new(),
			a: Linear::new(), b: MyModSmallA::new()} ;
		t.init_module();
		t
	}
}

    #[test]
    fn it_works() {
    	let x = MyModBig::new();
    }
}
<commit_msg>make Tensor usable as a trait object<commit_after>#![feature(trace_macros)]
#![feature(log_syntax)]

extern crate num;
extern crate rand;
extern crate rutorch;
#[macro_use]
extern crate modparse_derive;
extern crate linked_hash_map;

pub mod nn;
use rutorch::*;
use std::ops::{Index, IndexMut};
//use std::convert::From;
use std::cmp::max;
use std::slice;

trait Storage {
    fn new() -> Self;
    fn sized(len: isize) -> Self;
}

pub struct FloatStorage {
    t: *mut THFloatStorage,
}

impl Storage for FloatStorage {
    fn new() -> Self {
        unsafe { FloatStorage { t: THFloatStorage_new() } }
    }
    fn sized(size: isize) -> Self {
        unsafe { FloatStorage { t: THFloatStorage_newWithSize(size) } }
    }
}
// XXX annotate with lifetime for safety's sake
impl FloatStorage {
    fn into_slice(&self) -> &[f32] {
        unsafe { slice::from_raw_parts((*self.t).data, (*self.t).size as usize) }
    }
    fn into_slice_mut(&mut self) -> &mut [f32] {
        unsafe { slice::from_raw_parts_mut((*self.t).data, (*self.t).size as usize) }
    }
    pub fn iter(&self) -> slice::Iter<f32> {
        self.into_slice().iter()
    }
    pub fn iter_mut(&mut self) -> slice::IterMut<f32> {
        self.into_slice_mut().iter_mut()
    }
}

impl Index<isize> for FloatStorage {
    type Output = f32;

    fn index(&self, idx: isize) -> &f32 {
        unsafe { &*(*self.t).data.offset(idx) }
    }
}

impl IndexMut<isize> for FloatStorage {
    fn index_mut(&mut self, idx: isize) -> &mut f32 {
        unsafe { &mut *(*self.t).data.offset(idx) }
    }
}

//fn from(args: &ArgsArray<T>) -> Self;

trait Tensor {
	 fn _dummy(&self);
}

pub struct FloatTensor {
    t: *mut THFloatTensor,
    storage: FloatStorage,
    dims: Vec<isize>,
}

pub struct Parameter {
	data: Tensor,
}

impl FloatTensor {
    fn new() -> Self {
        unsafe {
            FloatTensor {
                t: THFloatTensor_new(),
                storage: FloatStorage::new(),
                dims: Vec::new(),
            }
        }
    }

    fn sized(dims: & [isize]) -> Self {
        let size = dims.iter().product();
        let storage = FloatStorage::sized(size);
        let strides = vec![1; dims.len()];
        let mut t = THFloatTensor {
            size: dims.clone().as_ptr() as *mut ::std::os::raw::c_long,
            stride: strides.as_ptr() as *mut ::std::os::raw::c_long,
            nDimension: dims.len() as i32,
            storage: storage.t,
            storageOffset: 0,
            refcount: 1,
            flag: TH_TENSOR_REFCOUNTED as i8,
        };
        FloatTensor {
            t: &mut t,
            storage: storage,
            dims: Vec::from(dims),
        }
    }
    fn randn(dims: & [isize]) -> Self {
        /* XXX */
        let mut t = FloatTensor::sized(dims);
        for x in t.storage.iter_mut() {
            *x = rand::random::<f32>()
        }
        t
    }
}

impl<'a> Index<&'a [isize]> for FloatTensor {
    type Output = f32;

    fn index(&self, idx: &'a [isize]) -> &f32 {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &self.storage[index]
    }
}

impl<'a> IndexMut<&'a [isize]> for FloatTensor {
    fn index_mut(&mut self, idx: &'a [isize]) -> &mut f32 {
        let mut index: isize = 0;
        let lastidx = max(0, idx.len() as isize - 1) as usize;
        if idx.len() != self.dims.len() {
            panic!("bad dimlen")
        }
        for i in 0..lastidx {
            if idx[i] >= self.dims[i] {
                panic!("bad dimlen")
            }
            index += idx[i] * self.dims[i]
        }
        if idx[lastidx] >= self.dims[lastidx] {
            panic!("bad dimlen")
        }
        index += idx[lastidx];
        &mut self.storage[index]
    }
}

/*
    def __init__(self):
        self._backend = thnn_backend
        self._parameters = OrderedDict()
        self._buffers = OrderedDict()
        self._backward_hooks = OrderedDict()
        self._forward_hooks = OrderedDict()
        self._modules = OrderedDict()
        self.training = True
*/

/*
impl fmt::Display for FloatTensor {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match (*self.t).size
		write!(f, "[torchrs.FloatTensor of size ]")
	}
}
*/
#[cfg(test)]
mod tests {
    use super::*;
    use nn::*;

#[derive(ModParse)]

pub struct MyModSmallA<'a> {
	delegate: Module<'a>,
}

impl <'a>MyModSmallA<'a> {
	pub fn new() -> Self {
		let mut t = MyModSmallA {delegate: Module::new()};
		t.init_module();
		t
	}
}

#[derive(ModParse)]
pub struct MyModBig<'a> {
	delegate: Module<'a>,
	#[module]
	a: Linear<'a> ,
	#[module]
	b: MyModSmallA<'a>
}

impl <'a>ModIntf<'a> for MyModBig<'a> {
	fn delegate(&mut self) -> &mut Module<'a> {
				&mut self.delegate

	}
	fn forward(&mut self /* Tensor */ ) /* -> Tensor */{}
}
impl <'a>ModIntf<'a> for MyModSmallA<'a> {
	fn delegate(&mut self) -> &mut Module<'a> {
				&mut self.delegate

	}
	fn forward(&mut self /* Tensor */ ) /* -> Tensor */{}
}
impl <'a> MyModBig<'a> {
	pub fn new() -> MyModBig<'a>  {
		let mut t = MyModBig {delegate: Module::new(),
			a: Linear::new(), b: MyModSmallA::new()} ;
		t.init_module();
		t
	}
}

    #[test]
    fn it_works() {
    	let x = MyModBig::new();
    }
}
<|endoftext|>