<commit_before>// Copyright (C) 2016, 2017 Mark Lee

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate env_logger;
extern crate futures;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate redis;
extern crate regex;
extern crate reqwest;
extern crate rquery;
extern crate semver;
extern crate serde;
extern crate serde_json;

use hyper::{Get, StatusCode};
use hyper::header::{Accept, ContentType};
use hyper::server::{Http, Request, Response, Service};
use redis::{Commands, RedisError, RedisResult};
use regex::Regex;
use rquery::Document;
use semver::Version;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io;
use std::io::Read;

const DEFAULT_SERVER_PORT: u32 = 9000;
const DEFAULT_MIN_BUNDLER_VERSION: &'static str = "1.12.0";
const RUBY_LANGPACK_RELEASES_URL: &'static str = "https://github.\
                                                  com/heroku/heroku-buildpack-ruby/releases.atom";

fn download_url(url: &str) -> io::Result<String> {
    let mut resp = reqwest::get(url).expect("Could not send HTTP request");
    let mut body = String::new();
    match resp.read_to_string(&mut body) {
        Err(error) => Err(error),
        _ => Ok(body),
    }
}

fn download_latest_buildpack_release() -> String {
    let xml = download_url(RUBY_LANGPACK_RELEASES_URL).expect("Could not download Atom releases!");
    let atom_doc = Document::new_from_xml_string(&xml[..]).expect("Could not parse Atom releases!");
    atom_doc
        .select("entry id")
        .expect("Could not find latest buildpack tag!")
        .text()
        .rsplitn(2, '/')
        .next()
        .expect("No slashes in the GitHub release ID!")
        .to_string()
}

fn redis_cache_value(redis: &redis::Connection, key: &str, value: &str) -> String {
    let set_result: RedisResult<()> = redis.set_ex(key, value, 3600);
    if set_result.is_err() {
        warn!("Cannot set {} in Redis, ignoring", key);
    }
    value.to_owned()
}

fn redis_cache_hash_value(redis: &redis::Connection, hash_name: &str, key: &str, value: &str) {
    let set_result: RedisResult<()> = redis.hset_nx(hash_name, key, value);
    if set_result.is_err() {
        warn!("Cannot set {} in Redis, ignoring", key);
    }
}

fn latest_buildpack_release(redis_result: &RedisResult<redis::Connection>) -> String {
    if let Ok(ref redis) = *redis_result {
        if let Ok(buildpack_release) = redis.get("latest_buildpack_release") {
            buildpack_release
        } else {
            let buildpack_release = download_latest_buildpack_release();
            redis_cache_value(redis, "latest_buildpack_release", &buildpack_release[..])
        }
    } else {
        download_latest_buildpack_release()
    }
}

fn cached_version_from_buildpack_release(
    buildpack_release: &str,
    redis_result: &RedisResult<redis::Connection>,
) -> Option<String> {
    if let Ok(ref redis) = *redis_result {
        if let Ok(version) = redis.hget("bundler_version", buildpack_release) {
            Some(version)
        } else {
            None
        }
    } else {
        None
    }
}

fn bundler_version_from_ruby_buildpack(
    redis_result: &RedisResult<redis::Connection>,
) -> Option<String> {
    let buildpack_release = latest_buildpack_release(redis_result);
    if let Some(cached_version) =
        cached_version_from_buildpack_release(&buildpack_release[..], redis_result)
    {
        return Some(cached_version);
    }
    let ruby_langpack_url = format!(
        "https://raw.githubusercontent.com/\
                                     heroku/heroku-buildpack-ruby/{}/lib/language_pack/\
                                     ruby.rb",
        buildpack_release
    );
    let ruby_file = &download_url(&ruby_langpack_url[..]).expect("Could not download ruby.rb!")[..];
    let regex = Regex::new(r#"BUNDLER_VERSION += "(.+?)""#).expect("Invalid regular expression!");
    if regex.is_match(ruby_file) {
        let captures = regex.captures(ruby_file).expect("Could not match?!");
        let version_match = captures.get(1).expect("Capture not found?!");
        let version = version_match.as_str();
        if let Ok(ref redis) = *redis_result {
            redis_cache_hash_value(redis, "bundler_version", &buildpack_release[..], version);
        }
        Some(version.to_owned())
    } else {
        None
    }
}

fn is_bundler_upgraded(redis_result: &RedisResult<redis::Connection>) -> bool {
    let bundler_version_result = bundler_version_from_ruby_buildpack(redis_result);
    if let Some(buildpack_bundler_version_str) = bundler_version_result {
        let min_version =
            Version::parse(&min_bundler_version()[..]).expect("Could not parse min version!");
        let new_version = Version::parse(&buildpack_bundler_version_str[..]).expect(
            "Could not parse new version!",
        );
        min_version < new_version
    } else {
        false
    }
}

fn determine_content_type(headers: &hyper::Headers) -> ContentType {
    use std::ops::Deref;
    if headers.has::<Accept>() {
        let accept = headers
            .get::<Accept>()
            .expect("Accept header not found?!")
            .deref();
        let use_json = accept.into_iter().any(
            |qitem| qitem.item == "application/json",
        );

        if use_json {
            ContentType::json()
        } else {
            ContentType::html()
        }
    } else {
        ContentType::html()
    }
}

fn result_to_json(result: bool) -> String {
    let mut map = HashMap::new();
    map.insert("result".to_owned(), result);
    serde_json::to_string(&map).expect("Could not serialize result!")
}

fn result_to_html(result: bool) -> String {
    let result_str = if result {
        r#"
Yes
"#
    } else {
        r#"
No
"#
    };
    match File::open("index.html") {
        Ok(mut html_file) => {
            let mut html = String::new();
            html_file.read_to_string(&mut html).expect(
                "Could not read HTML file!",
            );
            html.replace("{{ is_bundler_upgraded }}", result_str)
                .replace("{{ MIN_BUNDLER_VERSION }}", &min_bundler_version()[..])
        }
        Err(error) => format!("HTML NOT FOUND: {}", error),
    }
}

fn min_bundler_version() -> String {
    match env::var("MIN_BUNDLER_VERSION") {
        Ok(version) => version,
        _ => String::from(DEFAULT_MIN_BUNDLER_VERSION),
    }
}

fn server_port() -> String {
    match env::var("PORT") {
        Ok(port) => port,
        _ => format!("{}", DEFAULT_SERVER_PORT),
    }
}

fn connect_to_redis() -> RedisResult<redis::Connection> {
    if let Ok(redis_url) = env::var("REDIS_URL") {
        let client = redis::Client::open(&redis_url[..]).expect("Cannot connect to Redis");
        client.get_connection()
    } else {
        Err(RedisError::from(
            io::Error::new(io::ErrorKind::Other, "REDIS_URL not found"),
        ))
    }
}

struct HBBUYServer;

impl Service for HBBUYServer {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = futures::future::FutureResult<Self::Response, Self::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let response = match (req.uri().path(), req.method()) {
            ("/", &Get) => {
                let redis = connect_to_redis();
                let result = is_bundler_upgraded(&redis);
                let content_type = determine_content_type(req.headers());
                let data = match &format!("{}", content_type)[..] {
                    "application/json" => result_to_json(result),
                    _ => result_to_html(result),
                };

                Response::new().with_header(content_type).with_body(data)
            }
            (_, &Get) => Response::new().with_status(StatusCode::NotFound),
            (_, _) => Response::new().with_status(StatusCode::MethodNotAllowed),
        };

        futures::future::ok(response)
    }
}

fn main() {
    env_logger::try_init().expect("Could not initialize env_logger!");
    let addr = format!("0.0.0.0:{}", server_port()).parse().expect(
        "Could not parse address/port",
    );
    let server = Http::new().bind(&addr, || Ok(HBBUYServer)).expect(
        "Could not create server!",
    );
    server.run().expect(
        "Could not set up HTTP request handler!",
    );
}
<commit_msg>[Rust] rustfmt<commit_after>// Copyright (C) 2016, 2017 Mark Lee

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

extern crate env_logger;
extern crate futures;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate redis;
extern crate regex;
extern crate reqwest;
extern crate rquery;
extern crate semver;
extern crate serde;
extern crate serde_json;

use hyper::{Get, StatusCode};
use hyper::header::{Accept, ContentType};
use hyper::server::{Http, Request, Response, Service};
use redis::{Commands, RedisError, RedisResult};
use regex::Regex;
use rquery::Document;
use semver::Version;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io;
use std::io::Read;

const DEFAULT_SERVER_PORT: u32 = 9000;
const DEFAULT_MIN_BUNDLER_VERSION: &'static str = "1.12.0";
const RUBY_LANGPACK_RELEASES_URL: &'static str = "https://github.\
                                                  com/heroku/heroku-buildpack-ruby/releases.atom";

fn download_url(url: &str) -> io::Result<String> {
    let mut resp = reqwest::get(url).expect("Could not send HTTP request");
    let mut body = String::new();
    match resp.read_to_string(&mut body) {
        Err(error) => Err(error),
        _ => Ok(body),
    }
}

fn download_latest_buildpack_release() -> String {
    let xml = download_url(RUBY_LANGPACK_RELEASES_URL).expect("Could not download Atom releases!");
    let atom_doc = Document::new_from_xml_string(&xml[..]).expect("Could not parse Atom releases!");
    atom_doc
        .select("entry id")
        .expect("Could not find latest buildpack tag!")
        .text()
        .rsplitn(2, '/')
        .next()
        .expect("No slashes in the GitHub release ID!")
        .to_string()
}

fn redis_cache_value(redis: &redis::Connection, key: &str, value: &str) -> String {
    let set_result: RedisResult<()> = redis.set_ex(key, value, 3600);
    if set_result.is_err() {
        warn!("Cannot set {} in Redis, ignoring", key);
    }
    value.to_owned()
}

fn redis_cache_hash_value(redis: &redis::Connection, hash_name: &str, key: &str, value: &str) {
    let set_result: RedisResult<()> = redis.hset_nx(hash_name, key, value);
    if set_result.is_err() {
        warn!("Cannot set {} in Redis, ignoring", key);
    }
}

fn latest_buildpack_release(redis_result: &RedisResult<redis::Connection>) -> String {
    if let Ok(ref redis) = *redis_result {
        if let Ok(buildpack_release) = redis.get("latest_buildpack_release") {
            buildpack_release
        } else {
            let buildpack_release = download_latest_buildpack_release();
            redis_cache_value(redis, "latest_buildpack_release", &buildpack_release[..])
        }
    } else {
        download_latest_buildpack_release()
    }
}

fn cached_version_from_buildpack_release(
    buildpack_release: &str,
    redis_result: &RedisResult<redis::Connection>,
) -> Option<String> {
    if let Ok(ref redis) = *redis_result {
        if let Ok(version) = redis.hget("bundler_version", buildpack_release) {
            Some(version)
        } else {
            None
        }
    } else {
        None
    }
}

fn bundler_version_from_ruby_buildpack(
    redis_result: &RedisResult<redis::Connection>,
) -> Option<String> {
    let buildpack_release = latest_buildpack_release(redis_result);
    if let Some(cached_version) =
        cached_version_from_buildpack_release(&buildpack_release[..], redis_result)
    {
        return Some(cached_version);
    }
    let ruby_langpack_url = format!(
        "https://raw.githubusercontent.com/\
         heroku/heroku-buildpack-ruby/{}/lib/language_pack/\
         ruby.rb",
        buildpack_release
    );
    let ruby_file = &download_url(&ruby_langpack_url[..]).expect("Could not download ruby.rb!")[..];
    let regex = Regex::new(r#"BUNDLER_VERSION += "(.+?)""#).expect("Invalid regular expression!");
    if regex.is_match(ruby_file) {
        let captures = regex.captures(ruby_file).expect("Could not match?!");
        let version_match = captures.get(1).expect("Capture not found?!");
        let version = version_match.as_str();
        if let Ok(ref redis) = *redis_result {
            redis_cache_hash_value(redis, "bundler_version", &buildpack_release[..], version);
        }
        Some(version.to_owned())
    } else {
        None
    }
}

fn is_bundler_upgraded(redis_result: &RedisResult<redis::Connection>) -> bool {
    let bundler_version_result = bundler_version_from_ruby_buildpack(redis_result);
    if let Some(buildpack_bundler_version_str) = bundler_version_result {
        let min_version =
            Version::parse(&min_bundler_version()[..]).expect("Could not parse min version!");
        let new_version = Version::parse(&buildpack_bundler_version_str[..])
            .expect("Could not parse new version!");
        min_version < new_version
    } else {
        false
    }
}

fn determine_content_type(headers: &hyper::Headers) -> ContentType {
    use std::ops::Deref;
    if headers.has::<Accept>() {
        let accept = headers
            .get::<Accept>()
            .expect("Accept header not found?!")
            .deref();
        let use_json = accept
            .into_iter()
            .any(|qitem| qitem.item == "application/json");

        if use_json {
            ContentType::json()
        } else {
            ContentType::html()
        }
    } else {
        ContentType::html()
    }
}

fn result_to_json(result: bool) -> String {
    let mut map = HashMap::new();
    map.insert("result".to_owned(), result);
    serde_json::to_string(&map).expect("Could not serialize result!")
}

fn result_to_html(result: bool) -> String {
    let result_str = if result {
        r#"
Yes
"#
    } else {
        r#"
No
"#
    };
    match File::open("index.html") {
        Ok(mut html_file) => {
            let mut html = String::new();
            html_file
                .read_to_string(&mut html)
                .expect("Could not read HTML file!");
            html.replace("{{ is_bundler_upgraded }}", result_str)
                .replace("{{ MIN_BUNDLER_VERSION }}", &min_bundler_version()[..])
        }
        Err(error) => format!("HTML NOT FOUND: {}", error),
    }
}

fn min_bundler_version() -> String {
    match env::var("MIN_BUNDLER_VERSION") {
        Ok(version) => version,
        _ => String::from(DEFAULT_MIN_BUNDLER_VERSION),
    }
}

fn server_port() -> String {
    match env::var("PORT") {
        Ok(port) => port,
        _ => format!("{}", DEFAULT_SERVER_PORT),
    }
}

fn connect_to_redis() -> RedisResult<redis::Connection> {
    if let Ok(redis_url) = env::var("REDIS_URL") {
        let client = redis::Client::open(&redis_url[..]).expect("Cannot connect to Redis");
        client.get_connection()
    } else {
        Err(RedisError::from(io::Error::new(
            io::ErrorKind::Other,
            "REDIS_URL not found",
        )))
    }
}

struct HBBUYServer;

impl Service for HBBUYServer {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = futures::future::FutureResult<Self::Response, Self::Error>;

    fn call(&self, req: Request) -> Self::Future {
        let response = match (req.uri().path(), req.method()) {
            ("/", &Get) => {
                let redis = connect_to_redis();
                let result = is_bundler_upgraded(&redis);
                let content_type = determine_content_type(req.headers());
                let data = match &format!("{}", content_type)[..] {
                    "application/json" => result_to_json(result),
                    _ => result_to_html(result),
                };

                Response::new().with_header(content_type).with_body(data)
            }
            (_, &Get) => Response::new().with_status(StatusCode::NotFound),
            (_, _) => Response::new().with_status(StatusCode::MethodNotAllowed),
        };

        futures::future::ok(response)
    }
}

fn main() {
    env_logger::try_init().expect("Could not initialize env_logger!");
    let addr = format!("0.0.0.0:{}", server_port())
        .parse()
        .expect("Could not parse address/port");
    let server = Http::new()
        .bind(&addr, || Ok(HBBUYServer))
        .expect("Could not create server!");
    server
        .run()
        .expect("Could not set up HTTP request handler!");
}
<|endoftext|>


<commit_before>fn main() {
    println!("Hello, world!");
}
<commit_msg>Playing with threads<commit_after>#![feature(macro_rules, phase, slicing_syntax)]

use std::thread::Thread;
use std::io::Timer;
use std::rand;
use std::time::Duration;

static N_THREADS: int = 1000;

fn main() {
    let _ = (0..N_THREADS).map( |i| Thread::spawn(move || {
        let t = rand::random::<u8>();
        println!("this is thread number {}, sleeping for {}", i, t);
        let mut timer = Timer::new().unwrap();
        timer.sleep(Duration::milliseconds(t as i64));
        println!("this is thread number {}, finished sleeping for {}", i, t);
    })).collect::<Vec<_>>();
}
<|endoftext|>


<commit_before>#![feature(phase)]
extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;
extern crate graphviz;
extern crate serialize;

use cargo::core::resolver::Resolve;
use cargo::core::source::SourceId;
use docopt::{Error, FlagParser};
use graphviz as dot;
use std::io::File;
use std::str;

docopt!(Flags, "
Usage: cargo dot [options]
       cargo dot --help

Options:
    -h, --help         Show this message
    -V, --version      Print version info and exit
    --lock-file=FILE   Specify location of input file, default \"Cargo.lock\"
    --dot-file=FILE    Specify location of output file, default \"Cargo.dot\"
")

fn main() {
    let config = docopt::Config { version: Some("0.1.0".to_string()) , ..docopt::DEFAULT_CONFIG };
    let flags: Flags = FlagParser::parse_conf(config).unwrap_or_else(|e| e.exit());
    let lock_file = unless_empty(flags.flag_lock_file, "Cargo.lock");
    let dot_file  = unless_empty(flags.flag_dot_file, "Cargo.dot");

    // TODO: figure out how to get rid of this.
    let dummy_src_id = SourceId::from_url("git+https://github.com/doopdoop/dodoododo#b3a9dee814af4846267383c800999a42b295e0d2".to_string());
    let resolved = cargo::ops::load_lockfile(&Path::new(lock_file), &dummy_src_id)
                     .unwrap_or_else(|e| exit_with(e.description().as_slice()))
                     .unwrap_or_else(||  exit_with("Lock file not found."));
    let root = resolved.root();
    let name = root.get_name().to_string();
    let mut nodes = vec!(name);
    let mut edges = vec!();
    add_deps(&mut nodes, &mut edges, &resolved);

    let graph = Graph { nodes: nodes, edges: edges };
    let mut f = File::create(&Path::new(dot_file));

    graph.render_to(&mut f);
}

fn exit_with(s: &str) -> ! {
    fail!("Error parsing lockfile: {}", s)
}

fn unless_empty(s: String, default: &str) -> String {
    if s.is_empty() {
        default.to_string()
    } else {
        s
    }
}

fn add_deps(nodes: &mut Vec<String>, edges: &mut Vec<(uint, uint)>, resolved: &Resolve) {
    for crat in resolved.iter() {
        match resolved.deps(crat) {
            Some(mut crate_deps) => {
                let name = crat.get_name().to_string(); // TODO: move strs around to reduce allocation
                let idl = add_or_find(nodes, name);
                for dep in crate_deps {
                    let dep_name = dep.get_name().to_string(); // TODO: same
                    let idr = add_or_find(nodes, dep_name);
                    edges.push((idl, idr));
                };
            },
            None => { }
        }
    }
}

fn add_or_find(nodes: &mut Vec<String>, new: String) -> uint {
    for i in range(0, nodes.len()) {
        let ref s = (*nodes)[i];
        if *s == new {
            return i
        }
    }
    nodes.push(new);
    nodes.len() - 1
}

type Nd = uint;
type Ed<'a> = &'a (uint, uint);
struct Graph { nodes: Vec<String>,
               edges: Vec<(uint,uint)>,
             }

impl Graph {
    fn render_to<W:Writer>(self, output: &mut W) {
        dot::render(&self, output).unwrap()
    }
}

impl<'a> dot::Labeller<'a, Nd, Ed<'a>> for Graph {
    fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example3") }
    fn node_id(&'a self, n: &Nd) -> dot::Id {
        dot::Id::new(format!("N{:u}", *n))
    }
    fn node_label<'a>(&'a self, i: &Nd) -> dot::LabelText<'a> {
        dot::LabelStr(str::Slice(self.nodes[*i].as_slice()))
    }
}

impl<'a> dot::GraphWalk<'a, Nd, Ed<'a>> for Graph {
    fn nodes(&'a self) -> dot::Nodes<'a,Nd> {
        range(0, self.nodes.len()).collect()
    }
    fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> {
        self.edges.iter().collect()
    }
    fn source(&self, e: &Ed) -> Nd { let &(s,_) = *e; s }
    fn target(&self, e: &Ed) -> Nd { let &(_,t) = *e; t }
}
<commit_msg>Remove String allocations.<commit_after>#![feature(phase)]
extern crate cargo;
extern crate docopt;
#[phase(plugin)] extern crate docopt_macros;
extern crate graphviz;
extern crate serialize;

use cargo::core::resolver::Resolve;
use cargo::core::source::SourceId;
use docopt::{Error, FlagParser};
use graphviz as dot;
use std::io::File;
use std::str;

docopt!(Flags, "
Usage: cargo dot [options]
       cargo dot --help

Options:
    -h, --help         Show this message
    -V, --version      Print version info and exit
    --lock-file=FILE   Specify location of input file, default \"Cargo.lock\"
    --dot-file=FILE    Specify location of output file, default \"Cargo.dot\"
")

fn main() {
    let config = docopt::Config { version: Some("0.1.0".to_string()) , ..docopt::DEFAULT_CONFIG };
    let flags: Flags = FlagParser::parse_conf(config).unwrap_or_else(|e| e.exit());
    let lock_file = unless_empty(flags.flag_lock_file, "Cargo.lock");
    let dot_file  = unless_empty(flags.flag_dot_file, "Cargo.dot");

    // TODO: figure out how to get rid of this.
    let dummy_src_id = SourceId::from_url("git+https://github.com/doopdoop/dodoododo#b3a9dee814af4846267383c800999a42b295e0d2".to_string());
    let resolved = cargo::ops::load_lockfile(&Path::new(lock_file), &dummy_src_id)
                     .unwrap_or_else(|e| exit_with(e.description().as_slice()))
                     .unwrap_or_else(||  exit_with("Lock file not found."));
    let root = resolved.root();
    let name = root.get_name();
    let mut nodes = vec!(name);
    let mut edges = vec!();
    add_deps(&mut nodes, &mut edges, &resolved);

    let graph = Graph { nodes: nodes, edges: edges };
    let mut f = File::create(&Path::new(dot_file));

    graph.render_to(&mut f);
}

fn exit_with(s: &str) -> ! {
    fail!("Error parsing lockfile: {}", s)
}

fn unless_empty(s: String, default: &str) -> String {
    if s.is_empty() {
        default.to_string()
    } else {
        s
    }
}

fn add_deps<'a>(nodes: &mut Vec<&'a str>, edges: &mut Vec<(uint, uint)>, resolved: &'a Resolve) {
    for crat in resolved.iter() {
        match resolved.deps(crat) {
            Some(mut crate_deps) => {
                let name = crat.get_name();
                let idl = add_or_find(nodes, name);
                for dep in crate_deps {
                    let dep_name = dep.get_name();
                    let idr = add_or_find(nodes, dep_name);
                    edges.push((idl, idr));
                };
            },
            None => { }
        }
    }
}

fn add_or_find<'a>(nodes: &mut Vec<&'a str>, new: &'a str) -> uint {
    for (i, s) in nodes.iter().enumerate() {
        if s.as_slice() == new {
            return i
        }
    }
    nodes.push(new);
    nodes.len() - 1
}

type Nd = uint;
type Ed<'a> = &'a (uint, uint);
struct Graph<'a> {
    nodes: Vec<&'a str>,
    edges: Vec<(uint,uint)>,
}

impl<'a> Graph<'a> {
    fn render_to<W:Writer>(&'a self, output: &mut W) {
        dot::render(self, output).unwrap()
    }
}

impl<'a> dot::Labeller<'a, Nd, Ed<'a>> for Graph<'a> {
    fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new("example3") }
    fn node_id(&'a self, n: &Nd) -> dot::Id {
        dot::Id::new(format!("N{:u}", *n))
    }
    fn node_label<'a>(&'a self, i: &Nd) -> dot::LabelText<'a> {
        dot::LabelStr(str::Slice(self.nodes[*i].as_slice()))
    }
}

impl<'a> dot::GraphWalk<'a, Nd, Ed<'a>> for Graph<'a> {
    fn nodes(&'a self) -> dot::Nodes<'a,Nd> {
        range(0, self.nodes.len()).collect()
    }
    fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> {
        self.edges.iter().collect()
    }
    fn source(&self, e: &Ed) -> Nd { let &(s,_) = *e; s }
    fn target(&self, e: &Ed) -> Nd { let &(_,t) = *e; t }
}
<|endoftext|>


<commit_before>use std::io::{self, Write};

const HEADER_LEN: usize = 110;

pub struct Builder {
    name: String,
    ino: u32,
    mode: u32,
    uid: u32,
    gid: u32,
    nlink: u32,
    mtime: u32,
    dev_major: u32,
    dev_minor: u32,
    rdev_major: u32,
    rdev_minor: u32,
}

pub struct Writer<W: Write> {
    inner: W,
    written: u32,
    file_size: u32,
    header_size: usize,
    header: Vec<u8>,
}

fn pad(len: usize) -> Option<Vec<u8>> {
    // pad out to a multiple of 4 bytes
    let overhang = len % 4;
    if overhang != 0 {
        let repeat = 4 - overhang;
        Some(vec![0u8; repeat])
    } else {
        None
    }
}

impl Builder {
    pub fn new(name: &str) -> Builder {
        Builder {
            name: name.to_string(),
            ino: 0,
            mode: 0,
            uid: 0,
            gid: 0,
            nlink: 1,
            mtime: 0,
            dev_major: 0,
            dev_minor: 0,
            rdev_major: 0,
            rdev_minor: 0,
        }
    }

    pub fn ino(mut self, ino: u32) -> Builder {
        self.ino = ino;
        self
    }

    pub fn mode(mut self, mode: u32) -> Builder {
        self.mode = mode;
        self
    }

    pub fn uid(mut self, uid: u32) -> Builder {
        self.uid = uid;
        self
    }

    pub fn gid(mut self, gid: u32) -> Builder {
        self.gid = gid;
        self
    }

    pub fn nlink(mut self, nlink: u32) -> Builder {
        self.nlink = nlink;
        self
    }

    pub fn mtime(mut self, mtime: u32) -> Builder {
        self.mtime = mtime;
        self
    }

    pub fn dev_major(mut self, dev_major: u32) -> Builder {
        self.dev_major = dev_major;
        self
    }

    pub fn dev_minor(mut self, dev_minor: u32) -> Builder {
        self.dev_minor = dev_minor;
        self
    }

    pub fn rdev_major(mut self, rdev_major: u32) -> Builder {
        self.rdev_major = rdev_major;
        self
    }

    pub fn rdev_minor(mut self, rdev_minor: u32) -> Builder {
        self.rdev_minor = rdev_minor;
        self
    }

    pub fn write<W: Write>(self, w: W, file_size: u32) -> Writer<W> {
        let header = self.into_header(file_size);

        Writer {
            inner: w,
            written: 0,
            file_size: file_size,
            header_size: header.len(),
            header: header,
        }
    }

    fn into_header(self, file_size: u32) -> Vec<u8> {
        let mut header = Vec::with_capacity(HEADER_LEN);

        // char    c_magic[6];
        header.extend("070701".to_string().as_bytes());
        // char    c_ino[8];
        header.extend(format!("{:08x}", self.ino).as_bytes());
        // char    c_mode[8];
        header.extend(format!("{:08x}", self.mode).as_bytes());
        // char    c_uid[8];
        header.extend(format!("{:08x}", self.uid).as_bytes());
        // char    c_gid[8];
        header.extend(format!("{:08x}", self.gid).as_bytes());
        // char    c_nlink[8];
        header.extend(format!("{:08x}", self.nlink).as_bytes());
        // char    c_mtime[8];
        header.extend(format!("{:08x}", self.mtime).as_bytes());
        // char    c_filesize[8];
        header.extend(format!("{:08x}", file_size).as_bytes());
        // char    c_devmajor[8];
        header.extend(format!("{:08x}", self.dev_major).as_bytes());
        // char    c_devminor[8];
        header.extend(format!("{:08x}", self.dev_minor).as_bytes());
        // char    c_rdevmajor[8];
        header.extend(format!("{:08x}", self.rdev_major).as_bytes());
        // char    c_rdevminor[8];
        header.extend(format!("{:08x}", self.rdev_minor).as_bytes());
        // char    c_namesize[8];
        let name_len = self.name.len() + 1;
        header.extend(format!("{:08x}", name_len).as_bytes());
        // char    c_check[8];
        header.extend(format!("{:08x}", 0).as_bytes());

        // append the name to the end of the header
        header.extend(self.name.as_bytes());
        header.push(0u8);

        // pad out to a multiple of 4 bytes
        if let Some(pad) = pad(HEADER_LEN + name_len) {
            header.extend(pad);
        }

        header
    }
}

impl<W: Write> Writer<W> {
    pub fn finish(mut self) -> io::Result<W> {
        try!(self.do_finish());
        Ok(self.inner)
    }

    fn try_write_header(&mut self) -> io::Result<()> {
        if self.header.len() != 0 {
            try!(self.inner.write_all(&self.header));
            self.header.truncate(0);
        }
        Ok(())
    }

    fn do_finish(&mut self) -> io::Result<()> {
        try!(self.try_write_header());

        if self.written == self.file_size {
            if let Some(pad) = pad(self.header_size + self.file_size as usize) {
                try!(self.inner.write(&pad));
                try!(self.inner.flush());
            }
        }

        Ok(())
    }
}

impl<W: Write> Write for Writer<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.written + buf.len() as u32 <= self.file_size {
            try!(self.try_write_header());

            let n = try!(self.inner.write(buf));
            self.written += n as u32;
            Ok(n)
        } else {
            Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                               "trying to write more than the specified file size"))
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.flush()
    }
}

pub fn trailer<W: Write>(w: W) -> io::Result<()> {
    let b = Builder::new("TRAILER!!!").nlink(0);
    let writer = b.write(w, 0);
    let _ = try!(writer.finish());
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::{copy, Cursor};

    #[test]
    fn test_single_file() {
        // Set up our input file
        let data = "Hello, World".to_string();
        let length = data.len() as u32;
        let mut input = Cursor::new(data);

        // Set up our output file
        let output = Cursor::new(vec![]);

        // Set up the descriptor of our input file
        let b = Builder::new("./hello_world");
        // and get a writer for that input file
        let mut writer = b.write(output, length);

        // Copy the input file into our CPIO archive
        copy(&mut input, &mut writer).unwrap();
        let output = writer.finish().unwrap();

        // Finish up by writing the trailer for the archive
        trailer(output).unwrap();
    }

    #[test]
    fn test_multi_file() {
        // Set up our input files
        let data1 = "Hello, World".to_string();
        let length1 = data1.len() as u32;
        let mut input1 = Cursor::new(data1);

        let data2 = "Hello, World 2".to_string();
        let length2 = data2.len() as u32;
        let mut input2 = Cursor::new(data2);

        // Set up our output file
        let output = Cursor::new(vec![]);

        // Set up the descriptor of our input file
        let b = Builder::new("./hello_world")
            .ino(1)
            .uid(1000)
            .gid(1000)
            .mode(0o100644);
        // and get a writer for that input file
        let mut writer = b.write(output, length1);

        // Copy the input file into our CPIO archive
        copy(&mut input1, &mut writer).unwrap();
        let output = writer.finish().unwrap();

        // Set up the descriptor of our second input file
        let b = Builder::new("./hello_world2")
            .ino(2)
            .uid(1000)
            .gid(1000)
            .mode(0o100644);
        // and get a writer for that input file
        let mut writer = b.write(output, length2);

        // Copy the second input file into our CPIO archive
        copy(&mut input2, &mut writer).unwrap();
        let output = writer.finish().unwrap();

        // Finish up by writing the trailer for the archive
        trailer(output).unwrap();
    }
}
<commit_msg>the trailer function should return the writer<commit_after>use std::io::{self, Write};

const HEADER_LEN: usize = 110;

pub struct Builder {
    name: String,
    ino: u32,
    mode: u32,
    uid: u32,
    gid: u32,
    nlink: u32,
    mtime: u32,
    dev_major: u32,
    dev_minor: u32,
    rdev_major: u32,
    rdev_minor: u32,
}

pub struct Writer<W: Write> {
    inner: W,
    written: u32,
    file_size: u32,
    header_size: usize,
    header: Vec<u8>,
}

fn pad(len: usize) -> Option<Vec<u8>> {
    // pad out to a multiple of 4 bytes
    let overhang = len % 4;
    if overhang != 0 {
        let repeat = 4 - overhang;
        Some(vec![0u8; repeat])
    } else {
        None
    }
}

impl Builder {
    pub fn new(name: &str) -> Builder {
        Builder {
            name: name.to_string(),
            ino: 0,
            mode: 0,
            uid: 0,
            gid: 0,
            nlink: 1,
            mtime: 0,
            dev_major: 0,
            dev_minor: 0,
            rdev_major: 0,
            rdev_minor: 0,
        }
    }

    pub fn ino(mut self, ino: u32) -> Builder {
        self.ino = ino;
        self
    }

    pub fn mode(mut self, mode: u32) -> Builder {
        self.mode = mode;
        self
    }

    pub fn uid(mut self, uid: u32) -> Builder {
        self.uid = uid;
        self
    }

    pub fn gid(mut self, gid: u32) -> Builder {
        self.gid = gid;
        self
    }

    pub fn nlink(mut self, nlink: u32) -> Builder {
        self.nlink = nlink;
        self
    }

    pub fn mtime(mut self, mtime: u32) -> Builder {
        self.mtime = mtime;
        self
    }

    pub fn dev_major(mut self, dev_major: u32) -> Builder {
        self.dev_major = dev_major;
        self
    }

    pub fn dev_minor(mut self, dev_minor: u32) -> Builder {
        self.dev_minor = dev_minor;
        self
    }

    pub fn rdev_major(mut self, rdev_major: u32) -> Builder {
        self.rdev_major = rdev_major;
        self
    }

    pub fn rdev_minor(mut self, rdev_minor: u32) -> Builder {
        self.rdev_minor = rdev_minor;
        self
    }

    pub fn write<W: Write>(self, w: W, file_size: u32) -> Writer<W> {
        let header = self.into_header(file_size);

        Writer {
            inner: w,
            written: 0,
            file_size: file_size,
            header_size: header.len(),
            header: header,
        }
    }

    fn into_header(self, file_size: u32) -> Vec<u8> {
        let mut header = Vec::with_capacity(HEADER_LEN);

        // char    c_magic[6];
        header.extend("070701".to_string().as_bytes());
        // char    c_ino[8];
        header.extend(format!("{:08x}", self.ino).as_bytes());
        // char    c_mode[8];
        header.extend(format!("{:08x}", self.mode).as_bytes());
        // char    c_uid[8];
        header.extend(format!("{:08x}", self.uid).as_bytes());
        // char    c_gid[8];
        header.extend(format!("{:08x}", self.gid).as_bytes());
        // char    c_nlink[8];
        header.extend(format!("{:08x}", self.nlink).as_bytes());
        // char    c_mtime[8];
        header.extend(format!("{:08x}", self.mtime).as_bytes());
        // char    c_filesize[8];
        header.extend(format!("{:08x}", file_size).as_bytes());
        // char    c_devmajor[8];
        header.extend(format!("{:08x}", self.dev_major).as_bytes());
        // char    c_devminor[8];
        header.extend(format!("{:08x}", self.dev_minor).as_bytes());
        // char    c_rdevmajor[8];
        header.extend(format!("{:08x}", self.rdev_major).as_bytes());
        // char    c_rdevminor[8];
        header.extend(format!("{:08x}", self.rdev_minor).as_bytes());
        // char    c_namesize[8];
        let name_len = self.name.len() + 1;
        header.extend(format!("{:08x}", name_len).as_bytes());
        // char    c_check[8];
        header.extend(format!("{:08x}", 0).as_bytes());

        // append the name to the end of the header
        header.extend(self.name.as_bytes());
        header.push(0u8);

        // pad out to a multiple of 4 bytes
        if let Some(pad) = pad(HEADER_LEN + name_len) {
            header.extend(pad);
        }

        header
    }
}

impl<W: Write> Writer<W> {
    pub fn finish(mut self) -> io::Result<W> {
        try!(self.do_finish());
        Ok(self.inner)
    }

    fn try_write_header(&mut self) -> io::Result<()> {
        if self.header.len() != 0 {
            try!(self.inner.write_all(&self.header));
            self.header.truncate(0);
        }
        Ok(())
    }

    fn do_finish(&mut self) -> io::Result<()> {
        try!(self.try_write_header());

        if self.written == self.file_size {
            if let Some(pad) = pad(self.header_size + self.file_size as usize) {
                try!(self.inner.write(&pad));
                try!(self.inner.flush());
            }
        }

        Ok(())
    }
}

impl<W: Write> Write for Writer<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        if self.written + buf.len() as u32 <= self.file_size {
            try!(self.try_write_header());

            let n = try!(self.inner.write(buf));
            self.written += n as u32;
            Ok(n)
        } else {
            Err(io::Error::new(io::ErrorKind::UnexpectedEof,
                               "trying to write more than the specified file size"))
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.flush()
    }
}

pub fn trailer<W: Write>(w: W) -> io::Result<W> {
    let b = Builder::new("TRAILER!!!").nlink(0);
    let writer = b.write(w, 0);
    let w = try!(writer.finish());
    Ok(w)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io::{copy, Cursor};

    #[test]
    fn test_single_file() {
        // Set up our input file
        let data = "Hello, World".to_string();
        let length = data.len() as u32;
        let mut input = Cursor::new(data);

        // Set up our output file
        let output = Cursor::new(vec![]);

        // Set up the descriptor of our input file
        let b = Builder::new("./hello_world");
        // and get a writer for that input file
        let mut writer = b.write(output, length);

        // Copy the input file into our CPIO archive
        copy(&mut input, &mut writer).unwrap();
        let output = writer.finish().unwrap();

        // Finish up by writing the trailer for the archive
        trailer(output).unwrap();
    }

    #[test]
    fn test_multi_file() {
        // Set up our input files
        let data1 = "Hello, World".to_string();
        let length1 = data1.len() as u32;
        let mut input1 = Cursor::new(data1);

        let data2 = "Hello, World 2".to_string();
        let length2 = data2.len() as u32;
        let mut input2 = Cursor::new(data2);

        // Set up our output file
        let output = Cursor::new(vec![]);

        // Set up the descriptor of our input file
        let b = Builder::new("./hello_world")
            .ino(1)
            .uid(1000)
            .gid(1000)
            .mode(0o100644);
        // and get a writer for that input file
        let mut writer = b.write(output, length1);

        // Copy the input file into our CPIO archive
        copy(&mut input1, &mut writer).unwrap();
        let output = writer.finish().unwrap();

        // Set up the descriptor of our second input file
        let b = Builder::new("./hello_world2")
            .ino(2)
            .uid(1000)
            .gid(1000)
            .mode(0o100644);
        // and get a writer for that input file
        let mut writer = b.write(output, length2);

        // Copy the second input file into our CPIO archive
        copy(&mut input2, &mut writer).unwrap();
        let output = writer.finish().unwrap();

        // Finish up by writing the trailer for the archive
        trailer(output).unwrap();
    }
}
<|endoftext|>


<commit_before>use libc::c_uint;
use ffi::prelude::LLVMPassManagerRef;
use ffi::core;
use ffi::transforms::pass_manager_builder as builder;
use ffi::transforms::pass_manager_builder::LLVMPassManagerBuilderRef;
use module::Module;

/// Runs transformations on bitcode
pub struct PassManager {
    manager: LLVMPassManagerRef
}
native_ref!(PassManager, manager: LLVMPassManagerRef);
impl PassManager {
    /// Create a new pass manager
    pub fn new() -> PassManager {
        unsafe { core::LLVMCreatePassManager() }.into()
    }
    /// Run this pass manager
    pub fn run(&self, module: &Module) -> Result<(), ()> {
        if unsafe { core::LLVMRunPassManager(self.into(), module.into()) } == 0 {
            Ok(())
        } else {
            Err(())
        }
    }

    pub fn populate(&self, builder: PassManagerBuilder) {
        unsafe { builder::LLVMPassManagerBuilderPopulateModulePassManager(builder.into(), self.into()) }
    }
}
impl Drop for PassManager {
    fn drop(&mut self) {
        unsafe { core::LLVMDisposePassManager(self.into()) }
    }
}
pub struct PassManagerBuilder {
    builder: LLVMPassManagerBuilderRef
}
native_ref!(PassManagerBuilder, builder: LLVMPassManagerBuilderRef);
impl PassManagerBuilder {
    /// Set the optimisation level of the pass manager
    pub fn set_opt_level(&self, level: usize) {
        unsafe { builder::LLVMPassManagerBuilderSetOptLevel(self.into(), level as c_uint) }
    }
    /// Set the size level of the pass manager
    pub fn set_size_level(&self, size: usize) {
        unsafe { builder::LLVMPassManagerBuilderSetOptLevel(self.into(), size as c_uint) }
    }
}
impl Drop for PassManagerBuilder {
    fn drop(&mut self) {
        unsafe { builder::LLVMPassManagerBuilderDispose(self.into()) }
    }
}
<commit_msg>Add `add_target_data` method to `PassManager`<commit_after>use libc::c_uint;
use ffi::prelude::LLVMPassManagerRef;
use ffi::{core, target};
use ffi::transforms::pass_manager_builder as builder;
use ffi::transforms::pass_manager_builder::LLVMPassManagerBuilderRef;
use module::Module;
use target::TargetData;

/// Runs transformations on bitcode
pub struct PassManager {
    manager: LLVMPassManagerRef
}
native_ref!(PassManager, manager: LLVMPassManagerRef);
impl PassManager {
    /// Create a new pass manager
    pub fn new() -> PassManager {
        unsafe { core::LLVMCreatePassManager() }.into()
    }
    /// Adds target data information to a pass manage
    pub fn add_target_data(&self, data: &TargetData) {
        unsafe { target::LLVMAddTargetData(data.into(), self.into()) }
    }
    /// Run this pass manager
    pub fn run(&self, module: &Module) -> Result<(), ()> {
        if unsafe { core::LLVMRunPassManager(self.into(), module.into()) } == 0 {
            Ok(())
        } else {
            Err(())
        }
    }

    pub fn populate(&self, builder: PassManagerBuilder) {
        unsafe { builder::LLVMPassManagerBuilderPopulateModulePassManager(builder.into(), self.into()) }
    }
}
impl Drop for PassManager {
    fn drop(&mut self) {
        unsafe { core::LLVMDisposePassManager(self.into()) }
    }
}
pub struct PassManagerBuilder {
    builder: LLVMPassManagerBuilderRef
}
native_ref!(PassManagerBuilder, builder: LLVMPassManagerBuilderRef);
impl PassManagerBuilder {
    /// Set the optimisation level of the pass manager
    pub fn set_opt_level(&self, level: usize) {
        unsafe { builder::LLVMPassManagerBuilderSetOptLevel(self.into(), level as c_uint) }
    }
    /// Set the size level of the pass manager
    pub fn set_size_level(&self, size: usize) {
        unsafe { builder::LLVMPassManagerBuilderSetOptLevel(self.into(), size as c_uint) }
    }
}
impl Drop for PassManagerBuilder {
    fn drop(&mut self) {
        unsafe { builder::LLVMPassManagerBuilderDispose(self.into()) }
    }
}
<|endoftext|>


<commit_before>use summary::Summary;

struct BoxWhiskerData {
    box_lo: f64,
    box_mid: f64,
    box_hi: f64,
    wh_lo: f64,
    wh_hi: f64,
}

impl BoxWhiskerData {
    fn from_summary(summary: &Summary) -> Self {
        BoxWhiskerData {
            box_lo: summary.percentile(0.25).unwrap(),
            box_mid: summary.median(),
            box_hi: summary.percentile(0.75).unwrap(),
            wh_lo: summary.min(),
            wh_hi: summary.max(),
        }
    }
}

struct BoxWhiskerCols {
    box_lo: usize,
    box_mid: usize,
    box_hi: usize,
    wh_lo: usize,
    wh_hi: usize,
}

impl BoxWhiskerCols {
    fn new(data: &BoxWhiskerData, width: usize) -> Self {
        let max_col = width - 1;
        let range = data.wh_hi - data.wh_lo;
        let normalize = |x| (x - data.wh_lo) / range;
        let scale = |x| (normalize(x) * (max_col as f64)) as f64;
        let to_col = |x| scale(x).floor() as usize;

        BoxWhiskerCols {
            box_lo: to_col(data.box_lo),
            box_mid: to_col(data.box_mid),
            box_hi: to_col(data.box_hi),
            wh_lo: to_col(data.wh_lo),
            wh_hi: to_col(data.wh_hi),
        }
    }
}

fn make_row(width: usize) -> Vec<String> {
    use std::iter::repeat;

    let mut row = vec![];
    row.extend(repeat(String::from("")).take(width));

    row
}

struct Plot(Vec<String>, Vec<String>, Vec<String>);

impl Plot {
    fn new(width: usize) -> Self {
        Plot(make_row(width), make_row(width), make_row(width))
    }

    fn render(&self) -> String {
        let rows = vec![
            self.0.join(""),
            self.1.join(""),
            self.2.join(""),
        ];

        rows.join("\n")
    }
}

struct RowChars {
    wh_lo: String,
    wh_lo_box_lo_fill: String,
    box_lo: String,
    box_lo_box_mid_fill: String,
    box_mid: String,
    box_mid_box_hi_fill: String,
    box_hi: String,
    box_hi_wh_hi_fill: String,
    wh_hi: String,
}

impl RowChars {
    fn render(&self, row: &mut Vec<String>, cols: &BoxWhiskerCols) {
        row[cols.wh_lo] = self.wh_lo.clone();
        for i in (cols.wh_lo + 1)..cols.box_lo {
            row[i] = self.wh_lo_box_lo_fill.clone();
        }
        row[cols.box_lo] = self.box_lo.clone();
        for i in (cols.box_lo + 1)..cols.box_mid {
            row[i] = self.box_lo_box_mid_fill.clone();
        }
        row[cols.box_mid] = self.box_mid.clone();
        for i in (cols.box_mid + 1)..cols.box_hi {
            row[i] = self.box_mid_box_hi_fill.clone();
        }
        row[cols.box_hi] = self.box_hi.clone();
        for i in (cols.box_hi + 1)..cols.wh_hi {
            row[i] = self.box_hi_wh_hi_fill.clone();
        }
        row[cols.wh_hi] = self.wh_hi.clone();
    }
}

pub fn summary_plot(summary: &Summary, width: usize) -> String {
    let data = BoxWhiskerData::from_summary(summary);
    let cols = BoxWhiskerCols::new(&data, width);

    let mut plot = Plot::new(width);

    let chars1 = RowChars {
        wh_lo: String::from("┬"),
        wh_lo_box_lo_fill: String::from(" "),
        box_lo: String::from("┌"),
        box_lo_box_mid_fill: String::from("─"),
        box_mid: String::from("┬"),
        box_mid_box_hi_fill: String::from("─"),
        box_hi: String::from("┐"),
        box_hi_wh_hi_fill: String::from(" "),
        wh_hi: String::from("┬"),
    };
    chars1.render(&mut plot.0, &cols);

    let chars2 = RowChars {
        wh_lo: String::from("├"),
        wh_lo_box_lo_fill: String::from("─"),
        box_lo: String::from("┤"),
        box_lo_box_mid_fill: String::from(" "),
        box_mid: String::from("│"),
        box_mid_box_hi_fill: String::from(" "),
        box_hi: String::from("├"),
        box_hi_wh_hi_fill: String::from("─"),
        wh_hi: String::from("┤"),
    };
    chars2.render(&mut plot.1, &cols);

    let chars3 = RowChars {
        wh_lo: String::from("┴"),
        wh_lo_box_lo_fill: String::from(" "),
        box_lo: String::from("└"),
        box_lo_box_mid_fill: String::from("─"),
        box_mid: String::from("┴"),
        box_mid_box_hi_fill: String::from("─"),
        box_hi: String::from("┘"),
        box_hi_wh_hi_fill: String::from(" "),
        wh_hi: String::from("┴"),
    };
    chars3.render(&mut plot.2, &cols);

    plot.render()
}

fn make_padding(cols: usize) -> String {
    use std::iter::{FromIterator, repeat};

    String::from_iter(repeat(String::from(" ")).take(cols))
}

fn pad(s: &String, cols: usize) -> String {
    let padding = make_padding(cols);

    let padded: Vec<String> = s
        .split("\n")
        .map(|l| format!("{}{}", padding, l))
        .collect();

    padded.join("\n")
}

pub fn comparison_plot(
    summary1: &Summary,
    summary2: &Summary,
    width: usize,
) -> String {
    let min = summary1.min().min(summary2.min());
    let max = summary1.max().max(summary2.max());

    let range = max - min;
    let range1 = summary1.max() - summary1.min();
    let range2 = summary2.max() - summary2.min();

    let proportion1 = range1 / range;
    let proportion2 = range2 / range;

    let width1 = (proportion1 * (width as f64)).floor() as usize;
    let width2 = (proportion2 * (width as f64)).floor() as usize;

    let offset1 = {
        let neg_proportion = (summary1.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };
    let offset2 = {
        let neg_proportion = (summary2.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };

    let plot1 = summary_plot(&summary1, width1);
    let plot2 = summary_plot(&summary2, width2);

    format!("{}\n{}", pad(&plot1, offset1), pad(&plot2, offset2))
}
<commit_msg>Add ASCII-only plotting functions<commit_after>use summary::Summary;

struct BoxWhiskerData {
    box_lo: f64,
    box_mid: f64,
    box_hi: f64,
    wh_lo: f64,
    wh_hi: f64,
}

impl BoxWhiskerData {
    fn from_summary(summary: &Summary) -> Self {
        BoxWhiskerData {
            box_lo: summary.percentile(0.25).unwrap(),
            box_mid: summary.median(),
            box_hi: summary.percentile(0.75).unwrap(),
            wh_lo: summary.min(),
            wh_hi: summary.max(),
        }
    }
}

struct BoxWhiskerCols {
    box_lo: usize,
    box_mid: usize,
    box_hi: usize,
    wh_lo: usize,
    wh_hi: usize,
}

impl BoxWhiskerCols {
    fn new(data: &BoxWhiskerData, width: usize) -> Self {
        let max_col = width - 1;
        let range = data.wh_hi - data.wh_lo;
        let normalize = |x| (x - data.wh_lo) / range;
        let scale = |x| (normalize(x) * (max_col as f64)) as f64;
        let to_col = |x| scale(x).floor() as usize;

        BoxWhiskerCols {
            box_lo: to_col(data.box_lo),
            box_mid: to_col(data.box_mid),
            box_hi: to_col(data.box_hi),
            wh_lo: to_col(data.wh_lo),
            wh_hi: to_col(data.wh_hi),
        }
    }
}

struct RowChars {
    wh_lo: &'static str,
    wh_lo_box_lo_fill: &'static str,
    box_lo: &'static str,
    box_lo_box_mid_fill: &'static str,
    box_mid: &'static str,
    box_mid_box_hi_fill: &'static str,
    box_hi: &'static str,
    box_hi_wh_hi_fill: &'static str,
    wh_hi: &'static str,
}

impl RowChars {
    pub fn render(&self, row: &mut Vec<String>, cols: &BoxWhiskerCols) {
        row[cols.wh_lo] = self.wh_lo.to_string();
        for i in (cols.wh_lo + 1)..cols.box_lo {
            row[i] = self.wh_lo_box_lo_fill.to_string();
        }
        row[cols.box_lo] = self.box_lo.to_string();
        for i in (cols.box_lo + 1)..cols.box_mid {
            row[i] = self.box_lo_box_mid_fill.to_string();
        }
        row[cols.box_mid] = self.box_mid.to_string();
        for i in (cols.box_mid + 1)..cols.box_hi {
            row[i] = self.box_mid_box_hi_fill.to_string();
        }
        row[cols.box_hi] = self.box_hi.to_string();
        for i in (cols.box_hi + 1)..cols.wh_hi {
            row[i] = self.box_hi_wh_hi_fill.to_string();
        }
        row[cols.wh_hi] = self.wh_hi.to_string();
    }
}

struct CharSet(RowChars, RowChars, RowChars);

static ASCII_CHARS: CharSet = CharSet(
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
    RowChars {
        wh_lo: "|",
        wh_lo_box_lo_fill: "-",
        box_lo: "|",
        box_lo_box_mid_fill: " ",
        box_mid: "|",
        box_mid_box_hi_fill: " ",
        box_hi: "|",
        box_hi_wh_hi_fill: "-",
        wh_hi: "|",
    },
    RowChars {
        wh_lo: " ",
        wh_lo_box_lo_fill: " ",
        box_lo: "+",
        box_lo_box_mid_fill: "-",
        box_mid: "+",
        box_mid_box_hi_fill: "-",
        box_hi: "+",
        box_hi_wh_hi_fill: " ",
        wh_hi: " ",
    },
);

static UNICODE_CHARS: CharSet = CharSet(
    RowChars {
        wh_lo: "┬",
        wh_lo_box_lo_fill: " ",
        box_lo: "┌",
        box_lo_box_mid_fill: "─",
        box_mid: "┬",
        box_mid_box_hi_fill: "─",
        box_hi: "┐",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┬",
    },
    RowChars {
        wh_lo: "├",
        wh_lo_box_lo_fill: "─",
        box_lo: "┤",
        box_lo_box_mid_fill: " ",
        box_mid: "│",
        box_mid_box_hi_fill: " ",
        box_hi: "├",
        box_hi_wh_hi_fill: "─",
        wh_hi: "┤",
    },
    RowChars {
        wh_lo: "┴",
        wh_lo_box_lo_fill: " ",
        box_lo: "└",
        box_lo_box_mid_fill: "─",
        box_mid: "┴",
        box_mid_box_hi_fill: "─",
        box_hi: "┘",
        box_hi_wh_hi_fill: " ",
        wh_hi: "┴",
    },
);

fn make_row(width: usize) -> Vec<String> {
    use std::iter::repeat;

    let mut row = vec![];
    row.extend(repeat(String::from("")).take(width));

    row
}

struct Plot(Vec<String>, Vec<String>, Vec<String>);

impl Plot {
    fn new(width: usize) -> Self {
        Plot(make_row(width), make_row(width), make_row(width))
    }

    fn render(&self) -> String {
        let rows = vec![
            self.0.join(""),
            self.1.join(""),
            self.2.join(""),
        ];

        rows.join("\n")
    }
}

pub fn ascii_summary_plot(summary: &Summary, width: usize) -> String {
    let data = BoxWhiskerData::from_summary(summary);
    let cols = BoxWhiskerCols::new(&data, width);

    let mut plot = Plot::new(width);

    ASCII_CHARS.0.render(&mut plot.0, &cols);
    ASCII_CHARS.1.render(&mut plot.1, &cols);
    ASCII_CHARS.2.render(&mut plot.2, &cols);

    plot.render()
}

pub fn summary_plot(summary: &Summary, width: usize) -> String {
    let data = BoxWhiskerData::from_summary(summary);
    let cols = BoxWhiskerCols::new(&data, width);

    let mut plot = Plot::new(width);

    UNICODE_CHARS.0.render(&mut plot.0, &cols);
    UNICODE_CHARS.1.render(&mut plot.1, &cols);
    UNICODE_CHARS.2.render(&mut plot.2, &cols);

    plot.render()
}

fn make_padding(cols: usize) -> String {
    use std::iter::{FromIterator, repeat};

    String::from_iter(repeat(String::from(" ")).take(cols))
}

fn pad(s: &String, cols: usize) -> String {
    let padding = make_padding(cols);

    let padded: Vec<String> = s
        .split("\n")
        .map(|l| format!("{}{}", padding, l))
        .collect();

    padded.join("\n")
}

pub fn comparison_plot(
    summary1: &Summary,
    summary2: &Summary,
    width: usize,
    ascii: bool,
) -> String {
    let min = summary1.min().min(summary2.min());
    let max = summary1.max().max(summary2.max());

    let range = max - min;
    let range1 = summary1.max() - summary1.min();
    let range2 = summary2.max() - summary2.min();

    let proportion1 = range1 / range;
    let proportion2 = range2 / range;

    let width1 = (proportion1 * (width as f64)).floor() as usize;
    let width2 = (proportion2 * (width as f64)).floor() as usize;

    let offset1 = {
        let neg_proportion = (summary1.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };
    let offset2 = {
        let neg_proportion = (summary2.min() - min) / range;
        (neg_proportion * (width as f64)).floor() as usize
    };

    let (plot1, plot2) = if ascii {
        let plot1 = ascii_summary_plot(&summary1, width1);
        let plot2 = ascii_summary_plot(&summary2, width2);
        (plot1, plot2)
    } else {
        let plot1 = summary_plot(&summary1, width1);
        let plot2 = summary_plot(&summary2, width2);
        (plot1, plot2)
    };

    format!("{}\n{}", pad(&plot1, offset1), pad(&plot2, offset2))
}
<|endoftext|>


<commit_before>//! A simple connection pool
#![deprecated="Use https://github.com/sfackler/r2d2-postgres instead"]

use std::sync::{Arc, Mutex};

use {PostgresConnectParams, IntoConnectParams, PostgresConnection, SslMode};
use error::PostgresConnectError;

struct InnerConnectionPool {
    params: PostgresConnectParams,
    ssl: SslMode,
    pool: Vec<PostgresConnection>,
}

impl InnerConnectionPool {
    fn add_connection(&mut self) -> Result<(), PostgresConnectError> {
        PostgresConnection::connect(self.params.clone(), &self.ssl)
            .map(|c| self.pool.push(c))
    }
}

/// A simple fixed-size Postgres connection pool.
///
/// It can be shared across tasks.
///
/// ## Example
///
/// ```rust,no_run
/// # use postgres::NoSsl;
/// # use postgres::pool::PostgresConnectionPool;
/// let pool = PostgresConnectionPool::new("postgres://postgres@localhost",
///                                        NoSsl, 5).unwrap();
/// for _ in range(0u, 10) {
///     let pool = pool.clone();
///     spawn(proc() {
///         let conn = pool.get_connection();
///         conn.execute("UPDATE foo SET bar = 1", []).unwrap();
///     });
/// }
/// ```
#[deriving(Clone)]
pub struct PostgresConnectionPool {
    pool: Arc<Mutex<InnerConnectionPool>>
}

impl PostgresConnectionPool {
    /// Creates a new pool with the specified number of connections.
    ///
    /// Returns an error if the specified number of connections cannot be
    /// created.
    pub fn new<T: IntoConnectParams>(params: T, ssl: SslMode, pool_size: uint)
            -> Result<PostgresConnectionPool, PostgresConnectError> {
        let mut pool = InnerConnectionPool {
            params: try!(params.into_connect_params()),
            ssl: ssl,
            pool: vec![],
        };

        for _ in range(0, pool_size) {
            try!(pool.add_connection());
        }

        Ok(PostgresConnectionPool {
            pool: Arc::new(Mutex::new(pool))
        })
    }

    /// Retrieves a connection from the pool.
    ///
    /// If all connections are in use, blocks until one becomes available.
    pub fn get_connection(&self) -> PooledPostgresConnection {
        let mut pool = self.pool.lock();

        loop {
            match pool.pool.pop() {
                Some(conn) => {
                    return PooledPostgresConnection {
                        pool: self.clone(),
                        conn: Some(conn),
                    };
                }
                None => pool.cond.wait()
            }
        }
    }
}

/// A Postgres connection pulled from a connection pool.
///
/// It will be returned to the pool when it falls out of scope, even due to
/// task failure.
pub struct PooledPostgresConnection {
    pool: PostgresConnectionPool,
    // TODO remove the Option wrapper when drop takes self by value
    conn: Option<PostgresConnection>
}

impl Drop for PooledPostgresConnection {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        pool.pool.push(self.conn.take_unwrap());
        pool.cond.signal();
    }
}

impl Deref<PostgresConnection> for PooledPostgresConnection {
    fn deref<'a>(&'a self) -> &'a PostgresConnection {
        self.conn.get_ref()
    }
}
<commit_msg>Fix pool documentation<commit_after>//! A simple connection pool
#![deprecated="Use https://github.com/sfackler/r2d2-postgres instead"]

use std::sync::{Arc, Mutex};

use {PostgresConnectParams, IntoConnectParams, PostgresConnection, SslMode};
use error::PostgresConnectError;

struct InnerConnectionPool {
    params: PostgresConnectParams,
    ssl: SslMode,
    pool: Vec<PostgresConnection>,
}

impl InnerConnectionPool {
    fn add_connection(&mut self) -> Result<(), PostgresConnectError> {
        PostgresConnection::connect(self.params.clone(), &self.ssl)
            .map(|c| self.pool.push(c))
    }
}

/// A simple fixed-size Postgres connection pool.
///
/// It can be shared across tasks.
///
/// ## Example
///
/// ```rust,no_run
/// # #![allow(deprecated)]
/// # use postgres::NoSsl;
/// # use postgres::pool::PostgresConnectionPool;
/// let pool = PostgresConnectionPool::new("postgres://postgres@localhost",
///                                        NoSsl, 5).unwrap();
/// for _ in range(0u, 10) {
///     let pool = pool.clone();
///     spawn(proc() {
///         let conn = pool.get_connection();
///         conn.execute("UPDATE foo SET bar = 1", []).unwrap();
///     });
/// }
/// ```
#[deriving(Clone)]
pub struct PostgresConnectionPool {
    pool: Arc<Mutex<InnerConnectionPool>>
}

impl PostgresConnectionPool {
    /// Creates a new pool with the specified number of connections.
    ///
    /// Returns an error if the specified number of connections cannot be
    /// created.
    pub fn new<T: IntoConnectParams>(params: T, ssl: SslMode, pool_size: uint)
            -> Result<PostgresConnectionPool, PostgresConnectError> {
        let mut pool = InnerConnectionPool {
            params: try!(params.into_connect_params()),
            ssl: ssl,
            pool: vec![],
        };

        for _ in range(0, pool_size) {
            try!(pool.add_connection());
        }

        Ok(PostgresConnectionPool {
            pool: Arc::new(Mutex::new(pool))
        })
    }

    /// Retrieves a connection from the pool.
    ///
    /// If all connections are in use, blocks until one becomes available.
    pub fn get_connection(&self) -> PooledPostgresConnection {
        let mut pool = self.pool.lock();

        loop {
            match pool.pool.pop() {
                Some(conn) => {
                    return PooledPostgresConnection {
                        pool: self.clone(),
                        conn: Some(conn),
                    };
                }
                None => pool.cond.wait()
            }
        }
    }
}

/// A Postgres connection pulled from a connection pool.
///
/// It will be returned to the pool when it falls out of scope, even due to
/// task failure.
pub struct PooledPostgresConnection {
    pool: PostgresConnectionPool,
    // TODO remove the Option wrapper when drop takes self by value
    conn: Option<PostgresConnection>
}

impl Drop for PooledPostgresConnection {
    fn drop(&mut self) {
        let mut pool = self.pool.pool.lock();
        pool.pool.push(self.conn.take_unwrap());
        pool.cond.signal();
    }
}

impl Deref<PostgresConnection> for PooledPostgresConnection {
    fn deref<'a>(&'a self) -> &'a PostgresConnection {
        self.conn.get_ref()
    }
}
<|endoftext|>


<commit_before>//! Parse hoon source into AST twig

use std::str;
use std::str::FromStr;
use num::bigint::BigUint;

use twig::{self, Twig, Rune, Odor};

pub type ParseResult<'a, T> = Result<(&'a [u8], T), &'a [u8]>;

/// Parse Hoon source code into a Twig AST.
///
/// Return trailing input after a successful parse along with the resulting
/// Twig. Return trailing input after the point of failed parse on error.
pub fn ream(mut input: &[u8]) -> ParseResult<Twig> {
    // Eat initial space
    loop {
        if let Ok((tail, _)) = space_or_comment(input) {
            input = tail;
        } else {
            break;
        }
    }
    twig(input)
}

fn twig(input: &[u8]) -> ParseResult<Twig> {
    use twig::Rune::*;

    if let Ok(x) = atom(input) {
        return Ok(x);
    }
    if let Ok(x) = wing(input) {
        return Ok(x);
    }

    // Just crunch through the whole set of rune data and look for all the
    // ones that look like they can be parsed naively.
    for i in twig::RUNES.iter() {
        if i.rune.is_regular() && i.rune.glyph().is_some() {
            if let Ok(x) = rune(input, i.rune) {
                return Ok(x);
            }
        }
    }

    Err(input)
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum Form {
    Tall,
    Wide,
}

fn rune<'a>(input: &'a [u8], rune: Rune) -> ParseResult<'a, Twig> {
    assert!(rune.is_regular(),
            "Can't use standard parser on this type of rune!");
    let glyph = rune.glyph().expect("Trying to parse an unprintable rune");
    let (input, form) = try!(rune_start(input, &glyph));
    let (input, args) = try!(rune_args(input, form, rune.arity()));
    Ok((input, Twig::Cell(box Twig::Rune(rune), box args)))
}

/// Parse the start of a rune with the given glyph and determine if the rune
/// is in wide form (.*(p q) or tall form (.*  p  q).
fn rune_start<'a>(input: &'a [u8], glyph: &str) -> ParseResult<'a, Form> {
    assert!(glyph.len() == 2, "Rune isn't 2 characters");
    let (mut tail, _) = try!(tag(input, glyph));

    if let Ok((tail, _)) = tag(tail, "(") {
        return Ok((tail, Form::Wide));
    }

    if let Ok((tail, _)) = gap(tail) {
        return Ok((tail, Form::Tall));
    }

    Err(input)
}

fn rune_args(input: &[u8], form: Form, n: usize) -> ParseResult<Twig> {
    assert!(n > 0);
    if n == 1 {
        let (input, p) = try!(twig(input));
        let (input, _) = try!(rune_end(input, form));
        Ok((input, p))
    } else {
        let (input, p) = try!(twig(input));
        let (input, _) = try!(rune_sep(input, form));
        let (input, ps) = try!(rune_args(input, form, n - 1));
        Ok((input, Twig::Cell(box p, box ps)))
    }
}

fn rune_sep(input: &[u8], form: Form) -> ParseResult<&[u8]> {
    match form {
        Form::Tall => gap(input),
        Form::Wide => tag(input, " "),
    }
}

fn rune_end(input: &[u8], form: Form) -> ParseResult<&[u8]> {
    match form {
        Form::Tall => Ok((input, &input[..0])),
        Form::Wide => tag(input, ")"),
    }
}

fn atom(input: &[u8]) -> ParseResult<Twig> {
    if let Ok((tail, num)) = ud(input) {
        Ok((tail,
            Twig::Cell(box Twig::Rune(Rune::dtzy), box Twig::Atom(Odor::ud, num))))
    } else {
        Err(input)
    }
}

/// Unsigned decimal
fn ud(input: &[u8]) -> ParseResult<BigUint> {
    let mut idx = 0;
    let mut num = String::new();
    for c in input.iter() {
        if *c >= '0' as u8 && *c <= '9' as u8 {
            num.push(*c as char);
        } else if idx > 0 && *c == '.' as u8 {
            // Ignore separator dots.
            // We're lazy, so we let them show up in any pattern after the
            // initial digit instead of insisting that they group the digits
            // in sized groups.
        } else {
            if idx == 0 {
                return Err(input);
            }
            break;
        }
        idx += 1;
    }

    Ok((&input[idx..], FromStr::from_str(&num).unwrap()))
}

fn wing(input: &[u8]) -> ParseResult<Twig> {
    // TODO: Dotted forms expanding to multi-term wings.
    let (input, term) = try!(term(input));
    let s = str::from_utf8(term).unwrap().to_string();
    Ok((input,
        Twig::Cell(box Twig::Rune(Rune::cnzz), box Twig::Wing(vec![s]))))
}

fn term(input: &[u8]) -> ParseResult<&[u8]> {
    let mut idx = 0;
    for i in input.iter() {
        if idx == 0 && *i == '$' as u8 {
            // Special $
            if input.len() > 1 && is_ident_middle(input[1]) {
                // Can't have something like $foo.
                return Err(input);
            }
            idx += 1;
            break;
        }

        if idx == 0 && !is_ident_start(*i) {
            break;
        }

        if idx > 0 && !is_ident_middle(*i) {
            break;
        }

        idx += 1;
    }

    if idx == 0 {
        Err(input)
    } else {
        Ok((&input[idx..], &input[..idx]))
    }
}

fn space_or_comment(input: &[u8]) -> ParseResult<()> {
    let mut tail = input;
    loop {
        if let Ok((t, _)) = comment(tail) {
            tail = t
        } else {
            if tail.len() == 0 {
                break;
            } else if is_whitespace(tail[0]) {
                tail = &tail[1..];
            } else {
                break;
            }
        }
    }
    if tail == input {
        Err(input)
    } else {
        Ok((tail, ()))
    }
}

/// At least one newline or at least two spaces.
///
/// Used to separate tall forms in Hoon.
fn gap(input: &[u8]) -> ParseResult<&[u8]> {
    let mut spaces = 0;
    let mut idx = 0;
    for i in input.iter() {
        if *i == '\n' as u8 {
            spaces += 2;
        } else if is_whitespace(*i) {
            spaces += 1;
        } else {
            break;
        }

        idx += 1;
    }

    if spaces < 2 {
        Err(input)
    } else {
        Ok((&input[idx..], &input[0..idx]))
    }
}

fn comment(input: &[u8]) -> ParseResult<&[u8]> {
    let (input, _) = try!(tag(input, "::"));
    // XXX: The initial bit with the "::" won't make it to the return value.
    split_after(input, '\n' as u8)
}

fn is_whitespace(c: u8) -> bool {
    // Physical tabs not included. A physical tab in the code is a syntax
    // error.
    c == 0x10 || c == 0x13 || c == ' ' as u8
}

fn is_lowercase(c: u8) -> bool {
    c >= 'a' as u8 && c <= 'z' as u8
}

fn is_numeric(c: u8) -> bool {
    c >= '0' as u8 && c <= '9' as u8
}

fn is_ident_start(c: u8) -> bool {
    is_lowercase(c)
}

fn is_ident_middle(c: u8) -> bool {
    is_lowercase(c) || is_numeric(c) || c == '-' as u8
}

fn tag<'a>(input: &'a [u8], prefix: &str) -> ParseResult<'a, &'a [u8]> {
    let prefix = prefix.as_bytes();
    if input.len() < prefix.len() {
        return Err(input);
    }

    for (x, y) in prefix.iter().zip(input.iter()) {
        if x != y {
            return Err(input);
        }
    }

    Ok((&input[prefix.len()..], &input[0..prefix.len()]))
}

fn split_after(input: &[u8], c: u8) -> ParseResult<&[u8]> {
    let mut idx = 1;
    for i in input.iter() {
        if *i == c {
            break;
        }
        idx += 1;
    }
    Ok((&input[idx..], &input[0..idx]))
}
<commit_msg>Parser unit tests<commit_after>//! Parse hoon source into AST twig

use std::str;
use std::str::FromStr;
use num::bigint::BigUint;

use twig::{self, Twig, Rune, Odor};

pub type ParseResult<'a, T> = Result<(&'a [u8], T), &'a [u8]>;

/// Parse Hoon source code into a Twig AST.
///
/// Return trailing input after a successful parse along with the resulting
/// Twig. Return trailing input after the point of failed parse on error.
pub fn ream(mut input: &[u8]) -> ParseResult<Twig> {
    // Eat initial space
    loop {
        if let Ok((tail, _)) = space_or_comment(input) {
            input = tail;
        } else {
            break;
        }
    }
    twig(input)
}

fn twig(input: &[u8]) -> ParseResult<Twig> {
    use twig::Rune::*;

    if let Ok(x) = atom(input) {
        return Ok(x);
    }
    if let Ok(x) = wing(input) {
        return Ok(x);
    }

    // Just crunch through the whole set of rune data and look for all the
    // ones that look like they can be parsed naively.
    for i in twig::RUNES.iter() {
        if i.rune.is_regular() && i.rune.glyph().is_some() {
            if let Ok(x) = rune(input, i.rune) {
                return Ok(x);
            }
        }
    }

    Err(input)
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum Form {
    Tall,
    Wide,
}

fn rune<'a>(input: &'a [u8], rune: Rune) -> ParseResult<'a, Twig> {
    assert!(rune.is_regular(),
            "Can't use standard parser on this type of rune!");
    let glyph = rune.glyph().expect("Trying to parse an unprintable rune");
    let (input, form) = try!(rune_start(input, &glyph));
    let (input, args) = try!(rune_args(input, form, rune.arity()));
    Ok((input, Twig::Cell(box Twig::Rune(rune), box args)))
}

/// Parse the start of a rune with the given glyph and determine if the rune
/// is in wide form (.*(p q) or tall form (.*  p  q).
fn rune_start<'a>(input: &'a [u8], glyph: &str) -> ParseResult<'a, Form> {
    assert!(glyph.len() == 2, "Rune isn't 2 characters");
    let (mut tail, _) = try!(tag(input, glyph));

    if let Ok((tail, _)) = tag(tail, "(") {
        return Ok((tail, Form::Wide));
    }

    if let Ok((tail, _)) = gap(tail) {
        return Ok((tail, Form::Tall));
    }

    Err(input)
}

fn rune_args(input: &[u8], form: Form, n: usize) -> ParseResult<Twig> {
    assert!(n > 0);
    if n == 1 {
        let (input, p) = try!(twig(input));
        let (input, _) = try!(rune_end(input, form));
        Ok((input, p))
    } else {
        let (input, p) = try!(twig(input));
        let (input, _) = try!(rune_sep(input, form));
        let (input, ps) = try!(rune_args(input, form, n - 1));
        Ok((input, Twig::Cell(box p, box ps)))
    }
}

fn rune_sep(input: &[u8], form: Form) -> ParseResult<&[u8]> {
    match form {
        Form::Tall => gap(input),
        Form::Wide => tag(input, " "),
    }
}

fn rune_end(input: &[u8], form: Form) -> ParseResult<&[u8]> {
    match form {
        Form::Tall => Ok((input, &input[..0])),
        Form::Wide => tag(input, ")"),
    }
}

fn atom(input: &[u8]) -> ParseResult<Twig> {
    if let Ok((tail, num)) = ud(input) {
        Ok((tail,
            Twig::Cell(box Twig::Rune(Rune::dtzy), box Twig::Atom(Odor::ud, num))))
    } else {
        Err(input)
    }
}

/// Unsigned decimal
fn ud(input: &[u8]) -> ParseResult<BigUint> {
    let mut idx = 0;
    let mut num = String::new();
    for c in input.iter() {
        if *c >= '0' as u8 && *c <= '9' as u8 {
            num.push(*c as char);
        } else if idx > 0 && *c == '.' as u8 {
            // Ignore separator dots.
            // We're lazy, so we let them show up in any pattern after the
            // initial digit instead of insisting that they group the digits
            // in sized groups.
        } else {
            if idx == 0 {
                return Err(input);
            }
            break;
        }
        idx += 1;
    }

    Ok((&input[idx..], FromStr::from_str(&num).unwrap()))
}

fn wing(input: &[u8]) -> ParseResult<Twig> {
    // TODO: Dotted forms expanding to multi-term wings.
    let (input, term) = try!(term(input));
    let s = str::from_utf8(term).unwrap().to_string();
    Ok((input,
        Twig::Cell(box Twig::Rune(Rune::cnzz), box Twig::Wing(vec![s]))))
}

fn term(input: &[u8]) -> ParseResult<&[u8]> {
    let mut idx = 0;
    for i in input.iter() {
        if idx == 0 && *i == '$' as u8 {
            // Special $
            if input.len() > 1 && is_ident_middle(input[1]) {
                // Can't have something like $foo.
                return Err(input);
            }
            idx += 1;
            break;
        }

        if idx == 0 && !is_ident_start(*i) {
            break;
        }

        if idx > 0 && !is_ident_middle(*i) {
            break;
        }

        idx += 1;
    }

    if idx == 0 {
        Err(input)
    } else {
        Ok((&input[idx..], &input[..idx]))
    }
}

fn space_or_comment(input: &[u8]) -> ParseResult<()> {
    let mut tail = input;
    loop {
        if let Ok((t, _)) = comment(tail) {
            tail = t
        } else {
            if tail.len() == 0 {
                break;
            } else if is_whitespace(tail[0]) {
                tail = &tail[1..];
            } else {
                break;
            }
        }
    }
    if tail == input {
        Err(input)
    } else {
        Ok((tail, ()))
    }
}

/// At least one newline or at least two spaces.
///
/// Used to separate tall forms in Hoon.
fn gap(input: &[u8]) -> ParseResult<&[u8]> {
    let mut spaces = 0;
    let mut idx = 0;
    for i in input.iter() {
        if *i == '\n' as u8 {
            spaces += 2;
        } else if is_whitespace(*i) {
            spaces += 1;
        } else {
            break;
        }

        idx += 1;
    }

    if spaces < 2 {
        Err(input)
    } else {
        Ok((&input[idx..], &input[0..idx]))
    }
}

fn comment(input: &[u8]) -> ParseResult<&[u8]> {
    let (input, _) = try!(tag(input, "::"));
    // XXX: The initial bit with the "::" won't make it to the return value.
    split_after(input, '\n' as u8)
}

fn is_whitespace(c: u8) -> bool {
    // Physical tabs not included. A physical tab in the code is a syntax
    // error.
    c == 0x10 || c == 0x13 || c == ' ' as u8
}

fn is_lowercase(c: u8) -> bool {
    c >= 'a' as u8 && c <= 'z' as u8
}

fn is_numeric(c: u8) -> bool {
    c >= '0' as u8 && c <= '9' as u8
}

fn is_ident_start(c: u8) -> bool {
    is_lowercase(c)
}

fn is_ident_middle(c: u8) -> bool {
    is_lowercase(c) || is_numeric(c) || c == '-' as u8
}

fn tag<'a>(input: &'a [u8], prefix: &str) -> ParseResult<'a, &'a [u8]> {
    let prefix = prefix.as_bytes();
    if input.len() < prefix.len() {
        return Err(input);
    }

    for (x, y) in prefix.iter().zip(input.iter()) {
        if x != y {
            return Err(input);
        }
    }

    Ok((&input[prefix.len()..], &input[0..prefix.len()]))
}

fn split_after(input: &[u8], c: u8) -> ParseResult<&[u8]> {
    let mut idx = 1;
    for i in input.iter() {
        if *i == c {
            break;
        }
        idx += 1;
    }
    Ok((&input[idx..], &input[0..idx]))
}

#[cfg(test)]
mod test {
    use std::fmt;
    use std::str;
    use super::{ParseResult, ream};

    fn parses<T: fmt::Debug>(ret: ParseResult<T>, expect: &str) {
        assert_eq!(&format!("{:?}", ret.unwrap().1), expect);
    }

    #[test]
    fn test_parse() {
       parses(ream("123".as_bytes()), "Cell(Rune(dtzy), Atom(ud, BigUint { data: [123] }))");
       parses(ream("=>($ 3)".as_bytes()), "Cell(Rune(tsgr), Cell(Cell(Rune(cnzz), Wing([\"$\"])), Cell(Rune(dtzy), Atom(ud, BigUint { data: [3] }))))");
    }
}
<|endoftext|>


<commit_before>use std::convert::From;
use std::fmt;
use std::ops::{Add, AddAssign, Deref};
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

use super::content::{Content, ToContent};

#[derive(Debug, Default)]
pub struct Text {
    text: Vec<Content>,
}

impl<T> From<T> for Text
    where T: ToContent<T>
{
    fn from(s: T) -> Self {
        Text { text: vec![Content::from(s)] }
    }
}

impl Text {
    pub fn new() -> Self {
        Text::default()
    }

    pub fn len(&self) -> usize {
        let mut len: usize = 0;
        for elt in &self.text {
            len += elt.len();
        }
        len
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl fmt::Display for Text {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(&format!("{:?}", &self.text))
    }
}

impl Deref for Text {
    type Target = OsStr;
    fn deref(&self) -> &OsStr {
        if self.is_empty() {
            OsStr::new("")
        } else {
            match self.text[0] {
                Content::String(ref s) => s.as_ref(),
                Content::OsString(ref s) => s,
                Content::CString(ref s) => OsStr::from_bytes(s.as_bytes()),
                Content::PathBuf(ref p) => p.as_ref(),
            }
        }
    }
}

// Doesn't work - conflicting Deref implementation

// impl Deref for Text {
//     type Target = Path;
//     fn deref(&self) -> &Path {
//         Path::new(&self.text)
//     }
// }

// Add

impl Add for Text {
    type Output = Text;
    fn add(self, rhs: Text) -> Self::Output {
        let mut text = self.text.clone();
        text.extend_from_slice(&rhs.text);
        Text { text: text }
    }
}

impl<T> Add<T> for Text
    where T: ToContent<T>
{
    type Output = Text;
    fn add(self, rhs: T) -> Self::Output {
        let mut text = self.text.clone();
        text.push(Content::from(rhs));
        Text { text: text }
    }
}

// AddAssign implementation

impl AddAssign for Text {
    fn add_assign(&mut self, other: Self) {
        self.text.extend_from_slice(&other.text)
    }
}

// PartialEq implementation

// impl<T: Borrow<OsStr> + ?Sized> PartialEq<T> for Text {
//     default fn eq(&self, other: &T) -> bool {
//         unimplemented!()
//     }
// }

// impl<T: Borrow<Path> + ?Sized> PartialEq<T> for Text {
//     default fn eq(&self, other: &T) -> bool {
//         unimplemented!()
//     }
// }

impl PartialEq<str> for Text {
    fn eq(&self, other: &str) -> bool {
        unimplemented!()
    }
}

impl<'a> PartialEq<&'a str> for Text {
    fn eq(&self, other: &&'a str) -> bool {
        unimplemented!()
    }
}

impl PartialEq<String> for Text {
    fn eq(&self, other: &String) -> bool {
        unimplemented!()
    }
}

impl<'a> PartialEq<String> for &'a Text {
    fn eq(&self, other: &String) -> bool {
        unimplemented!()
        // self.text == *other
    }
}

impl PartialEq<Path> for Text {
    fn eq(&self, other: &Path) -> bool {
        unimplemented!()
    }
}

impl<'a> PartialEq<&'a Path> for Text {
    fn eq(&self, other: &&'a Path) -> bool {
        unimplemented!()
    }
}

impl PartialEq<PathBuf> for Text {
    fn eq(&self, other: &PathBuf) -> bool {
        unimplemented!()
    }
}

impl<'a> PartialEq<PathBuf> for &'a Text {
    fn eq(&self, other: &PathBuf) -> bool {
        unimplemented!()
    }
}

// impl<T> From<T> for Text
//     where T: Textable
// {
//     fn from(s: T) -> Self {
//         s.to_text()
//     }
// }

impl From<Text> for String {
    fn from(t: Text) -> Self {
        unimplemented!()
    }
}

impl<'a> From<&'a Text> for &'a Path {
    fn from(t: &'a Text) -> Self {
        unimplemented!()
    }
}
<commit_msg>Add internal representation<commit_after>use std::convert::From;
use std::fmt;
use std::ops::{Add, AddAssign, Deref};
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

use super::content::{Content, ToContent};

#[derive(Debug, Default)]
pub struct Text {
    inner: Option<String>,
    text: Vec<Content>,
}

impl<T> From<T> for Text
    where T: ToContent<T>
{
    fn from(s: T) -> Self {
        Text {
            inner: None,
            text: vec![Content::from(s)],
        }
    }
}

impl Text {
    pub fn new() -> Self {
        Text::default()
    }

    pub fn len(&self) -> usize {
        let mut len: usize = 0;
        for elt in &self.text {
            len += elt.len();
        }
        len
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl fmt::Display for Text {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(&format!("{:?}", &self.text))
    }
}

impl Deref for Text {
    type Target = OsStr;
    fn deref(&self) -> &OsStr {
        if self.is_empty() {
            OsStr::new("")
        } else {
            match self.text[0] {
                Content::String(ref s) => s.as_ref(),
                Content::OsString(ref s) => s,
                Content::CString(ref s) => OsStr::from_bytes(s.as_bytes()),
                Content::PathBuf(ref p) => p.as_ref(),
            }
        }
    }
}

// Doesn't work - conflicting Deref implementation

// impl Deref for Text {
//     type Target = Path;
//     fn deref(&self) -> &Path {
//         Path::new(&self.text)
//     }
// }

// Add

impl Add for Text {
    type Output = Text;
    fn add(self, rhs: Text) -> Self::Output {
        let mut text = self.text.clone();
        text.extend_from_slice(&rhs.text);
        Text { text: text }
    }
}

impl<T> Add<T> for Text
    where T: ToContent<T>
{
    type Output = Text;
    fn add(self, rhs: T) -> Self::Output {
        let mut text = self.text.clone();
        text.push(Content::from(rhs));
        Text { text: text }
    }
}

// AddAssign implementation

impl AddAssign for Text {
    fn add_assign(&mut self, other: Self) {
        self.text.extend_from_slice(&other.text)
    }
}

// PartialEq implementation

// impl<T: Borrow<OsStr> + ?Sized> PartialEq<T> for Text {
//     default fn eq(&self, other: &T) -> bool {
//         unimplemented!()
//     }
// }

// impl<T: Borrow<Path> + ?Sized> PartialEq<T> for Text {
//     default fn eq(&self, other: &T) -> bool {
//         unimplemented!()
//     }
// }

impl PartialEq<str> for Text {
    fn eq(&self, other: &str) -> bool {
        unimplemented!()
    }
}

impl<'a> PartialEq<&'a str> for Text {
    fn eq(&self, other: &&'a str) -> bool {
        unimplemented!()
    }
}

impl PartialEq<String> for Text {
    fn eq(&self, other: &String) -> bool {
        unimplemented!()
    }
}

impl<'a> PartialEq<String> for &'a Text {
    fn eq(&self, other: &String) -> bool {
        unimplemented!()
        // self.text == *other
    }
}

impl PartialEq<Path> for Text {
    fn eq(&self, other: &Path) -> bool {
        unimplemented!()
    }
}

impl<'a> PartialEq<&'a Path> for Text {
    fn eq(&self, other: &&'a Path) -> bool {
        unimplemented!()
    }
}

impl PartialEq<PathBuf> for Text {
    fn eq(&self, other: &PathBuf) -> bool {
        unimplemented!()
    }
}

impl<'a> PartialEq<PathBuf> for &'a Text {
    fn eq(&self, other: &PathBuf) -> bool {
        unimplemented!()
    }
}

// impl<T> From<T> for Text
//     where T: Textable
// {
//     fn from(s: T) -> Self {
//         s.to_text()
//     }
// }

impl From<Text> for String {
    fn from(t: Text) -> Self {
        unimplemented!()
    }
}

impl<'a> From<&'a Text> for &'a Path {
    fn from(t: &'a Text) -> Self {
        unimplemented!()
    }
}
<|endoftext|>