<commit_before>#![allow(non_snake_case)]

use std::env;
use std::fs::File;
use std::io;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;

use petgraph::graph::NodeIndex;
use petgraph::{EdgeDirection, Graph};
use regex::Regex;

use lazy_static::lazy_static;
use octobuild::cluster::client::RemoteCompiler;
use octobuild::compiler::*;
use octobuild::config::Config;
use octobuild::simple::create_temp_dir;
use octobuild::simple::supported_compilers;
use octobuild::version;
use octobuild::worker::execute_graph;
use octobuild::worker::validate_graph;
use octobuild::worker::{BuildAction, BuildGraph, BuildResult, BuildTask};
use octobuild::xg;
use octobuild::xg::parser::{XgGraph, XgNode};

fn main() {
    println!("xgConsole ({}):", version::full_version());
    let args: Vec<String> = env::args().collect();
    for arg in args.iter() {
        println!("  {}", arg);
    }
    if args.len() == 1 {
        println!();
        Config::help();
        return;
    }

    process::exit(match execute(&args[1..]) {
        Ok(result) => result.unwrap_or(501),
        Err(e) => {
            println!("FATAL ERROR: {}", e);
            500
        }
    })
}

fn is_flag(arg: &str) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"^/\w+([=].*)?$").unwrap();
    }
    RE.is_match(arg)
}

#[cfg(unix)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
    files.push(Path::new(arg).to_path_buf());
    files
}

#[cfg(windows)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
    use std::fs;

    fn mask_to_regex(mask: &str) -> Regex {
        let mut result = String::new();
        let mut begin = 0;
        result.push('^');
        for (index, separator) in mask.match_indices(|c| c == '?' || c == '*') {
            result.push_str(&regex::escape(&mask[begin..index]));
            result.push_str(match separator {
                "?" => ".",
                "*" => ".*",
                unknown => panic!("Unexpected separator: {}", unknown),
            });
            begin = index + separator.len()
        }
        result.push_str(&regex::escape(&mask[begin..]));
        result.push('$');
        Regex::new(&result).unwrap()
    }

    fn find_files(dir: &Path, mask: &str) -> Result<Vec<PathBuf>, Error> {
        let mut result = Vec::new();
        let expr = mask_to_regex(&mask.to_lowercase());
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            if entry
                .file_name()
                .to_str()
                .map_or(false, |s| expr.is_match(&s.to_lowercase()))
            {
                result.push(entry.path());
            }
        }
        Ok(result)
    }

    let path = Path::new(arg).to_path_buf();
    let mask = path.file_name().and_then(|name| name.to_str());
    match mask {
        Some(ref mask) if mask.contains(|c| c == '?' || c == '*') => {
            match find_files(path.parent().unwrap_or_else(|| Path::new(".")), mask) {
                Ok(ref mut found) if !found.is_empty() => {
                    files.append(found);
                }
                _ => {
                    files.push(path);
                }
            }
        }
        _ => {
            files.push(path);
        }
    }
    files
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
    let config = Config::new()?;
    let state = SharedState::new(&config)?;
    let compiler = RemoteCompiler::new(
        &config.coordinator,
        supported_compilers(&create_temp_dir()?),
    );
    let files = args
        .iter()
        .filter(|a| !is_flag(a))
        .fold(Vec::new(), |state, a| expand_files(state, a));
    if files.is_empty() {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "Build task files not found",
        ));
    }

    let mut graph = Graph::new();
    for arg in files.iter() {
        let file = File::open(&Path::new(arg))?;
        xg::parser::parse(&mut graph, BufReader::new(file))?;
    }
    let build_graph = validate_graph(graph).and_then(|graph| prepare_graph(&compiler, graph))?;

    let result = execute_graph(&state, build_graph, config.process_limit, print_task_result);
    let _ = state.cache.cleanup();
    println!("{}", state.statistic.to_string());
    result
}

fn env_resolver(name: &str) -> Option<String> {
    env::var(name).ok()
}

fn prepare_graph<C: Compiler>(compiler: &C, graph: XgGraph) -> Result<BuildGraph, Error> {
    let mut remap: Vec<NodeIndex> = Vec::with_capacity(graph.node_count());
    let mut depends: Vec<NodeIndex> = Vec::with_capacity(graph.node_count());

    let mut result: BuildGraph = Graph::new();
    for raw_node in graph.raw_nodes().iter() {
        let node: &XgNode = &raw_node.weight;
        let args: Vec<String> = node
            .args
            .iter()
            .map(|arg| expand_arg(arg, &env_resolver))
            .collect();
        let command = node.command.clone();

        let actions = BuildAction::create_tasks(compiler, command.clone(), &args, &node.title);
        let node_index = NodeIndex::new(remap.len());
        if actions.len() == 1 {
            depends.push(node_index);
            remap.push(result.add_node(Arc::new(BuildTask {
                title: node.title.clone(),
                action: actions.into_iter().next().unwrap(),
            })));
        } else {
            // Add group node for tracking end of all task actions
            let group_node = result.add_node(Arc::new(BuildTask {
                title: node.title.clone(),
                action: BuildAction::Empty,
            }));
            depends.push(NodeIndex::end());
            // Add task actions
            let mut index = 1;
            let total = actions.len();
            for action in actions.into_iter() {
                let action_node = result.add_node(Arc::new(BuildTask {
                    title: format!("{} ({}/{})", node.title, index, total),
                    action,
                }));
                depends.push(node_index);
                result.add_edge(group_node, action_node, ());
                index += 1;
            }
            remap.push(group_node);
        }
    }

    assert_eq!(remap.len(), graph.node_count());
    assert_eq!(depends.len(), result.node_count());
    for i in 0..depends.len() {
        let node_a = NodeIndex::new(i);
        for neighbor in graph.neighbors_directed(*depends.get(i).unwrap(), EdgeDirection::Outgoing)
        {
            let node_b = remap.get(neighbor.index()).unwrap();
            result.add_edge(node_a, *node_b, ());
        }
    }
    validate_graph(result)
}

fn print_task_result(result: BuildResult) -> Result<(), Error> {
    println!(
        "#{} {}/{}: {}",
        result.worker, result.completed, result.total, result.task.title
    );
    match result.result {
        Ok(ref output) => {
            io::stdout().write_all(&output.stdout)?;
            io::stderr().write_all(&output.stderr)?;
        }
        Err(_) => {}
    }
    Ok(())
}

fn expand_arg<F: Fn(&str) -> Option<String>>(arg: &str, resolver: &F) -> String {
    let mut result = String::new();
    let mut suffix = arg;
    loop {
        match suffix.find("$(") {
            Some(begin) => match suffix[begin..].find(')') {
                Some(end) => {
                    let name = &suffix[begin + 2..begin + end];
                    match resolver(name) {
                        Some(ref value) => {
                            result += &suffix[..begin];
                            result += value;
                        }
                        None => {
                            result += &suffix[..=begin + end];
                        }
                    }
                    suffix = &suffix[begin + end + 1..];
                }
                None => {
                    result += suffix;
                    break;
                }
            },
            None => {
                result += suffix;
                break;
            }
        }
    }
    result
}

#[test]
fn test_parse_vars() {
    assert_eq!(
        expand_arg(
            "A$(test)$(inner)$(none)B",
            &|name: &str| -> Option<String> {
                match name {
                    "test" => Some("foo".to_string()),
                    "inner" => Some("$(bar)".to_string()),
                    "none" => None,
                    _ => {
                        unreachable!(format!("Unexpected value: {}", name));
                    }
                }
            },
        ),
        "Afoo$(bar)$(none)B"
    );
}

#[test]
fn test_is_flag() {
    assert!(is_flag("/Wait"));
    assert!(is_flag("/out=/foo/bar"));
    assert!(!is_flag("/out/foo/bar"));
    assert!(!is_flag("foo/bar"));
    assert!(!is_flag("/Wait.xml"));
    assert!(!is_flag("/Wait/foo=bar"));
    assert!(is_flag("/WaitFoo=bar"));
    assert!(!is_flag("/Wait.Foo=bar"));
    assert!(is_flag("/Wait=/foo/bar"));
}
<commit_msg>Fix clippy warnings<commit_after>#![allow(non_snake_case)]

use std::env;
use std::fs::File;
use std::io;
use std::io::{BufReader, Error, ErrorKind, Write};
use std::path::{Path, PathBuf};
use std::process;
use std::sync::Arc;

use petgraph::graph::NodeIndex;
use petgraph::{EdgeDirection, Graph};
use regex::Regex;

use lazy_static::lazy_static;
use octobuild::cluster::client::RemoteCompiler;
use octobuild::compiler::*;
use octobuild::config::Config;
use octobuild::simple::create_temp_dir;
use octobuild::simple::supported_compilers;
use octobuild::version;
use octobuild::worker::execute_graph;
use octobuild::worker::validate_graph;
use octobuild::worker::{BuildAction, BuildGraph, BuildResult, BuildTask};
use octobuild::xg;
use octobuild::xg::parser::{XgGraph, XgNode};

fn main() {
    println!("xgConsole ({}):", version::full_version());
    let args: Vec<String> = env::args().collect();
    for arg in args.iter() {
        println!("  {}", arg);
    }
    if args.len() == 1 {
        println!();
        Config::help();
        return;
    }

    process::exit(match execute(&args[1..]) {
        Ok(result) => result.unwrap_or(501),
        Err(e) => {
            println!("FATAL ERROR: {}", e);
            500
        }
    })
}

fn is_flag(arg: &str) -> bool {
    lazy_static! {
        static ref RE: Regex = Regex::new(r"^/\w+([=].*)?$").unwrap();
    }
    RE.is_match(arg)
}

#[cfg(unix)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
    files.push(Path::new(arg).to_path_buf());
    files
}

#[cfg(windows)]
fn expand_files(mut files: Vec<PathBuf>, arg: &str) -> Vec<PathBuf> {
    use std::fs;

    fn mask_to_regex(mask: &str) -> Regex {
        let mut result = String::new();
        let mut begin = 0;
        result.push('^');
        for (index, separator) in mask.match_indices(|c| c == '?' || c == '*') {
            result.push_str(&regex::escape(&mask[begin..index]));
            result.push_str(match separator {
                "?" => ".",
                "*" => ".*",
                unknown => panic!("Unexpected separator: {}", unknown),
            });
            begin = index + separator.len()
        }
        result.push_str(&regex::escape(&mask[begin..]));
        result.push('$');
        Regex::new(&result).unwrap()
    }

    fn find_files(dir: &Path, mask: &str) -> Result<Vec<PathBuf>, Error> {
        let mut result = Vec::new();
        let expr = mask_to_regex(&mask.to_lowercase());
        for entry in fs::read_dir(dir)? {
            let entry = entry?;
            if entry
                .file_name()
                .to_str()
                .map_or(false, |s| expr.is_match(&s.to_lowercase()))
            {
                result.push(entry.path());
            }
        }
        Ok(result)
    }

    let path = Path::new(arg).to_path_buf();
    let mask = path.file_name().and_then(|name| name.to_str());
    match mask {
        Some(mask) if mask.contains(|c| c == '?' || c == '*') => {
            match find_files(path.parent().unwrap_or_else(|| Path::new(".")), mask) {
                Ok(ref mut found) if !found.is_empty() => {
                    files.append(found);
                }
                _ => {
                    files.push(path);
                }
            }
        }
        _ => {
            files.push(path);
        }
    }
    files
}

fn execute(args: &[String]) -> Result<Option<i32>, Error> {
    let config = Config::new()?;
    let state = SharedState::new(&config)?;
    let compiler = RemoteCompiler::new(
        &config.coordinator,
        supported_compilers(&create_temp_dir()?),
    );
    let files = args
        .iter()
        .filter(|a| !is_flag(a))
        .fold(Vec::new(), |state, a| expand_files(state, a));
    if files.is_empty() {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            "Build task files not found",
        ));
    }

    let mut graph = Graph::new();
    for arg in files.iter() {
        let file = File::open(&Path::new(arg))?;
        xg::parser::parse(&mut graph, BufReader::new(file))?;
    }
    let build_graph = validate_graph(graph).and_then(|graph| prepare_graph(&compiler, graph))?;

    let result = execute_graph(&state, build_graph, config.process_limit, print_task_result);
    let _ = state.cache.cleanup();
    println!("{}", state.statistic.to_string());
    result
}

fn env_resolver(name: &str) -> Option<String> {
    env::var(name).ok()
}

fn prepare_graph<C: Compiler>(compiler: &C, graph: XgGraph) -> Result<BuildGraph, Error> {
    let mut remap: Vec<NodeIndex> = Vec::with_capacity(graph.node_count());
    let mut depends: Vec<NodeIndex> = Vec::with_capacity(graph.node_count());

    let mut result: BuildGraph = Graph::new();
    for raw_node in graph.raw_nodes().iter() {
        let node: &XgNode = &raw_node.weight;
        let args: Vec<String> = node
            .args
            .iter()
            .map(|arg| expand_arg(arg, &env_resolver))
            .collect();
        let command = node.command.clone();

        let actions = BuildAction::create_tasks(compiler, command.clone(), &args, &node.title);
        let node_index = NodeIndex::new(remap.len());
        if actions.len() == 1 {
            depends.push(node_index);
            remap.push(result.add_node(Arc::new(BuildTask {
                title: node.title.clone(),
                action: actions.into_iter().next().unwrap(),
            })));
        } else {
            // Add group node for tracking end of all task actions
            let group_node = result.add_node(Arc::new(BuildTask {
                title: node.title.clone(),
                action: BuildAction::Empty,
            }));
            depends.push(NodeIndex::end());
            // Add task actions
            let mut index = 1;
            let total = actions.len();
            for action in actions.into_iter() {
                let action_node = result.add_node(Arc::new(BuildTask {
                    title: format!("{} ({}/{})", node.title, index, total),
                    action,
                }));
                depends.push(node_index);
                result.add_edge(group_node, action_node, ());
                index += 1;
            }
            remap.push(group_node);
        }
    }

    assert_eq!(remap.len(), graph.node_count());
    assert_eq!(depends.len(), result.node_count());
    for i in 0..depends.len() {
        let node_a = NodeIndex::new(i);
        for neighbor in graph.neighbors_directed(*depends.get(i).unwrap(), EdgeDirection::Outgoing)
        {
            let node_b = remap.get(neighbor.index()).unwrap();
            result.add_edge(node_a, *node_b, ());
        }
    }
    validate_graph(result)
}

fn print_task_result(result: BuildResult) -> Result<(), Error> {
    println!(
        "#{} {}/{}: {}",
        result.worker, result.completed, result.total, result.task.title
    );
    match result.result {
        Ok(ref output) => {
            io::stdout().write_all(&output.stdout)?;
            io::stderr().write_all(&output.stderr)?;
        }
        Err(_) => {}
    }
    Ok(())
}

fn expand_arg<F: Fn(&str) -> Option<String>>(arg: &str, resolver: &F) -> String {
    let mut result = String::new();
    let mut suffix = arg;
    loop {
        match suffix.find("$(") {
            Some(begin) => match suffix[begin..].find(')') {
                Some(end) => {
                    let name = &suffix[begin + 2..begin + end];
                    match resolver(name) {
                        Some(ref value) => {
                            result += &suffix[..begin];
                            result += value;
                        }
                        None => {
                            result += &suffix[..=begin + end];
                        }
                    }
                    suffix = &suffix[begin + end + 1..];
                }
                None => {
                    result += suffix;
                    break;
                }
            },
            None => {
                result += suffix;
                break;
            }
        }
    }
    result
}

#[test]
fn test_parse_vars() {
    assert_eq!(
        expand_arg(
            "A$(test)$(inner)$(none)B",
            &|name: &str| -> Option<String> {
                match name {
                    "test" => Some("foo".to_string()),
                    "inner" => Some("$(bar)".to_string()),
                    "none" => None,
                    _ => {
                        unreachable!(format!("Unexpected value: {}", name));
                    }
                }
            },
        ),
        "Afoo$(bar)$(none)B"
    );
}

#[test]
fn test_is_flag() {
    assert!(is_flag("/Wait"));
    assert!(is_flag("/out=/foo/bar"));
    assert!(!is_flag("/out/foo/bar"));
    assert!(!is_flag("foo/bar"));
    assert!(!is_flag("/Wait.xml"));
    assert!(!is_flag("/Wait/foo=bar"));
    assert!(is_flag("/WaitFoo=bar"));
    assert!(!is_flag("/Wait.Foo=bar"));
    assert!(is_flag("/Wait=/foo/bar"));
}
<|endoftext|>


<commit_before>use bytes::{Buf, BufMut, Bytes};

use super::HttpBody;

/// Concatenate the buffers from a body into a single `Bytes` asynchronously.
///
/// This may require copying the data into a single buffer. If you don't need
/// a contiguous buffer, prefer the [`aggregate`](crate::body::aggregate())
/// function.
///
/// # Note
///
/// Care needs to be taken if the remote is untrusted. The function doesn't implement any length
/// checks and an malicious peer might make it consume arbitrary amounts of memory. Checking the
/// `Content-Length` is a possibility, but it is not strictly mandated to be present.
pub async fn to_bytes<T>(body: T) -> Result<Bytes, T::Error>
where
    T: HttpBody,
{
    futures_util::pin_mut!(body);

    // If there's only 1 chunk, we can just return Buf::to_bytes()
    let mut first = if let Some(buf) = body.data().await {
        buf?
    } else {
        return Ok(Bytes::new());
    };

    let second = if let Some(buf) = body.data().await {
        buf?
    } else {
        return Ok(first.copy_to_bytes(first.remaining()));
    };

    // With more than 1 buf, we gotta flatten into a Vec first.
    let cap = first.remaining() + second.remaining() + body.size_hint().lower() as usize;
    let mut vec = Vec::with_capacity(cap);
    vec.put(first);
    vec.put(second);

    while let Some(buf) = body.data().await {
        vec.put(buf?);
    }

    Ok(vec.into())
}
<commit_msg>docs(body): add example for to_bytes()<commit_after>use bytes::{Buf, BufMut, Bytes};

use super::HttpBody;

/// Concatenate the buffers from a body into a single `Bytes` asynchronously.
///
/// This may require copying the data into a single buffer. If you don't need
/// a contiguous buffer, prefer the [`aggregate`](crate::body::aggregate())
/// function.
///
/// # Note
///
/// Care needs to be taken if the remote is untrusted. The function doesn't implement any length
/// checks and an malicious peer might make it consume arbitrary amounts of memory. Checking the
/// `Content-Length` is a possibility, but it is not strictly mandated to be present.
///
/// # Example
///
/// ```
/// # async fn doc() -> hyper::Result<()> {
/// use hyper::{body::HttpBody};
///
/// # let request = hyper::Request::builder()
/// #        .method(hyper::Method::POST)
/// #        .uri("http://httpbin.org/post")
/// #        .header("content-type", "application/json")
/// #        .body(hyper::Body::from(r#"{"library":"hyper"}"#)).unwrap();
/// # let client = hyper::Client::new();
/// let response = client.request(request).await?;
///
/// const MAX_ALLOWED_RESPONSE_SIZE: u64 = 1024;
///
/// let response_content_length = match response.body().size_hint().upper() {
///     Some(v) => v,
///     None => MAX_ALLOWED_RESPONSE_SIZE + 1 // Just to protect ourselves from a malicious response
/// };
///
/// if response_content_length < MAX_ALLOWED_RESPONSE_SIZE {
///     let body_bytes = hyper::body::to_bytes(response.into_body()).await?;
///     println!("body: {:?}", body_bytes);
/// }
///
/// # Ok(())
/// # }
/// ```
pub async fn to_bytes<T>(body: T) -> Result<Bytes, T::Error>
where
    T: HttpBody,
{
    futures_util::pin_mut!(body);

    // If there's only 1 chunk, we can just return Buf::to_bytes()
    let mut first = if let Some(buf) = body.data().await {
        buf?
    } else {
        return Ok(Bytes::new());
    };

    let second = if let Some(buf) = body.data().await {
        buf?
    } else {
        return Ok(first.copy_to_bytes(first.remaining()));
    };

    // With more than 1 buf, we gotta flatten into a Vec first.
    let cap = first.remaining() + second.remaining() + body.size_hint().lower() as usize;
    let mut vec = Vec::with_capacity(cap);
    vec.put(first);
    vec.put(second);

    while let Some(buf) = body.data().await {
        vec.put(buf?);
    }

    Ok(vec.into())
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate coatcheck;
extern crate test;

use test::Bencher;
use std::collections::HashMap;

use coatcheck::*;

#[bench]
fn bench_hash_map(b: &mut Bencher) {
    let mut map = HashMap::with_capacity(6);
    b.iter(|| {
        map.insert(0us, "something");
        map.insert(1, "something");
        let _ = map.remove(&0);
        map.insert(2, "something");
        map.insert(3, "something");
        map.insert(4, "something");
        let _ = map.remove(&3);
        map.insert(5, "something");
        let _ = map.remove(&2);
        let _ = map.remove(&1);
        let _ = map.remove(&4);
        let _ = map.remove(&5);
    });
}

#[bench]
fn bench_coat_check(b: &mut Bencher) {
    let mut cc = CoatCheck::with_capacity(6);
    b.iter(|| {
        let t1 = cc.check("something");
        let t2 = cc.check("something");
        let _ = cc.claim(t1);
        let t3 = cc.check("something");
        let t4 = cc.check("something");
        let t5 = cc.check("something");
        let _ = cc.claim(t4);
        let t6 = cc.check("something");
        let _ = cc.claim(t3);
        let _ = cc.claim(t2);
        let _ = cc.claim(t5);
        let _ = cc.claim(t6);
    });
}

#[bench]
fn bench_box(b: &mut Bencher) {
    b.iter(|| {
        let b1 = Box::new("something");
        let b2 = Box::new("something");
        drop(b1);
        let b3 = Box::new("something");
        let b4 = Box::new("something");
        let b5 = Box::new("something");
        drop(b4);
        let b6 = Box::new("something");
        drop(b3);
        drop(b2);
        drop(b5);
        drop(b6);
    });
}

#[bench]
fn bench_coat_check_init(b: &mut Bencher) {
    b.iter(|| {
        for _ in 0..1000 {
            test::black_box(CoatCheck::<u64>::new());
        }
    });
}

#[bench]
fn bench_coat_check_access(b: &mut Bencher) {
    let mut cc = CoatCheck::new();
    let mut tickets = Vec::with_capacity(100);
    for _ in 0..100 {
        tickets.push(cc.check("something"));
    }
    let ref t = tickets[20];
    b.iter(|&: | {
        test::black_box(&cc[*t]);
    });
}

#[bench]
fn bench_hash_map_access(b: &mut Bencher) {
    let mut map = HashMap::with_capacity(100);
    for i in 0i32..100 {
        map.insert(i, "something");
    }
    b.iter(|&:| {
        test::black_box(&map[20i32]);
    });
}

<commit_msg>Fix closure syntax.<commit_after>#![feature(test)]

extern crate coatcheck;
extern crate test;

use test::Bencher;
use std::collections::HashMap;

use coatcheck::*;

#[bench]
fn bench_hash_map(b: &mut Bencher) {
    let mut map = HashMap::with_capacity(6);
    b.iter(|| {
        map.insert(0us, "something");
        map.insert(1, "something");
        let _ = map.remove(&0);
        map.insert(2, "something");
        map.insert(3, "something");
        map.insert(4, "something");
        let _ = map.remove(&3);
        map.insert(5, "something");
        let _ = map.remove(&2);
        let _ = map.remove(&1);
        let _ = map.remove(&4);
        let _ = map.remove(&5);
    });
}

#[bench]
fn bench_coat_check(b: &mut Bencher) {
    let mut cc = CoatCheck::with_capacity(6);
    b.iter(|| {
        let t1 = cc.check("something");
        let t2 = cc.check("something");
        let _ = cc.claim(t1);
        let t3 = cc.check("something");
        let t4 = cc.check("something");
        let t5 = cc.check("something");
        let _ = cc.claim(t4);
        let t6 = cc.check("something");
        let _ = cc.claim(t3);
        let _ = cc.claim(t2);
        let _ = cc.claim(t5);
        let _ = cc.claim(t6);
    });
}

#[bench]
fn bench_box(b: &mut Bencher) {
    b.iter(|| {
        let b1 = Box::new("something");
        let b2 = Box::new("something");
        drop(b1);
        let b3 = Box::new("something");
        let b4 = Box::new("something");
        let b5 = Box::new("something");
        drop(b4);
        let b6 = Box::new("something");
        drop(b3);
        drop(b2);
        drop(b5);
        drop(b6);
    });
}

#[bench]
fn bench_coat_check_init(b: &mut Bencher) {
    b.iter(|| {
        for _ in 0..1000 {
            test::black_box(CoatCheck::<u64>::new());
        }
    });
}

#[bench]
fn bench_coat_check_access(b: &mut Bencher) {
    let mut cc = CoatCheck::new();
    let mut tickets = Vec::with_capacity(100);
    for _ in 0..100 {
        tickets.push(cc.check("something"));
    }
    let ref t = tickets[20];
    b.iter(|| {
        test::black_box(&cc[*t]);
    });
}

#[bench]
fn bench_hash_map_access(b: &mut Bencher) {
    let mut map = HashMap::with_capacity(100);
    for i in 0i32..100 {
        map.insert(i, "something");
    }
    b.iter(|| {
        test::black_box(&map[20i32]);
    });
}

<|endoftext|>


<commit_before>use std::error::Error;
use std::fs::File;
use std::io::{ Read, Write };
use std::path::Path;

use reqwest;
use reqwest::header::{ ContentLength, Header, HeaderFormat};

pub fn download_file_and<F>(url: &str, output: &Path, and: F) -> Result<u64, String>
    where F: Fn(u64)
{
    let response = match reqwest::get(url) {
        Ok(x) => x,
        Err(why) => return Err("Error occured while making a GET request. Reason:".to_string() + why.description())
    };

    let mut target = match File::create(output) {
        Ok(x) => x,
        Err(why) => return Err("Error occured while creating file. Reason:".to_string() + why.description())
    };

    let length = match response.headers().get::<ContentLength>() {
        Some(x) => **x,
        None => 0u64
    };

    for byte in response.bytes() {
        target.write(&[byte.unwrap()]).unwrap();
    }

    and(length);
    Ok(length)
}<commit_msg>Use macros.<commit_after>use std::error::Error;
use std::fs::File;
use std::io::{ Read, Write };
use std::path::Path;

use reqwest;
use reqwest::header::{ ContentLength, Header, HeaderFormat};

macro_rules! get {
    ($x:expr, $y:expr) => (match $x {
        Ok(x) => x,
        Err(why) => return Err($y.to_string() + why.description()),
    });
}

pub fn download_file_and<F>(url: &str, output: &Path, and: F) -> Result<u64, String>
    where F: Fn(u64) {
    let response = get!(reqwest::get(url), "Error occured while making a GET request. Reason:\n");
    let mut target = get!(File::create(output), "Error occured while creating file. Reason:\n");

    let length = match response.headers().get::<ContentLength>() {
        Some(x) => **x,
        None => 0u64
    };

    for byte in response.bytes() {
        target.write(&[byte.unwrap()]).unwrap();
    }

    and(length);
    Ok(length)
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{c_void};
use std::ffi::CStr;
use std::ffi::CString;
use std::{ptr, thread, time};

use super::super::couchbase::*;

#[derive(Debug)]
pub struct ClientOps {
    pub total: usize
}

#[derive(Debug)]
pub struct Client {
    pub opts: CreateSt,
    pub instance: Instance,
    pub uri: String,
    pub ops: ClientOps
}

impl Client {
    pub fn new(uri: &str) -> Client {
        let connstr = CString::new(uri).unwrap();

        let mut opts = CreateSt::default();
        opts.v3.connstr = connstr.as_ptr();

        let mut instance: Instance = ptr::null_mut();

        unsafe {
            let res = lcb_create(&mut instance as *mut Instance, &opts as *const CreateSt);
            if res != ErrorType::Success {
                error!("lcb_connect() failed - {:?}", res);
            }

            info!("Connecting to {}", uri);

            let res = lcb_connect(instance);
            if res != ErrorType::Success {
                error!("lcb_connect() failed - {:?}", res);
            }

            let res = lcb_wait(instance);
            if res != ErrorType::Success {
                error!("lcb_wait() failed - {:?}", res);
            }

            let res = lcb_get_bootstrap_status(instance);
            if res != ErrorType::Success {
                error!("lcb_get_bootstrap_status() failed - {:?}, \"{}\"",
                         res,
                         CStr::from_ptr(lcb_strerror(instance, res)).to_str().unwrap()
                );
            }

            lcb_install_callback3(instance, CallbackType::Get, Some(op_callback));
            lcb_install_callback3(instance, CallbackType::Store, Some(op_callback));

            let ops = ClientOps {
                total: 0
            };

            Client {
                opts: opts,
                instance: instance,
                uri: uri.to_string(),
                ops: ops
            }
        }
    }

    pub fn get<F>(&mut self, key: &str, callback: F) -> &mut Client
        where F: Fn(&response::Get)
    {
        let ckey = CString::new(key).unwrap();
        let mut gcmd = cmd::Get::default();
        gcmd.key._type = KvBufferType::Copy;
        gcmd.key.contig.bytes = ckey.as_ptr() as *const libc::c_void;
        gcmd.key.contig.nbytes = key.len() as u64;

        self.ops.total += 1;

        unsafe {
            let boxed: Box<Fn(&response::Get)> = Box::new(|response: &response::Get| {
                callback(response);
            });

            let user_data = &boxed as *const _ as *mut c_void;

            let res = lcb_get3(self.instance, user_data, &gcmd as *const cmd::Get);
            if res != ErrorType::Success {
                println!("lcb_get3() failed - {:?}", res);
            }

            let res = lcb_wait(self.instance);
            if res != ErrorType::Success {
                println!("lcb_wait() failed - {:?}", res);
            }
        }

        return self;
    }

    pub fn store<F>(&mut self, key: &str, value: &str, callback: F) -> &mut Client
        where F: Fn(&response::Store)
    {
        let ckey = CString::new(key).unwrap();
        let cvalue = CString::new(value).unwrap();
        let mut gcmd = cmd::Store::default();
        gcmd.key._type = KvBufferType::Copy;
        gcmd.key.contig.bytes = ckey.as_ptr() as *const libc::c_void;
        gcmd.key.contig.nbytes = key.len() as u64;
        gcmd.value._type = KvBufferType::Copy;
        gcmd.value.contig.bytes = cvalue.as_ptr() as *const libc::c_void;
        gcmd.value.contig.nbytes = value.len() as u64;

        self.ops.total += 1;

        unsafe {
            let boxed: Box<Fn(&response::Store)> = Box::new(|res: &response::Store| {
                callback(res);
            });

            let user_data = &boxed as *const _ as *mut c_void;

            let res = lcb_store3(self.instance, user_data, &gcmd as *const cmd::Store);
            if res != ErrorType::Success {
                println!("lcb_get3() failed - {:?}", res);
            }

            let res = lcb_wait(self.instance);
            if res != ErrorType::Success {
                println!("lcb_wait() failed - {:?}", res);
            }
        }

        return self;
    }

    pub fn ops_unfinished_count(&self) -> usize {
        return self.ops.total;
    }

    pub fn ops_finished(&mut self) -> bool {
        return self.ops_unfinished_count() == 0;
    }

    pub fn wait(&mut self) {
         let interval = time::Duration::from_millis(100);
         while self.ops_finished() == false {
             thread::sleep(interval);
         }
    }

    pub fn wait_max(&mut self, max_msec: usize) {
        let mut t = 0 as usize;
        let interval = time::Duration::from_millis(100);
        while self.ops_finished() == false {
            thread::sleep(interval);
            t += 100;

            if t > max_msec {
                println!("wait_max - still {} operations unfinished", self.ops_unfinished_count());
                break;
            }
        }
    }
}

impl Drop for Client {
    fn drop(&mut self) {
        unsafe {
            info!("Disconnecting from {}", self.uri);
            lcb_destroy(self.instance);
        }
    }
}

unsafe extern "C" fn op_callback(_instance: Instance, cbtype: CallbackType, resp: *const response::Base) {
    match cbtype {
        CallbackType::Get => {
            let gresp = resp as *const response::Get;
            let cookie = (*gresp).cookie;
            let callback = cookie as *const Box<Fn(&response::Get)>;
            println!("{:?}", *gresp);
            (*callback)(&(*gresp));
        },
        CallbackType::Store => {
            let gresp = resp as *const response::Store;

            let cookie = (*gresp).cookie;
            let callback = cookie as *const Box<Fn(&response::Store)>;
            (*callback)(&(*gresp));
        },
        _ => error!("! Unknown Callback...")
    };
}

#[test]
fn it_works() {
    assert!(1 == 1);
}
<commit_msg>Add debug output<commit_after>extern crate libc;

use libc::{c_void};
use std::ffi::CStr;
use std::ffi::CString;
use std::{ptr, thread, time};

use super::super::couchbase::*;

#[derive(Debug)]
pub struct ClientOps {
    pub total: usize
}

#[derive(Debug)]
pub struct Client {
    pub opts: CreateSt,
    pub instance: Instance,
    pub uri: String,
    pub ops: ClientOps
}

impl Client {
    pub fn new(uri: &str) -> Client {
        let connstr = CString::new(uri).unwrap();

        let mut opts = CreateSt::default();
        opts.v3.connstr = connstr.as_ptr();

        let mut instance: Instance = ptr::null_mut();

        unsafe {
            let res = lcb_create(&mut instance as *mut Instance, &opts as *const CreateSt);
            if res != ErrorType::Success {
                error!("lcb_connect() failed - {:?}", res);
            }

            info!("Connecting to {}", uri);

            let res = lcb_connect(instance);
            if res != ErrorType::Success {
                error!("lcb_connect() failed - {:?}", res);
            }

            let res = lcb_wait(instance);
            if res != ErrorType::Success {
                error!("lcb_wait() failed - {:?}", res);
            }

            let res = lcb_get_bootstrap_status(instance);
            if res != ErrorType::Success {
                error!("lcb_get_bootstrap_status() failed - {:?}, \"{}\"",
                         res,
                         CStr::from_ptr(lcb_strerror(instance, res)).to_str().unwrap()
                );
            }

            lcb_install_callback3(instance, CallbackType::Get, Some(op_callback));
            lcb_install_callback3(instance, CallbackType::Store, Some(op_callback));

            let ops = ClientOps {
                total: 0
            };

            Client {
                opts: opts,
                instance: instance,
                uri: uri.to_string(),
                ops: ops
            }
        }
    }

    pub fn get<F>(&mut self, key: &str, callback: F) -> &mut Client
        where F: Fn(&response::Get)
    {
        let ckey = CString::new(key).unwrap();
        let mut gcmd = cmd::Get::default();
        gcmd.key._type = KvBufferType::Copy;
        gcmd.key.contig.bytes = ckey.as_ptr() as *const libc::c_void;
        gcmd.key.contig.nbytes = key.len() as u64;

        self.ops.total += 1;

        unsafe {
            let boxed: Box<Fn(&response::Get)> = Box::new(|response: &response::Get| {
                callback(response);
            });

            let user_data = &boxed as *const _ as *mut c_void;

            let res = lcb_get3(self.instance, user_data, &gcmd as *const cmd::Get);
            if res != ErrorType::Success {
                println!("lcb_get3() failed - {:?}", res);
            }

            let res = lcb_wait(self.instance);
            if res != ErrorType::Success {
                println!("lcb_wait() failed - {:?}", res);
            }
        }

        return self;
    }

    pub fn store<F>(&mut self, key: &str, value: &str, callback: F) -> &mut Client
        where F: Fn(&response::Store)
    {
        let ckey = CString::new(key).unwrap();
        let cvalue = CString::new(value).unwrap();
        let mut gcmd = cmd::Store::default();
        gcmd.key._type = KvBufferType::Copy;
        gcmd.key.contig.bytes = ckey.as_ptr() as *const libc::c_void;
        gcmd.key.contig.nbytes = key.len() as u64;
        gcmd.value._type = KvBufferType::Copy;
        gcmd.value.contig.bytes = cvalue.as_ptr() as *const libc::c_void;
        gcmd.value.contig.nbytes = value.len() as u64;

        self.ops.total += 1;

        unsafe {
            let boxed: Box<Fn(&response::Store)> = Box::new(|res: &response::Store| {
                callback(res);
            });

            let user_data = &boxed as *const _ as *mut c_void;

            let res = lcb_store3(self.instance, user_data, &gcmd as *const cmd::Store);
            if res != ErrorType::Success {
                println!("lcb_get3() failed - {:?}", res);
            }

            let res = lcb_wait(self.instance);
            if res != ErrorType::Success {
                println!("lcb_wait() failed - {:?}", res);
            }
        }

        return self;
    }

    pub fn ops_unfinished_count(&self) -> usize {
        return self.ops.total;
    }

    pub fn ops_finished(&mut self) -> bool {
        return self.ops_unfinished_count() == 0;
    }

    pub fn wait(&mut self) {
         let interval = time::Duration::from_millis(100);
         while self.ops_finished() == false {
             thread::sleep(interval);
         }
    }

    pub fn wait_max(&mut self, max_msec: usize) {
        let mut t = 0 as usize;
        let interval = time::Duration::from_millis(100);
        while self.ops_finished() == false {
            thread::sleep(interval);
            t += 100;

            if t > max_msec {
                println!("wait_max - still {} operations unfinished", self.ops_unfinished_count());
                break;
            }
        }
    }
}

impl Drop for Client {
    fn drop(&mut self) {
        unsafe {
            info!("Disconnecting from {}", self.uri);
            lcb_destroy(self.instance);
        }
    }
}

unsafe extern "C" fn op_callback(_instance: Instance, cbtype: CallbackType, resp: *const response::Base) {
    match cbtype {
        CallbackType::Get => {
            let gresp = resp as *const response::Get;
            debug!("{:?}", *gresp);

            let cookie = (*gresp).cookie;
            let callback = cookie as *const Box<Fn(&response::Get)>;
            (*callback)(&(*gresp));
        },
        CallbackType::Store => {
            let gresp = resp as *const response::Store;
            debug!("{:?}", *gresp);

            let cookie = (*gresp).cookie;
            let callback = cookie as *const Box<Fn(&response::Store)>;
            (*callback)(&(*gresp));
        },
        _ => error!("! Unknown Callback...")
    };
}

#[test]
fn it_works() {
    assert!(1 == 1);
}
<|endoftext|>


<commit_before>//! Provides the substrate for implementing pipelined, streaming protocols.
//!
//! In most cases, it's sufficient to work with `streaming::pipeline::{Client,
//! Server}` instead. But for some advanced protocols in which the client and
//! servers have more of a peer relationship, it's useful to work directly with
//! these implementation details.

use futures::sync::mpsc;
use futures::{Future, Poll, Async, Stream, Sink, AsyncSink, StartSend};
use std::io;
use streaming::{Message, Body};
use super::{Frame, Transport};
use buffer_one::BufferOne;

// TODO:
//
// - Wait for service readiness
// - Handle request body stream cancellation

/// Provides protocol pipelining functionality in a generic way over clients
/// and servers. Used internally by `pipeline::Client` and `pipeline::Server`.
pub struct Pipeline<T> where T: Dispatch {
    // True as long as the connection has more request frames to read.
    run: bool,

    // Glues the service with the pipeline task
    dispatch: BufferOne<DispatchSink<T>>,

    // The `Sender` for the current request body stream
    out_body: Option<BodySender<T::BodyOut, T::Error>>,

    // The response body stream
    in_body: Option<T::Stream>,

    // True when the transport is fully flushed
    is_flushed: bool,
}

/// Message used to communicate through the multiplex dispatch
pub type PipelineMessage<T, B, E> = Result<Message<T, B>, E>;

/// Dispatch messages from the transport to the service
pub trait Dispatch {
    /// Type of underlying I/O object
    type Io;

    /// Message written to transport
    type In;

    /// Body written to transport
    type BodyIn;

    /// Messages read from the transport
    type Out;

    /// Outbound body frame
    type BodyOut;

    /// Transport error
    type Error: From<io::Error>;

    /// Body stream written to transport
    type Stream: Stream<Item = Self::BodyIn, Error = Self::Error>;

    /// Transport type
    type Transport: Transport<Item = Frame<Self::Out, Self::BodyOut, Self::Error>,
                              SinkItem = Frame<Self::In, Self::BodyIn, Self::Error>>;

    /// Mutable reference to the transport
    fn transport(&mut self) -> &mut Self::Transport;

    /// Process an out message
    fn dispatch(&mut self, message: PipelineMessage<Self::Out, Body<Self::BodyOut, Self::Error>, Self::Error>) -> io::Result<()>;

    /// Poll the next completed message
    fn poll(&mut self) -> Poll<Option<PipelineMessage<Self::In, Self::Stream, Self::Error>>, io::Error>;

    /// RPC currently in flight
    /// TODO: Get rid of
    fn has_in_flight(&self) -> bool;
}

struct DispatchSink<T> {
    inner: T,
}

type BodySender<B, E> = BufferOne<mpsc::Sender<Result<B, E>>>;

impl<T> Pipeline<T> where T: Dispatch {
    /// Create a new pipeline `Pipeline` dispatcher with the given service and
    /// transport
    pub fn new(dispatch: T) -> Pipeline<T> {
        // Add `Sink` impl for `Dispatch`
        let dispatch = DispatchSink { inner: dispatch };

        // Add a single slot buffer for the sink
        let dispatch = BufferOne::new(dispatch);

        Pipeline {
            run: true,
            dispatch: dispatch,
            out_body: None,
            in_body: None,
            is_flushed: true,
        }
    }

    /// Returns true if the pipeline server dispatch has nothing left to do
    fn is_done(&self) -> bool {
        !self.run && self.is_flushed && !self.has_in_flight()
    }

    fn read_out_frames(&mut self) -> io::Result<()> {
        while self.run {
            // Return true if the pipeliner can process new outbound frames
            if !self.check_out_body_stream() {
                break;
            }

            if let Async::Ready(frame) = try!(self.dispatch.get_mut().inner.transport().poll()) {
                try!(self.process_out_frame(frame));
            } else {
                break;
            }
        }

        Ok(())
    }

    fn check_out_body_stream(&mut self) -> bool {
        let body = match self.out_body {
            Some(ref mut body) => body,
            None => return true,
        };

        body.poll_ready().is_ready()
    }

    fn process_out_frame(&mut self,
                         frame: Option<Frame<T::Out, T::BodyOut, T::Error>>)
                         -> io::Result<()> {
        trace!("process_out_frame");
        // At this point, the service & transport are ready to process the
        // frame, no matter what it is.
        match frame {
            Some(Frame::Message { message, body }) => {
                if body {
                    trace!("read out message with body");

                    let (tx, rx) = Body::pair();
                    let message = Message::WithBody(message, rx);

                    // Track the out body sender. If `self.out_body`
                    // currently holds a sender for the previous out body, it
                    // will get dropped. This terminates the stream.
                    self.out_body = Some(BufferOne::new(tx));

                    if let Err(_) = self.dispatch.get_mut().inner.dispatch(Ok(message)) {
                        // TODO: Should dispatch be infallible
                        unimplemented!();
                    }
                } else {
                    trace!("read out message");

                    let message = Message::WithoutBody(message);

                    // There is no streaming body. Set `out_body` to `None` so that
                    // the previous body stream is dropped.
                    self.out_body = None;

                    if let Err(_) = self.dispatch.get_mut().inner.dispatch(Ok(message)) {
                        // TODO: Should dispatch be infalliable
                        unimplemented!();
                    }
                }
            }
            Some(Frame::Body { chunk }) => {
                match chunk {
                    Some(chunk) => {
                        trace!("read out body chunk");
                        try!(self.process_out_body_chunk(chunk));
                    }
                    None => {
                        trace!("read out body EOF");
                        // Drop the sender.
                        // TODO: Ensure a sender exists
                        let _ = self.out_body.take();
                    }
                }
            }
            None => {
                trace!("read None");
                // At this point, we just return. This works
                // because tick() will be called again and go
                // through the read-cycle again.
                self.run = false;
            }
            Some(Frame::Error { .. }) => {
                // At this point, the transport is toast, there
                // isn't much else that we can do. Killing the task
                // will cause all in-flight requests to abort, but
                // they can't be written to the transport anyway...
                return Err(io::Error::new(io::ErrorKind::BrokenPipe, "An error occurred."));
            }
        }

        Ok(())
    }

    fn process_out_body_chunk(&mut self, chunk: T::BodyOut) -> io::Result<()> {
        trace!("process_out_body_chunk");
        let mut reset = false;
        match self.out_body {
            Some(ref mut body) => {
                debug!("sending a chunk");

                // Try sending the out body chunk
                match body.start_send(Ok(chunk)) {
                    Ok(AsyncSink::Ready) => debug!("immediately done"),
                    Err(_e) => reset = true, // interest canceled
                    Ok(AsyncSink::NotReady(_)) => {
                        // poll_ready() is checked before entering this path
                        unreachable!();
                    }
                }
            }
            None => {
                debug!("interest canceled");
                // The rx half canceled interest, there is nothing else to do
            }
        }
        if reset {
            self.out_body = None;
        }
        Ok(())
    }

    fn write_in_frames(&mut self) -> io::Result<()> {
        trace!("write_in_frames");
        while self.dispatch.poll_ready().is_ready() {
            // Ensure the current in body is fully written
            if !try!(self.write_in_body()) {
                debug!("write in body not done");
                break;
            }
            debug!("write in body done");

            // Write the next in-flight in message
            match try!(self.dispatch.get_mut().inner.poll()) {
                Async::Ready(Some(Ok(message))) => {
                    trace!("   --> got message");
                    try!(self.write_in_message(Ok(message)));
                }
                Async::Ready(Some(Err(error))) => {
                    trace!("   --> got error");
                    try!(self.write_in_message(Err(error)));
                }
                Async::Ready(None) => {
                    trace!("   --> got None");
                    // The service is done with the connection.
                    break;
                }
                // Nothing to dispatch
                Async::NotReady => break,
            }
        }

        Ok(())
    }

    fn write_in_message(&mut self, message: Result<Message<T::In, T::Stream>, T::Error>) -> io::Result<()> {
        trace!("write_in_message");
        match message {
            Ok(Message::WithoutBody(val)) => {
                trace!("got in_flight value without body");
                let msg = Frame::Message { message: val, body: false };
                try!(assert_send(&mut self.dispatch, msg));

                // TODO: don't panic maybe if this isn't true?
                assert!(self.in_body.is_none());

                // Track the response body
                self.in_body = None;
            }
            Ok(Message::WithBody(val, body)) => {
                trace!("got in_flight value with body");
                let msg = Frame::Message { message: val, body: true };
                try!(assert_send(&mut self.dispatch, msg));

                // TODO: don't panic maybe if this isn't true?
                assert!(self.in_body.is_none());

                // Track the response body
                self.in_body = Some(body);
            }
            Err(e) => {
                trace!("got in_flight error");
                let msg = Frame::Error { error: e };
                try!(assert_send(&mut self.dispatch, msg));
            }
        }

        Ok(())
    }

    // Returns true if the response body is fully written
    fn write_in_body(&mut self) -> io::Result<bool> {
        trace!("write_in_body");

        if self.in_body.is_some() {
            loop {
                // Even though this is checked before entering the function, checking should be
                // cheap and this is looped
                if !self.dispatch.poll_ready().is_ready() {
                    return Ok(false);
                }

                match self.in_body.as_mut().unwrap().poll() {
                    Ok(Async::Ready(Some(chunk))) => {
                        try!(assert_send(&mut self.dispatch,
                                         Frame::Body { chunk: Some(chunk) }));
                    }
                    Ok(Async::Ready(None)) => {
                        try!(assert_send(&mut self.dispatch,
                                         Frame::Body { chunk: None }));
                        break;
                    }
                    Err(_) => {
                        unimplemented!();
                    }
                    Ok(Async::NotReady) => {
                        debug!("not ready");
                        return Ok(false);
                    }
                }
            }
        }

        self.in_body = None;
        Ok(true)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.is_flushed = try!(self.dispatch.poll_complete()).is_ready();

        if let Some(ref mut out_body) = self.out_body {
            if out_body.poll_complete().is_ok() {
                return Ok(());
            }
        } else {
            return Ok(());
        }

        // Fall through and unset out_body
        self.out_body = None;
        Ok(())
    }

    fn has_in_flight(&self) -> bool {
        self.dispatch.get_ref().inner.has_in_flight()
    }
}

impl<T> Future for Pipeline<T> where T: Dispatch {
    type Item = ();
    type Error = io::Error;

    // Tick the pipeline state machine
    fn poll(&mut self) -> Poll<(), io::Error> {
        trace!("Pipeline::tick");

        // Always tick the transport first
        self.dispatch.get_mut().inner.transport().tick();

        // First read off data from the socket
        try!(self.read_out_frames());

        // Handle completed responses
        try!(self.write_in_frames());

        // Try flushing buffered writes
        try!(self.flush());

        // Clean shutdown of the pipeline server can happen when
        //
        // 1. The server is done running, this is signaled by Transport::poll()
        //    returning None.
        //
        // 2. The transport is done writing all data to the socket, this is
        //    signaled by Transport::flush() returning Ok(Some(())).
        //
        // 3. There are no further responses to write to the transport.
        //
        // It is necessary to perfom these three checks in order to handle the
        // case where the client shuts down half the socket.
        //
        if self.is_done() {
            return Ok(().into())
        }

        // Tick again later
        Ok(Async::NotReady)
    }
}

impl<T: Dispatch> Sink for DispatchSink<T> {
    type SinkItem = <T::Transport as Sink>::SinkItem;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Self::SinkItem)
                  -> StartSend<Self::SinkItem, io::Error>
    {
        self.inner.transport().start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        self.inner.transport().poll_complete()
    }
}

fn assert_send<S: Sink>(s: &mut S, item: S::SinkItem) -> Result<(), S::SinkError> {
    match try!(s.start_send(item)) {
        AsyncSink::Ready => Ok(()),
        AsyncSink::NotReady(_) => {
            panic!("sink reported itself as ready after `poll_ready` but was \
                    then unable to accept a message")
        }
    }
}
<commit_msg>Include transport errors in panic message.<commit_after>//! Provides the substrate for implementing pipelined, streaming protocols.
//!
//! In most cases, it's sufficient to work with `streaming::pipeline::{Client,
//! Server}` instead. But for some advanced protocols in which the client and
//! servers have more of a peer relationship, it's useful to work directly with
//! these implementation details.

use futures::sync::mpsc;
use futures::{Future, Poll, Async, Stream, Sink, AsyncSink, StartSend};
use std::io;
use streaming::{Message, Body};
use super::{Frame, Transport};
use buffer_one::BufferOne;

// TODO:
//
// - Wait for service readiness
// - Handle request body stream cancellation

/// Provides protocol pipelining functionality in a generic way over clients
/// and servers. Used internally by `pipeline::Client` and `pipeline::Server`.
pub struct Pipeline<T> where T: Dispatch {
    // True as long as the connection has more request frames to read.
    run: bool,

    // Glues the service with the pipeline task
    dispatch: BufferOne<DispatchSink<T>>,

    // The `Sender` for the current request body stream
    out_body: Option<BodySender<T::BodyOut, T::Error>>,

    // The response body stream
    in_body: Option<T::Stream>,

    // True when the transport is fully flushed
    is_flushed: bool,
}

/// Message used to communicate through the multiplex dispatch
pub type PipelineMessage<T, B, E> = Result<Message<T, B>, E>;

/// Dispatch messages from the transport to the service
pub trait Dispatch {
    /// Type of underlying I/O object
    type Io;

    /// Message written to transport
    type In;

    /// Body written to transport
    type BodyIn;

    /// Messages read from the transport
    type Out;

    /// Outbound body frame
    type BodyOut;

    /// Transport error
    type Error: From<io::Error>;

    /// Body stream written to transport
    type Stream: Stream<Item = Self::BodyIn, Error = Self::Error>;

    /// Transport type
    type Transport: Transport<Item = Frame<Self::Out, Self::BodyOut, Self::Error>,
                              SinkItem = Frame<Self::In, Self::BodyIn, Self::Error>>;

    /// Mutable reference to the transport
    fn transport(&mut self) -> &mut Self::Transport;

    /// Process an out message
    fn dispatch(&mut self, message: PipelineMessage<Self::Out, Body<Self::BodyOut, Self::Error>, Self::Error>) -> io::Result<()>;

    /// Poll the next completed message
    fn poll(&mut self) -> Poll<Option<PipelineMessage<Self::In, Self::Stream, Self::Error>>, io::Error>;

    /// RPC currently in flight
    /// TODO: Get rid of
    fn has_in_flight(&self) -> bool;
}

struct DispatchSink<T> {
    inner: T,
}

type BodySender<B, E> = BufferOne<mpsc::Sender<Result<B, E>>>;

impl<T> Pipeline<T> where T: Dispatch {
    /// Create a new pipeline `Pipeline` dispatcher with the given service and
    /// transport
    pub fn new(dispatch: T) -> Pipeline<T> {
        // Add `Sink` impl for `Dispatch`
        let dispatch = DispatchSink { inner: dispatch };

        // Add a single slot buffer for the sink
        let dispatch = BufferOne::new(dispatch);

        Pipeline {
            run: true,
            dispatch: dispatch,
            out_body: None,
            in_body: None,
            is_flushed: true,
        }
    }

    /// Returns true if the pipeline server dispatch has nothing left to do
    fn is_done(&self) -> bool {
        !self.run && self.is_flushed && !self.has_in_flight()
    }

    fn read_out_frames(&mut self) -> io::Result<()> {
        while self.run {
            // Return true if the pipeliner can process new outbound frames
            if !self.check_out_body_stream() {
                break;
            }

            if let Async::Ready(frame) = try!(self.dispatch.get_mut().inner.transport().poll()) {
                try!(self.process_out_frame(frame));
            } else {
                break;
            }
        }

        Ok(())
    }

    fn check_out_body_stream(&mut self) -> bool {
        let body = match self.out_body {
            Some(ref mut body) => body,
            None => return true,
        };

        body.poll_ready().is_ready()
    }

    fn process_out_frame(&mut self,
                         frame: Option<Frame<T::Out, T::BodyOut, T::Error>>)
                         -> io::Result<()> {
        trace!("process_out_frame");
        // At this point, the service & transport are ready to process the
        // frame, no matter what it is.
        match frame {
            Some(Frame::Message { message, body }) => {
                if body {
                    trace!("read out message with body");

                    let (tx, rx) = Body::pair();
                    let message = Message::WithBody(message, rx);

                    // Track the out body sender. If `self.out_body`
                    // currently holds a sender for the previous out body, it
                    // will get dropped. This terminates the stream.
                    self.out_body = Some(BufferOne::new(tx));

                    if let Err(e) = self.dispatch.get_mut().inner.dispatch(Ok(message)) {
                        // TODO: Should dispatch be infallible
                        panic!("unimplemented error handling: {:?}", e);
                    }
                } else {
                    trace!("read out message");

                    let message = Message::WithoutBody(message);

                    // There is no streaming body. Set `out_body` to `None` so that
                    // the previous body stream is dropped.
                    self.out_body = None;

                    if let Err(e) = self.dispatch.get_mut().inner.dispatch(Ok(message)) {
                        // TODO: Should dispatch be infalliable
                        panic!("unimplemented error handling: {:?}", e);
                    }
                }
            }
            Some(Frame::Body { chunk }) => {
                match chunk {
                    Some(chunk) => {
                        trace!("read out body chunk");
                        try!(self.process_out_body_chunk(chunk));
                    }
                    None => {
                        trace!("read out body EOF");
                        // Drop the sender.
                        // TODO: Ensure a sender exists
                        let _ = self.out_body.take();
                    }
                }
            }
            None => {
                trace!("read None");
                // At this point, we just return. This works
                // because tick() will be called again and go
                // through the read-cycle again.
                self.run = false;
            }
            Some(Frame::Error { .. }) => {
                // At this point, the transport is toast, there
                // isn't much else that we can do. Killing the task
                // will cause all in-flight requests to abort, but
                // they can't be written to the transport anyway...
                return Err(io::Error::new(io::ErrorKind::BrokenPipe, "An error occurred."));
            }
        }

        Ok(())
    }

    fn process_out_body_chunk(&mut self, chunk: T::BodyOut) -> io::Result<()> {
        trace!("process_out_body_chunk");
        let mut reset = false;
        match self.out_body {
            Some(ref mut body) => {
                debug!("sending a chunk");

                // Try sending the out body chunk
                match body.start_send(Ok(chunk)) {
                    Ok(AsyncSink::Ready) => debug!("immediately done"),
                    Err(_e) => reset = true, // interest canceled
                    Ok(AsyncSink::NotReady(_)) => {
                        // poll_ready() is checked before entering this path
                        unreachable!();
                    }
                }
            }
            None => {
                debug!("interest canceled");
                // The rx half canceled interest, there is nothing else to do
            }
        }
        if reset {
            self.out_body = None;
        }
        Ok(())
    }

    fn write_in_frames(&mut self) -> io::Result<()> {
        trace!("write_in_frames");
        while self.dispatch.poll_ready().is_ready() {
            // Ensure the current in body is fully written
            if !try!(self.write_in_body()) {
                debug!("write in body not done");
                break;
            }
            debug!("write in body done");

            // Write the next in-flight in message
            match try!(self.dispatch.get_mut().inner.poll()) {
                Async::Ready(Some(Ok(message))) => {
                    trace!("   --> got message");
                    try!(self.write_in_message(Ok(message)));
                }
                Async::Ready(Some(Err(error))) => {
                    trace!("   --> got error");
                    try!(self.write_in_message(Err(error)));
                }
                Async::Ready(None) => {
                    trace!("   --> got None");
                    // The service is done with the connection.
                    break;
                }
                // Nothing to dispatch
                Async::NotReady => break,
            }
        }

        Ok(())
    }

    fn write_in_message(&mut self, message: Result<Message<T::In, T::Stream>, T::Error>) -> io::Result<()> {
        trace!("write_in_message");
        match message {
            Ok(Message::WithoutBody(val)) => {
                trace!("got in_flight value without body");
                let msg = Frame::Message { message: val, body: false };
                try!(assert_send(&mut self.dispatch, msg));

                // TODO: don't panic maybe if this isn't true?
                assert!(self.in_body.is_none());

                // Track the response body
                self.in_body = None;
            }
            Ok(Message::WithBody(val, body)) => {
                trace!("got in_flight value with body");
                let msg = Frame::Message { message: val, body: true };
                try!(assert_send(&mut self.dispatch, msg));

                // TODO: don't panic maybe if this isn't true?
                assert!(self.in_body.is_none());

                // Track the response body
                self.in_body = Some(body);
            }
            Err(e) => {
                trace!("got in_flight error");
                let msg = Frame::Error { error: e };
                try!(assert_send(&mut self.dispatch, msg));
            }
        }

        Ok(())
    }

    // Returns true if the response body is fully written
    fn write_in_body(&mut self) -> io::Result<bool> {
        trace!("write_in_body");

        if self.in_body.is_some() {
            loop {
                // Even though this is checked before entering the function, checking should be
                // cheap and this is looped
                if !self.dispatch.poll_ready().is_ready() {
                    return Ok(false);
                }

                match self.in_body.as_mut().unwrap().poll() {
                    Ok(Async::Ready(Some(chunk))) => {
                        try!(assert_send(&mut self.dispatch,
                                         Frame::Body { chunk: Some(chunk) }));
                    }
                    Ok(Async::Ready(None)) => {
                        try!(assert_send(&mut self.dispatch,
                                         Frame::Body { chunk: None }));
                        break;
                    }
                    Err(_) => {
                        unimplemented!();
                    }
                    Ok(Async::NotReady) => {
                        debug!("not ready");
                        return Ok(false);
                    }
                }
            }
        }

        self.in_body = None;
        Ok(true)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.is_flushed = try!(self.dispatch.poll_complete()).is_ready();

        if let Some(ref mut out_body) = self.out_body {
            if out_body.poll_complete().is_ok() {
                return Ok(());
            }
        } else {
            return Ok(());
        }

        // Fall through and unset out_body
        self.out_body = None;
        Ok(())
    }

    fn has_in_flight(&self) -> bool {
        self.dispatch.get_ref().inner.has_in_flight()
    }
}

impl<T> Future for Pipeline<T> where T: Dispatch {
    type Item = ();
    type Error = io::Error;

    // Tick the pipeline state machine
    fn poll(&mut self) -> Poll<(), io::Error> {
        trace!("Pipeline::tick");

        // Always tick the transport first
        self.dispatch.get_mut().inner.transport().tick();

        // First read off data from the socket
        try!(self.read_out_frames());

        // Handle completed responses
        try!(self.write_in_frames());

        // Try flushing buffered writes
        try!(self.flush());

        // Clean shutdown of the pipeline server can happen when
        //
        // 1. The server is done running, this is signaled by Transport::poll()
        //    returning None.
        //
        // 2. The transport is done writing all data to the socket, this is
        //    signaled by Transport::flush() returning Ok(Some(())).
        //
        // 3. There are no further responses to write to the transport.
        //
        // It is necessary to perfom these three checks in order to handle the
        // case where the client shuts down half the socket.
        //
        if self.is_done() {
            return Ok(().into())
        }

        // Tick again later
        Ok(Async::NotReady)
    }
}

impl<T: Dispatch> Sink for DispatchSink<T> {
    type SinkItem = <T::Transport as Sink>::SinkItem;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Self::SinkItem)
                  -> StartSend<Self::SinkItem, io::Error>
    {
        self.inner.transport().start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        self.inner.transport().poll_complete()
    }
}

fn assert_send<S: Sink>(s: &mut S, item: S::SinkItem) -> Result<(), S::SinkError> {
    match try!(s.start_send(item)) {
        AsyncSink::Ready => Ok(()),
        AsyncSink::NotReady(_) => {
            panic!("sink reported itself as ready after `poll_ready` but was \
                    then unable to accept a message")
        }
    }
}
<|endoftext|>


<commit_before>extern crate gl;
extern crate glfw;
extern crate time;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem::size_of;

macro_rules! gl_str {
    ($string_literal:expr) => (concat!($string_literal, '\0').as_bytes().as_ptr() as *const GLchar)
}

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150

    in vec2 position;
    in vec3 color;

    out vec3 Color;

    void main() {
        Color = color;
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150

    in vec3 Color;

    out vec4 out_color;

    void main() {
        out_color = vec4(Color, 1.0);
    }
";

#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C, packed)]
struct Vertex {
    // Position.
    x: GLfloat, y: GLfloat,

    // Color.
    r: GLfloat, g: GLfloat, b: GLfloat,
}

static VERTICES: [Vertex; 6] = [
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0 }, // Top-left
    Vertex { x:  0.5, y:  0.5, r: 0.0, g: 1.0, b: 0.0 }, // Top-right
    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0 }, // Bottom-right

    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0 }, // Bottom-right
    Vertex { x: -0.5, y: -0.5, r: 1.0, g: 1.0, b: 1.0 }, // Bottom-left
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0 }, // Top-left
];

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(),
        buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
        // Create a vertex array object.
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a vertex buffer object and copy the vertex data to it.
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       (VERTICES.len() * size_of::<Vertex>()) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, gl_str!("out_color"));
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("position"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                size_of::<Vertex>() as GLint, std::ptr::null());

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("color"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 3, gl::FLOAT, gl::FALSE,
                                size_of::<Vertex>() as GLint,
                                std::ptr::null().offset(2 * size_of::<GLfloat>() as isize));
    }

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices.
            gl::DrawArrays(gl::TRIANGLES, 0, VERTICES.len() as GLint);
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<commit_msg>Use mem::size_of_val to get array byte size easily.<commit_after>extern crate gl;
extern crate glfw;
extern crate time;

use gl::types::*;
use glfw::{Context, OpenGlProfileHint, WindowHint, WindowMode};
use std::mem;

macro_rules! gl_str {
    ($string_literal:expr) => (concat!($string_literal, '\0').as_bytes().as_ptr() as *const GLchar)
}

const VERTEX_SHADER_SOURCE: &'static str = "
    #version 150

    in vec2 position;
    in vec3 color;

    out vec3 Color;

    void main() {
        Color = color;
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

const FRAGMENT_SHADER_SOURCE: &'static str = "
    #version 150

    in vec3 Color;

    out vec4 out_color;

    void main() {
        out_color = vec4(Color, 1.0);
    }
";

#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(C, packed)]
struct Vertex {
    // Position.
    x: GLfloat, y: GLfloat,

    // Color.
    r: GLfloat, g: GLfloat, b: GLfloat,
}

static VERTICES: [Vertex; 6] = [
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0 }, // Top-left
    Vertex { x:  0.5, y:  0.5, r: 0.0, g: 1.0, b: 0.0 }, // Top-right
    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0 }, // Bottom-right

    Vertex { x:  0.5, y: -0.5, r: 0.0, g: 0.0, b: 1.0 }, // Bottom-right
    Vertex { x: -0.5, y: -0.5, r: 1.0, g: 1.0, b: 1.0 }, // Bottom-left
    Vertex { x: -0.5, y:  0.5, r: 1.0, g: 0.0, b: 0.0 }, // Top-left
];

unsafe fn compile_shader(shader_type: GLenum, source: &str) -> Result<GLuint, String> {
    let shader = gl::CreateShader(shader_type);
    let source_ptr = source.as_bytes().as_ptr() as *const GLchar;
    let source_len = source.len() as GLint;
    gl::ShaderSource(shader, 1, &source_ptr, &source_len);
    gl::CompileShader(shader);

    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

    if status == gl::TRUE as GLint {
        Ok(shader)
    } else {
        let mut log_len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut log_len);
        if log_len == 0 { return Err(String::new()) }

        let mut buf = Vec::with_capacity(log_len as usize);
        buf.set_len(log_len as usize - 1); // Subtract 1 to ignore the trailing null.
        gl::GetShaderInfoLog(shader, log_len, std::ptr::null_mut(),
        buf.as_mut_ptr() as *mut GLchar);

        Err(String::from_utf8_lossy(&buf).into_owned())
    }
}

fn main() {
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

    glfw.window_hint(WindowHint::ContextVersion(3, 2));
    glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core));
    glfw.window_hint(WindowHint::OpenGlForwardCompat(true));
    glfw.window_hint(WindowHint::Resizable(false));

    let (mut window, events) = glfw.create_window(800, 600, "OpenGL", WindowMode::Windowed)
        .expect("Failed to create GLFW window.");

    // Listen for keyboard events on this window.
    window.set_key_polling(true);

    // Make this window's OpenGL context the current context. This must be done before calling
    // `gl::load_with`.
    window.make_current();

    // Load OpenGL function pointers.
    gl::load_with(|symbol| window.get_proc_address(symbol));

    let vertex_shader;
    let fragment_shader;
    let shader_program;
    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
        // Create a vertex array object.
        gl::GenVertexArrays(1, &mut vao);
        gl::BindVertexArray(vao);

        // Create a vertex buffer object and copy the vertex data to it.
        gl::GenBuffers(1, &mut vbo);
        gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
        gl::BufferData(gl::ARRAY_BUFFER,
                       mem::size_of_val(&VERTICES) as GLsizeiptr,
                       VERTICES.as_ptr() as *const GLvoid,
                       gl::STATIC_DRAW);

        // Compile the vertex and fragment shaders.
        vertex_shader = compile_shader(gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE).unwrap();
        fragment_shader = compile_shader(gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE).unwrap();

        // Link the vertex and fragment shaders into a shader program.
        shader_program = gl::CreateProgram();
        gl::AttachShader(shader_program, vertex_shader);
        gl::AttachShader(shader_program, fragment_shader);
        gl::BindFragDataLocation(shader_program, 0, gl_str!("out_color"));
        gl::LinkProgram(shader_program);
        gl::UseProgram(shader_program);

        // Specify the layout of the vertex data.
        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("position"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 2, gl::FLOAT, gl::FALSE,
                                size_of::<Vertex>() as GLint, std::ptr::null());

        let position_attrib = gl::GetAttribLocation(shader_program, gl_str!("color"));
        gl::EnableVertexAttribArray(position_attrib as GLuint);
        gl::VertexAttribPointer(position_attrib as GLuint, 3, gl::FLOAT, gl::FALSE,
                                size_of::<Vertex>() as GLint,
                                std::ptr::null().offset(2 * size_of::<GLfloat>() as isize));
    }

    while !window.should_close() {
        glfw.poll_events();
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&mut window, event);
        }

        unsafe {
            // Clear the screen to black.
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT);

            // Draw a triangle from the 3 vertices.
            gl::DrawArrays(gl::TRIANGLES, 0, VERTICES.len() as GLint);
        }

        window.swap_buffers();
    }

    unsafe {
        gl::DeleteProgram(shader_program);
        gl::DeleteShader(fragment_shader);
        gl::DeleteShader(vertex_shader);
        gl::DeleteBuffers(1, &vbo);
        gl::DeleteVertexArrays(1, &vao);
    }
}

fn handle_window_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
    use glfw::{Action, Key, WindowEvent};

    match event {
        WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
            window.set_should_close(true);
        },
        _ => {},
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
extern crate mdbook;
#[macro_use]
extern crate clap;

use std::env;
use std::error::Error;
use std::io::{self, Write};
use std::path::{Path, PathBuf};

use clap::{App, ArgMatches, SubCommand, AppSettings};

use mdbook::MDBook;

fn main() {
    let d_message = "-d, --dest-dir=[dest-dir]
'The output directory for your book{n}(Defaults to ./book when omitted)'";
    let dir_message = "[dir]
'A directory for your book{n}(Defaults to Current Directory when omitted)'";

    let matches = App::new("rustbook")
                    .about("Build a book with mdBook")
                    .author("Steve Klabnik <steve@steveklabnik.com>")
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage(d_message)
                        .arg_from_usage(dir_message))
                    .get_matches();

    // Check which subcomamnd the user ran...
    let res = match matches.subcommand() {
        ("build", Some(sub_matches)) => build(sub_matches),
        ("test", Some(sub_matches)) => test(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
        ::std::process::exit(101);
    }
}

// Build command implementation
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book = build_mdbook_struct(args);

    let mut book = match args.value_of("dest-dir") {
        Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
        None => book
    };

    try!(book.build());

    Ok(())
}

fn test(args: &ArgMatches) -> Result<(), Box<Error>> {
    let mut book = build_mdbook_struct(args);

    try!(book.test());

    Ok(())
}

fn build_mdbook_struct(args: &ArgMatches) -> mdbook::MDBook {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    // By default mdbook will attempt to create non-existent files referenced
    // from SUMMARY.md files. This is problematic on CI where we mount the
    // source directory as readonly. To avoid any issues, we'll disabled
    // mdbook's implicit file creation feature.
    book.create_missing = false;

    book
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}
<commit_msg>Rollup merge of #44313 - RalfJung:book, r=nikomatsakis<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
extern crate mdbook;
#[macro_use]
extern crate clap;

use std::env;
use std::error::Error;
use std::io::{self, Write};
use std::path::{Path, PathBuf};

use clap::{App, ArgMatches, SubCommand, AppSettings};

use mdbook::MDBook;

fn main() {
    let d_message = "-d, --dest-dir=[dest-dir]
'The output directory for your book{n}(Defaults to ./book when omitted)'";
    let dir_message = "[dir]
'A directory for your book{n}(Defaults to Current Directory when omitted)'";

    let matches = App::new("rustbook")
                    .about("Build a book with mdBook")
                    .author("Steve Klabnik <steve@steveklabnik.com>")
                    .version(&*format!("v{}", crate_version!()))
                    .setting(AppSettings::SubcommandRequired)
                    .subcommand(SubCommand::with_name("build")
                        .about("Build the book from the markdown files")
                        .arg_from_usage(d_message)
                        .arg_from_usage(dir_message))
                    .get_matches();

    // Check which subcomamnd the user ran...
    let res = match matches.subcommand() {
        ("build", Some(sub_matches)) => build(sub_matches),
        (_, _) => unreachable!(),
    };

    if let Err(e) = res {
        writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
        ::std::process::exit(101);
    }
}

// Build command implementation
fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
    let book = build_mdbook_struct(args);

    let mut book = match args.value_of("dest-dir") {
        Some(dest_dir) => book.set_dest(Path::new(dest_dir)),
        None => book
    };

    try!(book.build());

    Ok(())
}

fn build_mdbook_struct(args: &ArgMatches) -> mdbook::MDBook {
    let book_dir = get_book_dir(args);
    let mut book = MDBook::new(&book_dir).read_config();

    // By default mdbook will attempt to create non-existent files referenced
    // from SUMMARY.md files. This is problematic on CI where we mount the
    // source directory as readonly. To avoid any issues, we'll disabled
    // mdbook's implicit file creation feature.
    book.create_missing = false;

    book
}

fn get_book_dir(args: &ArgMatches) -> PathBuf {
    if let Some(dir) = args.value_of("dir") {
        // Check if path is relative from current dir, or absolute...
        let p = Path::new(dir);
        if p.is_relative() {
            env::current_dir().unwrap().join(dir)
        } else {
            p.to_path_buf()
        }
    } else {
        env::current_dir().unwrap()
    }
}
<|endoftext|>


<commit_before>use ::core::ui::KeyOrButton;
use ::monet::glium::glutin::{MouseButton, VirtualKeyCode};
use serde_json;

use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

#[derive(Serialize, Deserialize, PartialEq)]
pub struct Settings {
    //Controls
    pub rotation_speed: f32,
    pub move_speed: f32,
    pub zoom_speed: f32,
    pub invert_y: bool,

    pub mouse_main: Vec<KeyOrButton>,

    pub forward_key: Vec<KeyOrButton>,
    pub backward_key: Vec<KeyOrButton>,
    pub left_key: Vec<KeyOrButton>,
    pub right_key: Vec<KeyOrButton>,
    pub pan_modifier_key: Vec<KeyOrButton>,
    pub rotate_modifier_key: Vec<KeyOrButton>,
}

impl Settings{
    pub fn new() -> Settings{
        Settings{
            rotation_speed: 1.0f32,
            zoom_speed: 1.0f32,
            move_speed: 1.0f32,
            invert_y: false,

            mouse_main: vec![KeyOrButton::Button(MouseButton::Left)],
            forward_key: vec![KeyOrButton::Key(VirtualKeyCode::W), KeyOrButton::Key(VirtualKeyCode::Up)],
            backward_key: vec![KeyOrButton::Key(VirtualKeyCode::S), KeyOrButton::Key(VirtualKeyCode::Down)],
            left_key: vec![KeyOrButton::Key(VirtualKeyCode::A), KeyOrButton::Key(VirtualKeyCode::Left)],
            right_key: vec![KeyOrButton::Key(VirtualKeyCode::D), KeyOrButton::Key(VirtualKeyCode::Right)],

            pan_modifier_key:    vec![KeyOrButton::Key(VirtualKeyCode::LShift), KeyOrButton::Key(VirtualKeyCode::RShift)],
            rotate_modifier_key: vec![KeyOrButton::Button(MouseButton::Middle)],
        }
    }

    pub fn load() -> Settings{
        let path = Path::new("config.json");
        let display = path.display();
        let settings = Settings::new();

        let mut file = match File::open(&path) {
            Err(_) => {
                println!("Config file does not exist, creating new one");
                match File::create(&path) {
                    Err(why) => panic!("couldn't create {}: {}", display, why.description()),
                    Ok(mut file) => {
                        let serialized = serde_json::to_string(&settings).expect("Could not serialise Settings");
                        match file.write_all(serialized.as_bytes()) {
                            Err(why) => {
                                panic!("couldn't write config to {}: {}", display, why.description())
                            },
                            Ok(_) => println!("successfully wrote new config to {}", display),
                        }
                        file = match File::open(&path) {
                            Err(why) => panic!("couldn't open {}, which was just written to: {}", display, why.description()),
                            Ok(file) => file,
                        };
                        file
                    },
                }
            }
            Ok(file) => file,
        };
        let mut s = String::new();
        if let Err(why) = file.read_to_string(&mut s) {
            panic!("couldn't read {}: {}", display, why.description())
        }
        serde_json::from_str::<Settings>(&s).unwrap()
    }
}<commit_msg>Add ALT as default rotation modifier key (for people without middle mouse button)<commit_after>use ::core::ui::KeyOrButton;
use ::monet::glium::glutin::{MouseButton, VirtualKeyCode};
use serde_json;

use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

#[derive(Serialize, Deserialize, PartialEq)]
pub struct Settings {
    //Controls
    pub rotation_speed: f32,
    pub move_speed: f32,
    pub zoom_speed: f32,
    pub invert_y: bool,

    pub mouse_main: Vec<KeyOrButton>,

    pub forward_key: Vec<KeyOrButton>,
    pub backward_key: Vec<KeyOrButton>,
    pub left_key: Vec<KeyOrButton>,
    pub right_key: Vec<KeyOrButton>,
    pub pan_modifier_key: Vec<KeyOrButton>,
    pub rotate_modifier_key: Vec<KeyOrButton>,
}

impl Settings{
    pub fn new() -> Settings{
        Settings{
            rotation_speed: 1.0f32,
            zoom_speed: 1.0f32,
            move_speed: 1.0f32,
            invert_y: false,

            mouse_main: vec![KeyOrButton::Button(MouseButton::Left)],
            forward_key: vec![KeyOrButton::Key(VirtualKeyCode::W), KeyOrButton::Key(VirtualKeyCode::Up)],
            backward_key: vec![KeyOrButton::Key(VirtualKeyCode::S), KeyOrButton::Key(VirtualKeyCode::Down)],
            left_key: vec![KeyOrButton::Key(VirtualKeyCode::A), KeyOrButton::Key(VirtualKeyCode::Left)],
            right_key: vec![KeyOrButton::Key(VirtualKeyCode::D), KeyOrButton::Key(VirtualKeyCode::Right)],

            pan_modifier_key:    vec![KeyOrButton::Key(VirtualKeyCode::LShift), KeyOrButton::Key(VirtualKeyCode::RShift)],
            rotate_modifier_key: vec![KeyOrButton::Button(MouseButton::Middle), KeyOrButton::Key(VirtualKeyCode::LAlt), KeyOrButton::Key(VirtualKeyCode::RAlt)],
        }
    }

    pub fn load() -> Settings{
        let path = Path::new("config.json");
        let display = path.display();
        let settings = Settings::new();

        let mut file = match File::open(&path) {
            Err(_) => {
                println!("Config file does not exist, creating new one");
                match File::create(&path) {
                    Err(why) => panic!("couldn't create {}: {}", display, why.description()),
                    Ok(mut file) => {
                        let serialized = serde_json::to_string(&settings).expect("Could not serialise Settings");
                        match file.write_all(serialized.as_bytes()) {
                            Err(why) => {
                                panic!("couldn't write config to {}: {}", display, why.description())
                            },
                            Ok(_) => println!("successfully wrote new config to {}", display),
                        }
                        file = match File::open(&path) {
                            Err(why) => panic!("couldn't open {}, which was just written to: {}", display, why.description()),
                            Ok(file) => file,
                        };
                        file
                    },
                }
            }
            Ok(file) => file,
        };
        let mut s = String::new();
        if let Err(why) = file.read_to_string(&mut s) {
            panic!("couldn't read {}: {}", display, why.description())
        }
        serde_json::from_str::<Settings>(&s).unwrap()
    }
}<|endoftext|>