<commit_before>#![cfg_attr(all(test, feature = "nightly"), feature(test))] // we only need test feature when testing

#[macro_use] extern crate log;

extern crate syntex_syntax;
extern crate toml;
extern crate env_logger;

extern crate racer;

#[cfg(not(test))]
use racer::core;
#[cfg(not(test))]
use racer::util;
#[cfg(not(test))]
use racer::core::Match;
#[cfg(not(test))]
use racer::util::{getline, path_exists};
#[cfg(not(test))]
use racer::nameres::{do_file_search, do_external_search, PATH_SEP};
#[cfg(not(test))]
use racer::scopes;
#[cfg(not(test))]
use std::path::Path;

#[cfg(not(test))]
fn match_with_snippet_fn(m: Match) {
    let (linenum, charnum) = scopes::point_to_coords_from_file(&m.filepath, m.point, &m.session).unwrap();
    if m.matchstr == "" {
        panic!("MATCHSTR is empty - waddup?");
    }

    let snippet = racer::snippets::snippet_for_match(&m);
    println!("MATCH {};{};{};{};{};{:?};{}", m.matchstr,
                                    snippet,
                                    linenum.to_string(),
                                    charnum.to_string(),
                                    m.filepath.to_str().unwrap(),
                                    m.mtype,
                                    m.contextstr
             );
}

#[cfg(not(test))]
fn match_fn(m: Match) {
    if let Some((linenum, charnum)) = scopes::point_to_coords_from_file(&m.filepath,
                                                                        m.point,
                                                                        &m.session) {
        println!("MATCH {},{},{},{},{:?},{}", m.matchstr,
                                    linenum.to_string(),
                                    charnum.to_string(),
                                    m.filepath.to_str().unwrap(),
                                    m.mtype,
                                    m.contextstr
                 );
    } else {
        error!("Could not resolve file coords for match {:?}", m);
    }
}

#[cfg(not(test))]
fn complete(match_found: &Fn(Match), args: &[String]) {
    if args.len() < 1 {
        println!("Provide more arguments!");
        print_usage();
        std::process::exit(1);
    }
    match args[1].parse::<usize>() {
        Ok(linenum) => {
            // input: linenum, colnum, fname
            if args.len() < 4 {
                println!("Provide more arguments!");
                print_usage();
                std::process::exit(1);
            }
            let charnum = args[2].parse::<usize>().unwrap();
            let fname = &args[3];
            let substitute_file = Path::new(match args.len() > 4 {
                true => &args[4],
                false => fname
            });
            let fpath = Path::new(fname);
            let session = core::Session::from_path(&fpath, &substitute_file);
            let src = core::load_file(&fpath, &session);
            let line = &*getline(&substitute_file, linenum, &session);
            let (start, pos) = util::expand_ident(line, charnum);
            println!("PREFIX {},{},{}", start, pos, &line[start..pos]);

            let point = scopes::coords_to_point(&*src, linenum, charnum);
            for m in core::complete_from_file(&*src, &fpath, point, &session) {
                match_found(m);
            }
            println!("END");
        }
        Err(_) => {
            // input: a command line string passed in
            let arg = &args[1];
            let it = arg.split("::");
            let p: Vec<&str> = it.collect();

            for m in do_file_search(p[0], &Path::new(".")) {
                if p.len() == 1 {
                    match_found(m);
                } else {
                    for m in do_external_search(&p[1..], &m.filepath, m.point, core::SearchType::StartsWith, core::Namespace::BothNamespaces, &m.session) {
                        match_found(m);
                    }
                }
            }
        }
    }
}

#[cfg(not(test))]
fn prefix(args: &[String]) {
    if args.len() < 4 {
        println!("Provide more arguments!");
        print_usage();
        std::process::exit(1);
    }
    let linenum = args[1].parse::<usize>().unwrap();
    let charnum = args[2].parse::<usize>().unwrap();
    let fname = &args[3];
    let substitute_file = Path::new(match args.len() > 4 {
        true => &args[4],
        false => fname
    });
    let fpath = Path::new(&fname);
    let session = core::Session::from_path(&fpath, &substitute_file);

    // print the start, end, and the identifier prefix being matched
    let path = Path::new(fname);
    let line = &*getline(&path, linenum, &session);
    let (start, pos) = util::expand_ident(line, charnum);
    println!("PREFIX {},{},{}", start, pos, &line[start..pos]);
}

#[cfg(not(test))]
fn find_definition(args: &[String]) {
    if args.len() < 4 {
        println!("Provide more arguments!");
        print_usage();
        std::process::exit(1);
    }
    let linenum = args[1].parse::<usize>().unwrap();
    let charnum = args[2].parse::<usize>().unwrap();
    let fname = &args[3];
    let substitute_file = Path::new(match args.len() > 4 {
        true => &args[4],
        false => fname
    });
    let fpath = Path::new(&fname);
    let session = core::Session::from_path(&fpath, &substitute_file);
    let src = core::load_file(&fpath, &session);
    let pos = scopes::coords_to_point(&*src, linenum, charnum);

    core::find_definition(&*src, &fpath, pos, &session).map(match_fn);
    println!("END");
}

#[cfg(not(test))]
fn print_usage() {
    let program = std::env::args().next().unwrap().clone();
    println!("usage: {} complete linenum charnum fname [substitute_file]", program);
    println!("or:    {} find-definition linenum charnum fname [substitute_file]", program);
    println!("or:    {} complete fullyqualifiedname   (e.g. std::io::)", program);
    println!("or:    {} prefix linenum charnum fname", program);
    println!("or replace complete with complete-with-snippet for more detailed completions.");
    println!("or:    {} daemon     - to start a process that receives the above commands via stdin", program);
}

#[cfg(not(test))]
fn check_rust_src_env_var() {
    if let Ok(srcpaths) = std::env::var("RUST_SRC_PATH") {
        let v = srcpaths.split(PATH_SEP).collect::<Vec<_>>();
        if !v.is_empty() {
            let f = Path::new(v[0]);
            if !path_exists(f) {
                println!("racer can't find the directory pointed to by the RUST_SRC_PATH variable \"{}\". Try using an absolute fully qualified path and make sure it points to the src directory of a rust checkout - e.g. \"/home/foouser/src/rust/src\".", srcpaths);
                std::process::exit(1);
            } else if !path_exists(f.join("libstd")) {
                println!("Unable to find libstd under RUST_SRC_PATH. N.B. RUST_SRC_PATH variable needs to point to the *src* directory inside a rust checkout e.g. \"/home/foouser/src/rust/src\". Current value \"{}\"", srcpaths);
                std::process::exit(1);
            }
        }
    } else {
        println!("RUST_SRC_PATH environment variable must be set to point to the src directory of a rust checkout. E.g. \"/home/foouser/src/rust/src\"");
        std::process::exit(1);
    }
}

#[cfg(not(test))]
fn daemon() {
    use std::io;
    let mut input = String::new();
    while let Ok(n) = io::stdin().read_line(&mut input) {
        if n == 0 {
            break;
        }
        let args: Vec<String> = input.split(" ").map(|s| s.trim().to_string()).collect();
        run(&args);

        input.clear();
    }
}

#[cfg(not(test))]
fn main() {
    // make sure we get a stack trace ifwe panic
    ::std::env::set_var("RUST_BACKTRACE","1");

    env_logger::init().unwrap();
    check_rust_src_env_var();

    let args: Vec<String> = std::env::args().collect();

    if args.len() == 1 {
        print_usage();
        std::process::exit(1);
    }

    let args = &args[1..];
    run(args);
}

#[cfg(not(test))]
fn run(args: &[String]) {
    let command  = &args[0];
    match &command[..] {
        "daemon" => daemon(),
        "prefix" => prefix(&args),
        "complete" => complete(&match_fn, &args),
        "complete-with-snippet" => complete(&match_with_snippet_fn, &args),
        "find-definition" => find_definition(&args),
        "help" => print_usage(),
        cmd => {
            println!("Sorry, I didn't understand command {}", cmd);
            print_usage();
            std::process::exit(1);
        }
    }
}
<commit_msg>main: fix min number args for "complete", avoids panic<commit_after>#![cfg_attr(all(test, feature = "nightly"), feature(test))] // we only need test feature when testing

#[macro_use] extern crate log;

extern crate syntex_syntax;
extern crate toml;
extern crate env_logger;

extern crate racer;

#[cfg(not(test))]
use racer::core;
#[cfg(not(test))]
use racer::util;
#[cfg(not(test))]
use racer::core::Match;
#[cfg(not(test))]
use racer::util::{getline, path_exists};
#[cfg(not(test))]
use racer::nameres::{do_file_search, do_external_search, PATH_SEP};
#[cfg(not(test))]
use racer::scopes;
#[cfg(not(test))]
use std::path::Path;

#[cfg(not(test))]
fn match_with_snippet_fn(m: Match) {
    let (linenum, charnum) = scopes::point_to_coords_from_file(&m.filepath, m.point, &m.session).unwrap();
    if m.matchstr == "" {
        panic!("MATCHSTR is empty - waddup?");
    }

    let snippet = racer::snippets::snippet_for_match(&m);
    println!("MATCH {};{};{};{};{};{:?};{}", m.matchstr,
                                    snippet,
                                    linenum.to_string(),
                                    charnum.to_string(),
                                    m.filepath.to_str().unwrap(),
                                    m.mtype,
                                    m.contextstr
             );
}

#[cfg(not(test))]
fn match_fn(m: Match) {
    if let Some((linenum, charnum)) = scopes::point_to_coords_from_file(&m.filepath,
                                                                        m.point,
                                                                        &m.session) {
        println!("MATCH {},{},{},{},{:?},{}", m.matchstr,
                                    linenum.to_string(),
                                    charnum.to_string(),
                                    m.filepath.to_str().unwrap(),
                                    m.mtype,
                                    m.contextstr
                 );
    } else {
        error!("Could not resolve file coords for match {:?}", m);
    }
}

#[cfg(not(test))]
fn complete(match_found: &Fn(Match), args: &[String]) {
    if args.len() < 2 {
        println!("Provide more arguments!");
        print_usage();
        std::process::exit(1);
    }
    match args[1].parse::<usize>() {
        Ok(linenum) => {
            // input: linenum, colnum, fname
            if args.len() < 4 {
                println!("Provide more arguments!");
                print_usage();
                std::process::exit(1);
            }
            let charnum = args[2].parse::<usize>().unwrap();
            let fname = &args[3];
            let substitute_file = Path::new(match args.len() > 4 {
                true => &args[4],
                false => fname
            });
            let fpath = Path::new(fname);
            let session = core::Session::from_path(&fpath, &substitute_file);
            let src = core::load_file(&fpath, &session);
            let line = &*getline(&substitute_file, linenum, &session);
            let (start, pos) = util::expand_ident(line, charnum);
            println!("PREFIX {},{},{}", start, pos, &line[start..pos]);

            let point = scopes::coords_to_point(&*src, linenum, charnum);
            for m in core::complete_from_file(&*src, &fpath, point, &session) {
                match_found(m);
            }
            println!("END");
        }
        Err(_) => {
            // input: a command line string passed in
            let arg = &args[1];
            let it = arg.split("::");
            let p: Vec<&str> = it.collect();

            for m in do_file_search(p[0], &Path::new(".")) {
                if p.len() == 1 {
                    match_found(m);
                } else {
                    for m in do_external_search(&p[1..], &m.filepath, m.point, core::SearchType::StartsWith, core::Namespace::BothNamespaces, &m.session) {
                        match_found(m);
                    }
                }
            }
        }
    }
}

#[cfg(not(test))]
fn prefix(args: &[String]) {
    if args.len() < 4 {
        println!("Provide more arguments!");
        print_usage();
        std::process::exit(1);
    }
    let linenum = args[1].parse::<usize>().unwrap();
    let charnum = args[2].parse::<usize>().unwrap();
    let fname = &args[3];
    let substitute_file = Path::new(match args.len() > 4 {
        true => &args[4],
        false => fname
    });
    let fpath = Path::new(&fname);
    let session = core::Session::from_path(&fpath, &substitute_file);

    // print the start, end, and the identifier prefix being matched
    let path = Path::new(fname);
    let line = &*getline(&path, linenum, &session);
    let (start, pos) = util::expand_ident(line, charnum);
    println!("PREFIX {},{},{}", start, pos, &line[start..pos]);
}

#[cfg(not(test))]
fn find_definition(args: &[String]) {
    if args.len() < 4 {
        println!("Provide more arguments!");
        print_usage();
        std::process::exit(1);
    }
    let linenum = args[1].parse::<usize>().unwrap();
    let charnum = args[2].parse::<usize>().unwrap();
    let fname = &args[3];
    let substitute_file = Path::new(match args.len() > 4 {
        true => &args[4],
        false => fname
    });
    let fpath = Path::new(&fname);
    let session = core::Session::from_path(&fpath, &substitute_file);
    let src = core::load_file(&fpath, &session);
    let pos = scopes::coords_to_point(&*src, linenum, charnum);

    core::find_definition(&*src, &fpath, pos, &session).map(match_fn);
    println!("END");
}

#[cfg(not(test))]
fn print_usage() {
    let program = std::env::args().next().unwrap().clone();
    println!("usage: {} complete linenum charnum fname [substitute_file]", program);
    println!("or:    {} find-definition linenum charnum fname [substitute_file]", program);
    println!("or:    {} complete fullyqualifiedname   (e.g. std::io::)", program);
    println!("or:    {} prefix linenum charnum fname", program);
    println!("or replace complete with complete-with-snippet for more detailed completions.");
    println!("or:    {} daemon     - to start a process that receives the above commands via stdin", program);
}

#[cfg(not(test))]
fn check_rust_src_env_var() {
    if let Ok(srcpaths) = std::env::var("RUST_SRC_PATH") {
        let v = srcpaths.split(PATH_SEP).collect::<Vec<_>>();
        if !v.is_empty() {
            let f = Path::new(v[0]);
            if !path_exists(f) {
                println!("racer can't find the directory pointed to by the RUST_SRC_PATH variable \"{}\". Try using an absolute fully qualified path and make sure it points to the src directory of a rust checkout - e.g. \"/home/foouser/src/rust/src\".", srcpaths);
                std::process::exit(1);
            } else if !path_exists(f.join("libstd")) {
                println!("Unable to find libstd under RUST_SRC_PATH. N.B. RUST_SRC_PATH variable needs to point to the *src* directory inside a rust checkout e.g. \"/home/foouser/src/rust/src\". Current value \"{}\"", srcpaths);
                std::process::exit(1);
            }
        }
    } else {
        println!("RUST_SRC_PATH environment variable must be set to point to the src directory of a rust checkout. E.g. \"/home/foouser/src/rust/src\"");
        std::process::exit(1);
    }
}

#[cfg(not(test))]
fn daemon() {
    use std::io;
    let mut input = String::new();
    while let Ok(n) = io::stdin().read_line(&mut input) {
        if n == 0 {
            break;
        }
        let args: Vec<String> = input.split(" ").map(|s| s.trim().to_string()).collect();
        run(&args);

        input.clear();
    }
}

#[cfg(not(test))]
fn main() {
    // make sure we get a stack trace ifwe panic
    ::std::env::set_var("RUST_BACKTRACE","1");

    env_logger::init().unwrap();
    check_rust_src_env_var();

    let args: Vec<String> = std::env::args().collect();

    if args.len() == 1 {
        print_usage();
        std::process::exit(1);
    }

    let args = &args[1..];
    run(args);
}

#[cfg(not(test))]
fn run(args: &[String]) {
    let command  = &args[0];
    match &command[..] {
        "daemon" => daemon(),
        "prefix" => prefix(&args),
        "complete" => complete(&match_fn, &args),
        "complete-with-snippet" => complete(&match_with_snippet_fn, &args),
        "find-definition" => find_definition(&args),
        "help" => print_usage(),
        cmd => {
            println!("Sorry, I didn't understand command {}", cmd);
            print_usage();
            std::process::exit(1);
        }
    }
}
<|endoftext|>


<commit_before>/*!
# ParView
*/

#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(docopt_macros)]

#![feature(concat_idents)]

#![deny(non_camel_case_types)]
#![deny(unused_parens)]
#![deny(non_upper_case_globals)]
#![deny(unused_qualifications)]
#![deny(missing_docs)]
#![deny(unused_results)]

extern crate rustc_serialize;
extern crate docopt;

extern crate parview;

use std::path::Path;

use parview::{misc,Palette,Config,Frame,Parviewer};

// Write the Docopt usage string.
docopt!(Args derive Debug, "
Usage: parview [options] [--] [<file>]

Options:
    -h, --help              Help and usage
    -g, --generate          Generate test_frames.json
    -p, --palette FILE      Use palette file (toml file), instead of default.
    -c, --config FILE       Use config file (toml file), instead of default.

Arguments:
    <file>      json file representing the frames. json.gz also accepted, if the extension is \".gz\".
",
flag_palette : Option<String>,
flag_config : Option<String>,
arg_file : Option<String>,
);

/// Configuration to be loaded from the TOML file
#[allow(unused_attributes)]
#[derive(RustcDecodable,RustcEncodable)]
#[derive(Serialize,Deserialize)]
pub struct TomlConfig {
    /// Set initial pitch (degrees) [default: 90]
    pub pitch : f32,
    ///Set initial yaw (degrees) [default: 0]
    pub yaw : f32,
    /// Set camera field-of-view angle (degrees) [default: 45]
    pub fov : f32,
    /// Set distance between camera and box (L) [default: 2]
    pub distance : f32,
    /// Set window width (pixels) [default: 600]
    pub width : u32,
    /// Set window height, if different from width (pixels)
    pub height : Option<u32>,
    /// When finished, pause for FRAMES frames, then loop. None does not loop. [default: None]
    pub pauseloop : Option<f32>,
    /// Continuous box rotation (angle / frame) [default: 0]
    pub rotate : f32,
    /// Framerate: sets maximum framerate of drawing, independent of actual frames. [default: 24]
    pub framerate : f32,
    /// Rate of drawing frames. [default: 2.0]
    pub fps : f32
}

impl Default for TomlConfig {
    fn default() -> Self {
        TomlConfig {
            pitch : 90.,
            yaw : 0.,
            fov : 45.,
            distance : 2.,
            width : 800,
            height : None,
            pauseloop : None,
            rotate : 0.0,
            fps : 2.0,
            framerate : 24.0
        }
    }
}

/// Create a Config instance from these Args
#[allow(unused_variables)]
fn args_toml_to_config(args: &Args, toml_config: &TomlConfig) -> Config {
    Config {
        pitch : toml_config.pitch,
        yaw : toml_config.yaw,
        fov : toml_config.fov,
        width : toml_config.width,
        height : toml_config.height.unwrap_or(toml_config.width),
        distance : toml_config.distance,
        pauseloop : toml_config.pauseloop,
        rotate : toml_config.rotate,
        framerate : toml_config.framerate
    }
}

fn err_print(err : &std::error::Error) {
    println!("Description: {}", err.description());
    println!("Debug version: {:?}", err);

    if let Some(e) = err.cause() {
        println!("Cause.");
        err_print(e);
    }
}

fn run() -> Result<(), Box<std::error::Error>> {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    let toml_config : TomlConfig = match args.flag_config {
        None => Default::default(),
        Some(ref fname) => {
            let path : &Path = Path::new(&fname[..]);
            try!(misc::load_toml::<TomlConfig>(path))
        }
    };

    let config : Config = args_toml_to_config(&args, &toml_config);

    let fname : &str = match args.arg_file {
        Some(ref s) => s,
        None => "test_frame.json"
    };
    let path : &Path = Path::new(fname);

    let (frames, palette) : (Vec<Frame>, Palette) = if args.flag_generate {
        let frames = try!(misc::generate_frame(path));
        let palette = match args.flag_palette {
            None => Default::default(),
            Some(fname) => {
                let path : &Path = Path::new(&fname[..]);
                try!(misc::generate_palette(path))
            }
        };
        (frames, palette)
    } else {
        let frames = try!(misc::deserialize_by_ext(path));
        let palette = match args.flag_palette {
            None => Default::default(),
            Some(fname) => {
                let path : &Path = Path::new(&fname[..]);
                try!(misc::load_toml::<Palette>(path))
            }
        };
        (frames, palette)
    };

    // println!("config: {:?}", config);

    let mut viewer = try!(Parviewer::new(frames, palette, config));
    let _ = viewer.timer.at_least(toml_config.fps);
    viewer.run();
    Ok(())
}

fn main() {
    if let Err(err) = run() {
        println!("ERROR.");

        err_print(&*err);
    }
}
<commit_msg>Ignore dead code in main.rs when testing<commit_after>/*!
# ParView
*/

#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(docopt_macros)]

#![feature(concat_idents)]

#![deny(non_camel_case_types)]
#![deny(unused_parens)]
#![deny(non_upper_case_globals)]
#![deny(unused_qualifications)]
#![deny(missing_docs)]
#![deny(unused_results)]
// Don't warn about dead code in this module when testing, its annoying.
#![cfg_attr(test, allow(dead_code))]

extern crate rustc_serialize;
extern crate docopt;

extern crate parview;

use std::path::Path;

use parview::{misc,Palette,Config,Frame,Parviewer};

// Write the Docopt usage string.
docopt!(Args derive Debug, "
Usage: parview [options] [--] [<file>]

Options:
    -h, --help              Help and usage
    -g, --generate          Generate test_frames.json
    -p, --palette FILE      Use palette file (toml file), instead of default.
    -c, --config FILE       Use config file (toml file), instead of default.

Arguments:
    <file>      json file representing the frames. json.gz also accepted, if the extension is \".gz\".
",
flag_palette : Option<String>,
flag_config : Option<String>,
arg_file : Option<String>,
);

/// Configuration to be loaded from the TOML file
#[allow(unused_attributes)]
#[derive(RustcDecodable,RustcEncodable)]
#[derive(Serialize,Deserialize)]
pub struct TomlConfig {
    /// Set initial pitch (degrees) [default: 90]
    pub pitch : f32,
    ///Set initial yaw (degrees) [default: 0]
    pub yaw : f32,
    /// Set camera field-of-view angle (degrees) [default: 45]
    pub fov : f32,
    /// Set distance between camera and box (L) [default: 2]
    pub distance : f32,
    /// Set window width (pixels) [default: 600]
    pub width : u32,
    /// Set window height, if different from width (pixels)
    pub height : Option<u32>,
    /// When finished, pause for FRAMES frames, then loop. None does not loop. [default: None]
    pub pauseloop : Option<f32>,
    /// Continuous box rotation (angle / frame) [default: 0]
    pub rotate : f32,
    /// Framerate: sets maximum framerate of drawing, independent of actual frames. [default: 24]
    pub framerate : f32,
    /// Rate of drawing frames. [default: 2.0]
    pub fps : f32
}

impl Default for TomlConfig {
    fn default() -> Self {
        TomlConfig {
            pitch : 90.,
            yaw : 0.,
            fov : 45.,
            distance : 2.,
            width : 800,
            height : None,
            pauseloop : None,
            rotate : 0.0,
            fps : 2.0,
            framerate : 24.0
        }
    }
}

/// Create a Config instance from these Args
#[allow(unused_variables)]
fn args_toml_to_config(args: &Args, toml_config: &TomlConfig) -> Config {
    Config {
        pitch : toml_config.pitch,
        yaw : toml_config.yaw,
        fov : toml_config.fov,
        width : toml_config.width,
        height : toml_config.height.unwrap_or(toml_config.width),
        distance : toml_config.distance,
        pauseloop : toml_config.pauseloop,
        rotate : toml_config.rotate,
        framerate : toml_config.framerate
    }
}

fn err_print(err : &std::error::Error) {
    println!("Description: {}", err.description());
    println!("Debug version: {:?}", err);

    if let Some(e) = err.cause() {
        println!("Cause.");
        err_print(e);
    }
}

fn run() -> Result<(), Box<std::error::Error>> {
    let args: Args = Args::docopt().decode().unwrap_or_else(|e| e.exit());
    let toml_config : TomlConfig = match args.flag_config {
        None => Default::default(),
        Some(ref fname) => {
            let path : &Path = Path::new(&fname[..]);
            try!(misc::load_toml::<TomlConfig>(path))
        }
    };

    let config : Config = args_toml_to_config(&args, &toml_config);

    let fname : &str = match args.arg_file {
        Some(ref s) => s,
        None => "test_frame.json"
    };
    let path : &Path = Path::new(fname);

    let (frames, palette) : (Vec<Frame>, Palette) = if args.flag_generate {
        let frames = try!(misc::generate_frame(path));
        let palette = match args.flag_palette {
            None => Default::default(),
            Some(fname) => {
                let path : &Path = Path::new(&fname[..]);
                try!(misc::generate_palette(path))
            }
        };
        (frames, palette)
    } else {
        let frames = try!(misc::deserialize_by_ext(path));
        let palette = match args.flag_palette {
            None => Default::default(),
            Some(fname) => {
                let path : &Path = Path::new(&fname[..]);
                try!(misc::load_toml::<Palette>(path))
            }
        };
        (frames, palette)
    };

    // println!("config: {:?}", config);

    let mut viewer = try!(Parviewer::new(frames, palette, config));
    let _ = viewer.timer.at_least(toml_config.fps);
    viewer.run();
    Ok(())
}

fn main() {
    if let Err(err) = run() {
        println!("ERROR.");

        err_print(&*err);
    }
}
<|endoftext|>


<commit_before>#![feature(collections)]
#![feature(core)]
#![feature(libc)]
#![feature(std_misc)]
#![feature(unsafe_destructor)]

extern crate gl;
extern crate libc;
#[macro_use]
extern crate log;

pub mod gl_context;
pub mod shader;
pub mod texture;
pub mod vertex_buffer;
<commit_msg>#[deny(warnings)]<commit_after>#![deny(warnings)]

#![feature(collections)]
#![feature(core)]
#![feature(libc)]
#![feature(std_misc)]
#![feature(unsafe_destructor)]

extern crate gl;
extern crate libc;
#[macro_use]
extern crate log;

pub mod gl_context;
pub mod shader;
pub mod texture;
pub mod vertex_buffer;
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate miri;
extern crate rustc;
extern crate rustc_driver;

use miri::interpreter;
use rustc::session::Session;
use rustc_driver::{driver, CompilerCalls, Compilation};

struct MiriCompilerCalls;

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
        let mut control = driver::CompileController::basic();
        control.after_analysis.stop = Compilation::Stop;

        control.after_analysis.callback = Box::new(|state| {
            interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
        });

        control
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
}
<commit_msg>Abort miri if the Rust code had compilation errors.<commit_after>#![feature(rustc_private)]

extern crate miri;
extern crate rustc;
extern crate rustc_driver;

use miri::interpreter;
use rustc::session::Session;
use rustc_driver::{driver, CompilerCalls, Compilation};

struct MiriCompilerCalls;

impl<'a> CompilerCalls<'a> for MiriCompilerCalls {
    fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
        let mut control = driver::CompileController::basic();
        control.after_analysis.stop = Compilation::Stop;

        control.after_analysis.callback = Box::new(|state| {
            state.session.abort_if_errors();
            interpreter::interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
        });

        control
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
}
<|endoftext|>


<commit_before>pub struct Hidden<T> {
    opt_val: Option<T>
}

impl<T> Hidden<T> {
    /// Creates a Hidden<T> container, which should never be directly visible
    ///
    /// Should not be called directly. Only public so that `noleak!()` can call it
    pub unsafe fn new() -> Self {
        Hidden { opt_val: None }
    }
}

pub struct Acceptor<'a, T: 'a> {
    mut_hidden: &'a mut Hidden<T>
}

impl<'a, T: 'a> Acceptor<'a, T> {
    pub unsafe fn new(hid: &'a mut Hidden<T>) -> Self {
        Acceptor { mut_hidden: hid }
    }

    pub fn fill(self, t: T) -> Handle<'a, T> {
        self.mut_hidden.opt_val = Some(t);
        Handle { mut_hidden: self.mut_hidden }
    }

    pub fn fill_from<'b>(self, handle_t: Handle<'b, T>) -> Handle<'a, T> {
        let new = handle_t.mut_hidden.opt_val.take().expect("Attempting to .fill_from() an emptied Handle!")
        self.fill(new)
    }
}

pub struct Handle<'a, T: 'a> {
    mut_hidden: &'a mut Hidden<T>
}

#[cfg(test)]
mod test {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Fix missing semicolon. Implement Deref/DerefMut for Handle<commit_after>pub struct Hidden<T> {
    opt_val: Option<T>
}

impl<T> Hidden<T> {
    /// Creates a Hidden<T> container, which should never be directly visible
    ///
    /// Should not be called directly. Only public so that `noleak!()` can call it
    pub unsafe fn new() -> Self {
        Hidden { opt_val: None }
    }
}

pub struct Acceptor<'a, T: 'a> {
    mut_hidden: &'a mut Hidden<T>
}

impl<'a, T: 'a> Acceptor<'a, T> {
    pub unsafe fn new(hid: &'a mut Hidden<T>) -> Self {
        Acceptor { mut_hidden: hid }
    }

    pub fn fill(self, t: T) -> Handle<'a, T> {
        self.mut_hidden.opt_val = Some(t);
        Handle { mut_hidden: self.mut_hidden }
    }

    pub fn fill_from<'b>(self, handle_t: Handle<'b, T>) -> Handle<'a, T> {
        let new = handle_t.mut_hidden.opt_val.take().expect("Attempting to .fill_from() an emptied Handle!");
        self.fill(new)
    }
}

pub struct Handle<'a, T: 'a> {
    mut_hidden: &'a mut Hidden<T>
}

impl<'a, T: 'a> std::ops::Deref for Handle<'a, T> {
    type Target = T;
    fn deref(&self) -> &T {
        self.mut_hidden.opt_val.as_ref().expect("Tried to deref() an emptied Handle!")
    }
}

impl <'a, T: 'a> std::ops::DerefMut for Handle<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        self.mut_hidden.opt_val.as_mut().expect("Tried to deref_mut() an emptied Handle!")
    }
}

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


<commit_before>#![crate_name = "raft"]
#![crate_type="lib"]
#![doc(html_logo_url = "https://raw.githubusercontent.com/Hoverbear/raft/master/raft.png")]
#![doc(html_root_url = "https://hoverbear.github.io/raft/raft/")]

//! This is the Raft Distributed Consensus Protocol implemented for Rust.
//! [Raft](http://raftconsensus.github.io/) is described as:
//!
//! > Raft is a consensus algorithm that is designed to be easy to understand. It's equivalent to
//! > Paxos in fault-tolerance and performance. The difference is that it's decomposed into
//! > relatively independent subproblems, and it cleanly addresses all major pieces needed for
//! > practical systems.
//!
//! This implementation utilizes [Cap'n Proto](https://kentonv.github.io/capnproto/) for its RPC,
//! [`mio`](https://github.com/carllerche/mio) for it's async event loop.
//!
//! If this package fails to build for you it is possibly because you do not have the
//! [`capnp`](https://capnproto.org/capnp-tool.html) utility installed. You should be able to find
//! appropriate packages for most popular distributions.
//!
//! # Consuming this library
//!
//! Consuming this library works in a few parts:
//!
//! 1. Implement `Store` and `StateMachine` such that they will hook into your application.
//! 2. Create a `Raft` with those impls which will spawn it's own `Server` and join with a cluster.
//! 3. Interact with the cluster by issuing `append()` calls.
//! 4. React to calls to `apply()` from the implemented `StateMachine`
//!
//! It's important to note that issuing an `append()` call to `Raft` does not (at this time)
//! necessarily gaurantee that the entry has been applied to the `StateMachine`, since it must be
//! successfully replicated across a majority of nodes before it is applied.
//!
//! ## State
//!
//!     // TODO
//!
//! ## StateMachine
//!
//!     // TODO
//!
//! ## Client Requests
//!
//!     // TODO
//!
#![feature(buf_stream)]

extern crate capnp;
extern crate mio;
extern crate rand;
extern crate rustc_serialize;
extern crate uuid;
#[macro_use] extern crate log;

pub mod state_machine;
pub mod store;

mod server;
mod replica;
mod state;

mod messages_capnp {
    #![allow(dead_code)]
    include!(concat!(env!("OUT_DIR"), "/messages_capnp.rs"));
}

use std::{io, ops};
use std::collections::HashSet;
use std::net::SocketAddr;
use std::net::TcpStream;
use std::str::FromStr;
use std::io::BufStream;

use rustc_serialize::Encodable;
// Data structures.
use store::Store;
use server::Server;
use state_machine::StateMachine;

// Cap'n Proto
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, ReaderOptions, MallocMessageBuilder};
use messages_capnp::{
    client_request,
    client_response,
};

/// This is the primary interface with a `Server` in the cluster.
///
/// Note: Creating a new `Raft` client will, for now, automatically spawn a `Server` with the
/// relevant parameters. This may be changed in the future. This is based on the assumption that
/// any consuming application interacting with a Raft cluster will also be a participant.
pub struct Raft {
    current_leader: Option<SocketAddr>,
    related_server: SocketAddr, // Not Server because we move that to another thread.
    cluster_members: HashSet<SocketAddr>,
}

impl Raft {
    /// Create a new `Raft` client that has a cooresponding `Server` attached. Note that this
    /// `Raft` may not necessarily interact with the cooreponding `Server`, it will interact with
    /// the `Leader` of a cluster in almost all cases.
    /// *Note:* All requests are blocking, by design from the Raft paper.
    pub fn new<S, M>(addr: SocketAddr,
                     cluster_members: HashSet<SocketAddr>,
                     store: S,
                     state_machine: M)
                     -> Raft
    where S: Store, M: StateMachine {
        debug!("Starting Raft on {}", addr);
        let mut peers = cluster_members.clone();
        peers.remove(&addr);
        Server::<S, M>::spawn(addr, peers, store, state_machine);
        // Store relevant information.
        Raft {
            current_leader: None,
            related_server: addr,
            cluster_members: cluster_members,
        }
    }

    /// Appends an entry to the replicated log. This will only return once it's properly replicated
    /// to a majority of nodes.
    pub fn append(&mut self, entry: &[u8]) -> Result<()> {
        let mut message = MallocMessageBuilder::new_default();
        if self.current_leader.is_none() { try!(self.refresh_leader()); }
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_append(entry)
        }
        // We know current leader `is_some()` because `refresh_leader()` didn't fail.
        let mut unbuffered_socket = try!(TcpStream::connect(self.current_leader.unwrap())); // TODO: Handle Leader
        let mut socket = BufStream::new(unbuffered_socket);
        try!(serialize_packed::write_message(&mut socket, &mut message));

        // Wait for a response.

        let response = try!(serialize_packed::read_message(&mut socket, ReaderOptions::new()));
        let client_res = try!(response.get_root::<client_response::Reader>());
        // Set the current leader.
        match try!(client_res.which()) {
            client_response::Which::Success(()) => {
                // It worked!
                Ok(())
            },
            client_response::Which::NotLeader(Ok(leader_bytes)) => {
                self.current_leader = match SocketAddr::from_str(leader_bytes) {
                    Ok(socket) => Some(socket),
                    Err(_) => return Err(Error::Raft(ErrorKind::BadResponse))
                };
                // Try again.
                self.append(entry)
            },
            _ => unimplemented!(),
        }
    }

    /// Kills the node. Should only really be used for testing purposes.
    /// Accepts a `SocketAddr` because if you're going to kill a node you should be able to pick
    /// your victim.
    pub fn die(&mut self, target: SocketAddr, reason: String) -> Result<()> {
        if !self.cluster_members.contains(&target) {
            return Err(Error::Raft(ErrorKind::NotInCluster))
        }
        let mut message = MallocMessageBuilder::new_default();
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_die(&reason)
        }
        // We know current leader `is_some()` because `refresh_leader()` didn't fail.
        let mut unbuffered_socket = try!(TcpStream::connect(self.current_leader.unwrap())); // TODO: Handle Leader
        let mut socket = BufStream::new(unbuffered_socket);
        try!(serialize_packed::write_message(&mut socket, &mut message));

        // Wait for a response.
        let response = try!(serialize_packed::read_message(&mut socket, ReaderOptions::new()));
        let client_res = try!(response.get_root::<client_response::Reader>());
        // Set the current leader.
        match try!(client_res.which()) {
            client_response::Which::Success(()) => Ok(()),
            _ => unimplemented!(),
        }
    }

    /// This function will force the `Raft` interface to refresh it's knowledge of the leader from
    /// The cooresponding `Server` running alongside it.
    pub fn refresh_leader(&mut self) -> Result<()> {
        let mut message = MallocMessageBuilder::new_default();
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_leader_refresh(());
        }
        let mut unbuffered_socket = try!(TcpStream::connect(self.related_server));
        let mut socket = BufStream::new(unbuffered_socket);
        try!(serialize_packed::write_message(&mut socket, &mut message));

        // Wait for a response.
        let response = try!(serialize_packed::read_message(&mut socket, ReaderOptions::new()));
        let client_res = try!(response.get_root::<client_response::Reader>());
        // Set the current leader.
        self.current_leader = match try!(client_res.which()) {
            client_response::Which::Success(()) => unimplemented!(),
            client_response::Which::NotLeader(Ok(leader_bytes)) => {
                match SocketAddr::from_str(leader_bytes) {
                    Ok(socket) => Some(socket),
                    Err(_) => return Err(Error::Raft(ErrorKind::BadResponse))
                }
            },
            client_response::Which::NotLeader(e) => panic!("Error reading response. {:?}", e),
        };
        Ok(())
    }
}

pub type Result<T> = std::result::Result<T, Error>;

/// raft::Errors are the composed variety of errors that can originate from the various libraries.
/// With the exception of the `Raft` variant these are generated from `try!()` macros invoking
/// on `io::Error` or `capnp::Error` by using
/// [`FromError`](https://doc.rust-lang.org/std/error/#the-fromerror-trait).
#[derive(Debug)]
pub enum Error {
    CapnProto(capnp::Error),
    SchemaError(capnp::NotInSchema),
    Io(io::Error),
    Raft(ErrorKind),
}

/// Currently, this can only be:
///
/// * `RelatedNodeDown` - When the related Server is known to be down.
/// * `CannotProceed` - When the related Server cannot proceed due to more than a majority of
///                     nodes being unavailable.
/// TODO: Hook these up.
#[derive(Debug)]
pub enum ErrorKind {
    RelatedNodeDown,
    CannotProceed,
    NotInCluster,
    BadResponse,
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<capnp::Error> for Error {
    fn from(err: capnp::Error) -> Error {
        Error::CapnProto(err)
    }
}

impl From<capnp::NotInSchema> for Error {
    fn from(err: capnp::NotInSchema) -> Error {
        Error::SchemaError(err)
    }
}

/// The term of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
pub struct Term(u64);
impl From<u64> for Term {
    fn from(val: u64) -> Term {
        Term(val)
    }
}
impl Into<u64> for Term {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for Term {
    type Output = Term;
    fn add(self, rhs: u64) -> Term {
        Term(self.0.checked_add(rhs).expect("overflow while incrementing Term"))
    }
}
impl ops::Sub<u64> for Term {
    type Output = Term;
    fn sub(self, rhs: u64) -> Term {
        Term(self.0.checked_sub(rhs).expect("underflow while decrementing Term"))
    }
}

/// The index of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
pub struct LogIndex(u64);
impl From<u64> for LogIndex {
    fn from(val: u64) -> LogIndex {
        LogIndex(val)
    }
}
impl Into<u64> for LogIndex {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for LogIndex {
    type Output = LogIndex;
    fn add(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_add(rhs).expect("overflow while incrementing LogIndex"))
    }
}
impl ops::Sub<u64> for LogIndex {
    type Output = LogIndex;
    fn sub(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_sub(rhs).expect("underflow while decrementing LogIndex"))
    }
}
<commit_msg>small nits sockets need not be mutable<commit_after>#![crate_name = "raft"]
#![crate_type="lib"]
#![doc(html_logo_url = "https://raw.githubusercontent.com/Hoverbear/raft/master/raft.png")]
#![doc(html_root_url = "https://hoverbear.github.io/raft/raft/")]

//! This is the Raft Distributed Consensus Protocol implemented for Rust.
//! [Raft](http://raftconsensus.github.io/) is described as:
//!
//! > Raft is a consensus algorithm that is designed to be easy to understand. It's equivalent to
//! > Paxos in fault-tolerance and performance. The difference is that it's decomposed into
//! > relatively independent subproblems, and it cleanly addresses all major pieces needed for
//! > practical systems.
//!
//! This implementation utilizes [Cap'n Proto](https://kentonv.github.io/capnproto/) for its RPC,
//! [`mio`](https://github.com/carllerche/mio) for it's async event loop.
//!
//! If this package fails to build for you it is possibly because you do not have the
//! [`capnp`](https://capnproto.org/capnp-tool.html) utility installed. You should be able to find
//! appropriate packages for most popular distributions.
//!
//! # Consuming this library
//!
//! Consuming this library works in a few parts:
//!
//! 1. Implement `Store` and `StateMachine` such that they will hook into your application.
//! 2. Create a `Raft` with those impls which will spawn it's own `Server` and join with a cluster.
//! 3. Interact with the cluster by issuing `append()` calls.
//! 4. React to calls to `apply()` from the implemented `StateMachine`
//!
//! It's important to note that issuing an `append()` call to `Raft` does not (at this time)
//! necessarily gaurantee that the entry has been applied to the `StateMachine`, since it must be
//! successfully replicated across a majority of nodes before it is applied.
//!
//! ## State
//!
//!     // TODO
//!
//! ## StateMachine
//!
//!     // TODO
//!
//! ## Client Requests
//!
//!     // TODO
//!
#![feature(buf_stream)]

extern crate capnp;
extern crate mio;
extern crate rand;
extern crate rustc_serialize;
extern crate uuid;
#[macro_use] extern crate log;

pub mod state_machine;
pub mod store;

mod server;
mod replica;
mod state;

mod messages_capnp {
    #![allow(dead_code)]
    include!(concat!(env!("OUT_DIR"), "/messages_capnp.rs"));
}

use std::{io, ops};
use std::collections::HashSet;
use std::net::SocketAddr;
use std::net::TcpStream;
use std::str::FromStr;
use std::io::BufStream;

use rustc_serialize::Encodable;
// Data structures.
use store::Store;
use server::Server;
use state_machine::StateMachine;

// Cap'n Proto
use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, ReaderOptions, MallocMessageBuilder};
use messages_capnp::{
    client_request,
    client_response,
};

/// This is the primary interface with a `Server` in the cluster.
///
/// Note: Creating a new `Raft` client will, for now, automatically spawn a `Server` with the
/// relevant parameters. This may be changed in the future. This is based on the assumption that
/// any consuming application interacting with a Raft cluster will also be a participant.
pub struct Raft {
    current_leader: Option<SocketAddr>,
    related_server: SocketAddr, // Not Server because we move that to another thread.
    cluster_members: HashSet<SocketAddr>,
}

impl Raft {
    /// Create a new `Raft` client that has a cooresponding `Server` attached. Note that this
    /// `Raft` may not necessarily interact with the cooreponding `Server`, it will interact with
    /// the `Leader` of a cluster in almost all cases.
    /// *Note:* All requests are blocking, by design from the Raft paper.
    pub fn new<S, M>(addr: SocketAddr,
                     cluster_members: HashSet<SocketAddr>,
                     store: S,
                     state_machine: M)
                     -> Raft
    where S: Store, M: StateMachine {
        debug!("Starting Raft on {}", addr);
        let mut peers = cluster_members.clone();
        peers.remove(&addr);
        Server::<S, M>::spawn(addr, peers, store, state_machine);
        // Store relevant information.
        Raft {
            current_leader: None,
            related_server: addr,
            cluster_members: cluster_members,
        }
    }

    /// Appends an entry to the replicated log. This will only return once it's properly replicated
    /// to a majority of nodes.
    pub fn append(&mut self, entry: &[u8]) -> Result<()> {
        let mut message = MallocMessageBuilder::new_default();
        if self.current_leader.is_none() { try!(self.refresh_leader()); }
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_append(entry)
        }
        // We know current leader `is_some()` because `refresh_leader()` didn't fail.
        let unbuffered_socket = try!(TcpStream::connect(self.current_leader.unwrap())); // TODO: Handle Leader
        let mut socket = BufStream::new(unbuffered_socket);
        try!(serialize_packed::write_message(&mut socket, &mut message));

        // Wait for a response.

        let response = try!(serialize_packed::read_message(&mut socket, ReaderOptions::new()));
        let client_res = try!(response.get_root::<client_response::Reader>());
        // Set the current leader.
        match try!(client_res.which()) {
            client_response::Which::Success(()) => {
                // It worked!
                Ok(())
            },
            client_response::Which::NotLeader(Ok(leader_bytes)) => {
                self.current_leader = match SocketAddr::from_str(leader_bytes) {
                    Ok(socket) => Some(socket),
                    Err(_) => return Err(Error::Raft(ErrorKind::BadResponse))
                };
                // Try again.
                self.append(entry)
            },
            _ => unimplemented!(),
        }
    }

    /// Kills the node. Should only really be used for testing purposes.
    /// Accepts a `SocketAddr` because if you're going to kill a node you should be able to pick
    /// your victim.
    pub fn die(&mut self, target: SocketAddr, reason: String) -> Result<()> {
        if !self.cluster_members.contains(&target) {
            return Err(Error::Raft(ErrorKind::NotInCluster))
        }
        let mut message = MallocMessageBuilder::new_default();
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_die(&reason)
        }
        // We know current leader `is_some()` because `refresh_leader()` didn't fail.
        let unbuffered_socket = try!(TcpStream::connect(self.current_leader.unwrap())); // TODO: Handle Leader
        let mut socket = BufStream::new(unbuffered_socket);
        try!(serialize_packed::write_message(&mut socket, &mut message));

        // Wait for a response.
        let response = try!(serialize_packed::read_message(&mut socket, ReaderOptions::new()));
        let client_res = try!(response.get_root::<client_response::Reader>());
        // Set the current leader.
        match try!(client_res.which()) {
            client_response::Which::Success(()) => Ok(()),
            _ => unimplemented!(),
        }
    }

    /// This function will force the `Raft` interface to refresh it's knowledge of the leader from
    /// The cooresponding `Server` running alongside it.
    pub fn refresh_leader(&mut self) -> Result<()> {
        let mut message = MallocMessageBuilder::new_default();
        {
            let mut client_req = message.init_root::<client_request::Builder>();
            client_req.set_leader_refresh(());
        }
        let unbuffered_socket = try!(TcpStream::connect(self.related_server));
        let mut socket = BufStream::new(unbuffered_socket);
        try!(serialize_packed::write_message(&mut socket, &mut message));

        // Wait for a response.
        let response = try!(serialize_packed::read_message(&mut socket, ReaderOptions::new()));
        let client_res = try!(response.get_root::<client_response::Reader>());
        // Set the current leader.
        self.current_leader = match try!(client_res.which()) {
            client_response::Which::Success(()) => unimplemented!(),
            client_response::Which::NotLeader(Ok(leader_bytes)) => {
                match SocketAddr::from_str(leader_bytes) {
                    Ok(socket) => Some(socket),
                    Err(_) => return Err(Error::Raft(ErrorKind::BadResponse))
                }
            },
            client_response::Which::NotLeader(e) => panic!("Error reading response. {:?}", e),
        };
        Ok(())
    }
}

pub type Result<T> = std::result::Result<T, Error>;

/// raft::Errors are the composed variety of errors that can originate from the various libraries.
/// With the exception of the `Raft` variant these are generated from `try!()` macros invoking
/// on `io::Error` or `capnp::Error` by using
/// [`FromError`](https://doc.rust-lang.org/std/error/#the-fromerror-trait).
#[derive(Debug)]
pub enum Error {
    CapnProto(capnp::Error),
    SchemaError(capnp::NotInSchema),
    Io(io::Error),
    Raft(ErrorKind),
}

/// Currently, this can only be:
///
/// * `RelatedNodeDown` - When the related Server is known to be down.
/// * `CannotProceed` - When the related Server cannot proceed due to more than a majority of
///                     nodes being unavailable.
/// TODO: Hook these up.
#[derive(Debug)]
pub enum ErrorKind {
    RelatedNodeDown,
    CannotProceed,
    NotInCluster,
    BadResponse,
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<capnp::Error> for Error {
    fn from(err: capnp::Error) -> Error {
        Error::CapnProto(err)
    }
}

impl From<capnp::NotInSchema> for Error {
    fn from(err: capnp::NotInSchema) -> Error {
        Error::SchemaError(err)
    }
}

/// The term of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
pub struct Term(u64);
impl From<u64> for Term {
    fn from(val: u64) -> Term {
        Term(val)
    }
}
impl Into<u64> for Term {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for Term {
    type Output = Term;
    fn add(self, rhs: u64) -> Term {
        Term(self.0.checked_add(rhs).expect("overflow while incrementing Term"))
    }
}
impl ops::Sub<u64> for Term {
    type Output = Term;
    fn sub(self, rhs: u64) -> Term {
        Term(self.0.checked_sub(rhs).expect("underflow while decrementing Term"))
    }
}

/// The index of a log entry.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
pub struct LogIndex(u64);
impl From<u64> for LogIndex {
    fn from(val: u64) -> LogIndex {
        LogIndex(val)
    }
}
impl Into<u64> for LogIndex {
    fn into(self) -> u64 {
        self.0
    }
}
impl ops::Add<u64> for LogIndex {
    type Output = LogIndex;
    fn add(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_add(rhs).expect("overflow while incrementing LogIndex"))
    }
}
impl ops::Sub<u64> for LogIndex {
    type Output = LogIndex;
    fn sub(self, rhs: u64) -> LogIndex {
        LogIndex(self.0.checked_sub(rhs).expect("underflow while decrementing LogIndex"))
    }
}
<|endoftext|>


<commit_before>#![crate_type = "rlib"]
#![deny(warnings)]
#![deny(bad_style)]
#![feature(collections)]
extern crate rustc_serialize as serialize;
extern crate collections;

pub use mutable_json::MutableJson;
pub use object_builder::ObjectBuilder;
pub use array_builder::ArrayBuilder;
pub use serializer::{Serializer, ObjectSerializer, ObjectScopeSerializer};
pub use array_serializer::ArraySerializer;

pub mod array_builder;
pub mod object_builder;
pub mod mutable_json;
pub mod serializer;
pub mod array_serializer;

/// ```rust
/// let json = jsonway::object(|json| {
///     json.set("first_name", "Luke".to_string());
///     json.set("last_name", "Skywalker".to_string());
///
///     json.object("info", |json| {
///         json.set("homeworld", "Tatooine".to_string());
///         json.set("born", "19 BBY".to_string());
///         json.set("died", "Between 45 ABY and 137 ABY".to_string());
///     });
///
///     json.array("masters", |json| {
///         json.push("Obi-Wan Kenobi".to_string());
///         json.push("Yoda".to_string());
///         json.push("Joruus C'baoth (Briefly)".to_string());
///         json.push("Darth Sidious (Briefly)".to_string());
///     });
/// }).unwrap();
///
/// assert_eq!(json.find("first_name").unwrap().as_string().unwrap(), "Luke");
/// assert_eq!(json.find("last_name").unwrap().as_string().unwrap(), "Skywalker");
///
/// assert!(json.find("info").unwrap().is_object());
/// assert!(json.find("masters").unwrap().is_array());
/// ```

/// Create and return new ListBuilder
pub fn array<F>(builder: F) -> ArrayBuilder where F: FnOnce(&mut ArrayBuilder) {
    ArrayBuilder::build(builder)
}

/// Create and return new ObjectBuilder
pub fn object<F>(builder: F) -> ObjectBuilder where F: FnOnce(&mut ObjectBuilder) {
    ObjectBuilder::build(builder)
}
<commit_msg>updated lib.rs to compile on rust beta<commit_after>#![crate_type = "rlib"]
#![deny(warnings)]
#![deny(bad_style)]
extern crate rustc_serialize as serialize;

pub use mutable_json::MutableJson;
pub use object_builder::ObjectBuilder;
pub use array_builder::ArrayBuilder;
pub use serializer::{Serializer, ObjectSerializer, ObjectScopeSerializer};
pub use array_serializer::ArraySerializer;

pub mod array_builder;
pub mod object_builder;
pub mod mutable_json;
pub mod serializer;
pub mod array_serializer;

/// ```rust
/// let json = jsonway::object(|json| {
///     json.set("first_name", "Luke".to_string());
///     json.set("last_name", "Skywalker".to_string());
///
///     json.object("info", |json| {
///         json.set("homeworld", "Tatooine".to_string());
///         json.set("born", "19 BBY".to_string());
///         json.set("died", "Between 45 ABY and 137 ABY".to_string());
///     });
///
///     json.array("masters", |json| {
///         json.push("Obi-Wan Kenobi".to_string());
///         json.push("Yoda".to_string());
///         json.push("Joruus C'baoth (Briefly)".to_string());
///         json.push("Darth Sidious (Briefly)".to_string());
///     });
/// }).unwrap();
///
/// assert_eq!(json.find("first_name").unwrap().as_string().unwrap(), "Luke");
/// assert_eq!(json.find("last_name").unwrap().as_string().unwrap(), "Skywalker");
///
/// assert!(json.find("info").unwrap().is_object());
/// assert!(json.find("masters").unwrap().is_array());
/// ```

/// Create and return new ListBuilder
pub fn array<F>(builder: F) -> ArrayBuilder where F: FnOnce(&mut ArrayBuilder) {
    ArrayBuilder::build(builder)
}

/// Create and return new ObjectBuilder
pub fn object<F>(builder: F) -> ObjectBuilder where F: FnOnce(&mut ObjectBuilder) {
    ObjectBuilder::build(builder)
}
<|endoftext|>


<commit_before>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
pub struct Mp4Box {
    /// Four character box type
    name: u32,
    /// Size of the box in bytes
    size: u64,
}

/// File type box 'ftyp'.
pub struct Mp4FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Parse a box out of a data buffer.
pub fn read_box<T: ReadBytesExt>(src: &mut T) -> Option<Mp4Box> {
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let name = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    Some(Mp4Box{
        name: name,
        size: size,
    })
}

/// Parse an ftype box.
pub fn read_ftyp<T: ReadBytesExt>(src: &mut T) -> Option<Mp4FileTypeBox> {
    let head = read_box(src).unwrap();
    let major = src.read_u32::<BigEndian>().unwrap();
    let minor = src.read_u32::<BigEndian>().unwrap();
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push(src.read_u32::<BigEndian>().unwrap());
    }
    Some(Mp4FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

use std::fmt;
impl fmt::Display for Mp4Box {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let to_vec = |x| vec!((x >> 24 & 0xffu32) as u8,
                              (x >> 16 & 0xffu32) as u8,
                              (x >>  8 & 0xffu32) as u8,
                              (x & 0xffu32) as u8);
        let name_bytes = to_vec(self.name);
        let name = String::from_utf8_lossy(&name_bytes);
        write!(f, "'{}' {} bytes", name, self.size)
    }
}

#[test]
fn test_read_box() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}

#[test]
fn test_read_ftyp() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
    write!(&mut test, "ftyp").unwrap(); // type
    write!(&mut test, "mp42").unwrap(); // major brand
    test.extend(vec![0, 0, 0, 0]);      // minor version
    write!(&mut test, "isom").unwrap(); // compatible brands...
    write!(&mut test, "mp42").unwrap();
    assert_eq!(test.len(), 24);

    let mut stream = Cursor::new(test);
    let parsed = read_ftyp(&mut stream).unwrap();
    println!("box {} size {}", parsed.name, parsed.size);
    assert_eq!(parsed.name, 1718909296);
    assert_eq!(parsed.size, 24);
    assert_eq!(parsed.major_brand, 1836069938);
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
}
<commit_msg>Add fmt::Display for Mp4FileTypeBox.<commit_after>// Module for parsing ISO Base Media Format aka video/mp4 streams.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// Basic ISO box structure.
pub struct Mp4Box {
    /// Four character box type
    name: u32,
    /// Size of the box in bytes
    size: u64,
}

/// File type box 'ftyp'.
pub struct Mp4FileTypeBox {
    name: u32,
    size: u64,
    major_brand: u32,
    minor_version: u32,
    compatible_brands: Vec<u32>,
}

extern crate byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Parse a box out of a data buffer.
pub fn read_box<T: ReadBytesExt>(src: &mut T) -> Option<Mp4Box> {
    let tmp_size = src.read_u32::<BigEndian>().unwrap();
    let name = src.read_u32::<BigEndian>().unwrap();
    let size = match tmp_size {
        1 => src.read_u64::<BigEndian>().unwrap(),
        _ => tmp_size as u64,
    };
    Some(Mp4Box{
        name: name,
        size: size,
    })
}

/// Parse an ftype box.
pub fn read_ftyp<T: ReadBytesExt>(src: &mut T) -> Option<Mp4FileTypeBox> {
    let head = read_box(src).unwrap();
    let major = src.read_u32::<BigEndian>().unwrap();
    let minor = src.read_u32::<BigEndian>().unwrap();
    let brand_count = (head.size - 8 - 8) /4;
    let mut brands = Vec::new();
    for _ in 0..brand_count {
        brands.push(src.read_u32::<BigEndian>().unwrap());
    }
    Some(Mp4FileTypeBox{
        name: head.name,
        size: head.size,
        major_brand: major,
        minor_version: minor,
        compatible_brands: brands,
    })
}

use std::fmt;
impl fmt::Display for Mp4Box {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let to_vec = |x| vec!((x >> 24 & 0xffu32) as u8,
                              (x >> 16 & 0xffu32) as u8,
                              (x >>  8 & 0xffu32) as u8,
                              (x & 0xffu32) as u8);
        let name_bytes = to_vec(self.name);
        let name = String::from_utf8_lossy(&name_bytes);
        write!(f, "'{}' {} bytes", name, self.size)
    }
}

impl fmt::Display for Mp4FileTypeBox {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let to_vec = |x| vec!((x >> 24 & 0xffu32) as u8,
                              (x >> 16 & 0xffu32) as u8,
                              (x >>  8 & 0xffu32) as u8,
                              (x & 0xffu32) as u8);
        let name_bytes = to_vec(self.name);
        let name = String::from_utf8_lossy(&name_bytes);
        let brand_bytes = to_vec(self.major_brand);
        let brand = String::from_utf8_lossy(&brand_bytes);
        write!(f, "'{}' {} bytes '{}' v{}", name, self.size,
            brand, self.minor_version)
    }
}

#[test]
fn test_read_box() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 8];  // minimal box length
    write!(&mut test, "test").unwrap(); // box type
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1952805748);
    assert_eq!(parsed.size, 8);
    println!("box {}", parsed);
}

#[test]
fn test_read_box_long() {
    use std::io::Cursor;
    let mut test: Vec<u8> = vec![0, 0, 0, 1]; // long box extension code
    test.extend("long".to_string().into_bytes()); // box type
    test.extend(vec![0, 0, 0, 0, 0, 0, 16, 0]); // 64 bit size
    // Skip generating box content.
    let mut stream = Cursor::new(test);
    let parsed = read_box(&mut stream).unwrap();
    assert_eq!(parsed.name, 1819242087);
    assert_eq!(parsed.size, 4096);
    println!("box {}", parsed);
}

#[test]
fn test_read_ftyp() {
    use std::io::Cursor;
    use std::io::Write;
    let mut test: Vec<u8> = vec![0, 0, 0, 24]; // size
    write!(&mut test, "ftyp").unwrap(); // type
    write!(&mut test, "mp42").unwrap(); // major brand
    test.extend(vec![0, 0, 0, 0]);      // minor version
    write!(&mut test, "isom").unwrap(); // compatible brands...
    write!(&mut test, "mp42").unwrap();
    assert_eq!(test.len(), 24);

    let mut stream = Cursor::new(test);
    let parsed = read_ftyp(&mut stream).unwrap();
    println!("box {} size {}", parsed.name, parsed.size);
    assert_eq!(parsed.name, 1718909296);
    assert_eq!(parsed.size, 24);
    assert_eq!(parsed.major_brand, 1836069938);
    assert_eq!(parsed.minor_version, 0);
    assert_eq!(parsed.compatible_brands.len(), 2);
    println!("box {}", parsed);
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/pipe/0.4.0")]
#![cfg_attr(feature = "unstable-doc-cfg", feature(doc_cfg))]

//! Synchronous in-memory pipe
//!
//! ## Example
//!
//! ```
//! use std::thread::spawn;
//! use std::io::{Read, Write};
//!
//! let (mut read, mut write) = pipe::pipe();
//!
//! let message = "Hello, world!";
//! spawn(move || write.write_all(message.as_bytes()).unwrap());
//!
//! let mut s = String::new();
//! read.read_to_string(&mut s).unwrap();
//!
//! assert_eq!(&s, message);
//! ```

#[cfg(feature="readwrite")]
extern crate readwrite;
extern crate crossbeam_channel;

use crossbeam_channel::{Sender, Receiver, SendError, TrySendError};
use std::io::{self, BufRead, Read, Write};
use std::cmp::min;
use std::mem::replace;
use std::hint::unreachable_unchecked;

// value for libstd
const DEFAULT_BUF_SIZE: usize = 8 * 1024;

/// The `Read` end of a pipe (see `pipe()`)
pub struct PipeReader {
    receiver: Receiver<Vec<u8>>,
    buffer: Vec<u8>,
    position: usize,
}

/// The `Write` end of a pipe (see `pipe()`)
#[derive(Clone)]
pub struct PipeWriter {
    sender: Sender<Vec<u8>>
}

/// The `Write` end of a pipe (see `pipe()`) that will buffer small writes before sending
/// to the reader end.
pub struct PipeBufWriter {
    sender: Option<Sender<Vec<u8>>>,
    buffer: Vec<u8>,
    size: usize,
}

/// Creates a synchronous memory pipe
pub fn pipe() -> (PipeReader, PipeWriter) {
    let (sender, receiver) = crossbeam_channel::bounded(0);

    (
        PipeReader { receiver, buffer: Vec::new(), position: 0 },
        PipeWriter { sender },
    )
}

/// Creates a synchronous memory pipe with buffered writer
pub fn pipe_buffered() -> (PipeReader, PipeBufWriter) {
    let (tx, rx) = crossbeam_channel::bounded(0);

    (PipeReader{ receiver: rx, buffer: Vec::new(), position: 0 }, PipeBufWriter { sender: Some(tx), buffer: Vec::with_capacity(DEFAULT_BUF_SIZE), size: DEFAULT_BUF_SIZE } )
}

/// Creates a pair of pipes for bidirectional communication, a bit like UNIX's `socketpair(2)`.
#[cfg(feature = "bidirectional")]
#[cfg_attr(feature = "unstable-doc-cfg", doc(cfg(feature = "bidirectional")))]
pub fn bipipe() -> (readwrite::ReadWrite<PipeReader, PipeWriter>, readwrite::ReadWrite<PipeReader, PipeWriter>) {
    let (r1,w1) = pipe();
    let (r2,w2) = pipe();
    ((r1,w2).into(), (r2,w1).into())
}

/// Creates a pair of pipes for bidirectional communication using buffered writer, a bit like UNIX's `socketpair(2)`.
#[cfg(feature = "bidirectional")]
#[cfg_attr(feature = "unstable-doc-cfg", doc(cfg(feature = "bidirectional")))]
pub fn bipipe_buffered() -> (readwrite::ReadWrite<PipeReader, PipeBufWriter>, readwrite::ReadWrite<PipeReader, PipeBufWriter>) {
    let (r1,w1) = pipe_buffered();
    let (r2,w2) = pipe_buffered();
    ((r1,w2).into(), (r2,w1).into())
}

fn epipe() -> io::Error {
    io::Error::new(io::ErrorKind::BrokenPipe, "pipe reader has been dropped")
}

impl PipeWriter {
    /// Extracts the inner `Sender` from the writer
    pub fn into_inner(self) -> Sender<Vec<u8>> {
        self.sender
    }

    /// Gets a reference to the underlying `Sender`
    pub fn sender(&self) -> &Sender<Vec<u8>> {
        &self.sender
    }

    /// Write data to the associated `PipeReader`
    pub fn send<B: Into<Vec<u8>>>(&self, bytes: B) -> io::Result<()> {
        self.sender.send(bytes.into())
            .map_err(|_| epipe())
            .map(drop)
    }
}

impl PipeBufWriter {
    /// Extracts the inner `Sender` from the writer, and any pending buffered data
    pub fn into_inner(mut self) -> (Sender<Vec<u8>>, Vec<u8>) {
        let sender = match replace(&mut self.sender, None) {
            Some(sender) => sender,
            None => unsafe {
                // SAFETY: this is safe as long as `into_inner()` is the only method
                // that clears the sender
                unreachable_unchecked()
            },
        };
        (sender, replace(&mut self.buffer, Vec::new()))
    }

    #[inline]
    /// Gets a reference to the underlying `Sender`
    pub fn sender(&self) -> &Sender<Vec<u8>> {
        match &self.sender {
            Some(sender) => sender,
            None => unsafe {
                // SAFETY: this is safe as long as `into_inner()` is the only method
                // that clears the sender, and this fn is never called afterward
                unreachable_unchecked()
            },
        }
    }

    /// Returns a reference to the internally buffered data.
    pub fn buffer(&self) -> &[u8] {
        &self.buffer
    }

    /// Returns the number of bytes the internal buffer can hold without flushing.
    pub fn capacity(&self) -> usize {
        self.size
    }
}

/// Creates a new handle to the `PipeBufWriter` with a fresh new buffer. Any pending data is still
/// owned by the existing writer and should be flushed if necessary.
impl Clone for PipeBufWriter {
    fn clone(&self) -> Self {
        Self {
            sender: self.sender.clone(),
            buffer: Vec::with_capacity(self.size),
            size: self.size,
        }
    }
}

impl PipeReader {
    /// Extracts the inner `Receiver` from the writer, and any pending buffered data
    pub fn into_inner(mut self) -> (Receiver<Vec<u8>>, Vec<u8>) {
        self.buffer.drain(..self.position);
        (self.receiver, self.buffer)
    }
}

impl BufRead for PipeReader {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        while self.position >= self.buffer.len() {
            match self.receiver.recv() {
                // The only existing error is EOF
                Err(_) => break,
                Ok(data) => {
                    self.buffer = data;
                    self.position = 0;
                }
            }
        }

        Ok(&self.buffer[self.position..])
    }

    fn consume(&mut self, amt: usize) {
        debug_assert!(self.buffer.len() - self.position >= amt);
        self.position += amt
    }
}

impl Read for PipeReader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.is_empty() {
            return Ok(0);
        }

        let internal = self.fill_buf()?;

        let len = min(buf.len(), internal.len());
        if len > 0 {
            buf[..len].copy_from_slice(&internal[..len]);
            self.consume(len);
        }
        Ok(len)
    }
}

impl Write for &'_ PipeWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let data = buf.to_vec();

        self.send(data)
            .map(|_| buf.len())
    }

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

impl Write for PipeWriter {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Write::write(&mut &*self, buf)
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Write::flush(&mut &*self)
    }
}

impl Write for PipeBufWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let buffer_len = self.buffer.len();
        let bytes_written = if buf.len() > self.size {
            // bypass buffering for big writes
            buf.len()
        } else {
            // avoid resizing of the buffer
            min(buf.len(), self.size - buffer_len)
        };
        self.buffer.extend_from_slice(&buf[..bytes_written]);

        if self.buffer.len() >= self.size {
            self.flush()?;
        } else {
            // reserve capacity later to avoid needless allocations
            let data = replace(&mut self.buffer, Vec::new());

            // buffer still has space but try to send it in case the other side already awaits
            match self.sender().try_send(data) {
                Ok(_) => self.buffer.reserve(self.size),
                Err(TrySendError::Full(data)) =>
                    self.buffer = data,
                Err(TrySendError::Disconnected(data)) => {
                    self.buffer = data;
                    self.buffer.truncate(buffer_len);
                    return Err(epipe())
                },
            }
        }

        Ok(bytes_written)
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.buffer.is_empty() {
            Ok(())
        } else {
            let data = replace(&mut self.buffer, Vec::new());
            match self.sender().send(data) {
                Ok(_) => {
                    self.buffer.reserve(self.size);
                    Ok(())
                },
                Err(SendError(data)) => {
                    self.buffer = data;
                    Err(epipe())
                },
            }
        }
    }
}

/// Flushes the contents of the buffer before the writer is dropped. Errors are ignored, so it is
/// recommended that `flush()` be used explicitly instead of relying on Drop.
///
/// This final flush can be avoided by using `drop(writer.into_inner())`.
impl Drop for PipeBufWriter {
    fn drop(&mut self) {
        if !self.buffer.is_empty() {
            let data = replace(&mut self.buffer, Vec::new());
            let _ = self.sender().send(data);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::thread::spawn;
    use std::io::{Read, Write};
    use super::*;

    #[test]
    fn pipe_reader() {
        let i = b"hello there";
        let mut o = Vec::with_capacity(i.len());
        let (mut r, mut w) = pipe();
        let guard = spawn(move || {
            w.write_all(&i[..5]).unwrap();
            w.write_all(&i[5..]).unwrap();
            drop(w);
        });

        r.read_to_end(&mut o).unwrap();
        assert_eq!(i, &o[..]);

        guard.join().unwrap();
    }

    #[test]
    fn pipe_writer_fail() {
        let i = b"hi";
        let (r, mut w) = pipe();
        let guard = spawn(move || {
            drop(r);
        });

        assert!(w.write_all(i).is_err());

        guard.join().unwrap();
    }

    #[test]
    fn small_reads() {
        let block_cnt = 20;
        const BLOCK: usize = 20;
        let (mut r, mut w) = pipe();
        let guard = spawn(move || {
            for _ in 0..block_cnt {
                let data = &[0; BLOCK];
                w.write_all(data).unwrap();
            }
        });

        let mut buff = [0; BLOCK / 2];
        let mut read = 0;
        while let Ok(size) = r.read(&mut buff) {
            // 0 means EOF
            if size == 0 {
                break;
            }
            read += size;
        }
        assert_eq!(block_cnt * BLOCK, read);

        guard.join().unwrap();
    }

    #[test]
    fn pipe_reader_buffered() {
        let i = b"hello there";
        let mut o = Vec::with_capacity(i.len());
        let (mut r, mut w) = pipe_buffered();
        let guard = spawn(move || {
            w.write_all(&i[..5]).unwrap();
            w.write_all(&i[5..]).unwrap();
            w.flush().unwrap();
            drop(w);
        });

        r.read_to_end(&mut o).unwrap();
        assert_eq!(i, &o[..]);

        guard.join().unwrap();
    }

    #[test]
    fn pipe_writer_fail_buffered() {
        let i = &[0; DEFAULT_BUF_SIZE * 2];
        let (r, mut w) = pipe_buffered();
        let guard = spawn(move || {
            drop(r);
        });

        assert!(w.write_all(i).is_err());

        guard.join().unwrap();
    }

    #[test]
    fn small_reads_buffered() {
        let block_cnt = 20;
        const BLOCK: usize = 20;
        let (mut r, mut w) = pipe_buffered();
        let guard = spawn(move || {
            for _ in 0..block_cnt {
                let data = &[0; BLOCK];
                w.write_all(data).unwrap();
            }
            w.flush().unwrap();
        });

        let mut buff = [0; BLOCK / 2];
        let mut read = 0;
        while let Ok(size) = r.read(&mut buff) {
            // 0 means EOF
            if size == 0 {
                break;
            }
            read += size;
        }
        assert_eq!(block_cnt * BLOCK, read);

        guard.join().unwrap();
    }
}
<commit_msg>impl Clone for PipeReader<commit_after>#![deny(missing_docs)]
#![doc(html_root_url = "https://docs.rs/pipe/0.4.0")]
#![cfg_attr(feature = "unstable-doc-cfg", feature(doc_cfg))]

//! Synchronous in-memory pipe
//!
//! ## Example
//!
//! ```
//! use std::thread::spawn;
//! use std::io::{Read, Write};
//!
//! let (mut read, mut write) = pipe::pipe();
//!
//! let message = "Hello, world!";
//! spawn(move || write.write_all(message.as_bytes()).unwrap());
//!
//! let mut s = String::new();
//! read.read_to_string(&mut s).unwrap();
//!
//! assert_eq!(&s, message);
//! ```

#[cfg(feature="readwrite")]
extern crate readwrite;
extern crate crossbeam_channel;

use crossbeam_channel::{Sender, Receiver, SendError, TrySendError};
use std::io::{self, BufRead, Read, Write};
use std::cmp::min;
use std::mem::replace;
use std::hint::unreachable_unchecked;

// value for libstd
const DEFAULT_BUF_SIZE: usize = 8 * 1024;

/// The `Read` end of a pipe (see `pipe()`)
pub struct PipeReader {
    receiver: Receiver<Vec<u8>>,
    buffer: Vec<u8>,
    position: usize,
}

/// The `Write` end of a pipe (see `pipe()`)
#[derive(Clone)]
pub struct PipeWriter {
    sender: Sender<Vec<u8>>
}

/// The `Write` end of a pipe (see `pipe()`) that will buffer small writes before sending
/// to the reader end.
pub struct PipeBufWriter {
    sender: Option<Sender<Vec<u8>>>,
    buffer: Vec<u8>,
    size: usize,
}

/// Creates a synchronous memory pipe
pub fn pipe() -> (PipeReader, PipeWriter) {
    let (sender, receiver) = crossbeam_channel::bounded(0);

    (
        PipeReader { receiver, buffer: Vec::new(), position: 0 },
        PipeWriter { sender },
    )
}

/// Creates a synchronous memory pipe with buffered writer
pub fn pipe_buffered() -> (PipeReader, PipeBufWriter) {
    let (tx, rx) = crossbeam_channel::bounded(0);

    (PipeReader { receiver: rx, buffer: Vec::new(), position: 0 }, PipeBufWriter { sender: Some(tx), buffer: Vec::with_capacity(DEFAULT_BUF_SIZE), size: DEFAULT_BUF_SIZE } )
}

/// Creates a pair of pipes for bidirectional communication, a bit like UNIX's `socketpair(2)`.
#[cfg(feature = "bidirectional")]
#[cfg_attr(feature = "unstable-doc-cfg", doc(cfg(feature = "bidirectional")))]
pub fn bipipe() -> (readwrite::ReadWrite<PipeReader, PipeWriter>, readwrite::ReadWrite<PipeReader, PipeWriter>) {
    let (r1,w1) = pipe();
    let (r2,w2) = pipe();
    ((r1,w2).into(), (r2,w1).into())
}

/// Creates a pair of pipes for bidirectional communication using buffered writer, a bit like UNIX's `socketpair(2)`.
#[cfg(feature = "bidirectional")]
#[cfg_attr(feature = "unstable-doc-cfg", doc(cfg(feature = "bidirectional")))]
pub fn bipipe_buffered() -> (readwrite::ReadWrite<PipeReader, PipeBufWriter>, readwrite::ReadWrite<PipeReader, PipeBufWriter>) {
    let (r1,w1) = pipe_buffered();
    let (r2,w2) = pipe_buffered();
    ((r1,w2).into(), (r2,w1).into())
}

fn epipe() -> io::Error {
    io::Error::new(io::ErrorKind::BrokenPipe, "pipe reader has been dropped")
}

impl PipeWriter {
    /// Extracts the inner `Sender` from the writer
    pub fn into_inner(self) -> Sender<Vec<u8>> {
        self.sender
    }

    /// Gets a reference to the underlying `Sender`
    pub fn sender(&self) -> &Sender<Vec<u8>> {
        &self.sender
    }

    /// Write data to the associated `PipeReader`
    pub fn send<B: Into<Vec<u8>>>(&self, bytes: B) -> io::Result<()> {
        self.sender.send(bytes.into())
            .map_err(|_| epipe())
            .map(drop)
    }
}

impl PipeBufWriter {
    /// Extracts the inner `Sender` from the writer, and any pending buffered data
    pub fn into_inner(mut self) -> (Sender<Vec<u8>>, Vec<u8>) {
        let sender = match replace(&mut self.sender, None) {
            Some(sender) => sender,
            None => unsafe {
                // SAFETY: this is safe as long as `into_inner()` is the only method
                // that clears the sender
                unreachable_unchecked()
            },
        };
        (sender, replace(&mut self.buffer, Vec::new()))
    }

    #[inline]
    /// Gets a reference to the underlying `Sender`
    pub fn sender(&self) -> &Sender<Vec<u8>> {
        match &self.sender {
            Some(sender) => sender,
            None => unsafe {
                // SAFETY: this is safe as long as `into_inner()` is the only method
                // that clears the sender, and this fn is never called afterward
                unreachable_unchecked()
            },
        }
    }

    /// Returns a reference to the internally buffered data.
    pub fn buffer(&self) -> &[u8] {
        &self.buffer
    }

    /// Returns the number of bytes the internal buffer can hold without flushing.
    pub fn capacity(&self) -> usize {
        self.size
    }
}

/// Creates a new handle to the `PipeBufWriter` with a fresh new buffer. Any pending data is still
/// owned by the existing writer and should be flushed if necessary.
impl Clone for PipeBufWriter {
    fn clone(&self) -> Self {
        Self {
            sender: self.sender.clone(),
            buffer: Vec::with_capacity(self.size),
            size: self.size,
        }
    }
}

impl PipeReader {
    /// Extracts the inner `Receiver` from the writer, and any pending buffered data
    pub fn into_inner(mut self) -> (Receiver<Vec<u8>>, Vec<u8>) {
        self.buffer.drain(..self.position);
        (self.receiver, self.buffer)
    }
}

/// Creates a new handle to the `PipeReader` with a fresh new buffer. Any pending data is still
/// owned by the existing reader and will not be accessible from the new handle.
impl Clone for PipeReader {
    fn clone(&self) -> Self {
        Self {
            receiver: self.receiver.clone(),
            buffer: Vec::new(),
            position: 0,
        }
    }
}

impl BufRead for PipeReader {
    fn fill_buf(&mut self) -> io::Result<&[u8]> {
        while self.position >= self.buffer.len() {
            match self.receiver.recv() {
                // The only existing error is EOF
                Err(_) => break,
                Ok(data) => {
                    self.buffer = data;
                    self.position = 0;
                }
            }
        }

        Ok(&self.buffer[self.position..])
    }

    fn consume(&mut self, amt: usize) {
        debug_assert!(self.buffer.len() - self.position >= amt);
        self.position += amt
    }
}

impl Read for PipeReader {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.is_empty() {
            return Ok(0);
        }

        let internal = self.fill_buf()?;

        let len = min(buf.len(), internal.len());
        if len > 0 {
            buf[..len].copy_from_slice(&internal[..len]);
            self.consume(len);
        }
        Ok(len)
    }
}

impl Write for &'_ PipeWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let data = buf.to_vec();

        self.send(data)
            .map(|_| buf.len())
    }

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

impl Write for PipeWriter {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        Write::write(&mut &*self, buf)
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        Write::flush(&mut &*self)
    }
}

impl Write for PipeBufWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let buffer_len = self.buffer.len();
        let bytes_written = if buf.len() > self.size {
            // bypass buffering for big writes
            buf.len()
        } else {
            // avoid resizing of the buffer
            min(buf.len(), self.size - buffer_len)
        };
        self.buffer.extend_from_slice(&buf[..bytes_written]);

        if self.buffer.len() >= self.size {
            self.flush()?;
        } else {
            // reserve capacity later to avoid needless allocations
            let data = replace(&mut self.buffer, Vec::new());

            // buffer still has space but try to send it in case the other side already awaits
            match self.sender().try_send(data) {
                Ok(_) => self.buffer.reserve(self.size),
                Err(TrySendError::Full(data)) =>
                    self.buffer = data,
                Err(TrySendError::Disconnected(data)) => {
                    self.buffer = data;
                    self.buffer.truncate(buffer_len);
                    return Err(epipe())
                },
            }
        }

        Ok(bytes_written)
    }

    fn flush(&mut self) -> io::Result<()> {
        if self.buffer.is_empty() {
            Ok(())
        } else {
            let data = replace(&mut self.buffer, Vec::new());
            match self.sender().send(data) {
                Ok(_) => {
                    self.buffer.reserve(self.size);
                    Ok(())
                },
                Err(SendError(data)) => {
                    self.buffer = data;
                    Err(epipe())
                },
            }
        }
    }
}

/// Flushes the contents of the buffer before the writer is dropped. Errors are ignored, so it is
/// recommended that `flush()` be used explicitly instead of relying on Drop.
///
/// This final flush can be avoided by using `drop(writer.into_inner())`.
impl Drop for PipeBufWriter {
    fn drop(&mut self) {
        if !self.buffer.is_empty() {
            let data = replace(&mut self.buffer, Vec::new());
            let _ = self.sender().send(data);
        }
    }
}

#[cfg(test)]
mod tests {
    use std::thread::spawn;
    use std::io::{Read, Write};
    use super::*;

    #[test]
    fn pipe_reader() {
        let i = b"hello there";
        let mut o = Vec::with_capacity(i.len());
        let (mut r, mut w) = pipe();
        let guard = spawn(move || {
            w.write_all(&i[..5]).unwrap();
            w.write_all(&i[5..]).unwrap();
            drop(w);
        });

        r.read_to_end(&mut o).unwrap();
        assert_eq!(i, &o[..]);

        guard.join().unwrap();
    }

    #[test]
    fn pipe_writer_fail() {
        let i = b"hi";
        let (r, mut w) = pipe();
        let guard = spawn(move || {
            drop(r);
        });

        assert!(w.write_all(i).is_err());

        guard.join().unwrap();
    }

    #[test]
    fn small_reads() {
        let block_cnt = 20;
        const BLOCK: usize = 20;
        let (mut r, mut w) = pipe();
        let guard = spawn(move || {
            for _ in 0..block_cnt {
                let data = &[0; BLOCK];
                w.write_all(data).unwrap();
            }
        });

        let mut buff = [0; BLOCK / 2];
        let mut read = 0;
        while let Ok(size) = r.read(&mut buff) {
            // 0 means EOF
            if size == 0 {
                break;
            }
            read += size;
        }
        assert_eq!(block_cnt * BLOCK, read);

        guard.join().unwrap();
    }

    #[test]
    fn pipe_reader_buffered() {
        let i = b"hello there";
        let mut o = Vec::with_capacity(i.len());
        let (mut r, mut w) = pipe_buffered();
        let guard = spawn(move || {
            w.write_all(&i[..5]).unwrap();
            w.write_all(&i[5..]).unwrap();
            w.flush().unwrap();
            drop(w);
        });

        r.read_to_end(&mut o).unwrap();
        assert_eq!(i, &o[..]);

        guard.join().unwrap();
    }

    #[test]
    fn pipe_writer_fail_buffered() {
        let i = &[0; DEFAULT_BUF_SIZE * 2];
        let (r, mut w) = pipe_buffered();
        let guard = spawn(move || {
            drop(r);
        });

        assert!(w.write_all(i).is_err());

        guard.join().unwrap();
    }

    #[test]
    fn small_reads_buffered() {
        let block_cnt = 20;
        const BLOCK: usize = 20;
        let (mut r, mut w) = pipe_buffered();
        let guard = spawn(move || {
            for _ in 0..block_cnt {
                let data = &[0; BLOCK];
                w.write_all(data).unwrap();
            }
            w.flush().unwrap();
        });

        let mut buff = [0; BLOCK / 2];
        let mut read = 0;
        while let Ok(size) = r.read(&mut buff) {
            // 0 means EOF
            if size == 0 {
                break;
            }
            read += size;
        }
        assert_eq!(block_cnt * BLOCK, read);

        guard.join().unwrap();
    }
}
<|endoftext|>