<commit_before>use Endpoint;
use PageableEndpoint;
use Pager;
use client::Client;
use response;

#[derive(Serialize, Debug, Clone)]
pub struct GetFullEntry {
	pub id: usize,
}

impl Endpoint for GetFullEntry {
	type ResponseType = response::info::Fullentry;
	const URL: &'static str = "info/fullentry";
}

#[derive(Serialize, Debug, Clone)]
pub struct GetEntry {
	pub id: usize,
}

impl Endpoint for GetEntry {
	type ResponseType = response::info::GetEntry;
	const URL: &'static str = "info/entry";
}

#[derive(Serialize, Debug, Clone)]
pub struct GetNames {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetGate {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetLang {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetSeason {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetGroups {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetPublisher {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetListinfo {
	pub id: usize,
	pub p: Option<i64>,
	pub limit: Option<i64>,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetComments {
	pub id: usize,
	pub p: Option<usize>,
	pub limit: Option<usize>,
	pub sort: Option<String>,
}

impl Endpoint for GetComments {
	type ResponseType = Vec<response::info::Comment>;
	const URL: &'static str = "info/comments";
}

impl PageableEndpoint for GetComments {
	fn pager(self, client: Client) -> Pager<GetComments>
	{
		debug!("new pager with data: {:?}", self);
		Pager::new(client, self, Some(0), Some(3))
	}

	fn page_mut(&mut self) -> &mut Option<usize>
	{
		&mut self.p
	}

	fn limit_mut(&mut self) -> &mut Option<usize>
	{
		&mut self.limit
	}
}

#[derive(Serialize, Debug, Clone)]
pub struct GetRelations {
	pub info_id: usize,
	pub is_h: Option<bool>,
}

#[derive(Serialize, Debug, Clone)]
pub struct EntryTags {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetTranslatorgroup {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetIndustry {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct SetUserInfo {
	pub id: usize,
	/// since 'type' is a rust keyword, this parameter is renamed
	#[serde(rename = "type")]
	pub type_: String,
}
<commit_msg>docs: hide url's in docs<commit_after>use Endpoint;
use PageableEndpoint;
use Pager;
use client::Client;
use response;

#[derive(Serialize, Debug, Clone)]
pub struct GetFullEntry {
	pub id: usize,
}

impl Endpoint for GetFullEntry {
	type ResponseType = response::info::Fullentry;
	#[doc(hidden)]
	const URL: &'static str = "info/fullentry";
}

#[derive(Serialize, Debug, Clone)]
pub struct GetEntry {
	pub id: usize,
}

impl Endpoint for GetEntry {
	type ResponseType = response::info::GetEntry;
	#[doc(hidden)]
	const URL: &'static str = "info/entry";
}

#[derive(Serialize, Debug, Clone)]
pub struct GetNames {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetGate {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetLang {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetSeason {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetGroups {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetPublisher {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetListinfo {
	pub id: usize,
	pub p: Option<i64>,
	pub limit: Option<i64>,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetComments {
	pub id: usize,
	pub p: Option<usize>,
	pub limit: Option<usize>,
	pub sort: Option<String>,
}

impl Endpoint for GetComments {
	type ResponseType = Vec<response::info::Comment>;
	#[doc(hidden)]
	const URL: &'static str = "info/comments";
}

impl PageableEndpoint for GetComments {
	fn pager(self, client: Client) -> Pager<GetComments>
	{
		debug!("new pager with data: {:?}", self);
		Pager::new(client, self, Some(0), Some(3))
	}

	fn page_mut(&mut self) -> &mut Option<usize>
	{
		&mut self.p
	}

	fn limit_mut(&mut self) -> &mut Option<usize>
	{
		&mut self.limit
	}
}

#[derive(Serialize, Debug, Clone)]
pub struct GetRelations {
	pub info_id: usize,
	pub is_h: Option<bool>,
}

#[derive(Serialize, Debug, Clone)]
pub struct EntryTags {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetTranslatorgroup {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct GetIndustry {
	pub id: usize,
}

#[derive(Serialize, Debug, Clone)]
pub struct SetUserInfo {
	pub id: usize,
	/// since 'type' is a rust keyword, this parameter is renamed
	#[serde(rename = "type")]
	pub type_: String,
}
<|endoftext|>


<commit_before>
use std::io::prelude::*;
use std::fs;

fn main() {
    let mut s: String = String::new();
    let mut f = match fs::File::open("input") {
        Err(e) => panic!("Can't open file \"{}\": {}", "input", e),
        Ok(f) => f,
    };
    f.read_to_string(&mut s).ok().expect("can't read string");
    let floor = s.as_bytes().iter().fold(0i64, |acc: i64, &c| match c {
        b'(' => acc+1,
        b')' => acc-1,
        _ => acc,
    });
    println!("Santa should go to floor {}", floor);
}
<commit_msg>fixed day 1 input; switched byte iterator to char<commit_after>
use std::io::prelude::*;
use std::fs;

const FILENAME: &'static str = "input_d1";
fn main() {
    let mut s: String = String::new();
    let mut f = match fs::File::open(FILENAME) {
        Err(e) => panic!("Can't open file \"{}\": {}", FILENAME, e),
        Ok(f) => f,
    };
    f.read_to_string(&mut s).ok().expect("can't read string");
    let floor = s.chars().fold(0i64, |acc: i64, c| match c {
        '(' => acc+1,
        ')' => acc-1,
        _ => acc,
    });
    println!("Santa should go to floor {}", floor);
}
<|endoftext|>


<commit_before>extern crate bev;

#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;

use bev::{Bez3o2d};

use gfx::traits::FactoryExt;
use gfx::{Device, Primitive};
use gfx::state::Rasterizer;

use glutin::Event;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

gfx_vertex_struct!{ Vertex {
    pos: [f32; 2] = "v_pos",
}}

gfx_pipeline!{ pipe {
    vbuf: gfx::VertexBuffer<Vertex> = (),
    out: gfx::RenderTarget<ColorFormat> = "r_target",
}}

fn main() {
    let builder = glutin::WindowBuilder::new()
        .with_dimensions(720, 720)
        .with_multisampling(16)
        .with_title("Hello Bézier".into());
    let (window, mut device, mut factory, main_color, _) =
        gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
    let sset = factory.create_shader_set(VERT, FRAG).unwrap();
    let pso = factory.create_pipeline_state(
        &sset,
        Primitive::TriangleStrip,
        Rasterizer::new_fill(),
        pipe::new()
    ).unwrap();

    let curve = Bez3o2d::new(
        0.0, 0.0, 1.0, 1.0,
        0.0, 1.0, 0.0, 1.0
    );

    let mut verts = [Vertex{ pos: [0.0, 0.0] }; 31];
    let mut perps = [Vertex{ pos: [0.0, 0.0] }; 62];
    for i in 0..verts.len() {
        let t = i as f32/(verts.len()-1) as f32;

        let interp = curve.interp(t);
        verts[i].pos = interp.into();

        let perp = curve.slope(t).normalize().perp() * 0.01;
        perps[i*2].pos = (-perp + interp).into();
        perps[i*2 + 1].pos = (perp + interp).into();
    }

    // let (vert_buffer, vert_slice) = factory.create_vertex_buffer_with_slice(&verts, ());
    let (perp_buffer, perp_slice) = factory.create_vertex_buffer_with_slice(&perps, ());
    let mut data = pipe::Data {
        vbuf: perp_buffer.clone(),
        out: main_color
    };

    'main: loop {
        for event in window.poll_events() {
            match event {
                Event::Closed => break 'main,
                _ => ()
            }
        }

        encoder.clear(&data.out, [0.0, 0.0, 0.0, 1.0]);

        // data.vbuf = vert_buffer.clone();
        // encoder.draw(&vert_slice, &pso, &data);

        data.vbuf = perp_buffer.clone();
        encoder.draw(&perp_slice, &pso, &data);

        encoder.flush(&mut device);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

const VERT: &'static [u8] = br#"
    #version 150 core

    in vec2 v_pos;

    void main() {
        gl_Position = vec4(v_pos, 0.0, 1.0);
    }
"#;

const FRAG: &'static [u8] = br#"
    #version 150 core

    out vec4 r_target;

    void main() {
        r_target = vec4(1.0, 1.0, 1.0, 1.0);
    }
"#;<commit_msg>Add color passthrough to curve drawing example<commit_after>extern crate bev;

#[macro_use]
extern crate gfx;
extern crate gfx_window_glutin;
extern crate glutin;

use bev::{Bez3o2d};

use gfx::traits::FactoryExt;
use gfx::{Device, Primitive};
use gfx::state::Rasterizer;

use glutin::Event;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

gfx_vertex_struct!{ Vertex {
    pos: [f32; 2] = "v_pos",
    col: [f32; 3] = "v_col",
}}

gfx_pipeline!{ pipe {
    vbuf: gfx::VertexBuffer<Vertex> = (),
    out: gfx::RenderTarget<ColorFormat> = "r_target",
}}

fn main() {
    let builder = glutin::WindowBuilder::new()
        .with_dimensions(720, 720)
        .with_multisampling(16)
        .with_title("Hello Bézier".into());
    let (window, mut device, mut factory, main_color, _) =
        gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
    let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
    let sset = factory.create_shader_set(VERT, FRAG).unwrap();
    let pso = factory.create_pipeline_state(
        &sset,
        Primitive::TriangleStrip,
        Rasterizer::new_fill(),
        pipe::new()
    ).unwrap();

    let curve = Bez3o2d::new(
        0.0, 0.0, 1.0, 1.0,
        0.0, 1.0, 0.0, 1.0
    );

    let mut verts = [Vertex{ pos: [0.0, 0.0], col: [1.0, 1.0, 1.0] }; 31];
    let mut perps = [Vertex{ pos: [0.0, 0.0], col: [1.0, 1.0, 1.0] }; 62];
    for i in 0..verts.len() {
        let t = i as f32/(verts.len()-1) as f32;

        let interp = curve.interp(t);
        verts[i].pos = interp.into();

        let perp = curve.slope(t).normalize().perp() * 0.01;
        perps[i*2].pos = (-perp + interp).into();
        perps[i*2 + 1].pos = (perp + interp).into();
    }

    // let (vert_buffer, vert_slice) = factory.create_vertex_buffer_with_slice(&verts, ());
    let (perp_buffer, perp_slice) = factory.create_vertex_buffer_with_slice(&perps, ());
    let mut data = pipe::Data {
        vbuf: perp_buffer.clone(),
        out: main_color
    };

    'main: loop {
        for event in window.poll_events() {
            match event {
                Event::Closed => break 'main,
                _ => ()
            }
        }

        encoder.clear(&data.out, [0.0, 0.0, 0.0, 1.0]);

        // data.vbuf = vert_buffer.clone();
        // encoder.draw(&vert_slice, &pso, &data);

        data.vbuf = perp_buffer.clone();
        encoder.draw(&perp_slice, &pso, &data);

        encoder.flush(&mut device);
        window.swap_buffers().unwrap();
        device.cleanup();
    }
}

const VERT: &'static [u8] = br#"
    #version 150 core

    in vec2 v_pos;
    in vec3 v_col;
    out vec4 f_col;

    void main() {
        f_col = vec4(v_col, 1.0);
        gl_Position = vec4(v_pos, 0.0, 1.0);
    }
"#;

const FRAG: &'static [u8] = br#"
    #version 150 core

    in vec4 f_col;
    out vec4 r_target;

    void main() {
        r_target = f_col;
    }
"#;<|endoftext|>


<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, session: core::SessionRef) {
    let (linenum, charnum) = scopes::point_to_coords_from_file(&m.filepath, m.point, session).unwrap();
    if m.matchstr == "" {
        panic!("MATCHSTR is empty - waddup?");
    }

    let snippet = racer::snippets::snippet_for_match(&m, session);
    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, session: core::SessionRef) {
    if let Some((linenum, charnum)) = scopes::point_to_coords_from_file(&m.filepath,
                                                                        m.point,
                                                                        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, core::SessionRef), 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 = session.load_file(&fpath);
            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, &session);
            }
            println!("END");
        }
        Err(_) => {
            // input: a command line string passed in
            let arg = &args[1];
            let it = arg.split("::");
            let p: Vec<&str> = it.collect();
            let session = core::Session::from_path(&Path::new("."), &Path::new("."));

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

#[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 = session.load_file(&fpath);
    let pos = scopes::coords_to_point(&src, linenum, charnum);

    core::find_definition(&src, &fpath, pos, &session).map(|m| match_fn(m, &session));
    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>Wrapped complete in a thread to catch panics<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, session: core::SessionRef) {
    let (linenum, charnum) = scopes::point_to_coords_from_file(&m.filepath, m.point, session).unwrap();
    if m.matchstr == "" {
        panic!("MATCHSTR is empty - waddup?");
    }

    let snippet = racer::snippets::snippet_for_match(&m, session);
    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, session: core::SessionRef) {
    if let Some((linenum, charnum)) = scopes::point_to_coords_from_file(&m.filepath,
                                                                        m.point,
                                                                        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(args: Vec<String>, print_type: CompletePrinter) {
    if args.len() < 1 {
        println!("Provide more arguments!");
        print_usage();
        std::process::exit(1);
    }
    match args[0].parse::<usize>() {
        Ok(linenum) => {
            complete_by_line_coords(args, linenum, print_type);
        }
        Err(_) => {
            external_complete(&args);
        }
    }
}

#[cfg(not(test))]
fn complete_by_line_coords(args: Vec<String>,
                           linenum: usize,
                           print_type: CompletePrinter) {
    // input: linenum, colnum, fname
    let tb = std::thread::Builder::new().name("searcher".to_string());

    // PD: this probably sucks for performance, but lots of plugins
    // end up failing and leaving tmp files around if racer crashes,
    // so catch the crash.
    let res = tb.spawn(move || {
        run_the_complete_fn(args, linenum, print_type);
    }).unwrap();
    match res.join() {
        Ok(_) => {},
        Err(e) => {
            error!("Search thread paniced: {:?}", e);
        }
    }

    println!("END");

}

#[cfg(not(test))]
enum CompletePrinter {
    Normal,
    WithSnippets
}

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

    let fpath = Path::new(fname);
    let session = core::Session::from_path(&fpath, &substitute_file);
    let src = session.load_file(&fpath);
    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 print_type {
            CompletePrinter::Normal => match_fn(m, &session),
            CompletePrinter::WithSnippets => match_with_snippet_fn(m, &session),
        };
    }
}

#[cfg(not(test))]
fn external_complete(args: &[String]) {
    // input: a command line string passed in
    let arg = &args[0];
    let it = arg.split("::");
    let p: Vec<&str> = it.collect();
    let session = core::Session::from_path(&Path::new("."), &Path::new("."));

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

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

    core::find_definition(&src, &fpath, pos, &session).map(|m| match_fn(m, &session));
    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 mut args: Vec<String> = std::env::args().collect();

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

    args.remove(0);
    run(args);
}

#[cfg(not(test))]
fn run(mut args: Vec<String>) {
    //let command  = &args[0];
    let command = args.remove(0);
    match &command[..] {
        "daemon" => daemon(),
        "prefix" => prefix(&args),
        "complete" => complete(args, CompletePrinter::Normal),
        "complete-with-snippet" => complete(args, CompletePrinter::WithSnippets),
        "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>//! The internal representation of a book and infrastructure for loading it from
//! disk and building it.
//!
//! For examples on using `MDBook`, consult the [top-level documentation][1].
//!
//! [1]: ../index.html

#![deny(missing_docs)]

mod summary;
mod book;
mod init;

pub use self::book::{load_book, Book, BookItem, BookItems, Chapter};
pub use self::summary::{parse_summary, Link, SectionNumber, Summary, SummaryItem};
pub use self::init::BookBuilder;

use std::path::PathBuf;
use std::io::Write;
use std::process::Command;
use tempdir::TempDir;
use toml::Value;

use utils;
use renderer::{CmdRenderer, HtmlHandlebars, RenderContext, Renderer};
use preprocess::{Preprocessor, LinkPreprocessor, PreprocessorContext};
use errors::*;

use config::Config;

/// The object used to manage and build a book.
pub struct MDBook {
    /// The book's root directory.
    pub root: PathBuf,
    /// The configuration used to tweak now a book is built.
    pub config: Config,
    /// A representation of the book's contents in memory.
    pub book: Book,
    renderers: Vec<Box<Renderer>>,

    /// The URL used for live reloading when serving up the book.
    pub livereload: Option<String>,

    /// List of pre-processors to be run on the book
    preprocessors: Vec<Box<Preprocessor>>
}

impl MDBook {
    /// Load a book from its root directory on disk.
    pub fn load<P: Into<PathBuf>>(book_root: P) -> Result<MDBook> {
        let book_root = book_root.into();
        let config_location = book_root.join("book.toml");

        // the book.json file is no longer used, so we should emit a warning to
        // let people know to migrate to book.toml
        if book_root.join("book.json").exists() {
            warn!("It appears you are still using book.json for configuration.");
            warn!("This format is no longer used, so you should migrate to the");
            warn!("book.toml format.");
            warn!("Check the user guide for migration information:");
            warn!("\thttps://rust-lang-nursery.github.io/mdBook/format/config.html");
        }

        let mut config = if config_location.exists() {
            debug!("[*] Loading config from {}", config_location.display());
            Config::from_disk(&config_location)?
        } else {
            Config::default()
        };

        config.update_from_env();

        if log_enabled!(::log::Level::Trace) {
            for line in format!("Config: {:#?}", config).lines() {
                trace!("{}", line);
            }
        }

        MDBook::load_with_config(book_root, config)
    }

    /// Load a book from its root directory using a custom config.
    pub fn load_with_config<P: Into<PathBuf>>(book_root: P, config: Config) -> Result<MDBook> {
        let root = book_root.into();

        let src_dir = root.join(&config.book.src);
        let book = book::load_book(&src_dir, &config.build)?;
        let livereload = None;

        let renderers = determine_renderers(&config);
        let preprocessors = determine_preprocessors(&config)?;

        Ok(MDBook {
            root,
            config,
            book,
            renderers,
            livereload,
            preprocessors,
        })
    }

    /// Returns a flat depth-first iterator over the elements of the book,
    /// it returns an [BookItem enum](bookitem.html):
    /// `(section: String, bookitem: &BookItem)`
    ///
    /// ```no_run
    /// # extern crate mdbook;
    /// # use mdbook::MDBook;
    /// # use mdbook::book::BookItem;
    /// # #[allow(unused_variables)]
    /// # fn main() {
    /// # let book = MDBook::load("mybook").unwrap();
    /// for item in book.iter() {
    ///     match *item {
    ///         BookItem::Chapter(ref chapter) => {},
    ///         BookItem::Separator => {},
    ///     }
    /// }
    ///
    /// // would print something like this:
    /// // 1. Chapter 1
    /// // 1.1 Sub Chapter
    /// // 1.2 Sub Chapter
    /// // 2. Chapter 2
    /// //
    /// // etc.
    /// # }
    /// ```
    pub fn iter(&self) -> BookItems {
        self.book.iter()
    }

    /// `init()` gives you a `BookBuilder` which you can use to setup a new book
    /// and its accompanying directory structure.
    ///
    /// The `BookBuilder` creates some boilerplate files and directories to get
    /// you started with your book.
    ///
    /// ```text
    /// book-test/
    /// ├── book
    /// └── src
    ///     ├── chapter_1.md
    ///     └── SUMMARY.md
    /// ```
    ///
    /// It uses the path provided as the root directory for your book, then adds
    /// in a `src/` directory containing a `SUMMARY.md` and `chapter_1.md` file
    /// to get you started.
    pub fn init<P: Into<PathBuf>>(book_root: P) -> BookBuilder {
        BookBuilder::new(book_root)
    }

    /// Tells the renderer to build our book and put it in the build directory.
    pub fn build(&self) -> Result<()> {
        debug!("[fn]: build");

        let mut preprocessed_book = self.book.clone();
        let preprocess_ctx = PreprocessorContext::new(self.root.clone(), self.config.clone());

        for preprocessor in &self.preprocessors {
            preprocessor.run(&preprocess_ctx, &mut preprocessed_book)?;
        }

        for renderer in &self.renderers {
            self.run_renderer(&preprocessed_book, renderer.as_ref())?;
        }

        Ok(())
    }

    fn run_renderer(&self, preprocessed_book: &Book, renderer: &Renderer) -> Result<()> {
        let name = renderer.name();
        let build_dir = self.build_dir_for(name);
        if build_dir.exists() {
            debug!(
                "Cleaning build dir for the \"{}\" renderer ({})",
                name,
                build_dir.display()
            );

            utils::fs::remove_dir_content(&build_dir)
                .chain_err(|| "Unable to clear output directory")?;
        }

        let render_context = RenderContext::new(
            self.root.clone(),
            preprocessed_book.clone(),
            self.config.clone(),
            build_dir,
        );

        renderer
            .render(&render_context)
            .chain_err(|| "Rendering failed")
    }

    /// You can change the default renderer to another one by using this method.
    /// The only requirement is for your renderer to implement the [`Renderer`
    /// trait](../renderer/trait.Renderer.html)
    pub fn with_renderer<R: Renderer + 'static>(&mut self, renderer: R) -> &mut Self {
        self.renderers.push(Box::new(renderer));
        self
    }

    /// Register a [`Preprocessor`](../preprocess/trait.Preprocessor.html) to be used when rendering the book.
    pub fn with_preprecessor<P: Preprocessor + 'static>(&mut self, preprocessor: P) -> &mut Self {
        self.preprocessors.push(Box::new(preprocessor));
        self
    }

    /// Run `rustdoc` tests on the book, linking against the provided libraries.
    pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
        let library_args: Vec<&str> = (0..library_paths.len())
            .map(|_| "-L")
            .zip(library_paths.into_iter())
            .flat_map(|x| vec![x.0, x.1])
            .collect();

        let temp_dir = TempDir::new("mdbook")?;

        let preprocess_context = PreprocessorContext::new(self.root.clone(), self.config.clone());

        LinkPreprocessor::new().run(&preprocess_context, &mut self.book)?;

        for item in self.iter() {
            if let BookItem::Chapter(ref ch) = *item {
                if !ch.path.as_os_str().is_empty() {
                    let path = self.source_dir().join(&ch.path);
                    let content = utils::fs::file_to_string(&path)?;
                    println!("[*]: Testing file: {:?}", path);

                    // write preprocessed file to tempdir
                    let path = temp_dir.path().join(&ch.path);
                    let mut tmpf = utils::fs::create_file(&path)?;
                    tmpf.write_all(content.as_bytes())?;

                    let output = Command::new("rustdoc")
                        .arg(&path)
                        .arg("--test")
                        .args(&library_args)
                        .output()?;

                    if !output.status.success() {
                        bail!(ErrorKind::Subprocess(
                            "Rustdoc returned an error".to_string(),
                            output
                        ));
                    }
                }
            }
        }
        Ok(())
    }

    /// The logic for determining where a backend should put its build
    /// artefacts.
    ///
    /// If there is only 1 renderer, put it in the directory pointed to by the
    /// `build.build_dir` key in `Config`. If there is more than one then the
    /// renderer gets its own directory within the main build dir.
    ///
    /// i.e. If there were only one renderer (in this case, the HTML renderer):
    ///
    /// - build/
    ///   - index.html
    ///   - ...
    ///
    /// Otherwise if there are multiple:
    ///
    /// - build/
    ///   - epub/
    ///     - my_awesome_book.epub
    ///   - html/
    ///     - index.html
    ///     - ...
    ///   - latex/
    ///     - my_awesome_book.tex
    ///
    pub fn build_dir_for(&self, backend_name: &str) -> PathBuf {
        let build_dir = self.root.join(&self.config.build.build_dir);

        if self.renderers.len() <= 1 {
            build_dir
        } else {
            build_dir.join(backend_name)
        }
    }

    /// Get the directory containing this book's source files.
    pub fn source_dir(&self) -> PathBuf {
        self.root.join(&self.config.book.src)
    }

    // FIXME: This really belongs as part of the `HtmlConfig`.
    #[doc(hidden)]
    pub fn theme_dir(&self) -> PathBuf {
        match self.config.html_config().and_then(|h| h.theme) {
            Some(d) => self.root.join(d),
            None => self.root.join("theme"),
        }
    }
}

/// Look at the `Config` and try to figure out what renderers to use.
fn determine_renderers(config: &Config) -> Vec<Box<Renderer>> {
    let mut renderers: Vec<Box<Renderer>> = Vec::new();

    if let Some(output_table) = config.get("output").and_then(|o| o.as_table()) {
        for (key, table) in output_table.iter() {
            // the "html" backend has its own Renderer
            if key == "html" {
                renderers.push(Box::new(HtmlHandlebars::new()));
            } else {
                let renderer = interpret_custom_renderer(key, table);
                renderers.push(renderer);
            }
        }
    }

    // if we couldn't find anything, add the HTML renderer as a default
    if renderers.is_empty() {
        renderers.push(Box::new(HtmlHandlebars::new()));
    }

    renderers
}

fn default_preprocessors() -> Vec<Box<Preprocessor>> {
    vec![Box::new(LinkPreprocessor::new())]
}

/// Look at the `MDBook` and try to figure out what preprocessors to run.
fn determine_preprocessors(config: &Config) -> Result<Vec<Box<Preprocessor>>> {

    let preprocess_list = match config.build.preprocess {
        Some(ref p) => p,
        // If no preprocessor field is set, default to the LinkPreprocessor. This allows you
        // to disable the LinkPreprocessor by setting "preprocess" to an empty list.
        None => return Ok(default_preprocessors())
    };

    let mut preprocessors: Vec<Box<Preprocessor>> = Vec::new();

    for key in preprocess_list {
        match key.as_ref() {
            "links" => {
                preprocessors.push(Box::new(LinkPreprocessor::new()))
            }
            _ =>  bail!("{:?} is not a recognised preprocessor", key),
        }
    }

    Ok(preprocessors)
}

fn interpret_custom_renderer(key: &str, table: &Value) -> Box<Renderer> {
    // look for the `command` field, falling back to using the key
    // prepended by "mdbook-"
    let table_dot_command = table
        .get("command")
        .and_then(|c| c.as_str())
        .map(|s| s.to_string());

    let command = table_dot_command.unwrap_or_else(|| format!("mdbook-{}", key));

    Box::new(CmdRenderer::new(key.to_string(), command.to_string()))
}

#[cfg(test)]
mod tests {
    use super::*;
    use toml::value::{Table, Value};

    #[test]
    fn config_defaults_to_html_renderer_if_empty() {
        let cfg = Config::default();

        // make sure we haven't got anything in the `output` table
        assert!(cfg.get("output").is_none());

        let got = determine_renderers(&cfg);

        assert_eq!(got.len(), 1);
        assert_eq!(got[0].name(), "html");
    }

    #[test]
    fn add_a_random_renderer_to_the_config() {
        let mut cfg = Config::default();
        cfg.set("output.random", Table::new()).unwrap();

        let got = determine_renderers(&cfg);

        assert_eq!(got.len(), 1);
        assert_eq!(got[0].name(), "random");
    }

    #[test]
    fn add_a_random_renderer_with_custom_command_to_the_config() {
        let mut cfg = Config::default();

        let mut table = Table::new();
        table.insert("command".to_string(), Value::String("false".to_string()));
        cfg.set("output.random", table).unwrap();

        let got = determine_renderers(&cfg);

        assert_eq!(got.len(), 1);
        assert_eq!(got[0].name(), "random");
    }

    #[test]
    fn config_defaults_to_link_preprocessor_if_not_set() {
        let cfg = Config::default();

        // make sure we haven't got anything in the `output` table
        assert!(cfg.build.preprocess.is_none());

        let got = determine_preprocessors(&cfg);

        assert!(got.is_ok());
        assert_eq!(got.as_ref().unwrap().len(), 1);
        assert_eq!(got.as_ref().unwrap()[0].name(), "links");
    }

    #[test]
    fn config_doesnt_default_if_empty() {
        let cfg_str: &'static str = r#"
        [book]
        title = "Some Book"

        [build]
        build-dir = "outputs"
        create-missing = false
        preprocess = []
        "#;

        let cfg = Config::from_str(cfg_str).unwrap();

        // make sure we have something in the `output` table
        assert!(cfg.build.preprocess.is_some());

        let got = determine_preprocessors(&cfg);

        assert!(got.is_ok());
        assert!(got.unwrap().is_empty());
    }

    #[test]
    fn config_complains_if_unimplemented_preprocessor() {
        let cfg_str: &'static str = r#"
        [book]
        title = "Some Book"

        [build]
        build-dir = "outputs"
        create-missing = false
        preprocess = ["random"]
        "#;

        let cfg = Config::from_str(cfg_str).unwrap();

        // make sure we have something in the `output` table
        assert!(cfg.build.preprocess.is_some());

        let got = determine_preprocessors(&cfg);

        assert!(got.is_err());
    }
}
<commit_msg>Log as each preprocessor is run<commit_after>//! The internal representation of a book and infrastructure for loading it from
//! disk and building it.
//!
//! For examples on using `MDBook`, consult the [top-level documentation][1].
//!
//! [1]: ../index.html

#![deny(missing_docs)]

mod summary;
mod book;
mod init;

pub use self::book::{load_book, Book, BookItem, BookItems, Chapter};
pub use self::summary::{parse_summary, Link, SectionNumber, Summary, SummaryItem};
pub use self::init::BookBuilder;

use std::path::PathBuf;
use std::io::Write;
use std::process::Command;
use tempdir::TempDir;
use toml::Value;

use utils;
use renderer::{CmdRenderer, HtmlHandlebars, RenderContext, Renderer};
use preprocess::{Preprocessor, LinkPreprocessor, PreprocessorContext};
use errors::*;

use config::Config;

/// The object used to manage and build a book.
pub struct MDBook {
    /// The book's root directory.
    pub root: PathBuf,
    /// The configuration used to tweak now a book is built.
    pub config: Config,
    /// A representation of the book's contents in memory.
    pub book: Book,
    renderers: Vec<Box<Renderer>>,

    /// The URL used for live reloading when serving up the book.
    pub livereload: Option<String>,

    /// List of pre-processors to be run on the book
    preprocessors: Vec<Box<Preprocessor>>
}

impl MDBook {
    /// Load a book from its root directory on disk.
    pub fn load<P: Into<PathBuf>>(book_root: P) -> Result<MDBook> {
        let book_root = book_root.into();
        let config_location = book_root.join("book.toml");

        // the book.json file is no longer used, so we should emit a warning to
        // let people know to migrate to book.toml
        if book_root.join("book.json").exists() {
            warn!("It appears you are still using book.json for configuration.");
            warn!("This format is no longer used, so you should migrate to the");
            warn!("book.toml format.");
            warn!("Check the user guide for migration information:");
            warn!("\thttps://rust-lang-nursery.github.io/mdBook/format/config.html");
        }

        let mut config = if config_location.exists() {
            debug!("[*] Loading config from {}", config_location.display());
            Config::from_disk(&config_location)?
        } else {
            Config::default()
        };

        config.update_from_env();

        if log_enabled!(::log::Level::Trace) {
            for line in format!("Config: {:#?}", config).lines() {
                trace!("{}", line);
            }
        }

        MDBook::load_with_config(book_root, config)
    }

    /// Load a book from its root directory using a custom config.
    pub fn load_with_config<P: Into<PathBuf>>(book_root: P, config: Config) -> Result<MDBook> {
        let root = book_root.into();

        let src_dir = root.join(&config.book.src);
        let book = book::load_book(&src_dir, &config.build)?;
        let livereload = None;

        let renderers = determine_renderers(&config);
        let preprocessors = determine_preprocessors(&config)?;

        Ok(MDBook {
            root,
            config,
            book,
            renderers,
            livereload,
            preprocessors,
        })
    }

    /// Returns a flat depth-first iterator over the elements of the book,
    /// it returns an [BookItem enum](bookitem.html):
    /// `(section: String, bookitem: &BookItem)`
    ///
    /// ```no_run
    /// # extern crate mdbook;
    /// # use mdbook::MDBook;
    /// # use mdbook::book::BookItem;
    /// # #[allow(unused_variables)]
    /// # fn main() {
    /// # let book = MDBook::load("mybook").unwrap();
    /// for item in book.iter() {
    ///     match *item {
    ///         BookItem::Chapter(ref chapter) => {},
    ///         BookItem::Separator => {},
    ///     }
    /// }
    ///
    /// // would print something like this:
    /// // 1. Chapter 1
    /// // 1.1 Sub Chapter
    /// // 1.2 Sub Chapter
    /// // 2. Chapter 2
    /// //
    /// // etc.
    /// # }
    /// ```
    pub fn iter(&self) -> BookItems {
        self.book.iter()
    }

    /// `init()` gives you a `BookBuilder` which you can use to setup a new book
    /// and its accompanying directory structure.
    ///
    /// The `BookBuilder` creates some boilerplate files and directories to get
    /// you started with your book.
    ///
    /// ```text
    /// book-test/
    /// ├── book
    /// └── src
    ///     ├── chapter_1.md
    ///     └── SUMMARY.md
    /// ```
    ///
    /// It uses the path provided as the root directory for your book, then adds
    /// in a `src/` directory containing a `SUMMARY.md` and `chapter_1.md` file
    /// to get you started.
    pub fn init<P: Into<PathBuf>>(book_root: P) -> BookBuilder {
        BookBuilder::new(book_root)
    }

    /// Tells the renderer to build our book and put it in the build directory.
    pub fn build(&self) -> Result<()> {
        debug!("[fn]: build");

        let mut preprocessed_book = self.book.clone();
        let preprocess_ctx = PreprocessorContext::new(self.root.clone(), self.config.clone());

        for preprocessor in &self.preprocessors {
            debug!("Running the {} preprocessor.", preprocessor.name());
            preprocessor.run(&preprocess_ctx, &mut preprocessed_book)?;
        }

        for renderer in &self.renderers {
            self.run_renderer(&preprocessed_book, renderer.as_ref())?;
        }

        Ok(())
    }

    fn run_renderer(&self, preprocessed_book: &Book, renderer: &Renderer) -> Result<()> {
        let name = renderer.name();
        let build_dir = self.build_dir_for(name);
        if build_dir.exists() {
            debug!(
                "Cleaning build dir for the \"{}\" renderer ({})",
                name,
                build_dir.display()
            );

            utils::fs::remove_dir_content(&build_dir)
                .chain_err(|| "Unable to clear output directory")?;
        }

        let render_context = RenderContext::new(
            self.root.clone(),
            preprocessed_book.clone(),
            self.config.clone(),
            build_dir,
        );

        renderer
            .render(&render_context)
            .chain_err(|| "Rendering failed")
    }

    /// You can change the default renderer to another one by using this method.
    /// The only requirement is for your renderer to implement the [`Renderer`
    /// trait](../renderer/trait.Renderer.html)
    pub fn with_renderer<R: Renderer + 'static>(&mut self, renderer: R) -> &mut Self {
        self.renderers.push(Box::new(renderer));
        self
    }

    /// Register a [`Preprocessor`](../preprocess/trait.Preprocessor.html) to be used when rendering the book.
    pub fn with_preprecessor<P: Preprocessor + 'static>(&mut self, preprocessor: P) -> &mut Self {
        self.preprocessors.push(Box::new(preprocessor));
        self
    }

    /// Run `rustdoc` tests on the book, linking against the provided libraries.
    pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
        let library_args: Vec<&str> = (0..library_paths.len())
            .map(|_| "-L")
            .zip(library_paths.into_iter())
            .flat_map(|x| vec![x.0, x.1])
            .collect();

        let temp_dir = TempDir::new("mdbook")?;

        let preprocess_context = PreprocessorContext::new(self.root.clone(), self.config.clone());

        LinkPreprocessor::new().run(&preprocess_context, &mut self.book)?;

        for item in self.iter() {
            if let BookItem::Chapter(ref ch) = *item {
                if !ch.path.as_os_str().is_empty() {
                    let path = self.source_dir().join(&ch.path);
                    let content = utils::fs::file_to_string(&path)?;
                    println!("[*]: Testing file: {:?}", path);

                    // write preprocessed file to tempdir
                    let path = temp_dir.path().join(&ch.path);
                    let mut tmpf = utils::fs::create_file(&path)?;
                    tmpf.write_all(content.as_bytes())?;

                    let output = Command::new("rustdoc")
                        .arg(&path)
                        .arg("--test")
                        .args(&library_args)
                        .output()?;

                    if !output.status.success() {
                        bail!(ErrorKind::Subprocess(
                            "Rustdoc returned an error".to_string(),
                            output
                        ));
                    }
                }
            }
        }
        Ok(())
    }

    /// The logic for determining where a backend should put its build
    /// artefacts.
    ///
    /// If there is only 1 renderer, put it in the directory pointed to by the
    /// `build.build_dir` key in `Config`. If there is more than one then the
    /// renderer gets its own directory within the main build dir.
    ///
    /// i.e. If there were only one renderer (in this case, the HTML renderer):
    ///
    /// - build/
    ///   - index.html
    ///   - ...
    ///
    /// Otherwise if there are multiple:
    ///
    /// - build/
    ///   - epub/
    ///     - my_awesome_book.epub
    ///   - html/
    ///     - index.html
    ///     - ...
    ///   - latex/
    ///     - my_awesome_book.tex
    ///
    pub fn build_dir_for(&self, backend_name: &str) -> PathBuf {
        let build_dir = self.root.join(&self.config.build.build_dir);

        if self.renderers.len() <= 1 {
            build_dir
        } else {
            build_dir.join(backend_name)
        }
    }

    /// Get the directory containing this book's source files.
    pub fn source_dir(&self) -> PathBuf {
        self.root.join(&self.config.book.src)
    }

    // FIXME: This really belongs as part of the `HtmlConfig`.
    #[doc(hidden)]
    pub fn theme_dir(&self) -> PathBuf {
        match self.config.html_config().and_then(|h| h.theme) {
            Some(d) => self.root.join(d),
            None => self.root.join("theme"),
        }
    }
}

/// Look at the `Config` and try to figure out what renderers to use.
fn determine_renderers(config: &Config) -> Vec<Box<Renderer>> {
    let mut renderers: Vec<Box<Renderer>> = Vec::new();

    if let Some(output_table) = config.get("output").and_then(|o| o.as_table()) {
        for (key, table) in output_table.iter() {
            // the "html" backend has its own Renderer
            if key == "html" {
                renderers.push(Box::new(HtmlHandlebars::new()));
            } else {
                let renderer = interpret_custom_renderer(key, table);
                renderers.push(renderer);
            }
        }
    }

    // if we couldn't find anything, add the HTML renderer as a default
    if renderers.is_empty() {
        renderers.push(Box::new(HtmlHandlebars::new()));
    }

    renderers
}

fn default_preprocessors() -> Vec<Box<Preprocessor>> {
    vec![Box::new(LinkPreprocessor::new())]
}

/// Look at the `MDBook` and try to figure out what preprocessors to run.
fn determine_preprocessors(config: &Config) -> Result<Vec<Box<Preprocessor>>> {

    let preprocess_list = match config.build.preprocess {
        Some(ref p) => p,
        // If no preprocessor field is set, default to the LinkPreprocessor. This allows you
        // to disable the LinkPreprocessor by setting "preprocess" to an empty list.
        None => return Ok(default_preprocessors())
    };

    let mut preprocessors: Vec<Box<Preprocessor>> = Vec::new();

    for key in preprocess_list {
        match key.as_ref() {
            "links" => {
                preprocessors.push(Box::new(LinkPreprocessor::new()))
            }
            _ =>  bail!("{:?} is not a recognised preprocessor", key),
        }
    }

    Ok(preprocessors)
}

fn interpret_custom_renderer(key: &str, table: &Value) -> Box<Renderer> {
    // look for the `command` field, falling back to using the key
    // prepended by "mdbook-"
    let table_dot_command = table
        .get("command")
        .and_then(|c| c.as_str())
        .map(|s| s.to_string());

    let command = table_dot_command.unwrap_or_else(|| format!("mdbook-{}", key));

    Box::new(CmdRenderer::new(key.to_string(), command.to_string()))
}

#[cfg(test)]
mod tests {
    use super::*;
    use toml::value::{Table, Value};

    #[test]
    fn config_defaults_to_html_renderer_if_empty() {
        let cfg = Config::default();

        // make sure we haven't got anything in the `output` table
        assert!(cfg.get("output").is_none());

        let got = determine_renderers(&cfg);

        assert_eq!(got.len(), 1);
        assert_eq!(got[0].name(), "html");
    }

    #[test]
    fn add_a_random_renderer_to_the_config() {
        let mut cfg = Config::default();
        cfg.set("output.random", Table::new()).unwrap();

        let got = determine_renderers(&cfg);

        assert_eq!(got.len(), 1);
        assert_eq!(got[0].name(), "random");
    }

    #[test]
    fn add_a_random_renderer_with_custom_command_to_the_config() {
        let mut cfg = Config::default();

        let mut table = Table::new();
        table.insert("command".to_string(), Value::String("false".to_string()));
        cfg.set("output.random", table).unwrap();

        let got = determine_renderers(&cfg);

        assert_eq!(got.len(), 1);
        assert_eq!(got[0].name(), "random");
    }

    #[test]
    fn config_defaults_to_link_preprocessor_if_not_set() {
        let cfg = Config::default();

        // make sure we haven't got anything in the `output` table
        assert!(cfg.build.preprocess.is_none());

        let got = determine_preprocessors(&cfg);

        assert!(got.is_ok());
        assert_eq!(got.as_ref().unwrap().len(), 1);
        assert_eq!(got.as_ref().unwrap()[0].name(), "links");
    }

    #[test]
    fn config_doesnt_default_if_empty() {
        let cfg_str: &'static str = r#"
        [book]
        title = "Some Book"

        [build]
        build-dir = "outputs"
        create-missing = false
        preprocess = []
        "#;

        let cfg = Config::from_str(cfg_str).unwrap();

        // make sure we have something in the `output` table
        assert!(cfg.build.preprocess.is_some());

        let got = determine_preprocessors(&cfg);

        assert!(got.is_ok());
        assert!(got.unwrap().is_empty());
    }

    #[test]
    fn config_complains_if_unimplemented_preprocessor() {
        let cfg_str: &'static str = r#"
        [book]
        title = "Some Book"

        [build]
        build-dir = "outputs"
        create-missing = false
        preprocess = ["random"]
        "#;

        let cfg = Config::from_str(cfg_str).unwrap();

        // make sure we have something in the `output` table
        assert!(cfg.build.preprocess.is_some());

        let got = determine_preprocessors(&cfg);

        assert!(got.is_err());
    }
}
<|endoftext|>


<commit_before>//! Merges the contents of multiple streams.

use crate::Data;
use crate::dataflow::channels::pact::Pipeline;
use crate::dataflow::{Stream, Scope};

/// Merge the contents of two streams.
pub trait Concat<G: Scope, D: Data> {
    /// Merge the contents of two streams.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Concat, Inspect};
    ///
    /// timely::example(|scope| {
    ///
    ///     let stream = (0..10).to_stream(scope);
    ///     stream.concat(&stream)
    ///           .inspect(|x| println!("seen: {:?}", x));
    /// });
    /// ```
    fn concat(&self, _: &Stream<G, D>) -> Stream<G, D>;
}

impl<G: Scope, D: Data> Concat<G, D> for Stream<G, D> {
    fn concat(&self, other: &Stream<G, D>) -> Stream<G, D> {
        self.scope().concatenate(vec![self.clone(), other.clone()])
    }
}

/// Merge the contents of multiple streams.
pub trait Concatenate<G: Scope, D: Data> {
    /// Merge the contents of multiple streams.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Concatenate, Inspect};
    ///
    /// timely::example(|scope| {
    ///
    ///     let streams = vec![(0..10).to_stream(scope),
    ///                        (0..10).to_stream(scope),
    ///                        (0..10).to_stream(scope)];
    ///
    ///     scope.concatenate(streams)
    ///          .inspect(|x| println!("seen: {:?}", x));
    /// });
    /// ```
    fn concatenate(&self, _: impl IntoIterator<Item=Stream<G, D>>) -> Stream<G, D>;
}

impl<G: Scope, D: Data> Concatenate<G, D> for G {
    fn concatenate(&self, sources: impl IntoIterator<Item=Stream<G, D>>) -> Stream<G, D> {

        // create an operator builder.
        use crate::dataflow::operators::generic::builder_rc::OperatorBuilder;
        let mut builder = OperatorBuilder::new("Concatenate".to_string(), self.clone());

        // create new input handles for each input stream.
        let mut handles = sources.into_iter().map(|s| builder.new_input(&s, Pipeline)).collect::<Vec<_>>();

        // create one output handle for the concatenated results.
        let (mut output, result) = builder.new_output();

        // build an operator that plays out all input data.
        builder.build(move |_capability| {

            let mut vector = Vec::new();
            move |_frontier| {
                let mut output = output.activate();
                for handle in handles.iter_mut() {
                    handle.for_each(|time, data| {
                        data.swap(&mut vector);
                        output.session(&time).give_vec(&mut vector);
                    })
                }
            }
        });

        result
    }
}
<commit_msg>add Concatenate for streams<commit_after>//! Merges the contents of multiple streams.

use crate::Data;
use crate::dataflow::channels::pact::Pipeline;
use crate::dataflow::{Stream, Scope};

/// Merge the contents of two streams.
pub trait Concat<G: Scope, D: Data> {
    /// Merge the contents of two streams.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Concat, Inspect};
    ///
    /// timely::example(|scope| {
    ///
    ///     let stream = (0..10).to_stream(scope);
    ///     stream.concat(&stream)
    ///           .inspect(|x| println!("seen: {:?}", x));
    /// });
    /// ```
    fn concat(&self, _: &Stream<G, D>) -> Stream<G, D>;
}

impl<G: Scope, D: Data> Concat<G, D> for Stream<G, D> {
    fn concat(&self, other: &Stream<G, D>) -> Stream<G, D> {
        self.scope().concatenate(vec![self.clone(), other.clone()])
    }
}

/// Merge the contents of multiple streams.
pub trait Concatenate<G: Scope, D: Data> {
    /// Merge the contents of multiple streams.
    ///
    /// # Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Concatenate, Inspect};
    ///
    /// timely::example(|scope| {
    ///
    ///     let streams = vec![(0..10).to_stream(scope),
    ///                        (0..10).to_stream(scope),
    ///                        (0..10).to_stream(scope)];
    ///
    ///     scope.concatenate(streams)
    ///          .inspect(|x| println!("seen: {:?}", x));
    /// });
    /// ```
    fn concatenate<I>(&self, sources: I) -> Stream<G, D>
    where
        I: IntoIterator<Item=Stream<G, D>>;
}

impl<G: Scope, D: Data> Concatenate<G, D> for Stream<G, D> {
    fn concatenate<I>(&self, sources: I) -> Stream<G, D>
    where
        I: IntoIterator<Item=Stream<G, D>>
    {
        let clone = self.clone();
        self.scope().concatenate(Some(clone).into_iter().chain(sources))
    }
}

impl<G: Scope, D: Data> Concatenate<G, D> for G {
    fn concatenate<I>(&self, sources: I) -> Stream<G, D>
    where
        I: IntoIterator<Item=Stream<G, D>>
    {

        // create an operator builder.
        use crate::dataflow::operators::generic::builder_rc::OperatorBuilder;
        let mut builder = OperatorBuilder::new("Concatenate".to_string(), self.clone());

        // create new input handles for each input stream.
        let mut handles = sources.into_iter().map(|s| builder.new_input(&s, Pipeline)).collect::<Vec<_>>();

        // create one output handle for the concatenated results.
        let (mut output, result) = builder.new_output();

        // build an operator that plays out all input data.
        builder.build(move |_capability| {

            let mut vector = Vec::new();
            move |_frontier| {
                let mut output = output.activate();
                for handle in handles.iter_mut() {
                    handle.for_each(|time, data| {
                        data.swap(&mut vector);
                        output.session(&time).give_vec(&mut vector);
                    })
                }
            }
        });

        result
    }
}
<|endoftext|>


<commit_before>//! Procedurally generating the game world.
//!

/// Main type to generate the game world. Implements the `WorldProvider` trait
/// (TODO, see #8).
pub struct WorldGenerator {
    seed: u64,
}

impl WorldGenerator {
    /// Creates the generator with the given seed.
    pub fn with_seed(seed: u64) -> Self {
        WorldGenerator { seed: seed }
    }

    /// Returns the seed of this world generator.
    pub fn seed(&self) -> u64 {
        self.seed
    }
}
<commit_msg>implement Provider for WorldGenerator<commit_after>//! Procedurally generating the game world.
//!

use super::super::world::{Chunk, ChunkIndex, Provider};

/// Main type to generate the game world. Implements the `WorldProvider` trait
/// (TODO, see #8).
pub struct WorldGenerator {
    seed: u64,
}

impl WorldGenerator {
    /// Creates the generator with the given seed.
    pub fn with_seed(seed: u64) -> Self {
        WorldGenerator { seed: seed }
    }

    /// Returns the seed of this world generator.
    pub fn seed(&self) -> u64 {
        self.seed
    }
}

impl Provider for WorldGenerator {
    /// Returns requested `Chunk`.
    fn load_chunk(&self, _: ChunkIndex) -> Option<Chunk> {
        // for the moment returns dummy chunk
        Some(Chunk::dummy())
    }

    /// Returns wether `Chunk` load is possible
    fn is_chunk_loadable(&self, _: ChunkIndex) -> bool {
        // for the moment returns true
        true
    }
}
<|endoftext|>


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

use super::super::general::write_vec;

pub fn begin<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#![allow(non_camel_case_types)]",
"#![allow(dead_code)]",
"",
"extern crate libc;",
"#[macro_use] extern crate bitflags;",
    ];

    write_vec(w, &v)
}

pub fn after_extern_crates<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[allow(unused_imports)]",
"use libc::{c_int, c_char, c_float, c_uint, c_double,",
"    c_short, c_ushort, c_long, c_ulong,",
"    c_void, size_t, ssize_t, time_t};",
    ];

    write_vec(w, &v)
}

pub fn use_glib_ffi<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[allow(unused_imports)]",
"use glib_ffi::{gboolean, gconstpointer, gpointer};",
    ];

    write_vec(w, &v)
}

pub fn only_for_glib<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"pub type gboolean = c_int;",
"pub const GFALSE:  c_int = 0;",
"pub const GTRUE:   c_int = 1;",
"",
"pub type gconstpointer = *const c_void;",
"pub type gpointer = *mut c_void;",
    ];

    write_vec(w, &v)
}

pub fn only_for_gtk<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"pub const GTK_ENTRY_BUFFER_MAX_SIZE: u16 = ::std::u16::MAX;",
"",
"//pub type GtkTreeModelForeachFunc = fn(model: *mut GtkTreeModel, path: *mut GtkTreePath, iter: *mut GtkTreeIter, data: gpointer) -> gboolean;",
"",
"pub const GTK_STYLE_PROVIDER_PRIORITY_FALLBACK: u32 = 1;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_THEME: u32 = 200;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_SETTINGS: u32 = 400;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_APPLICATION: u32 = 600;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_USER: u32 = 800;",
    ];

    write_vec(w, &v)
}
<commit_msg>sys: Enable dead_code lints<commit_after>use std::io::{Result, Write};

use super::super::general::write_vec;

pub fn begin<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#![allow(non_camel_case_types)]",
"",
"extern crate libc;",
"#[macro_use] extern crate bitflags;",
    ];

    write_vec(w, &v)
}

pub fn after_extern_crates<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[allow(unused_imports)]",
"use libc::{c_int, c_char, c_float, c_uint, c_double,",
"    c_short, c_ushort, c_long, c_ulong,",
"    c_void, size_t, ssize_t, time_t};",
    ];

    write_vec(w, &v)
}

pub fn use_glib_ffi<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"#[allow(unused_imports)]",
"use glib_ffi::{gboolean, gconstpointer, gpointer};",
    ];

    write_vec(w, &v)
}

pub fn only_for_glib<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"pub type gboolean = c_int;",
"pub const GFALSE:  c_int = 0;",
"pub const GTRUE:   c_int = 1;",
"",
"pub type gconstpointer = *const c_void;",
"pub type gpointer = *mut c_void;",
    ];

    write_vec(w, &v)
}

pub fn only_for_gtk<W: Write>(w: &mut W) -> Result<()>{
    let v = vec![
"",
"pub const GTK_ENTRY_BUFFER_MAX_SIZE: u16 = ::std::u16::MAX;",
"",
"//pub type GtkTreeModelForeachFunc = fn(model: *mut GtkTreeModel, path: *mut GtkTreePath, iter: *mut GtkTreeIter, data: gpointer) -> gboolean;",
"",
"pub const GTK_STYLE_PROVIDER_PRIORITY_FALLBACK: u32 = 1;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_THEME: u32 = 200;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_SETTINGS: u32 = 400;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_APPLICATION: u32 = 600;",
"pub const GTK_STYLE_PROVIDER_PRIORITY_USER: u32 = 800;",
    ];

    write_vec(w, &v)
}
<|endoftext|>


<commit_before>use crate::{
    executor::Executor,
    message::{Delivery, DeliveryResult},
    types::ShortString,
    BasicProperties, Error, Result,
};
use crossbeam_channel::{Receiver, Sender};
use futures_core::stream::Stream;
use log::trace;
use parking_lot::{Mutex, MutexGuard};
use std::{
    fmt,
    pin::Pin,
    sync::Arc,
    task::{Context, Poll, Waker},
};

pub trait ConsumerDelegate: Send + Sync {
    fn on_new_delivery(&self, delivery: DeliveryResult);
    fn drop_prefetched_messages(&self) {}
}

impl<DeliveryHandler: Fn(DeliveryResult) + Send + Sync> ConsumerDelegate for DeliveryHandler {
    fn on_new_delivery(&self, delivery: DeliveryResult) {
        self(delivery);
    }
}

#[derive(Clone)]
pub struct Consumer {
    inner: Arc<Mutex<ConsumerInner>>,
}

impl Consumer {
    pub(crate) fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Consumer {
        Consumer {
            inner: Arc::new(Mutex::new(ConsumerInner::new(consumer_tag, executor))),
        }
    }

    pub fn inner(&self) -> MutexGuard<'_, ConsumerInner> {
        self.inner.lock()
    }

    pub fn set_delegate<D: ConsumerDelegate + 'static>(&self, delegate: D) {
        let mut inner = self.inner();
        while let Some(delivery) = inner.next_delivery() {
            delegate.on_new_delivery(delivery);
        }
        inner.delegate = Some(Arc::new(Box::new(delegate)));
    }

    pub(crate) fn start_new_delivery(&mut self, delivery: Delivery) {
        self.inner().current_message = Some(delivery)
    }

    pub(crate) fn set_delivery_properties(&mut self, properties: BasicProperties) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.properties = properties;
        }
    }

    pub(crate) fn receive_delivery_content(&mut self, payload: Vec<u8>) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.receive_content(payload);
        }
    }

    pub(crate) fn new_delivery_complete(&mut self) -> Result<()> {
        let mut inner = self.inner();
        if let Some(delivery) = inner.current_message.take() {
            inner.new_delivery(delivery)?;
        }
        Ok(())
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<()> {
        self.inner().drop_prefetched_messages()
    }

    pub(crate) fn cancel(&self) -> Result<()> {
        self.inner().cancel()
    }

    pub(crate) fn set_error(&self, error: Error) -> Result<()> {
        self.inner().set_error(error)
    }
}

pub struct ConsumerInner {
    current_message: Option<Delivery>,
    deliveries_in: Sender<DeliveryResult>,
    deliveries_out: Receiver<DeliveryResult>,
    task: Option<Waker>,
    tag: ShortString,
    delegate: Option<Arc<Box<dyn ConsumerDelegate>>>,
    executor: Arc<dyn Executor>,
}

pub struct ConsumerIterator {
    receiver: Receiver<DeliveryResult>,
}

impl Iterator for ConsumerIterator {
    type Item = Result<Delivery>;

    fn next(&mut self) -> Option<Self::Item> {
        self.receiver.recv().ok().and_then(Result::transpose)
    }
}

impl IntoIterator for Consumer {
    type Item = Result<Delivery>;
    type IntoIter = ConsumerIterator;

    fn into_iter(self) -> Self::IntoIter {
        ConsumerIterator {
            receiver: self.inner().deliveries_out.clone(),
        }
    }
}

impl fmt::Debug for ConsumerInner {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "ConsumerInnder({})", self.tag)
    }
}

impl ConsumerInner {
    fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Self {
        let (sender, receiver) = crossbeam_channel::unbounded();
        Self {
            current_message: None,
            deliveries_in: sender,
            deliveries_out: receiver,
            task: None,
            tag: consumer_tag,
            delegate: None,
            executor,
        }
    }

    pub fn next_delivery(&mut self) -> Option<DeliveryResult> {
        self.deliveries_out.try_recv().ok()
    }

    pub fn tag(&self) -> &ShortString {
        &self.tag
    }

    fn new_delivery(&mut self, delivery: Delivery) -> Result<()> {
        trace!("new_delivery; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor.execute(Box::new(move || {
                delegate.on_new_delivery(Ok(Some(delivery)))
            }))?;
        } else {
            self.deliveries_in
                .send(Ok(Some(delivery)))
                .expect("failed to send delivery to consumer");
        }
        if let Some(task) = self.task.as_ref() {
            task.wake_by_ref();
        }
        Ok(())
    }

    fn drop_prefetched_messages(&mut self) -> Result<()> {
        trace!("drop_prefetched_messages; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.drop_prefetched_messages()))?;
        }
        while let Some(_) = self.next_delivery() {}
        Ok(())
    }

    fn cancel(&mut self) -> Result<()> {
        trace!("cancel; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.on_new_delivery(Ok(None))))?;
        } else {
            self.deliveries_in
                .send(Ok(None))
                .expect("failed to send cancel to consumer");
        }
        if let Some(task) = self.task.take() {
            task.wake();
        }
        Ok(())
    }

    pub fn set_error(&mut self, error: Error) -> Result<()> {
        trace!("set_error; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.on_new_delivery(Err(error))))?;
        } else {
            self.deliveries_in
                .send(Err(error))
                .expect("failed to send error to consumer");
        }
        self.cancel()
    }
}

impl fmt::Debug for Consumer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Consumer({})", self.inner().tag())
    }
}

impl Stream for Consumer {
    type Item = Result<Delivery>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        trace!("consumer poll; polling transport");
        let mut inner = self.inner();
        trace!(
            "consumer poll; acquired inner lock, consumer_tag={}",
            inner.tag()
        );
        inner.task = Some(cx.waker().clone());
        if let Some(delivery) = inner.next_delivery() {
            match delivery {
                Ok(Some(delivery)) => {
                    trace!(
                        "delivery; consumer_tag={}, delivery_tag={:?}",
                        inner.tag(),
                        delivery.delivery_tag
                    );
                    Poll::Ready(Some(Ok(delivery)))
                }
                Ok(None) => {
                    trace!("consumer canceled; consumer_tag={}", inner.tag());
                    Poll::Ready(None)
                }
                Err(error) => Poll::Ready(Some(Err(error))),
            }
        } else {
            trace!("delivery; status=NotReady, consumer_tag={}", inner.tag());
            Poll::Pending
        }
    }
}

#[cfg(test)]
mod futures_tests {
    use super::*;
    use crate::executor::DefaultExecutor;

    use std::task::{Context, Poll};

    use futures_test::task::new_count_waker;
    use futures_util::stream::StreamExt;

    #[test]
    fn stream_on_cancel() {
        let (waker, awoken_count) = new_count_waker();
        let mut cx = Context::from_waker(&waker);

        let mut consumer = Consumer::new(
            ShortString::from("test-consumer"),
            DefaultExecutor::default(),
        );

        assert_eq!(awoken_count.get(), 0);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Pending);

        consumer.cancel().unwrap();

        assert_eq!(awoken_count.get(), 1);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Ready(None));
    }

    #[test]
    fn stream_on_error() {
        let (waker, awoken_count) = new_count_waker();
        let mut cx = Context::from_waker(&waker);

        let mut consumer = Consumer::new(
            ShortString::from("test-consumer"),
            DefaultExecutor::default(),
        );

        assert_eq!(awoken_count.get(), 0);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Pending);

        consumer.set_error(Error::InvalidFrameReceived).unwrap();

        assert_eq!(awoken_count.get(), 1);
        assert_eq!(
            consumer.poll_next_unpin(&mut cx),
            Poll::Ready(Some(Err(Error::InvalidFrameReceived)))
        );
    }
}
<commit_msg>consumer: update deprecated log<commit_after>use crate::{
    executor::Executor,
    message::{Delivery, DeliveryResult},
    types::ShortString,
    BasicProperties, Error, Result,
};
use crossbeam_channel::{Receiver, Sender};
use futures_core::stream::Stream;
use log::trace;
use parking_lot::{Mutex, MutexGuard};
use std::{
    fmt,
    pin::Pin,
    sync::Arc,
    task::{Context, Poll, Waker},
};

pub trait ConsumerDelegate: Send + Sync {
    fn on_new_delivery(&self, delivery: DeliveryResult);
    fn drop_prefetched_messages(&self) {}
}

impl<DeliveryHandler: Fn(DeliveryResult) + Send + Sync> ConsumerDelegate for DeliveryHandler {
    fn on_new_delivery(&self, delivery: DeliveryResult) {
        self(delivery);
    }
}

#[derive(Clone)]
pub struct Consumer {
    inner: Arc<Mutex<ConsumerInner>>,
}

impl Consumer {
    pub(crate) fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Consumer {
        Consumer {
            inner: Arc::new(Mutex::new(ConsumerInner::new(consumer_tag, executor))),
        }
    }

    pub fn inner(&self) -> MutexGuard<'_, ConsumerInner> {
        self.inner.lock()
    }

    pub fn set_delegate<D: ConsumerDelegate + 'static>(&self, delegate: D) {
        let mut inner = self.inner();
        while let Some(delivery) = inner.next_delivery() {
            delegate.on_new_delivery(delivery);
        }
        inner.delegate = Some(Arc::new(Box::new(delegate)));
    }

    pub(crate) fn start_new_delivery(&mut self, delivery: Delivery) {
        self.inner().current_message = Some(delivery)
    }

    pub(crate) fn set_delivery_properties(&mut self, properties: BasicProperties) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.properties = properties;
        }
    }

    pub(crate) fn receive_delivery_content(&mut self, payload: Vec<u8>) {
        if let Some(delivery) = self.inner().current_message.as_mut() {
            delivery.receive_content(payload);
        }
    }

    pub(crate) fn new_delivery_complete(&mut self) -> Result<()> {
        let mut inner = self.inner();
        if let Some(delivery) = inner.current_message.take() {
            inner.new_delivery(delivery)?;
        }
        Ok(())
    }

    pub(crate) fn drop_prefetched_messages(&self) -> Result<()> {
        self.inner().drop_prefetched_messages()
    }

    pub(crate) fn cancel(&self) -> Result<()> {
        self.inner().cancel()
    }

    pub(crate) fn set_error(&self, error: Error) -> Result<()> {
        self.inner().set_error(error)
    }
}

pub struct ConsumerInner {
    current_message: Option<Delivery>,
    deliveries_in: Sender<DeliveryResult>,
    deliveries_out: Receiver<DeliveryResult>,
    task: Option<Waker>,
    tag: ShortString,
    delegate: Option<Arc<Box<dyn ConsumerDelegate>>>,
    executor: Arc<dyn Executor>,
}

pub struct ConsumerIterator {
    receiver: Receiver<DeliveryResult>,
}

impl Iterator for ConsumerIterator {
    type Item = Result<Delivery>;

    fn next(&mut self) -> Option<Self::Item> {
        self.receiver.recv().ok().and_then(Result::transpose)
    }
}

impl IntoIterator for Consumer {
    type Item = Result<Delivery>;
    type IntoIter = ConsumerIterator;

    fn into_iter(self) -> Self::IntoIter {
        ConsumerIterator {
            receiver: self.inner().deliveries_out.clone(),
        }
    }
}

impl fmt::Debug for ConsumerInner {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "ConsumerInnder({})", self.tag)
    }
}

impl ConsumerInner {
    fn new(consumer_tag: ShortString, executor: Arc<dyn Executor>) -> Self {
        let (sender, receiver) = crossbeam_channel::unbounded();
        Self {
            current_message: None,
            deliveries_in: sender,
            deliveries_out: receiver,
            task: None,
            tag: consumer_tag,
            delegate: None,
            executor,
        }
    }

    pub fn next_delivery(&mut self) -> Option<DeliveryResult> {
        self.deliveries_out.try_recv().ok()
    }

    pub fn tag(&self) -> &ShortString {
        &self.tag
    }

    fn new_delivery(&mut self, delivery: Delivery) -> Result<()> {
        trace!("new_delivery; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor.execute(Box::new(move || {
                delegate.on_new_delivery(Ok(Some(delivery)))
            }))?;
        } else {
            self.deliveries_in
                .send(Ok(Some(delivery)))
                .expect("failed to send delivery to consumer");
        }
        if let Some(task) = self.task.as_ref() {
            task.wake_by_ref();
        }
        Ok(())
    }

    fn drop_prefetched_messages(&mut self) -> Result<()> {
        trace!("drop_prefetched_messages; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.drop_prefetched_messages()))?;
        }
        while let Some(_) = self.next_delivery() {}
        Ok(())
    }

    fn cancel(&mut self) -> Result<()> {
        trace!("cancel; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.on_new_delivery(Ok(None))))?;
        } else {
            self.deliveries_in
                .send(Ok(None))
                .expect("failed to send cancel to consumer");
        }
        if let Some(task) = self.task.take() {
            task.wake();
        }
        Ok(())
    }

    pub fn set_error(&mut self, error: Error) -> Result<()> {
        trace!("set_error; consumer_tag={}", self.tag);
        if let Some(delegate) = self.delegate.as_ref() {
            let delegate = delegate.clone();
            self.executor
                .execute(Box::new(move || delegate.on_new_delivery(Err(error))))?;
        } else {
            self.deliveries_in
                .send(Err(error))
                .expect("failed to send error to consumer");
        }
        self.cancel()
    }
}

impl fmt::Debug for Consumer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "Consumer({})", self.inner().tag())
    }
}

impl Stream for Consumer {
    type Item = Result<Delivery>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        trace!("consumer poll_next");
        let mut inner = self.inner();
        trace!(
            "consumer poll; acquired inner lock, consumer_tag={}",
            inner.tag()
        );
        inner.task = Some(cx.waker().clone());
        if let Some(delivery) = inner.next_delivery() {
            match delivery {
                Ok(Some(delivery)) => {
                    trace!(
                        "delivery; consumer_tag={}, delivery_tag={:?}",
                        inner.tag(),
                        delivery.delivery_tag
                    );
                    Poll::Ready(Some(Ok(delivery)))
                }
                Ok(None) => {
                    trace!("consumer canceled; consumer_tag={}", inner.tag());
                    Poll::Ready(None)
                }
                Err(error) => Poll::Ready(Some(Err(error))),
            }
        } else {
            trace!("delivery; status=NotReady, consumer_tag={}", inner.tag());
            Poll::Pending
        }
    }
}

#[cfg(test)]
mod futures_tests {
    use super::*;
    use crate::executor::DefaultExecutor;

    use std::task::{Context, Poll};

    use futures_test::task::new_count_waker;
    use futures_util::stream::StreamExt;

    #[test]
    fn stream_on_cancel() {
        let (waker, awoken_count) = new_count_waker();
        let mut cx = Context::from_waker(&waker);

        let mut consumer = Consumer::new(
            ShortString::from("test-consumer"),
            DefaultExecutor::default(),
        );

        assert_eq!(awoken_count.get(), 0);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Pending);

        consumer.cancel().unwrap();

        assert_eq!(awoken_count.get(), 1);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Ready(None));
    }

    #[test]
    fn stream_on_error() {
        let (waker, awoken_count) = new_count_waker();
        let mut cx = Context::from_waker(&waker);

        let mut consumer = Consumer::new(
            ShortString::from("test-consumer"),
            DefaultExecutor::default(),
        );

        assert_eq!(awoken_count.get(), 0);
        assert_eq!(consumer.poll_next_unpin(&mut cx), Poll::Pending);

        consumer.set_error(Error::InvalidFrameReceived).unwrap();

        assert_eq!(awoken_count.get(), 1);
        assert_eq!(
            consumer.poll_next_unpin(&mut cx),
            Poll::Ready(Some(Err(Error::InvalidFrameReceived)))
        );
    }
}
<|endoftext|>


<commit_before>use state::State;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use context::base::BaseContext;

pub use self::message::MessageActionType;

use std::cell::RefCell;
use std::rc::Rc;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ActionType {
    Message(self::message::MessageActionType)
}

trait Action {
    fn execute(&self, state: &State, context: &BaseContext);
    fn set_response_sender(&self, _sender: Rc<RefCell<Box<ResponseSender<Response>>>>) {}
}

mod deser {
    use serde;
    use super::ActionType;

    impl serde::de::Deserialize for ActionType {
    fn deserialize<D>(deserializer: &mut D) -> Result<ActionType, D::Error>
                      where D: serde::de::Deserializer {
        enum Field {
            Message,
        }

        impl serde::de::Deserialize for Field {
            #[inline]
            fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
                where D: serde::de::Deserializer {
                    struct FieldVisitor;

                    impl serde::de::Visitor for FieldVisitor {
                        type Value = Field;

                        fn visit_str<E>(&mut self, value: &str) -> Result<Field, E> where E: serde::de::Error {
                            match value {
                                "message" => Ok(Field::Message),
                                _ => Err(serde::de::Error::unknown_field(value)),
                            }
                        }
                    }

                    deserializer.visit(FieldVisitor)
                }
            }

            struct Visitor;

            impl serde::de::EnumVisitor for Visitor {
                type Value = ActionType;

                fn visit<V>(&mut self, mut visitor: V) -> Result<ActionType, V::Error>
                    where V: serde::de::VariantVisitor
                {
                    match try!(visitor.visit_variant()) {
                        Field::Message => {
                            let value = try!(visitor.visit_newtype());
                            Ok(ActionType::Message(value))
                        }
                    }
                }
            }

            const VARIANTS: &'static [&'static str] = &["message"];

            deserializer.visit_enum("ActionType", VARIANTS, Visitor)
        }
    }

    #[cfg(test)]
    mod test {
        use serde_json::from_str;
        use action::ActionType;

        #[test]
        fn test_given_action_when_it_is_deserialized_then_we_get_the_right_result() {
            let text = r#"
                {
                    "message": null
                }
            "#;

            let result = from_str::<ActionType>(text);
            println!("{:?}", &result);
            let action = result.ok().expect("Failed to deserialize a valid ActionType");
            match action {
                ActionType::Message(_) => {}
            }
        }
    }
}

pub mod message {
    use context::base::BaseContext;
    use super::Action;
    use state::State;

    #[derive(Clone, Debug, PartialEq, Eq)]
    pub struct MessageActionType;

    impl MessageActionType {
        pub fn new() -> MessageActionType {
            MessageActionType
        }
    }

    impl Action for MessageActionType {
        fn execute(&self, _state: &State, _context: &BaseContext) {

        }
    }

    impl From<MessageActionType> for super::ActionType {
        fn from(action: MessageActionType) -> super::ActionType {
            super::ActionType::Message(action)
        }
    }

    mod deser {

    use super::MessageActionType;
    use serde;
    use serde::de::Deserialize;

    impl serde::Deserialize for MessageActionType {
        fn deserialize<D>(deserializer: &mut D) -> Result<MessageActionType, D::Error>
            where D: serde::de::Deserializer
        {
            deserializer.visit_unit_struct("MessageActionType", MessageActionVisitor)
        }
    }

    struct MessageActionVisitor;

    impl serde::de::Visitor for MessageActionVisitor {
        type Value = MessageActionType;
        fn visit_unit<E>(&mut self) -> Result<Self::Value, E>
            where E: serde::de::Error {
            Ok(MessageActionType)
        }
    }
    }
}
<commit_msg>Action: make it public and add Debug requirement<commit_after>use state::State;
use dispatcher::Response;
use dispatcher::response::ResponseSender;
use context::base::BaseContext;

pub use self::message::MessageActionType;

use std::cell::RefCell;
use std::fmt::Debug;
use std::rc::Rc;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ActionType {
    Message(self::message::MessageActionType)
}

pub trait Action: Debug {
    fn execute(&self, state: &State, context: &BaseContext);
    fn set_response_sender(&self, _sender: Rc<RefCell<Box<ResponseSender<Response>>>>) {}
}

mod deser {
    use serde;
    use super::ActionType;

    impl serde::de::Deserialize for ActionType {
    fn deserialize<D>(deserializer: &mut D) -> Result<ActionType, D::Error>
                      where D: serde::de::Deserializer {
        enum Field {
            Message,
        }

        impl serde::de::Deserialize for Field {
            #[inline]
            fn deserialize<D>(deserializer: &mut D) -> Result<Field, D::Error>
                where D: serde::de::Deserializer {
                    struct FieldVisitor;

                    impl serde::de::Visitor for FieldVisitor {
                        type Value = Field;

                        fn visit_str<E>(&mut self, value: &str) -> Result<Field, E> where E: serde::de::Error {
                            match value {
                                "message" => Ok(Field::Message),
                                _ => Err(serde::de::Error::unknown_field(value)),
                            }
                        }
                    }

                    deserializer.visit(FieldVisitor)
                }
            }

            struct Visitor;

            impl serde::de::EnumVisitor for Visitor {
                type Value = ActionType;

                fn visit<V>(&mut self, mut visitor: V) -> Result<ActionType, V::Error>
                    where V: serde::de::VariantVisitor
                {
                    match try!(visitor.visit_variant()) {
                        Field::Message => {
                            let value = try!(visitor.visit_newtype());
                            Ok(ActionType::Message(value))
                        }
                    }
                }
            }

            const VARIANTS: &'static [&'static str] = &["message"];

            deserializer.visit_enum("ActionType", VARIANTS, Visitor)
        }
    }

    #[cfg(test)]
    mod test {
        use serde_json::from_str;
        use action::ActionType;

        #[test]
        fn test_given_action_when_it_is_deserialized_then_we_get_the_right_result() {
            let text = r#"
                {
                    "message": null
                }
            "#;

            let result = from_str::<ActionType>(text);
            println!("{:?}", &result);
            let action = result.ok().expect("Failed to deserialize a valid ActionType");
            match action {
                ActionType::Message(_) => {}
            }
        }
    }
}

pub mod message {
    use context::base::BaseContext;
    use super::Action;
    use state::State;

    #[derive(Clone, Debug, PartialEq, Eq)]
    pub struct MessageActionType;

    impl MessageActionType {
        pub fn new() -> MessageActionType {
            MessageActionType
        }
    }

    impl Action for MessageActionType {
        fn execute(&self, _state: &State, _context: &BaseContext) {

        }
    }

    impl From<MessageActionType> for super::ActionType {
        fn from(action: MessageActionType) -> super::ActionType {
            super::ActionType::Message(action)
        }
    }

    mod deser {

    use super::MessageActionType;
    use serde;
    use serde::de::Deserialize;

    impl serde::Deserialize for MessageActionType {
        fn deserialize<D>(deserializer: &mut D) -> Result<MessageActionType, D::Error>
            where D: serde::de::Deserializer
        {
            deserializer.visit_unit_struct("MessageActionType", MessageActionVisitor)
        }
    }

    struct MessageActionVisitor;

    impl serde::de::Visitor for MessageActionVisitor {
        type Value = MessageActionType;
        fn visit_unit<E>(&mut self) -> Result<Self::Value, E>
            where E: serde::de::Error {
            Ok(MessageActionType)
        }
    }
    }
}
<|endoftext|>