<commit_before>//! [aurelius](https://github.com/euclio/aurelius) is a complete solution for rendering and
//! previewing markdown.
//!
//! This crate provides a server that can render and update an HTML preview of markdown without a
//! client-side refresh. The server listens for both WebSocket and HTTP connections on arbitrary
//! ports. Upon receiving an HTTP request, the server renders a page containing a markdown preview.
//! Client-side JavaScript then initiates a WebSocket connection which allows the server to push
//! changes to the client.
//!
//! This crate was designed to power [vim-markdown-composer], a markdown preview plugin for
//! [Neovim](http://neovim.io), but it may be used to implement similar plugins for any editor.
//! See [vim-markdown-composer] for a usage example.
//!
//! aurelius follows stable Rust. However, the API currently unstable and may change without
//! warning.
//!
//! # Acknowledgments
//! This crate is inspired by suan's
//! [instant-markdown-d](https://github.com/suan/instant-markdown-d).
//!
//! # Why the name?
//! "Aurelius" is a Roman *gens* (family name) shared by many famous Romans, including emperor
//! Marcus Aurelius, one of the "Five Good Emperors." The gens itself originates from the Latin
//! *aureus* meaning "golden." Also, tell me that "Markdown Aurelius" isn't a great pun.
//!
//! [Aurelia (gens) on Wikipedia](https://en.wikipedia.org/wiki/Aurelia_(gens)).
//!
//! [vim-markdown-composer]: https://github.com/euclio/vim-markdown-composer

extern crate hoedown;
extern crate porthole;
extern crate url;
extern crate uuid;
extern crate websocket as websockets;

#[macro_use] extern crate log;
#[macro_use] extern crate nickel;

pub mod browser;
pub mod markdown;

mod http;
mod websocket;

use http::Server as HttpServer;
use websocket::Server as WebSocketServer;

use std::sync::{Arc, RwLock};
use std::thread;

/// Representation of the running markdown server.
pub struct ServerHandle {
    server: Server,
}

impl ServerHandle {
    /// Returns the port that the WebSocket server is listening on.
    pub fn websocket_port(&self) -> u16 {
        let ws_server_lock = self.server.websocket_server.clone();
        let ws_server = ws_server_lock.read().unwrap();
        ws_server.port
    }

    /// Returns the port that the HTTP server is listening on.
    pub fn http_port(&self) -> u16 {
        let http_server_lock = self.server.http_server.clone();
        let http_server = http_server_lock.read().unwrap();
        http_server.port
    }

    /// Send a markdown string to be rendered by the server.
    ///
    /// The HTML will then be sent to all websocket connections.
    pub fn send_markdown(&self, markdown: String) {
        let ws_server_lock = self.server.websocket_server.clone();
        let ws_server = ws_server_lock.read().unwrap();
        ws_server.notify(markdown::to_html(&markdown));
    }
}

/// The `Server` type constructs a new markdown server.
///
/// The server will listen for HTTP and WebSocket connections on arbitrary ports.
pub struct Server {
    websocket_port: u16,
    http_server: Arc<RwLock<HttpServer>>,
    websocket_server: Arc<RwLock<WebSocketServer>>,
    initial_markdown: Option<String>,
    highlight_theme: Option<String>,
}

impl Server {
    /// Creates a new markdown preview server.
    ///
    /// Builder methods are provided to configure the server before starting it.
    pub fn new() -> Server {
        let websocket_port = porthole::open().unwrap();
        let websocket_server = WebSocketServer::new(websocket_port);

        let http_port = porthole::open().unwrap();
        let http_server = HttpServer::new(http_port);

        Server {
            websocket_port: websocket_port,
            http_server: Arc::new(RwLock::new(http_server)),
            websocket_server: Arc::new(RwLock::new(websocket_server)),
            initial_markdown: None,
            highlight_theme: None,
        }
    }

    /// Sets the markdown that the server should display when the first connection is received.
    pub fn initial_markdown(&mut self, markdown: &str) -> &mut Server {
        self.initial_markdown = Some(markdown.to_string());
        self
    }

    /// Sets the theme that should be used for syntax highlighting.
    ///
    /// Syntax highlighting is provided by [highlight.js](https://highlightjs.org/). All themes
    /// supported by highlight.js are supported.
    pub fn highlight_theme(&mut self, theme: &str) -> &mut Server {
        self.highlight_theme = Some(theme.to_string());
        self
    }

    /// Starts the server, returning a `ServerHandle` to communicate with it.
    pub fn start(self) -> ServerHandle {
        let websocket_server = self.websocket_server.clone();

        // Start websocket server
        thread::spawn(move || {
            let server = websocket_server.read().unwrap();
            server.start();
        });

        let http_server = self.http_server.clone();
        let websocket_port = self.websocket_port;

        // Start http server
        let initial_markdown = match self.initial_markdown {
            Some(ref markdown) => markdown.clone(),
            None => "".to_string()
        };
        let highlight_theme = match self.highlight_theme {
            Some(ref theme) => theme.clone(),
            None => "github".to_string()
        };
        thread::spawn(move || {
            let server = http_server.read().unwrap();
            debug!("Starting http_server");
            server.start(websocket_port, initial_markdown, highlight_theme);
        });

        ServerHandle { server: self }
    }
}
<commit_msg>use borrowed String for sending markdown<commit_after>//! [aurelius](https://github.com/euclio/aurelius) is a complete solution for rendering and
//! previewing markdown.
//!
//! This crate provides a server that can render and update an HTML preview of markdown without a
//! client-side refresh. The server listens for both WebSocket and HTTP connections on arbitrary
//! ports. Upon receiving an HTTP request, the server renders a page containing a markdown preview.
//! Client-side JavaScript then initiates a WebSocket connection which allows the server to push
//! changes to the client.
//!
//! This crate was designed to power [vim-markdown-composer], a markdown preview plugin for
//! [Neovim](http://neovim.io), but it may be used to implement similar plugins for any editor.
//! See [vim-markdown-composer] for a usage example.
//!
//! aurelius follows stable Rust. However, the API currently unstable and may change without
//! warning.
//!
//! # Acknowledgments
//! This crate is inspired by suan's
//! [instant-markdown-d](https://github.com/suan/instant-markdown-d).
//!
//! # Why the name?
//! "Aurelius" is a Roman *gens* (family name) shared by many famous Romans, including emperor
//! Marcus Aurelius, one of the "Five Good Emperors." The gens itself originates from the Latin
//! *aureus* meaning "golden." Also, tell me that "Markdown Aurelius" isn't a great pun.
//!
//! [Aurelia (gens) on Wikipedia](https://en.wikipedia.org/wiki/Aurelia_(gens)).
//!
//! [vim-markdown-composer]: https://github.com/euclio/vim-markdown-composer

extern crate hoedown;
extern crate porthole;
extern crate url;
extern crate uuid;
extern crate websocket as websockets;

#[macro_use] extern crate log;
#[macro_use] extern crate nickel;

pub mod browser;
pub mod markdown;

mod http;
mod websocket;

use http::Server as HttpServer;
use websocket::Server as WebSocketServer;

use std::sync::{Arc, RwLock};
use std::thread;

/// Representation of the running markdown server.
pub struct ServerHandle {
    server: Server,
}

impl ServerHandle {
    /// Returns the port that the WebSocket server is listening on.
    pub fn websocket_port(&self) -> u16 {
        let ws_server_lock = self.server.websocket_server.clone();
        let ws_server = ws_server_lock.read().unwrap();
        ws_server.port
    }

    /// Returns the port that the HTTP server is listening on.
    pub fn http_port(&self) -> u16 {
        let http_server_lock = self.server.http_server.clone();
        let http_server = http_server_lock.read().unwrap();
        http_server.port
    }

    /// Send a markdown string to be rendered by the server.
    ///
    /// The HTML will then be sent to all websocket connections.
    pub fn send_markdown(&self, markdown: &str) {
        let ws_server_lock = self.server.websocket_server.clone();
        let ws_server = ws_server_lock.read().unwrap();
        ws_server.notify(markdown::to_html(markdown));
    }
}

/// The `Server` type constructs a new markdown preview server.
///
/// The server will listen for HTTP and WebSocket connections on arbitrary ports.
pub struct Server {
    websocket_port: u16,
    http_server: Arc<RwLock<HttpServer>>,
    websocket_server: Arc<RwLock<WebSocketServer>>,
    initial_markdown: Option<String>,
    highlight_theme: Option<String>,
}

impl Server {
    /// Creates a new markdown preview server.
    ///
    /// Builder methods are provided to configure the server before starting it.
    pub fn new() -> Server {
        let websocket_port = porthole::open().unwrap();
        let websocket_server = WebSocketServer::new(websocket_port);

        let http_port = porthole::open().unwrap();
        let http_server = HttpServer::new(http_port);

        Server {
            websocket_port: websocket_port,
            http_server: Arc::new(RwLock::new(http_server)),
            websocket_server: Arc::new(RwLock::new(websocket_server)),
            initial_markdown: None,
            highlight_theme: None,
        }
    }

    /// Sets the markdown that the server should display when the first connection is received.
    pub fn initial_markdown(&mut self, markdown: &str) -> &mut Server {
        self.initial_markdown = Some(markdown.to_string());
        self
    }

    /// Sets the theme that should be used for syntax highlighting.
    ///
    /// Syntax highlighting is provided by [highlight.js](https://highlightjs.org/). All themes
    /// supported by highlight.js are supported.
    pub fn highlight_theme(&mut self, theme: &str) -> &mut Server {
        self.highlight_theme = Some(theme.to_string());
        self
    }

    /// Starts the server, returning a `ServerHandle` to communicate with it.
    pub fn start(self) -> ServerHandle {
        let websocket_server = self.websocket_server.clone();

        // Start websocket server
        thread::spawn(move || {
            let server = websocket_server.read().unwrap();
            server.start();
        });

        let http_server = self.http_server.clone();
        let websocket_port = self.websocket_port;

        // Start http server
        let initial_markdown = match self.initial_markdown {
            Some(ref markdown) => markdown.clone(),
            None => "".to_string()
        };
        let highlight_theme = match self.highlight_theme {
            Some(ref theme) => theme.clone(),
            None => "github".to_string()
        };
        thread::spawn(move || {
            let server = http_server.read().unwrap();
            debug!("Starting http_server");
            server.start(websocket_port, initial_markdown, highlight_theme);
        });

        ServerHandle { server: self }
    }
}
<|endoftext|>


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

extern crate rustc;
extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::Registry;
use syntax::ast::Ident;
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult};
use syntax::parse::token::{DelimToken, Token};

mod parser_any_macro;

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

fn interpolate_idents<'a>(cx: &'a mut ExtCtxt,
              _: Span,
              tts: &[TokenTree]) -> Box<MacResult + 'a> {
    fn concat_idents(tts: TokenStream, delim: DelimToken) -> Option<TokenTree> {
        match delim {
            DelimToken::Bracket => {
                let mut new_ident = String::new();
                let mut new_span: Option<Span> = None;

                for token in tts.trees() {
                    match token {
                        TokenTree::Token(ref span, Token::Ident(ref ident)) => {
                            match new_span {
                                Some(ref mut s) => { *s = s.with_hi(span.hi()); },
                                None => { new_span = Some(span.clone()); },
                            }
                            new_ident.push_str(&ident.name.as_str());
                        },
                        TokenTree::Token(ref span, Token::Underscore) => {
                            match new_span {
                                Some(ref mut s) => { *s = s.with_hi(span.hi()); },
                                None => { new_span = Some(span.clone()); },
                            }
                            new_ident.push_str("_");
                        },
                        _ => return None,
                    }
                }

                match new_span {
                    Some(s) => {
                        let new_ident = Ident::from_str(&new_ident[..]);
                        Some(TokenTree::Token(s, Token::Ident(new_ident)))
                    },
                    None => None
                }
            },
            _ => None,
        }
    }

    fn map_tts(tts: TokenStream) -> TokenStream {
        // Ignore brackets preceded by a pound symbol (or a pound and an exclamation mark), so as
        // to allow attributes.
        let mut is_prev_pound = false;

        tts.trees().map(|t| {
            if is_prev_pound {
                is_prev_pound = false;
                return t.clone();
            }

            if let TokenTree::Token(_, Token::Pound) = t {
                is_prev_pound = true;
            }

            match t {
                TokenTree::Delimited(s, d) => {
                    match concat_idents(d.tts.clone().into(), d.delim) {
                        Some(t) => t,
                        None => {
                            TokenTree::Delimited(s, syntax::tokenstream::Delimited {
                                delim: d.delim,
                                tts: map_tts(d.tts.into()).into(),
                            })
                        },
                    }
                },
                TokenTree::Token(..) => t.clone(),
            }
        }).collect()
    }

    let tts: TokenStream = map_tts(tts.iter().cloned().collect());
    let tts: Vec<TokenTree> = tts.trees().collect();
    let parser = cx.new_parser_from_tts(&*tts);
    Box::new(parser_any_macro::ParserAnyMacro::new(parser)) as Box<MacResult>
}
<commit_msg>Handle underscore as identifier<commit_after>#![feature(plugin_registrar, rustc_private)]

extern crate rustc;
extern crate rustc_plugin;
extern crate syntax;

use rustc_plugin::Registry;
use syntax::ast::Ident;
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, MacResult};
use syntax::parse::token::{DelimToken, Token};

mod parser_any_macro;

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

fn interpolate_idents<'a>(cx: &'a mut ExtCtxt,
              _: Span,
              tts: &[TokenTree]) -> Box<MacResult + 'a> {
    fn concat_idents(tts: TokenStream, delim: DelimToken) -> Option<TokenTree> {
        match delim {
            DelimToken::Bracket => {
                let mut new_ident = String::new();
                let mut new_span: Option<Span> = None;

                for token in tts.trees() {
                    match token {
                        TokenTree::Token(ref span, Token::Ident(ref ident)) => {
                            match new_span {
                                Some(ref mut s) => { *s = s.with_hi(span.hi()); },
                                None => { new_span = Some(span.clone()); },
                            }
                            new_ident.push_str(&ident.name.as_str());
                        },
                        _ => return None,
                    }
                }

                match new_span {
                    Some(s) => {
                        let new_ident = Ident::from_str(&new_ident[..]);
                        Some(TokenTree::Token(s, Token::Ident(new_ident)))
                    },
                    None => None
                }
            },
            _ => None,
        }
    }

    fn map_tts(tts: TokenStream) -> TokenStream {
        // Ignore brackets preceded by a pound symbol (or a pound and an exclamation mark), so as
        // to allow attributes.
        let mut is_prev_pound = false;

        tts.trees().map(|t| {
            if is_prev_pound {
                is_prev_pound = false;
                return t.clone();
            }

            if let TokenTree::Token(_, Token::Pound) = t {
                is_prev_pound = true;
            }

            match t {
                TokenTree::Delimited(s, d) => {
                    match concat_idents(d.tts.clone().into(), d.delim) {
                        Some(t) => t,
                        None => {
                            TokenTree::Delimited(s, syntax::tokenstream::Delimited {
                                delim: d.delim,
                                tts: map_tts(d.tts.into()).into(),
                            })
                        },
                    }
                },
                TokenTree::Token(..) => t.clone(),
            }
        }).collect()
    }

    let tts: TokenStream = map_tts(tts.iter().cloned().collect());
    let tts: Vec<TokenTree> = tts.trees().collect();
    let parser = cx.new_parser_from_tts(&*tts);
    Box::new(parser_any_macro::ParserAnyMacro::new(parser)) as Box<MacResult>
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Add comment<commit_after>//! Generic worst-case-linear-time sorting and partitioning algorithms based on [discrim](http://www.diku.dk/hjemmesider/ansatte/henglein/papers/henglein2011a.pdf)[inators](http://www.diku.dk/hjemmesider/ansatte/henglein/papers/henglein2011c.pdf).  Partially a port of the [Haskell library of the same name](https://github.com/ekmett/discrimination).

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>//! # cronjob
//!
//! The `cronjob` library lets you create cronjobs for your methods.
//!
//! ## Getting started
//!
//! ``` no_run
//! extern crate cronjob;
//! use cronjob::CronJob;
//!
//! fn main() {
//!     // Create the `CronJob` object.
//!     let mut cron = CronJob::new("Test Cron", on_cron);
//!     // Start the cronjob.
//!     cron.start_job();
//! }
//!
//! // Our cronjob handler.
//! fn on_cron(name: &str) {
//!     println!("{}: It's time!", name);
//! }
//! ```
//!
//! ## schedule
//! The `cronjob` allows to optionally add schedule parameters.
//!
//! ``` no_run
//! extern crate cronjob;
//! use cronjob::CronJob;
//!
//! fn main() {
//!     // Create the `CronJob` object.
//!     let mut cron = CronJob::new("Test Cron", on_cron);
//!     // Set seconds.
//!     cron.seconds("0");
//!     // Set minutes.
//!     cron.minutes(0);
//!     // Start the cronjob.
//!     cron.start_job();
//! }
//!
//! // Our cronjob handler.
//! fn on_cron(name: &str) {
//!     println!("{}: It's time!", name);
//! }
//! ```
//!
//! ## Threaded
//! ``` no_run
//! extern crate cronjob;
//! use cronjob::CronJob;
//!
//! fn main() {
//!     // Create the `CronJob` object.
//!     let mut cron = CronJob::new("Test Cron Threaded", on_cron);
//!     // start the cronjob.
//!     CronJob::start_job_threaded(cron);
//! }
//!
//! // Our cronjob handler.
//! fn on_cron(name: &str) {
//!     println!("{}: It's time!", name);
//! }
//! ```

extern crate cron;
extern crate chrono;

pub use cronjob::CronJob;

use command::Command;
use chrono::FixedOffset;

mod cronjob;
mod command;

const HOUR: i32 = 3600;

/// Use this to automaticly get an `FixedOffset` for the `CronJob` object
pub fn get_timezone_offset(hours: i32) -> FixedOffset {
    if hours > 0 {
        FixedOffset::east(HOUR * hours)
    } else {
        FixedOffset::west(HOUR * (hours * -1))
    }
}

/// Implementation of `Command` for your methods to be used by the `CronJob` object
impl<T: Sync + Send + 'static + FnMut(&str)> Command for T {
    fn execute(&mut self, name: &str) {
        self(name);
    }
}
<commit_msg>removed old method to get timezone<commit_after>//! # cronjob
//!
//! The `cronjob` library lets you create cronjobs for your methods.
//!
//! ## Getting started
//!
//! ``` no_run
//! extern crate cronjob;
//! use cronjob::CronJob;
//!
//! fn main() {
//!     // Create the `CronJob` object.
//!     let mut cron = CronJob::new("Test Cron", on_cron);
//!     // Start the cronjob.
//!     cron.start_job();
//! }
//!
//! // Our cronjob handler.
//! fn on_cron(name: &str) {
//!     println!("{}: It's time!", name);
//! }
//! ```
//!
//! ## schedule
//! The `cronjob` allows to optionally add schedule parameters.
//!
//! ``` no_run
//! extern crate cronjob;
//! use cronjob::CronJob;
//!
//! fn main() {
//!     // Create the `CronJob` object.
//!     let mut cron = CronJob::new("Test Cron", on_cron);
//!     // Set seconds.
//!     cron.seconds("0");
//!     // Set minutes.
//!     cron.minutes(0);
//!     // Start the cronjob.
//!     cron.start_job();
//! }
//!
//! // Our cronjob handler.
//! fn on_cron(name: &str) {
//!     println!("{}: It's time!", name);
//! }
//! ```
//!
//! ## Threaded
//! ``` no_run
//! extern crate cronjob;
//! use cronjob::CronJob;
//!
//! fn main() {
//!     // Create the `CronJob` object.
//!     let mut cron = CronJob::new("Test Cron Threaded", on_cron);
//!     // start the cronjob.
//!     CronJob::start_job_threaded(cron);
//! }
//!
//! // Our cronjob handler.
//! fn on_cron(name: &str) {
//!     println!("{}: It's time!", name);
//! }
//! ```

extern crate cron;
extern crate chrono;

pub use cronjob::CronJob;

use command::Command;

mod cronjob;
mod command;

/// Implementation of `Command` for your methods to be used by the `CronJob` object
impl<T: Sync + Send + 'static + FnMut(&str)> Command for T {
    fn execute(&mut self, name: &str) {
        self(name);
    }
}
<|endoftext|>


<commit_before>extern crate fixedbitset;
extern crate rand;

use fixedbitset::FixedBitSet;
use rand::Rng;
use std::collections::BTreeMap;
use std::fmt::Debug;

pub trait NodeType: Clone + Debug + Send + Sized {
    /// If the node allows incoming connections
    fn accept_incoming_links(&self) -> bool;

    /// If the node allows outgoing connections
    fn accept_outgoing_links(&self) -> bool;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
/// New type wrapping a node index.
pub struct NodeIndex(usize);

impl NodeIndex {
    pub fn new(idx: usize) -> NodeIndex {
        NodeIndex(idx)
    }

    pub fn index(&self) -> usize {
        self.0
    }
}

#[derive(Clone, Debug)]
pub struct Link<W: Clone + Debug> {
    pub node_idx: NodeIndex,
    pub weight: W,
}

#[derive(Clone, Debug)]
pub struct Node<NT: NodeType, N: Clone + Debug, W: Clone + Debug> {
    pub node_type: NT,
    pub node_data: N,
    pub input_links: Vec<Link<W>>,
    pub output_links: Vec<Link<W>>,
}

struct CycleDetector<'a, NT: NodeType + 'a, N: Clone + Debug + 'a, W: Clone + Debug + 'a> {
    nodes: &'a [Node<NT, N, W>],
    nodes_to_visit: Vec<usize>,
    seen_nodes: FixedBitSet,
    dirty: bool,
}

impl<'a, NT: NodeType + 'a, N: Clone + Debug + 'a, W: Clone + Debug + 'a> CycleDetector<'a,
                                                                                NT,
                                                                                N,
                                                                                W>
    {
    fn new(network: &'a Network<NT, N, W>) -> CycleDetector<'a, NT, N, W> {
        CycleDetector {
            nodes: &network.nodes,
            nodes_to_visit: Vec::new(),
            seen_nodes: FixedBitSet::with_capacity(network.nodes.len()),
            dirty: false,
        }
    }

    // The algorithm used in `Network.link_would_cycle` and
    // `Network.find_random_unconnected_link_no_cycle`.  This is mostly extracted to avoid
    // repetetive memory allocations in `find_random_unconnected_link_no_cycle`.
    fn link_would_cycle(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        let path_from = target_node_idx.index();
        let path_to = source_node_idx.index();

        assert!(path_from != path_to);

        let nodes = self.nodes;
        let mut nodes_to_visit = &mut self.nodes_to_visit;
        let mut seen_nodes = &mut self.seen_nodes;

        if self.dirty {
            nodes_to_visit.clear();
            seen_nodes.clear();
        }
        self.dirty = true;

        // We start at the from the target_node and iterate all paths from there. If we hit the source node,
        // the addition of this link would lead towards a cycle. Otherwise not.
        nodes_to_visit.push(path_from);
        seen_nodes.insert(path_from);

        while let Some(visit_node) = nodes_to_visit.pop() {
            for out_link in &nodes[visit_node].output_links {
                let next_node = out_link.node_idx.index();
                if !seen_nodes.contains(next_node) {
                    if next_node == path_to {
                        // We found a path to `path_to`. We have found a cycle.
                        return true;
                    }

                    seen_nodes.insert(next_node);
                    nodes_to_visit.push(next_node)
                }
            }
        }

        // We haven't found a cycle.
        return false;
    }
}

#[derive(Clone, Debug)]
/// A directed, acylic network.
pub struct Network<NT: NodeType, N: Clone + Debug, W: Clone + Debug> {
    nodes: Vec<Node<NT, N, W>>,
}

impl<NT: NodeType, N: Clone + Debug, W: Clone + Debug> Network<NT, N, W> {
    pub fn new() -> Network<NT, N, W> {
        Network { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<NT, N, W>] {
        &self.nodes
    }

    pub fn add_node(&mut self, node_type: NT, node_data: N) -> NodeIndex {
        let idx = NodeIndex(self.nodes.len());
        self.nodes.push(Node {
            node_type: node_type,
            node_data: node_data,
            input_links: Vec::new(),
            output_links: Vec::new(),
        });
        return idx;
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(NodeIndex, NodeIndex)> {

        let n = self.nodes.len();

        let idx = &|i, j| i * n + j;

        let mut adj_matrix = FixedBitSet::with_capacity(n * n);

        // Build up a binary, undirected adjacency matrix of the graph.
        // Every unset bit in the adj_matrix will be a potential link.
        for (i, node) in self.nodes.iter().enumerate() {
            for link in node.output_links.iter() {
                let j = link.node_idx.index();
                adj_matrix.insert(idx(i, j));
                // include the link of reverse direction, because this would
                // create a cycle anyway.
                adj_matrix.insert(idx(j, i));
            }
        }

        let adj_matrix = adj_matrix; // make immutable

        // We now test all potential links of every node in the graph, if it would
        // introduce a cycle. For that, we shuffle the node indices (`node_order`).
        // in random order.
        let mut node_order: Vec<_> = (0..n).into_iter().collect();
        let mut edge_order: Vec<_> = (0..n).into_iter().collect();
        rng.shuffle(&mut node_order);

        let node_order = node_order; // make immutable

        let mut cycler = CycleDetector::new(self);
        for &i in &node_order {
            rng.shuffle(&mut edge_order);
            for &j in &edge_order {
                if i != j && !adj_matrix.contains(idx(i, j)) {
                    // The link (i, j) neither is reflexive, nor exists.
                    let ni = NodeIndex(i);
                    let nj = NodeIndex(j);
                    if self.valid_link(ni, nj).is_ok() && !cycler.link_would_cycle(ni, nj) {
                        // If the link is valid and does not create a cycle, we are done!
                        return Some((ni, nj));
                    }
                }
            }
        }

        return None;
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        if source_node_idx == target_node_idx {
            return true;
        }

        CycleDetector::new(self).link_would_cycle(source_node_idx, target_node_idx)
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_idx: NodeIndex,
                      target_node_idx: NodeIndex)
                      -> Result<(), &'static str> {
        if source_node_idx == target_node_idx {
            return Err("Loops are not allowed");
        }

        if !self.nodes[source_node_idx.index()].node_type.accept_outgoing_links() {
            return Err("Node does not allow outgoing links");
        }

        if !self.nodes[target_node_idx.index()].node_type.accept_incoming_links() {
            return Err("Node does not allow incoming links");
        }

        Ok(())
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex, weight: W) {
        if let Err(err) = self.valid_link(source_node_idx, target_node_idx) {
            panic!(err);
        }

        self.nodes[source_node_idx.index()].output_links.push(Link {
            node_idx: target_node_idx,
            weight: weight.clone(),
        });

        self.nodes[target_node_idx.index()].input_links.push(Link {
            node_idx: source_node_idx,
            weight: weight,
        });
    }
}

#[derive(Clone, Debug)]
pub struct NetworkMap<NKEY: Ord + Clone + Debug, NT: NodeType, N: Clone + Debug, W: Clone + Debug> {
    network: Network<NT, N, W>,
    node_map: BTreeMap<NKEY, NodeIndex>,
    node_map_rev: BTreeMap<NodeIndex, NKEY>,
}

impl<NKEY: Ord + Clone + Debug, NT: NodeType, N: Clone + Debug, W: Clone + Debug> NetworkMap<NKEY,
                                                                                NT,
                                                                                N,
                                                                                W>
    {
    pub fn new() -> NetworkMap<NKEY, NT, N, W> {
        NetworkMap {
            network: Network::new(),
            node_map: BTreeMap::new(),
            node_map_rev: BTreeMap::new(),
        }
    }

    pub fn nodes(&self) -> &[Node<NT, N, W>] {
        self.network.nodes()
    }

    /// Registers/creates a new node under the external key `node_key`.
    /// Panics if a node with `node_key` already exists.
    pub fn add_node(&mut self, node_key: NKEY, node_type: NT, node_data: N) {
        // XXX: Use node_map.entry()
        if self.node_map.contains_key(&node_key) {
            panic!("Duplicate node index");
        }
        let idx = self.network.add_node(node_type, node_data);
        self.node_map.insert(node_key.clone(), idx);
        self.node_map_rev.insert(idx, node_key);
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(&NKEY, &NKEY)> {
        match self.network.find_random_unconnected_link_no_cycle(rng) {
            Some((a, b)) => Some((&self.node_map_rev[&a], &self.node_map_rev[&b])),
            None => None,
        }
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_key: NKEY, target_node_key: NKEY) -> bool {
        self.network.link_would_cycle(self.node_map[&source_node_key],
                                      self.node_map[&target_node_key])
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_key: NKEY,
                      target_node_key: NKEY)
                      -> Result<(), &'static str> {
        self.network.valid_link(self.node_map[&source_node_key],
                                self.node_map[&target_node_key])
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_key: NKEY, target_node_key: NKEY, weight: W) {
        self.network.add_link(self.node_map[&source_node_key],
                              self.node_map[&target_node_key],
                              weight)
    }
}

#[cfg(test)]
mod tests {
    use rand;
    use super::{NodeType, Network};

    #[derive(Clone, Debug)]
    enum NodeT {
        Input,
        Hidden,
        Output,
    }

    impl NodeType for NodeT {
        fn accept_incoming_links(&self) -> bool {
            match *self {
                NodeT::Input => false,
                _ => true,
            }
        }
        fn accept_outgoing_links(&self) -> bool {
            match *self {
                NodeT::Output => false,
                _ => true,
            }
        }
    }

    #[test]
    fn test_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let h1 = g.add_node(NodeT::Hidden, ());
        let h2 = g.add_node(NodeT::Hidden, ());
        assert_eq!(true, g.valid_link(i1, i1).is_err());
        assert_eq!(true, g.valid_link(h1, h1).is_err());

        assert_eq!(true, g.valid_link(h1, i1).is_err());
        assert_eq!(Ok(()), g.valid_link(i1, h1));
        assert_eq!(Ok(()), g.valid_link(i1, h2));
        assert_eq!(Ok(()), g.valid_link(h1, h2));

        g.add_link(i1, h1, 0.0);
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(false, g.link_would_cycle(i1, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
        assert_eq!(true, g.link_would_cycle(i1, i1));
        assert_eq!(false, g.link_would_cycle(h1, h2));
        assert_eq!(false, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(h2, i1));

        g.add_link(h1, h2, 0.0);
        assert_eq!(true, g.link_would_cycle(h2, i1));
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(true, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
    }

    #[test]
    fn test_find_random_unconnected_link_no_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input, ());
        let o1 = g.add_node(NodeT::Output, ());
        let o2 = g.add_node(NodeT::Output, ());

        let mut rng = rand::thread_rng();

        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        let l = link.unwrap();
        assert!((i1, o1) == l || (i1, o2) == l);

        g.add_link(i1, o2, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        assert_eq!((i1, o1), link.unwrap());

        g.add_link(i1, o1, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(false, link.is_some());
    }
}
<commit_msg>Unify NodeType and node_data. Introduce LinkWeight trait.<commit_after>extern crate fixedbitset;
extern crate rand;

use fixedbitset::FixedBitSet;
use rand::Rng;
use std::collections::BTreeMap;
use std::fmt::Debug;

pub trait NodeType: Clone + Debug + Send + Sized {
    /// If the node allows incoming connections
    fn accept_incoming_links(&self) -> bool;

    /// If the node allows outgoing connections
    fn accept_outgoing_links(&self) -> bool;
}

pub trait LinkWeight: Clone + Debug + Send + Sized {
}

impl LinkWeight for f64 {}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
/// New type wrapping a node index.
pub struct NodeIndex(usize);

impl NodeIndex {
    pub fn new(idx: usize) -> NodeIndex {
        NodeIndex(idx)
    }

    pub fn index(&self) -> usize {
        self.0
    }
}

#[derive(Clone, Debug)]
pub struct Link<L: LinkWeight> {
    pub node_idx: NodeIndex,
    pub weight: L,
}

#[derive(Clone, Debug)]
pub struct Node<N: NodeType, L: LinkWeight> {
    pub node_type: N,
    pub input_links: Vec<Link<L>>,
    pub output_links: Vec<Link<L>>,
}

struct CycleDetector<'a, N: NodeType + 'a, L: LinkWeight + 'a> {
    nodes: &'a [Node<N, L>],
    nodes_to_visit: Vec<usize>,
    seen_nodes: FixedBitSet,
    dirty: bool,
}

impl<'a, N: NodeType + 'a, L: LinkWeight + 'a> CycleDetector<'a, N, L> {
    fn new(network: &'a Network<N, L>) -> CycleDetector<'a, N, L> {
        CycleDetector {
            nodes: &network.nodes,
            nodes_to_visit: Vec::new(),
            seen_nodes: FixedBitSet::with_capacity(network.nodes.len()),
            dirty: false,
        }
    }

    // The algorithm used in `Network.link_would_cycle` and
    // `Network.find_random_unconnected_link_no_cycle`.  This is mostly extracted to avoid
    // repetetive memory allocations in `find_random_unconnected_link_no_cycle`.
    fn link_would_cycle(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        let path_from = target_node_idx.index();
        let path_to = source_node_idx.index();

        assert!(path_from != path_to);

        let nodes = self.nodes;
        let mut nodes_to_visit = &mut self.nodes_to_visit;
        let mut seen_nodes = &mut self.seen_nodes;

        if self.dirty {
            nodes_to_visit.clear();
            seen_nodes.clear();
        }
        self.dirty = true;

        // We start at the from the target_node and iterate all paths from there. If we hit the source node,
        // the addition of this link would lead towards a cycle. Otherwise not.
        nodes_to_visit.push(path_from);
        seen_nodes.insert(path_from);

        while let Some(visit_node) = nodes_to_visit.pop() {
            for out_link in &nodes[visit_node].output_links {
                let next_node = out_link.node_idx.index();
                if !seen_nodes.contains(next_node) {
                    if next_node == path_to {
                        // We found a path to `path_to`. We have found a cycle.
                        return true;
                    }

                    seen_nodes.insert(next_node);
                    nodes_to_visit.push(next_node)
                }
            }
        }

        // We haven't found a cycle.
        return false;
    }
}

#[derive(Clone, Debug)]
/// A directed, acylic network.
pub struct Network<N: NodeType, L: LinkWeight> {
    nodes: Vec<Node<N, L>>,
}

impl<N: NodeType, L: LinkWeight> Network<N, L> {
    pub fn new() -> Network<N, L> {
        Network { nodes: Vec::new() }
    }

    pub fn nodes(&self) -> &[Node<N, L>] {
        &self.nodes
    }

    pub fn add_node(&mut self, node_type: N) -> NodeIndex {
        let idx = NodeIndex(self.nodes.len());
        self.nodes.push(Node {
            node_type: node_type,
            input_links: Vec::new(),
            output_links: Vec::new(),
        });
        return idx;
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(NodeIndex, NodeIndex)> {

        let n = self.nodes.len();

        let idx = &|i, j| i * n + j;

        let mut adj_matrix = FixedBitSet::with_capacity(n * n);

        // Build up a binary, undirected adjacency matrix of the graph.
        // Every unset bit in the adj_matrix will be a potential link.
        for (i, node) in self.nodes.iter().enumerate() {
            for link in node.output_links.iter() {
                let j = link.node_idx.index();
                adj_matrix.insert(idx(i, j));
                // include the link of reverse direction, because this would
                // create a cycle anyway.
                adj_matrix.insert(idx(j, i));
            }
        }

        let adj_matrix = adj_matrix; // make immutable

        // We now test all potential links of every node in the graph, if it would
        // introduce a cycle. For that, we shuffle the node indices (`node_order`).
        // in random order.
        let mut node_order: Vec<_> = (0..n).into_iter().collect();
        let mut edge_order: Vec<_> = (0..n).into_iter().collect();
        rng.shuffle(&mut node_order);

        let node_order = node_order; // make immutable

        let mut cycler = CycleDetector::new(self);
        for &i in &node_order {
            rng.shuffle(&mut edge_order);
            for &j in &edge_order {
                if i != j && !adj_matrix.contains(idx(i, j)) {
                    // The link (i, j) neither is reflexive, nor exists.
                    let ni = NodeIndex(i);
                    let nj = NodeIndex(j);
                    if self.valid_link(ni, nj).is_ok() && !cycler.link_would_cycle(ni, nj) {
                        // If the link is valid and does not create a cycle, we are done!
                        return Some((ni, nj));
                    }
                }
            }
        }

        return None;
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_idx: NodeIndex, target_node_idx: NodeIndex) -> bool {
        if source_node_idx == target_node_idx {
            return true;
        }

        CycleDetector::new(self).link_would_cycle(source_node_idx, target_node_idx)
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_idx: NodeIndex,
                      target_node_idx: NodeIndex)
                      -> Result<(), &'static str> {
        if source_node_idx == target_node_idx {
            return Err("Loops are not allowed");
        }

        if !self.nodes[source_node_idx.index()].node_type.accept_outgoing_links() {
            return Err("Node does not allow outgoing links");
        }

        if !self.nodes[target_node_idx.index()].node_type.accept_incoming_links() {
            return Err("Node does not allow incoming links");
        }

        Ok(())
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_idx: NodeIndex, target_node_idx: NodeIndex, weight: L) {
        if let Err(err) = self.valid_link(source_node_idx, target_node_idx) {
            panic!(err);
        }

        self.nodes[source_node_idx.index()].output_links.push(Link {
            node_idx: target_node_idx,
            weight: weight.clone(),
        });

        self.nodes[target_node_idx.index()].input_links.push(Link {
            node_idx: source_node_idx,
            weight: weight,
        });
    }
}

#[derive(Clone, Debug)]
pub struct NetworkMap<NKEY: Ord + Clone + Debug, N: NodeType, L: LinkWeight> {
    network: Network<N, L>,
    node_map: BTreeMap<NKEY, NodeIndex>,
    node_map_rev: BTreeMap<NodeIndex, NKEY>,
}

impl<NKEY: Ord + Clone + Debug, N: NodeType, L: LinkWeight> NetworkMap<NKEY, N, L> {
    pub fn new() -> NetworkMap<NKEY, N, L> {
        NetworkMap {
            network: Network::new(),
            node_map: BTreeMap::new(),
            node_map_rev: BTreeMap::new(),
        }
    }

    pub fn nodes(&self) -> &[Node<N, L>] {
        self.network.nodes()
    }

    /// Registers/creates a new node under the external key `node_key`.
    ///
    /// # Panics
    ///
    /// If a node with `node_key` already exists.
    pub fn add_node(&mut self, node_key: NKEY, node_type: N) {
        // XXX: Use node_map.entry()
        if self.node_map.contains_key(&node_key) {
            panic!("Duplicate node index");
        }
        let idx = self.network.add_node(node_type);
        self.node_map.insert(node_key.clone(), idx);
        self.node_map_rev.insert(idx, node_key);
    }

    /// Returns a random link between two unconnected nodes, which would not introduce
    /// a cycle. Return None is no such exists.
    pub fn find_random_unconnected_link_no_cycle<R: Rng>(&self,
                                                         rng: &mut R)
                                                         -> Option<(&NKEY, &NKEY)> {
        match self.network.find_random_unconnected_link_no_cycle(rng) {
            Some((a, b)) => Some((&self.node_map_rev[&a], &self.node_map_rev[&b])),
            None => None,
        }
    }

    /// Returns true if the introduction of this directed link would lead towards a cycle.
    pub fn link_would_cycle(&self, source_node_key: NKEY, target_node_key: NKEY) -> bool {
        self.network.link_would_cycle(self.node_map[&source_node_key],
                                      self.node_map[&target_node_key])
    }

    // Check if the link is valid. Doesn't check for cycles.
    pub fn valid_link(&self,
                      source_node_key: NKEY,
                      target_node_key: NKEY)
                      -> Result<(), &'static str> {
        self.network.valid_link(self.node_map[&source_node_key],
                                self.node_map[&target_node_key])
    }

    // Note: Doesn't check for cycles (except in the simple reflexive case).
    pub fn add_link(&mut self, source_node_key: NKEY, target_node_key: NKEY, weight: L) {
        self.network.add_link(self.node_map[&source_node_key],
                              self.node_map[&target_node_key],
                              weight)
    }
}

#[cfg(test)]
mod tests {
    use rand;
    use super::{NodeType, Network};

    #[derive(Clone, Debug)]
    enum NodeT {
        Input,
        Hidden,
        Output,
    }

    impl NodeType for NodeT {
        fn accept_incoming_links(&self) -> bool {
            match *self {
                NodeT::Input => false,
                _ => true,
            }
        }
        fn accept_outgoing_links(&self) -> bool {
            match *self {
                NodeT::Output => false,
                _ => true,
            }
        }
    }

    #[test]
    fn test_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input);
        let h1 = g.add_node(NodeT::Hidden);
        let h2 = g.add_node(NodeT::Hidden);
        assert_eq!(true, g.valid_link(i1, i1).is_err());
        assert_eq!(true, g.valid_link(h1, h1).is_err());

        assert_eq!(true, g.valid_link(h1, i1).is_err());
        assert_eq!(Ok(()), g.valid_link(i1, h1));
        assert_eq!(Ok(()), g.valid_link(i1, h2));
        assert_eq!(Ok(()), g.valid_link(h1, h2));

        g.add_link(i1, h1, 0.0);
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(false, g.link_would_cycle(i1, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
        assert_eq!(true, g.link_would_cycle(i1, i1));
        assert_eq!(false, g.link_would_cycle(h1, h2));
        assert_eq!(false, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(h2, i1));

        g.add_link(h1, h2, 0.0);
        assert_eq!(true, g.link_would_cycle(h2, i1));
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(true, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
    }

    #[test]
    fn test_find_random_unconnected_link_no_cycle() {
        let mut g = Network::new();
        let i1 = g.add_node(NodeT::Input);
        let o1 = g.add_node(NodeT::Output);
        let o2 = g.add_node(NodeT::Output);

        let mut rng = rand::thread_rng();

        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        let l = link.unwrap();
        assert!((i1, o1) == l || (i1, o2) == l);

        g.add_link(i1, o2, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        assert_eq!((i1, o1), link.unwrap());

        g.add_link(i1, o1, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(false, link.is_some());
    }
}
<|endoftext|>


<commit_before>#![feature(fnbox)]

//! Work-stealing job-queue implementation.
//! Inspired by the Molecular Matters blog posts.

use std::borrow::Borrow;
use std::boxed::FnBox;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::mem;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};

use ::rand::thread_rng;
use ::rand::distributions::{IndependentSample, Range};

extern crate rand;

/// Messages that can be sent to workers.
enum WorkerMessage {
    Stop,
}

/// A job is a unit of work to be done.
struct Job {
    func: Option<Box<FnBox(&Worker) + 'static + Send>>,
    finished: AtomicBool,
}

impl Job {
    // make a new, unrooted job.
    fn new<F: FnOnce(&Worker) + 'static + Send>(f: F) -> Job {
        Job {
            func: Some(Box::new(f)),
            finished: AtomicBool::new(false),
        }
    }

    // run this job.
    fn run(&mut self, worker: &Worker) {
        let f: Box<FnBox(&Worker) + 'static + Send> = match self.func.take() {
            Some(f) => f,
            // jobs should never be run more than once.
            None => unreachable!(),
        };

        FnBox::call_box(f, (worker,));

        self.finished.store(true, Ordering::SeqCst);
    }

    fn is_finished(&self) -> bool {
        self.finished.load(Ordering::SeqCst)
    }
}

/// A thread-safe double-ended queue for jobs.
/// Right now, it's just a dumb locking wrapper of VecDeque.
struct JobQueue {
    inner: Mutex<VecDeque<*mut Job>>,
}

impl JobQueue {
    fn new() -> Self {
        JobQueue {
            inner: Mutex::new(VecDeque::new()),
        }
    }

    // pop a job from the private end of the queue.
    // only the owner of this queue should call this.
    fn pop(&self) -> Option<*mut Job> {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.pop_back()
    }

    // steal a job from the public end of the queu.
    fn steal(&self) -> Option<*mut Job> {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.pop_front()
    }

    // push another job to the queue.
    fn push(&self, job: *mut Job) {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.push_back(job);
    }
}

unsafe impl Send for JobQueue {}
unsafe impl Sync for JobQueue {}

/// A worker thread. This logically owns a queue of jobs to run, and
/// a list of other worker threads' queues to steal from.
pub struct Worker {
    queue: Arc<JobQueue>,
    siblings: Box<[Arc<JobQueue>]>,
}

impl Worker {
    /// Submit a job to be run by this worker.
    /// You must use this handle to join
    pub fn submit<F: FnOnce(&Worker) + 'static + Send>(&self, f: F) -> JoinHandle {
        let job = Box::new(Job::new(f));
        self.give_job(&*job as *const _ as *mut Job);

        JoinHandle {
            job: job,
            worker: self,
        }
    }

    /// Create an execution scope where you can run jobs with a non-static
    /// lifetime.
    pub fn scope<'a, 'b, F>(&'a self, f: F)
    where F: FnOnce(&Scope<'a, 'b>) {
        let scope = Scope {
            worker: self,
            children: RefCell::new(Vec::new()),
            _marker: PhantomData,
        };

        f(&scope);

        drop(scope);
    }

    fn give_job(&self, job: *mut Job) {
        self.queue.push(job);
    }

    // Get a job from this queue or another.
    fn get_job(&self) -> Option<*mut Job> {
        if let Some(job) = self.queue.pop() {
            Some(job)
        } else {
            let mut rng = thread_rng();
            // ranges are [low, high)
            let dist_range = Range::new(0, self.siblings.len());

            let other_queue: &Arc<JobQueue> = &self.siblings[dist_range.ind_sample(&mut rng)];
            if &**other_queue as *const JobQueue != &*self.queue as *const JobQueue {
                other_queue.steal()
            } else {
                None
            }
        }
    }

    fn run_job(&self) {
        if let Some(job) = self.get_job() {
            unsafe { (*job).run(self) }
        }
    }
}

/// A handle to a specific job.
/// Users can either call `wait()` to explicitly wait for the job
/// to finish, or the job will be waited for at the end of scope.
/// This handle will not cause any memory unsafety when leaked.
#[must_use]
pub struct JoinHandle<'a> {
    job: Box<Job>,
    worker: &'a Worker,
}

impl<'a> JoinHandle<'a> {
    /// Wait for this job to be finished.
    pub fn wait(self) {
        drop(self);
    }

    fn wait_(&self) {
        // work while we wait.
        while !self.job.is_finished() {
            self.worker.run_job();
        }
    }

    // TODO: find a way to release that doesn't involve
    // leaking memory or dropping the box.
    // I suspect it'll come when I change boxing jobs to
    // allocating them from a thread-local pool.
}

impl<'a> Drop for JoinHandle<'a> {
    fn drop(&mut self) {
        self.wait_();
    }
}

/// An execution scope for jobs.
pub struct Scope<'a, 'b> {
    worker: &'a Worker,
    children: RefCell<Vec<Box<Job>>>,
    _marker: PhantomData<Cell<&'b ()>>,
}

impl<'a, 'b> Scope<'a, 'b>{
    /// Submit a job to be completed within this scope.
    pub fn submit<F>(&'a self, f: F) -> ChildHandle<'a>
    where F: FnOnce(&Worker) + 'b + Send {
        let bounded_fn: Box<FnBox(&Worker) + 'b + Send> = Box::new(f);
        let unbounded_fn: Box<FnBox(&Worker) + 'static + Send> = unsafe { mem::transmute(bounded_fn) };

        let job = Box::new(Job {
            func: Some(unbounded_fn),
            finished: AtomicBool::new(false),
        });

        let job_ptr = &*job as *const _ as *mut Job;
        self.children.borrow_mut().push(job);

        self.worker.give_job(job_ptr);

        // this handle is safe to leak and drop:
        // the scope object owns the jobs' memory and
        // also enforces that the jobs don't outlive it.
        ChildHandle {
            job: job_ptr,
            worker: &self.worker,
        }
    }

    fn wait_all(&self) {
        // wait until all the children are done.
        for child in self.children.borrow().iter() {
            while !child.is_finished() {
                self.worker.run_job();
            }
        }
    }
}

impl<'a, 'b> Drop for Scope<'a, 'b> {
    fn drop(&mut self) {
        self.wait_all();
    }
}

/// A handle to a job spawned within a scope. Users can manually
/// `wait()` until it's completed. They can also `release()`
/// the guard to defer its completion to an arbitrary time
/// within its lifetime.
pub struct ChildHandle<'a> {
    job: *mut Job,
    worker: &'a Worker,
}

impl<'a> ChildHandle<'a> {
    /// Wait for this job to be finished.
    pub fn wait(self) {
        if self.job.is_null() { return; }

        // work while we wait.
        while unsafe { !(*self.job).is_finished() } {
            self.worker.run_job();
        }
    }

    /// Releases this job. This allows it to be finished
    /// at any point within the job's lifetime.
    pub fn release(self) {
        drop(self)
    }
}

pub struct JobSystem {
    handles: Vec<Sender<WorkerMessage>>,
    worker: Worker,
}

impl JobSystem {
    /// Gets a reference to the worker for this thread.
    pub fn get_worker(&self) -> &Worker {
        &self.worker
    }
}

// No unsafety is induced by not stopping the handles.
// However, the threads will spin forever, which probably
// isn't ideal.
impl Drop for JobSystem {
    fn drop(&mut self) {
        for handle in &mut self.handles {
            // at this point, either the worker receives
            // the message or it's already shut down.
            let _ = handle.send(WorkerMessage::Stop);
        }
    }
}

/// Create a new `JobSystem` with `n_threads` workers, including the
/// current thread. This will fail if `n_threads` is 0.
pub fn make_pool(n_threads: usize) -> Option<JobSystem> {
    use std::thread;

    if n_threads == 0 {
        return None;
    }

    // make a queue for every thread, including this one.
    let queues: Vec<_> = (0..n_threads)
        .map(|_| Arc::new(JobQueue::new())).collect();

    let queues = queues.into_boxed_slice();

    let mut handles = Vec::new();

    // Spawn a worker thread for every queue but the last one,
    // since that belongs to the thread this is spawned on.
    for queue in queues.iter().cloned().take(queues.len() - 1) {
        let (tx, rx) = channel();
        let siblings = queues.clone();

        thread::spawn(move || {
            let worker = Worker {
                queue: queue,
                siblings: siblings,
            };
            worker_main(worker, rx);
        });
        handles.push(tx);
    }

    Some(JobSystem {
        handles: handles,
        worker: Worker {
            queue: queues.last().unwrap().clone(),
            siblings: queues,
        },
    })
}

fn worker_main(worker: Worker, rx: Receiver<WorkerMessage>) {
    loop {
        // check for message
        match rx.try_recv() {
            Ok(WorkerMessage::Stop) => {
                break;
            }

            Err(TryRecvError::Disconnected) => {
                break;
            }

            _ => {}
        }

        worker.run_job();
    }
}

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

    #[test]
    fn basic_spawning() {
        // four worker threads, including this one.
        let pool = make_pool(4).unwrap();
        let this_worker = pool.get_worker();

        let mut my_jobs = Vec::new();

        for _ in 0..100 {
            let handle = this_worker.submit(|_| println!("Hello!"));
            my_jobs.push(handle);
        }
    }

    #[test]
    fn child_jobs() {
        let pool = make_pool(4).unwrap();
        let this_worker = pool.get_worker();

        this_worker.submit(|worker| {
            let mut jobs = Vec::new();
            for _ in 0..100 {
                let handle = worker.submit(|_| println!("Hello!"));
                jobs.push(handle);
            };
        }).wait();
    }

    #[test]
    fn scoping() {
        let pool = make_pool(4).unwrap();
        let this_worker = pool.get_worker();
        this_worker.submit(|worker| {
            let mut v = vec![0; 256];

            worker.scope(|scope| {
                for chunk in v.chunks_mut(32) {
                    scope.submit(move |_| {
                        for i in chunk { *i += 1 }
                    }).release();
                }
            });

            for i in v {
                assert_eq!(i, 1);
            }

        }).wait();
    }
}<commit_msg>Improved docs<commit_after>#![feature(fnbox)]

//! Work-stealing job-queue implementation.
//! Inspired by the Molecular Matters blog posts.

use std::borrow::Borrow;
use std::boxed::FnBox;
use std::cell::{Cell, RefCell};
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::mem;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};

use ::rand::thread_rng;
use ::rand::distributions::{IndependentSample, Range};

extern crate rand;

/// Messages that can be sent to workers.
enum WorkerMessage {
    Stop,
}

/// A job is a unit of work to be done.
struct Job {
    func: Option<Box<FnBox(&Worker) + 'static + Send>>,
    finished: AtomicBool,
}

impl Job {
    // make a new, unrooted job.
    fn new<F: FnOnce(&Worker) + 'static + Send>(f: F) -> Job {
        Job {
            func: Some(Box::new(f)),
            finished: AtomicBool::new(false),
        }
    }

    // run this job.
    fn run(&mut self, worker: &Worker) {
        let f: Box<FnBox(&Worker) + 'static + Send> = match self.func.take() {
            Some(f) => f,
            // jobs should never be run more than once.
            None => unreachable!(),
        };

        FnBox::call_box(f, (worker,));

        self.finished.store(true, Ordering::SeqCst);
    }

    fn is_finished(&self) -> bool {
        self.finished.load(Ordering::SeqCst)
    }
}

/// A thread-safe double-ended queue for jobs.
/// Right now, it's just a dumb locking wrapper of VecDeque.
struct JobQueue {
    inner: Mutex<VecDeque<*mut Job>>,
}

impl JobQueue {
    fn new() -> Self {
        JobQueue {
            inner: Mutex::new(VecDeque::new()),
        }
    }

    // pop a job from the private end of the queue.
    // only the owner of this queue should call this.
    fn pop(&self) -> Option<*mut Job> {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.pop_back()
    }

    // steal a job from the public end of the queu.
    fn steal(&self) -> Option<*mut Job> {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.pop_front()
    }

    // push another job to the queue.
    fn push(&self, job: *mut Job) {
        let mut guard = match self.inner.lock() {
            Ok(g) => g,
            Err(p) => p.into_inner(),
        };

        guard.push_back(job);
    }
}

unsafe impl Send for JobQueue {}
unsafe impl Sync for JobQueue {}

/// A worker thread. This logically owns a queue of jobs to run, and
/// a list of other worker threads' queues to steal from.
pub struct Worker {
    queue: Arc<JobQueue>,
    siblings: Box<[Arc<JobQueue>]>,
}

impl Worker {
    /// Submit a job to be run by this worker.
    /// You must use this handle to join
    pub fn submit<F: FnOnce(&Worker) + 'static + Send>(&self, f: F) -> JoinHandle {
        let job = Box::new(Job::new(f));
        self.give_job(&*job as *const _ as *mut Job);

        JoinHandle {
            job: job,
            worker: self,
        }
    }

    /// Create an execution scope where you can run jobs with a non-static
    /// lifetime.
    pub fn scope<'a, 'b, F>(&'a self, f: F)
    where F: FnOnce(&Scope<'a, 'b>) {
        let scope = Scope {
            worker: self,
            children: RefCell::new(Vec::new()),
            _marker: PhantomData,
        };

        f(&scope);

        drop(scope);
    }

    fn give_job(&self, job: *mut Job) {
        self.queue.push(job);
    }

    // Get a job from this queue or another.
    fn get_job(&self) -> Option<*mut Job> {
        if let Some(job) = self.queue.pop() {
            Some(job)
        } else {
            let mut rng = thread_rng();
            // ranges are [low, high)
            let dist_range = Range::new(0, self.siblings.len());

            let other_queue: &Arc<JobQueue> = &self.siblings[dist_range.ind_sample(&mut rng)];
            if &**other_queue as *const JobQueue != &*self.queue as *const JobQueue {
                other_queue.steal()
            } else {
                None
            }
        }
    }

    fn run_job(&self) {
        if let Some(job) = self.get_job() {
            unsafe { (*job).run(self) }
        }
    }
}

/// A handle to a specific job.
/// Users can either call `wait()` to explicitly wait for the job
/// to finish, or the job will be waited for at the end of scope.
/// This handle will not cause any memory unsafety when leaked.
#[must_use]
pub struct JoinHandle<'a> {
    job: Box<Job>,
    worker: &'a Worker,
}

impl<'a> JoinHandle<'a> {
    /// Wait for this job to be finished.
    /// This is identical to dropping the guard.
    pub fn wait(self) {
        drop(self);
    }

    fn wait_(&self) {
        // work while we wait.
        while !self.job.is_finished() {
            self.worker.run_job();
        }
    }

    // TODO: find a way to release that doesn't involve
    // leaking memory or dropping the box.
    // I suspect it'll come when I change boxing jobs to
    // allocating them from a thread-local pool.
}

impl<'a> Drop for JoinHandle<'a> {
    fn drop(&mut self) {
        self.wait_();
    }
}

/// An execution scope for jobs.
pub struct Scope<'a, 'b> {
    worker: &'a Worker,
    children: RefCell<Vec<Box<Job>>>,
    _marker: PhantomData<Cell<&'b ()>>,
}

impl<'a, 'b> Scope<'a, 'b>{
    /// Submit a job to be completed within this scope.
    pub fn submit<F>(&'a self, f: F) -> ChildHandle<'a>
    where F: FnOnce(&Worker) + 'b + Send {
        let bounded_fn: Box<FnBox(&Worker) + 'b + Send> = Box::new(f);
        let unbounded_fn: Box<FnBox(&Worker) + 'static + Send> = unsafe { mem::transmute(bounded_fn) };

        let job = Box::new(Job {
            func: Some(unbounded_fn),
            finished: AtomicBool::new(false),
        });

        let job_ptr = &*job as *const _ as *mut Job;
        self.children.borrow_mut().push(job);

        self.worker.give_job(job_ptr);

        // this handle is safe to leak and drop:
        // the scope object owns the jobs' memory and
        // also enforces that the jobs don't outlive it.
        ChildHandle {
            job: job_ptr,
            worker: &self.worker,
        }
    }

    fn wait_all(&self) {
        // wait until all the children are done.
        for child in self.children.borrow().iter() {
            while !child.is_finished() {
                self.worker.run_job();
            }
        }
    }
}

impl<'a, 'b> Drop for Scope<'a, 'b> {
    fn drop(&mut self) {
        self.wait_all();
    }
}

/// A handle to a job spawned within a scope. Users can manually
/// `wait()` until it's completed. They can also `release()`
/// the guard to defer its completion to an arbitrary time
/// within its lifetime.
pub struct ChildHandle<'a> {
    job: *mut Job,
    worker: &'a Worker,
}

impl<'a> ChildHandle<'a> {
    /// Wait for this job to be finished.
    pub fn wait(self) {
        if self.job.is_null() { return; }

        // work while we wait.
        while unsafe { !(*self.job).is_finished() } {
            self.worker.run_job();
        }
    }

    /// Releases this job. This allows it to be finished
    /// at any point within the job's lifetime.
    pub fn release(self) {
        drop(self)
    }
}

/// The JobSystem holds a worker for the thread it exists on,
/// as well as handles to all the other threads.
pub struct JobSystem {
    handles: Vec<Sender<WorkerMessage>>,
    worker: Worker,
    // to mark it !Send
    _marker: PhantomData<*mut ()>,
}

impl JobSystem {
    /// Gets a reference to the worker for this thread.
    pub fn get_worker(&self) -> &Worker {
        &self.worker
    }
}

// No unsafety is induced by not stopping the handles.
// However, the threads will spin forever, which probably
// isn't ideal.
impl Drop for JobSystem {
    fn drop(&mut self) {
        for handle in &mut self.handles {
            // at this point, either the worker receives
            // the message or it's already shut down.
            let _ = handle.send(WorkerMessage::Stop);
        }
    }
}

/// Create a new `JobSystem` with `n_threads` workers, including the
/// current thread. This will fail if `n_threads` is 0.
pub fn make_pool(n_threads: usize) -> Option<JobSystem> {
    use std::thread;

    if n_threads == 0 {
        return None;
    }

    // make a queue for every thread, including this one.
    let queues: Vec<_> = (0..n_threads)
        .map(|_| Arc::new(JobQueue::new())).collect();

    let queues = queues.into_boxed_slice();

    let mut handles = Vec::new();

    // Spawn a worker thread for every queue but the last one,
    // since that belongs to the thread this is spawned on.
    for queue in queues.iter().cloned().take(queues.len() - 1) {
        let (tx, rx) = channel();
        let siblings = queues.clone();

        thread::spawn(move || {
            let worker = Worker {
                queue: queue,
                siblings: siblings,
            };
            worker_main(worker, rx);
        });
        handles.push(tx);
    }

    Some(JobSystem {
        handles: handles,
        worker: Worker {
            queue: queues.last().unwrap().clone(),
            siblings: queues,
        },
    })
}

// the main thread for each worker
fn worker_main(worker: Worker, rx: Receiver<WorkerMessage>) {
    loop {
        // check for message
        match rx.try_recv() {
            // time to stop!
            Ok(WorkerMessage::Stop) => {
                break;
            }

            // somehow the JobSystem got dropped without disconnecting.
            Err(TryRecvError::Disconnected) => {
                break;
            }

            _ => {}
        }

        // run a job
        worker.run_job();
    }
}

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

    #[test]
    fn basic_spawning() {
        // four worker threads, including this one.
        let pool = make_pool(4).unwrap();
        let this_worker = pool.get_worker();

        let mut my_jobs = Vec::new();

        for _ in 0..100 {
            let handle = this_worker.submit(|_| println!("Hello!"));
            my_jobs.push(handle);
        }
    }

    #[test]
    fn child_jobs() {
        let pool = make_pool(4).unwrap();
        let this_worker = pool.get_worker();

        this_worker.submit(|worker| {
            let mut jobs = Vec::new();
            for _ in 0..100 {
                let handle = worker.submit(|_| println!("Hello!"));
                jobs.push(handle);
            };
        }).wait();
    }

    #[test]
    fn scoping() {
        let pool = make_pool(4).unwrap();
        let this_worker = pool.get_worker();
        this_worker.submit(|worker| {
            let mut v = vec![0; 256];

            worker.scope(|scope| {
                for chunk in v.chunks_mut(32) {
                    scope.submit(move |_| {
                        for i in chunk { *i += 1 }
                    }).release();
                }
            });

            for i in v {
                assert_eq!(i, 1);
            }

        }).wait();
    }
}<|endoftext|>


<commit_before>extern crate toml;

// Import traits
use std::io::prelude::Read;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

#[derive(Debug)]
    Echo,
enum Step {
    Run,
    Shell,
    SetEnv,
}

fn parse_toml(filename: &str) -> Vec<Step> {

    println!("Reading toml file {}", filename);

    // Read toml file content
    let mut input = String::new();
    std::fs::File::open(&filename).and_then(|mut f| {
        f.read_to_string(&mut input)
    }).unwrap();

    // Pase toml file
    let mut parser = toml::Parser::new(&input);

    let toml = parser.parse().unwrap_or_else(|| {
        for err in &parser.errors {
            let (loline, locol) = parser.to_linecol(err.lo);
            let (hiline, hicol) = parser.to_linecol(err.hi);
            println!("{}:{}:{}-{}:{} error: {}",
                     filename, loline, locol, hiline, hicol, err.desc);
        }
        panic!("Error parsing toml file.");
    });

    println!("toml: {:#?}", toml);
    println!("toml: {:?}", toml.len());

    // Parse "on" table
    // unimplemented!();

    // Parse "variables" table
    // unimplemented!();

    // Parse "steps" table
    let mut steps = Vec::<Step>::with_capacity(10);

    steps
}

pub fn execute_steps(filename: &str) {

    let steps = parse_toml(filename);

    println!("Steps: {:#?}", steps);
}
<commit_msg>Parse Echo step<commit_after>extern crate toml;

// Import traits
use std::io::prelude::Read;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

pub fn test() {
    println!("Hello from lib.rs");
}

#[derive(Debug)]
enum Step {
    Echo {name: String, string: String},
    Run,
    Shell,
    SetEnv,
}

fn parse_toml(filename: &str) -> Vec<Step> {

    println!("Reading toml file {}", filename);

    // Read toml file content
    let mut input = String::new();
    std::fs::File::open(&filename).and_then(|mut f| {
        f.read_to_string(&mut input)
    }).unwrap();

    // Pase toml file
    let mut parser = toml::Parser::new(&input);

    let toml = parser.parse().unwrap_or_else(|| {
        for err in &parser.errors {
            let (loline, locol) = parser.to_linecol(err.lo);
            let (hiline, hicol) = parser.to_linecol(err.hi);
            println!("{}:{}:{}-{}:{} error: {}",
                     filename, loline, locol, hiline, hicol, err.desc);
        }
        panic!("Error parsing toml file.");
    });

    println!("toml: {:#?}", toml);
    println!("toml: {:?}", toml.len());

    // Parse "on" table
    // unimplemented!();

    // Parse "variables" table
    // unimplemented!();

    // Parse "steps" table
    let mut steps = Vec::<Step>::with_capacity(10);

    for step in toml.get("step").unwrap().as_slice().unwrap() {
        let action = step.as_table().unwrap().get("action").unwrap().as_str().unwrap();
        let name = step.as_table().unwrap().get("name").unwrap().as_str().unwrap().to_string();
        let details = step.as_table().unwrap().get("details").unwrap().as_table().unwrap();
        println!("name:   {}", name);
        println!("action: {}", action);
        let step = match action {
            "echo" => {
                let string = details.get("string").unwrap().as_str().unwrap().to_string();
                println!("string: {}", string);
                Step::Echo {name: name, string: string}
            },
            // "shell" => {
            // },
            // "run" => {
            // },
            // "setenv" => {
            // },
            _ => {
                println!("Unknown action '{}' in toml file", action);
                unimplemented!();
            },
        };
        unimplemented!();
        steps.push(step);
    }

    steps
}

pub fn execute_steps(filename: &str) {

    let steps = parse_toml(filename);

    println!("Steps: {:#?}", steps);
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate nix;

mod ffi;
pub mod exec_handler;
pub mod trap;
<commit_msg>Add some crate-levle docs<commit_after>//! Signal handling library
//!
//! The library is focused on higher-level abstractions for handling signals.
//! All low-level stuff should be in `nix`.
//!
//! Currently we have two mechanisms for handling exeptions:
//!
//! 1. The `exec_handler` module for replacing process with newly runned
//!    command designed as crash safety measure
//! 2. The `Trap` mechanism that masks out signals and allows wait for them
//!    explicitly
//!
//! Both are specifically suited for making process supervisors.
//!
//! On TODO list:
//!
//! * `signalfd`
//!
//! The library tested only on linux
//!

extern crate libc;
extern crate nix;

mod ffi;
pub mod exec_handler;
pub mod trap;
<|endoftext|>


<commit_before>//! # Mime
//!
//! Mime is now Media Type, technically, but `Mime` is more immediately
//! understandable, so the main type here is `Mime`.
//!
//! ## What is Mime?
//!
//! Example mime string: `text/plain;charset=utf-8`
//!
//! ```rust
//! # use std::from_str::FromStr;
//! use mime::{Mime, Text, Plain, Charset, Utf8};
//! let mime: Mime = FromStr::from_str("text/plain;charset=utf-8").unwrap();
//! assert_eq!(mime, Mime(Text, Plain, vec![(Charset, Utf8)]));
//! ```

#![license = "MIT"]
#![doc(html_root_url = "http://seanmonstar.github.io/mime.rs")]
#![experimental]
#![feature(macro_rules, phase)]

#[phase(plugin, link)]
extern crate log;

#[cfg(test)]
extern crate test;

use std::ascii::AsciiExt;
use std::cmp::Equiv;
use std::fmt;
use std::from_str::FromStr;
use std::iter::Enumerate;
use std::str::Chars;

macro_rules! inspect(
    ($s:expr, $t:expr) => ({
        let t = $t;
        debug!("inspect {}: {}", $s, t);
        t
    })
)

/// Mime, or Media Type. Encapsulates common registers types.
///
/// Consider that a traditional mime type contains a "top level type",
/// a "sub level type", and 0-N "parameters". And they're all strings.
/// Strings everywhere. Strings mean typos. Rust has type safety. We should
/// use types!
///
/// So, Mime bundles together this data into types so the compiler can catch
/// your typos.
///
/// This improves things so you use match without Strings:
///
/// ```rust
/// use std::from_str::from_str;
/// use mime::{Mime, Application, Json};
///
/// let mime: mime::Mime = from_str("application/json").unwrap();
///
/// match mime {
///     Mime(Application, Json, _) => println!("matched json!"),
///     _ => ()
/// }
/// ```
#[deriving(Clone, PartialEq)]
pub struct Mime(pub TopLevel, pub SubLevel, pub Vec<Param>);

macro_rules! enoom (
    (pub enum $en:ident; $ext:ident; $($ty:ident, $text:expr;)*) => (

        #[deriving(Clone, PartialEq)]
        pub enum $en {
            $($ty),*,
            $ext(String)
        }

        impl fmt::Show for $en {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                match *self {
                    $($ty => $text),*,
                    $ext(ref s) => return s.fmt(fmt)
                }.fmt(fmt)
            }
        }

        impl FromStr for $en {
            fn from_str(s: &str) -> Option<$en> {
                Some(match s {
                    $(_s if _s == $text => $ty),*,
                    s => $ext(inspect!(stringify!($ext), s).to_string())
                })
            }
        }
    )
)

enoom! {
    pub enum TopLevel;
    TopExt;
    TopStar, "*"; // remove Top prefix if enums gain namespaces
    Text, "text";
    Image, "image";
    Audio, "audio";
    Video, "video";
    Application, "application";
    Multipart, "multipart";
    Message, "message";
    Model, "model";
}

enoom! {
    pub enum SubLevel;
    SubExt;
    SubStar, "*"; // remove Sub prefix if enums gain namespaces

    // common text/*
    Plain, "plain";
    Html, "html";
    Xml, "xml";
    Javascript, "javascript";
    Css, "css";

    // common application/*
    Json, "json";
    WwwFormUrlEncoded, "x-www-form-urlencoded";

    // common image/*
    Png, "png";
    Gif, "gif";
    Bmp, "bmp";
    Jpeg, "jpeg";
}

enoom! {
    pub enum Attr;
    AttrExt;
    Charset, "charset";
    Q, "q";
}

enoom! {
    pub enum Value;
    ValueExt;
    Utf8, "utf-8";
}

pub type Param = (Attr, Value);

impl Equiv<Mime> for Mime {
    fn equiv(&self, other: &Mime) -> bool {
        //im so sorry
        //TODO: be less sorry. dont to_string()
        self.to_string() == other.to_string()
    }
}

impl fmt::Show for Mime {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Mime(ref top, ref sub, ref params) = *self;
        try!(write!(fmt, "{}/{}", top, sub));
        fmt_params(params.as_slice(), fmt)
    }
}

impl FromStr for Mime {
    fn from_str(raw: &str) -> Option<Mime> {
        let ascii = raw.to_ascii_lower(); // lifetimes :(
        let raw = ascii.as_slice();
        let len = raw.len();
        let mut iter = raw.chars().enumerate();
        let mut params = vec![];
        // toplevel
        let mut start;
        let mut top;
        loop {
            match inspect!("top iter", iter.next()) {
                Some((0, c)) if is_restricted_name_first_char(c) => (),
                Some((i, c)) if i > 0 && is_restricted_name_char(c) => (),
                Some((i, '/')) if i > 0 => match FromStr::from_str(raw.slice_to(i)) {
                    Some(t) => {
                        top = t;
                        start = i + 1;
                        break;
                    }
                    None => return None
                },
                _ => return None // EOF and no toplevel is no Mime
            };

        }

        // sublevel
        let mut sub;
        loop {
            match inspect!("sub iter", iter.next()) {
                Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
                Some((i, c)) if i > start && is_restricted_name_char(c) => (),
                Some((i, ';')) if i > start => match FromStr::from_str(raw.slice(start, i)) {
                    Some(s) => {
                        sub = s;
                        start = i + 1;
                        break;
                    }
                    None => return None
                },
                None => match FromStr::from_str(raw.slice_from(start)) {
                    Some(s) => return Some(Mime(top, s, params)),
                    None => return None
                },
                _ => return None
            };
        }

        // params
        debug!("starting params, len={}", len);
        loop {
            match inspect!("param", param_from_str(raw, &mut iter, start)) {
                Some((p, end)) => {
                    params.push(p);
                    start = end;
                    if start >= len {
                        break;
                    }
                }
                None => break
            }
        }

        Some(Mime(top, sub, params))
    }
}

fn param_from_str(raw: &str, iter: &mut Enumerate<Chars>, mut start: uint) -> Option<(Param, uint)> {
    let mut attr;
    debug!("param_from_str, start={}", start);
    loop {
        match inspect!("attr iter", iter.next()) {
            Some((i, ' ')) if i == start => start = i + 1,
            Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
            Some((i, c)) if i > start && is_restricted_name_char(c) => (),
            Some((i, '=')) if i > start => match FromStr::from_str(raw.slice(start, i)) {
                Some(a) => {
                    attr = inspect!("attr", a);
                    start = i + 1;
                    break;
                },
                None => return None
            },
            _ => return None
        }
    }
    let mut value;
    // values must be restrict-name-char or "anything goes"
    let mut is_quoted = false;
    loop {
        match inspect!("value iter", iter.next()) {
            Some((i, '"')) if i == start => {
                debug!("quoted");
                is_quoted = true;
                start = i + 1;
            },
            Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
            Some((i, '"')) if i > start && is_quoted => match FromStr::from_str(raw.slice(start, i)) {
                Some(v) => {
                    value = v;
                    start = i + 1;
                    break;
                },
                None => return None
            },
            Some((i, c)) if i > start && is_quoted || is_restricted_name_char(c) => (),
            Some((i, ';')) if i > start => match FromStr::from_str(raw.slice(start, i)) {
                Some(v) => {
                    value = v;
                    start = i + 1;
                    break;
                },
                None => return None
            },
            None => match FromStr::from_str(raw.slice_from(start)) {
                Some(v) => {
                    value = v;
                    start = raw.len();
                    break;
                },
                None => return None
            },

            _ => return None
        }
    }

    Some(((attr, value), start))
}

// From [RFC6838](http://tools.ietf.org/html/rfc6838#section-4.2):
//
// > All registered media types MUST be assigned top-level type and
// > subtype names.  The combination of these names serves to uniquely
// > identify the media type, and the subtype name facet (or the absence
// > of one) identifies the registration tree.  Both top-level type and
// > subtype names are case-insensitive.
// >
// > Type and subtype names MUST conform to the following ABNF:
// >
// >     type-name = restricted-name
// >     subtype-name = restricted-name
// >
// >     restricted-name = restricted-name-first *126restricted-name-chars
// >     restricted-name-first  = ALPHA / DIGIT
// >     restricted-name-chars  = ALPHA / DIGIT / "!" / "#" /
// >                              "$" / "&" / "-" / "^" / "_"
// >     restricted-name-chars =/ "." ; Characters before first dot always
// >                                  ; specify a facet name
// >     restricted-name-chars =/ "+" ; Characters after last plus always
// >                                  ; specify a structured syntax suffix
//
fn is_restricted_name_first_char(c: char) -> bool {
    match c {
        'a'...'z' |
        '0'...'9' => true,
        _ => false
    }
}

fn is_restricted_name_char(c: char) -> bool {
    if is_restricted_name_first_char(c) {
        true
    } else {
        match c {
            '!' |
            '#' |
            '$' |
            '&' |
            '-' |
            '^' |
            '.' |
            '+' |
            '_' => true,
            _ => false
        }
    }
}

#[inline]
fn fmt_params<T: AsSlice<Param>>(params: T, fmt: &mut fmt::Formatter) -> fmt::Result {
    for param in params.as_slice().iter() {
        try!(fmt_param(param, fmt));
    }
    Ok(())
}

#[inline]
fn fmt_param(param: &Param, fmt: &mut fmt::Formatter) -> fmt::Result {
    let (ref attr, ref value) = *param;
    write!(fmt, "; {}={}", attr, value)
}

#[cfg(test)]
mod tests {
    use std::from_str::{FromStr, from_str};
    use test::Bencher;
    use super::{Mime, Text, Plain, Charset, Utf8, AttrExt, ValueExt};

    #[test]
    fn test_mime_show() {
        let mime = Mime(Text, Plain, vec![]);
        assert_eq!(mime.to_string(), "text/plain".to_string());
        let mime = Mime(Text, Plain, vec![(Charset, Utf8)]);
        assert_eq!(mime.to_string(), "text/plain; charset=utf-8".to_string());
    }

    #[test]
    fn test_mime_from_str() {
        assert_eq!(FromStr::from_str("text/plain"), Some(Mime(Text, Plain, vec![])));
        assert_eq!(FromStr::from_str("TEXT/PLAIN"), Some(Mime(Text, Plain, vec![])));
        assert_eq!(FromStr::from_str("text/plain; charset=utf-8"), Some(Mime(Text, Plain, vec![(Charset, Utf8)])));
        assert_eq!(FromStr::from_str("text/plain;charset=\"utf-8\""), Some(Mime(Text, Plain, vec![(Charset, Utf8)])));
        assert_eq!(FromStr::from_str("text/plain; charset=utf-8; foo=bar"),
            Some(Mime(Text, Plain, vec![(Charset, Utf8),
                                        (AttrExt("foo".to_string()), ValueExt("bar".to_string())) ])));
    }

    #[bench]
    fn bench_show(b: &mut Bencher) {
        let mime = Mime(Text, Plain, vec![(Charset, Utf8), (AttrExt("foo".to_string()), ValueExt("bar".to_string()))]);
        b.bytes = mime.to_string().as_bytes().len() as u64;
        b.iter(|| mime.to_string())
    }

    #[bench]
    fn bench_from_str(b: &mut Bencher) {
        let s = "text/plain; charset=utf-8; foo=bar";
        b.bytes = s.as_bytes().len() as u64;
        b.iter(|| from_str::<Mime>(s))
    }
}
<commit_msg>add FormData SubLevel<commit_after>//! # Mime
//!
//! Mime is now Media Type, technically, but `Mime` is more immediately
//! understandable, so the main type here is `Mime`.
//!
//! ## What is Mime?
//!
//! Example mime string: `text/plain;charset=utf-8`
//!
//! ```rust
//! # use std::from_str::FromStr;
//! use mime::{Mime, Text, Plain, Charset, Utf8};
//! let mime: Mime = FromStr::from_str("text/plain;charset=utf-8").unwrap();
//! assert_eq!(mime, Mime(Text, Plain, vec![(Charset, Utf8)]));
//! ```

#![license = "MIT"]
#![doc(html_root_url = "http://seanmonstar.github.io/mime.rs")]
#![experimental]
#![feature(macro_rules, phase)]

#[phase(plugin, link)]
extern crate log;

#[cfg(test)]
extern crate test;

use std::ascii::AsciiExt;
use std::cmp::Equiv;
use std::fmt;
use std::from_str::FromStr;
use std::iter::Enumerate;
use std::str::Chars;

macro_rules! inspect(
    ($s:expr, $t:expr) => ({
        let t = $t;
        debug!("inspect {}: {}", $s, t);
        t
    })
)

/// Mime, or Media Type. Encapsulates common registers types.
///
/// Consider that a traditional mime type contains a "top level type",
/// a "sub level type", and 0-N "parameters". And they're all strings.
/// Strings everywhere. Strings mean typos. Rust has type safety. We should
/// use types!
///
/// So, Mime bundles together this data into types so the compiler can catch
/// your typos.
///
/// This improves things so you use match without Strings:
///
/// ```rust
/// use std::from_str::from_str;
/// use mime::{Mime, Application, Json};
///
/// let mime: mime::Mime = from_str("application/json").unwrap();
///
/// match mime {
///     Mime(Application, Json, _) => println!("matched json!"),
///     _ => ()
/// }
/// ```
#[deriving(Clone, PartialEq)]
pub struct Mime(pub TopLevel, pub SubLevel, pub Vec<Param>);

macro_rules! enoom (
    (pub enum $en:ident; $ext:ident; $($ty:ident, $text:expr;)*) => (

        #[deriving(Clone, PartialEq)]
        pub enum $en {
            $($ty),*,
            $ext(String)
        }

        impl fmt::Show for $en {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                match *self {
                    $($ty => $text),*,
                    $ext(ref s) => return s.fmt(fmt)
                }.fmt(fmt)
            }
        }

        impl FromStr for $en {
            fn from_str(s: &str) -> Option<$en> {
                Some(match s {
                    $(_s if _s == $text => $ty),*,
                    s => $ext(inspect!(stringify!($ext), s).to_string())
                })
            }
        }
    )
)

enoom! {
    pub enum TopLevel;
    TopExt;
    TopStar, "*"; // remove Top prefix if enums gain namespaces
    Text, "text";
    Image, "image";
    Audio, "audio";
    Video, "video";
    Application, "application";
    Multipart, "multipart";
    Message, "message";
    Model, "model";
}

enoom! {
    pub enum SubLevel;
    SubExt;
    SubStar, "*"; // remove Sub prefix if enums gain namespaces

    // common text/*
    Plain, "plain";
    Html, "html";
    Xml, "xml";
    Javascript, "javascript";
    Css, "css";

    // common application/*
    Json, "json";
    WwwFormUrlEncoded, "x-www-form-urlencoded";

    // multipart/*
    FormData, "form-data";

    // common image/*
    Png, "png";
    Gif, "gif";
    Bmp, "bmp";
    Jpeg, "jpeg";
}

enoom! {
    pub enum Attr;
    AttrExt;
    Charset, "charset";
    Q, "q";
}

enoom! {
    pub enum Value;
    ValueExt;
    Utf8, "utf-8";
}

pub type Param = (Attr, Value);

impl Equiv<Mime> for Mime {
    fn equiv(&self, other: &Mime) -> bool {
        //im so sorry
        //TODO: be less sorry. dont to_string()
        self.to_string() == other.to_string()
    }
}

impl fmt::Show for Mime {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Mime(ref top, ref sub, ref params) = *self;
        try!(write!(fmt, "{}/{}", top, sub));
        fmt_params(params.as_slice(), fmt)
    }
}

impl FromStr for Mime {
    fn from_str(raw: &str) -> Option<Mime> {
        let ascii = raw.to_ascii_lower(); // lifetimes :(
        let raw = ascii.as_slice();
        let len = raw.len();
        let mut iter = raw.chars().enumerate();
        let mut params = vec![];
        // toplevel
        let mut start;
        let mut top;
        loop {
            match inspect!("top iter", iter.next()) {
                Some((0, c)) if is_restricted_name_first_char(c) => (),
                Some((i, c)) if i > 0 && is_restricted_name_char(c) => (),
                Some((i, '/')) if i > 0 => match FromStr::from_str(raw.slice_to(i)) {
                    Some(t) => {
                        top = t;
                        start = i + 1;
                        break;
                    }
                    None => return None
                },
                _ => return None // EOF and no toplevel is no Mime
            };

        }

        // sublevel
        let mut sub;
        loop {
            match inspect!("sub iter", iter.next()) {
                Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
                Some((i, c)) if i > start && is_restricted_name_char(c) => (),
                Some((i, ';')) if i > start => match FromStr::from_str(raw.slice(start, i)) {
                    Some(s) => {
                        sub = s;
                        start = i + 1;
                        break;
                    }
                    None => return None
                },
                None => match FromStr::from_str(raw.slice_from(start)) {
                    Some(s) => return Some(Mime(top, s, params)),
                    None => return None
                },
                _ => return None
            };
        }

        // params
        debug!("starting params, len={}", len);
        loop {
            match inspect!("param", param_from_str(raw, &mut iter, start)) {
                Some((p, end)) => {
                    params.push(p);
                    start = end;
                    if start >= len {
                        break;
                    }
                }
                None => break
            }
        }

        Some(Mime(top, sub, params))
    }
}

fn param_from_str(raw: &str, iter: &mut Enumerate<Chars>, mut start: uint) -> Option<(Param, uint)> {
    let mut attr;
    debug!("param_from_str, start={}", start);
    loop {
        match inspect!("attr iter", iter.next()) {
            Some((i, ' ')) if i == start => start = i + 1,
            Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
            Some((i, c)) if i > start && is_restricted_name_char(c) => (),
            Some((i, '=')) if i > start => match FromStr::from_str(raw.slice(start, i)) {
                Some(a) => {
                    attr = inspect!("attr", a);
                    start = i + 1;
                    break;
                },
                None => return None
            },
            _ => return None
        }
    }
    let mut value;
    // values must be restrict-name-char or "anything goes"
    let mut is_quoted = false;
    loop {
        match inspect!("value iter", iter.next()) {
            Some((i, '"')) if i == start => {
                debug!("quoted");
                is_quoted = true;
                start = i + 1;
            },
            Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
            Some((i, '"')) if i > start && is_quoted => match FromStr::from_str(raw.slice(start, i)) {
                Some(v) => {
                    value = v;
                    start = i + 1;
                    break;
                },
                None => return None
            },
            Some((i, c)) if i > start && is_quoted || is_restricted_name_char(c) => (),
            Some((i, ';')) if i > start => match FromStr::from_str(raw.slice(start, i)) {
                Some(v) => {
                    value = v;
                    start = i + 1;
                    break;
                },
                None => return None
            },
            None => match FromStr::from_str(raw.slice_from(start)) {
                Some(v) => {
                    value = v;
                    start = raw.len();
                    break;
                },
                None => return None
            },

            _ => return None
        }
    }

    Some(((attr, value), start))
}

// From [RFC6838](http://tools.ietf.org/html/rfc6838#section-4.2):
//
// > All registered media types MUST be assigned top-level type and
// > subtype names.  The combination of these names serves to uniquely
// > identify the media type, and the subtype name facet (or the absence
// > of one) identifies the registration tree.  Both top-level type and
// > subtype names are case-insensitive.
// >
// > Type and subtype names MUST conform to the following ABNF:
// >
// >     type-name = restricted-name
// >     subtype-name = restricted-name
// >
// >     restricted-name = restricted-name-first *126restricted-name-chars
// >     restricted-name-first  = ALPHA / DIGIT
// >     restricted-name-chars  = ALPHA / DIGIT / "!" / "#" /
// >                              "$" / "&" / "-" / "^" / "_"
// >     restricted-name-chars =/ "." ; Characters before first dot always
// >                                  ; specify a facet name
// >     restricted-name-chars =/ "+" ; Characters after last plus always
// >                                  ; specify a structured syntax suffix
//
fn is_restricted_name_first_char(c: char) -> bool {
    match c {
        'a'...'z' |
        '0'...'9' => true,
        _ => false
    }
}

fn is_restricted_name_char(c: char) -> bool {
    if is_restricted_name_first_char(c) {
        true
    } else {
        match c {
            '!' |
            '#' |
            '$' |
            '&' |
            '-' |
            '^' |
            '.' |
            '+' |
            '_' => true,
            _ => false
        }
    }
}

#[inline]
fn fmt_params<T: AsSlice<Param>>(params: T, fmt: &mut fmt::Formatter) -> fmt::Result {
    for param in params.as_slice().iter() {
        try!(fmt_param(param, fmt));
    }
    Ok(())
}

#[inline]
fn fmt_param(param: &Param, fmt: &mut fmt::Formatter) -> fmt::Result {
    let (ref attr, ref value) = *param;
    write!(fmt, "; {}={}", attr, value)
}

#[cfg(test)]
mod tests {
    use std::from_str::{FromStr, from_str};
    use test::Bencher;
    use super::{Mime, Text, Plain, Charset, Utf8, AttrExt, ValueExt};

    #[test]
    fn test_mime_show() {
        let mime = Mime(Text, Plain, vec![]);
        assert_eq!(mime.to_string(), "text/plain".to_string());
        let mime = Mime(Text, Plain, vec![(Charset, Utf8)]);
        assert_eq!(mime.to_string(), "text/plain; charset=utf-8".to_string());
    }

    #[test]
    fn test_mime_from_str() {
        assert_eq!(FromStr::from_str("text/plain"), Some(Mime(Text, Plain, vec![])));
        assert_eq!(FromStr::from_str("TEXT/PLAIN"), Some(Mime(Text, Plain, vec![])));
        assert_eq!(FromStr::from_str("text/plain; charset=utf-8"), Some(Mime(Text, Plain, vec![(Charset, Utf8)])));
        assert_eq!(FromStr::from_str("text/plain;charset=\"utf-8\""), Some(Mime(Text, Plain, vec![(Charset, Utf8)])));
        assert_eq!(FromStr::from_str("text/plain; charset=utf-8; foo=bar"),
            Some(Mime(Text, Plain, vec![(Charset, Utf8),
                                        (AttrExt("foo".to_string()), ValueExt("bar".to_string())) ])));
    }

    #[bench]
    fn bench_show(b: &mut Bencher) {
        let mime = Mime(Text, Plain, vec![(Charset, Utf8), (AttrExt("foo".to_string()), ValueExt("bar".to_string()))]);
        b.bytes = mime.to_string().as_bytes().len() as u64;
        b.iter(|| mime.to_string())
    }

    #[bench]
    fn bench_from_str(b: &mut Bencher) {
        let s = "text/plain; charset=utf-8; foo=bar";
        b.bytes = s.as_bytes().len() as u64;
        b.iter(|| from_str::<Mime>(s))
    }
}
<|endoftext|>